1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-02 04:21:28 +03:00

Disallow changing NO INHERIT status of a not-null constraint

It makes no sense to add a NO INHERIT not-null constraint to a child
table that already has one in that column inherited from its parent.
Disallow that, and add tests for the relevant cases.

Per complaint from Kyotaro Horiguchi.  I also used part of his proposed
patch.

Co-authored-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Co-authored-by: Álvaro Herrera <alvherre@alvh.no-ip.org>
Discussion: https://postgr.es/m/20230828.161658.1184657435220765047.horikyota.ntt@gmail.com
This commit is contained in:
Alvaro Herrera
2023-08-29 19:19:24 +02:00
parent 952db4979f
commit 9b581c5341
5 changed files with 47 additions and 6 deletions

View File

@@ -2533,7 +2533,7 @@ AddRelationNewConstraints(Relation rel,
* update its catalog status and we're done.
*/
if (AdjustNotNullInheritance1(RelationGetRelid(rel), colnum,
cdef->inhcount))
cdef->inhcount, cdef->is_no_inherit))
continue;
/*
@@ -2830,6 +2830,17 @@ AddRelationNotNullConstraints(Relation rel, List *constraints,
if (old->attnum == attnum)
{
/*
* If we get a constraint from the parent, having a local NO
* INHERIT one doesn't work.
*/
if (constr->is_no_inherit)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot define not-null constraint on column \"%s\" with NO INHERIT",
strVal(linitial(constr->keys))),
errdetail("The column has an inherited not-null constraint.")));
inhcount++;
old_notnulls = foreach_delete_current(old_notnulls, lc2);
}

View File

@@ -669,7 +669,8 @@ extractNotNullColumn(HeapTuple constrTup)
* If no not-null constraint is found for the column, return false.
*/
bool
AdjustNotNullInheritance1(Oid relid, AttrNumber attnum, int count)
AdjustNotNullInheritance1(Oid relid, AttrNumber attnum, int count,
bool is_no_inherit)
{
HeapTuple tup;
@@ -681,6 +682,19 @@ AdjustNotNullInheritance1(Oid relid, AttrNumber attnum, int count)
pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock);
conform = (Form_pg_constraint) GETSTRUCT(tup);
/*
* Don't let the NO INHERIT status change (but don't complain
* unnecessarily.) In the future it might be useful to let an
* inheritable constraint replace a non-inheritable one, but we'd need
* to recurse to children to get it added there.
*/
if (is_no_inherit != conform->connoinherit)
ereport(ERROR,
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("cannot change NO INHERIT status of inherited NOT NULL constraint \"%s\" on relation \"%s\"",
NameStr(conform->conname), get_rel_name(relid)));
if (count > 0)
conform->coninhcount += count;
@@ -691,9 +705,9 @@ AdjustNotNullInheritance1(Oid relid, AttrNumber attnum, int count)
get_rel_name(relid));
/*
* If the constraints are no longer inherited, mark them local. It's
* arguable that we should drop them instead, but it's hard to see
* that being better. The user can drop it manually later.
* If the constraint is no longer inherited, mark it local. It's
* arguable that we should drop it instead, but it's hard to see that
* being better. The user can drop it manually later.
*/
if (conform->coninhcount == 0)
conform->conislocal = true;