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.
This commit is contained in:
Tom Lane 2000-12-05 19:57:56 +00:00
parent 5ce8ab96f5
commit 981a7d32d1
6 changed files with 98 additions and 39 deletions

View file

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* The PerformAddAttribute() code, like most of the relation * The PerformAddAttribute() code, like most of the relation
@ -1287,26 +1287,33 @@ AlterTableAddConstraint(char *relationName,
{ {
List *attrl; List *attrl;
/* go through the fkconstraint->pk_attrs list */ /* Make sure this index has the same number of keys -- It obviously
foreach(attrl, fkconstraint->pk_attrs) * won't match otherwise. */
{ for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++);
Ident *attr=lfirst(attrl); if (i!=length(fkconstraint->pk_attrs))
found = false; found=false;
for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++) else {
/* go through the fkconstraint->pk_attrs list */
foreach(attrl, fkconstraint->pk_attrs)
{ {
int pkattno = indexStruct->indkey[i]; Ident *attr=lfirst(attrl);
if (pkattno>0) found = false;
for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
{ {
char *name = NameStr(rel_attrs[pkattno-1]->attname); int pkattno = indexStruct->indkey[i];
if (strcmp(name, attr->name)==0) if (pkattno>0)
{ {
found = true; char *name = NameStr(rel_attrs[pkattno-1]->attname);
break; if (strcmp(name, attr->name)==0)
{
found = true;
break;
}
} }
} }
if (!found)
break;
} }
if (!found)
break;
} }
} }
ReleaseSysCache(indexTuple); ReleaseSysCache(indexTuple);

View file

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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; List *pkattrs;
Ident *pkattr; Ident *pkattr;
if (ind->unique) { if (ind->unique) {
foreach(pkattrs, fkconstraint->pk_attrs) { int count=0;
foreach(indparms, ind->indexParams) {
count++;
}
if (count!=length(fkconstraint->pk_attrs))
found=0; found=0;
pkattr=lfirst(pkattrs); else {
foreach(indparms, ind->indexParams) { foreach(pkattrs, fkconstraint->pk_attrs) {
indparm=lfirst(indparms); found=0;
if (strcmp(indparm->name, pkattr->name)==0) { pkattr=lfirst(pkattrs);
found=1; foreach(indparms, ind->indexParams) {
break; indparm=lfirst(indparms);
if (strcmp(indparm->name, pkattr->name)==0) {
found=1;
break;
}
} }
if (!found)
break;
} }
if (!found)
break;
} }
} }
if (found) if (found)
@ -2634,26 +2642,31 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint)
{ {
List *attrl; List *attrl;
/* go through the fkconstraint->pk_attrs list */ for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++);
foreach(attrl, fkconstraint->pk_attrs) if (i!=length(fkconstraint->pk_attrs))
{ found=false;
Ident *attr=lfirst(attrl); else {
found = false; /* go through the fkconstraint->pk_attrs list */
for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++) foreach(attrl, fkconstraint->pk_attrs)
{ {
int pkattno = indexStruct->indkey[i]; Ident *attr=lfirst(attrl);
if (pkattno>0) found = false;
for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
{ {
char *name = NameStr(pkrel_attrs[pkattno - 1]->attname); int pkattno = indexStruct->indkey[i];
if (strcmp(name, attr->name)==0) if (pkattno>0)
{ {
found = true; char *name = NameStr(pkrel_attrs[pkattno - 1]->attname);
break; if (strcmp(name, attr->name)==0)
{
found = true;
break;
}
} }
} }
if (!found)
break;
} }
if (!found)
break;
} }
} }
ReleaseSysCache(indexTuple); ReleaseSysCache(indexTuple);

View file

@ -273,6 +273,9 @@ SELECT unique1 FROM tenk1 WHERE unique1 < 5;
CREATE TABLE tmp2 (a int primary key); CREATE TABLE tmp2 (a int primary key);
NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index 'tmp2_pkey' for table 'tmp2' NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index 'tmp2_pkey' for table 'tmp2'
CREATE TABLE tmp3 (a int, b int); 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 rows into tmp2 (pktable)
INSERT INTO tmp2 values (1); INSERT INTO tmp2 values (1);
INSERT INTO tmp2 values (2); INSERT INTO tmp2 values (2);
@ -299,6 +302,13 @@ DELETE FROM tmp3 where a=5;
-- Try (and succeed) -- Try (and succeed)
ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full; 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) 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; 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"
NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "tmp2" NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "tmp2"

View file

@ -703,3 +703,12 @@ ERROR: table "fktable_fail1" does not exist
DROP TABLE FKTABLE_FAIL2; DROP TABLE FKTABLE_FAIL2;
ERROR: table "fktable_fail2" does not exist ERROR: table "fktable_fail2" does not exist
DROP TABLE PKTABLE; 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;

View file

@ -169,6 +169,10 @@ CREATE TABLE tmp2 (a int primary key);
CREATE TABLE tmp3 (a int, b int); 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 rows into tmp2 (pktable)
INSERT INTO tmp2 values (1); INSERT INTO tmp2 values (1);
INSERT INTO tmp2 values (2); INSERT INTO tmp2 values (2);
@ -195,6 +199,15 @@ DELETE FROM tmp3 where a=5;
-- Try (and succeed) -- Try (and succeed)
ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full; 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 tmp3;
DROP TABLE tmp2; DROP TABLE tmp2;

View file

@ -418,3 +418,10 @@ CREATE TABLE FKTABLE_FAIL2 ( ftest1 int, CONSTRAINT fkfail1 FOREIGN KEY (ftest1)
DROP TABLE FKTABLE_FAIL1; DROP TABLE FKTABLE_FAIL1;
DROP TABLE FKTABLE_FAIL2; DROP TABLE FKTABLE_FAIL2;
DROP TABLE PKTABLE; 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;