Repair mishandling of PRIMARY KEY declaration that references an
authorTom Lane
Mon, 18 Dec 2000 01:37:56 +0000 (01:37 +0000)
committerTom Lane
Mon, 18 Dec 2000 01:37:56 +0000 (01:37 +0000)
inherited column, per bug report from Elphick 12/15/00.

src/backend/parser/analyze.c

index 4be93ff5822d859560a4ebc1b56b5bfa6d59bd93..1c7c5dab56fa6f96cf1ccd8e77acd0b316a09c06 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.172 2000/12/07 01:12:08 tgl Exp $
+ * $Id: analyze.c,v 1.173 2000/12/18 01:37:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -945,9 +945,10 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
        index->withClause = NIL;
        index->whereClause = NULL;
 
-       foreach(keys, constraint->keys)
+       foreach (keys, constraint->keys)
        {
-           int found=0;
+           bool    found = false;
+
            key = (Ident *) lfirst(keys);
            Assert(IsA(key, Ident));
            column = NULL;
@@ -956,26 +957,58 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
                column = lfirst(columns);
                Assert(IsA(column, ColumnDef));
                if (strcmp(column->colname, key->name) == 0)
+               {
+                   found = true;
                    break;
+               }
+           }
+           if (found)
+           {
+               /* found column in the new table; force it to be NOT NULL */
+               if (constraint->contype == CONSTR_PRIMARY)
+                   column->is_not_null = TRUE;
            }
-           if (columns == NIL) { /* try inherited tables */
+           else
+           {
+               /* try inherited tables */
+               List *inhRelnames = stmt->inhRelnames;
                List *inher;
-               List *inhRelnames=stmt->inhRelnames;
-               Relation rel;
-               foreach (inher, inhRelnames) {
-                   int count=0;
-                   Value *inh=lfirst(inher);
-                   if (inh->type!=T_String) {
-                       elog(ERROR, "inherited table name list returns a non-string");
-                   }
-                   rel=heap_openr(inh->val.str, AccessShareLock);
+
+               foreach (inher, inhRelnames)
+               {
+                   Value *inh = lfirst(inher);
+                   Relation rel;
+                   int count;
+
+                   Assert(IsA(inh, String));
+                   rel = heap_openr(inh->val.str, AccessShareLock);
                    if (rel->rd_rel->relkind != RELKIND_RELATION)
                        elog(ERROR, "inherited table \"%s\" is not a relation",
-                           inh->val.str);
-                   for (; countrd_att->natts; count++) {
-                       char *name=NameStr(rel->rd_att->attrs[count]->attname);
-                       if (strcmp(key->name, name) == 0) {
-                           found=1;
+                            inh->val.str);
+                   for (count = 0; count < rel->rd_att->natts; count++)
+                   {
+                       Form_pg_attribute inhattr = rel->rd_att->attrs[count];
+                       char *inhname = NameStr(inhattr->attname);
+
+                       if (strcmp(key->name, inhname) == 0)
+                       {
+                           found = true;
+                           /*
+                            * If the column is inherited, we currently have
+                            * no easy way to force it to be NOT NULL.
+                            * Only way I can see to fix this would be to
+                            * convert the inherited-column info to ColumnDef
+                            * nodes before we reach this point, and then
+                            * create the table from those nodes rather than
+                            * referencing the parent tables later.  That
+                            * would likely be cleaner, but too much work
+                            * to contemplate right now.  Instead, raise an
+                            * error if the inherited column won't be NOT NULL.
+                            * (Would a NOTICE be more reasonable?)
+                            */
+                           if (! inhattr->attnotnull)
+                               elog(ERROR, "inherited attribute \"%s\" cannot be a PRIMARY KEY because it is not marked NOT NULL",
+                                    inhname);
                            break;
                        }
                    }
@@ -984,16 +1017,11 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
                        break;
                }
            }
-           else {
-               found=1;
-           }
 
            if (!found)
-               elog(ERROR, "CREATE TABLE: column '%s' named in key does not exist",
+               elog(ERROR, "CREATE TABLE: column \"%s\" named in key does not exist",
                     key->name);
 
-           if (constraint->contype == CONSTR_PRIMARY)
-               column->is_not_null = TRUE;
            iparam = makeNode(IndexElem);
            iparam->name = pstrdup(key->name);
            iparam->args = NIL;
@@ -1001,7 +1029,8 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
            index->indexParams = lappend(index->indexParams, iparam);
 
            if (index->idxname == NULL)
-               index->idxname = CreateIndexName(stmt->relname, iparam->name, "key", ilist);
+               index->idxname = CreateIndexName(stmt->relname, iparam->name,
+                                                "key", ilist);
        }
 
        if (index->idxname == NULL)     /* should not happen */