-
Notifications
You must be signed in to change notification settings - Fork 38
CHECK (FALSE) NO INHERIT constraints silently dropped during plan/apply #386
Description
Summary
CHECK constraints that reference no columns (e.g., CHECK (FALSE) NO INHERIT)
are silently dropped during schema introspection.
They never appear in the generated plan and are absent from the applied schema.
Reproduction
-- schema.sql
CREATE TABLE parent_base (
id UUID PRIMARY KEY,
name TEXT NOT NULL,
CONSTRAINT no_direct_insert CHECK (FALSE) NO INHERIT
);
CREATE TABLE child (
CONSTRAINT child_pkey PRIMARY KEY (id)
) INHERITS (parent_base);pgschema plan --schema public --file schema.sql --output-human stdoutExpected: plan includes no_direct_insert constraint on parent_base.
Actual: no_direct_insert is absent from the plan output.
After apply, the constraint does not exist in the database:
SELECT conname, pg_get_constraintdef(oid, true)
FROM pg_constraint
WHERE conrelid = 'parent_base'::regclass AND contype = 'c';
-- no_direct_insert is missingBackground
CHECK (FALSE) NO INHERIT is a standard PostgreSQL pattern to prevent
direct INSERTs into a parent table while allowing child tables
(via INHERITS) to accept inserts normally.
The NO INHERIT modifier ensures the always-false check
is not inherited by children.
Root cause
In ir/inspector.go, the constraint introspection loop skips
any constraint where the joined column name is empty:
// ir/inspector.go:455-457
if columnName == "" || columnName == "<nil>" {
continue // Skip constraints without columns
}The introspection query joins pg_constraint with pg_attribute
via a.attnum = ANY(c.conkey).
For CHECK (FALSE), conkey is an empty array ({}),
so the LEFT JOIN produces a row with NULL for attname.
The guard above then skips the entire constraint.
This means any CHECK constraint that does not reference a column
is silently excluded from the IR
and never appears in plans or applied schemas.
Additional note: NO INHERIT modifier not preserved
Even if the column-less constraint were included in the IR,
there is a secondary issue:
- The
Constraintstruct has no field forconnoinherit/NO INHERIT. - The introspection query does not read
connoinheritfrompg_constraint. normalizeCheckClausedoes not handle theNO INHERITsuffix
returned bypg_get_constraintdef.
As a result, NO INHERIT information would be lost
even if the constraint itself were retained.
Environment
- pgschema v1.7.4
- PostgreSQL 18.1