From 85c7dcb3719b03a0ee657af5ab5df504ea5ef8fe Mon Sep 17 00:00:00 2001 From: satyanarayana narlapuram Date: Tue, 21 Apr 2026 07:52:56 +0000 Subject: [PATCH v20260428 1/3] Prevent dropping the last label from a property graph element Per SQL/PGQ standard, every graph element must have at least one label. When dropping a label from a graph element, ensure that there exists at least one other label on the element. If the label being dropped is the only label on the element, raise an error. Reported By: Satyanarayana Narlapuram Author: Satyanarayana Narlapuram Author: Ashutosh Bapat Reviewed by: Ashutosh Bapat Discussion: https://www.postgresql.org/message-id/CAHg+QDeP=mTHTV48R23zKMy1SBmCKZ_L7-z5zKnYyw+K0x-gCg@mail.gmail.com --- doc/src/sgml/ref/alter_property_graph.sgml | 4 +- src/backend/commands/propgraphcmds.c | 54 +++++++++++++++++-- .../expected/create_property_graph.out | 6 +++ .../regress/sql/create_property_graph.sql | 4 ++ 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/doc/src/sgml/ref/alter_property_graph.sgml b/doc/src/sgml/ref/alter_property_graph.sgml index f517f2b2d7a..2fd0c138e12 100644 --- a/doc/src/sgml/ref/alter_property_graph.sgml +++ b/doc/src/sgml/ref/alter_property_graph.sgml @@ -99,7 +99,9 @@ ALTER PROPERTY GRAPH [ IF EXISTS ] nameALTER {VERTEX|NODE|EDGE|RELATIONSHIP} TABLE ... DROP LABEL - This form removes a label from an existing vertex or edge table. + This form removes a label from an existing vertex or edge table. The + last label on an element table cannot be dropped; every vertex or edge + table must have at least one label. diff --git a/src/backend/commands/propgraphcmds.c b/src/backend/commands/propgraphcmds.c index 6d509fccf46..7836e7ab63e 100644 --- a/src/backend/commands/propgraphcmds.c +++ b/src/backend/commands/propgraphcmds.c @@ -1491,8 +1491,14 @@ AlterPropGraph(ParseState *pstate, const AlterPropGraphStmt *stmt) { Oid peoid; Oid labeloid; - Oid ellabeloid; + Oid ellabeloid = InvalidOid; ObjectAddress obj; + Relation elrel; + SysScanDesc elscan; + ScanKeyData elkey[1]; + int nlabels = 0; + HeapTuple tuple; + if (stmt->element_kind == PROPGRAPH_ELEMENT_KIND_VERTEX) peoid = get_vertex_oid(pstate, pgrelid, stmt->element_alias, -1); @@ -1510,11 +1516,38 @@ AlterPropGraph(ParseState *pstate, const AlterPropGraphStmt *stmt) get_rel_name(pgrelid), stmt->element_alias, stmt->drop_label), parser_errposition(pstate, -1)); - ellabeloid = GetSysCacheOid2(PROPGRAPHELEMENTLABELELEMENTLABEL, - Anum_pg_propgraph_element_label_oid, - ObjectIdGetDatum(peoid), - ObjectIdGetDatum(labeloid)); + /* + * Is the given label associated with the element? Is this the only + * label associated with the element? + */ + elrel = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&elkey[0], + Anum_pg_propgraph_element_label_pgelelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(peoid)); + elscan = systable_beginscan(elrel, PropgraphElementLabelElementLabelIndexId, + true, NULL, 1, elkey); + while (HeapTupleIsValid(tuple = systable_getnext(elscan))) + { + Form_pg_propgraph_element_label elform = (Form_pg_propgraph_element_label) GETSTRUCT(tuple); + + nlabels++; + if (elform->pgellabelid == labeloid) + ellabeloid = elform->oid; + + /* + * If we find more than one label associated with the given + * element and also found the label we are going to drop, we are + * done. + */ + if (nlabels > 1 && OidIsValid(ellabeloid)) + break; + } + systable_endscan(elscan); + table_close(elrel, AccessShareLock); + + /* Given label is not associated with the element. */ if (!ellabeloid) ereport(ERROR, errcode(ERRCODE_UNDEFINED_OBJECT), @@ -1522,6 +1555,17 @@ AlterPropGraph(ParseState *pstate, const AlterPropGraphStmt *stmt) get_rel_name(pgrelid), stmt->element_alias, stmt->drop_label), parser_errposition(pstate, -1)); + /* + * Prevent dropping the last label from an element. Every element must + * have at least one label. + */ + if (nlabels == 1) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("cannot drop the last label from element \"%s\"", + stmt->element_alias), + errhint("Every element must have at least one label."))); + ObjectAddressSet(obj, PropgraphElementLabelRelationId, ellabeloid); performDeletion(&obj, stmt->drop_behavior, 0); diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..740f886cd83 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -57,6 +57,12 @@ ALTER PROPERTY GRAPH g3 ALTER PROPERTY GRAPH g3 ALTER VERTEX TABLE t3 DROP LABEL t3l3x; -- error ERROR: property graph "g3" element "t3" has no label "t3l3x" ALTER PROPERTY GRAPH g3 ALTER VERTEX TABLE t3 DROP LABEL t3l3; +-- Test that the last label on an element cannot be dropped +ALTER PROPERTY GRAPH g3 ALTER VERTEX TABLE t3 DROP LABEL t3l2; +ALTER PROPERTY GRAPH g3 ALTER VERTEX TABLE t3 DROP LABEL t3l1; -- error: last label +ERROR: cannot drop the last label from element "t3" +HINT: Every element must have at least one label. +ALTER PROPERTY GRAPH g3 ALTER VERTEX TABLE t3 ADD LABEL t3l2 PROPERTIES ALL COLUMNS; ALTER PROPERTY GRAPH g3 DROP VERTEX TABLES (t2); -- fail ERROR: cannot drop vertex t2 of property graph g3 because other objects depend on it DETAIL: edge e1 of property graph g3 depends on vertex t2 of property graph g3 diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..4cf771596a8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -52,6 +52,10 @@ ALTER PROPERTY GRAPH g3 ADD LABEL t3l3 PROPERTIES ALL COLUMNS; ALTER PROPERTY GRAPH g3 ALTER VERTEX TABLE t3 DROP LABEL t3l3x; -- error ALTER PROPERTY GRAPH g3 ALTER VERTEX TABLE t3 DROP LABEL t3l3; +-- Test that the last label on an element cannot be dropped +ALTER PROPERTY GRAPH g3 ALTER VERTEX TABLE t3 DROP LABEL t3l2; +ALTER PROPERTY GRAPH g3 ALTER VERTEX TABLE t3 DROP LABEL t3l1; -- error: last label +ALTER PROPERTY GRAPH g3 ALTER VERTEX TABLE t3 ADD LABEL t3l2 PROPERTIES ALL COLUMNS; ALTER PROPERTY GRAPH g3 DROP VERTEX TABLES (t2); -- fail ALTER PROPERTY GRAPH g3 DROP VERTEX TABLES (t2) CASCADE; ALTER PROPERTY GRAPH g3 DROP EDGE TABLES (e2); base-commit: c210647aeb17692c138014235c7e7a2d9af73b87 -- 2.34.1