On 25.02.26 09:28, Ashutosh Bapat wrote:
Thanks for committing those patches. Here's a patchset rebased on top
of these commits.

0001 is the same as earlier 0001, but with a conflict in
pg_overexplain.sql/.out resolved. It needs 0002 so that a property
graph can be used in the GRAPH_TABLE clause.
0002 is your patch to add parserOpenPropGraph() with the typo and
comment fixed as mentioned above. It should be squashed into 0001 in
the next patchset.
pg_overexplain failed on CI because of new overexplain fields. Here's
a patchset fixing the failure by adding those fields to the graph
table query in pg_overexplain.

Here are some additional patches for fixups and some bug fixes to apply on top.

Some additional comments:

- In parse_graphtable.c, maybe some of the functions could have more verbose comments, like what is the input structure, what is the output structure, what does it check for. Consider for example transformLabelExpr().

- The structure GraphTableParseState is completely undocumented. Also, I don't think it belongs into nodes/parsenodes.h. Maybe better in parser/parse_node.h, where ParseState is also?

- Let's remove the debug elog(INFO) in rewriteGraphTable().

- In some cases in rewriteGraphTable.c(), it's not clear to me whether the elog should be a user-facing ereport, for example in generate_queries_for_path_pattern(). Although if there is an invalid path pattern structure, this should be handled in the parser already?

- Also, check the error message style: no initial capital letter, no period, "can not" -> "cannot".

- The difference between get_gep_kind_name() and get_graph_elem_kind_name() is unclear and confusing. Should they be the same?

Also, for this kind of internal error:

elog(ERROR, "unsupported element pattern kind: \"%s\"", get_gep_kind_name(gep->kind))

we should just print the raw gep->kind. (If it's unsupported, chances are that it's not even something that get_gep_kind_name() can translate.)
From 5d80213547ffbdb16709cd718f3ddf724d85731f Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 25 Feb 2026 12:04:36 +0100
Subject: [PATCH 01/10] Add BEGIN_CATALOG_STRUCT/END_CATALOG_STRUCT

see commit ecae0972523
---
 src/include/catalog/pg_propgraph_element.h        | 4 ++++
 src/include/catalog/pg_propgraph_element_label.h  | 4 ++++
 src/include/catalog/pg_propgraph_label.h          | 4 ++++
 src/include/catalog/pg_propgraph_label_property.h | 4 ++++
 src/include/catalog/pg_propgraph_property.h       | 4 ++++
 5 files changed, 20 insertions(+)

diff --git a/src/include/catalog/pg_propgraph_element.h 
b/src/include/catalog/pg_propgraph_element.h
index a1c7c07013d..2f8af537691 100644
--- a/src/include/catalog/pg_propgraph_element.h
+++ b/src/include/catalog/pg_propgraph_element.h
@@ -25,6 +25,8 @@
  *             typedef struct FormData_pg_propgraph_element
  * ----------------
  */
+BEGIN_CATALOG_STRUCT
+
 CATALOG(pg_propgraph_element,8299,PropgraphElementRelationId)
 {
        Oid                     oid;
@@ -86,6 +88,8 @@ CATALOG(pg_propgraph_element,8299,PropgraphElementRelationId)
 #endif
 } FormData_pg_propgraph_element;
 
+END_CATALOG_STRUCT
+
 /* ----------------
  *             Form_pg_propgraph_element corresponds to a pointer to a tuple 
with
  *             the format of pg_propgraph_element relation.
diff --git a/src/include/catalog/pg_propgraph_element_label.h 
b/src/include/catalog/pg_propgraph_element_label.h
index 092fc60f47b..afd1533cadd 100644
--- a/src/include/catalog/pg_propgraph_element_label.h
+++ b/src/include/catalog/pg_propgraph_element_label.h
@@ -24,6 +24,8 @@
  *             typedef struct FormData_pg_propgraph_element_label
  * ----------------
  */
+BEGIN_CATALOG_STRUCT
+
 CATALOG(pg_propgraph_element_label,8305,PropgraphElementLabelRelationId)
 {
        Oid                     oid;
@@ -35,6 +37,8 @@ 
CATALOG(pg_propgraph_element_label,8305,PropgraphElementLabelRelationId)
        Oid                     pgelelid BKI_LOOKUP(pg_propgraph_element);
 } FormData_pg_propgraph_element_label;
 
+END_CATALOG_STRUCT
+
 /* ----------------
  *             Form_pg_propgraph_element_label corresponds to a pointer to a 
tuple with
  *             the format of pg_propgraph_element_label relation.
diff --git a/src/include/catalog/pg_propgraph_label.h 
b/src/include/catalog/pg_propgraph_label.h
index 54e51ed2579..5c78bfa1b19 100644
--- a/src/include/catalog/pg_propgraph_label.h
+++ b/src/include/catalog/pg_propgraph_label.h
@@ -24,6 +24,8 @@
  *             typedef struct FormData_pg_propgraph_label
  * ----------------
  */
+BEGIN_CATALOG_STRUCT
+
 CATALOG(pg_propgraph_label,8303,PropgraphLabelRelationId)
 {
        Oid                     oid;
@@ -35,6 +37,8 @@ CATALOG(pg_propgraph_label,8303,PropgraphLabelRelationId)
        NameData        pgllabel;
 } FormData_pg_propgraph_label;
 
+END_CATALOG_STRUCT
+
 /* ----------------
  *             Form_pg_propgraph_label corresponds to a pointer to a tuple with
  *             the format of pg_propgraph_label relation.
diff --git a/src/include/catalog/pg_propgraph_label_property.h 
b/src/include/catalog/pg_propgraph_label_property.h
index 79d20fc353a..39d55bf68a4 100644
--- a/src/include/catalog/pg_propgraph_label_property.h
+++ b/src/include/catalog/pg_propgraph_label_property.h
@@ -24,6 +24,8 @@
  *             typedef struct FormData_pg_propgraph_label_property
  * ----------------
  */
+BEGIN_CATALOG_STRUCT
+
 CATALOG(pg_propgraph_label_property,8318,PropgraphLabelPropertyRelationId)
 {
        Oid                     oid;
@@ -42,6 +44,8 @@ 
CATALOG(pg_propgraph_label_property,8318,PropgraphLabelPropertyRelationId)
 #endif
 } FormData_pg_propgraph_label_property;
 
+END_CATALOG_STRUCT
+
 /* ----------------
  *             Form_pg_propgraph_label_property corresponds to a pointer to a 
tuple with
  *             the format of pg_propgraph_label_property relation.
diff --git a/src/include/catalog/pg_propgraph_property.h 
b/src/include/catalog/pg_propgraph_property.h
index 5f93dbfa6c5..72beafbbf15 100644
--- a/src/include/catalog/pg_propgraph_property.h
+++ b/src/include/catalog/pg_propgraph_property.h
@@ -24,6 +24,8 @@
  *             typedef struct FormData_pg_propgraph_property
  * ----------------
  */
+BEGIN_CATALOG_STRUCT
+
 CATALOG(pg_propgraph_property,8306,PropgraphPropertyRelationId)
 {
        Oid                     oid;
@@ -44,6 +46,8 @@ 
CATALOG(pg_propgraph_property,8306,PropgraphPropertyRelationId)
        Oid                     pgpcollation BKI_LOOKUP_OPT(pg_collation);
 } FormData_pg_propgraph_property;
 
+END_CATALOG_STRUCT
+
 /* ----------------
  *             Form_pg_propgraph_property corresponds to a pointer to a tuple 
with
  *             the format of pg_propgraph_property relation.
-- 
2.53.0

From a856ed9cc56337d21cfa171ba271520bf55f828f Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 25 Feb 2026 12:06:15 +0100
Subject: [PATCH 02/10] Use LOCKMODE

syncs with commit aca61f7e5f8
---
 src/backend/parser/parse_clause.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/backend/parser/parse_clause.c 
b/src/backend/parser/parse_clause.c
index ee063f6c409..85904198c05 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -906,7 +906,7 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc 
*rtf)
  * Similar to parserOpenTable() but for property graphs.
  */
 static Relation
-parserOpenPropGraph(ParseState *pstate, const RangeVar *relation, int lockmode)
+parserOpenPropGraph(ParseState *pstate, const RangeVar *relation, LOCKMODE 
lockmode)
 {
        Relation        rel;
        ParseCallbackState pcbstate;
-- 
2.53.0

From f81d94c0cc8aaa54b186adeddb1e23448ea76220 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 25 Feb 2026 08:51:25 +0100
Subject: [PATCH 03/10] Add missing quote_identifier() calls in ruleutils.c

---
 src/backend/utils/adt/ruleutils.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/backend/utils/adt/ruleutils.c 
b/src/backend/utils/adt/ruleutils.c
index b03595a2d50..6193d7715cf 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -1698,7 +1698,7 @@ make_propgraphdef_elements(StringInfo buf, Oid pgrelid, 
char pgekind)
                else
                        appendStringInfo(buf, "        %s AS %s",
                                                         
generate_relation_name(pgeform->pgerelid, NIL),
-                                                        
NameStr(pgeform->pgealias));
+                                                        
quote_identifier(NameStr(pgeform->pgealias)));
 
                datum = heap_getattr(tup, Anum_pg_propgraph_element_pgekey, 
RelationGetDescr(pgerel), &isnull);
                if (!isnull)
@@ -1737,12 +1737,12 @@ make_propgraphdef_elements(StringInfo buf, Oid pgrelid, 
char pgekind)
                        {
                                appendStringInfoString(buf, " KEY (");
                                decompile_column_index_array(srckey, 
pgeform->pgerelid, false, buf);
-                               appendStringInfo(buf, ") REFERENCES %s (", 
NameStr(pgeform2->pgealias));
+                               appendStringInfo(buf, ") REFERENCES %s (", 
quote_identifier(NameStr(pgeform2->pgealias)));
                                decompile_column_index_array(srcref, 
pgeform2->pgerelid, false, buf);
                                appendStringInfoString(buf, ")");
                        }
                        else
-                               appendStringInfo(buf, " %s ", 
NameStr(pgeform2->pgealias));
+                               appendStringInfo(buf, " %s ", 
quote_identifier(NameStr(pgeform2->pgealias)));
                        ReleaseSysCache(tup2);
 
                        appendStringInfoString(buf, " DESTINATION");
@@ -1754,12 +1754,12 @@ make_propgraphdef_elements(StringInfo buf, Oid pgrelid, 
char pgekind)
                        {
                                appendStringInfoString(buf, " KEY (");
                                decompile_column_index_array(destkey, 
pgeform->pgerelid, false, buf);
-                               appendStringInfo(buf, ") REFERENCES %s (", 
NameStr(pgeform2->pgealias));
+                               appendStringInfo(buf, ") REFERENCES %s (", 
quote_identifier(NameStr(pgeform2->pgealias)));
                                decompile_column_index_array(destref, 
pgeform2->pgerelid, false, buf);
                                appendStringInfoString(buf, ")");
                        }
                        else
-                               appendStringInfo(buf, " %s", 
NameStr(pgeform2->pgealias));
+                               appendStringInfo(buf, " %s", 
quote_identifier(NameStr(pgeform2->pgealias)));
                        ReleaseSysCache(tup2);
                }
 
@@ -1915,11 +1915,11 @@ make_propgraphdef_properties(StringInfo buf, Oid 
ellabelid, Oid elrelid)
                                appendStringInfo(buf, ", ");
 
                        if (IsA(expr, Var) && strcmp(propname, 
get_attname(elrelid, castNode(Var, expr)->varattno, false)) == 0)
-                               appendStringInfo(buf, "%s", propname);
+                               appendStringInfo(buf, "%s", 
quote_identifier(propname));
                        else
                                appendStringInfo(buf, "%s AS %s",
                                                                 
deparse_expression_pretty(expr, context, false, false, 0, 0),
-                                                                propname);
+                                                                
quote_identifier(propname));
                }
 
                appendStringInfo(buf, ")");
@@ -8017,7 +8017,7 @@ get_path_pattern_expr_def(List *path_pattern_expr, 
deparse_context *context)
 
                if (gep->variable)
                {
-                       appendStringInfoString(buf, gep->variable);
+                       appendStringInfoString(buf, 
quote_identifier(gep->variable));
                        sep = " ";
                }
 
-- 
2.53.0

From e53dbf81c85e734668d92cc8a20868b39f15ee97 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 25 Feb 2026 09:11:10 +0100
Subject: [PATCH 04/10] Add missing $$ assignment in gram.y

---
 src/backend/parser/gram.y | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index ce63e8b0e63..fc9807985ee 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -17972,6 +17972,8 @@ path_factor:
                                        GraphElementPattern *gep = 
(GraphElementPattern *) $1;
 
                                        gep->quantifier = $2;
+
+                                       $$ = (Node *) gep;
                                }
                ;
 
-- 
2.53.0

From 0c514f0c02e72965d171bcf4dc9ddcf9d2f9a29a Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 25 Feb 2026 09:30:34 +0100
Subject: [PATCH 05/10] Use correct default privileges for property graphs

---
 src/backend/catalog/aclchk.c | 12 ++++++++++++
 src/backend/utils/adt/acl.c  |  4 ++++
 2 files changed, 16 insertions(+)

diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 94a16a6ecf7..52f38480c52 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -1853,11 +1853,20 @@ ExecGrant_Relation(InternalGrant *istmt)
                                         errmsg("\"%s\" is not a sequence",
                                                        
NameStr(pg_class_tuple->relname))));
 
+               if (istmt->objtype == OBJECT_PROPGRAPH &&
+                       pg_class_tuple->relkind != RELKIND_PROPGRAPH)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                                        errmsg("\"%s\" is not a property 
graph",
+                                                       
NameStr(pg_class_tuple->relname))));
+
                /* Adjust the default permissions based on object type */
                if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
                {
                        if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
                                this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
+                       else if (pg_class_tuple->relkind == RELKIND_PROPGRAPH)
+                               this_privileges = ACL_ALL_RIGHTS_PROPGRAPH;
                        else
                                this_privileges = ACL_ALL_RIGHTS_RELATION;
                }
@@ -1951,6 +1960,9 @@ ExecGrant_Relation(InternalGrant *istmt)
                                case RELKIND_SEQUENCE:
                                        old_acl = acldefault(OBJECT_SEQUENCE, 
ownerId);
                                        break;
+                               case RELKIND_PROPGRAPH:
+                                       old_acl = acldefault(OBJECT_PROPGRAPH, 
ownerId);
+                                       break;
                                default:
                                        old_acl = acldefault(OBJECT_TABLE, 
ownerId);
                                        break;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 641673f0b0e..a1c0b033ff6 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -868,6 +868,10 @@ acldefault(ObjectType objtype, Oid ownerId)
                        world_default = ACL_NO_RIGHTS;
                        owner_default = ACL_ALL_RIGHTS_PARAMETER_ACL;
                        break;
+               case OBJECT_PROPGRAPH:
+                       world_default = ACL_NO_RIGHTS;
+                       owner_default = ACL_ALL_RIGHTS_PROPGRAPH;
+                       break;
                default:
                        elog(ERROR, "unrecognized object type: %d", (int) 
objtype);
                        world_default = ACL_NO_RIGHTS;  /* keep compiler quiet 
*/
-- 
2.53.0

From da81c35a9a41132cbad62d9ff825d239556c49f7 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 25 Feb 2026 09:36:45 +0100
Subject: [PATCH 06/10] Record dependency of property on collation

---
 src/backend/commands/propgraphcmds.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/backend/commands/propgraphcmds.c 
b/src/backend/commands/propgraphcmds.c
index 5bc36dc1d68..deedb313c76 100644
--- a/src/backend/commands/propgraphcmds.c
+++ b/src/backend/commands/propgraphcmds.c
@@ -954,6 +954,11 @@ insert_property_record(Oid graphid, Oid ellabeloid, Oid 
pgerelid, const char *pr
                recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
                ObjectAddressSet(referenced, TypeRelationId, exprtypid);
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+               if (OidIsValid(exprcollation) && exprcollation != 
DEFAULT_COLLATION_OID)
+               {
+                       ObjectAddressSet(referenced, CollationRelationId, 
exprcollation);
+                       recordDependencyOn(&myself, &referenced, 
DEPENDENCY_NORMAL);
+               }
 
                table_close(rel, NoLock);
        }
-- 
2.53.0

From 951405125fb5428c9ddca6d873dc6adc9156778d Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 25 Feb 2026 10:06:33 +0100
Subject: [PATCH 07/10] Check for duplicate alias in ALTER PROPERTY GRAPH

This would previously still fail with a unique index violation, but
this gives a better error message.
---
 src/backend/commands/propgraphcmds.c           | 18 ++++++++++++++++++
 .../regress/expected/create_property_graph.out |  4 ++++
 src/test/regress/sql/create_property_graph.sql |  2 +-
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/src/backend/commands/propgraphcmds.c 
b/src/backend/commands/propgraphcmds.c
index deedb313c76..45d2ff1bbba 100644
--- a/src/backend/commands/propgraphcmds.c
+++ b/src/backend/commands/propgraphcmds.c
@@ -1341,6 +1341,15 @@ AlterPropGraph(ParseState *pstate, const 
AlterPropGraphStmt *stmt)
 
                table_close(rel, NoLock);
 
+               if (SearchSysCacheExists2(PROPGRAPHELALIAS,
+                                                                 
ObjectIdGetDatum(pgrelid),
+                                                                 
CStringGetDatum(vinfo->aliasname)))
+                       ereport(ERROR,
+                                       
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                       errmsg("alias \"%s\" already exists in 
property graph \"%s\"",
+                                                  vinfo->aliasname, 
stmt->pgname->relname),
+                                       parser_errposition(pstate, 
vertex->vtable->location));
+
                peoid = insert_element_record(pgaddress, vinfo);
 
                CommandCounterIncrement();
@@ -1401,6 +1410,15 @@ AlterPropGraph(ParseState *pstate, const 
AlterPropGraphStmt *stmt)
 
                table_close(rel, NoLock);
 
+               if (SearchSysCacheExists2(PROPGRAPHELALIAS,
+                                                                 
ObjectIdGetDatum(pgrelid),
+                                                                 
CStringGetDatum(einfo->aliasname)))
+                       ereport(ERROR,
+                                       
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                       errmsg("alias \"%s\" already exists in 
property graph \"%s\"",
+                                                  einfo->aliasname, 
stmt->pgname->relname),
+                                       parser_errposition(pstate, 
edge->etable->location));
+
                peoid = insert_element_record(pgaddress, einfo);
 
                CommandCounterIncrement();
diff --git a/src/test/regress/expected/create_property_graph.out 
b/src/test/regress/expected/create_property_graph.out
index 95e34336f4e..ffc263cdb77 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -114,6 +114,10 @@ CREATE PROPERTY GRAPH gx VERTEX TABLES (t1 KEY (a), t2 KEY 
(i), t1 KEY (a));
 ERROR:  alias "t1" used more than once as element table
 LINE 1: ...Y GRAPH gx VERTEX TABLES (t1 KEY (a), t2 KEY (i), t1 KEY (a)...
                                                              ^
+ALTER PROPERTY GRAPH g3 ADD VERTEX TABLES (t3 KEY (x));  -- duplicate alias
+ERROR:  alias "t3" already exists in property graph "g3"
+LINE 1: ALTER PROPERTY GRAPH g3 ADD VERTEX TABLES (t3 KEY (x));
+                                                   ^
 CREATE PROPERTY GRAPH gx
     VERTEX TABLES (t1 AS tt KEY (a), t2 KEY (i))
     EDGE TABLES (
diff --git a/src/test/regress/sql/create_property_graph.sql 
b/src/test/regress/sql/create_property_graph.sql
index a976905c5ee..5c2ced14753 100644
--- a/src/test/regress/sql/create_property_graph.sql
+++ b/src/test/regress/sql/create_property_graph.sql
@@ -94,6 +94,7 @@ CREATE PROPERTY GRAPH g5
 CREATE UNLOGGED PROPERTY GRAPH gx VERTEX TABLES (xx, yy);
 CREATE PROPERTY GRAPH gx VERTEX TABLES (xx, yy);
 CREATE PROPERTY GRAPH gx VERTEX TABLES (t1 KEY (a), t2 KEY (i), t1 KEY (a));
+ALTER PROPERTY GRAPH g3 ADD VERTEX TABLES (t3 KEY (x));  -- duplicate alias
 CREATE PROPERTY GRAPH gx
     VERTEX TABLES (t1 AS tt KEY (a), t2 KEY (i))
     EDGE TABLES (
@@ -168,7 +169,6 @@ CREATE PROPERTY GRAPH gx
 ALTER PROPERTY GRAPH g4 ALTER VERTEX TABLE t1 ADD LABEL t3l1 PROPERTIES (a AS 
x, b AS zz);  -- mismatching property names on label
 ALTER PROPERTY GRAPH g4 ALTER VERTEX TABLE t1 ADD LABEL t3l1 PROPERTIES (a AS 
x);  -- mismatching number of properties on label
 
-
 ALTER PROPERTY GRAPH g1 OWNER TO regress_graph_user1;
 SET ROLE regress_graph_user1;
 GRANT SELECT ON PROPERTY GRAPH g1 TO regress_graph_user2;
-- 
2.53.0

From 22270b7e8051a19435e9db5c5a7bf02c235fb1a6 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 25 Feb 2026 10:41:48 +0100
Subject: [PATCH 08/10] Fix dumping of property graph privileges

---
 src/bin/pg_dump/dumputils.c      |  3 +++
 src/bin/pg_dump/pg_dump.c        | 16 ++++++++++++++--
 src/bin/pg_dump/t/002_pg_dump.pl | 16 ++++++++++++++++
 3 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index 5bc77fed974..dfb1f603a43 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -510,6 +510,9 @@ do { \
                /* UPDATE */
                CONVERT_PRIV('w', "UPDATE");
        }
+       else if (strcmp(type, "PROPERTY GRAPH") == 0 ||
+                        strcmp(type, "PROPERTY GRAPHS") == 0)
+               CONVERT_PRIV('r', "SELECT");
        else if (strcmp(type, "FUNCTION") == 0 ||
                         strcmp(type, "FUNCTIONS") == 0)
                CONVERT_PRIV('X', "EXECUTE");
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 73a860378b2..36284c71ddd 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -16904,8 +16904,20 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
        namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
        if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
        {
-               const char *objtype =
-                       (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : 
"TABLE";
+               const char *objtype;
+
+               switch (tbinfo->relkind)
+               {
+                       case RELKIND_SEQUENCE:
+                               objtype = "SEQUENCE";
+                               break;
+                       case RELKIND_PROPGRAPH:
+                               objtype = "PROPERTY GRAPH";
+                               break;
+                       default:
+                               objtype = "TABLE";
+                               break;
+               }
 
                tableAclDumpId =
                        dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index 0ddf4acb754..b18aae7bd67 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -4455,6 +4455,22 @@
                },
        },
 
+       'GRANT SELECT ON PROPERTY GRAPH propgraph' => {
+               create_order => 21,
+               create_sql =>
+                 'GRANT SELECT ON PROPERTY GRAPH dump_test.propgraph TO 
regress_dump_test_role;',
+               regexp => qr/^
+                       \QGRANT ALL ON PROPERTY GRAPH dump_test.propgraph TO 
regress_dump_test_role;\E
+                       /xm,
+               like =>
+                 { %full_runs, %dump_test_schema_runs, section_pre_data => 1, 
},
+               unlike => {
+                       exclude_dump_test_schema => 1,
+                       no_privs => 1,
+                       only_dump_measurement => 1,
+               },
+       },
+
        'GRANT EXECUTE ON FUNCTION pg_sleep() TO regress_dump_test_role' => {
                create_order => 16,
                create_sql => 'GRANT EXECUTE ON FUNCTION pg_sleep(float8)
-- 
2.53.0

From 884af67957c542a74bd739b78f4292d9afea028f Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 25 Feb 2026 10:57:51 +0100
Subject: [PATCH 09/10] Check for A_Star in transformGraphTablePropertyRef()

---
 src/backend/parser/parse_graphtable.c     | 6 ++++++
 src/test/regress/expected/graph_table.out | 5 +++++
 src/test/regress/sql/graph_table.sql      | 2 ++
 3 files changed, 13 insertions(+)

diff --git a/src/backend/parser/parse_graphtable.c 
b/src/backend/parser/parse_graphtable.c
index 0682f27f359..d4fc12f8d02 100644
--- a/src/backend/parser/parse_graphtable.c
+++ b/src/backend/parser/parse_graphtable.c
@@ -50,6 +50,12 @@ transformGraphTablePropertyRef(ParseState *pstate, ColumnRef 
*cref)
                char       *elvarname;
                char       *propname;
 
+               if (IsA(field1, A_Star) || IsA(field2, A_Star))
+                       ereport(ERROR,
+                                       errcode(ERRCODE_SYNTAX_ERROR),
+                                       errmsg("\"*\" not allowed here"),
+                                       parser_errposition(pstate, 
cref->location));
+
                elvarname = strVal(field1);
                propname = strVal(field2);
 
diff --git a/src/test/regress/expected/graph_table.out 
b/src/test/regress/expected/graph_table.out
index 547a6b50916..5029d2a7ef7 100644
--- a/src/test/regress/expected/graph_table.out
+++ b/src/test/regress/expected/graph_table.out
@@ -404,6 +404,11 @@ SELECT * FROM GRAPH_TABLE (g1 MATCH (src IS 
el1)-[conn]->(dest) COLUMNS (conn.en
 ERROR:  can not find label "el1" in property graph "g1" for element type 
"vertex"
 SELECT * FROM GRAPH_TABLE (g1 MATCH (src IS el1 | vl1)-[conn]->(dest) COLUMNS 
(conn.ename AS cename));
 ERROR:  can not find label "el1" in property graph "g1" for element type 
"vertex"
+-- star in property reference
+SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.address = 
'US')-[IS customer_orders]->(o IS orders) COLUMNS (c.*));
+ERROR:  "*" not allowed here
+LINE 1: ... = 'US')-[IS customer_orders]->(o IS orders) COLUMNS (c.*));
+                                                                 ^
 -- select all the properties across all the labels associated with a given type
 -- of graph element
 SELECT * FROM GRAPH_TABLE (g1 MATCH (src)-[conn]->(dest) COLUMNS (src.vname AS 
svname, conn.ename AS cename, dest.vname AS dvname, src.vprop1 AS svp1, 
src.vprop2 AS svp2, src.lprop1 AS slp1, dest.vprop1 AS dvp1, dest.vprop2 AS 
dvp2, dest.lprop1 AS dlp1, conn.eprop1 AS cep1, conn.lprop2 AS clp2));
diff --git a/src/test/regress/sql/graph_table.sql 
b/src/test/regress/sql/graph_table.sql
index d94f88ad619..443947ca77e 100644
--- a/src/test/regress/sql/graph_table.sql
+++ b/src/test/regress/sql/graph_table.sql
@@ -283,6 +283,8 @@ CREATE PROPERTY GRAPH g1
 -- el1 is associated with only edges, and cannot qualify a vertex
 SELECT * FROM GRAPH_TABLE (g1 MATCH (src IS el1)-[conn]->(dest) COLUMNS 
(conn.ename AS cename));
 SELECT * FROM GRAPH_TABLE (g1 MATCH (src IS el1 | vl1)-[conn]->(dest) COLUMNS 
(conn.ename AS cename));
+-- star in property reference
+SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.address = 
'US')-[IS customer_orders]->(o IS orders) COLUMNS (c.*));
 
 -- select all the properties across all the labels associated with a given type
 -- of graph element
-- 
2.53.0

From d8672633f3ca2ce3d7c9aedc0a59e108528bca2f Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 25 Feb 2026 11:05:53 +0100
Subject: [PATCH 10/10] Add error location and improve error code

---
 src/backend/parser/parse_graphtable.c     | 5 +++--
 src/test/regress/expected/graph_table.out | 2 ++
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/backend/parser/parse_graphtable.c 
b/src/backend/parser/parse_graphtable.c
index d4fc12f8d02..dcaf15bd44f 100644
--- a/src/backend/parser/parse_graphtable.c
+++ b/src/backend/parser/parse_graphtable.c
@@ -68,8 +68,9 @@ transformGraphTablePropertyRef(ParseState *pstate, ColumnRef 
*cref)
                        pgptup = SearchSysCache2(PROPGRAPHPROPNAME, 
ObjectIdGetDatum(gpstate->graphid), CStringGetDatum(propname));
                        if (!HeapTupleIsValid(pgptup))
                                ereport(ERROR,
-                                               errcode(ERRCODE_SYNTAX_ERROR),
-                                               errmsg("property \"%s\" does 
not exist", propname));
+                                               
errcode(ERRCODE_UNDEFINED_OBJECT),
+                                               errmsg("property \"%s\" does 
not exist", propname),
+                                               parser_errposition(pstate, 
cref->location));
                        pgpform = (Form_pg_propgraph_property) 
GETSTRUCT(pgptup);
 
                        gpr->location = cref->location;
diff --git a/src/test/regress/expected/graph_table.out 
b/src/test/regress/expected/graph_table.out
index 5029d2a7ef7..565c7caea82 100644
--- a/src/test/regress/expected/graph_table.out
+++ b/src/test/regress/expected/graph_table.out
@@ -87,6 +87,8 @@ LINE 1: ...US')-[IS customer_orders]->(o IS orders) COLUMNS 
(cx.name AS...
                                                              ^
 SELECT customer_name FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE 
c.address = 'US')-[IS customer_orders]->(o IS orders) COLUMNS (c.namex AS 
customer_name));  -- error
 ERROR:  property "namex" does not exist
+LINE 1: ...US')-[IS customer_orders]->(o IS orders) COLUMNS (c.namex AS...
+                                                             ^
 SELECT customer_name FROM GRAPH_TABLE (myshop MATCH (c IS customers|employees 
WHERE c.address = 'US')-[IS customer_orders]->(o IS orders) COLUMNS (c.name AS 
customer_name));  -- error
 ERROR:  label "employees" does not exist in property graph "myshop"
 SELECT customer_name FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE 
c.address = 'US')-[IS customer_orders] COLUMNS (c.name AS customer_name));  -- 
error
-- 
2.53.0

Reply via email to