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
No known key found for this signature in database
GPG Key ID: 1C20ACB9D5C564AE
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;

View File

@ -248,7 +248,8 @@ extern char *ChooseConstraintName(const char *name1, const char *name2,
extern HeapTuple findNotNullConstraintAttnum(Oid relid, AttrNumber attnum);
extern HeapTuple findNotNullConstraint(Oid relid, const char *colname);
extern AttrNumber extractNotNullColumn(HeapTuple constrTup);
extern bool AdjustNotNullInheritance1(Oid relid, AttrNumber attnum, int count);
extern bool AdjustNotNullInheritance1(Oid relid, AttrNumber attnum, int count,
bool is_no_inherit);
extern void AdjustNotNullInheritance(Oid relid, Bitmapset *columns, int count);
extern List *RelationGetNotNullConstraints(Oid relid, bool cooked);

View File

@ -2051,6 +2051,15 @@ Not-null constraints:
Inherits: pp1,
cc1
-- cannot create table with inconsistent NO INHERIT constraint
create table cc3 (a2 int not null no inherit) inherits (cc1);
NOTICE: moving and merging column "a2" with inherited definition
DETAIL: User-specified column moved to the position of the inherited column.
ERROR: cannot define not-null constraint on column "a2" with NO INHERIT
DETAIL: The column has an inherited not-null constraint.
-- change NO INHERIT status of inherited constraint: no dice, it's inherited
alter table cc2 add not null a2 no inherit;
ERROR: cannot change NO INHERIT status of inherited NOT NULL constraint "nn" on relation "cc2"
-- remove constraint from cc2: no dice, it's inherited
alter table cc2 alter column a2 drop not null;
ERROR: cannot drop inherited constraint "nn" of relation "cc2"

View File

@ -736,6 +736,12 @@ alter table pp1 alter column f1 set not null;
\d+ cc1
\d+ cc2
-- cannot create table with inconsistent NO INHERIT constraint
create table cc3 (a2 int not null no inherit) inherits (cc1);
-- change NO INHERIT status of inherited constraint: no dice, it's inherited
alter table cc2 add not null a2 no inherit;
-- remove constraint from cc2: no dice, it's inherited
alter table cc2 alter column a2 drop not null;