Summary
pgsql-deparser drops the partition name entirely from ALTER TABLE ... ATTACH PARTITION and DETACH PARTITION when that name is schema-qualified. The resulting SQL is syntactically invalid. Unqualified names are handled correctly.
This matters in practice because pg_dump always emits schema-qualified names, so any parse → deparse round-trip of a dump containing partitioned tables produces broken SQL.
Versions
pgsql-deparser@18.3.6
plpgsql-parser@18.5.8
libpg-query@18.1.4
- Node 24
Reproduction
import { parse } from 'plpgsql-parser'
import { deparse } from 'pgsql-deparser'
import { loadModule } from 'libpg-query'
await loadModule()
const sql = `ALTER TABLE ONLY public.measurement ATTACH PARTITION public.measurement_y2024 FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');`
console.log(await deparse((await parse(sql)).sql))
Expected
ALTER TABLE ONLY public.measurement ATTACH PARTITION public.measurement_y2024 FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
Actual
ALTER TABLE ONLY public.measurement ATTACH PARTITION FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
The partition name is missing. DETACH is affected the same way:
in : ALTER TABLE ONLY public.measurement DETACH PARTITION public.measurement_y2024;
out: ALTER TABLE ONLY public.measurement DETACH PARTITION ;
Control — the unqualified form is correct:
in : ALTER TABLE ONLY measurement ATTACH PARTITION measurement_y2024 FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
out: ALTER TABLE ONLY measurement ATTACH PARTITION measurement_y2024 FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
The parse tree is correct
The name is present in the AST, so this looks like a deparser-side omission rather than a parser problem:
{"PartitionCmd":{"name":{"schemaname":"public","relname":"measurement_y2024","inh":true,"relpersistence":"p"},
"bound":{"strategy":"r","lowerdatums":[...],"upperdatums":[...]}}}
PartitionCmd.name appears to be rendered by a path that reads relname but not schemaname.
Impact
Silent corruption rather than a loud failure: the statement is emitted, just without its target. In a migration pipeline this either fails to apply or, worse, is skipped as unparseable further downstream.
Summary
pgsql-deparserdrops the partition name entirely fromALTER TABLE ... ATTACH PARTITIONandDETACH PARTITIONwhen that name is schema-qualified. The resulting SQL is syntactically invalid. Unqualified names are handled correctly.This matters in practice because
pg_dumpalways emits schema-qualified names, so any parse → deparse round-trip of a dump containing partitioned tables produces broken SQL.Versions
pgsql-deparser@18.3.6plpgsql-parser@18.5.8libpg-query@18.1.4Reproduction
Expected
Actual
The partition name is missing.
DETACHis affected the same way:Control — the unqualified form is correct:
The parse tree is correct
The name is present in the AST, so this looks like a deparser-side omission rather than a parser problem:
{"PartitionCmd":{"name":{"schemaname":"public","relname":"measurement_y2024","inh":true,"relpersistence":"p"}, "bound":{"strategy":"r","lowerdatums":[...],"upperdatums":[...]}}}PartitionCmd.nameappears to be rendered by a path that readsrelnamebut notschemaname.Impact
Silent corruption rather than a loud failure: the statement is emitted, just without its target. In a migration pipeline this either fails to apply or, worse, is skipped as unparseable further downstream.