]> granicus.if.org Git - postgresql/commitdiff
Rethink node-level representation of partial-aggregation modes.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 26 Jun 2016 18:33:38 +0000 (14:33 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 26 Jun 2016 18:33:38 +0000 (14:33 -0400)
The original coding had three separate booleans representing partial
aggregation behavior, which was confusing, unreadable, and error-prone,
not least because the booleans weren't always listed in the same order.
It was also inadequate for the allegedly-desirable future extension to
support intermediate partial aggregation, because we'd need separate
markers for serialization and deserialization in such a case.

Merge these bools into an enum "AggSplit" to provide symbolic names for
the supported operating modes (and document what those are).  By assigning
the values of the enum constants carefully, we can treat AggSplit values
as options bitmasks so that tests of what to do aren't noticeably more
expensive than before.

While at it, get rid of Aggref.aggoutputtype.  That's not needed since
commit 59a3795c2 got rid of setrefs.c's special-purpose Aggref comparison
code, and it likewise seemed more confusing than helpful.

Assorted comment cleanup as well (there's still more that I want to do
in that line).

catversion bump for change in Aggref node contents.  Should be the last
one for partial-aggregation changes.

Discussion: <29309.1466699160@sss.pgh.pa.us>

26 files changed:
src/backend/commands/explain.c
src/backend/executor/execQual.c
src/backend/executor/nodeAgg.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/nodeFuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/plan/setrefs.c
src/backend/optimizer/prep/prepunion.c
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/pathnode.c
src/backend/parser/parse_func.c
src/backend/utils/adt/ruleutils.c
src/include/catalog/catversion.h
src/include/nodes/execnodes.h
src/include/nodes/nodes.h
src/include/nodes/plannodes.h
src/include/nodes/primnodes.h
src/include/nodes/relation.h
src/include/optimizer/clauses.h
src/include/optimizer/pathnode.h
src/include/optimizer/planmain.h
src/include/optimizer/planner.h

index 379fc5c429e1607ba2b777f2a80240634aca99c9..319dd8e22481602bf22296ae93af221c0299ab1c 100644 (file)
@@ -947,9 +947,9 @@ ExplainNode(PlanState *planstate, List *ancestors,
                        {
                                Agg                *agg = (Agg *) plan;
 
-                               if (agg->finalizeAggs == false)
+                               if (DO_AGGSPLIT_SKIPFINAL(agg->aggsplit))
                                        operation = "Partial";
-                               else if (agg->combineStates == true)
+                               else if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
                                        operation = "Finalize";
 
                                switch (agg->aggstrategy)
index 01e04d3b14eb76218fbba4b833ee6dabc1f5cf18..d04d1a89a7ffacc7dc4eef97d2e27d425f454d75 100644 (file)
@@ -4510,35 +4510,20 @@ ExecInitExpr(Expr *node, PlanState *parent)
                case T_Aggref:
                        {
                                AggrefExprState *astate = makeNode(AggrefExprState);
-                               AggState   *aggstate = (AggState *) parent;
-                               Aggref     *aggref = (Aggref *) node;
 
                                astate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalAggref;
-                               if (!aggstate || !IsA(aggstate, AggState))
+                               if (parent && IsA(parent, AggState))
                                {
-                                       /* planner messed up */
-                                       elog(ERROR, "Aggref found in non-Agg plan node");
-                               }
-                               if (aggref->aggpartial == aggstate->finalizeAggs)
-                               {
-                                       /* planner messed up */
-                                       if (aggref->aggpartial)
-                                               elog(ERROR, "partial Aggref found in finalize agg plan node");
-                                       else
-                                               elog(ERROR, "non-partial Aggref found in non-finalize agg plan node");
-                               }
+                                       AggState   *aggstate = (AggState *) parent;
 
-                               if (aggref->aggcombine != aggstate->combineStates)
+                                       aggstate->aggs = lcons(astate, aggstate->aggs);
+                                       aggstate->numaggs++;
+                               }
+                               else
                                {
                                        /* planner messed up */
-                                       if (aggref->aggcombine)
-                                               elog(ERROR, "combine Aggref found in non-combine agg plan node");
-                                       else
-                                               elog(ERROR, "non-combine Aggref found in combine agg plan node");
+                                       elog(ERROR, "Aggref found in non-Agg plan node");
                                }
-
-                               aggstate->aggs = lcons(astate, aggstate->aggs);
-                               aggstate->numaggs++;
                                state = (ExprState *) astate;
                        }
                        break;
index a44796461299856b99817a62ef8fff4206ee1c78..b3187e666817a0d9ee357c6f3c45ba875ab1091c 100644 (file)
  *                     transvalue = transfunc(transvalue, input_value(s))
  *              result = finalfunc(transvalue, direct_argument(s))
  *
- *       If a finalfunc is not supplied or finalizeAggs is false, then the result
- *       is just the ending value of transvalue.
- *
- *       Other behavior is also supported and is controlled by the 'combineStates'
- *       and 'finalizeAggs'. 'combineStates' controls whether the trans func or
- *       the combine func is used during aggregation.  When 'combineStates' is
- *       true we expect other (previously) aggregated states as input rather than
- *       input tuples. This mode facilitates multiple aggregate stages which
- *       allows us to support pushing aggregation down deeper into the plan rather
- *       than leaving it for the final stage. For example with a query such as:
- *
- *       SELECT count(*) FROM (SELECT * FROM a UNION ALL SELECT * FROM b);
- *
- *       with this functionality the planner has the flexibility to generate a
- *       plan which performs count(*) on table a and table b separately and then
- *       add a combine phase to combine both results. In this case the combine
- *       function would simply add both counts together.
- *
- *       When multiple aggregate stages exist the planner should have set the
- *       'finalizeAggs' to true only for the final aggregtion state, and each
- *       stage, apart from the very first one should have 'combineStates' set to
- *       true. This permits plans such as:
- *
- *             Finalize Aggregate
- *                     ->      Partial Aggregate
- *                             ->      Partial Aggregate
- *
- *       Combine functions which use pass-by-ref states should be careful to
- *       always update the 1st state parameter by adding the 2nd parameter to it,
- *       rather than the other way around. If the 1st state is NULL, then it's not
- *       sufficient to simply return the 2nd state, as the memory context is
- *       incorrect. Instead a new state should be created in the correct aggregate
- *       memory context and the 2nd state should be copied over.
- *
- *       The 'serialStates' option can be used to allow multi-stage aggregation
- *       for aggregates with an INTERNAL state type. When this mode is disabled
- *       only a pointer to the INTERNAL aggregate states are passed around the
- *       executor.  When enabled, INTERNAL states are serialized and deserialized
- *       as required; this is useful when data must be passed between processes.
+ *       If a finalfunc is not supplied then the result is just the ending
+ *       value of transvalue.
+ *
+ *       Other behaviors can be selected by the "aggsplit" mode, which exists
+ *       to support partial aggregation.  It is possible to:
+ *       * Skip running the finalfunc, so that the output is always the
+ *       final transvalue state.
+ *       * Substitute the combinefunc for the transfunc, so that transvalue
+ *       states (propagated up from a child partial-aggregation step) are merged
+ *       rather than processing raw input rows.  (The statements below about
+ *       the transfunc apply equally to the combinefunc, when it's selected.)
+ *       * Apply the serializefunc to the output values (this only makes sense
+ *       when skipping the finalfunc, since the serializefunc works on the
+ *       transvalue data type).
+ *       * Apply the deserializefunc to the input values (this only makes sense
+ *       when using the combinefunc, for similar reasons).
+ *       It is the planner's responsibility to connect up Agg nodes using these
+ *       alternate behaviors in a way that makes sense, with partial aggregation
+ *       results being fed to nodes that expect them.
  *
  *       If a normal aggregate call specifies DISTINCT or ORDER BY, we sort the
  *       input tuples and eliminate duplicates (if required) before performing
  *       the above-depicted process.  (However, we don't do that for ordered-set
  *       aggregates; their "ORDER BY" inputs are ordinary aggregate arguments
- *       so far as this module is concerned.)
+ *       so far as this module is concerned.)  Note that partial aggregation
+ *       is not supported in these cases, since we couldn't ensure global
+ *       ordering or distinctness of the inputs.
  *
  *       If transfunc is marked "strict" in pg_proc and initcond is NULL,
  *       then the first non-NULL input_value is assigned directly to transvalue,
@@ -862,8 +844,6 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
        int                     numGroupingSets = Max(aggstate->phase->numsets, 1);
        int                     numTrans = aggstate->numtrans;
 
-       Assert(!aggstate->combineStates);
-
        for (transno = 0; transno < numTrans; transno++)
        {
                AggStatePerTrans pertrans = &aggstate->pertrans[transno];
@@ -948,9 +928,11 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
 }
 
 /*
- * combine_aggregates is used when running in 'combineState' mode. This
- * advances each aggregate transition state by adding another transition state
- * to it.
+ * combine_aggregates replaces advance_aggregates in DO_AGGSPLIT_COMBINE
+ * mode.  The principal difference is that here we may need to apply the
+ * deserialization function before running the transfn (which, in this mode,
+ * is actually the aggregate's combinefn).  Also, we know we don't need to
+ * handle FILTER, DISTINCT, ORDER BY, or grouping sets.
  */
 static void
 combine_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
@@ -960,14 +942,13 @@ combine_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
 
        /* combine not supported with grouping sets */
        Assert(aggstate->phase->numsets == 0);
-       Assert(aggstate->combineStates);
 
        for (transno = 0; transno < numTrans; transno++)
        {
                AggStatePerTrans pertrans = &aggstate->pertrans[transno];
+               AggStatePerGroup pergroupstate = &pergroup[transno];
                TupleTableSlot *slot;
                FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
-               AggStatePerGroup pergroupstate = &pergroup[transno];
 
                /* Evaluate the current input expressions for this aggregate */
                slot = ExecProject(pertrans->evalproj, NULL);
@@ -979,15 +960,12 @@ combine_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
                 */
                if (OidIsValid(pertrans->deserialfn_oid))
                {
-                       /*
-                        * Don't call a strict deserialization function with NULL input. A
-                        * strict deserialization function and a null value means we skip
-                        * calling the combine function for this state. We assume that
-                        * this would be a waste of time and effort anyway so just skip
-                        * it.
-                        */
+                       /* Don't call a strict deserialization function with NULL input */
                        if (pertrans->deserialfn.fn_strict && slot->tts_isnull[0])
-                               continue;
+                       {
+                               fcinfo->arg[1] = slot->tts_values[0];
+                               fcinfo->argnull[1] = slot->tts_isnull[0];
+                       }
                        else
                        {
                                FunctionCallInfo dsinfo = &pertrans->deserialfn_fcinfo;
@@ -1110,7 +1088,6 @@ advance_combine_function(AggState *aggstate,
        pergroupstate->transValueIsNull = fcinfo->isnull;
 
        MemoryContextSwitchTo(oldContext);
-
 }
 
 
@@ -1415,7 +1392,7 @@ finalize_aggregate(AggState *aggstate,
 }
 
 /*
- * Compute the final value of one partial aggregate.
+ * Compute the output value of one partial aggregate.
  *
  * The serialization function will be run, and the result delivered, in the
  * output-tuple context; caller's CurrentMemoryContext does not matter.
@@ -1432,8 +1409,8 @@ finalize_partialaggregate(AggState *aggstate,
        oldContext = MemoryContextSwitchTo(aggstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory);
 
        /*
-        * serialfn_oid will be set if we must serialize the input state before
-        * calling the combine function on the state.
+        * serialfn_oid will be set if we must serialize the transvalue before
+        * returning it
         */
        if (OidIsValid(pertrans->serialfn_oid))
        {
@@ -1577,12 +1554,12 @@ finalize_aggregates(AggState *aggstate,
                                                                                                pergroupstate);
                }
 
-               if (aggstate->finalizeAggs)
-                       finalize_aggregate(aggstate, peragg, pergroupstate,
-                                                          &aggvalues[aggno], &aggnulls[aggno]);
-               else
+               if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
                        finalize_partialaggregate(aggstate, peragg, pergroupstate,
                                                                          &aggvalues[aggno], &aggnulls[aggno]);
+               else
+                       finalize_aggregate(aggstate, peragg, pergroupstate,
+                                                          &aggvalues[aggno], &aggnulls[aggno]);
        }
 }
 
@@ -2114,10 +2091,10 @@ agg_retrieve_direct(AggState *aggstate)
                                 */
                                for (;;)
                                {
-                                       if (!aggstate->combineStates)
-                                               advance_aggregates(aggstate, pergroup);
-                                       else
+                                       if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
                                                combine_aggregates(aggstate, pergroup);
+                                       else
+                                               advance_aggregates(aggstate, pergroup);
 
                                        /* Reset per-input-tuple context after each tuple */
                                        ResetExprContext(tmpcontext);
@@ -2225,10 +2202,10 @@ agg_fill_hash_table(AggState *aggstate)
                entry = lookup_hash_entry(aggstate, outerslot);
 
                /* Advance the aggregates */
-               if (!aggstate->combineStates)
-                       advance_aggregates(aggstate, entry->pergroup);
-               else
+               if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
                        combine_aggregates(aggstate, entry->pergroup);
+               else
+                       advance_aggregates(aggstate, entry->pergroup);
 
                /* Reset per-input-tuple context after each tuple */
                ResetExprContext(tmpcontext);
@@ -2352,6 +2329,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
        aggstate->aggs = NIL;
        aggstate->numaggs = 0;
        aggstate->numtrans = 0;
+       aggstate->aggsplit = node->aggsplit;
        aggstate->maxsets = 0;
        aggstate->hashfunctions = NULL;
        aggstate->projected_set = -1;
@@ -2359,11 +2337,8 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
        aggstate->peragg = NULL;
        aggstate->pertrans = NULL;
        aggstate->curpertrans = NULL;
-       aggstate->agg_done = false;
-       aggstate->combineStates = node->combineStates;
-       aggstate->finalizeAggs = node->finalizeAggs;
-       aggstate->serialStates = node->serialStates;
        aggstate->input_done = false;
+       aggstate->agg_done = false;
        aggstate->pergroup = NULL;
        aggstate->grp_firstTuple = NULL;
        aggstate->hashtable = NULL;
@@ -2681,6 +2656,8 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
 
                /* Planner should have assigned aggregate to correct level */
                Assert(aggref->agglevelsup == 0);
+               /* ... and the split mode should match */
+               Assert(aggref->aggsplit == aggstate->aggsplit);
 
                /* 1. Check for already processed aggs which can be re-used */
                existing_aggno = find_compatible_peragg(aggref, aggstate, aggno,
@@ -2724,7 +2701,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
                 * If this aggregation is performing state combines, then instead of
                 * using the transition function, we'll use the combine function
                 */
-               if (aggstate->combineStates)
+               if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
                {
                        transfn_oid = aggform->aggcombinefn;
 
@@ -2736,39 +2713,45 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
                        transfn_oid = aggform->aggtransfn;
 
                /* Final function only required if we're finalizing the aggregates */
-               if (aggstate->finalizeAggs)
-                       peragg->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
-               else
+               if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
                        peragg->finalfn_oid = finalfn_oid = InvalidOid;
+               else
+                       peragg->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
 
                serialfn_oid = InvalidOid;
                deserialfn_oid = InvalidOid;
 
                /*
-                * Determine if we require serialization or deserialization of the
-                * aggregate states. This is only required if the aggregate state is
-                * internal.
+                * Check if serialization/deserialization is required.  We only do it
+                * for aggregates that have transtype INTERNAL.
                 */
-               if (aggstate->serialStates && aggtranstype == INTERNALOID)
+               if (aggtranstype == INTERNALOID)
                {
                        /*
-                        * The planner should only have generated an agg node with
-                        * serialStates if every aggregate with an INTERNAL state has
-                        * serialization/deserialization functions.  Verify that.
+                        * The planner should only have generated a serialize agg node if
+                        * every aggregate with an INTERNAL state has a serialization
+                        * function.  Verify that.
                         */
-                       if (!OidIsValid(aggform->aggserialfn))
-                               elog(ERROR, "serialfunc not set during serialStates aggregation step");
-
-                       if (!OidIsValid(aggform->aggdeserialfn))
-                               elog(ERROR, "deserialfunc not set during serialStates aggregation step");
+                       if (DO_AGGSPLIT_SERIALIZE(aggstate->aggsplit))
+                       {
+                               /* serialization only valid when not running finalfn */
+                               Assert(DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
 
-                       /* serialization func only required when not finalizing aggs */
-                       if (!aggstate->finalizeAggs)
+                               if (!OidIsValid(aggform->aggserialfn))
+                                       elog(ERROR, "serialfunc not provided for serialization aggregation");
                                serialfn_oid = aggform->aggserialfn;
+                       }
+
+                       /* Likewise for deserialization functions */
+                       if (DO_AGGSPLIT_DESERIALIZE(aggstate->aggsplit))
+                       {
+                               /* deserialization only valid when combining states */
+                               Assert(DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
 
-                       /* deserialization func only required when combining states */
-                       if (aggstate->combineStates)
+                               if (!OidIsValid(aggform->aggdeserialfn))
+                                       elog(ERROR, "deserialfunc not provided for deserialization aggregation");
                                deserialfn_oid = aggform->aggdeserialfn;
+                       }
                }
 
                /* Check that aggregate owner has permission to call component fns */
@@ -2853,7 +2836,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
                }
 
                /* get info about the output value's datatype */
-               get_typlenbyval(aggref->aggoutputtype,
+               get_typlenbyval(aggref->aggtype,
                                                &peragg->resulttypeLen,
                                                &peragg->resulttypeByVal);
 
@@ -2972,7 +2955,7 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
         * transfn and transfn_oid fields of pertrans refer to the combine
         * function rather than the transition function.
         */
-       if (aggstate->combineStates)
+       if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
        {
                Expr       *combinefnexpr;
 
index 59add5ba794fc6214a34c5806622184e61b88250..d2786575d98545cd7251aef25927289e903f02a9 100644 (file)
@@ -870,9 +870,7 @@ _copyAgg(const Agg *from)
        CopyPlanFields((const Plan *) from, (Plan *) newnode);
 
        COPY_SCALAR_FIELD(aggstrategy);
-       COPY_SCALAR_FIELD(combineStates);
-       COPY_SCALAR_FIELD(finalizeAggs);
-       COPY_SCALAR_FIELD(serialStates);
+       COPY_SCALAR_FIELD(aggsplit);
        COPY_SCALAR_FIELD(numCols);
        if (from->numCols > 0)
        {
@@ -1235,7 +1233,6 @@ _copyAggref(const Aggref *from)
 
        COPY_SCALAR_FIELD(aggfnoid);
        COPY_SCALAR_FIELD(aggtype);
-       COPY_SCALAR_FIELD(aggoutputtype);
        COPY_SCALAR_FIELD(aggcollid);
        COPY_SCALAR_FIELD(inputcollid);
        COPY_SCALAR_FIELD(aggtranstype);
@@ -1247,10 +1244,9 @@ _copyAggref(const Aggref *from)
        COPY_NODE_FIELD(aggfilter);
        COPY_SCALAR_FIELD(aggstar);
        COPY_SCALAR_FIELD(aggvariadic);
-       COPY_SCALAR_FIELD(aggcombine);
-       COPY_SCALAR_FIELD(aggpartial);
        COPY_SCALAR_FIELD(aggkind);
        COPY_SCALAR_FIELD(agglevelsup);
+       COPY_SCALAR_FIELD(aggsplit);
        COPY_LOCATION_FIELD(location);
 
        return newnode;
index 8258c01f32a6e7a629ee8f5de07b94f9049d4460..1eb679926af9f0f1ab412f11278711756e6ccae0 100644 (file)
@@ -192,7 +192,6 @@ _equalAggref(const Aggref *a, const Aggref *b)
 {
        COMPARE_SCALAR_FIELD(aggfnoid);
        COMPARE_SCALAR_FIELD(aggtype);
-       COMPARE_SCALAR_FIELD(aggoutputtype);
        COMPARE_SCALAR_FIELD(aggcollid);
        COMPARE_SCALAR_FIELD(inputcollid);
        /* ignore aggtranstype since it might not be set yet */
@@ -204,10 +203,9 @@ _equalAggref(const Aggref *a, const Aggref *b)
        COMPARE_NODE_FIELD(aggfilter);
        COMPARE_SCALAR_FIELD(aggstar);
        COMPARE_SCALAR_FIELD(aggvariadic);
-       COMPARE_SCALAR_FIELD(aggcombine);
-       COMPARE_SCALAR_FIELD(aggpartial);
        COMPARE_SCALAR_FIELD(aggkind);
        COMPARE_SCALAR_FIELD(agglevelsup);
+       COMPARE_SCALAR_FIELD(aggsplit);
        COMPARE_LOCATION_FIELD(location);
 
        return true;
index c5283016308457ea8ac90ea40155c808c4c25160..cd391673511693217ef97099a8d3bcf2cbd8face 100644 (file)
@@ -58,7 +58,7 @@ exprType(const Node *expr)
                        type = ((const Param *) expr)->paramtype;
                        break;
                case T_Aggref:
-                       type = ((const Aggref *) expr)->aggoutputtype;
+                       type = ((const Aggref *) expr)->aggtype;
                        break;
                case T_GroupingFunc:
                        type = INT4OID;
index b0a28f515f19e3e8f615935a4c2e1f1b05fec630..9186f049ec77614918fb3803db0e365b947fc840 100644 (file)
@@ -705,9 +705,7 @@ _outAgg(StringInfo str, const Agg *node)
        _outPlanInfo(str, (const Plan *) node);
 
        WRITE_ENUM_FIELD(aggstrategy, AggStrategy);
-       WRITE_BOOL_FIELD(combineStates);
-       WRITE_BOOL_FIELD(finalizeAggs);
-       WRITE_BOOL_FIELD(serialStates);
+       WRITE_ENUM_FIELD(aggsplit, AggSplit);
        WRITE_INT_FIELD(numCols);
 
        appendStringInfoString(str, " :grpColIdx");
@@ -1031,7 +1029,6 @@ _outAggref(StringInfo str, const Aggref *node)
 
        WRITE_OID_FIELD(aggfnoid);
        WRITE_OID_FIELD(aggtype);
-       WRITE_OID_FIELD(aggoutputtype);
        WRITE_OID_FIELD(aggcollid);
        WRITE_OID_FIELD(inputcollid);
        WRITE_OID_FIELD(aggtranstype);
@@ -1043,10 +1040,9 @@ _outAggref(StringInfo str, const Aggref *node)
        WRITE_NODE_FIELD(aggfilter);
        WRITE_BOOL_FIELD(aggstar);
        WRITE_BOOL_FIELD(aggvariadic);
-       WRITE_BOOL_FIELD(aggcombine);
-       WRITE_BOOL_FIELD(aggpartial);
        WRITE_CHAR_FIELD(aggkind);
        WRITE_UINT_FIELD(agglevelsup);
+       WRITE_ENUM_FIELD(aggsplit, AggSplit);
        WRITE_LOCATION_FIELD(location);
 }
 
@@ -1854,6 +1850,7 @@ _outAggPath(StringInfo str, const AggPath *node)
 
        WRITE_NODE_FIELD(subpath);
        WRITE_ENUM_FIELD(aggstrategy, AggStrategy);
+       WRITE_ENUM_FIELD(aggsplit, AggSplit);
        WRITE_FLOAT_FIELD(numGroups, "%.0f");
        WRITE_NODE_FIELD(groupClause);
        WRITE_NODE_FIELD(qual);
index b1f9e3e41ecf66fa77407ab8c47c5f16566746d7..45659818e21b84eb9a3bd37b08eefc6cc416bada 100644 (file)
@@ -546,7 +546,6 @@ _readAggref(void)
 
        READ_OID_FIELD(aggfnoid);
        READ_OID_FIELD(aggtype);
-       READ_OID_FIELD(aggoutputtype);
        READ_OID_FIELD(aggcollid);
        READ_OID_FIELD(inputcollid);
        READ_OID_FIELD(aggtranstype);
@@ -558,10 +557,9 @@ _readAggref(void)
        READ_NODE_FIELD(aggfilter);
        READ_BOOL_FIELD(aggstar);
        READ_BOOL_FIELD(aggvariadic);
-       READ_BOOL_FIELD(aggcombine);
-       READ_BOOL_FIELD(aggpartial);
        READ_CHAR_FIELD(aggkind);
        READ_UINT_FIELD(agglevelsup);
+       READ_ENUM_FIELD(aggsplit, AggSplit);
        READ_LOCATION_FIELD(location);
 
        READ_DONE();
@@ -1989,9 +1987,7 @@ _readAgg(void)
        ReadCommonPlan(&local_node->plan);
 
        READ_ENUM_FIELD(aggstrategy, AggStrategy);
-       READ_BOOL_FIELD(combineStates);
-       READ_BOOL_FIELD(finalizeAggs);
-       READ_BOOL_FIELD(serialStates);
+       READ_ENUM_FIELD(aggsplit, AggSplit);
        READ_INT_FIELD(numCols);
        READ_ATTRNUMBER_ARRAY(grpColIdx, local_node->numCols);
        READ_OID_ARRAY(grpOperators, local_node->numCols);
index b2db6e8d0355c8f9e0ebe8c351fab985c1623d6b..58bfd491307bf7e3c29db3802d3eb9c9e2088d35 100644 (file)
@@ -1304,9 +1304,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path, int flags)
                plan = (Plan *) make_agg(build_path_tlist(root, &best_path->path),
                                                                 NIL,
                                                                 AGG_HASHED,
-                                                                false,
-                                                                true,
-                                                                false,
+                                                                AGGSPLIT_SIMPLE,
                                                                 numGroupCols,
                                                                 groupColIdx,
                                                                 groupOperators,
@@ -1610,9 +1608,7 @@ create_agg_plan(PlannerInfo *root, AggPath *best_path)
 
        plan = make_agg(tlist, quals,
                                        best_path->aggstrategy,
-                                       best_path->combineStates,
-                                       best_path->finalizeAggs,
-                                       best_path->serialStates,
+                                       best_path->aggsplit,
                                        list_length(best_path->groupClause),
                                        extract_grouping_cols(best_path->groupClause,
                                                                                  subplan->targetlist),
@@ -1765,9 +1761,7 @@ create_groupingsets_plan(PlannerInfo *root, GroupingSetsPath *best_path)
                        agg_plan = (Plan *) make_agg(NIL,
                                                                                 NIL,
                                                                                 AGG_SORTED,
-                                                                                false,
-                                                                                true,
-                                                                                false,
+                                                                                AGGSPLIT_SIMPLE,
                                                                           list_length((List *) linitial(gsets)),
                                                                                 new_grpColIdx,
                                                                                 extract_grouping_ops(groupClause),
@@ -1802,9 +1796,7 @@ create_groupingsets_plan(PlannerInfo *root, GroupingSetsPath *best_path)
                plan = make_agg(build_path_tlist(root, &best_path->path),
                                                best_path->qual,
                                                (numGroupCols > 0) ? AGG_SORTED : AGG_PLAIN,
-                                               false,
-                                               true,
-                                               false,
+                                               AGGSPLIT_SIMPLE,
                                                numGroupCols,
                                                top_grpColIdx,
                                                extract_grouping_ops(groupClause),
@@ -5652,8 +5644,7 @@ materialize_finished_plan(Plan *subplan)
 
 Agg *
 make_agg(List *tlist, List *qual,
-                AggStrategy aggstrategy,
-                bool combineStates, bool finalizeAggs, bool serialStates,
+                AggStrategy aggstrategy, AggSplit aggsplit,
                 int numGroupCols, AttrNumber *grpColIdx, Oid *grpOperators,
                 List *groupingSets, List *chain,
                 double dNumGroups, Plan *lefttree)
@@ -5666,9 +5657,7 @@ make_agg(List *tlist, List *qual,
        numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
 
        node->aggstrategy = aggstrategy;
-       node->combineStates = combineStates;
-       node->finalizeAggs = finalizeAggs;
-       node->serialStates = serialStates;
+       node->aggsplit = aggsplit;
        node->numCols = numGroupCols;
        node->grpColIdx = grpColIdx;
        node->grpOperators = grpOperators;
index 322a18df7344508b667da0a3c8374f61b4f723a6..cc208a6a9bb3f568675c5f91d9c5e231a0f2e1b0 100644 (file)
@@ -3391,10 +3391,10 @@ create_grouping_paths(PlannerInfo *root,
        MemSet(&agg_costs, 0, sizeof(AggClauseCosts));
        if (parse->hasAggs)
        {
-               count_agg_clauses(root, (Node *) target->exprs, &agg_costs, true,
-                                                 false, false);
-               count_agg_clauses(root, parse->havingQual, &agg_costs, true, false,
-                                                 false);
+               get_agg_clause_costs(root, (Node *) target->exprs, AGGSPLIT_SIMPLE,
+                                                        &agg_costs);
+               get_agg_clause_costs(root, parse->havingQual, AGGSPLIT_SIMPLE,
+                                                        &agg_costs);
        }
 
        /*
@@ -3480,14 +3480,17 @@ create_grouping_paths(PlannerInfo *root,
                if (parse->hasAggs)
                {
                        /* partial phase */
-                       count_agg_clauses(root, (Node *) partial_grouping_target->exprs,
-                                                         &agg_partial_costs, false, false, true);
+                       get_agg_clause_costs(root, (Node *) partial_grouping_target->exprs,
+                                                                AGGSPLIT_INITIAL_SERIAL,
+                                                                &agg_partial_costs);
 
                        /* final phase */
-                       count_agg_clauses(root, (Node *) target->exprs, &agg_final_costs,
-                                                         true, true, true);
-                       count_agg_clauses(root, parse->havingQual, &agg_final_costs, true,
-                                                         true, true);
+                       get_agg_clause_costs(root, (Node *) target->exprs,
+                                                                AGGSPLIT_FINAL_DESERIAL,
+                                                                &agg_final_costs);
+                       get_agg_clause_costs(root, parse->havingQual,
+                                                                AGGSPLIT_FINAL_DESERIAL,
+                                                                &agg_final_costs);
                }
 
                if (can_sort)
@@ -3523,13 +3526,11 @@ create_grouping_paths(PlannerInfo *root,
                                                                                                                 path,
                                                                                                         partial_grouping_target,
                                                                 parse->groupClause ? AGG_SORTED : AGG_PLAIN,
+                                                                                                        AGGSPLIT_INITIAL_SERIAL,
                                                                                                                 parse->groupClause,
                                                                                                                 NIL,
                                                                                                                 &agg_partial_costs,
-                                                                                                                dNumPartialGroups,
-                                                                                                                false,
-                                                                                                                false,
-                                                                                                                true));
+                                                                                                                dNumPartialGroups));
                                        else
                                                add_partial_path(grouped_rel, (Path *)
                                                                                 create_group_path(root,
@@ -3565,13 +3566,11 @@ create_grouping_paths(PlannerInfo *root,
                                                                                                 cheapest_partial_path,
                                                                                                 partial_grouping_target,
                                                                                                 AGG_HASHED,
+                                                                                                AGGSPLIT_INITIAL_SERIAL,
                                                                                                 parse->groupClause,
                                                                                                 NIL,
                                                                                                 &agg_partial_costs,
-                                                                                                dNumPartialGroups,
-                                                                                                false,
-                                                                                                false,
-                                                                                                true));
+                                                                                                dNumPartialGroups));
                        }
                }
        }
@@ -3630,13 +3629,11 @@ create_grouping_paths(PlannerInfo *root,
                                                                                         path,
                                                                                         target,
                                                                 parse->groupClause ? AGG_SORTED : AGG_PLAIN,
+                                                                                        AGGSPLIT_SIMPLE,
                                                                                         parse->groupClause,
                                                                                         (List *) parse->havingQual,
                                                                                         &agg_costs,
-                                                                                        dNumGroups,
-                                                                                        false,
-                                                                                        true,
-                                                                                        false));
+                                                                                        dNumGroups));
                                }
                                else if (parse->groupClause)
                                {
@@ -3697,13 +3694,11 @@ create_grouping_paths(PlannerInfo *root,
                                                                                 path,
                                                                                 target,
                                                                 parse->groupClause ? AGG_SORTED : AGG_PLAIN,
+                                                                                AGGSPLIT_FINAL_DESERIAL,
                                                                                 parse->groupClause,
                                                                                 (List *) parse->havingQual,
                                                                                 &agg_final_costs,
-                                                                                dNumGroups,
-                                                                                true,
-                                                                                true,
-                                                                                true));
+                                                                                dNumGroups));
                        else
                                add_path(grouped_rel, (Path *)
                                                 create_group_path(root,
@@ -3740,13 +3735,11 @@ create_grouping_paths(PlannerInfo *root,
                                                                         cheapest_path,
                                                                         target,
                                                                         AGG_HASHED,
+                                                                        AGGSPLIT_SIMPLE,
                                                                         parse->groupClause,
                                                                         (List *) parse->havingQual,
                                                                         &agg_costs,
-                                                                        dNumGroups,
-                                                                        false,
-                                                                        true,
-                                                                        false));
+                                                                        dNumGroups));
                }
 
                /*
@@ -3779,13 +3772,11 @@ create_grouping_paths(PlannerInfo *root,
                                                                                 path,
                                                                                 target,
                                                                                 AGG_HASHED,
+                                                                                AGGSPLIT_FINAL_DESERIAL,
                                                                                 parse->groupClause,
                                                                                 (List *) parse->havingQual,
                                                                                 &agg_final_costs,
-                                                                                dNumGroups,
-                                                                                true,
-                                                                                true,
-                                                                                true));
+                                                                                dNumGroups));
                        }
                }
        }
@@ -4123,13 +4114,11 @@ create_distinct_paths(PlannerInfo *root,
                                                                 cheapest_input_path,
                                                                 cheapest_input_path->pathtarget,
                                                                 AGG_HASHED,
+                                                                AGGSPLIT_SIMPLE,
                                                                 parse->distinctClause,
                                                                 NIL,
                                                                 NULL,
-                                                                numDistinctRows,
-                                                                false,
-                                                                true,
-                                                                false));
+                                                                numDistinctRows));
        }
 
        /* Give a helpful error if we failed to find any implementation */
@@ -4414,8 +4403,8 @@ make_partial_grouping_target(PlannerInfo *root, PathTarget *grouping_target)
                        newaggref = makeNode(Aggref);
                        memcpy(newaggref, aggref, sizeof(Aggref));
 
-                       /* XXX assume serialization required */
-                       mark_partial_aggref(newaggref, true);
+                       /* For now, assume serialization is required */
+                       mark_partial_aggref(newaggref, AGGSPLIT_INITIAL_SERIAL);
 
                        lfirst(lc) = newaggref;
                }
@@ -4431,27 +4420,33 @@ make_partial_grouping_target(PlannerInfo *root, PathTarget *grouping_target)
 
 /*
  * mark_partial_aggref
- *       Adjust an Aggref to make it represent the output of partial aggregation.
+ *       Adjust an Aggref to make it represent a partial-aggregation step.
  *
  * The Aggref node is modified in-place; caller must do any copying required.
  */
 void
-mark_partial_aggref(Aggref *agg, bool serialize)
+mark_partial_aggref(Aggref *agg, AggSplit aggsplit)
 {
        /* aggtranstype should be computed by this point */
        Assert(OidIsValid(agg->aggtranstype));
+       /* ... but aggsplit should still be as the parser left it */
+       Assert(agg->aggsplit == AGGSPLIT_SIMPLE);
+
+       /* Mark the Aggref with the intended partial-aggregation mode */
+       agg->aggsplit = aggsplit;
 
        /*
-        * Normally, a partial aggregate returns the aggregate's transition type;
-        * but if that's INTERNAL and we're serializing, it returns BYTEA instead.
+        * Adjust result type if needed.  Normally, a partial aggregate returns
+        * the aggregate's transition type; but if that's INTERNAL and we're
+        * serializing, it returns BYTEA instead.
         */
-       if (agg->aggtranstype == INTERNALOID && serialize)
-               agg->aggoutputtype = BYTEAOID;
-       else
-               agg->aggoutputtype = agg->aggtranstype;
-
-       /* flag it as partial */
-       agg->aggpartial = true;
+       if (DO_AGGSPLIT_SKIPFINAL(aggsplit))
+       {
+               if (agg->aggtranstype == INTERNALOID && DO_AGGSPLIT_SERIALIZE(aggsplit))
+                       agg->aggtype = BYTEAOID;
+               else
+                       agg->aggtype = agg->aggtranstype;
+       }
 }
 
 /*
index e02cf18576fb731c66eaadb99b356f0bd69298b9..ffff6db249032ed780bdcbed9f17c57b88621169 100644 (file)
@@ -679,7 +679,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
                                 * partial-aggregate subexpressions that will be available
                                 * from the child plan node.
                                 */
-                               if (agg->combineStates)
+                               if (DO_AGGSPLIT_COMBINE(agg->aggsplit))
                                {
                                        plan->targetlist = (List *)
                                                convert_combining_aggrefs((Node *) plan->targetlist,
@@ -1772,16 +1772,16 @@ convert_combining_aggrefs(Node *node, void *context)
 
                /*
                 * Now, set up child_agg to represent the first phase of partial
-                * aggregation.  XXX assume serialization required.
+                * aggregation.  For now, assume serialization is required.
                 */
-               mark_partial_aggref(child_agg, true);
+               mark_partial_aggref(child_agg, AGGSPLIT_INITIAL_SERIAL);
 
                /*
                 * And set up parent_agg to represent the second phase.
                 */
                parent_agg->args = list_make1(makeTargetEntry((Expr *) child_agg,
                                                                                                          1, NULL, false));
-               parent_agg->aggcombine = true;
+               mark_partial_aggref(parent_agg, AGGSPLIT_FINAL_DESERIAL);
 
                return (Node *) parent_agg;
        }
index 552b756b8b1b5da51445c02183a304889b439ee1..ca01238c7f23b9d76cc18de7005b3418f615b583 100644 (file)
@@ -861,13 +861,11 @@ make_union_unique(SetOperationStmt *op, Path *path, List *tlist,
                                                                                path,
                                                                                create_pathtarget(root, tlist),
                                                                                AGG_HASHED,
+                                                                               AGGSPLIT_SIMPLE,
                                                                                groupList,
                                                                                NIL,
                                                                                NULL,
-                                                                               dNumGroups,
-                                                                               false,
-                                                                               true,
-                                                                               false);
+                                                                               dNumGroups);
        }
        else
        {
index 7138cad31d82452dc0b7aed9b9414919b258008c..40c39772649503a3175c1fe669fd728639d49c3b 100644 (file)
@@ -60,11 +60,9 @@ typedef struct
 typedef struct
 {
        PlannerInfo *root;
+       AggSplit        aggsplit;
        AggClauseCosts *costs;
-       bool            finalizeAggs;
-       bool            combineStates;
-       bool            serialStates;
-} count_agg_clauses_context;
+} get_agg_clause_costs_context;
 
 typedef struct
 {
@@ -103,8 +101,8 @@ typedef struct
 static bool aggregates_allow_partial_walker(Node *node,
                                                                partial_agg_context *context);
 static bool contain_agg_clause_walker(Node *node, void *context);
-static bool count_agg_clauses_walker(Node *node,
-                                                count_agg_clauses_context *context);
+static bool get_agg_clause_costs_walker(Node *node,
+                                                       get_agg_clause_costs_context *context);
 static bool find_window_functions_walker(Node *node, WindowFuncLists *lists);
 static bool expression_returns_set_rows_walker(Node *node, double *count);
 static bool contain_subplans_walker(Node *node, void *context);
@@ -519,44 +517,43 @@ contain_agg_clause_walker(Node *node, void *context)
 }
 
 /*
- * count_agg_clauses
- *       Recursively count the Aggref nodes in an expression tree, and
- *       accumulate other information about them too.
+ * get_agg_clause_costs
+ *       Recursively find the Aggref nodes in an expression tree, and
+ *       accumulate cost information about them.
  *
- *       Note: this also checks for nested aggregates, which are an error.
+ * 'aggsplit' tells us the expected partial-aggregation mode, which affects
+ * the cost estimates.
  *
- * We not only count the nodes, but estimate their execution costs, and
- * attempt to estimate the total space needed for their transition state
- * values if all are evaluated in parallel (as would be done in a HashAgg
- * plan).  See AggClauseCosts for the exact set of statistics collected.
+ * NOTE that the counts/costs are ADDED to those already in *costs ... so
+ * the caller is responsible for zeroing the struct initially.
+ *
+ * We count the nodes, estimate their execution costs, and estimate the total
+ * space needed for their transition state values if all are evaluated in
+ * parallel (as would be done in a HashAgg plan).  See AggClauseCosts for
+ * the exact set of statistics collected.
  *
  * In addition, we mark Aggref nodes with the correct aggtranstype, so
  * that that doesn't need to be done repeatedly.  (That makes this function's
  * name a bit of a misnomer.)
  *
- * NOTE that the counts/costs are ADDED to those already in *costs ... so
- * the caller is responsible for zeroing the struct initially.
- *
  * This does not descend into subqueries, and so should be used only after
  * reduction of sublinks to subplans, or in contexts where it's known there
  * are no subqueries.  There mustn't be outer-aggregate references either.
  */
 void
-count_agg_clauses(PlannerInfo *root, Node *clause, AggClauseCosts *costs,
-                                 bool finalizeAggs, bool combineStates, bool serialStates)
+get_agg_clause_costs(PlannerInfo *root, Node *clause, AggSplit aggsplit,
+                                        AggClauseCosts *costs)
 {
-       count_agg_clauses_context context;
+       get_agg_clause_costs_context context;
 
        context.root = root;
+       context.aggsplit = aggsplit;
        context.costs = costs;
-       context.finalizeAggs = finalizeAggs;
-       context.combineStates = combineStates;
-       context.serialStates = serialStates;
-       (void) count_agg_clauses_walker(clause, &context);
+       (void) get_agg_clause_costs_walker(clause, &context);
 }
 
 static bool
-count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
+get_agg_clause_costs_walker(Node *node, get_agg_clause_costs_context *context)
 {
        if (node == NULL)
                return false;
@@ -628,34 +625,28 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
                 * Add the appropriate component function execution costs to
                 * appropriate totals.
                 */
-               if (context->combineStates)
+               if (DO_AGGSPLIT_COMBINE(context->aggsplit))
                {
                        /* charge for combining previously aggregated states */
                        costs->transCost.per_tuple += get_func_cost(aggcombinefn) * cpu_operator_cost;
-
-                       /* charge for deserialization, when appropriate */
-                       if (context->serialStates && OidIsValid(aggdeserialfn))
-                               costs->transCost.per_tuple += get_func_cost(aggdeserialfn) * cpu_operator_cost;
                }
                else
                        costs->transCost.per_tuple += get_func_cost(aggtransfn) * cpu_operator_cost;
-
-               if (context->finalizeAggs)
-               {
-                       if (OidIsValid(aggfinalfn))
-                               costs->finalCost += get_func_cost(aggfinalfn) * cpu_operator_cost;
-               }
-               else if (context->serialStates)
-               {
-                       if (OidIsValid(aggserialfn))
-                               costs->finalCost += get_func_cost(aggserialfn) * cpu_operator_cost;
-               }
+               if (DO_AGGSPLIT_DESERIALIZE(context->aggsplit) &&
+                       OidIsValid(aggdeserialfn))
+                       costs->transCost.per_tuple += get_func_cost(aggdeserialfn) * cpu_operator_cost;
+               if (DO_AGGSPLIT_SERIALIZE(context->aggsplit) &&
+                       OidIsValid(aggserialfn))
+                       costs->finalCost += get_func_cost(aggserialfn) * cpu_operator_cost;
+               if (!DO_AGGSPLIT_SKIPFINAL(context->aggsplit) &&
+                       OidIsValid(aggfinalfn))
+                       costs->finalCost += get_func_cost(aggfinalfn) * cpu_operator_cost;
 
                /*
-                * Some costs will already have been incurred by the initial aggregate
-                * node, so we mustn't include these again.
+                * These costs are incurred only by the initial aggregate node, so we
+                * mustn't include them again at upper levels.
                 */
-               if (!context->combineStates)
+               if (!DO_AGGSPLIT_COMBINE(context->aggsplit))
                {
                        /* add the input expressions' cost to per-input-row costs */
                        cost_qual_eval_node(&argcosts, (Node *) aggref->args, context->root);
@@ -747,14 +738,12 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
                /*
                 * We assume that the parser checked that there are no aggregates (of
                 * this level anyway) in the aggregated arguments, direct arguments,
-                * or filter clause.  Hence, we need not recurse into any of them. (If
-                * either the parser or the planner screws up on this point, the
-                * executor will still catch it; see ExecInitExpr.)
+                * or filter clause.  Hence, we need not recurse into any of them.
                 */
                return false;
        }
        Assert(!IsA(node, SubLink));
-       return expression_tree_walker(node, count_agg_clauses_walker,
+       return expression_tree_walker(node, get_agg_clause_costs_walker,
                                                                  (void *) context);
 }
 
index 8fd933fd6bdff4efa87b899b6e0792ec04d21afb..c3eab379534ea886f5e00a8af07160f838305978 100644 (file)
@@ -2466,12 +2466,11 @@ create_upper_unique_path(PlannerInfo *root,
  * 'subpath' is the path representing the source of data
  * 'target' is the PathTarget to be computed
  * 'aggstrategy' is the Agg node's basic implementation strategy
+ * 'aggsplit' is the Agg node's aggregate-splitting mode
  * 'groupClause' is a list of SortGroupClause's representing the grouping
  * 'qual' is the HAVING quals if any
  * 'aggcosts' contains cost info about the aggregate functions to be computed
  * 'numGroups' is the estimated number of groups (1 if not grouping)
- * 'combineStates' is set to true if the Agg node should combine agg states
- * 'finalizeAggs' is set to false if the Agg node should not call the finalfn
  */
 AggPath *
 create_agg_path(PlannerInfo *root,
@@ -2479,13 +2478,11 @@ create_agg_path(PlannerInfo *root,
                                Path *subpath,
                                PathTarget *target,
                                AggStrategy aggstrategy,
+                               AggSplit aggsplit,
                                List *groupClause,
                                List *qual,
                                const AggClauseCosts *aggcosts,
-                               double numGroups,
-                               bool combineStates,
-                               bool finalizeAggs,
-                               bool serialStates)
+                               double numGroups)
 {
        AggPath    *pathnode = makeNode(AggPath);
 
@@ -2505,12 +2502,10 @@ create_agg_path(PlannerInfo *root,
        pathnode->subpath = subpath;
 
        pathnode->aggstrategy = aggstrategy;
+       pathnode->aggsplit = aggsplit;
        pathnode->numGroups = numGroups;
        pathnode->groupClause = groupClause;
        pathnode->qual = qual;
-       pathnode->finalizeAggs = finalizeAggs;
-       pathnode->combineStates = combineStates;
-       pathnode->serialStates = serialStates;
 
        cost_agg(&pathnode->path, root,
                         aggstrategy, aggcosts,
index d36d352fe9eab232b25d1457ba6ee106ec4f0a32..61af484feebafbbc5e76bab805488e3c8e345acf 100644 (file)
@@ -647,8 +647,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
                Aggref     *aggref = makeNode(Aggref);
 
                aggref->aggfnoid = funcid;
-               /* default the outputtype to be the same as aggtype */
-               aggref->aggtype = aggref->aggoutputtype = rettype;
+               aggref->aggtype = rettype;
                /* aggcollid and inputcollid will be set by parse_collate.c */
                aggref->aggtranstype = InvalidOid;              /* will be set by planner */
                /* aggargtypes will be set by transformAggregateCall */
@@ -657,10 +656,9 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
                aggref->aggfilter = agg_filter;
                aggref->aggstar = agg_star;
                aggref->aggvariadic = func_variadic;
-               /* at this point, the Aggref is never partial or combining */
-               aggref->aggcombine = aggref->aggpartial = false;
                aggref->aggkind = aggkind;
                /* agglevelsup will be set by transformAggregateCall */
+               aggref->aggsplit = AGGSPLIT_SIMPLE;             /* planner might change this */
                aggref->location = location;
 
                /*
index 8cb3075e7856b45c6c6a98dd4d66bf5b839ed99a..afc26d424fede1c6d27a5e15c93584ed8f3d225e 100644 (file)
@@ -8285,7 +8285,7 @@ get_agg_expr(Aggref *aggref, deparse_context *context,
         * one element, which will point to a partial Aggref that supplies us with
         * transition states to combine.
         */
-       if (aggref->aggcombine)
+       if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
        {
                TargetEntry *tle = linitial(aggref->args);
 
@@ -8296,8 +8296,11 @@ get_agg_expr(Aggref *aggref, deparse_context *context,
                return;
        }
 
-       /* Mark as PARTIAL, if appropriate. */
-       if (original_aggref->aggpartial)
+       /*
+        * Mark as PARTIAL, if appropriate.  We look to the original aggref so as
+        * to avoid printing this when recursing from the code just above.
+        */
+       if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
                appendStringInfoString(buf, "PARTIAL ");
 
        /* Extract the argument types as seen by the parser */
index 9c404523d7d75c5b9ad4de83c526d7551297ea61..cca1249cddb08cf440686456932deed64630076d 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201606221
+#define CATALOG_VERSION_NO     201606261
 
 #endif
index 1ddf14a86a0dad0ebadddd6fb062a35a6ada9b5d..e7fd7bd08eef05356dfc740ad69b84e539e9ebca 100644 (file)
@@ -1823,6 +1823,7 @@ typedef struct AggState
        List       *aggs;                       /* all Aggref nodes in targetlist & quals */
        int                     numaggs;                /* length of list (could be zero!) */
        int                     numtrans;               /* number of pertrans items */
+       AggSplit        aggsplit;               /* agg-splitting mode, see nodes.h */
        AggStatePerPhase phase;         /* pointer to current phase data */
        int                     numphases;              /* number of phases */
        int                     current_phase;  /* current phase number */
@@ -1834,9 +1835,6 @@ typedef struct AggState
        AggStatePerTrans curpertrans;           /* currently active trans state */
        bool            input_done;             /* indicates end of input */
        bool            agg_done;               /* indicates completion of Agg scan */
-       bool            combineStates;  /* input tuples contain transition states */
-       bool            finalizeAggs;   /* should we call the finalfn on agg states? */
-       bool            serialStates;   /* should agg states be (de)serialized? */
        int                     projected_set;  /* The last projected grouping set */
        int                     current_set;    /* The current grouping set being evaluated */
        Bitmapset  *grouped_cols;       /* grouped cols in current projection */
index 8f46091fd9be3ad6ab90c8d863bf3a7a520e75c6..6b850e4bc4ecbd4aded4db991168900144fea02f 100644 (file)
@@ -694,6 +694,36 @@ typedef enum AggStrategy
        AGG_HASHED                                      /* grouped agg, use internal hashtable */
 } AggStrategy;
 
+/*
+ * AggSplit -
+ *       splitting (partial aggregation) modes for Agg plan nodes
+ *
+ * This is needed in both plannodes.h and relation.h, so put it here...
+ */
+
+/* Primitive options supported by nodeAgg.c: */
+#define AGGSPLITOP_COMBINE             0x01    /* substitute combinefn for transfn */
+#define AGGSPLITOP_SKIPFINAL   0x02    /* skip finalfn, return state as-is */
+#define AGGSPLITOP_SERIALIZE   0x04    /* apply serializefn to output */
+#define AGGSPLITOP_DESERIALIZE 0x08    /* apply deserializefn to input */
+
+/* Supported operating modes (i.e., useful combinations of these options): */
+typedef enum AggSplit
+{
+       /* Basic, non-split aggregation: */
+       AGGSPLIT_SIMPLE = 0,
+       /* Initial phase of partial aggregation, with serialization: */
+       AGGSPLIT_INITIAL_SERIAL = AGGSPLITOP_SKIPFINAL | AGGSPLITOP_SERIALIZE,
+       /* Final phase of partial aggregation, with deserialization: */
+       AGGSPLIT_FINAL_DESERIAL = AGGSPLITOP_COMBINE | AGGSPLITOP_DESERIALIZE
+} AggSplit;
+
+/* Test whether an AggSplit value selects each primitive option: */
+#define DO_AGGSPLIT_COMBINE(as)                (((as) & AGGSPLITOP_COMBINE) != 0)
+#define DO_AGGSPLIT_SKIPFINAL(as)      (((as) & AGGSPLITOP_SKIPFINAL) != 0)
+#define DO_AGGSPLIT_SERIALIZE(as)      (((as) & AGGSPLITOP_SERIALIZE) != 0)
+#define DO_AGGSPLIT_DESERIALIZE(as) (((as) & AGGSPLITOP_DESERIALIZE) != 0)
+
 /*
  * SetOpCmd and SetOpStrategy -
  *       overall semantics and execution strategies for SetOp plan nodes
index 72f53fd03493e92a95d44efc90a0a6595e5efaad..b375870e19998b07ef102fe8e0c38f1a1b41194c 100644 (file)
@@ -711,9 +711,7 @@ typedef struct Agg
 {
        Plan            plan;
        AggStrategy aggstrategy;        /* basic strategy, see nodes.h */
-       bool            combineStates;  /* input tuples contain transition states */
-       bool            finalizeAggs;   /* should we call the finalfn on agg states? */
-       bool            serialStates;   /* should agg states be (de)serialized? */
+       AggSplit        aggsplit;               /* agg-splitting mode, see nodes.h */
        int                     numCols;                /* number of grouping columns */
        AttrNumber *grpColIdx;          /* their indexes in the target list */
        Oid                *grpOperators;       /* equality operators to compare with */
index 3de11f020ff83cb07e36ae27a80f5e93f3c13a15..057cc2ca85e969c671a22195352f722a904219ed 100644 (file)
@@ -266,22 +266,18 @@ typedef struct Param
  * replaced with a single argument representing the partial-aggregate
  * transition values.
  *
- * XXX need more documentation about partial aggregation here
- *
- * 'aggtype' and 'aggoutputtype' are the same except when we're performing
- * partal aggregation; in that case, we output transition states.  Nothing
- * interesting happens in the Aggref itself, but we must set the output data
- * type to whatever type is used for transition values.
- *
- * Note: If you are adding fields here you may also need to add a comparison
- * in search_indexed_tlist_for_partial_aggref()
+ * aggsplit indicates the expected partial-aggregation mode for the Aggref's
+ * parent plan node.  It's always set to AGGSPLIT_SIMPLE in the parser, but
+ * the planner might change it to something else.  We use this mainly as
+ * a crosscheck that the Aggrefs match the plan; but note that when aggsplit
+ * indicates a non-final mode, aggtype reflects the transition data type
+ * not the SQL-level output type of the aggregate.
  */
 typedef struct Aggref
 {
        Expr            xpr;
        Oid                     aggfnoid;               /* pg_proc Oid of the aggregate */
-       Oid                     aggtype;                /* type Oid of final result of the aggregate */
-       Oid                     aggoutputtype;  /* type Oid of result of this aggregate */
+       Oid                     aggtype;                /* type Oid of result of the aggregate */
        Oid                     aggcollid;              /* OID of collation of result */
        Oid                     inputcollid;    /* OID of collation that function should use */
        Oid                     aggtranstype;   /* type Oid of aggregate's transition value */
@@ -294,10 +290,9 @@ typedef struct Aggref
        bool            aggstar;                /* TRUE if argument list was really '*' */
        bool            aggvariadic;    /* true if variadic arguments have been
                                                                 * combined into an array last argument */
-       bool            aggcombine;             /* combining agg; input is a transvalue */
-       bool            aggpartial;             /* partial agg; output is a transvalue */
        char            aggkind;                /* aggregate kind (see pg_aggregate.h) */
        Index           agglevelsup;    /* > 0 if agg belongs to outer query */
+       AggSplit        aggsplit;               /* expected agg-splitting mode of parent Agg */
        int                     location;               /* token location, or -1 if unknown */
 } Aggref;
 
index 9470df626cc86c45417951c138b104e3930e8f74..b5f96839755896a3a1cef14808843476df9c65eb 100644 (file)
@@ -1347,12 +1347,10 @@ typedef struct AggPath
        Path            path;
        Path       *subpath;            /* path representing input source */
        AggStrategy aggstrategy;        /* basic strategy, see nodes.h */
+       AggSplit        aggsplit;               /* agg-splitting mode, see nodes.h */
        double          numGroups;              /* estimated number of groups in input */
        List       *groupClause;        /* a list of SortGroupClause's */
        List       *qual;                       /* quals (HAVING quals), if any */
-       bool            combineStates;  /* input is partially aggregated agg states */
-       bool            finalizeAggs;   /* should the executor call the finalfn? */
-       bool            serialStates;   /* should agg states be (de)serialized? */
 } AggPath;
 
 /*
index 53cf726c0b5198aab47f627a1d5d229b12d246ae..526126df6fc8cf67a78975c92a250e8582ab8b5c 100644 (file)
@@ -67,9 +67,8 @@ extern List *make_ands_implicit(Expr *clause);
 
 extern PartialAggType aggregates_allow_partial(Node *clause);
 extern bool contain_agg_clause(Node *clause);
-extern void count_agg_clauses(PlannerInfo *root, Node *clause,
-                                 AggClauseCosts *costs, bool finalizeAggs,
-                                 bool combineStates, bool serialStates);
+extern void get_agg_clause_costs(PlannerInfo *root, Node *clause,
+                                        AggSplit aggsplit, AggClauseCosts *costs);
 
 extern bool contain_window_function(Node *clause);
 extern WindowFuncLists *find_window_functions(Node *clause, Index maxWinRef);
index 5de4c34a2b73c2fa26fd3541f8592ff1d66ac7f4..71d9154a5cfdbcfc518a3e099634682cf300bccf 100644 (file)
@@ -166,13 +166,11 @@ extern AggPath *create_agg_path(PlannerInfo *root,
                                Path *subpath,
                                PathTarget *target,
                                AggStrategy aggstrategy,
+                               AggSplit aggsplit,
                                List *groupClause,
                                List *qual,
                                const AggClauseCosts *aggcosts,
-                               double numGroups,
-                               bool combineStates,
-                               bool finalizeAggs,
-                               bool serialStates);
+                               double numGroups);
 extern GroupingSetsPath *create_groupingsets_path(PlannerInfo *root,
                                                 RelOptInfo *rel,
                                                 Path *subpath,
index c529085eef2cf09836ad27897596228feb7a2369..4fbb6cc3e7e41af3e6d25786e3fa4b23f5701ab1 100644 (file)
@@ -58,8 +58,8 @@ extern bool is_projection_capable_plan(Plan *plan);
 
 /* External use of these functions is deprecated: */
 extern Sort *make_sort_from_sortclauses(List *sortcls, Plan *lefttree);
-extern Agg *make_agg(List *tlist, List *qual, AggStrategy aggstrategy,
-                bool combineStates, bool finalizeAggs, bool serialStates,
+extern Agg *make_agg(List *tlist, List *qual,
+                AggStrategy aggstrategy, AggSplit aggsplit,
                 int numGroupCols, AttrNumber *grpColIdx, Oid *grpOperators,
                 List *groupingSets, List *chain,
                 double dNumGroups, Plan *lefttree);
index 0d209766359797992f59e04df5e8a725176ad7f8..d9790d7a970bdf7bacf7299e3c02a3ee0a361e27 100644 (file)
@@ -46,7 +46,7 @@ extern bool is_dummy_plan(Plan *plan);
 extern RowMarkType select_rowmark_type(RangeTblEntry *rte,
                                        LockClauseStrength strength);
 
-extern void mark_partial_aggref(Aggref *agg, bool serialize);
+extern void mark_partial_aggref(Aggref *agg, AggSplit aggsplit);
 
 extern Path *get_cheapest_fractional_path(RelOptInfo *rel,
                                                         double tuple_fraction);