diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 620054380a46450231f4df289b4398c22a64738d..6977a6081de7a1384052812ebbc22c8095cfda50 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.159 2001/10/25 05:49:30 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.160 2001/11/05 05:00:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1835,6 +1835,7 @@ _copySelectStmt(SelectStmt *from)
 	if (from->into)
 		newnode->into = pstrdup(from->into);
 	newnode->istemp = from->istemp;
+	Node_Copy(from, newnode, intoColNames);
 	Node_Copy(from, newnode, targetList);
 	Node_Copy(from, newnode, fromClause);
 	Node_Copy(from, newnode, whereClause);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 0a48a194df3081e78bb4f8810c38219ab6e428aa..538a773e31b406b3e9388b69617d3681b12f4cf4 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.107 2001/10/25 05:49:30 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.108 2001/11/05 05:00:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -681,6 +681,8 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b)
 		return false;
 	if (a->istemp != b->istemp)
 		return false;
+	if (!equal(a->intoColNames, b->intoColNames))
+		return false;
 	if (!equal(a->targetList, b->targetList))
 		return false;
 	if (!equal(a->fromClause, b->fromClause))
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 0d833079e4a2bc2126be879cd43882330fd312e9..40e9700f024f0a4a5200c2b66573b931ca2ef5ac 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -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.209 2001/11/04 03:08:11 momjian Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.210 2001/11/05 05:00:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -88,6 +88,7 @@ static void transformFKConstraints(ParseState *pstate,
 					   CreateStmtContext *cxt);
 static Node *transformTypeRefs(ParseState *pstate, Node *stmt);
 
+static void applyColumnNames(List *dst, List *src);
 static void transformTypeRefsList(ParseState *pstate, List *l);
 static void transformTypeRef(ParseState *pstate, TypeName *tn);
 static List *getSetColTypes(ParseState *pstate, Node *node);
@@ -1942,9 +1943,13 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
 	/* process the FROM clause */
 	transformFromClause(pstate, stmt->fromClause);
 
-	/* transform targetlist and WHERE */
+	/* transform targetlist */
 	qry->targetList = transformTargetList(pstate, stmt->targetList);
 
+	if (stmt->intoColNames)
+		applyColumnNames(qry->targetList, stmt->intoColNames);
+
+	/* transform WHERE */
 	qual = transformWhereClause(pstate, stmt->whereClause);
 
 	/*
@@ -2003,6 +2008,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 	SetOperationStmt *sostmt;
 	char	   *into;
 	bool		istemp;
+	List	   *intoColNames;
 	char	   *portalname;
 	bool		binary;
 	List	   *sortClause;
@@ -2031,12 +2037,14 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 		   leftmostSelect->larg == NULL);
 	into = leftmostSelect->into;
 	istemp = leftmostSelect->istemp;
+	intoColNames = leftmostSelect->intoColNames;
 	portalname = stmt->portalname;
 	binary = stmt->binary;
 
 	/* clear them to prevent complaints in transformSetOperationTree() */
 	leftmostSelect->into = NULL;
 	leftmostSelect->istemp = false;
+	leftmostSelect->intoColNames = NIL;
 	stmt->portalname = NULL;
 	stmt->binary = false;
 
@@ -2149,6 +2157,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 		qry->isBinary = FALSE;
 	}
 
+	if (intoColNames)
+		applyColumnNames(qry->targetList, intoColNames);
+
 	/*
 	 * As a first step towards supporting sort clauses that are
 	 * expressions using the output columns, generate a namespace entry
@@ -2377,6 +2388,27 @@ getSetColTypes(ParseState *pstate, Node *node)
 	}
 }
 
+/* Attach column names from a ColumnDef list to a TargetEntry list */
+static void
+applyColumnNames(List *dst, List *src)
+{
+	if (length(src) > length(dst))
+		elog(ERROR,"CREATE TABLE AS specifies too many column names");
+
+	while (src != NIL && dst != NIL)
+	{
+		TargetEntry *d = (TargetEntry *) lfirst(dst);
+		ColumnDef *s = (ColumnDef *) lfirst(src);
+
+		Assert(d->resdom && !d->resdom->resjunk);
+
+		d->resdom->resname = pstrdup(s->colname);
+
+		dst = lnext(dst);
+		src = lnext(src);
+	}
+}
+
 
 /*
  * transformUpdateStmt -
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c97c9da509e14a3ec2326012ea1be52b7be43b1f..63465c916861ce5d257989489aa753b7edd2282e 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.271 2001/10/31 04:49:43 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.272 2001/11/05 05:00:14 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -86,7 +86,6 @@ static Node *makeTypeCast(Node *arg, TypeName *typename);
 static Node *makeStringConst(char *str, TypeName *typename);
 static Node *makeFloatConst(char *str);
 static Node *makeRowExpr(char *opr, List *largs, List *rargs);
-static void mapTargetColumns(List *source, List *target);
 static SelectStmt *findLeftmostSelect(SelectStmt *node);
 static void insertSelectOptions(SelectStmt *stmt,
 								List *sortClause, List *forUpdate,
@@ -1611,11 +1610,10 @@ CreateAsStmt:  CREATE OptTemp TABLE relation_name OptCreateAs AS SelectStmt
 					 */
 					SelectStmt *n = findLeftmostSelect((SelectStmt *) $7);
 					if (n->into != NULL)
-						elog(ERROR,"CREATE TABLE / AS SELECT may not specify INTO");
+						elog(ERROR,"CREATE TABLE AS may not specify INTO");
 					n->istemp = $2;
 					n->into = $4;
-					if ($5 != NIL)
-						mapTargetColumns($5, n->targetList);
+					n->intoColNames = $5;
 					$$ = $7;
 				}
 		;
@@ -3552,6 +3550,7 @@ simple_select: SELECT opt_distinct target_list
 					n->targetList = $3;
 					n->istemp = (bool) ((Value *) lfirst($4))->val.ival;
 					n->into = (char *) lnext($4);
+					n->intoColNames = NIL;
 					n->fromClause = $5;
 					n->whereClause = $6;
 					n->groupClause = $7;
@@ -6106,28 +6105,6 @@ makeRowExpr(char *opr, List *largs, List *rargs)
 	return expr;
 }
 
-static void
-mapTargetColumns(List *src, List *dst)
-{
-	ColumnDef *s;
-	ResTarget *d;
-
-	if (length(src) != length(dst))
-		elog(ERROR,"CREATE TABLE / AS SELECT has mismatched column count");
-
-	while ((src != NIL) && (dst != NIL))
-	{
-		s = (ColumnDef *)lfirst(src);
-		d = (ResTarget *)lfirst(dst);
-
-		d->name = s->colname;
-
-		src = lnext(src);
-		dst = lnext(dst);
-	}
-} /* mapTargetColumns() */
-
-
 /* findLeftmostSelect()
  *		Find the leftmost component SelectStmt in a set-operation parsetree.
  */
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 1abd7ba365a824f4c799d95b36e72473c139584f..892177c920c63e5fb7bda406cb89fab78959017b 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.149 2001/10/28 06:26:07 momjian Exp $
+ * $Id: parsenodes.h,v 1.150 2001/11/05 05:00:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -881,6 +881,7 @@ typedef struct SelectStmt
 								 * DISTINCT) */
 	char	   *into;			/* name of table (for select into table) */
 	bool		istemp;			/* into is a temp table? */
+	List	   *intoColNames;	/* column names for into table */
 	List	   *targetList;		/* the target list (of ResTarget) */
 	List	   *fromClause;		/* the FROM clause */
 	Node	   *whereClause;	/* WHERE qualification */