]> granicus.if.org Git - postgresql/commitdiff
Fix foreign keys on system columns.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 23 Oct 2001 17:39:03 +0000 (17:39 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 23 Oct 2001 17:39:03 +0000 (17:39 +0000)
src/backend/commands/command.c
src/backend/parser/analyze.c
src/backend/parser/parse_relation.c
src/include/parser/parse_relation.h

index a81d097d8b0e56fb4c8e5d4f68b3dd70accf467f..5297f7481d6ec432f0a54a3a2db553281dd7dd11 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.144 2001/10/12 00:07:14 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.145 2001/10/23 17:39:02 tgl Exp $
  *
  * NOTES
  *       The PerformAddAttribute() code, like most of the relation
@@ -1347,9 +1347,7 @@ AlterTableAddConstraint(char *relationName,
                             bool  istemp = is_temp_rel_name(relationName);
                             List          *indexoidlist;
                             List     *indexoidscan;
-                            Form_pg_attribute *rel_attrs;
-                            int num_keys = 0;
-                            int keys_matched = 0;
+                            int num_keys;
                             bool index_found = false;
                             bool index_found_unique = false;
                             bool index_found_primary = false;
@@ -1394,15 +1392,9 @@ AlterTableAddConstraint(char *relationName,
                              * constraint
                              */
 
-                            rel_attrs = rel->rd_att->attrs;
-
-                            /* Retrieve the oids of all indices on the relation */
+                            /* Loop over all indices on the relation */
                             indexoidlist = RelationGetIndexList(rel);
-                            index_found = false;
-                            index_found_unique = false;
-                            index_found_primary = false;
 
-                            /* Loop over all indices on the relation */
                             foreach(indexoidscan, indexoidlist)
                             {
                                Oid                     indexoid = lfirsti(indexoidscan);
@@ -1424,43 +1416,41 @@ AlterTableAddConstraint(char *relationName,
                                * Make sure this index has the same number of
                                * keys as the constraint -- It obviously won't match otherwise.
                                */
-                               for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++);
+                               for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
+                                                                  ;
                                num_keys = length(constr->keys);
-                               keys_matched = 0;
 
                                if (i == num_keys)
                                {
                                   /* Loop over each key in the constraint and check that there is a
                                      corresponding key in the index. */
+                                                                  int keys_matched = 0;
+
                                   i = 0;
                                   foreach(keyl, constr->keys)
                                   {
                                      Ident    *key = lfirst(keyl);
+                                                                        int       keyno = indexStruct->indkey[i];
 
                                      /* Look at key[i] in the index and check that it is over the same column
                                         as key[i] in the constraint.  This is to differentiate between (a,b)
                                         and (b,a) */
-                                     if (i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0)
-                                     {
-                                        int       keyno = indexStruct->indkey[i];
-
-                                        if (keyno > 0)
-                                        {
-                                           char  *name = NameStr(rel_attrs[keyno - 1]->attname);
-                                           if (strcmp(name, key->name) == 0) keys_matched++;
-                                        }
-                                     }
-                                     else elog(ERROR, "ALTER TABLE/ADD CONSTRAINT: Key \"%u[%u]\" not found", indexoid, i);
+                                                                        if (namestrcmp(attnumAttName(rel, keyno),
+                                                                                                       key->name) == 0)
+                                                                                keys_matched++;
+                                                                        else
+                                                                                break;
                                      i++;
                                   }
                                   if (keys_matched == num_keys) {
                                      index_found = true;
                                      index_found_unique = indexStruct->indisunique;
                                      index_found_primary = indexStruct->indisprimary;
-                                     if (index_found_unique || index_found_primary) break;
                                   }
                                }
                                ReleaseSysCache(indexTuple);
+                                                          if (index_found_unique || index_found_primary)
+                                                                  break;
                             }
 
                             freeList(indexoidlist);
@@ -1504,19 +1494,7 @@ AlterTableAddConstraint(char *relationName,
                                Trigger         trig;
                                List       *list;
                                int                     count;
-                               List       *indexoidlist,
-                                                  *indexoidscan;
-                               Form_pg_attribute *rel_attrs = NULL;
-                               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.");
@@ -1530,140 +1508,21 @@ AlterTableAddConstraint(char *relationName,
                                if (pkrel->rd_rel->relkind != RELKIND_RELATION)
                                        elog(ERROR, "referenced table \"%s\" not a relation",
                                                 fkconstraint->pktable_name);
+                               heap_close(pkrel, NoLock);
 
                                /*
+                                * First we check for limited correctness of the constraint.
+                                *
+                                * NOTE: we assume parser has already checked for existence
+                                * of an appropriate unique index on the referenced relation,
+                                * and that the column datatypes are comparable.
+                                *
                                 * Scan through each tuple, calling the RI_FKey_Match_Ins
                                 * (insert trigger) as if that tuple had just been
                                 * inserted.  If any of those fail, it should elog(ERROR)
                                 * and that's that.
                                 */
 
-                               /*
-                                * First we check for limited correctness of the
-                                * constraint
-                                */
-
-                               rel_attrs = pkrel->rd_att->attrs;
-                               indexoidlist = RelationGetIndexList(pkrel);
-
-                               foreach(indexoidscan, indexoidlist)
-                               {
-                                       Oid                     indexoid = lfirsti(indexoidscan);
-                                       HeapTuple       indexTuple;
-                                       Form_pg_index indexStruct;
-
-                                       indexTuple = SearchSysCache(INDEXRELID,
-                                                                                         ObjectIdGetDatum(indexoid),
-                                                                                               0, 0, 0);
-                                       if (!HeapTupleIsValid(indexTuple))
-                                               elog(ERROR, "transformFkeyGetPrimaryKey: index %u not found",
-                                                        indexoid);
-                                       indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
-
-                                       if (indexStruct->indisunique)
-                                       {
-                                               List       *attrl;
-
-                                               /*
-                                                * 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
-                                               {
-                                                       attloc=0;
-                                                       /* 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++)
-                                                               {
-                                                                       int                     pkattno = indexStruct->indkey[i];
-
-                                                                       if (pkattno > 0)
-                                                                       {
-                                                                               char       *name = NameStr(rel_attrs[pkattno - 1]->attname);
-
-                                                                               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;
-                                                                               }
-                                                                       }
-                                                               }
-                                                               if (!found)
-                                                                       break;
-                                                       }
-                                               }
-                                       }
-                                       ReleaseSysCache(indexTuple);
-                                       if (found)
-                                               break;
-                               }
-
-                               if (!found)
-                                       elog(ERROR, "UNIQUE constraint matching given keys for referenced table \"%s\" not found",
-                                                fkconstraint->pktable_name);
-
-                               freeList(indexoidlist);
-                               heap_close(pkrel, NoLock);
-
-                               rel_attrs = rel->rd_att->attrs;
-                               if (fkconstraint->fk_attrs != NIL)
-                               {
-                                       List       *fkattrs;
-                                       Ident      *fkattr;
-
-                                       found = false;
-                                       attloc = 0;
-                                       foreach(fkattrs, fkconstraint->fk_attrs)
-                                       {
-                                               int                     count;
-
-                                               found = false;
-                                               fkattr = lfirst(fkattrs);
-                                               for (count = 0; count < rel->rd_att->natts; count++)
-                                               {
-                                                       char       *name = NameStr(rel->rd_att->attrs[count]->attname);
-
-                                                       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;
-                                                       }
-                                               }
-                                               if (!found)
-                                                       break;
-                                       }
-                                       if (!found)
-                                               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;
@@ -1706,7 +1565,6 @@ AlterTableAddConstraint(char *relationName,
                                trig.tgnargs = count - 1;
 
                                scan = heap_beginscan(rel, false, SnapshotNow, 0, NULL);
-                               AssertState(scan != NULL);
 
                                while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
                                {
index 6c61ab9acbf38ca6a7dbbbad0f99dbf20dbd45e0..6e89abefe8a62d662cf9ebfe086f18ccaadc21ac 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.202 2001/10/22 22:49:02 tgl Exp $
+ *     $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.203 2001/10/23 17:39:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2428,7 +2428,6 @@ getSetColTypes(ParseState *pstate, Node *node)
 /*
  * transformUpdateStmt -
  *       transforms an update statement
- *
  */
 static Query *
 transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
@@ -2802,17 +2801,15 @@ static void
 transformFkeyCheckAttrs(FkConstraint *fkconstraint, Oid *pktypoid)
 {
        Relation        pkrel;
-       Form_pg_attribute *pkrel_attrs;
        List       *indexoidlist,
                           *indexoidscan;
        int                     i;
        bool            found = false;
 
        /*
-        * Open the referenced table and get the attributes list
+        * Open the referenced table
         */
        pkrel = heap_openr(fkconstraint->pktable_name, AccessShareLock);
-       pkrel_attrs = pkrel->rd_att->attrs;
 
        /*
         * Get the list of index OIDs for the table from the relcache, and
@@ -2827,6 +2824,7 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint, Oid *pktypoid)
                HeapTuple       indexTuple;
                Form_pg_index indexStruct;
 
+               found = false;
                indexTuple = SearchSysCache(INDEXRELID,
                                                                        ObjectIdGetDatum(indexoid),
                                                                        0, 0, 0);
@@ -2837,16 +2835,14 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint, Oid *pktypoid)
 
                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))
-                               found = false;
-                       else
+                       if (i == length(fkconstraint->pk_attrs))
                        {
                                /* go through the fkconstraint->pk_attrs list */
+                               List       *attrl;
+                               int        attnum = 0;
+
                                foreach(attrl, fkconstraint->pk_attrs)
                                {
                                        Ident      *attr = lfirst(attrl);
@@ -2856,16 +2852,12 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint, Oid *pktypoid)
                                        {
                                                int                     pkattno = indexStruct->indkey[i];
 
-                                               if (pkattno > 0)
+                                               if (namestrcmp(attnumAttName(pkrel, pkattno),
+                                                                          attr->name) == 0)
                                                {
-                                                       char       *name = NameStr(pkrel_attrs[pkattno - 1]->attname);
-
-                                                       if (strcmp(name, attr->name) == 0)
-                                                       {
-                                                               pktypoid[attnum++]=pkrel_attrs[pkattno-1]->atttypid;
-                                                               found = true;
-                                                               break;
-                                                       }
+                                                       pktypoid[attnum++] = attnumTypeId(pkrel, pkattno);
+                                                       found = true;
+                                                       break;
                                                }
                                        }
                                        if (!found)
@@ -2896,7 +2888,6 @@ static void
 transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid)
 {
        Relation        pkrel;
-       Form_pg_attribute *pkrel_attrs;
        List       *indexoidlist,
                           *indexoidscan;
        HeapTuple       indexTuple = NULL;
@@ -2905,10 +2896,9 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid)
        int             attnum=0;
 
        /*
-        * Open the referenced table and get the attributes list
+        * Open the referenced table
         */
        pkrel = heap_openr(fkconstraint->pktable_name, AccessShareLock);
-       pkrel_attrs = pkrel->rd_att->attrs;
 
        /*
         * Get the list of index OIDs for the table from the relcache, and
@@ -2952,10 +2942,10 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid)
                int                     pkattno = indexStruct->indkey[i];
                Ident      *pkattr = makeNode(Ident);
 
-               pkattr->name = pstrdup(NameStr(pkrel_attrs[pkattno-1]->attname));
+               pkattr->name = pstrdup(NameStr(*attnumAttName(pkrel, pkattno)));
                pkattr->indirection = NIL;
                pkattr->isRel = false;
-               pktypoid[attnum++] = pkrel_attrs[pkattno-1]->atttypid;
+               pktypoid[attnum++] = attnumTypeId(pkrel, pkattno);
 
                fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs, pkattr);
        }
@@ -3023,6 +3013,7 @@ transformFkeyGetColType(CreateStmtContext *cxt, char *colname)
        List       *cols;
        List       *inher;
        Oid                     result;
+       Form_pg_attribute sysatt;
 
        /* First look for column among the newly-created columns */
        foreach(cols, cxt->columns)
@@ -3040,6 +3031,10 @@ transformFkeyGetColType(CreateStmtContext *cxt, char *colname)
                        return result;
                }
        }
+       /* Perhaps it's a system column name */
+       sysatt = SystemAttributeByName(colname, cxt->hasoids);
+       if (sysatt)
+               return sysatt->atttypid;
        /* Look for column among inherited columns (if CREATE TABLE case) */
        foreach(inher, cxt->inhRelnames)
        {
index 5077d092da4f3d51566648b1ee32d254b61cd4ef..10861bf273b696efda4d8c0bef8d99fabd4e7fbf 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.57 2001/10/22 22:47:57 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.58 2001/10/23 17:39:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -938,7 +938,7 @@ attnameAttNum(Relation rd, char *a)
        int                     i;
 
        for (i = 0; i < rd->rd_rel->relnatts; i++)
-               if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a))
+               if (namestrcmp(&(rd->rd_att->attrs[i]->attname), a) == 0)
                        return i + 1;
 
        if ((i = specialAttNum(a)) != InvalidAttrNumber)
@@ -974,6 +974,28 @@ specialAttNum(char *a)
 }
 
 
+/*
+ * given attribute id, return name of that attribute
+ *
+ *     This should only be used if the relation is already
+ *     heap_open()'ed.  Use the cache version get_atttype()
+ *     for access to non-opened relations.
+ */
+Name
+attnumAttName(Relation rd, int attid)
+{
+       if (attid <= 0)
+       {
+               Form_pg_attribute sysatt;
+
+               sysatt = SystemAttributeDefinition(attid, rd->rd_rel->relhasoids);
+               return &sysatt->attname;
+       }
+       if (attid > rd->rd_att->natts)
+               elog(ERROR, "attnumAttName: invalid attribute number %d", attid);
+       return &rd->rd_att->attrs[attid - 1]->attname;
+}
+
 /*
  * given attribute id, return type of that attribute
  *
@@ -991,10 +1013,8 @@ attnumTypeId(Relation rd, int attid)
                sysatt = SystemAttributeDefinition(attid, rd->rd_rel->relhasoids);
                return sysatt->atttypid;
        }
-
-       /*
-        * -1 because attid is 1-based
-        */
+       if (attid > rd->rd_att->natts)
+               elog(ERROR, "attnumTypeId: invalid attribute number %d", attid);
        return rd->rd_att->attrs[attid - 1]->atttypid;
 }
 
index 82b3b0dd1560a587e278e03b5314dce7aafa8039..0cf4f40f19e8a2ae1a406b83880178f89b26c150 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_relation.h,v 1.24 2001/08/10 18:57:41 tgl Exp $
+ * $Id: parse_relation.h,v 1.25 2001/10/23 17:39:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -45,6 +45,7 @@ extern List *expandRelAttrs(ParseState *pstate, RangeTblEntry *rte);
 extern List *expandJoinAttrs(ParseState *pstate, JoinExpr *join,
                                int sublevels_up);
 extern int     attnameAttNum(Relation rd, char *a);
+extern Name attnumAttName(Relation rd, int attid);
 extern Oid     attnumTypeId(Relation rd, int attid);
 
 #endif  /* PARSE_RELATION_H */