From 8a9c83bfaf889702401f532fbe2adaf604ca1bd6 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Fri, 28 Apr 2017 14:48:38 -0400 Subject: [PATCH] Fix VALIDATE CONSTRAINT to consider NO INHERIT attribute. Currently, trying to validate a NO INHERIT constraint on the parent will search for the constraint in child tables (where it is not supposed to exist), wrongly causing a "constraint does not exist" error. Amit Langote, per a report from Hans Buschmann. Discussion: http://postgr.es/m/20170421184012.24362.19@wrigleys.postgresql.org --- src/backend/commands/tablecmds.c | 5 +++-- src/test/regress/expected/alter_table.out | 20 ++++++++++++++++++++ src/test/regress/sql/alter_table.sql | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 608b0b19c4..5fe367d46b 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -6903,9 +6903,10 @@ ATExecValidateConstraint(Relation rel, char *constrName, bool recurse, /* * If we're recursing, the parent has already done this, so skip - * it. + * it. Also, if the constraint is a NO INHERIT constraint, we + * shouldn't try to look for it in the children. */ - if (!recursing) + if (!recursing && !con->connoinherit) children = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index f931236410..513d9e20f6 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -367,6 +367,26 @@ NOTICE: merging constraint "identity" with inherited definition ALTER TABLE tmp3 VALIDATE CONSTRAINT identity; NOTICE: boo: 16 NOTICE: boo: 20 +-- A NO INHERIT constraint should not be looked for in children during VALIDATE CONSTRAINT +create table parent_noinh_convalid (a int); +create table child_noinh_convalid () inherits (parent_noinh_convalid); +insert into parent_noinh_convalid values (1); +insert into child_noinh_convalid values (1); +alter table parent_noinh_convalid add constraint check_a_is_2 check (a = 2) no inherit not valid; +-- fail, because of the row in parent +alter table parent_noinh_convalid validate constraint check_a_is_2; +ERROR: check constraint "check_a_is_2" is violated by some row +delete from only parent_noinh_convalid; +-- ok (parent itself contains no violating rows) +alter table parent_noinh_convalid validate constraint check_a_is_2; +select convalidated from pg_constraint where conrelid = 'parent_noinh_convalid'::regclass and conname = 'check_a_is_2'; + convalidated +-------------- + t +(1 row) + +-- cleanup +drop table parent_noinh_convalid, child_noinh_convalid; -- Try (and fail) to create constraint from tmp5(a) to tmp4(a) - unique constraint on -- tmp4 is a,b ALTER TABLE tmp5 add constraint tmpconstr foreign key(a) references tmp4(a) match full; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 4a32f99ec7..9b3615b4dd 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -307,6 +307,21 @@ ALTER TABLE tmp7 ADD CONSTRAINT identity CHECK (b = boo(b)); ALTER TABLE tmp3 ADD CONSTRAINT IDENTITY check (b = boo(b)) NOT VALID; ALTER TABLE tmp3 VALIDATE CONSTRAINT identity; +-- A NO INHERIT constraint should not be looked for in children during VALIDATE CONSTRAINT +create table parent_noinh_convalid (a int); +create table child_noinh_convalid () inherits (parent_noinh_convalid); +insert into parent_noinh_convalid values (1); +insert into child_noinh_convalid values (1); +alter table parent_noinh_convalid add constraint check_a_is_2 check (a = 2) no inherit not valid; +-- fail, because of the row in parent +alter table parent_noinh_convalid validate constraint check_a_is_2; +delete from only parent_noinh_convalid; +-- ok (parent itself contains no violating rows) +alter table parent_noinh_convalid validate constraint check_a_is_2; +select convalidated from pg_constraint where conrelid = 'parent_noinh_convalid'::regclass and conname = 'check_a_is_2'; +-- cleanup +drop table parent_noinh_convalid, child_noinh_convalid; + -- Try (and fail) to create constraint from tmp5(a) to tmp4(a) - unique constraint on -- tmp4 is a,b