From: Tom Lane Date: Tue, 5 Dec 2000 19:57:56 +0000 (+0000) Subject: From Stephan Szabo: X-Git-Tag: REL7_1_BETA2~247 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=981a7d32d1326325caefa3e22df090e48f54cc6c;p=postgresql From Stephan Szabo: I believe this should fix the issue that Philip Warner noticed about the check for unique constraints meeting the referenced keys of a foreign key constraint allowing the specification of a subset of a foreign key instead of rejecting it. I also added tests for a base case of this to the foreign key and alter table tests and patches for expected output. --- diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 42f05f0761..78a3d5e1a7 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.112 2000/11/16 22:30:19 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.113 2000/12/05 19:57:55 tgl Exp $ * * NOTES * The PerformAddAttribute() code, like most of the relation @@ -1287,26 +1287,33 @@ AlterTableAddConstraint(char *relationName, { List *attrl; - /* go through the fkconstraint->pk_attrs list */ - foreach(attrl, fkconstraint->pk_attrs) - { - Ident *attr=lfirst(attrl); - found = false; - for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++) + /* Make sure this index has the same number of keys -- It obviously + * won't match otherwise. */ + for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++); + if (i!=length(fkconstraint->pk_attrs)) + found=false; + else { + /* go through the fkconstraint->pk_attrs list */ + foreach(attrl, fkconstraint->pk_attrs) { - int pkattno = indexStruct->indkey[i]; - if (pkattno>0) + Ident *attr=lfirst(attrl); + found = false; + for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++) { - char *name = NameStr(rel_attrs[pkattno-1]->attname); - if (strcmp(name, attr->name)==0) + int pkattno = indexStruct->indkey[i]; + if (pkattno>0) { - found = true; - break; + char *name = NameStr(rel_attrs[pkattno-1]->attname); + if (strcmp(name, attr->name)==0) + { + found = true; + break; + } } } + if (!found) + break; } - if (!found) - break; } } ReleaseSysCache(indexTuple); diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index dcd5234754..e483415876 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: analyze.c,v 1.169 2000/12/05 19:15:10 tgl Exp $ + * $Id: analyze.c,v 1.170 2000/12/05 19:57:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1209,18 +1209,26 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt) List *pkattrs; Ident *pkattr; if (ind->unique) { - foreach(pkattrs, fkconstraint->pk_attrs) { + int count=0; + foreach(indparms, ind->indexParams) { + count++; + } + if (count!=length(fkconstraint->pk_attrs)) found=0; - pkattr=lfirst(pkattrs); - foreach(indparms, ind->indexParams) { - indparm=lfirst(indparms); - if (strcmp(indparm->name, pkattr->name)==0) { - found=1; - break; + else { + foreach(pkattrs, fkconstraint->pk_attrs) { + found=0; + pkattr=lfirst(pkattrs); + foreach(indparms, ind->indexParams) { + indparm=lfirst(indparms); + if (strcmp(indparm->name, pkattr->name)==0) { + found=1; + break; + } } + if (!found) + break; } - if (!found) - break; } } if (found) @@ -2634,26 +2642,31 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint) { List *attrl; - /* go through the fkconstraint->pk_attrs list */ - foreach(attrl, fkconstraint->pk_attrs) - { - Ident *attr=lfirst(attrl); - found = false; - for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++) + for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++); + if (i!=length(fkconstraint->pk_attrs)) + found=false; + else { + /* go through the fkconstraint->pk_attrs list */ + foreach(attrl, fkconstraint->pk_attrs) { - int pkattno = indexStruct->indkey[i]; - if (pkattno>0) + Ident *attr=lfirst(attrl); + found = false; + for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++) { - char *name = NameStr(pkrel_attrs[pkattno - 1]->attname); - if (strcmp(name, attr->name)==0) + int pkattno = indexStruct->indkey[i]; + if (pkattno>0) { - found = true; - break; + char *name = NameStr(pkrel_attrs[pkattno - 1]->attname); + if (strcmp(name, attr->name)==0) + { + found = true; + break; + } } } + if (!found) + break; } - if (!found) - break; } } ReleaseSysCache(indexTuple); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index d79a65c983..082a0be478 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -273,6 +273,9 @@ SELECT unique1 FROM tenk1 WHERE unique1 < 5; CREATE TABLE tmp2 (a int primary key); NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index 'tmp2_pkey' for table 'tmp2' CREATE TABLE tmp3 (a int, b int); +CREATE TABLE tmp4 (a int, b int, unique(a,b)); +NOTICE: CREATE TABLE/UNIQUE will create implicit index 'tmp4_a_key' for table 'tmp4' +CREATE TABLE tmp5 (a int, b int); -- Insert rows into tmp2 (pktable) INSERT INTO tmp2 values (1); INSERT INTO tmp2 values (2); @@ -299,6 +302,13 @@ DELETE FROM tmp3 where a=5; -- Try (and succeed) ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full; NOTICE: ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for FOREIGN KEY check(s) +-- 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; +NOTICE: ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for FOREIGN KEY check(s) +ERROR: UNIQUE constraint matching given keys for referenced table "tmp4" not found +DROP TABLE tmp5; +DROP TABLE tmp4; DROP TABLE tmp3; NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "tmp2" NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "tmp2" diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out index 4126324755..075b6aa2f8 100644 --- a/src/test/regress/expected/foreign_key.out +++ b/src/test/regress/expected/foreign_key.out @@ -703,3 +703,12 @@ ERROR: table "fktable_fail1" does not exist DROP TABLE FKTABLE_FAIL2; ERROR: table "fktable_fail2" does not exist DROP TABLE PKTABLE; +-- Test for referencing column number smaller than referenced constraint +CREATE TABLE PKTABLE (ptest1 int, ptest2 int, UNIQUE(ptest1, ptest2)); +NOTICE: CREATE TABLE/UNIQUE will create implicit index 'pktable_ptest1_key' for table 'pktable' +CREATE TABLE FKTABLE_FAIL1 (ftest1 int REFERENCES pktable(ptest1)); +NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s) +ERROR: UNIQUE constraint matching given keys for referenced table "pktable" not found +DROP TABLE FKTABLE_FAIL1; +ERROR: table "fktable_fail1" does not exist +DROP TABLE PKTABLE; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index cb7b9a2a46..f90710f8d9 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -169,6 +169,10 @@ CREATE TABLE tmp2 (a int primary key); CREATE TABLE tmp3 (a int, b int); +CREATE TABLE tmp4 (a int, b int, unique(a,b)); + +CREATE TABLE tmp5 (a int, b int); + -- Insert rows into tmp2 (pktable) INSERT INTO tmp2 values (1); INSERT INTO tmp2 values (2); @@ -195,6 +199,15 @@ DELETE FROM tmp3 where a=5; -- Try (and succeed) ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full; +-- 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; + +DROP TABLE tmp5; + +DROP TABLE tmp4; + DROP TABLE tmp3; DROP TABLE tmp2; diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql index ac29e50579..91ff0aafe5 100644 --- a/src/test/regress/sql/foreign_key.sql +++ b/src/test/regress/sql/foreign_key.sql @@ -418,3 +418,10 @@ CREATE TABLE FKTABLE_FAIL2 ( ftest1 int, CONSTRAINT fkfail1 FOREIGN KEY (ftest1) DROP TABLE FKTABLE_FAIL1; DROP TABLE FKTABLE_FAIL2; DROP TABLE PKTABLE; + +-- Test for referencing column number smaller than referenced constraint +CREATE TABLE PKTABLE (ptest1 int, ptest2 int, UNIQUE(ptest1, ptest2)); +CREATE TABLE FKTABLE_FAIL1 (ftest1 int REFERENCES pktable(ptest1)); + +DROP TABLE FKTABLE_FAIL1; +DROP TABLE PKTABLE;