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-16 14:38:13 -0800
commitbf6c614a2f2c58312b3be34a47e7fb7362e07bcb (patch)
treebbc91aed13afc3ef3b71bada700322197fe40b69 /src/backend/executor/nodeAgg.c
parentad9a274778d2d88c46b90309212b92ee7fdf9afe (diff)
downloadpostgresql-bf6c614a2f2c58312b3be34a47e7fb7362e07bcb.tar.gz
postgresql-bf6c614a2f2c58312b3be34a47e7fb7362e07bcb.zip
Do execGrouping.c via expression eval machinery, take two.
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. Large parts of this were previously committed (773aec7aa), but the commit contained an omission around cross-type comparisons and was thus reverted. 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.c145
1 files changed, 88 insertions, 57 deletions
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index a86d4b68eac..e74b3a93911 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,9 +1277,11 @@ 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->eqfuncoids,
perhash->hashfunctions,
perhash->aggnode->numGroups,
additionalsize,
@@ -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->eqfuncoids,
+ &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 **)