Commit 996fdb9a authored by Tom Lane's avatar Tom Lane

Cause GROUP BY clause to adopt ordering operators from ORDER BY when

both clauses specify the same targets, rather than always using the
default ordering operator.  This allows 'GROUP BY foo ORDER BY foo DESC'
to be done with only one sort step.
parent da78e3e2
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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) ...@@ -1787,14 +1787,19 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
*/ */
qry->havingQual = transformWhereClause(pstate, stmt->havingClause); qry->havingQual = transformWhereClause(pstate, stmt->havingClause);
qry->groupClause = transformGroupClause(pstate, /*
stmt->groupClause, * Transform sorting/grouping stuff. Do ORDER BY first because both
qry->targetList); * transformGroupClause and transformDistinctClause need the results.
*/
qry->sortClause = transformSortClause(pstate, qry->sortClause = transformSortClause(pstate,
stmt->sortClause, stmt->sortClause,
qry->targetList); qry->targetList);
qry->groupClause = transformGroupClause(pstate,
stmt->groupClause,
qry->targetList,
qry->sortClause);
qry->distinctClause = transformDistinctClause(pstate, qry->distinctClause = transformDistinctClause(pstate,
stmt->distinctClause, stmt->distinctClause,
qry->targetList, qry->targetList,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -1124,7 +1124,8 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
* transform a GROUP BY clause * transform a GROUP BY clause
*/ */
List * List *
transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist) transformGroupClause(ParseState *pstate, List *grouplist,
List *targetlist, List *sortClause)
{ {
List *glist = NIL, List *glist = NIL,
*gl; *gl;
...@@ -1132,21 +1133,41 @@ transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist) ...@@ -1132,21 +1133,41 @@ transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
foreach(gl, grouplist) foreach(gl, grouplist)
{ {
TargetEntry *tle; TargetEntry *tle;
Oid ordering_op;
GroupClause *grpcl;
tle = findTargetlistEntry(pstate, lfirst(gl), tle = findTargetlistEntry(pstate, lfirst(gl),
targetlist, GROUP_CLAUSE); targetlist, GROUP_CLAUSE);
/* avoid making duplicate grouplist entries */ /* avoid making duplicate grouplist entries */
if (!targetIsInSortList(tle, glist)) if (targetIsInSortList(tle, glist))
{ continue;
GroupClause *grpcl = makeNode(GroupClause);
grpcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
grpcl->sortop = ordering_oper_opid(tle->resdom->restype);
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; return glist;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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, ...@@ -22,7 +22,7 @@ extern int setTargetTable(ParseState *pstate, RangeVar *relation,
extern bool interpretInhOption(InhOption inhOpt); extern bool interpretInhOption(InhOption inhOpt);
extern Node *transformWhereClause(ParseState *pstate, Node *where); extern Node *transformWhereClause(ParseState *pstate, Node *where);
extern List *transformGroupClause(ParseState *pstate, List *grouplist, extern List *transformGroupClause(ParseState *pstate, List *grouplist,
List *targetlist); List *targetlist, List *sortClause);
extern List *transformSortClause(ParseState *pstate, List *orderlist, extern List *transformSortClause(ParseState *pstate, List *orderlist,
List *targetlist); List *targetlist);
extern List *transformDistinctClause(ParseState *pstate, List *distinctlist, extern List *transformDistinctClause(ParseState *pstate, List *distinctlist,
......
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