Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions

nodeAgg.h File Reference

#include "nodes/execnodes.h"
Include dependency graph for nodeAgg.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

AggStateExecInitAgg (Agg *node, EState *estate, int eflags)
TupleTableSlotExecAgg (AggState *node)
void ExecEndAgg (AggState *node)
void ExecReScanAgg (AggState *node)
Size hash_agg_entry_size (int numAggs)
Datum aggregate_dummy (PG_FUNCTION_ARGS)

Function Documentation

Datum aggregate_dummy ( PG_FUNCTION_ARGS   ) 

Definition at line 2046 of file nodeAgg.c.

References elog, and ERROR.

{
    elog(ERROR, "aggregate function %u called as normal function",
         fcinfo->flinfo->fn_oid);
    return (Datum) 0;           /* keep compiler quiet */
}

TupleTableSlot* ExecAgg ( AggState node  ) 

Definition at line 978 of file nodeAgg.c.

References AggState::agg_done, agg_fill_hash_table(), AGG_HASHED, agg_retrieve_direct(), agg_retrieve_hash_table(), ExecProject(), ExprMultipleResult, PlanState::plan, ScanState::ps, PlanState::ps_ProjInfo, PlanState::ps_TupFromTlist, AggState::ss, and AggState::table_filled.

Referenced by ExecProcNode().

{
    /*
     * Check to see if we're still projecting out tuples from a previous agg
     * tuple (because there is a function-returning-set in the projection
     * expressions).  If so, try to project another one.
     */
    if (node->ss.ps.ps_TupFromTlist)
    {
        TupleTableSlot *result;
        ExprDoneCond isDone;

        result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
        if (isDone == ExprMultipleResult)
            return result;
        /* Done with that source tuple... */
        node->ss.ps.ps_TupFromTlist = false;
    }

    /*
     * Exit if nothing left to do.  (We must do the ps_TupFromTlist check
     * first, because in some cases agg_done gets set before we emit the final
     * aggregate tuple, and we have to finish running SRFs for it.)
     */
    if (node->agg_done)
        return NULL;

    /* Dispatch based on strategy */
    if (((Agg *) node->ss.ps.plan)->aggstrategy == AGG_HASHED)
    {
        if (!node->table_filled)
            agg_fill_hash_table(node);
        return agg_retrieve_hash_table(node);
    }
    else
        return agg_retrieve_direct(node);
}

void ExecEndAgg ( AggState node  ) 

Definition at line 1883 of file nodeAgg.c.

References AggState::aggcontext, ExecClearTuple(), ExecEndNode(), ExecFreeExprContext(), MemoryContextDelete(), AggState::numaggs, outerPlanState, AggState::peragg, ScanState::ps, PlanState::ps_ExprContext, AggStatePerAggData::sortstate, AggState::ss, ScanState::ss_ScanTupleSlot, AggState::tmpcontext, and tuplesort_end().

Referenced by ExecEndNode().

{
    PlanState  *outerPlan;
    int         aggno;

    /* Make sure we have closed any open tuplesorts */
    for (aggno = 0; aggno < node->numaggs; aggno++)
    {
        AggStatePerAgg peraggstate = &node->peragg[aggno];

        if (peraggstate->sortstate)
            tuplesort_end(peraggstate->sortstate);
    }

    /*
     * Free both the expr contexts.
     */
    ExecFreeExprContext(&node->ss.ps);
    node->ss.ps.ps_ExprContext = node->tmpcontext;
    ExecFreeExprContext(&node->ss.ps);

    /* clean up tuple table */
    ExecClearTuple(node->ss.ss_ScanTupleSlot);

    MemoryContextDelete(node->aggcontext);

    outerPlan = outerPlanState(node);
    ExecEndNode(outerPlan);
}

AggState* ExecInitAgg ( Agg node,
EState estate,
int  eflags 
)

Definition at line 1377 of file nodeAgg.c.

References ACL_EXECUTE, ACL_KIND_PROC, aclcheck_error(), ACLCHECK_OK, AggState::agg_done, AGG_HASHED, AggState::aggcontext, Aggref::aggdistinct, Aggref::aggfnoid, AGGFNOID, Aggref::agglevelsup, AggrefExprState::aggno, Aggref::aggorder, AggState::aggs, Agg::aggstrategy, Aggref::aggtype, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), Anum_pg_aggregate_agginitval, AggrefExprState::args, Aggref::args, Assert, build_aggregate_fnexprs(), build_hash_table(), contain_volatile_functions(), CurrentMemoryContext, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, elog, enforce_generic_type_consistency(), AggState::eqfunctions, SortGroupClause::eqop, equal(), ereport, errcode(), errmsg(), ERROR, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecAssignResultTypeFromTL(), ExecAssignScanTypeFromOuterPlan(), ExecBuildProjectionInfo(), ExecInitExpr(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitResultTupleSlot(), ExecInitScanTupleSlot(), ExecSetSlotDescriptor(), execTuplesHashPrepare(), execTuplesMatchPrepare(), ExecTypeFromTL(), TargetEntry::expr, ExprState::expr, exprCollation(), exprType(), find_hash_columns(), fmgr_info(), fmgr_info_set_expr, FUNC_MAX_ARGS, get_func_name(), get_func_signature(), get_opcode(), get_sortgroupclause_tle(), get_typlenbyval(), GetAggInitVal(), GETSTRUCT, GetUserId(), AggState::grp_firstTuple, Agg::grpOperators, AggState::hash_needed, AggState::hashfunctions, AggState::hashslot, AggState::hashtable, HeapTupleIsValid, i, Aggref::inputcollid, InvokeFunctionExecuteHook, IsBinaryCoercible(), IsPolymorphicType, lfirst, list_length(), makeNode, NULL, SortGroupClause::nulls_first, AggState::numaggs, Agg::numCols, ObjectIdGetDatum, OidIsValid, outerPlan, outerPlanState, palloc(), palloc0(), AggState::peragg, AggState::pergroup, pfree(), pg_proc_aclcheck(), Agg::plan, PlanState::plan, PROCOID, ScanState::ps, PlanState::ps_ExprContext, PlanState::ps_TupFromTlist, Plan::qual, PlanState::qual, ReleaseSysCache(), TargetEntry::resjunk, TargetEntry::resno, SearchSysCache1, SortGroupClause::sortop, AggState::ss, PlanState::state, SysCacheGetAttr(), AggState::table_filled, Plan::targetlist, PlanState::targetlist, AggState::tmpcontext, and AggrefExprState::xprstate.

Referenced by ExecInitNode().

{
    AggState   *aggstate;
    AggStatePerAgg peragg;
    Plan       *outerPlan;
    ExprContext *econtext;
    int         numaggs,
                aggno;
    ListCell   *l;

    /* check for unsupported flags */
    Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));

    /*
     * create state structure
     */
    aggstate = makeNode(AggState);
    aggstate->ss.ps.plan = (Plan *) node;
    aggstate->ss.ps.state = estate;

    aggstate->aggs = NIL;
    aggstate->numaggs = 0;
    aggstate->eqfunctions = NULL;
    aggstate->hashfunctions = NULL;
    aggstate->peragg = NULL;
    aggstate->agg_done = false;
    aggstate->pergroup = NULL;
    aggstate->grp_firstTuple = NULL;
    aggstate->hashtable = NULL;

    /*
     * Create expression contexts.  We need two, one for per-input-tuple
     * processing and one for per-output-tuple processing.  We cheat a little
     * by using ExecAssignExprContext() to build both.
     */
    ExecAssignExprContext(estate, &aggstate->ss.ps);
    aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
    ExecAssignExprContext(estate, &aggstate->ss.ps);

    /*
     * We also need a long-lived memory context for holding hashtable data
     * structures and transition values.  NOTE: the details of what is stored
     * in aggcontext and what is stored in the regular per-query memory
     * context are driven by a simple decision: we want to reset the
     * aggcontext at group boundaries (if not hashing) and in ExecReScanAgg to
     * recover no-longer-wanted space.
     */
    aggstate->aggcontext =
        AllocSetContextCreate(CurrentMemoryContext,
                              "AggContext",
                              ALLOCSET_DEFAULT_MINSIZE,
                              ALLOCSET_DEFAULT_INITSIZE,
                              ALLOCSET_DEFAULT_MAXSIZE);

    /*
     * tuple table initialization
     */
    ExecInitScanTupleSlot(estate, &aggstate->ss);
    ExecInitResultTupleSlot(estate, &aggstate->ss.ps);
    aggstate->hashslot = ExecInitExtraTupleSlot(estate);

    /*
     * initialize child expressions
     *
     * Note: ExecInitExpr finds Aggrefs for us, and also checks that no aggs
     * contain other agg calls in their arguments.  This would make no sense
     * under SQL semantics anyway (and it's forbidden by the spec). Because
     * that is true, we don't need to worry about evaluating the aggs in any
     * particular order.
     */
    aggstate->ss.ps.targetlist = (List *)
        ExecInitExpr((Expr *) node->plan.targetlist,
                     (PlanState *) aggstate);
    aggstate->ss.ps.qual = (List *)
        ExecInitExpr((Expr *) node->plan.qual,
                     (PlanState *) aggstate);

    /*
     * initialize child nodes
     *
     * If we are doing a hashed aggregation then the child plan does not need
     * to handle REWIND efficiently; see ExecReScanAgg.
     */
    if (node->aggstrategy == AGG_HASHED)
        eflags &= ~EXEC_FLAG_REWIND;
    outerPlan = outerPlan(node);
    outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags);

    /*
     * initialize source tuple type.
     */
    ExecAssignScanTypeFromOuterPlan(&aggstate->ss);

    /*
     * Initialize result tuple type and projection info.
     */
    ExecAssignResultTypeFromTL(&aggstate->ss.ps);
    ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);

    aggstate->ss.ps.ps_TupFromTlist = false;

    /*
     * get the count of aggregates in targetlist and quals
     */
    numaggs = aggstate->numaggs;
    Assert(numaggs == list_length(aggstate->aggs));
    if (numaggs <= 0)
    {
        /*
         * This is not an error condition: we might be using the Agg node just
         * to do hash-based grouping.  Even in the regular case,
         * constant-expression simplification could optimize away all of the
         * Aggrefs in the targetlist and qual.  So keep going, but force local
         * copy of numaggs positive so that palloc()s below don't choke.
         */
        numaggs = 1;
    }

    /*
     * If we are grouping, precompute fmgr lookup data for inner loop. We need
     * both equality and hashing functions to do it by hashing, but only
     * equality if not hashing.
     */
    if (node->numCols > 0)
    {
        if (node->aggstrategy == AGG_HASHED)
            execTuplesHashPrepare(node->numCols,
                                  node->grpOperators,
                                  &aggstate->eqfunctions,
                                  &aggstate->hashfunctions);
        else
            aggstate->eqfunctions =
                execTuplesMatchPrepare(node->numCols,
                                       node->grpOperators);
    }

    /*
     * Set up aggregate-result storage in the output expr context, and also
     * allocate my private per-agg working storage
     */
    econtext = aggstate->ss.ps.ps_ExprContext;
    econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
    econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numaggs);

    peragg = (AggStatePerAgg) palloc0(sizeof(AggStatePerAggData) * numaggs);
    aggstate->peragg = peragg;

    if (node->aggstrategy == AGG_HASHED)
    {
        build_hash_table(aggstate);
        aggstate->table_filled = false;
        /* Compute the columns we actually need to hash on */
        aggstate->hash_needed = find_hash_columns(aggstate);
    }
    else
    {
        AggStatePerGroup pergroup;

        pergroup = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData) * numaggs);
        aggstate->pergroup = pergroup;
    }

    /*
     * Perform lookups of aggregate function info, and initialize the
     * unchanging fields of the per-agg data.  We also detect duplicate
     * aggregates (for example, "SELECT sum(x) ... HAVING sum(x) > 0"). When
     * duplicates are detected, we only make an AggStatePerAgg struct for the
     * first one.  The clones are simply pointed at the same result entry by
     * giving them duplicate aggno values.
     */
    aggno = -1;
    foreach(l, aggstate->aggs)
    {
        AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(l);
        Aggref     *aggref = (Aggref *) aggrefstate->xprstate.expr;
        AggStatePerAgg peraggstate;
        Oid         inputTypes[FUNC_MAX_ARGS];
        int         numArguments;
        int         numInputs;
        int         numSortCols;
        int         numDistinctCols;
        List       *sortlist;
        HeapTuple   aggTuple;
        Form_pg_aggregate aggform;
        Oid         aggtranstype;
        AclResult   aclresult;
        Oid         transfn_oid,
                    finalfn_oid;
        Expr       *transfnexpr,
                   *finalfnexpr;
        Datum       textInitVal;
        int         i;
        ListCell   *lc;

        /* Planner should have assigned aggregate to correct level */
        Assert(aggref->agglevelsup == 0);

        /* Look for a previous duplicate aggregate */
        for (i = 0; i <= aggno; i++)
        {
            if (equal(aggref, peragg[i].aggref) &&
                !contain_volatile_functions((Node *) aggref))
                break;
        }
        if (i <= aggno)
        {
            /* Found a match to an existing entry, so just mark it */
            aggrefstate->aggno = i;
            continue;
        }

        /* Nope, so assign a new PerAgg record */
        peraggstate = &peragg[++aggno];

        /* Mark Aggref state node with assigned index in the result array */
        aggrefstate->aggno = aggno;

        /* Fill in the peraggstate data */
        peraggstate->aggrefstate = aggrefstate;
        peraggstate->aggref = aggref;
        numInputs = list_length(aggref->args);
        peraggstate->numInputs = numInputs;
        peraggstate->sortstate = NULL;

        /*
         * Get actual datatypes of the inputs.  These could be different from
         * the agg's declared input types, when the agg accepts ANY or a
         * polymorphic type.
         */
        numArguments = 0;
        foreach(lc, aggref->args)
        {
            TargetEntry *tle = (TargetEntry *) lfirst(lc);

            if (!tle->resjunk)
                inputTypes[numArguments++] = exprType((Node *) tle->expr);
        }
        peraggstate->numArguments = numArguments;

        aggTuple = SearchSysCache1(AGGFNOID,
                                   ObjectIdGetDatum(aggref->aggfnoid));
        if (!HeapTupleIsValid(aggTuple))
            elog(ERROR, "cache lookup failed for aggregate %u",
                 aggref->aggfnoid);
        aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);

        /* Check permission to call aggregate function */
        aclresult = pg_proc_aclcheck(aggref->aggfnoid, GetUserId(),
                                     ACL_EXECUTE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error(aclresult, ACL_KIND_PROC,
                           get_func_name(aggref->aggfnoid));
        InvokeFunctionExecuteHook(aggref->aggfnoid);

        peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
        peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;

        /* Check that aggregate owner has permission to call component fns */
        {
            HeapTuple   procTuple;
            Oid         aggOwner;

            procTuple = SearchSysCache1(PROCOID,
                                        ObjectIdGetDatum(aggref->aggfnoid));
            if (!HeapTupleIsValid(procTuple))
                elog(ERROR, "cache lookup failed for function %u",
                     aggref->aggfnoid);
            aggOwner = ((Form_pg_proc) GETSTRUCT(procTuple))->proowner;
            ReleaseSysCache(procTuple);

            aclresult = pg_proc_aclcheck(transfn_oid, aggOwner,
                                         ACL_EXECUTE);
            if (aclresult != ACLCHECK_OK)
                aclcheck_error(aclresult, ACL_KIND_PROC,
                               get_func_name(transfn_oid));
            InvokeFunctionExecuteHook(transfn_oid);
            if (OidIsValid(finalfn_oid))
            {
                aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
                                             ACL_EXECUTE);
                if (aclresult != ACLCHECK_OK)
                    aclcheck_error(aclresult, ACL_KIND_PROC,
                                   get_func_name(finalfn_oid));
                InvokeFunctionExecuteHook(finalfn_oid);
            }
        }

        /* resolve actual type of transition state, if polymorphic */
        aggtranstype = aggform->aggtranstype;
        if (IsPolymorphicType(aggtranstype))
        {
            /* have to fetch the agg's declared input types... */
            Oid        *declaredArgTypes;
            int         agg_nargs;

            (void) get_func_signature(aggref->aggfnoid,
                                      &declaredArgTypes, &agg_nargs);
            Assert(agg_nargs == numArguments);
            aggtranstype = enforce_generic_type_consistency(inputTypes,
                                                            declaredArgTypes,
                                                            agg_nargs,
                                                            aggtranstype,
                                                            false);
            pfree(declaredArgTypes);
        }

        /* build expression trees using actual argument & result types */
        build_aggregate_fnexprs(inputTypes,
                                numArguments,
                                aggtranstype,
                                aggref->aggtype,
                                aggref->inputcollid,
                                transfn_oid,
                                finalfn_oid,
                                &transfnexpr,
                                &finalfnexpr);

        fmgr_info(transfn_oid, &peraggstate->transfn);
        fmgr_info_set_expr((Node *) transfnexpr, &peraggstate->transfn);

        if (OidIsValid(finalfn_oid))
        {
            fmgr_info(finalfn_oid, &peraggstate->finalfn);
            fmgr_info_set_expr((Node *) finalfnexpr, &peraggstate->finalfn);
        }

        peraggstate->aggCollation = aggref->inputcollid;

        get_typlenbyval(aggref->aggtype,
                        &peraggstate->resulttypeLen,
                        &peraggstate->resulttypeByVal);
        get_typlenbyval(aggtranstype,
                        &peraggstate->transtypeLen,
                        &peraggstate->transtypeByVal);

        /*
         * initval is potentially null, so don't try to access it as a struct
         * field. Must do it the hard way with SysCacheGetAttr.
         */
        textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
                                      Anum_pg_aggregate_agginitval,
                                      &peraggstate->initValueIsNull);

        if (peraggstate->initValueIsNull)
            peraggstate->initValue = (Datum) 0;
        else
            peraggstate->initValue = GetAggInitVal(textInitVal,
                                                   aggtranstype);

        /*
         * If the transfn is strict and the initval is NULL, make sure input
         * type and transtype are the same (or at least binary-compatible), so
         * that it's OK to use the first input value as the initial
         * transValue.  This should have been checked at agg definition time,
         * but just in case...
         */
        if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull)
        {
            if (numArguments < 1 ||
                !IsBinaryCoercible(inputTypes[0], aggtranstype))
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                         errmsg("aggregate %u needs to have compatible input type and transition type",
                                aggref->aggfnoid)));
        }

        /*
         * Get a tupledesc corresponding to the inputs (including sort
         * expressions) of the agg.
         */
        peraggstate->evaldesc = ExecTypeFromTL(aggref->args, false);

        /* Create slot we're going to do argument evaluation in */
        peraggstate->evalslot = ExecInitExtraTupleSlot(estate);
        ExecSetSlotDescriptor(peraggstate->evalslot, peraggstate->evaldesc);

        /* Set up projection info for evaluation */
        peraggstate->evalproj = ExecBuildProjectionInfo(aggrefstate->args,
                                                        aggstate->tmpcontext,
                                                        peraggstate->evalslot,
                                                        NULL);

        /*
         * If we're doing either DISTINCT or ORDER BY, then we have a list of
         * SortGroupClause nodes; fish out the data in them and stick them
         * into arrays.
         *
         * Note that by construction, if there is a DISTINCT clause then the
         * ORDER BY clause is a prefix of it (see transformDistinctClause).
         */
        if (aggref->aggdistinct)
        {
            sortlist = aggref->aggdistinct;
            numSortCols = numDistinctCols = list_length(sortlist);
            Assert(numSortCols >= list_length(aggref->aggorder));
        }
        else
        {
            sortlist = aggref->aggorder;
            numSortCols = list_length(sortlist);
            numDistinctCols = 0;
        }

        peraggstate->numSortCols = numSortCols;
        peraggstate->numDistinctCols = numDistinctCols;

        if (numSortCols > 0)
        {
            /*
             * We don't implement DISTINCT or ORDER BY aggs in the HASHED case
             * (yet)
             */
            Assert(node->aggstrategy != AGG_HASHED);

            /* If we have only one input, we need its len/byval info. */
            if (numInputs == 1)
            {
                get_typlenbyval(inputTypes[0],
                                &peraggstate->inputtypeLen,
                                &peraggstate->inputtypeByVal);
            }
            else if (numDistinctCols > 0)
            {
                /* we will need an extra slot to store prior values */
                peraggstate->uniqslot = ExecInitExtraTupleSlot(estate);
                ExecSetSlotDescriptor(peraggstate->uniqslot,
                                      peraggstate->evaldesc);
            }

            /* Extract the sort information for use later */
            peraggstate->sortColIdx =
                (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
            peraggstate->sortOperators =
                (Oid *) palloc(numSortCols * sizeof(Oid));
            peraggstate->sortCollations =
                (Oid *) palloc(numSortCols * sizeof(Oid));
            peraggstate->sortNullsFirst =
                (bool *) palloc(numSortCols * sizeof(bool));

            i = 0;
            foreach(lc, sortlist)
            {
                SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
                TargetEntry *tle = get_sortgroupclause_tle(sortcl,
                                                           aggref->args);

                /* the parser should have made sure of this */
                Assert(OidIsValid(sortcl->sortop));

                peraggstate->sortColIdx[i] = tle->resno;
                peraggstate->sortOperators[i] = sortcl->sortop;
                peraggstate->sortCollations[i] = exprCollation((Node *) tle->expr);
                peraggstate->sortNullsFirst[i] = sortcl->nulls_first;
                i++;
            }
            Assert(i == numSortCols);
        }

        if (aggref->aggdistinct)
        {
            Assert(numArguments > 0);

            /*
             * We need the equal function for each DISTINCT comparison we will
             * make.
             */
            peraggstate->equalfns =
                (FmgrInfo *) palloc(numDistinctCols * sizeof(FmgrInfo));

            i = 0;
            foreach(lc, aggref->aggdistinct)
            {
                SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);

                fmgr_info(get_opcode(sortcl->eqop), &peraggstate->equalfns[i]);
                i++;
            }
            Assert(i == numDistinctCols);
        }

        ReleaseSysCache(aggTuple);
    }

    /* Update numaggs to match number of unique aggregates found */
    aggstate->numaggs = aggno + 1;

    return aggstate;
}

void ExecReScanAgg ( AggState node  ) 

Definition at line 1914 of file nodeAgg.c.

References AggState::agg_done, AGG_HASHED, AggState::aggcontext, build_hash_table(), PlanState::chgParam, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExecReScan(), AggState::grp_firstTuple, AggState::hashiter, AggState::hashtable, heap_freetuple(), PlanState::lefttree, MemoryContextResetAndDeleteChildren(), MemSet, NULL, AggState::numaggs, AggState::peragg, AggState::pergroup, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, PlanState::ps_TupFromTlist, ResetTupleHashIterator, AggStatePerAggData::sortstate, AggState::ss, AggState::table_filled, and tuplesort_end().

Referenced by ExecReScan().

{
    ExprContext *econtext = node->ss.ps.ps_ExprContext;
    int         aggno;

    node->agg_done = false;

    node->ss.ps.ps_TupFromTlist = false;

    if (((Agg *) node->ss.ps.plan)->aggstrategy == AGG_HASHED)
    {
        /*
         * In the hashed case, if we haven't yet built the hash table then we
         * can just return; nothing done yet, so nothing to undo. If subnode's
         * chgParam is not NULL then it will be re-scanned by ExecProcNode,
         * else no reason to re-scan it at all.
         */
        if (!node->table_filled)
            return;

        /*
         * If we do have the hash table and the subplan does not have any
         * parameter changes, then we can just rescan the existing hash table;
         * no need to build it again.
         */
        if (node->ss.ps.lefttree->chgParam == NULL)
        {
            ResetTupleHashIterator(node->hashtable, &node->hashiter);
            return;
        }
    }

    /* Make sure we have closed any open tuplesorts */
    for (aggno = 0; aggno < node->numaggs; aggno++)
    {
        AggStatePerAgg peraggstate = &node->peragg[aggno];

        if (peraggstate->sortstate)
            tuplesort_end(peraggstate->sortstate);
        peraggstate->sortstate = NULL;
    }

    /* Release first tuple of group, if we have made a copy */
    if (node->grp_firstTuple != NULL)
    {
        heap_freetuple(node->grp_firstTuple);
        node->grp_firstTuple = NULL;
    }

    /* Forget current agg values */
    MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
    MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);

    /*
     * Release all temp storage. Note that with AGG_HASHED, the hash table is
     * allocated in a sub-context of the aggcontext. We're going to rebuild
     * the hash table from scratch, so we need to use
     * MemoryContextResetAndDeleteChildren() to avoid leaking the old hash
     * table's memory context header.
     */
    MemoryContextResetAndDeleteChildren(node->aggcontext);

    if (((Agg *) node->ss.ps.plan)->aggstrategy == AGG_HASHED)
    {
        /* Rebuild an empty hash table */
        build_hash_table(node);
        node->table_filled = false;
    }
    else
    {
        /*
         * Reset the per-group state (in particular, mark transvalues null)
         */
        MemSet(node->pergroup, 0,
               sizeof(AggStatePerGroupData) * node->numaggs);
    }

    /*
     * if chgParam of subnode is not null then plan will be re-scanned by
     * first ExecProcNode.
     */
    if (node->ss.ps.lefttree->chgParam == NULL)
        ExecReScan(node->ss.ps.lefttree);
}

Size hash_agg_entry_size ( int  numAggs  ) 

Definition at line 905 of file nodeAgg.c.

References MAXALIGN.

Referenced by choose_hashed_grouping().

{
    Size        entrysize;

    /* This must match build_hash_table */
    entrysize = sizeof(AggHashEntryData) +
        (numAggs - 1) * sizeof(AggStatePerGroupData);
    entrysize = MAXALIGN(entrysize);
    /* Account for hashtable overhead (assuming fill factor = 1) */
    entrysize += 3 * sizeof(void *);
    return entrysize;
}