Summary
pgsql-deparser drops the optional column list from ON DELETE SET NULL (...) and ON DELETE SET DEFAULT (...). The output is still valid SQL, but it means something different from the input — the referential action is silently widened from specific columns to all foreign key columns.
The column list on SET NULL / SET DEFAULT was added in PostgreSQL 15.
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 child ADD CONSTRAINT child_fk FOREIGN KEY (a, b) REFERENCES parent(a, b) ON DELETE SET NULL (b);`
console.log(await deparse((await parse(sql)).sql))
Expected
ALTER TABLE ONLY child ADD CONSTRAINT child_fk FOREIGN KEY (a, b) REFERENCES parent (a, b) ON DELETE SET NULL (b);
Actual
ALTER TABLE ONLY child ADD CONSTRAINT child_fk FOREIGN KEY(a, b) REFERENCES parent (a, b) ON DELETE SET NULL;
SET DEFAULT behaves the same way:
in : ... ON DELETE SET DEFAULT (b);
out: ... ON DELETE SET DEFAULT;
The parse tree is correct
Constraint keys: contype, conname, is_enforced, initially_valid, pktable,
fk_attrs, pk_attrs, fk_matchtype, fk_upd_action,
fk_del_action, fk_del_set_cols, location
fk_del_set_cols: [{"String":{"sval":"b"}}]
fk_del_action : "n"
fk_del_set_cols is populated but does not appear to be consulted when rendering the ON DELETE clause.
Impact
This one is quiet — the output parses and applies cleanly, so nothing surfaces at apply time. The difference only shows up later, when a delete nulls more columns than the original schema intended.
Summary
pgsql-deparserdrops the optional column list fromON DELETE SET NULL (...)andON DELETE SET DEFAULT (...). The output is still valid SQL, but it means something different from the input — the referential action is silently widened from specific columns to all foreign key columns.The column list on
SET NULL/SET DEFAULTwas added in PostgreSQL 15.Versions
pgsql-deparser@18.3.6plpgsql-parser@18.5.8libpg-query@18.1.4Reproduction
Expected
Actual
SET DEFAULTbehaves the same way:The parse tree is correct
fk_del_set_colsis populated but does not appear to be consulted when rendering theON DELETEclause.Impact
This one is quiet — the output parses and applies cleanly, so nothing surfaces at apply time. The difference only shows up later, when a delete nulls more columns than the original schema intended.