Commit de434c2d authored by Tom Lane's avatar Tom Lane

Arrange for ORDER BY an expression on a UNION/INTERSECT/EXCEPT result,

such as
    SELECT f1 FROM foo UNION SELECT ... ORDER BY upper(f1)
to draw
'ORDER BY on a UNION/INTERSECT/EXCEPT result must be on one of the result columns'
rather than the uninformative 'f1 not found' we were producing before.
Eventually this should actually work, but that looks much too hard to try
to implement in late beta...
parent c7d2ce7b
......@@ -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");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment