aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeAgg.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2017-10-16 15:51:23 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2017-10-16 15:51:23 -0400
commitbe0ebb65f51225223421df6e10eb6e87fc8264d7 (patch)
tree47f81081e66bb4f8ad984b8f56f9b62d3bacfd51 /src/backend/executor/nodeAgg.c
parentc3dfe0fec01469b8a7de327303cad50ba8ed338a (diff)
downloadpostgresql-be0ebb65f51225223421df6e10eb6e87fc8264d7.tar.gz
postgresql-be0ebb65f51225223421df6e10eb6e87fc8264d7.zip
Allow the built-in ordered-set aggregates to share transition state.
The built-in OSAs all share the same transition function, so they can share transition state as long as the final functions cooperate to not do the sort step more than once. To avoid running the tuplesort object in randomAccess mode unnecessarily, add a bit of infrastructure to nodeAgg.c to let the aggregate functions find out whether the transition state is actually being shared or not. This doesn't work for the hypothetical aggregates, since those inject a hypothetical row that isn't traceable to the shared input state. So they remain marked aggfinalmodify = 'w'. Discussion: https://postgr.es/m/CAB4ELO5RZhOamuT9Xsf72ozbenDLLXZKSk07FiSVsuJNZB861A@mail.gmail.com
Diffstat (limited to 'src/backend/executor/nodeAgg.c')
-rw-r--r--src/backend/executor/nodeAgg.c52
1 files changed, 49 insertions, 3 deletions
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 8a6dfd64e8b..82ed5b3e1cb 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -255,6 +255,11 @@ typedef struct AggStatePerTransData
Aggref *aggref;
/*
+ * Is this state value actually being shared by more than one Aggref?
+ */
+ bool aggshared;
+
+ /*
* Nominal number of arguments for aggregate function. For plain aggs,
* this excludes any ORDER BY expressions. For ordered-set aggs, this
* counts both the direct and aggregated (ORDER BY) arguments.
@@ -3360,9 +3365,10 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
{
/*
* Existing compatible trans found, so just point the 'peragg' to
- * the same per-trans struct.
+ * the same per-trans struct, and mark the trans state as shared.
*/
pertrans = &pertransstates[existing_transno];
+ pertrans->aggshared = true;
peragg->transno = existing_transno;
}
else
@@ -3512,6 +3518,7 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
/* Begin filling in the pertrans data */
pertrans->aggref = aggref;
+ pertrans->aggshared = false;
pertrans->aggCollation = aggref->inputcollid;
pertrans->transfn_oid = aggtransfn;
pertrans->serialfn_oid = aggserialfn;
@@ -4161,17 +4168,18 @@ AggGetAggref(FunctionCallInfo fcinfo)
{
if (fcinfo->context && IsA(fcinfo->context, AggState))
{
+ AggState *aggstate = (AggState *) fcinfo->context;
AggStatePerAgg curperagg;
AggStatePerTrans curpertrans;
/* check curperagg (valid when in a final function) */
- curperagg = ((AggState *) fcinfo->context)->curperagg;
+ curperagg = aggstate->curperagg;
if (curperagg)
return curperagg->aggref;
/* check curpertrans (valid when in a transition function) */
- curpertrans = ((AggState *) fcinfo->context)->curpertrans;
+ curpertrans = aggstate->curpertrans;
if (curpertrans)
return curpertrans->aggref;
@@ -4202,6 +4210,44 @@ AggGetTempMemoryContext(FunctionCallInfo fcinfo)
}
/*
+ * AggStateIsShared - find out whether transition state is shared
+ *
+ * If the function is being called as an aggregate support function,
+ * return TRUE if the aggregate's transition state is shared across
+ * multiple aggregates, FALSE if it is not.
+ *
+ * Returns TRUE if not called as an aggregate support function.
+ * This is intended as a conservative answer, ie "no you'd better not
+ * scribble on your input". In particular, will return TRUE if the
+ * aggregate is being used as a window function, which is a scenario
+ * in which changing the transition state is a bad idea. We might
+ * want to refine the behavior for the window case in future.
+ */
+bool
+AggStateIsShared(FunctionCallInfo fcinfo)
+{
+ if (fcinfo->context && IsA(fcinfo->context, AggState))
+ {
+ AggState *aggstate = (AggState *) fcinfo->context;
+ AggStatePerAgg curperagg;
+ AggStatePerTrans curpertrans;
+
+ /* check curperagg (valid when in a final function) */
+ curperagg = aggstate->curperagg;
+
+ if (curperagg)
+ return aggstate->pertrans[curperagg->transno].aggshared;
+
+ /* check curpertrans (valid when in a transition function) */
+ curpertrans = aggstate->curpertrans;
+
+ if (curpertrans)
+ return curpertrans->aggshared;
+ }
+ return true;
+}
+
+/*
* AggRegisterCallback - register a cleanup callback for an aggregate
*
* This is useful for aggs to register shutdown callbacks, which will ensure