From Stephan Szabo:
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 5 Dec 2000 19:57:56 +0000 (19:57 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 5 Dec 2000 19:57:56 +0000 (19:57 +0000)
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.

src/backend/commands/command.c
src/backend/parser/analyze.c
src/test/regress/expected/alter_table.out
src/test/regress/expected/foreign_key.out
src/test/regress/sql/alter_table.sql
src/test/regress/sql/foreign_key.sql

index 42f05f0761cf0c2c013d987d95368602c88b175b..78a3d5e1a75fe198f4c5b19d39cd21cb1b35ffc8 100644 (file)
@@ -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);
index dcd523475440cce849e8e1110f57cc59fffea208..e4834158765d3da6e621fc366c8768e8ce29ed12 100644 (file)
@@ -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);
index d79a65c983a9b7d361b12b63a775bafa7bacfd8e..082a0be4782128dcf1f1336bd68e39bb19ecd2a9 100644 (file)
@@ -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"
index 412632475566ed6b64084f1f80cb7d613db55b50..075b6aa2f8706cc572fe244bfab05d9367e9b7a6 100644 (file)
@@ -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;
index cb7b9a2a469e055b05b4a7fdda6e53202c314409..f90710f8d96ea623a22c247ab5dca1a42175ba2e 100644 (file)
@@ -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;
index ac29e50579c7c24b6e945a8c51a6b3bf1ffad9c1..91ff0aafe58c0efd13c5cbeeddab7a41f1c4565f 100644 (file)
@@ -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;