On 2026-08-23 Su 4:41 AM, Taha Naveed wrote:
Hi,

I also encountered an issue with pg_get_propgraphdef() and pg_dump.

CREATE TABLE wr (
    id int PRIMARY KEY,
    x text
);

CREATE PROPERTY GRAPH gwr
    VERTEX TABLES (
        wr PROPERTIES (wr AS whole)
    );

SELECT pg_get_propgraphdef('gwr'::regclass);
ERROR:  cache lookup failed for attribute 0 of relation ...

The graph itself works, and the whole row property can be queried through GRAPH_TABLE. However, pg_dump also fails because it calls pg_get_propgraphdef().
Reproduced this on PG 19beta3 as well as current master.



Hi Andres, Taha,

I ran a broader audit using Opus 5 off the back of this thread and can confirm essentially everything reported here, including Taha's whole-row crash (that one's a one-line guard — get_attname() needs varattno > 0 before
the shortcut, ruleutils.c:1951).

Two further issues, both more urgent than the dump problems since neither needs any privilege on the underlying tables:

- AlterPropGraph() never checks its target is actually a property graph. ALTER PROPERTY GRAPH <any table/view/index/sequence you own> ADD VERTEX TABLES (...) succeeds and writes catalog rows nobody can read
  back.
- GRAPH_TABLE's rewriter enumerates the full cartesian product of candidate paths with no bound on breadth. A short EXPLAIN over a middling multi-element pattern — SELECT on someone else's graph is enough, or   just the default TEMP privilege — can OOM the backend bringing down the postmaster. That one probably belongs first in the queue.

Repro for that one:

 CREATE TEMP TABLE z (id int primary key, s int, t int);
  ALTER TABLE z ADD CONSTRAINT zfk FOREIGN KEY (s) REFERENCES z(id);

  CREATE PROPERTY GRAPH gz
    VERTEX TABLES (z AS v1, z AS v2, z AS v3, z AS v4)
    EDGE TABLES (z AS e1 KEY (id) SOURCE KEY (s) REFERENCES v1 (id) DESTINATION KEY (t) REFERENCES v1 (id),                  z AS e2 KEY (id) SOURCE KEY (s) REFERENCES v2 (id) DESTINATION KEY (t) REFERENCES v2 (id),                  z AS e3 KEY (id) SOURCE KEY (s) REFERENCES v3 (id) DESTINATION KEY (t) REFERENCES v3 (id),                  z AS e4 KEY (id) SOURCE KEY (s) REFERENCES v4 (id) DESTINATION KEY (t) REFERENCES v4 (id));

  EXPLAIN (COSTS OFF) SELECT count(*) FROM GRAPH_TABLE (gz MATCH
(a1)-[b1]->(a2)-[b2]->(a3)-[b3]->(a4)-[b4]->(a5)-[b5]->(a6) COLUMNS (a1.id AS c1));

On the AI-assisted items in Andres' third message: the correctness bugs behind all four hold up, but the privilege-escalation framing attached to each doesn't survive inspection. No surviving orphan row carries a relation OID; ExecCheckPermissions() reruns on every execution, so the relcache-invalidation gap is a plan-staleness issue, not an auth one; the cross-label lookup is keyed by (elemoid, propid) and can't cross tables; and replacing a cast or operator already requires owning the type. Real bugs, not exploitable ones.

On Andres' original question — the pg_attribute rows do look vestigial. heap.c already carves the rowtype out for propgraphs (and toast tables, sequences); nobody made the matching carve-out for attributes. Keeping the pg_class representation overall seems right (the ACL and relcache-invalidation reuse pays for itself), but three targeted fixes — the attribute carve-out, a propgraph_open() along the lines Ashutosh floated and dropped upthread, and giving pg_dump its own dump-object type instead of riding on DO_TABLE — would close most of what's turned up here, ordering bug included.


cheers

andrew

--
Andrew Dunstan
EDB: https://www.enterprisedb.com



Reply via email to