Handle element label and label property objects in object address functions

getObjectTypeDescription() and getObjectIdentityParts() do not handle
objects in pg_propgraph_element_label and pg_propgraph_label_property
catalogs.  These functions when called for handling DDL that affects
these objects cause an "unsupported object class" error.  An error is
reported when these functions are called via pg_identify_object() and
pg_identify_object_as_address() with objects from the said catalogs.

The objects in these catalogs do not have a (user-given) name but they
can be manipulated individually through ALTER PROPERTY GRAPH
sub-commands.  Hence they need to be accessible to the event triggers.
Handle these catalogs in the respective functions.

Reported-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Author: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Discussion: https://www.postgresql.org/message-id/aej1DkLwhyZWmtxJ@bdtpg
This commit is contained in:
Peter Eisentraut 2026-06-05 08:59:05 +02:00
parent 9ec568b3eb
commit 72498a8698
7 changed files with 267 additions and 93 deletions

View file

@ -895,9 +895,15 @@ static const struct object_type_map
{
"property graph element", -1
},
{
"property graph element label", -1
},
{
"property graph label", -1
},
{
"property graph label property", -1
},
{
"property graph property", -1
},
@ -4897,6 +4903,14 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
appendStringInfoString(&buffer, "property graph property");
break;
case PropgraphElementLabelRelationId:
appendStringInfoString(&buffer, "property graph element label");
break;
case PropgraphLabelPropertyRelationId:
appendStringInfoString(&buffer, "property graph label property");
break;
case PublicationRelationId:
appendStringInfoString(&buffer, "publication");
break;
@ -6212,6 +6226,81 @@ getObjectIdentityParts(const ObjectAddress *object,
break;
}
case PropgraphElementLabelRelationId:
{
Relation ellabelDesc;
HeapTuple tup;
Form_pg_propgraph_element_label pgelform;
ObjectAddress oa;
char *labelname;
ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
tup = get_catalog_object_by_oid(ellabelDesc,
Anum_pg_propgraph_element_label_oid,
object->objectId);
if (!HeapTupleIsValid(tup))
{
if (!missing_ok)
elog(ERROR, "could not find tuple for element label %u",
object->objectId);
table_close(ellabelDesc, AccessShareLock);
break;
}
pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
labelname = get_propgraph_label_name(pgelform->pgellabelid);
appendStringInfo(&buffer, "%s of ", quote_identifier(labelname));
ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
objargs, false));
/* labelname is already pstrdup'ed. */
if (objname)
*objname = lappend(*objname, labelname);
table_close(ellabelDesc, AccessShareLock);
break;
}
case PropgraphLabelPropertyRelationId:
{
Relation lblpropDesc;
HeapTuple tup;
Form_pg_propgraph_label_property plpform;
ObjectAddress oa;
char *propname;
lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
AccessShareLock);
tup = get_catalog_object_by_oid(lblpropDesc,
Anum_pg_propgraph_label_property_oid,
object->objectId);
if (!HeapTupleIsValid(tup))
{
if (!missing_ok)
elog(ERROR, "could not find tuple for label property %u",
object->objectId);
table_close(lblpropDesc, AccessShareLock);
break;
}
plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
propname = get_propgraph_property_name(plpform->plppropid);
appendStringInfo(&buffer, "%s of ", quote_identifier(propname));
ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
objargs, false));
/* propname is already pstrdup'ed. */
if (objname)
*objname = lappend(*objname, propname);
table_close(lblpropDesc, AccessShareLock);
break;
}
case PublicationRelationId:
{
char *pubname;

View file

@ -661,93 +661,122 @@ SELECT * FROM information_schema.pg_property_graph_privileges WHERE grantee LIKE
(2 rows)
-- test object address functions
CREATE TEMPORARY VIEW deps_tree AS
WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
SELECT classid, objid, objsubid,
refclassid, refobjid, refobjsubid
FROM pg_depend
WHERE refclassid = 'pg_class'::regclass AND
refobjid = 'create_property_graph_tests.gt'::regclass AND
-- eliminate this view, which is not a real dependency, from the result
classid <> 'pg_rewrite'::regclass
UNION ALL
SELECT d.classid, d.objid, d.objsubid,
d.refclassid, d.refobjid, d.refobjsubid
FROM pg_depend d
JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
) SELECT DISTINCT * FROM deps;
SELECT pg_describe_object(classid, objid, objsubid) as obj,
pg_describe_object(refclassid, refobjid, refobjsubid) as reference_graph
FROM pg_depend
WHERE refclassid = 'pg_class'::regclass AND
refobjid = 'create_property_graph_tests.g2'::regclass
ORDER BY 1, 2;
obj | reference_graph
---------------------------------+-------------------
edge e1 of property graph g2 | property graph g2
edge e2 of property graph g2 | property graph g2
label e1 of property graph g2 | property graph g2
label e2 of property graph g2 | property graph g2
label t1 of property graph g2 | property graph g2
label t2 of property graph g2 | property graph g2
label t3l1 of property graph g2 | property graph g2
label t3l2 of property graph g2 | property graph g2
property a of property graph g2 | property graph g2
property b of property graph g2 | property graph g2
property i of property graph g2 | property graph g2
property j of property graph g2 | property graph g2
property k of property graph g2 | property graph g2
property t of property graph g2 | property graph g2
property x of property graph g2 | property graph g2
property y of property graph g2 | property graph g2
property z of property graph g2 | property graph g2
vertex t1 of property graph g2 | property graph g2
vertex t2 of property graph g2 | property graph g2
vertex t3 of property graph g2 | property graph g2
(20 rows)
pg_describe_object(refclassid, refobjid, refobjsubid) as refobj
FROM deps_tree ORDER BY 1, 2;
obj | refobj
----------------------------------------------------------+--------------------------------------------
edge e of property graph gt | property graph gt
edge e of property graph gt | vertex v1 of property graph gt
edge e of property graph gt | vertex v2 of property graph gt
label e of edge e of property graph gt | edge e of property graph gt
label e of edge e of property graph gt | label e of property graph gt
label e of property graph gt | property graph gt
label v1 of property graph gt | property graph gt
label v1 of vertex v1 of property graph gt | label v1 of property graph gt
label v1 of vertex v1 of property graph gt | vertex v1 of property graph gt
label v2 of property graph gt | property graph gt
label v2 of vertex v2 of property graph gt | label v2 of property graph gt
label v2 of vertex v2 of property graph gt | vertex v2 of property graph gt
property a of label v1 of vertex v1 of property graph gt | label v1 of vertex v1 of property graph gt
property a of label v1 of vertex v1 of property graph gt | property a of property graph gt
property a of property graph gt | property graph gt
property b of label v1 of vertex v1 of property graph gt | label v1 of vertex v1 of property graph gt
property b of label v1 of vertex v1 of property graph gt | property b of property graph gt
property b of property graph gt | property graph gt
property c of label e of edge e of property graph gt | label e of edge e of property graph gt
property c of label e of edge e of property graph gt | property c of property graph gt
property c of property graph gt | property graph gt
property k1 of label e of edge e of property graph gt | label e of edge e of property graph gt
property k1 of label e of edge e of property graph gt | property k1 of property graph gt
property k1 of property graph gt | property graph gt
property k2 of label e of edge e of property graph gt | label e of edge e of property graph gt
property k2 of label e of edge e of property graph gt | property k2 of property graph gt
property k2 of property graph gt | property graph gt
property m of label v2 of vertex v2 of property graph gt | label v2 of vertex v2 of property graph gt
property m of label v2 of vertex v2 of property graph gt | property m of property graph gt
property m of property graph gt | property graph gt
property n of label v2 of vertex v2 of property graph gt | label v2 of vertex v2 of property graph gt
property n of label v2 of vertex v2 of property graph gt | property n of property graph gt
property n of property graph gt | property graph gt
vertex v1 of property graph gt | property graph gt
vertex v2 of property graph gt | property graph gt
(35 rows)
SELECT (pg_identify_object_as_address(classid, objid, objsubid)).*
FROM pg_depend
WHERE refclassid = 'pg_class'::regclass AND
refobjid = 'create_property_graph_tests.g2'::regclass
FROM (SELECT DISTINCT classid, objid, objsubid FROM deps_tree)
ORDER BY 1, 2, 3;
type | object_names | object_args
-------------------------+---------------------------------------+-------------
property graph element | {create_property_graph_tests,g2,e1} | {}
property graph element | {create_property_graph_tests,g2,e2} | {}
property graph element | {create_property_graph_tests,g2,t1} | {}
property graph element | {create_property_graph_tests,g2,t2} | {}
property graph element | {create_property_graph_tests,g2,t3} | {}
property graph label | {create_property_graph_tests,g2,e1} | {}
property graph label | {create_property_graph_tests,g2,e2} | {}
property graph label | {create_property_graph_tests,g2,t1} | {}
property graph label | {create_property_graph_tests,g2,t2} | {}
property graph label | {create_property_graph_tests,g2,t3l1} | {}
property graph label | {create_property_graph_tests,g2,t3l2} | {}
property graph property | {create_property_graph_tests,g2,a} | {}
property graph property | {create_property_graph_tests,g2,b} | {}
property graph property | {create_property_graph_tests,g2,i} | {}
property graph property | {create_property_graph_tests,g2,j} | {}
property graph property | {create_property_graph_tests,g2,k} | {}
property graph property | {create_property_graph_tests,g2,t} | {}
property graph property | {create_property_graph_tests,g2,x} | {}
property graph property | {create_property_graph_tests,g2,y} | {}
property graph property | {create_property_graph_tests,g2,z} | {}
(20 rows)
type | object_names | object_args
-------------------------------+------------------------------------------+-------------
property graph element | {create_property_graph_tests,gt,e} | {}
property graph element | {create_property_graph_tests,gt,v1} | {}
property graph element | {create_property_graph_tests,gt,v2} | {}
property graph element label | {create_property_graph_tests,gt,e,e} | {}
property graph element label | {create_property_graph_tests,gt,v1,v1} | {}
property graph element label | {create_property_graph_tests,gt,v2,v2} | {}
property graph label | {create_property_graph_tests,gt,e} | {}
property graph label | {create_property_graph_tests,gt,v1} | {}
property graph label | {create_property_graph_tests,gt,v2} | {}
property graph label property | {create_property_graph_tests,gt,e,e,c} | {}
property graph label property | {create_property_graph_tests,gt,e,e,k1} | {}
property graph label property | {create_property_graph_tests,gt,e,e,k2} | {}
property graph label property | {create_property_graph_tests,gt,v1,v1,a} | {}
property graph label property | {create_property_graph_tests,gt,v1,v1,b} | {}
property graph label property | {create_property_graph_tests,gt,v2,v2,m} | {}
property graph label property | {create_property_graph_tests,gt,v2,v2,n} | {}
property graph property | {create_property_graph_tests,gt,a} | {}
property graph property | {create_property_graph_tests,gt,b} | {}
property graph property | {create_property_graph_tests,gt,c} | {}
property graph property | {create_property_graph_tests,gt,k1} | {}
property graph property | {create_property_graph_tests,gt,k2} | {}
property graph property | {create_property_graph_tests,gt,m} | {}
property graph property | {create_property_graph_tests,gt,n} | {}
(23 rows)
SELECT (pg_identify_object(classid, objid, objsubid)).*
FROM pg_depend
WHERE refclassid = 'pg_class'::regclass AND
refobjid = 'create_property_graph_tests.g2'::regclass
FROM (SELECT DISTINCT classid, objid, objsubid FROM deps_tree)
ORDER BY 1, 2, 3, 4;
type | schema | name | identity
-------------------------+--------+------+----------------------------------------
property graph element | | | e1 of create_property_graph_tests.g2
property graph element | | | e2 of create_property_graph_tests.g2
property graph element | | | t1 of create_property_graph_tests.g2
property graph element | | | t2 of create_property_graph_tests.g2
property graph element | | | t3 of create_property_graph_tests.g2
property graph label | | | e1 of create_property_graph_tests.g2
property graph label | | | e2 of create_property_graph_tests.g2
property graph label | | | t1 of create_property_graph_tests.g2
property graph label | | | t2 of create_property_graph_tests.g2
property graph label | | | t3l1 of create_property_graph_tests.g2
property graph label | | | t3l2 of create_property_graph_tests.g2
property graph property | | | a of create_property_graph_tests.g2
property graph property | | | b of create_property_graph_tests.g2
property graph property | | | i of create_property_graph_tests.g2
property graph property | | | j of create_property_graph_tests.g2
property graph property | | | k of create_property_graph_tests.g2
property graph property | | | t of create_property_graph_tests.g2
property graph property | | | x of create_property_graph_tests.g2
property graph property | | | y of create_property_graph_tests.g2
property graph property | | | z of create_property_graph_tests.g2
(20 rows)
type | schema | name | identity
-------------------------------+--------+------+-------------------------------------------------
property graph element | | | e of create_property_graph_tests.gt
property graph element | | | v1 of create_property_graph_tests.gt
property graph element | | | v2 of create_property_graph_tests.gt
property graph element label | | | e of e of create_property_graph_tests.gt
property graph element label | | | v1 of v1 of create_property_graph_tests.gt
property graph element label | | | v2 of v2 of create_property_graph_tests.gt
property graph label | | | e of create_property_graph_tests.gt
property graph label | | | v1 of create_property_graph_tests.gt
property graph label | | | v2 of create_property_graph_tests.gt
property graph label property | | | a of v1 of v1 of create_property_graph_tests.gt
property graph label property | | | b of v1 of v1 of create_property_graph_tests.gt
property graph label property | | | c of e of e of create_property_graph_tests.gt
property graph label property | | | k1 of e of e of create_property_graph_tests.gt
property graph label property | | | k2 of e of e of create_property_graph_tests.gt
property graph label property | | | m of v2 of v2 of create_property_graph_tests.gt
property graph label property | | | n of v2 of v2 of create_property_graph_tests.gt
property graph property | | | a of create_property_graph_tests.gt
property graph property | | | b of create_property_graph_tests.gt
property graph property | | | c of create_property_graph_tests.gt
property graph property | | | k1 of create_property_graph_tests.gt
property graph property | | | k2 of create_property_graph_tests.gt
property graph property | | | m of create_property_graph_tests.gt
property graph property | | | n of create_property_graph_tests.gt
(23 rows)
\a\t
SELECT pg_get_propgraphdef('g2'::regclass);

View file

@ -173,6 +173,28 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING
alter default privileges for role regress_evt_user
revoke delete on tables from regress_evt_user;
NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
-- DROP PROPERTY GRAPH should work with event trigger in place
CREATE TABLE tv1 (a int PRIMARY KEY, b text);
NOTICE: test_event_trigger: ddl_command_start CREATE TABLE
NOTICE: test_event_trigger: ddl_command_end CREATE TABLE
CREATE TABLE tv2 (i int PRIMARY KEY, j text);
NOTICE: test_event_trigger: ddl_command_start CREATE TABLE
NOTICE: test_event_trigger: ddl_command_end CREATE TABLE
CREATE TABLE te1 (p int PRIMARY KEY, a int REFERENCES tv1(a), b int REFERENCES tv2(i), q text);
NOTICE: test_event_trigger: ddl_command_start CREATE TABLE
NOTICE: test_event_trigger: ddl_command_end CREATE TABLE
CREATE PROPERTY GRAPH gx
VERTEX TABLES (
tv1 LABEL l1 PROPERTIES (b AS p1),
tv2 LABEL l2 PROPERTIES (j AS p1))
EDGE TABLES (te1 SOURCE tv1 DESTINATION tv2 LABEL e1 PROPERTIES (q as p1));
NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH
ALTER PROPERTY GRAPH gx ALTER EDGE TABLE te1 ALTER LABEL e1 DROP PROPERTIES (p1);
NOTICE: test_event_trigger: ddl_command_end ALTER PROPERTY GRAPH
DROP PROPERTY GRAPH gx;
NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH
DROP TABLE tv1, tv2, te1;
NOTICE: test_event_trigger: ddl_command_end DROP TABLE
-- alter owner to non-superuser should fail
alter event trigger regress_event_trigger owner to regress_evt_user;
ERROR: permission denied to change owner of event trigger "regress_event_trigger"

View file

@ -67,7 +67,8 @@ DECLARE
BEGIN
FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
('toast table column'), ('view column'), ('materialized view column'),
('property graph element'), ('property graph label'), ('property graph property')
('property graph element'), ('property graph label'), ('property graph property'),
('property graph element label'), ('property graph label property')
LOOP
BEGIN
PERFORM pg_get_object_address(objtype, '{one}', '{}');
@ -86,6 +87,8 @@ WARNING: error for materialized view column: unsupported object type "materiali
WARNING: error for property graph element: unsupported object type "property graph element"
WARNING: error for property graph label: unsupported object type "property graph label"
WARNING: error for property graph property: unsupported object type "property graph property"
WARNING: error for property graph element label: unsupported object type "property graph element label"
WARNING: error for property graph label property: unsupported object type "property graph label property"
-- miscellaneous other errors
select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}');
ERROR: operator 1 (int4, bool) of operator family integer_ops for access method btree does not exist
@ -595,6 +598,8 @@ WITH objects (classid, objid, objsubid) AS (VALUES
('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
('pg_publication'::regclass, 0, 0), -- no publication
('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
('pg_publication_rel'::regclass, 0, 0), -- no publication relation
@ -653,6 +658,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid;
("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL
("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL
("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL
("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL
("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL
("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL
-- restore normal output mode
\a\t

View file

@ -281,21 +281,30 @@ SELECT * FROM information_schema.pg_property_data_types ORDER BY property_graph_
SELECT * FROM information_schema.pg_property_graph_privileges WHERE grantee LIKE 'regress%' ORDER BY property_graph_name, grantor, grantee, privilege_type;
-- test object address functions
CREATE TEMPORARY VIEW deps_tree AS
WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS (
SELECT classid, objid, objsubid,
refclassid, refobjid, refobjsubid
FROM pg_depend
WHERE refclassid = 'pg_class'::regclass AND
refobjid = 'create_property_graph_tests.gt'::regclass AND
-- eliminate this view, which is not a real dependency, from the result
classid <> 'pg_rewrite'::regclass
UNION ALL
SELECT d.classid, d.objid, d.objsubid,
d.refclassid, d.refobjid, d.refobjsubid
FROM pg_depend d
JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid
) SELECT DISTINCT * FROM deps;
SELECT pg_describe_object(classid, objid, objsubid) as obj,
pg_describe_object(refclassid, refobjid, refobjsubid) as reference_graph
FROM pg_depend
WHERE refclassid = 'pg_class'::regclass AND
refobjid = 'create_property_graph_tests.g2'::regclass
ORDER BY 1, 2;
pg_describe_object(refclassid, refobjid, refobjsubid) as refobj
FROM deps_tree ORDER BY 1, 2;
SELECT (pg_identify_object_as_address(classid, objid, objsubid)).*
FROM pg_depend
WHERE refclassid = 'pg_class'::regclass AND
refobjid = 'create_property_graph_tests.g2'::regclass
FROM (SELECT DISTINCT classid, objid, objsubid FROM deps_tree)
ORDER BY 1, 2, 3;
SELECT (pg_identify_object(classid, objid, objsubid)).*
FROM pg_depend
WHERE refclassid = 'pg_class'::regclass AND
refobjid = 'create_property_graph_tests.g2'::regclass
FROM (SELECT DISTINCT classid, objid, objsubid FROM deps_tree)
ORDER BY 1, 2, 3, 4;
\a\t

View file

@ -143,6 +143,21 @@ create user mapping for regress_evt_user server useless_server;
alter default privileges for role regress_evt_user
revoke delete on tables from regress_evt_user;
-- DROP PROPERTY GRAPH should work with event trigger in place
CREATE TABLE tv1 (a int PRIMARY KEY, b text);
CREATE TABLE tv2 (i int PRIMARY KEY, j text);
CREATE TABLE te1 (p int PRIMARY KEY, a int REFERENCES tv1(a), b int REFERENCES tv2(i), q text);
CREATE PROPERTY GRAPH gx
VERTEX TABLES (
tv1 LABEL l1 PROPERTIES (b AS p1),
tv2 LABEL l2 PROPERTIES (j AS p1))
EDGE TABLES (te1 SOURCE tv1 DESTINATION tv2 LABEL e1 PROPERTIES (q as p1));
ALTER PROPERTY GRAPH gx ALTER EDGE TABLE te1 ALTER LABEL e1 DROP PROPERTIES (p1);
DROP PROPERTY GRAPH gx;
DROP TABLE tv1, tv2, te1;
-- alter owner to non-superuser should fail
alter event trigger regress_event_trigger owner to regress_evt_user;

View file

@ -67,7 +67,8 @@ DECLARE
BEGIN
FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
('toast table column'), ('view column'), ('materialized view column'),
('property graph element'), ('property graph label'), ('property graph property')
('property graph element'), ('property graph label'), ('property graph property'),
('property graph element label'), ('property graph label property')
LOOP
BEGIN
PERFORM pg_get_object_address(objtype, '{one}', '{}');
@ -284,6 +285,8 @@ WITH objects (classid, objid, objsubid) AS (VALUES
('pg_propgraph_element'::regclass, 0, 0), -- no property graph element
('pg_propgraph_label'::regclass, 0, 0), -- no property graph label
('pg_propgraph_property'::regclass, 0, 0), -- no property graph property
('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label
('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property
('pg_publication'::regclass, 0, 0), -- no publication
('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace
('pg_publication_rel'::regclass, 0, 0), -- no publication relation