themiguelamador opened a new issue, #2503:
URL: https://github.com/apache/age/issues/2503
### Summary
After `pg_dump` + restore of a database containing a graph, **every Cypher
query fails** with `graph with oid N does not exist`, even though the restore
reports no errors and all label tables and rows arrive intact.
The cause is that `ag_catalog.ag_graph` stores the graph's namespace
**twice, in two different types**, and only one of them survives a logical dump:
| Column | Type | Survives `pg_dump`/restore? |
| --- | --- | --- |
| `ag_graph.namespace` | `regnamespace` | ✅ dumped as the schema **name**,
re-resolves to the new oid |
| `ag_label.relation` | `regclass` | ✅ dumped as the table **name**,
re-resolves |
| `ag_graph.graphid` | `oid` | ❌ dumped as a bare integer — still the
**source** database's namespace oid |
| `ag_label.graph` | `oid` | ❌ same, and FK-bound to `graphid` |
`cypher()` resolves the graph through `graphid`, so it looks for a namespace
oid that only ever existed in the source cluster.
The failure is **silent at restore time** — `psql -f dump.sql` exits with 0
errors. The first symptom is every query failing later.
### Reproduction
AGE 1.5.0, PostgreSQL 16.9 (Debian 16.9-1.pgdg120+1), aarch64.
```sql
-- source database
CREATE EXTENSION IF NOT EXISTS age;
LOAD 'age';
SET search_path = ag_catalog, "$user", public;
SELECT create_graph('demo');
SELECT * FROM cypher('demo', $$ CREATE (:P {name: 'a'}) $$) AS (v agtype);
SELECT * FROM cypher('demo', $$ MATCH (n:P) RETURN n.name $$) AS (name
agtype); -- "a"
```
```bash
pg_dump -U postgres -d age_repro_src -f age_repro.sql
createdb -U postgres age_repro_dst
psql -U postgres -d age_repro_dst -f age_repro.sql # 0 errors
```
```sql
-- restored database
SELECT name, graphid, namespace::oid AS namespace_oid, graphid =
namespace::oid AS healthy
FROM ag_catalog.ag_graph;
-- name | graphid | namespace_oid | healthy
-- demo | 5616016 | 5616051 | f
SELECT count(*) FROM demo."P"; -- 1 (data restored fine)
LOAD 'age';
SET search_path = ag_catalog, "$user", public;
SELECT * FROM cypher('demo', $$ MATCH (n:P) RETURN n.name $$) AS (name
agtype);
-- ERROR: graph with oid 5616016 does not exist
```
### Expected
Cypher queries work against a restored database, as they do against the
original.
### Workaround
The correct oid is already present in the same row, as `namespace::oid`, so
the catalog can be repaired without consulting `pg_namespace`. `ag_label` must
be updated first (it joins on the old `graphid`), and `fk_graph_oid` is not
deferrable, so it has to be dropped for the duration:
```sql
BEGIN;
ALTER TABLE ag_catalog.ag_label DROP CONSTRAINT fk_graph_oid;
UPDATE ag_catalog.ag_label l
SET graph = g.namespace::oid
FROM ag_catalog.ag_graph g
WHERE l.graph = g.graphid
AND g.graphid IS DISTINCT FROM g.namespace::oid;
UPDATE ag_catalog.ag_graph
SET graphid = namespace::oid
WHERE graphid IS DISTINCT FROM namespace::oid;
ALTER TABLE ag_catalog.ag_label
ADD CONSTRAINT fk_graph_oid FOREIGN KEY (graph) REFERENCES
ag_catalog.ag_graph (graphid);
COMMIT;
```
Verified on both the minimal case above and a ~1.3 GB production snapshot (2
graphs, 18 label tables, 6188 edges): Cypher works again afterwards and the
statements are idempotent.
### Possible fixes
1. **Type `graphid` as `regnamespace`** (and `ag_label.graph` to match), so
`pg_dump` emits names and PostgreSQL re-resolves them — the same mechanism that
already makes `namespace` and `relation` correct. Requires a catalog migration
for existing installs.
2. **Drop the redundant column** and resolve the graph through `namespace`
(already `regnamespace`), since the two are meant to hold the same value.
3. **Self-heal on load**, treating `namespace::oid` as authoritative when
the two disagree.
4. At minimum, **detect and report**: a mismatch could raise something like
`graph "demo" has a stale graphid (restored from a dump?)` instead of an oid
that means nothing to the user.
Happy to open a PR for whichever direction maintainers prefer.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]