aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeAgg.c
diff options
context:
space:
mode:
authorAndres Freund <andres@anarazel.de>2018-02-15 21:55:31 -0800
committerAndres Freund <andres@anarazel.de>2018-02-15 21:55:31 -0800
commit773aec7aa98abd38d6d9435913bb8e14e392c274 (patch)
tree149ffe4c29433a85e84e128eb47aa22f3b388853 /src/backend/executor/nodeAgg.c
parent51db0d18fbf58b0c2e5ebc2b5b2c48daf45c8d93 (diff)
downloadpostgresql-773aec7aa98abd38d6d9435913bb8e14e392c274.tar.gz
postgresql-773aec7aa98abd38d6d9435913bb8e14e392c274.zip
Do execGrouping.c via expression eval machinery.
This has a performance benefit on own, although not hugely so. The primary benefit is that it will allow for to JIT tuple deforming and comparator invocations. Author: Andres Freund Discussion: https://postgr.es/m/20171129080934.amqqkke2zjtekd4t@alap3.anarazel.de
Diffstat (limited to 'src/backend/executor/nodeAgg.c')
-rw-r--r--src/backend/executor/nodeAgg.c143
1 files changed, 87 insertions, 56 deletions
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index a86d4b68eac..467f8d896ec 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -755,7 +755,7 @@ process_ordered_aggregate_single(AggState *aggstate,
((oldIsNull && *isNull) ||
(!oldIsNull && !*isNull &&
oldAbbrevVal == newAbbrevVal &&
- DatumGetBool(FunctionCall2(&pertrans->equalfns[0],
+ DatumGetBool(FunctionCall2(&pertrans->equalfnOne,
oldVal, *newVal)))))
{
/* equal to prior, so forget this one */
@@ -802,7 +802,7 @@ process_ordered_aggregate_multi(AggState *aggstate,
AggStatePerTrans pertrans,
AggStatePerGroup pergroupstate)
{
- MemoryContext workcontext = aggstate->tmpcontext->ecxt_per_tuple_memory;
+ ExprContext *tmpcontext = aggstate->tmpcontext;
FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
TupleTableSlot *slot1 = pertrans->sortslot;
TupleTableSlot *slot2 = pertrans->uniqslot;
@@ -811,6 +811,7 @@ process_ordered_aggregate_multi(AggState *aggstate,
Datum newAbbrevVal = (Datum) 0;
Datum oldAbbrevVal = (Datum) 0;
bool haveOldValue = false;
+ TupleTableSlot *save = aggstate->tmpcontext->ecxt_outertuple;
int i;
tuplesort_performsort(pertrans->sortstates[aggstate->current_set]);
@@ -824,22 +825,20 @@ process_ordered_aggregate_multi(AggState *aggstate,
{
CHECK_FOR_INTERRUPTS();
- /*
- * Extract the first numTransInputs columns as datums to pass to the
- * transfn. (This will help execTuplesMatch too, so we do it
- * immediately.)
- */
- slot_getsomeattrs(slot1, numTransInputs);
+ tmpcontext->ecxt_outertuple = slot1;
+ tmpcontext->ecxt_innertuple = slot2;
if (numDistinctCols == 0 ||
!haveOldValue ||
newAbbrevVal != oldAbbrevVal ||
- !execTuplesMatch(slot1, slot2,
- numDistinctCols,
- pertrans->sortColIdx,
- pertrans->equalfns,
- workcontext))
+ !ExecQual(pertrans->equalfnMulti, tmpcontext))
{
+ /*
+ * Extract the first numTransInputs columns as datums to pass to
+ * the transfn.
+ */
+ slot_getsomeattrs(slot1, numTransInputs);
+
/* Load values into fcinfo */
/* Start from 1, since the 0th arg will be the transition value */
for (i = 0; i < numTransInputs; i++)
@@ -857,15 +856,14 @@ process_ordered_aggregate_multi(AggState *aggstate,
slot2 = slot1;
slot1 = tmpslot;
- /* avoid execTuplesMatch() calls by reusing abbreviated keys */
+ /* avoid ExecQual() calls by reusing abbreviated keys */
oldAbbrevVal = newAbbrevVal;
haveOldValue = true;
}
}
- /* Reset context each time, unless execTuplesMatch did it for us */
- if (numDistinctCols == 0)
- MemoryContextReset(workcontext);
+ /* Reset context each time */
+ ResetExprContext(tmpcontext);
ExecClearTuple(slot1);
}
@@ -875,6 +873,9 @@ process_ordered_aggregate_multi(AggState *aggstate,
tuplesort_end(pertrans->sortstates[aggstate->current_set]);
pertrans->sortstates[aggstate->current_set] = NULL;
+
+ /* restore previous slot, potentially in use for grouping sets */
+ tmpcontext->ecxt_outertuple = save;
}
/*
@@ -1276,7 +1277,9 @@ build_hash_table(AggState *aggstate)
Assert(perhash->aggnode->numGroups > 0);
- perhash->hashtable = BuildTupleHashTable(perhash->numCols,
+ perhash->hashtable = BuildTupleHashTable(&aggstate->ss.ps,
+ perhash->hashslot->tts_tupleDescriptor,
+ perhash->numCols,
perhash->hashGrpColIdxHash,
perhash->eqfunctions,
perhash->hashfunctions,
@@ -1314,6 +1317,7 @@ find_hash_columns(AggState *aggstate)
Bitmapset *base_colnos;
List *outerTlist = outerPlanState(aggstate)->plan->targetlist;
int numHashes = aggstate->num_hashes;
+ EState *estate = aggstate->ss.ps.state;
int j;
/* Find Vars that will be needed in tlist and qual */
@@ -1393,6 +1397,12 @@ find_hash_columns(AggState *aggstate)
}
hashDesc = ExecTypeFromTL(hashTlist, false);
+
+ execTuplesHashPrepare(perhash->numCols,
+ perhash->aggnode->grpOperators,
+ &perhash->eqfunctions,
+ &perhash->hashfunctions);
+ perhash->hashslot = ExecAllocTableSlot(&estate->es_tupleTable);
ExecSetSlotDescriptor(perhash->hashslot, hashDesc);
list_free(hashTlist);
@@ -1694,17 +1704,14 @@ agg_retrieve_direct(AggState *aggstate)
* of the next grouping set
*----------
*/
+ tmpcontext->ecxt_innertuple = econtext->ecxt_outertuple;
if (aggstate->input_done ||
(node->aggstrategy != AGG_PLAIN &&
aggstate->projected_set != -1 &&
aggstate->projected_set < (numGroupingSets - 1) &&
nextSetSize > 0 &&
- !execTuplesMatch(econtext->ecxt_outertuple,
- tmpcontext->ecxt_outertuple,
- nextSetSize,
- node->grpColIdx,
- aggstate->phase->eqfunctions,
- tmpcontext->ecxt_per_tuple_memory)))
+ !ExecQualAndReset(aggstate->phase->eqfunctions[nextSetSize - 1],
+ tmpcontext)))
{
aggstate->projected_set += 1;
@@ -1847,12 +1854,9 @@ agg_retrieve_direct(AggState *aggstate)
*/
if (node->aggstrategy != AGG_PLAIN)
{
- if (!execTuplesMatch(firstSlot,
- outerslot,
- node->numCols,
- node->grpColIdx,
- aggstate->phase->eqfunctions,
- tmpcontext->ecxt_per_tuple_memory))
+ tmpcontext->ecxt_innertuple = firstSlot;
+ if (!ExecQual(aggstate->phase->eqfunctions[node->numCols - 1],
+ tmpcontext))
{
aggstate->grp_firstTuple = ExecCopySlotTuple(outerslot);
break;
@@ -2078,6 +2082,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
AggStatePerGroup *pergroups;
Plan *outerPlan;
ExprContext *econtext;
+ TupleDesc scanDesc;
int numaggs,
transno,
aggno;
@@ -2233,9 +2238,9 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
* initialize source tuple type.
*/
ExecAssignScanTypeFromOuterPlan(&aggstate->ss);
+ scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
if (node->chain)
- ExecSetSlotDescriptor(aggstate->sort_slot,
- aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor);
+ ExecSetSlotDescriptor(aggstate->sort_slot, scanDesc);
/*
* Initialize result tuple type and projection info.
@@ -2355,11 +2360,43 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
*/
if (aggnode->aggstrategy == AGG_SORTED)
{
+ int i = 0;
+
Assert(aggnode->numCols > 0);
+ /*
+ * Build a separate function for each subset of columns that
+ * need to be compared.
+ */
phasedata->eqfunctions =
- execTuplesMatchPrepare(aggnode->numCols,
- aggnode->grpOperators);
+ (ExprState **) palloc0(aggnode->numCols * sizeof(ExprState *));
+
+ /* for each grouping set */
+ for (i = 0; i < phasedata->numsets; i++)
+ {
+ int length = phasedata->gset_lengths[i];
+
+ if (phasedata->eqfunctions[length - 1] != NULL)
+ continue;
+
+ phasedata->eqfunctions[length - 1] =
+ execTuplesMatchPrepare(scanDesc,
+ length,
+ aggnode->grpColIdx,
+ aggnode->grpOperators,
+ (PlanState *) aggstate);
+ }
+
+ /* and for all grouped columns, unless already computed */
+ if (phasedata->eqfunctions[aggnode->numCols - 1] == NULL)
+ {
+ phasedata->eqfunctions[aggnode->numCols - 1] =
+ execTuplesMatchPrepare(scanDesc,
+ aggnode->numCols,
+ aggnode->grpColIdx,
+ aggnode->grpOperators,
+ (PlanState *) aggstate);
+ }
}
phasedata->aggnode = aggnode;
@@ -2412,16 +2449,6 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
*/
if (use_hashing)
{
- for (i = 0; i < numHashes; ++i)
- {
- aggstate->perhash[i].hashslot = ExecInitExtraTupleSlot(estate);
-
- execTuplesHashPrepare(aggstate->perhash[i].numCols,
- aggstate->perhash[i].aggnode->grpOperators,
- &aggstate->perhash[i].eqfunctions,
- &aggstate->perhash[i].hashfunctions);
- }
-
/* this is an array of pointers, not structures */
aggstate->hash_pergroup = pergroups;
@@ -3101,24 +3128,28 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
if (aggref->aggdistinct)
{
+ Oid *ops;
+
Assert(numArguments > 0);
+ Assert(list_length(aggref->aggdistinct) == numDistinctCols);
- /*
- * We need the equal function for each DISTINCT comparison we will
- * make.
- */
- pertrans->equalfns =
- (FmgrInfo *) palloc(numDistinctCols * sizeof(FmgrInfo));
+ ops = palloc(numDistinctCols * sizeof(Oid));
i = 0;
foreach(lc, aggref->aggdistinct)
- {
- SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
+ ops[i++] = ((SortGroupClause *) lfirst(lc))->eqop;
- fmgr_info(get_opcode(sortcl->eqop), &pertrans->equalfns[i]);
- i++;
- }
- Assert(i == numDistinctCols);
+ /* lookup / build the necessary comparators */
+ if (numDistinctCols == 1)
+ fmgr_info(get_opcode(ops[0]), &pertrans->equalfnOne);
+ else
+ pertrans->equalfnMulti =
+ execTuplesMatchPrepare(pertrans->sortdesc,
+ numDistinctCols,
+ pertrans->sortColIdx,
+ ops,
+ &aggstate->ss.ps);
+ pfree(ops);
}
pertrans->sortstates = (Tuplesortstate **)