diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index cf43da0d70747f85e1e80034fd26c89b21a4ead6..ba0a3cfa348b7ed29f931a56e3c156446c8b9177 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
  *
- *	$Id: analyze.c,v 1.180 2001/02/14 23:32:38 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.181 2001/02/15 01:10:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1871,7 +1871,11 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 	List	   *forUpdate;
 	Node	   *node;
 	List	   *lefttl,
-			   *dtlist;
+			   *dtlist,
+			   *targetvars,
+			   *targetnames,
+			   *sv_namespace;
+	JoinExpr   *jnode;
 	int			tllen;
 
 	qry->commandType = CMD_SELECT;
@@ -1934,22 +1938,26 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 	Assert(leftmostQuery != NULL);
 	/*
 	 * Generate dummy targetlist for outer query using column names of
-	 * leftmost select and common datatypes of topmost set operation
+	 * leftmost select and common datatypes of topmost set operation.
+	 * Also make lists of the dummy vars and their names for use in
+	 * parsing ORDER BY.
 	 */
 	qry->targetList = NIL;
+	targetvars = NIL;
+	targetnames = NIL;
 	lefttl = leftmostQuery->targetList;
 	foreach(dtlist, sostmt->colTypes)
 	{
 		Oid		colType = (Oid) lfirsti(dtlist);
 		Resdom *leftResdom = ((TargetEntry *) lfirst(lefttl))->resdom;
-		char   *colName = leftResdom->resname;
+		char   *colName = pstrdup(leftResdom->resname);
 		Resdom *resdom;
 		Node   *expr;
 
 		resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
 							colType,
 							-1,
-							pstrdup(colName),
+							colName,
 							false);
 		expr = (Node *) makeVar(leftmostRTI,
 								leftResdom->resno,
@@ -1958,6 +1966,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 								0);
 		qry->targetList = lappend(qry->targetList,
 								  makeTargetEntry(resdom, expr));
+		targetvars = lappend(targetvars, expr);
+		targetnames = lappend(targetnames, makeString(colName));
 		lefttl = lnext(lefttl);
 	}
 	/*
@@ -1997,6 +2007,23 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 		qry->isBinary = FALSE;
 	}
 
+	/*
+	 * As a first step towards supporting sort clauses that are expressions
+	 * using the output columns, generate a namespace entry that makes the
+	 * output columns visible.  A JoinExpr node is handy for this, since
+	 * we can easily control the Vars generated upon matches.
+	 *
+	 * Note: we don't yet do anything useful with such cases, but at least
+	 * "ORDER BY upper(foo)" will draw the right error message rather than
+	 * "foo not found".
+	 */
+	jnode = makeNode(JoinExpr);
+	jnode->colnames = targetnames;
+	jnode->colvars = targetvars;
+
+	sv_namespace = pstate->p_namespace;
+	pstate->p_namespace = makeList1(jnode);
+
 	/*
 	 * For now, we don't support resjunk sort clauses on the output of a
 	 * setOperation tree --- you can only use the SQL92-spec options of
@@ -2009,6 +2036,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 										  sortClause,
 										  qry->targetList);
 
+	pstate->p_namespace = sv_namespace;
+
 	if (tllen != length(qry->targetList))
 		elog(ERROR, "ORDER BY on a UNION/INTERSECT/EXCEPT result must be on one of the result columns");