From 42d5e34e779c540787712e6475c25a1cb4e03e61 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Mon, 18 Dec 2000 01:37:56 +0000
Subject: [PATCH] Repair mishandling of PRIMARY KEY declaration that references
 an inherited column, per bug report from Elphick 12/15/00.

---
 src/backend/parser/analyze.c | 79 ++++++++++++++++++++++++------------
 1 file changed, 54 insertions(+), 25 deletions(-)

diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 4be93ff5822..1c7c5dab56f 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -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 (; count<rel->rd_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 */
-- 
GitLab