This patch should catch cases where the types
authorBruce Momjian <bruce@momjian.us>
Wed, 9 May 2001 21:10:39 +0000 (21:10 +0000)
committerBruce Momjian <bruce@momjian.us>
Wed, 9 May 2001 21:10:39 +0000 (21:10 +0000)
in referencing and referenced columns of an fk constraint
aren't comparable using '=' at constraint definition time
rather than insert/update time.

Stephan Szabo

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 13a78f1177390f0108702c94a7cc005e0a28b183..cd7e1d29524ed2d7fae6ecb22ac79042e7d737a7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.126 2001/05/07 00:43:17 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.127 2001/05/09 21:10:38 momjian Exp $
  *
  * NOTES
  *   The PerformAddAttribute() code, like most of the relation
@@ -39,6 +39,7 @@
 #include "parser/parse_expr.h"
 #include "parser/parse_clause.h"
 #include "parser/parse_relation.h"
+#include "parser/parse_oper.h"
 #include "nodes/makefuncs.h"
 #include "optimizer/planmain.h"
 #include "optimizer/clauses.h"
@@ -1342,6 +1343,13 @@ AlterTableAddConstraint(char *relationName,
                int         i;
                bool        found = false;
 
+               Oid     fktypoid[INDEX_MAX_KEYS];
+               Oid     pktypoid[INDEX_MAX_KEYS];
+               int     attloc;
+               for (i=0; i<INDEX_MAX_KEYS; i++) 
+                   fktypoid[i]=pktypoid[i]=0;
+
                if (is_temp_rel_name(fkconstraint->pktable_name) &&
                    !is_temp_rel_name(relationName))
                    elog(ERROR, "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint.");
@@ -1403,6 +1411,7 @@ AlterTableAddConstraint(char *relationName,
                            found = false;
                        else
                        {
+                           attloc=0;
                            /* go through the fkconstraint->pk_attrs list */
                            foreach(attrl, fkconstraint->pk_attrs)
                            {
@@ -1419,6 +1428,11 @@ AlterTableAddConstraint(char *relationName,
 
                                        if (strcmp(name, attr->name) == 0)
                                        {
+                                           /* We get the type of this attribute here and
+                                            * store it so we can use it later for making
+                                            * sure the types are comparable.
+                                            */
+                                           pktypoid[attloc++]=rel_attrs[pkattno-1]->atttypid;
                                            found = true;
                                            break;
                                        }
@@ -1448,6 +1462,7 @@ AlterTableAddConstraint(char *relationName,
                    Ident      *fkattr;
 
                    found = false;
+                   attloc = 0;
                    foreach(fkattrs, fkconstraint->fk_attrs)
                    {
                        int         count;
@@ -1460,6 +1475,11 @@ AlterTableAddConstraint(char *relationName,
 
                            if (strcmp(name, fkattr->name) == 0)
                            {
+                               /*
+                                * Here once again we get the types, this
+                                * time for the fk table's attributes
+                                */
+                               fktypoid[attloc++]=rel->rd_att->attrs[count]->atttypid;
                                found = true;
                                break;
                            }
@@ -1471,6 +1491,17 @@ AlterTableAddConstraint(char *relationName,
                        elog(ERROR, "columns referenced in foreign key constraint not found.");
                }
 
+               for (i=0; i < INDEX_MAX_KEYS && fktypoid[i] !=0; i++) {
+                   /*
+                    * fktypoid[i] is the foreign key table's i'th element's type oid
+                    * pktypoid[i] is the primary key table's i'th element's type oid
+                    * We let oper() do our work for us, including elog(ERROR) if the
+                    * types can't compare with =
+                    */
+                   Operator o=oper("=", fktypoid[i], pktypoid[i], false);
+                   ReleaseSysCache(o);
+               }
+
                trig.tgoid = 0;
                if (fkconstraint->constr_name)
                    trig.tgname = fkconstraint->constr_name;
index 76cc095bc4edcdbf4cfecad9627a1e5a29d03256..c5d9b484c6cf899a5eb0d90c12314a992421000f 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.184 2001/05/07 00:43:22 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.185 2001/05/09 21:10:39 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,6 +24,8 @@
 #include "parser/parse_agg.h"
 #include "parser/parse_clause.h"
 #include "parser/parse_coerce.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_oper.h"
 #include "parser/parse_relation.h"
 #include "parser/parse_target.h"
 #include "parser/parse_type.h"
@@ -52,10 +54,10 @@ static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt);
 
 static List *getSetColTypes(ParseState *pstate, Node *node);
 static void transformForUpdate(Query *qry, List *forUpdate);
-static void transformFkeyGetPrimaryKey(FkConstraint *fkconstraint);
+static void transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid);
 static void transformConstraintAttrs(List *constraintList);
 static void transformColumnType(ParseState *pstate, ColumnDef *column);
-static void transformFkeyCheckAttrs(FkConstraint *fkconstraint);
+static void transformFkeyCheckAttrs(FkConstraint *fkconstraint, Oid *pktypoid);
 
 static void release_pstate_resources(ParseState *pstate);
 static FromExpr *makeFromExpr(List *fromlist, Node *quals);
@@ -1139,7 +1141,13 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
        List       *fk_attr;
        List       *pk_attr;
        Ident      *id;
+       Oid    pktypoid[INDEX_MAX_KEYS];
+       Oid    fktypoid[INDEX_MAX_KEYS];
+       int    i;
 
+       for (i=0; i<INDEX_MAX_KEYS; i++) {
+           pktypoid[i]=fktypoid[i]=0;
+       }
        elog(NOTICE, "CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)");
 
        foreach(fkclist, fkconstraints)
@@ -1160,6 +1168,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
            if (fkconstraint->fk_attrs != NIL)
            {
                int         found = 0;
+               int    attnum=0;
                List       *cols;
                List       *fkattrs;
                Ident      *fkattr = NULL;
@@ -1174,46 +1183,50 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
                        col = lfirst(cols);
                        if (strcmp(col->colname, fkattr->name) == 0)
                        {
+                           char *buff=TypeNameToInternalName(col->typename);
+                           Oid type=typenameTypeId(buff);
+                           if (!OidIsValid(type)) {
+                               elog(ERROR, "Unable to lookup type %s", col->typename->name);
+                           }
+                           fktypoid[attnum++]=type;
                            found = 1;
                            break;
                        }
                    }
-                   if (!found)
-                       break;
-               }
-               if (!found)
-               {               /* try inherited tables */
-                   List       *inher;
-                   List       *inhRelnames = stmt->inhRelnames;
-                   Relation    rel;
+                   if (!found) {
+                       List       *inher;
+                       List       *inhRelnames = stmt->inhRelnames;
+                       Relation    rel;
 
-                   foreach(inher, inhRelnames)
-                   {
-                       Value      *inh = lfirst(inher);
-                       int         count;
-
-                       Assert(IsA(inh, String));
-                       rel = heap_openr(strVal(inh), AccessShareLock);
-                       if (rel->rd_rel->relkind != RELKIND_RELATION)
-                           elog(ERROR, "inherited table \"%s\" is not a relation",
-                                strVal(inh));
-                       for (count = 0; count < rel->rd_att->natts; count++)
+                       foreach(inher, inhRelnames)
                        {
-                           char       *name = NameStr(rel->rd_att->attrs[count]->attname);
-
-                           if (strcmp(fkattr->name, name) == 0)
+                           Value      *inh = lfirst(inher);
+                           int         count;
+
+                           Assert(IsA(inh, String));
+                           rel = heap_openr(strVal(inh), AccessShareLock);
+                           if (rel->rd_rel->relkind != RELKIND_RELATION)
+                               elog(ERROR, "inherited table \"%s\" is not a relation",
+                                    strVal(inh));
+                           for (count = 0; count < rel->rd_att->natts; count++)
                            {
-                               found = 1;
-                               break;
+                               char       *name = NameStr(rel->rd_att->attrs[count]->attname);
+
+                               if (strcmp(fkattr->name, name) == 0)
+                               {
+                                   fktypoid[attnum++]=rel->rd_att->attrs[count]->atttypid;
+                                   found = 1;
+                                   break;
+                               }
                            }
+                           heap_close(rel, NoLock);
+                           if (found)
+                               break;
                        }
-                       heap_close(rel, NoLock);
-                       if (found)
-                           break;
                    }
+                   if (!found) 
+                       break;
                }
-               else
-                   found = 1;
                if (!found)
                    elog(ERROR, "columns referenced in foreign key constraint not found.");
            }
@@ -1228,13 +1241,16 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
            if (fkconstraint->fk_attrs != NIL && fkconstraint->pk_attrs == NIL)
            {
                if (strcmp(fkconstraint->pktable_name, stmt->relname) != 0)
-                   transformFkeyGetPrimaryKey(fkconstraint);
+                   transformFkeyGetPrimaryKey(fkconstraint, pktypoid);
                else if (pkey != NULL)
                {
                    List       *pkey_attr = pkey->indexParams;
                    List       *attr;
+                   List       *findattr;
                    IndexElem  *ielem;
                    Ident      *pkattr;
+                   int    attnum=0;
+                   ColumnDef  *col;
 
                    foreach(attr, pkey_attr)
                    {
@@ -1244,6 +1260,18 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
                        pkattr->indirection = NIL;
                        pkattr->isRel = false;
                        fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs, pkattr);
+                       foreach (findattr, stmt->tableElts) {
+                                                   col=lfirst(findattr);
+                                                   if (strcmp(col->colname, ielem->name)==0) {
+                               char *buff=TypeNameToInternalName(col->typename);
+                               Oid type=typenameTypeId(buff);
+                                                           if (!OidIsValid(type)) {
+                                                                   elog(ERROR, "Unable to lookup type %s", col->typename->name);
+                                                           }
+                                                           pktypoid[attnum++]=type; /* need to convert typename */
+                                                           break;
+                                                   }
+                       }
                    }
                }
                else
@@ -1255,7 +1283,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
            else
            {
                if (strcmp(fkconstraint->pktable_name, stmt->relname) != 0)
-                   transformFkeyCheckAttrs(fkconstraint);
+                   transformFkeyCheckAttrs(fkconstraint, pktypoid);
                else
                {
                    /* Get a unique/pk constraint from above */
@@ -1268,11 +1296,14 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
                        IndexElem  *indparm;
                        List       *indparms;
                        List       *pkattrs;
+                       List       *findattr;
+                       ColumnDef  *col;
                        Ident      *pkattr;
 
                        if (ind->unique)
                        {
                            int         count = 0;
+                           int attnum=0;
 
                            foreach(indparms, ind->indexParams)
                                count++;
@@ -1289,7 +1320,43 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
                                        indparm = lfirst(indparms);
                                        if (strcmp(indparm->name, pkattr->name) == 0)
                                        {
-                                           found = 1;
+                                           foreach (findattr, stmt->tableElts) {
+                                               col=lfirst(findattr);
+                                               if (strcmp(col->colname, indparm->name)==0) {
+                                                   char *buff=TypeNameToInternalName(col->typename);
+                                                   Oid type=typenameTypeId(buff);
+                                                   if (!OidIsValid(type)) {
+                                                       elog(ERROR, "Unable to lookup type %s", col->typename->name);
+                                                   }
+                                                   pktypoid[attnum++]=type;
+                                                   found=1;
+                                                   break;
+                                               }
+                                           }
+                                           if (!found) {
+                                               List *inher;
+                                               List *inhRelnames=stmt->inhRelnames;
+                                               Relation rel;
+                                               foreach (inher, inhRelnames) {
+                                                   Value *inh=lfirst(inher);
+                                                   int count;
+                                                   Assert(IsA(inh, String));
+                                                   rel=heap_openr(strVal(inh), AccessShareLock);
+                                                   if (rel->rd_rel->relkind!=RELKIND_RELATION)
+                                                       elog(ERROR, "inherited table \"%s\" is not a relation", strVal(inh));
+                                                   for (count=0; count<rel->rd_att->natts; count++) {
+                                                       char *name=NameStr(rel->rd_att->attrs[count]->attname);
+                                                       if (strcmp(pkattr->name, name)==0) {
+                                                           pktypoid[attnum++]=rel->rd_att->attrs[count]->atttypid;
+                                                           found=1;
+                                                           break;
+                                                       }
+                                                   }
+                                                   heap_close(rel, NoLock);
+                                                   if (found)
+                                                       break;
+                                               }
+                                           }
                                            break;
                                        }
                                    }
@@ -1307,6 +1374,16 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
                }
            }
 
+           for (i = 0; i < INDEX_MAX_KEYS && fktypoid[i] != 0; i++) {
+               /*
+                * fktypoid[i] is the foreign key table's i'th element's type oid
+                * pktypoid[i] is the primary key table's i'th element's type oid
+                * We let oper() do our work for us, including elog(ERROR) if the
+                * types don't compare with =
+                */
+               Operator o=oper("=", fktypoid[i], pktypoid[i], false);
+               ReleaseSysCache(o);
+           }
            /*
             * Build a CREATE CONSTRAINT TRIGGER statement for the CHECK
             * action.
@@ -2399,8 +2476,10 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt)
                 * omitted, lookup for the definition of the primary key
                 *
                 */
-               if (fkconstraint->fk_attrs != NIL && fkconstraint->pk_attrs == NIL)
-                   transformFkeyGetPrimaryKey(fkconstraint);
+               if (fkconstraint->fk_attrs != NIL && fkconstraint->pk_attrs == NIL) {
+                   Oid pktypoid[INDEX_MAX_KEYS];
+                   transformFkeyGetPrimaryKey(fkconstraint, pktypoid);
+               }
 
                /*
                 * Build a CREATE CONSTRAINT TRIGGER statement for the
@@ -2702,7 +2781,7 @@ transformForUpdate(Query *qry, List *forUpdate)
  *
  */
 static void
-transformFkeyCheckAttrs(FkConstraint *fkconstraint)
+transformFkeyCheckAttrs(FkConstraint *fkconstraint, Oid *pktypoid)
 {
    Relation    pkrel;
    Form_pg_attribute *pkrel_attrs;
@@ -2744,6 +2823,7 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint)
        if (indexStruct->indisunique)
        {
            List       *attrl;
+           int    attnum=0;
 
            for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++);
            if (i != length(fkconstraint->pk_attrs))
@@ -2766,6 +2846,7 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint)
 
                            if (strcmp(name, attr->name) == 0)
                            {
+                               pktypoid[attnum++]=pkrel_attrs[pkattno-1]->atttypid;
                                found = true;
                                break;
                            }
@@ -2797,7 +2878,7 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint)
  *
  */
 static void
-transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
+transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid)
 {
    Relation    pkrel;
    Form_pg_attribute *pkrel_attrs;
@@ -2806,6 +2887,7 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
    HeapTuple   indexTuple = NULL;
    Form_pg_index indexStruct = NULL;
    int         i;
+   int     attnum=0;
 
    /*
     * Open the referenced table and get the attributes list
@@ -2862,6 +2944,7 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
                    NameGetDatum(&(pkrel_attrs[pkattno - 1]->attname))));
        pkattr->indirection = NIL;
        pkattr->isRel = false;
+       pktypoid[attnum++]=pkrel_attrs[pkattno-1]->atttypid;
 
        fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs, pkattr);
    }
index 082a0be4782128dcf1f1336bd68e39bb19ecd2a9..dab0c7f9c5caf462bbdb503f32fe501cfae13055 100644 (file)
@@ -313,3 +313,60 @@ 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"
 DROP TABLE tmp2;
+-- Foreign key adding test with mixed types
+CREATE TABLE PKTABLE (ptest1 int PRIMARY KEY);
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+CREATE TABLE FKTABLE (ftest1 text);
+-- This next should fail, because text=int does not exist
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
+NOTICE:  ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'text' and 'int4'
+   You will have to retype this query using an explicit cast
+-- This should also fail for the same reason, but here we
+-- give the column name
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1);
+NOTICE:  ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'text' and 'int4'
+   You will have to retype this query using an explicit cast
+-- This should succeed, even though they are different types
+-- because varchar=int does exist
+DROP TABLE FKTABLE;
+CREATE TABLE FKTABLE (ftest1 varchar);
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
+NOTICE:  ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for FOREIGN KEY check(s)
+-- As should this
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1);
+NOTICE:  ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for FOREIGN KEY check(s)
+DROP TABLE pktable;
+NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "fktable"
+NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "fktable"
+DROP TABLE fktable;
+CREATE TABLE PKTABLE (ptest1 int, ptest2 text, PRIMARY KEY(ptest1, ptest2));
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+-- This should fail, because we just chose really odd types
+CREATE TABLE FKTABLE (ftest1 cidr, ftest2 datetime);
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2) references pktable;
+NOTICE:  ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'cidr' and 'int4'
+   You will have to retype this query using an explicit cast
+-- Again, so should this...
+DROP TABLE FKTABLE;
+CREATE TABLE FKTABLE (ftest1 cidr, ftest2 datetime);
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2) references pktable(ptest1, ptest2);
+NOTICE:  ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'cidr' and 'int4'
+   You will have to retype this query using an explicit cast
+-- This fails because we mixed up the column ordering
+DROP TABLE FKTABLE;
+CREATE TABLE FKTABLE (ftest1 int, ftest2 text);
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2) references pktable(ptest2, ptest1);
+NOTICE:  ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'int4' and 'text'
+   You will have to retype this query using an explicit cast
+-- As does this...
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest2, ftest1) references pktable(ptest1, ptest2);
+NOTICE:  ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'text' and 'int4'
+   You will have to retype this query using an explicit cast
+DROP TABLE FKTABLE;
+DROP TABLE PKTABLE;
index 075b6aa2f8706cc572fe244bfab05d9367e9b7a6..990c59c90c98780a5c6370255f38f3b957ea9eb8 100644 (file)
@@ -712,3 +712,253 @@ ERROR:  UNIQUE constraint matching given keys for referenced table "pktable" not
 DROP TABLE FKTABLE_FAIL1;
 ERROR:  table "fktable_fail1" does not exist
 DROP TABLE PKTABLE;
+--
+-- Tests for mismatched types
+--
+-- Basic one column, two table setup 
+CREATE TABLE PKTABLE (ptest1 int PRIMARY KEY);
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+-- This next should fail, because text=int does not exist
+CREATE TABLE FKTABLE (ftest1 text REFERENCES pktable);
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'text' and 'int4'
+   You will have to retype this query using an explicit cast
+-- This should also fail for the same reason, but here we
+-- give the column name
+CREATE TABLE FKTABLE (ftest1 text REFERENCES pktable(ptest1));
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'text' and 'int4'
+   You will have to retype this query using an explicit cast
+-- This should succeed, even though they are different types
+-- because varchar=int does exist
+CREATE TABLE FKTABLE (ftest1 varchar REFERENCES pktable);
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+DROP TABLE FKTABLE;
+NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
+NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
+-- As should this
+CREATE TABLE FKTABLE (ftest1 varchar REFERENCES pktable(ptest1));
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+DROP TABLE FKTABLE;
+NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
+NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
+DROP TABLE PKTABLE;
+-- Two columns, two tables
+CREATE TABLE PKTABLE (ptest1 int, ptest2 text, PRIMARY KEY(ptest1, ptest2));
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+-- This should fail, because we just chose really odd types
+CREATE TABLE FKTABLE (ftest1 cidr, ftest2 datetime, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable);
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'cidr' and 'int4'
+   You will have to retype this query using an explicit cast
+-- Again, so should this...
+CREATE TABLE FKTABLE (ftest1 cidr, ftest2 datetime, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest1, ptest2));
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'cidr' and 'int4'
+   You will have to retype this query using an explicit cast
+-- This fails because we mixed up the column ordering
+CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable);
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'text' and 'int4'
+   You will have to retype this query using an explicit cast
+-- As does this...
+CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest1, ptest2));
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'text' and 'int4'
+   You will have to retype this query using an explicit cast
+-- And again..
+CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest2, ptest1));
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'int4' and 'text'
+   You will have to retype this query using an explicit cast
+-- This works...
+CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest2, ptest1));
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+DROP TABLE FKTABLE;
+NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
+NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
+-- As does this
+CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest1, ptest2));
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+DROP TABLE FKTABLE;
+NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
+NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
+DROP TABLE PKTABLE;
+-- Two columns, same table
+-- Make sure this still works...
+CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
+ptest4) REFERENCES pktable(ptest1, ptest2));
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+DROP TABLE PKTABLE;
+-- And this, 
+CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
+ptest4) REFERENCES pktable);
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+DROP TABLE PKTABLE;
+-- This shouldn't (mixed up columns)
+CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
+ptest4) REFERENCES pktable(ptest2, ptest1));
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'int4' and 'text'
+   You will have to retype this query using an explicit cast
+-- Nor should this... (same reason, we have 4,3 referencing 1,2 which mismatches types
+CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest4,
+ptest3) REFERENCES pktable(ptest1, ptest2));
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'text' and 'int4'
+   You will have to retype this query using an explicit cast
+-- Not this one either... Same as the last one except we didn't defined the columns being referenced.
+CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest4,
+ptest3) REFERENCES pktable);
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'text' and 'int4'
+   You will have to retype this query using an explicit cast
+--
+-- Now some cases with inheritance
+-- Basic 2 table case: 1 column of matching types.
+create table pktable_base (base1 int not null);
+create table pktable (ptest1 int, primary key(base1), unique(base1, ptest1)) inherits (pktable_base);
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+NOTICE:  CREATE TABLE/UNIQUE will create implicit index 'pktable_base1_key' for table 'pktable'
+create table fktable (ftest1 int references pktable(base1));
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+-- now some ins, upd, del
+insert into pktable(base1) values (1);
+insert into pktable(base1) values (2);
+--  let's insert a non-existant fktable value
+insert into fktable(ftest1) values (3);
+ERROR:  <unnamed> referential integrity violation - key referenced from fktable not found in pktable
+--  let's make a valid row for that
+insert into pktable(base1) values (3);
+insert into fktable(ftest1) values (3);
+-- let's try removing a row that should fail from pktable
+delete from pktable where base1>2;
+ERROR:  <unnamed> referential integrity violation - key in pktable still referenced from fktable
+-- okay, let's try updating all of the base1 values to *4
+-- which should fail.
+update pktable set base1=base1*4;
+ERROR:  <unnamed> referential integrity violation - key in pktable still referenced from fktable
+-- okay, let's try an update that should work.
+update pktable set base1=base1*4 where base1<3;
+-- and a delete that should work
+delete from pktable where base1>3;
+-- cleanup
+drop table fktable;
+NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
+NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
+delete from pktable;
+-- Now 2 columns 2 tables, matching types
+create table fktable (ftest1 int, ftest2 int, foreign key(ftest1, ftest2) references pktable(base1, ptest1));
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+-- now some ins, upd, del
+insert into pktable(base1, ptest1) values (1, 1);
+insert into pktable(base1, ptest1) values (2, 2);
+--  let's insert a non-existant fktable value
+insert into fktable(ftest1, ftest2) values (3, 1);
+ERROR:  <unnamed> referential integrity violation - key referenced from fktable not found in pktable
+--  let's make a valid row for that
+insert into pktable(base1,ptest1) values (3, 1);
+insert into fktable(ftest1, ftest2) values (3, 1);
+-- let's try removing a row that should fail from pktable
+delete from pktable where base1>2;
+ERROR:  <unnamed> referential integrity violation - key in pktable still referenced from fktable
+-- okay, let's try updating all of the base1 values to *4
+-- which should fail.
+update pktable set base1=base1*4;
+ERROR:  <unnamed> referential integrity violation - key in pktable still referenced from fktable
+-- okay, let's try an update that should work.
+update pktable set base1=base1*4 where base1<3;
+-- and a delete that should work
+delete from pktable where base1>3;
+-- cleanup
+drop table fktable;
+NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
+NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
+drop table pktable;
+drop table pktable_base;
+-- Now we'll do one all in 1 table with 2 columns of matching types
+create table pktable_base(base1 int not null, base2 int);
+create table pktable(ptest1 int, ptest2 int, primary key(base1, ptest1), foreign key(base2, ptest2) references
+                                             pktable(base1, ptest1)) inherits (pktable_base);
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+insert into pktable (base1, ptest1, base2, ptest2) values (1, 1, 1, 1);
+insert into pktable (base1, ptest1, base2, ptest2) values (2, 1, 1, 1);
+insert into pktable (base1, ptest1, base2, ptest2) values (2, 2, 2, 1);
+insert into pktable (base1, ptest1, base2, ptest2) values (1, 3, 2, 2);
+-- fails (3,2) isn't in base1, ptest1
+insert into pktable (base1, ptest1, base2, ptest2) values (2, 3, 3, 2);
+ERROR:  <unnamed> referential integrity violation - key referenced from pktable not found in pktable
+-- fails (2,2) is being referenced
+delete from pktable where base1=2;
+ERROR:  <unnamed> referential integrity violation - key in pktable still referenced from pktable
+-- fails (1,1) is being referenced (twice)
+update pktable set base1=3 where base1=1;
+ERROR:  <unnamed> referential integrity violation - key in pktable still referenced from pktable
+-- this sequence of two deletes will work, since after the first there will be no (2,*) references
+delete from pktable where base2=2;
+delete from pktable where base1=2;
+drop table pktable;
+drop table pktable_base;
+-- 2 columns (2 tables), mismatched types
+create table pktable_base(base1 int not null);
+create table pktable(ptest1 text, primary key(base1, ptest1)) inherits (pktable_base);
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+-- just generally bad types (with and without column references on the referenced table)
+create table fktable(ftest1 cidr, ftest2 int[], foreign key (ftest1, ftest2) references pktable);
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'cidr' and 'int4'
+   You will have to retype this query using an explicit cast
+create table fktable(ftest1 cidr, ftest2 int[], foreign key (ftest1, ftest2) references pktable(base1, ptest1));
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'cidr' and 'int4'
+   You will have to retype this query using an explicit cast
+-- let's mix up which columns reference which
+create table fktable(ftest1 int, ftest2 text, foreign key(ftest2, ftest1) references pktable);
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'text' and 'int4'
+   You will have to retype this query using an explicit cast
+create table fktable(ftest1 int, ftest2 text, foreign key(ftest2, ftest1) references pktable(base1, ptest1));
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'text' and 'int4'
+   You will have to retype this query using an explicit cast
+create table fktable(ftest1 int, ftest2 text, foreign key(ftest1, ftest2) references pktable(ptest1, base1));
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'int4' and 'text'
+   You will have to retype this query using an explicit cast
+drop table pktable;
+drop table pktable_base;
+-- 2 columns (1 table), mismatched types
+create table pktable_base(base1 int not null, base2 int);
+create table pktable(ptest1 text, ptest2 text[], primary key(base1, ptest1), foreign key(base2, ptest2) references
+                                             pktable(base1, ptest1)) inherits (pktable_base);
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types '_text' and 'text'
+   You will have to retype this query using an explicit cast
+create table pktable(ptest1 text, ptest2 text, primary key(base1, ptest1), foreign key(base2, ptest2) references
+                                             pktable(ptest1, base1)) inherits (pktable_base);
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'int4' and 'text'
+   You will have to retype this query using an explicit cast
+create table pktable(ptest1 text, ptest2 text, primary key(base1, ptest1), foreign key(ptest2, base2) references
+                                             pktable(base1, ptest1)) inherits (pktable_base);
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'text' and 'int4'
+   You will have to retype this query using an explicit cast
+create table pktable(ptest1 text, ptest2 text, primary key(base1, ptest1), foreign key(ptest2, base2) references
+                                             pktable(base1, ptest1)) inherits (pktable_base);
+NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
+NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
+ERROR:  Unable to identify an operator '=' for types 'text' and 'int4'
+   You will have to retype this query using an explicit cast
+drop table pktable;
+ERROR:  table "pktable" does not exist
+drop table pktable_base;
index f90710f8d96ea623a22c247ab5dca1a42175ba2e..f0ac095c535fda08c762c253d44e2ff6fb3b9ae6 100644 (file)
@@ -212,3 +212,39 @@ DROP TABLE tmp3;
 
 DROP TABLE tmp2;
 
+-- Foreign key adding test with mixed types
+
+CREATE TABLE PKTABLE (ptest1 int PRIMARY KEY);
+CREATE TABLE FKTABLE (ftest1 text);
+-- This next should fail, because text=int does not exist
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
+-- This should also fail for the same reason, but here we
+-- give the column name
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1);
+-- This should succeed, even though they are different types
+-- because varchar=int does exist
+DROP TABLE FKTABLE;
+CREATE TABLE FKTABLE (ftest1 varchar);
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
+-- As should this
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1);
+DROP TABLE pktable;
+DROP TABLE fktable;
+
+CREATE TABLE PKTABLE (ptest1 int, ptest2 text, PRIMARY KEY(ptest1, ptest2));
+-- This should fail, because we just chose really odd types
+CREATE TABLE FKTABLE (ftest1 cidr, ftest2 datetime);
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2) references pktable;
+-- Again, so should this...
+DROP TABLE FKTABLE;
+CREATE TABLE FKTABLE (ftest1 cidr, ftest2 datetime);
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2) references pktable(ptest1, ptest2);
+-- This fails because we mixed up the column ordering
+DROP TABLE FKTABLE;
+CREATE TABLE FKTABLE (ftest1 int, ftest2 text);
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2) references pktable(ptest2, ptest1);
+-- As does this...
+ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest2, ftest1) references pktable(ptest1, ptest2);
+
+DROP TABLE FKTABLE;
+DROP TABLE PKTABLE;
index 91ff0aafe58c0efd13c5cbeeddab7a41f1c4565f..587fd850f724aff837d0208addd142a47fa89ccd 100644 (file)
@@ -425,3 +425,159 @@ CREATE TABLE FKTABLE_FAIL1 (ftest1 int REFERENCES pktable(ptest1));
 
 DROP TABLE FKTABLE_FAIL1;
 DROP TABLE PKTABLE;
+
+--
+-- Tests for mismatched types
+--
+-- Basic one column, two table setup 
+CREATE TABLE PKTABLE (ptest1 int PRIMARY KEY);
+-- This next should fail, because text=int does not exist
+CREATE TABLE FKTABLE (ftest1 text REFERENCES pktable);
+-- This should also fail for the same reason, but here we
+-- give the column name
+CREATE TABLE FKTABLE (ftest1 text REFERENCES pktable(ptest1));
+-- This should succeed, even though they are different types
+-- because varchar=int does exist
+CREATE TABLE FKTABLE (ftest1 varchar REFERENCES pktable);
+DROP TABLE FKTABLE;
+-- As should this
+CREATE TABLE FKTABLE (ftest1 varchar REFERENCES pktable(ptest1));
+DROP TABLE FKTABLE;
+DROP TABLE PKTABLE;
+
+-- Two columns, two tables
+CREATE TABLE PKTABLE (ptest1 int, ptest2 text, PRIMARY KEY(ptest1, ptest2));
+-- This should fail, because we just chose really odd types
+CREATE TABLE FKTABLE (ftest1 cidr, ftest2 datetime, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable);
+-- Again, so should this...
+CREATE TABLE FKTABLE (ftest1 cidr, ftest2 datetime, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest1, ptest2));
+-- This fails because we mixed up the column ordering
+CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable);
+-- As does this...
+CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest1, ptest2));
+-- And again..
+CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest2, ptest1));
+-- This works...
+CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest2, ptest1));
+DROP TABLE FKTABLE;
+-- As does this
+CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest1, ptest2));
+DROP TABLE FKTABLE;
+DROP TABLE PKTABLE;
+
+-- Two columns, same table
+-- Make sure this still works...
+CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
+ptest4) REFERENCES pktable(ptest1, ptest2));
+DROP TABLE PKTABLE;
+-- And this, 
+CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
+ptest4) REFERENCES pktable);
+DROP TABLE PKTABLE;
+-- This shouldn't (mixed up columns)
+CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
+ptest4) REFERENCES pktable(ptest2, ptest1));
+-- Nor should this... (same reason, we have 4,3 referencing 1,2 which mismatches types
+CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest4,
+ptest3) REFERENCES pktable(ptest1, ptest2));
+-- Not this one either... Same as the last one except we didn't defined the columns being referenced.
+CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest4,
+ptest3) REFERENCES pktable);
+
+--
+-- Now some cases with inheritance
+-- Basic 2 table case: 1 column of matching types.
+create table pktable_base (base1 int not null);
+create table pktable (ptest1 int, primary key(base1), unique(base1, ptest1)) inherits (pktable_base);
+create table fktable (ftest1 int references pktable(base1));
+-- now some ins, upd, del
+insert into pktable(base1) values (1);
+insert into pktable(base1) values (2);
+--  let's insert a non-existant fktable value
+insert into fktable(ftest1) values (3);
+--  let's make a valid row for that
+insert into pktable(base1) values (3);
+insert into fktable(ftest1) values (3);
+-- let's try removing a row that should fail from pktable
+delete from pktable where base1>2;
+-- okay, let's try updating all of the base1 values to *4
+-- which should fail.
+update pktable set base1=base1*4;
+-- okay, let's try an update that should work.
+update pktable set base1=base1*4 where base1<3;
+-- and a delete that should work
+delete from pktable where base1>3;
+-- cleanup
+drop table fktable;
+delete from pktable;
+
+-- Now 2 columns 2 tables, matching types
+create table fktable (ftest1 int, ftest2 int, foreign key(ftest1, ftest2) references pktable(base1, ptest1));
+-- now some ins, upd, del
+insert into pktable(base1, ptest1) values (1, 1);
+insert into pktable(base1, ptest1) values (2, 2);
+--  let's insert a non-existant fktable value
+insert into fktable(ftest1, ftest2) values (3, 1);
+--  let's make a valid row for that
+insert into pktable(base1,ptest1) values (3, 1);
+insert into fktable(ftest1, ftest2) values (3, 1);
+-- let's try removing a row that should fail from pktable
+delete from pktable where base1>2;
+-- okay, let's try updating all of the base1 values to *4
+-- which should fail.
+update pktable set base1=base1*4;
+-- okay, let's try an update that should work.
+update pktable set base1=base1*4 where base1<3;
+-- and a delete that should work
+delete from pktable where base1>3;
+-- cleanup
+drop table fktable;
+drop table pktable;
+drop table pktable_base;
+
+-- Now we'll do one all in 1 table with 2 columns of matching types
+create table pktable_base(base1 int not null, base2 int);
+create table pktable(ptest1 int, ptest2 int, primary key(base1, ptest1), foreign key(base2, ptest2) references
+                                             pktable(base1, ptest1)) inherits (pktable_base);
+insert into pktable (base1, ptest1, base2, ptest2) values (1, 1, 1, 1);
+insert into pktable (base1, ptest1, base2, ptest2) values (2, 1, 1, 1);
+insert into pktable (base1, ptest1, base2, ptest2) values (2, 2, 2, 1);
+insert into pktable (base1, ptest1, base2, ptest2) values (1, 3, 2, 2);
+-- fails (3,2) isn't in base1, ptest1
+insert into pktable (base1, ptest1, base2, ptest2) values (2, 3, 3, 2);
+-- fails (2,2) is being referenced
+delete from pktable where base1=2;
+-- fails (1,1) is being referenced (twice)
+update pktable set base1=3 where base1=1;
+-- this sequence of two deletes will work, since after the first there will be no (2,*) references
+delete from pktable where base2=2;
+delete from pktable where base1=2;
+drop table pktable;
+drop table pktable_base;
+
+-- 2 columns (2 tables), mismatched types
+create table pktable_base(base1 int not null);
+create table pktable(ptest1 text, primary key(base1, ptest1)) inherits (pktable_base);
+-- just generally bad types (with and without column references on the referenced table)
+create table fktable(ftest1 cidr, ftest2 int[], foreign key (ftest1, ftest2) references pktable);
+create table fktable(ftest1 cidr, ftest2 int[], foreign key (ftest1, ftest2) references pktable(base1, ptest1));
+-- let's mix up which columns reference which
+create table fktable(ftest1 int, ftest2 text, foreign key(ftest2, ftest1) references pktable);
+create table fktable(ftest1 int, ftest2 text, foreign key(ftest2, ftest1) references pktable(base1, ptest1));
+create table fktable(ftest1 int, ftest2 text, foreign key(ftest1, ftest2) references pktable(ptest1, base1));
+drop table pktable;
+drop table pktable_base;
+
+-- 2 columns (1 table), mismatched types
+create table pktable_base(base1 int not null, base2 int);
+create table pktable(ptest1 text, ptest2 text[], primary key(base1, ptest1), foreign key(base2, ptest2) references
+                                             pktable(base1, ptest1)) inherits (pktable_base);
+create table pktable(ptest1 text, ptest2 text, primary key(base1, ptest1), foreign key(base2, ptest2) references
+                                             pktable(ptest1, base1)) inherits (pktable_base);
+create table pktable(ptest1 text, ptest2 text, primary key(base1, ptest1), foreign key(ptest2, base2) references
+                                             pktable(base1, ptest1)) inherits (pktable_base);
+create table pktable(ptest1 text, ptest2 text, primary key(base1, ptest1), foreign key(ptest2, base2) references
+                                             pktable(base1, ptest1)) inherits (pktable_base);
+drop table pktable;
+drop table pktable_base;
+