Skip to content

Commit db436ad

Browse files
committed
Major revision of sort-node handling: push knowledge of query
sort order down into planner, instead of handling it only at the very top level of the planner. This fixes many things. An explicit sort is now avoided if there is a cheaper alternative (typically an indexscan) not only for ORDER BY, but also for the internal sort of GROUP BY. It works even when there is no other reason (such as a WHERE condition) to consider the indexscan. It works for indexes on functions. It works for indexes on functions, backwards. It's just so cool... CAUTION: I have changed the representation of SortClause nodes, therefore THIS UPDATE BREAKS STORED RULES. You will need to initdb.
1 parent 5588c55 commit db436ad

33 files changed

+961
-996
lines changed

src/backend/executor/nodeAgg.c

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "executor/executor.h"
2424
#include "executor/nodeAgg.h"
2525
#include "optimizer/clauses.h"
26+
#include "optimizer/planmain.h"
2627
#include "parser/parse_type.h"
2728
#include "utils/syscache.h"
2829

@@ -91,7 +92,7 @@ ExecAgg(Agg *node)
9192
EState *estate;
9293
Plan *outerPlan;
9394
int aggno,
94-
nagg;
95+
numaggs;
9596
Datum *value1,
9697
*value2;
9798
int *noInitValue;
@@ -128,27 +129,27 @@ ExecAgg(Agg *node)
128129
estate = node->plan.state;
129130
econtext = aggstate->csstate.cstate.cs_ExprContext;
130131

131-
nagg = length(node->aggs);
132+
numaggs = length(aggstate->aggs);
132133

133134
value1 = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_values;
134135
nulls = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_nulls;
135136

136-
value2 = (Datum *) palloc(sizeof(Datum) * nagg);
137-
MemSet(value2, 0, sizeof(Datum) * nagg);
137+
value2 = (Datum *) palloc(sizeof(Datum) * numaggs);
138+
MemSet(value2, 0, sizeof(Datum) * numaggs);
138139

139-
aggFuncInfo = (AggFuncInfo *) palloc(sizeof(AggFuncInfo) * nagg);
140-
MemSet(aggFuncInfo, 0, sizeof(AggFuncInfo) * nagg);
140+
aggFuncInfo = (AggFuncInfo *) palloc(sizeof(AggFuncInfo) * numaggs);
141+
MemSet(aggFuncInfo, 0, sizeof(AggFuncInfo) * numaggs);
141142

142-
noInitValue = (int *) palloc(sizeof(int) * nagg);
143-
MemSet(noInitValue, 0, sizeof(int) * nagg);
143+
noInitValue = (int *) palloc(sizeof(int) * numaggs);
144+
MemSet(noInitValue, 0, sizeof(int) * numaggs);
144145

145146
outerPlan = outerPlan(node);
146147
oneTuple = NULL;
147148

148149
projInfo = aggstate->csstate.cstate.cs_ProjInfo;
149150

150151
aggno = -1;
151-
foreach(alist, node->aggs)
152+
foreach(alist, aggstate->aggs)
152153
{
153154
Aggref *aggref = lfirst(alist);
154155
char *aggname;
@@ -269,7 +270,7 @@ ExecAgg(Agg *node)
269270
}
270271

271272
aggno = -1;
272-
foreach(alist, node->aggs)
273+
foreach(alist, aggstate->aggs)
273274
{
274275
Aggref *aggref = lfirst(alist);
275276
AggFuncInfo *aggfns = &aggFuncInfo[++aggno];
@@ -367,7 +368,7 @@ ExecAgg(Agg *node)
367368
*/
368369

369370
aggno = -1;
370-
foreach(alist, node->aggs)
371+
foreach(alist, aggstate->aggs)
371372
{
372373
char *args[2];
373374
AggFuncInfo *aggfns = &aggFuncInfo[++aggno];
@@ -467,6 +468,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
467468
AggState *aggstate;
468469
Plan *outerPlan;
469470
ExprContext *econtext;
471+
int numaggs;
470472

471473
/*
472474
* assign the node's execution state
@@ -478,7 +480,16 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
478480
*/
479481
aggstate = makeNode(AggState);
480482
node->aggstate = aggstate;
481-
aggstate->agg_done = FALSE;
483+
aggstate->agg_done = false;
484+
485+
/*
486+
* find aggregates in targetlist and quals
487+
*/
488+
aggstate->aggs = nconc(pull_agg_clause((Node *) node->plan.targetlist),
489+
pull_agg_clause((Node *) node->plan.qual));
490+
numaggs = length(aggstate->aggs);
491+
if (numaggs <= 0)
492+
elog(ERROR, "ExecInitAgg: could not find any aggregate functions");
482493

483494
/*
484495
* assign node's base id and create expression context
@@ -495,10 +506,10 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
495506
ExecInitResultTupleSlot(estate, &aggstate->csstate.cstate);
496507

497508
econtext = aggstate->csstate.cstate.cs_ExprContext;
498-
econtext->ecxt_values = (Datum *) palloc(sizeof(Datum) * length(node->aggs));
499-
MemSet(econtext->ecxt_values, 0, sizeof(Datum) * length(node->aggs));
500-
econtext->ecxt_nulls = (char *) palloc(sizeof(char) * length(node->aggs));
501-
MemSet(econtext->ecxt_nulls, 0, sizeof(char) * length(node->aggs));
509+
econtext->ecxt_values = (Datum *) palloc(sizeof(Datum) * numaggs);
510+
MemSet(econtext->ecxt_values, 0, sizeof(Datum) * numaggs);
511+
econtext->ecxt_nulls = (char *) palloc(sizeof(char) * numaggs);
512+
MemSet(econtext->ecxt_nulls, 0, sizeof(char) * numaggs);
502513

503514
/*
504515
* initializes child nodes
@@ -510,7 +521,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
510521
* Result runs in its own context, but make it use our aggregates fix
511522
* for 'select sum(2+2)'
512523
*/
513-
if (nodeTag(outerPlan) == T_Result)
524+
if (IsA(outerPlan, Result))
514525
{
515526
((Result *) outerPlan)->resstate->cstate.cs_ProjInfo->pi_exprContext->ecxt_values =
516527
econtext->ecxt_values;
@@ -645,9 +656,9 @@ ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent)
645656
AggState *aggstate = node->aggstate;
646657
ExprContext *econtext = aggstate->csstate.cstate.cs_ExprContext;
647658

648-
aggstate->agg_done = FALSE;
649-
MemSet(econtext->ecxt_values, 0, sizeof(Datum) * length(node->aggs));
650-
MemSet(econtext->ecxt_nulls, 0, sizeof(char) * length(node->aggs));
659+
aggstate->agg_done = false;
660+
MemSet(econtext->ecxt_values, 0, sizeof(Datum) * length(aggstate->aggs));
661+
MemSet(econtext->ecxt_nulls, 0, sizeof(char) * length(aggstate->aggs));
651662

652663
/*
653664
* if chgParam of subnode is not null then plan will be re-scanned by

src/backend/nodes/copyfuncs.c

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.91 1999/08/16 02:17:41 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.92 1999/08/21 03:48:57 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -456,12 +456,6 @@ _copyAgg(Agg *from)
456456

457457
CopyPlanFields((Plan *) from, (Plan *) newnode);
458458

459-
/*
460-
* Cannot copy agg list; it must be rebuilt to point to subnodes of
461-
* new node.
462-
*/
463-
set_agg_tlist_references(newnode);
464-
465459
return newnode;
466460
}
467461

@@ -474,8 +468,8 @@ _copyGroupClause(GroupClause *from)
474468
{
475469
GroupClause *newnode = makeNode(GroupClause);
476470

477-
newnode->grpOpoid = from->grpOpoid;
478-
newnode->tleGroupref = from->tleGroupref;
471+
newnode->tleSortGroupRef = from->tleSortGroupRef;
472+
newnode->sortop = from->sortop;
479473

480474
return newnode;
481475
}
@@ -567,12 +561,11 @@ _copyResdom(Resdom *from)
567561
newnode->resno = from->resno;
568562
newnode->restype = from->restype;
569563
newnode->restypmod = from->restypmod;
570-
571564
if (from->resname != NULL)
572565
newnode->resname = pstrdup(from->resname);
566+
newnode->ressortgroupref = from->ressortgroupref;
573567
newnode->reskey = from->reskey;
574568
newnode->reskeyop = from->reskeyop;
575-
newnode->resgroupref = from->resgroupref;
576569
newnode->resjunk = from->resjunk;
577570

578571
return newnode;
@@ -862,8 +855,8 @@ _copyAggref(Aggref *from)
862855
newnode->basetype = from->basetype;
863856
newnode->aggtype = from->aggtype;
864857
Node_Copy(from, newnode, target);
865-
newnode->aggno = from->aggno;
866858
newnode->usenulls = from->usenulls;
859+
newnode->aggno = from->aggno; /* probably not needed */
867860

868861
return newnode;
869862
}
@@ -1345,8 +1338,8 @@ _copySortClause(SortClause *from)
13451338
{
13461339
SortClause *newnode = makeNode(SortClause);
13471340

1348-
Node_Copy(from, newnode, resdom);
1349-
newnode->opoid = from->opoid;
1341+
newnode->tleSortGroupRef = from->tleSortGroupRef;
1342+
newnode->sortop = from->sortop;
13501343

13511344
return newnode;
13521345
}
@@ -1398,33 +1391,29 @@ _copyQuery(Query *from)
13981391
newnode->isBinary = from->isBinary;
13991392
newnode->isTemp = from->isTemp;
14001393
newnode->unionall = from->unionall;
1401-
if (from->uniqueFlag)
1402-
newnode->uniqueFlag = pstrdup(from->uniqueFlag);
1403-
Node_Copy(from, newnode, sortClause);
1394+
newnode->hasAggs = from->hasAggs;
1395+
newnode->hasSubLinks = from->hasSubLinks;
1396+
14041397
Node_Copy(from, newnode, rtable);
14051398
Node_Copy(from, newnode, targetList);
14061399
Node_Copy(from, newnode, qual);
1400+
Node_Copy(from, newnode, rowMark);
14071401

1402+
if (from->uniqueFlag)
1403+
newnode->uniqueFlag = pstrdup(from->uniqueFlag);
1404+
Node_Copy(from, newnode, sortClause);
14081405
Node_Copy(from, newnode, groupClause);
14091406
Node_Copy(from, newnode, havingQual);
14101407

1411-
newnode->hasAggs = from->hasAggs;
1412-
newnode->hasSubLinks = from->hasSubLinks;
1413-
1414-
if (from->unionClause)
1415-
{
1416-
List *ulist,
1417-
*temp_list = NIL;
1418-
1419-
foreach(ulist, from->unionClause)
1420-
temp_list = lappend(temp_list, copyObject(lfirst(ulist)));
1421-
newnode->unionClause = temp_list;
1422-
}
1408+
/* why is intersectClause missing? */
1409+
Node_Copy(from, newnode, unionClause);
14231410

14241411
Node_Copy(from, newnode, limitOffset);
14251412
Node_Copy(from, newnode, limitCount);
14261413

1427-
Node_Copy(from, newnode, rowMark);
1414+
/* we do not copy the planner internal fields: base_rel_list,
1415+
* join_rel_list, query_pathkeys. Not entirely clear if this is right?
1416+
*/
14281417

14291418
return newnode;
14301419
}

src/backend/nodes/equalfuncs.c

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.47 1999/08/16 02:17:41 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.48 1999/08/21 03:48:57 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -34,14 +34,23 @@ _equalResdom(Resdom *a, Resdom *b)
3434
return false;
3535
if (a->restypmod != b->restypmod)
3636
return false;
37-
if (strcmp(a->resname, b->resname) != 0)
37+
if (a->resname && b->resname)
38+
{
39+
if (strcmp(a->resname, b->resname) != 0)
40+
return false;
41+
}
42+
else
43+
{
44+
/* must both be null to be equal */
45+
if (a->resname != b->resname)
46+
return false;
47+
}
48+
if (a->ressortgroupref != b->ressortgroupref)
3849
return false;
3950
if (a->reskey != b->reskey)
4051
return false;
4152
if (a->reskeyop != b->reskeyop)
4253
return false;
43-
if (a->resgroupref != b->resgroupref)
44-
return false;
4554
/* we ignore resjunk flag ... is this correct? */
4655

4756
return true;
@@ -208,10 +217,9 @@ _equalAggref(Aggref *a, Aggref *b)
208217
return false;
209218
if (!equal(a->target, b->target))
210219
return false;
211-
if (a->aggno != b->aggno)
212-
return false;
213220
if (a->usenulls != b->usenulls)
214221
return false;
222+
/* ignore aggno, which is only a private field for the executor */
215223
return true;
216224
}
217225

@@ -503,6 +511,14 @@ _equalQuery(Query *a, Query *b)
503511
return false;
504512
if (a->hasSubLinks != b->hasSubLinks)
505513
return false;
514+
if (!equal(a->rtable, b->rtable))
515+
return false;
516+
if (!equal(a->targetList, b->targetList))
517+
return false;
518+
if (!equal(a->qual, b->qual))
519+
return false;
520+
if (!equal(a->rowMark, b->rowMark))
521+
return false;
506522
if (a->uniqueFlag && b->uniqueFlag)
507523
{
508524
if (strcmp(a->uniqueFlag, b->uniqueFlag) != 0)
@@ -515,14 +531,6 @@ _equalQuery(Query *a, Query *b)
515531
}
516532
if (!equal(a->sortClause, b->sortClause))
517533
return false;
518-
if (!equal(a->rtable, b->rtable))
519-
return false;
520-
if (!equal(a->targetList, b->targetList))
521-
return false;
522-
if (!equal(a->qual, b->qual))
523-
return false;
524-
if (!equal(a->rowMark, b->rowMark))
525-
return false;
526534
if (!equal(a->groupClause, b->groupClause))
527535
return false;
528536
if (!equal(a->havingQual, b->havingQual))
@@ -537,9 +545,9 @@ _equalQuery(Query *a, Query *b)
537545
return false;
538546

539547
/*
540-
* We do not check the internal-to-the-planner fields base_rel_list
541-
* and join_rel_list. They might not be set yet, and in any case they
542-
* should be derivable from the other fields.
548+
* We do not check the internal-to-the-planner fields: base_rel_list,
549+
* join_rel_list, query_pathkeys. They might not be set yet, and
550+
* in any case they should be derivable from the other fields.
543551
*/
544552
return true;
545553
}

src/backend/nodes/freefuncs.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.25 1999/08/16 02:17:42 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.26 1999/08/21 03:48:57 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -371,8 +371,6 @@ _freeAgg(Agg *node)
371371
{
372372
FreePlanFields((Plan *) node);
373373

374-
freeList(node->aggs);
375-
376374
pfree(node);
377375
}
378376

@@ -964,8 +962,6 @@ _freeRowMark(RowMark *node)
964962
static void
965963
_freeSortClause(SortClause *node)
966964
{
967-
freeObject(node->resdom);
968-
969965
pfree(node);
970966
}
971967

@@ -1000,19 +996,22 @@ _freeQuery(Query *node)
1000996
}
1001997
if (node->into)
1002998
pfree(node->into);
999+
freeObject(node->rtable);
1000+
freeObject(node->targetList);
1001+
freeObject(node->qual);
1002+
freeObject(node->rowMark);
10031003
if (node->uniqueFlag)
10041004
pfree(node->uniqueFlag);
10051005

10061006
freeObject(node->sortClause);
1007-
freeObject(node->rtable);
1008-
freeObject(node->targetList);
1009-
freeObject(node->qual);
10101007
freeObject(node->groupClause);
10111008
freeObject(node->havingQual);
1009+
/* why not intersectClause? */
10121010
freeObject(node->unionClause);
10131011
freeObject(node->limitOffset);
10141012
freeObject(node->limitCount);
1015-
freeObject(node->rowMark);
1013+
1014+
/* XXX should we be freeing the planner internal fields? */
10161015

10171016
pfree(node);
10181017
}

0 commit comments

Comments
 (0)