diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 9ac8132f08..95b209e4ac 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -1787,14 +1787,19 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt) */ 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, diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index a29eb007fb..2e2beabddc 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -1124,7 +1124,8 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause) * 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; @@ -1132,21 +1133,41 @@ transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist) 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)) + if (targetIsInSortList(tle, glist)) + continue; + + /* + * 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) { - GroupClause *grpcl = makeNode(GroupClause); - - grpcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist); - - grpcl->sortop = ordering_oper_opid(tle->resdom->restype); - - glist = lappend(glist, grpcl); + 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; diff --git a/src/include/parser/parse_clause.h b/src/include/parser/parse_clause.h index da7e7abec4..12ab7317d9 100644 --- a/src/include/parser/parse_clause.h +++ b/src/include/parser/parse_clause.h @@ -7,7 +7,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -22,7 +22,7 @@ extern int setTargetTable(ParseState *pstate, RangeVar *relation, 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,