From: Tom Lane Date: Thu, 15 Feb 2001 01:10:28 +0000 (+0000) Subject: Arrange for ORDER BY an expression on a UNION/INTERSECT/EXCEPT result, X-Git-Tag: REL7_1~407 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=de434c2d5f2d666861408ca2c04e96939a19b368;p=postgresql 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... --- diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index cf43da0d70..ba0a3cfa34 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");