* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.273 2003/06/06 15:04:02 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.274 2003/06/15 16:42:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
qry->havingQual = transformWhereClause(pstate, stmt->havingClause);
- qry->groupClause = transformGroupClause(pstate,
- stmt->groupClause,
- qry->targetList);
-
+ /*
+ * Transform sorting/grouping stuff. Do ORDER BY first because both
+ * transformGroupClause and transformDistinctClause need the results.
+ */
qry->sortClause = transformSortClause(pstate,
stmt->sortClause,
qry->targetList);
+ qry->groupClause = transformGroupClause(pstate,
+ stmt->groupClause,
+ qry->targetList,
+ qry->sortClause);
+
qry->distinctClause = transformDistinctClause(pstate,
stmt->distinctClause,
qry->targetList,
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.114 2003/06/06 15:04:02 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.115 2003/06/15 16:42:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* transform a GROUP BY clause
*/
List *
-transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
+transformGroupClause(ParseState *pstate, List *grouplist,
+ List *targetlist, List *sortClause)
{
List *glist = NIL,
*gl;
foreach(gl, grouplist)
{
TargetEntry *tle;
+ Oid ordering_op;
+ GroupClause *grpcl;
tle = findTargetlistEntry(pstate, lfirst(gl),
targetlist, GROUP_CLAUSE);
/* avoid making duplicate grouplist entries */
- if (!targetIsInSortList(tle, glist))
- {
- GroupClause *grpcl = makeNode(GroupClause);
-
- grpcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
-
- grpcl->sortop = ordering_oper_opid(tle->resdom->restype);
+ if (targetIsInSortList(tle, glist))
+ continue;
- glist = lappend(glist, grpcl);
+ /*
+ * If the GROUP BY clause matches the ORDER BY clause, we want to
+ * adopt the ordering operators from the latter rather than using
+ * the default ops. This allows "GROUP BY foo ORDER BY foo DESC" to
+ * be done with only one sort step. Note we are assuming that any
+ * user-supplied ordering operator will bring equal values together,
+ * which is all that GROUP BY needs.
+ */
+ if (sortClause &&
+ ((SortClause *) lfirst(sortClause))->tleSortGroupRef ==
+ tle->resdom->ressortgroupref)
+ {
+ ordering_op = ((SortClause *) lfirst(sortClause))->sortop;
+ sortClause = lnext(sortClause);
}
+ else
+ {
+ ordering_op = ordering_oper_opid(tle->resdom->restype);
+ sortClause = NIL; /* disregard ORDER BY once match fails */
+ }
+
+ grpcl = makeNode(GroupClause);
+ grpcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
+ grpcl->sortop = ordering_op;
+ glist = lappend(glist, grpcl);
}
return glist;
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_clause.h,v 1.30 2003/03/22 01:49:38 tgl Exp $
+ * $Id: parse_clause.h,v 1.31 2003/06/15 16:42:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern bool interpretInhOption(InhOption inhOpt);
extern Node *transformWhereClause(ParseState *pstate, Node *where);
extern List *transformGroupClause(ParseState *pstate, List *grouplist,
- List *targetlist);
+ List *targetlist, List *sortClause);
extern List *transformSortClause(ParseState *pstate, List *orderlist,
List *targetlist);
extern List *transformDistinctClause(ParseState *pstate, List *distinctlist,