66 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
9- *$Id: analyze.c,v 1.180 2001/02/14 23:32:38 tgl Exp $
9+ *$Header: /cvsroot/pgsql/src/backend/parser/ analyze.c,v 1.181 2001/02/15 01:10:28 tgl Exp $
1010 *
1111 *-------------------------------------------------------------------------
1212 */
@@ -1871,7 +1871,11 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
18711871List * forUpdate ;
18721872Node * node ;
18731873List * lefttl ,
1874- * dtlist ;
1874+ * dtlist ,
1875+ * targetvars ,
1876+ * targetnames ,
1877+ * sv_namespace ;
1878+ JoinExpr * jnode ;
18751879int tllen ;
18761880
18771881qry -> commandType = CMD_SELECT ;
@@ -1934,22 +1938,26 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
19341938Assert (leftmostQuery != NULL );
19351939/*
19361940 * Generate dummy targetlist for outer query using column names of
1937- * leftmost select and common datatypes of topmost set operation
1941+ * leftmost select and common datatypes of topmost set operation.
1942+ * Also make lists of the dummy vars and their names for use in
1943+ * parsing ORDER BY.
19381944 */
19391945qry -> targetList = NIL ;
1946+ targetvars = NIL ;
1947+ targetnames = NIL ;
19401948lefttl = leftmostQuery -> targetList ;
19411949foreach (dtlist ,sostmt -> colTypes )
19421950{
19431951Oid colType = (Oid )lfirsti (dtlist );
19441952Resdom * leftResdom = ((TargetEntry * )lfirst (lefttl ))-> resdom ;
1945- char * colName = leftResdom -> resname ;
1953+ char * colName = pstrdup ( leftResdom -> resname ) ;
19461954Resdom * resdom ;
19471955Node * expr ;
19481956
19491957resdom = makeResdom ((AttrNumber )pstate -> p_last_resno ++ ,
19501958colType ,
19511959-1 ,
1952- pstrdup ( colName ) ,
1960+ colName ,
19531961false);
19541962expr = (Node * )makeVar (leftmostRTI ,
19551963leftResdom -> resno ,
@@ -1958,6 +1966,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
195819660 );
19591967qry -> targetList = lappend (qry -> targetList ,
19601968makeTargetEntry (resdom ,expr ));
1969+ targetvars = lappend (targetvars ,expr );
1970+ targetnames = lappend (targetnames ,makeString (colName ));
19611971lefttl = lnext (lefttl );
19621972}
19631973/*
@@ -1997,6 +2007,23 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
19972007qry -> isBinary = FALSE;
19982008}
19992009
2010+ /*
2011+ * As a first step towards supporting sort clauses that are expressions
2012+ * using the output columns, generate a namespace entry that makes the
2013+ * output columns visible. A JoinExpr node is handy for this, since
2014+ * we can easily control the Vars generated upon matches.
2015+ *
2016+ * Note: we don't yet do anything useful with such cases, but at least
2017+ * "ORDER BY upper(foo)" will draw the right error message rather than
2018+ * "foo not found".
2019+ */
2020+ jnode = makeNode (JoinExpr );
2021+ jnode -> colnames = targetnames ;
2022+ jnode -> colvars = targetvars ;
2023+
2024+ sv_namespace = pstate -> p_namespace ;
2025+ pstate -> p_namespace = makeList1 (jnode );
2026+
20002027/*
20012028 * For now, we don't support resjunk sort clauses on the output of a
20022029 * setOperation tree --- you can only use the SQL92-spec options of
@@ -2009,6 +2036,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
20092036sortClause ,
20102037qry -> targetList );
20112038
2039+ pstate -> p_namespace = sv_namespace ;
2040+
20122041if (tllen != length (qry -> targetList ))
20132042elog (ERROR ,"ORDER BY on a UNION/INTERSECT/EXCEPT result must be on one of the result columns" );
20142043