diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 5f799199ed..b6e745c465 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.130 2001/05/30 12:57:36 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.131 2001/05/30 13:00:03 momjian Exp $ * * NOTES * The PerformAddAttribute() code, like most of the relation @@ -1215,6 +1215,7 @@ AlterTableAddConstraint(char *relationName, Relation rel; Node *expr; char *name; + Oid myrelid; if (constr->name) name = constr->name; @@ -1224,6 +1225,7 @@ AlterTableAddConstraint(char *relationName, constlist = makeList1(constr); rel = heap_openr(relationName, AccessExclusiveLock); + myrelid = RelationGetRelid(rel); /* make sure it is not a view */ if (rel->rd_rel->relkind == RELKIND_VIEW) @@ -1318,6 +1320,35 @@ AlterTableAddConstraint(char *relationName, */ AddRelationRawConstraints(rel, NIL, constlist); heap_close(rel, NoLock); + + if (inh) { + List *child, + *children; + + /* this routine is actually in the planner */ + children = find_all_inheritors(myrelid); + + /* + * find_all_inheritors does the recursive search of the + * inheritance hierarchy, so all we have to do is process all + * of the relids in the list that it returns. + */ + foreach(child, children) + { + Oid childrelid = lfirsti(child); + char *childrelname; + + if (childrelid == myrelid) + continue; + rel = heap_open(childrelid, AccessExclusiveLock); + childrelname = pstrdup(RelationGetRelationName(rel)); + heap_close(rel, AccessExclusiveLock); + + AlterTableAddConstraint(childrelname, false, newConstraint); + + pfree(childrelname); + } + } pfree(constlist); break; diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index b8ea97d261..bc5472f31c 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -375,3 +375,76 @@ NOTICE: ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for FORE ERROR: Unable to identify an operator '=' for types 'text' and 'int4' You will have to retype this query using an explicit cast -- temp tables should go away by themselves, need not drop them. +-- test check constraint adding +create table atacc1 ( test int ); +-- add a check constraint +alter table atacc1 add constraint atacc_test1 check (test>3); +-- should fail +insert into atacc1 (test) values (2); +ERROR: ExecAppend: rejected due to CHECK constraint atacc_test1 +-- should succeed +insert into atacc1 (test) values (4); +drop table atacc1; +-- let's do one where the check fails when added +create table atacc1 ( test int ); +-- insert a soon to be failing row +insert into atacc1 (test) values (2); +-- add a check constraint (fails) +alter table atacc1 add constraint atacc_test1 check (test>3); +ERROR: AlterTableAddConstraint: rejected due to CHECK constraint atacc_test1 +insert into atacc1 (test) values (4); +drop table atacc1; +-- let's do one where the check fails because the column doesn't exist +create table atacc1 ( test int ); +-- add a check constraint (fails) +alter table atacc1 add constraint atacc_test1 check (test1>3); +ERROR: Attribute 'test1' not found +drop table atacc1; +-- something a little more complicated +create table atacc1 ( test int, test2 int, test3 int); +-- add a check constraint (fails) +alter table atacc1 add constraint atacc_test1 check (test+test23), test2 int); +alter table atacc1 add check (test2>test); +-- should fail for $2 +insert into atacc1 (test2, test) values (3, 4); +ERROR: ExecAppend: rejected due to CHECK constraint $2 +drop table atacc1; +-- inheritance related tests +create table atacc1 (test int); +create table atacc2 (test2 int); +create table atacc3 (test3 int) inherits (atacc1, atacc2); +alter table atacc2 add constraint foo check (test2>0); +-- fail and then succeed on atacc2 +insert into atacc2 (test2) values (-3); +ERROR: ExecAppend: rejected due to CHECK constraint foo +insert into atacc2 (test2) values (3); +-- fail and then succeed on atacc3 +insert into atacc3 (test2) values (-3); +ERROR: ExecAppend: rejected due to CHECK constraint foo +insert into atacc3 (test2) values (3); +drop table atacc3; +drop table atacc2; +drop table atacc1; +-- let's try only to add only to the parent +create table atacc1 (test int); +create table atacc2 (test2 int); +create table atacc3 (test3 int) inherits (atacc1, atacc2); +alter table only atacc2 add constraint foo check (test2>0); +-- fail and then succeed on atacc2 +insert into atacc2 (test2) values (-3); +ERROR: ExecAppend: rejected due to CHECK constraint foo +insert into atacc2 (test2) values (3); +-- both succeed on atacc3 +insert into atacc3 (test2) values (-3); +insert into atacc3 (test2) values (3); +drop table atacc3; +drop table atacc2; +drop table atacc1; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 8b1b327693..50a611f83f 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -254,3 +254,78 @@ ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest2, ftest1) references pktable(ptest1, ptest2); -- temp tables should go away by themselves, need not drop them. + +-- test check constraint adding + +create table atacc1 ( test int ); +-- add a check constraint +alter table atacc1 add constraint atacc_test1 check (test>3); +-- should fail +insert into atacc1 (test) values (2); +-- should succeed +insert into atacc1 (test) values (4); +drop table atacc1; + +-- let's do one where the check fails when added +create table atacc1 ( test int ); +-- insert a soon to be failing row +insert into atacc1 (test) values (2); +-- add a check constraint (fails) +alter table atacc1 add constraint atacc_test1 check (test>3); +insert into atacc1 (test) values (4); +drop table atacc1; + +-- let's do one where the check fails because the column doesn't exist +create table atacc1 ( test int ); +-- add a check constraint (fails) +alter table atacc1 add constraint atacc_test1 check (test1>3); +drop table atacc1; + +-- something a little more complicated +create table atacc1 ( test int, test2 int, test3 int); +-- add a check constraint (fails) +alter table atacc1 add constraint atacc_test1 check (test+test23), test2 int); +alter table atacc1 add check (test2>test); +-- should fail for $2 +insert into atacc1 (test2, test) values (3, 4); +drop table atacc1; + +-- inheritance related tests +create table atacc1 (test int); +create table atacc2 (test2 int); +create table atacc3 (test3 int) inherits (atacc1, atacc2); +alter table atacc2 add constraint foo check (test2>0); +-- fail and then succeed on atacc2 +insert into atacc2 (test2) values (-3); +insert into atacc2 (test2) values (3); +-- fail and then succeed on atacc3 +insert into atacc3 (test2) values (-3); +insert into atacc3 (test2) values (3); +drop table atacc3; +drop table atacc2; +drop table atacc1; + +-- let's try only to add only to the parent + +create table atacc1 (test int); +create table atacc2 (test2 int); +create table atacc3 (test3 int) inherits (atacc1, atacc2); +alter table only atacc2 add constraint foo check (test2>0); +-- fail and then succeed on atacc2 +insert into atacc2 (test2) values (-3); +insert into atacc2 (test2) values (3); +-- both succeed on atacc3 +insert into atacc3 (test2) values (-3); +insert into atacc3 (test2) values (3); +drop table atacc3; +drop table atacc2; +drop table atacc1; +