PostgreSQL Source Code  git master
nodeAgg.h File Reference
#include "access/parallel.h"
#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.

Data Structures

struct  AggStatePerTransData
 
struct  AggStatePerAggData
 
struct  AggStatePerGroupData
 
struct  AggStatePerPhaseData
 
struct  AggStatePerHashData
 

Macros

#define FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUE   0
 
#define FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUEISNULL   1
 
#define FIELDNO_AGGSTATEPERGROUPDATA_NOTRANSVALUE   2
 

Typedefs

typedef struct AggStatePerTransData AggStatePerTransData
 
typedef struct AggStatePerAggData AggStatePerAggData
 
typedef struct AggStatePerGroupData AggStatePerGroupData
 
typedef struct AggStatePerPhaseData AggStatePerPhaseData
 
typedef struct AggStatePerHashData AggStatePerHashData
 

Functions

AggStateExecInitAgg (Agg *node, EState *estate, int eflags)
 
void ExecEndAgg (AggState *node)
 
void ExecReScanAgg (AggState *node)
 
Size hash_agg_entry_size (int numTrans, Size tupleWidth, Size transitionSpace)
 
void hash_agg_set_limits (double hashentrysize, double input_groups, int used_bits, Size *mem_limit, uint64 *ngroups_limit, int *num_partitions)
 
void ExecAggEstimate (AggState *node, ParallelContext *pcxt)
 
void ExecAggInitializeDSM (AggState *node, ParallelContext *pcxt)
 
void ExecAggInitializeWorker (AggState *node, ParallelWorkerContext *pwcxt)
 
void ExecAggRetrieveInstrumentation (AggState *node)
 

Macro Definition Documentation

◆ FIELDNO_AGGSTATEPERGROUPDATA_NOTRANSVALUE

#define FIELDNO_AGGSTATEPERGROUPDATA_NOTRANSVALUE   2

Definition at line 249 of file nodeAgg.h.

Referenced by llvm_compile_expr().

◆ FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUE

#define FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUE   0

Definition at line 244 of file nodeAgg.h.

Referenced by llvm_compile_expr().

◆ FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUEISNULL

#define FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUEISNULL   1

Definition at line 246 of file nodeAgg.h.

Referenced by llvm_compile_expr().

Typedef Documentation

◆ AggStatePerAggData

◆ AggStatePerGroupData

◆ AggStatePerHashData

◆ AggStatePerPhaseData

◆ AggStatePerTransData

Function Documentation

◆ ExecAggEstimate()

void ExecAggEstimate ( AggState node,
ParallelContext pcxt 
)

Definition at line 4756 of file nodeAgg.c.

References add_size(), ParallelContext::estimator, PlanState::instrument, mul_size(), ParallelContext::nworkers, offsetof, ScanState::ps, shm_toc_estimate_chunk, shm_toc_estimate_keys, and AggState::ss.

Referenced by ExecParallelEstimate().

4757 {
4758  Size size;
4759 
4760  /* don't need this if not instrumenting or no workers */
4761  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4762  return;
4763 
4764  size = mul_size(pcxt->nworkers, sizeof(AggregateInstrumentation));
4765  size = add_size(size, offsetof(SharedAggInfo, sinstrument));
4766  shm_toc_estimate_chunk(&pcxt->estimator, size);
4767  shm_toc_estimate_keys(&pcxt->estimator, 1);
4768 }
Instrumentation * instrument
Definition: execnodes.h:976
ScanState ss
Definition: execnodes.h:2276
shm_toc_estimator estimator
Definition: parallel.h:42
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
PlanState ps
Definition: execnodes.h:1377
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
size_t Size
Definition: c.h:540
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
#define offsetof(type, field)
Definition: c.h:727

◆ ExecAggInitializeDSM()

void ExecAggInitializeDSM ( AggState node,
ParallelContext pcxt 
)

Definition at line 4777 of file nodeAgg.c.

References PlanState::instrument, SharedAggInfo::num_workers, ParallelContext::nworkers, offsetof, PlanState::plan, Plan::plan_node_id, ScanState::ps, AggState::shared_info, shm_toc_allocate(), shm_toc_insert(), AggState::ss, and ParallelContext::toc.

Referenced by ExecParallelInitializeDSM().

4778 {
4779  Size size;
4780 
4781  /* don't need this if not instrumenting or no workers */
4782  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4783  return;
4784 
4785  size = offsetof(SharedAggInfo, sinstrument)
4786  + pcxt->nworkers * sizeof(AggregateInstrumentation);
4787  node->shared_info = shm_toc_allocate(pcxt->toc, size);
4788  /* ensure any unfilled slots will contain zeroes */
4789  memset(node->shared_info, 0, size);
4790  node->shared_info->num_workers = pcxt->nworkers;
4791  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
4792  node->shared_info);
4793 }
Instrumentation * instrument
Definition: execnodes.h:976
ScanState ss
Definition: execnodes.h:2276
int plan_node_id
Definition: plannodes.h:140
PlanState ps
Definition: execnodes.h:1377
struct AggregateInstrumentation AggregateInstrumentation
Plan * plan
Definition: execnodes.h:966
size_t Size
Definition: c.h:540
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
SharedAggInfo * shared_info
Definition: execnodes.h:2348
#define offsetof(type, field)
Definition: c.h:727
shm_toc * toc
Definition: parallel.h:45

◆ ExecAggInitializeWorker()

void ExecAggInitializeWorker ( AggState node,
ParallelWorkerContext pwcxt 
)

Definition at line 4802 of file nodeAgg.c.

References PlanState::plan, Plan::plan_node_id, ScanState::ps, AggState::shared_info, shm_toc_lookup(), AggState::ss, and ParallelWorkerContext::toc.

Referenced by ExecParallelInitializeWorker().

4803 {
4804  node->shared_info =
4805  shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
4806 }
ScanState ss
Definition: execnodes.h:2276
int plan_node_id
Definition: plannodes.h:140
PlanState ps
Definition: execnodes.h:1377
Plan * plan
Definition: execnodes.h:966
SharedAggInfo * shared_info
Definition: execnodes.h:2348
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

◆ ExecAggRetrieveInstrumentation()

void ExecAggRetrieveInstrumentation ( AggState node)

Definition at line 4815 of file nodeAgg.c.

References SharedAggInfo::num_workers, offsetof, palloc(), and AggState::shared_info.

Referenced by ExecParallelRetrieveInstrumentation().

4816 {
4817  Size size;
4818  SharedAggInfo *si;
4819 
4820  if (node->shared_info == NULL)
4821  return;
4822 
4823  size = offsetof(SharedAggInfo, sinstrument)
4825  si = palloc(size);
4826  memcpy(si, node->shared_info, size);
4827  node->shared_info = si;
4828 }
struct AggregateInstrumentation AggregateInstrumentation
size_t Size
Definition: c.h:540
void * palloc(Size size)
Definition: mcxt.c:1062
SharedAggInfo * shared_info
Definition: execnodes.h:2348
#define offsetof(type, field)
Definition: c.h:727

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

Definition at line 4367 of file nodeAgg.c.

References AggState::aggcontexts, Assert, ExecClearTuple(), ExecEndNode(), ExecFreeExprContext(), AggregateInstrumentation::hash_batches_used, AggState::hash_batches_used, AggregateInstrumentation::hash_disk_used, AggState::hash_disk_used, AggregateInstrumentation::hash_mem_peak, AggState::hash_mem_peak, AggState::hash_metacxt, hashagg_reset_spill_state(), AggState::hashcontext, IsParallelWorker, Max, AggState::maxsets, MemoryContextDelete(), AggState::numtrans, outerPlan, outerPlanState, ParallelWorkerNumber, AggState::pertrans, ScanState::ps, ReScanExprContext(), AggState::shared_info, SharedAggInfo::sinstrument, AggState::sort_in, AggState::sort_out, AggStatePerTransData::sortstates, AggState::ss, ScanState::ss_ScanTupleSlot, and tuplesort_end().

Referenced by ExecEndNode().

4368 {
4370  int transno;
4371  int numGroupingSets = Max(node->maxsets, 1);
4372  int setno;
4373 
4374  /*
4375  * When ending a parallel worker, copy the statistics gathered by the
4376  * worker back into shared memory so that it can be picked up by the main
4377  * process to report in EXPLAIN ANALYZE.
4378  */
4379  if (node->shared_info && IsParallelWorker())
4380  {
4382 
4383  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
4386  si->hash_disk_used = node->hash_disk_used;
4387  si->hash_mem_peak = node->hash_mem_peak;
4388  }
4389 
4390  /* Make sure we have closed any open tuplesorts */
4391 
4392  if (node->sort_in)
4393  tuplesort_end(node->sort_in);
4394  if (node->sort_out)
4395  tuplesort_end(node->sort_out);
4396 
4398 
4399  if (node->hash_metacxt != NULL)
4400  {
4402  node->hash_metacxt = NULL;
4403  }
4404 
4405  for (transno = 0; transno < node->numtrans; transno++)
4406  {
4407  AggStatePerTrans pertrans = &node->pertrans[transno];
4408 
4409  for (setno = 0; setno < numGroupingSets; setno++)
4410  {
4411  if (pertrans->sortstates[setno])
4412  tuplesort_end(pertrans->sortstates[setno]);
4413  }
4414  }
4415 
4416  /* And ensure any agg shutdown callbacks have been called */
4417  for (setno = 0; setno < numGroupingSets; setno++)
4418  ReScanExprContext(node->aggcontexts[setno]);
4419  if (node->hashcontext)
4421 
4422  /*
4423  * We don't actually free any ExprContexts here (see comment in
4424  * ExecFreeExprContext), just unlinking the output one from the plan node
4425  * suffices.
4426  */
4427  ExecFreeExprContext(&node->ss.ps);
4428 
4429  /* clean up tuple table */
4431 
4432  outerPlan = outerPlanState(node);
4433  ExecEndNode(outerPlan);
4434 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3199
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:556
Tuplesortstate * sort_out
Definition: execnodes.h:2309
ScanState ss
Definition: execnodes.h:2276
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1380
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2252
AggStatePerTrans pertrans
Definition: execnodes.h:2286
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:650
int numtrans
Definition: execnodes.h:2279
PlanState ps
Definition: execnodes.h:1377
int maxsets
Definition: execnodes.h:2306
MemoryContext hash_metacxt
Definition: execnodes.h:2318
Tuplesortstate * sort_in
Definition: execnodes.h:2308
#define outerPlanState(node)
Definition: execnodes.h:1062
Tuplesortstate ** sortstates
Definition: nodeAgg.h:154
int ParallelWorkerNumber
Definition: parallel.c:112
#define IsParallelWorker()
Definition: parallel.h:61
int hash_batches_used
Definition: execnodes.h:2337
#define outerPlan(node)
Definition: plannodes.h:171
ExprContext * hashcontext
Definition: execnodes.h:2287
uint64 hash_disk_used
Definition: execnodes.h:2336
#define Max(x, y)
Definition: c.h:980
ExprContext ** aggcontexts
Definition: execnodes.h:2288
#define Assert(condition)
Definition: c.h:804
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:438
Size hash_mem_peak
Definition: execnodes.h:2333
SharedAggInfo * shared_info
Definition: execnodes.h:2348
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1464

◆ ExecInitAgg()

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

Definition at line 3251 of file nodeAgg.c.

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, AggState::agg_done, AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, AggState::aggcontexts, AggStatePerAggData::aggdirectargs, Aggref::aggdirectargs, AGGFNOID, Aggref::aggfnoid, Aggref::aggkind, Aggref::agglevelsup, Aggref::aggno, AggStatePerPhaseData::aggnode, AggStatePerHashData::aggnode, AggStatePerTransData::aggref, AggStatePerAggData::aggref, AggState::aggs, AggStatePerTransData::aggshared, Aggref::aggsplit, Agg::aggsplit, AggState::aggsplit, AggStatePerPhaseData::aggstrategy, Agg::aggstrategy, AggState::aggstrategy, Aggref::aggtransno, Aggref::aggtranstype, Aggref::aggtype, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Aggref::args, Assert, bms_add_member(), bms_add_members(), bms_next_member(), build_aggregate_finalfn_expr(), build_hash_tables(), build_pertrans_for_aggref(), castNode, Agg::chain, CreateWorkExprContext(), AggState::curperagg, AggState::curpertrans, AggState::current_set, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_DESERIALIZE, DO_AGGSPLIT_SERIALIZE, DO_AGGSPLIT_SKIPFINAL, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, elog, AggStatePerPhaseData::eqfunctions, ereport, errcode(), errmsg(), ERROR, EState::es_query_cxt, AggStatePerPhaseData::evaltrans, AggStatePerPhaseData::evaltrans_cache, EXEC_FLAG_BACKWARD, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_MARK, EXEC_FLAG_REWIND, ExecAgg(), ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecBuildAggTrans(), ExecCreateScanSlotFromOuterPlan(), ExecGetResultSlotOps(), ExecInitExprList(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlotTL(), PlanState::ExecProcNode, execTuplesMatchPrepare(), AggStatePerAggData::finalfn, AggStatePerAggData::finalfn_oid, find_hash_columns(), fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_strict, format_type_be(), FUNC_MAX_ARGS, get_aggregate_argtypes(), get_func_name(), get_typlenbyval(), GetAggInitVal(), GETSTRUCT, GetUserId(), AggStatePerPhaseData::grouped_cols, Agg::groupingSets, AggState::grp_firstTuple, Agg::grpColIdx, Agg::grpCollations, Agg::grpOperators, AggStatePerPhaseData::gset_lengths, hash_agg_entry_size(), hash_agg_set_limits(), AggState::hashcontext, HeapTupleIsValid, i, initialize_phase(), initValue(), AggStatePerTransData::initValueIsNull, AggState::input_done, Aggref::inputcollid, InvalidOid, InvokeFunctionExecuteHook, IsBinaryCoercible(), lcons_int(), Plan::lefttree, lfirst, list_length(), list_nth_node, makeNode, Max, AggState::maxsets, NIL, AggState::numaggs, AggStatePerHashData::numCols, Agg::numCols, AggStatePerAggData::numFinalArgs, AggState::numphases, AggStatePerPhaseData::numsets, AggState::numtrans, AggStatePerTransData::numTransInputs, OBJECT_AGGREGATE, OBJECT_FUNCTION, ObjectIdGetDatum, OidIsValid, PlanState::outerops, PlanState::outeropsfixed, PlanState::outeropsset, outerPlan, outerPlanState, palloc(), palloc0(), AggState::peragg, AggState::pergroups, AggState::pertrans, pg_proc_aclcheck(), Agg::plan, PlanState::plan, Plan::plan_width, PROCOID, AggState::projected_set, ScanState::ps, PlanState::ps_ExprContext, Plan::qual, PlanState::qual, ReleaseSysCache(), AggStatePerAggData::resulttypeByVal, AggStatePerAggData::resulttypeLen, SearchSysCache1(), select_current_set(), AggState::sort_in, AggState::sort_out, AggState::sort_slot, AggStatePerPhaseData::sortnode, AggState::ss, ScanState::ss_ScanTupleSlot, PlanState::state, SysCacheGetAttr(), AggState::tmpcontext, AggStatePerTransData::transfn, Agg::transitionSpace, AggStatePerAggData::transno, TupleTableSlot::tts_tupleDescriptor, TTSOpsMinimalTuple, and TTSOpsVirtual.

Referenced by ExecInitNode().

3252 {
3253  AggState *aggstate;
3254  AggStatePerAgg peraggs;
3255  AggStatePerTrans pertransstates;
3256  AggStatePerGroup *pergroups;
3257  Plan *outerPlan;
3258  ExprContext *econtext;
3259  TupleDesc scanDesc;
3260  int max_aggno;
3261  int max_transno;
3262  int numaggrefs;
3263  int numaggs;
3264  int numtrans;
3265  int phase;
3266  int phaseidx;
3267  ListCell *l;
3268  Bitmapset *all_grouped_cols = NULL;
3269  int numGroupingSets = 1;
3270  int numPhases;
3271  int numHashes;
3272  int i = 0;
3273  int j = 0;
3274  bool use_hashing = (node->aggstrategy == AGG_HASHED ||
3275  node->aggstrategy == AGG_MIXED);
3276 
3277  /* check for unsupported flags */
3278  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
3279 
3280  /*
3281  * create state structure
3282  */
3283  aggstate = makeNode(AggState);
3284  aggstate->ss.ps.plan = (Plan *) node;
3285  aggstate->ss.ps.state = estate;
3286  aggstate->ss.ps.ExecProcNode = ExecAgg;
3287 
3288  aggstate->aggs = NIL;
3289  aggstate->numaggs = 0;
3290  aggstate->numtrans = 0;
3291  aggstate->aggstrategy = node->aggstrategy;
3292  aggstate->aggsplit = node->aggsplit;
3293  aggstate->maxsets = 0;
3294  aggstate->projected_set = -1;
3295  aggstate->current_set = 0;
3296  aggstate->peragg = NULL;
3297  aggstate->pertrans = NULL;
3298  aggstate->curperagg = NULL;
3299  aggstate->curpertrans = NULL;
3300  aggstate->input_done = false;
3301  aggstate->agg_done = false;
3302  aggstate->pergroups = NULL;
3303  aggstate->grp_firstTuple = NULL;
3304  aggstate->sort_in = NULL;
3305  aggstate->sort_out = NULL;
3306 
3307  /*
3308  * phases[0] always exists, but is dummy in sorted/plain mode
3309  */
3310  numPhases = (use_hashing ? 1 : 2);
3311  numHashes = (use_hashing ? 1 : 0);
3312 
3313  /*
3314  * Calculate the maximum number of grouping sets in any phase; this
3315  * determines the size of some allocations. Also calculate the number of
3316  * phases, since all hashed/mixed nodes contribute to only a single phase.
3317  */
3318  if (node->groupingSets)
3319  {
3320  numGroupingSets = list_length(node->groupingSets);
3321 
3322  foreach(l, node->chain)
3323  {
3324  Agg *agg = lfirst(l);
3325 
3326  numGroupingSets = Max(numGroupingSets,
3327  list_length(agg->groupingSets));
3328 
3329  /*
3330  * additional AGG_HASHED aggs become part of phase 0, but all
3331  * others add an extra phase.
3332  */
3333  if (agg->aggstrategy != AGG_HASHED)
3334  ++numPhases;
3335  else
3336  ++numHashes;
3337  }
3338  }
3339 
3340  aggstate->maxsets = numGroupingSets;
3341  aggstate->numphases = numPhases;
3342 
3343  aggstate->aggcontexts = (ExprContext **)
3344  palloc0(sizeof(ExprContext *) * numGroupingSets);
3345 
3346  /*
3347  * Create expression contexts. We need three or more, one for
3348  * per-input-tuple processing, one for per-output-tuple processing, one
3349  * for all the hashtables, and one for each grouping set. The per-tuple
3350  * memory context of the per-grouping-set ExprContexts (aggcontexts)
3351  * replaces the standalone memory context formerly used to hold transition
3352  * values. We cheat a little by using ExecAssignExprContext() to build
3353  * all of them.
3354  *
3355  * NOTE: the details of what is stored in aggcontexts and what is stored
3356  * in the regular per-query memory context are driven by a simple
3357  * decision: we want to reset the aggcontext at group boundaries (if not
3358  * hashing) and in ExecReScanAgg to recover no-longer-wanted space.
3359  */
3360  ExecAssignExprContext(estate, &aggstate->ss.ps);
3361  aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
3362 
3363  for (i = 0; i < numGroupingSets; ++i)
3364  {
3365  ExecAssignExprContext(estate, &aggstate->ss.ps);
3366  aggstate->aggcontexts[i] = aggstate->ss.ps.ps_ExprContext;
3367  }
3368 
3369  if (use_hashing)
3370  aggstate->hashcontext = CreateWorkExprContext(estate);
3371 
3372  ExecAssignExprContext(estate, &aggstate->ss.ps);
3373 
3374  /*
3375  * Initialize child nodes.
3376  *
3377  * If we are doing a hashed aggregation then the child plan does not need
3378  * to handle REWIND efficiently; see ExecReScanAgg.
3379  */
3380  if (node->aggstrategy == AGG_HASHED)
3381  eflags &= ~EXEC_FLAG_REWIND;
3382  outerPlan = outerPlan(node);
3383  outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags);
3384 
3385  /*
3386  * initialize source tuple type.
3387  */
3388  aggstate->ss.ps.outerops =
3390  &aggstate->ss.ps.outeropsfixed);
3391  aggstate->ss.ps.outeropsset = true;
3392 
3393  ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss,
3394  aggstate->ss.ps.outerops);
3395  scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
3396 
3397  /*
3398  * If there are more than two phases (including a potential dummy phase
3399  * 0), input will be resorted using tuplesort. Need a slot for that.
3400  */
3401  if (numPhases > 2)
3402  {
3403  aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc,
3405 
3406  /*
3407  * The output of the tuplesort, and the output from the outer child
3408  * might not use the same type of slot. In most cases the child will
3409  * be a Sort, and thus return a TTSOpsMinimalTuple type slot - but the
3410  * input can also be presorted due an index, in which case it could be
3411  * a different type of slot.
3412  *
3413  * XXX: For efficiency it would be good to instead/additionally
3414  * generate expressions with corresponding settings of outerops* for
3415  * the individual phases - deforming is often a bottleneck for
3416  * aggregations with lots of rows per group. If there's multiple
3417  * sorts, we know that all but the first use TTSOpsMinimalTuple (via
3418  * the nodeAgg.c internal tuplesort).
3419  */
3420  if (aggstate->ss.ps.outeropsfixed &&
3421  aggstate->ss.ps.outerops != &TTSOpsMinimalTuple)
3422  aggstate->ss.ps.outeropsfixed = false;
3423  }
3424 
3425  /*
3426  * Initialize result type, slot and projection.
3427  */
3429  ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
3430 
3431  /*
3432  * initialize child expressions
3433  *
3434  * We expect the parser to have checked that no aggs contain other agg
3435  * calls in their arguments (and just to be sure, we verify it again while
3436  * initializing the plan node). This would make no sense under SQL
3437  * semantics, and it's forbidden by the spec. Because it is true, we
3438  * don't need to worry about evaluating the aggs in any particular order.
3439  *
3440  * Note: execExpr.c finds Aggrefs for us, and adds them to aggstate->aggs.
3441  * Aggrefs in the qual are found here; Aggrefs in the targetlist are found
3442  * during ExecAssignProjectionInfo, above.
3443  */
3444  aggstate->ss.ps.qual =
3445  ExecInitQual(node->plan.qual, (PlanState *) aggstate);
3446 
3447  /*
3448  * We should now have found all Aggrefs in the targetlist and quals.
3449  */
3450  numaggrefs = list_length(aggstate->aggs);
3451  max_aggno = -1;
3452  max_transno = -1;
3453  foreach(l, aggstate->aggs)
3454  {
3455  Aggref *aggref = (Aggref *) lfirst(l);
3456 
3457  max_aggno = Max(max_aggno, aggref->aggno);
3458  max_transno = Max(max_transno, aggref->aggtransno);
3459  }
3460  numaggs = max_aggno + 1;
3461  numtrans = max_transno + 1;
3462 
3463  /*
3464  * For each phase, prepare grouping set data and fmgr lookup data for
3465  * compare functions. Accumulate all_grouped_cols in passing.
3466  */
3467  aggstate->phases = palloc0(numPhases * sizeof(AggStatePerPhaseData));
3468 
3469  aggstate->num_hashes = numHashes;
3470  if (numHashes)
3471  {
3472  aggstate->perhash = palloc0(sizeof(AggStatePerHashData) * numHashes);
3473  aggstate->phases[0].numsets = 0;
3474  aggstate->phases[0].gset_lengths = palloc(numHashes * sizeof(int));
3475  aggstate->phases[0].grouped_cols = palloc(numHashes * sizeof(Bitmapset *));
3476  }
3477 
3478  phase = 0;
3479  for (phaseidx = 0; phaseidx <= list_length(node->chain); ++phaseidx)
3480  {
3481  Agg *aggnode;
3482  Sort *sortnode;
3483 
3484  if (phaseidx > 0)
3485  {
3486  aggnode = list_nth_node(Agg, node->chain, phaseidx - 1);
3487  sortnode = castNode(Sort, aggnode->plan.lefttree);
3488  }
3489  else
3490  {
3491  aggnode = node;
3492  sortnode = NULL;
3493  }
3494 
3495  Assert(phase <= 1 || sortnode);
3496 
3497  if (aggnode->aggstrategy == AGG_HASHED
3498  || aggnode->aggstrategy == AGG_MIXED)
3499  {
3500  AggStatePerPhase phasedata = &aggstate->phases[0];
3501  AggStatePerHash perhash;
3502  Bitmapset *cols = NULL;
3503 
3504  Assert(phase == 0);
3505  i = phasedata->numsets++;
3506  perhash = &aggstate->perhash[i];
3507 
3508  /* phase 0 always points to the "real" Agg in the hash case */
3509  phasedata->aggnode = node;
3510  phasedata->aggstrategy = node->aggstrategy;
3511 
3512  /* but the actual Agg node representing this hash is saved here */
3513  perhash->aggnode = aggnode;
3514 
3515  phasedata->gset_lengths[i] = perhash->numCols = aggnode->numCols;
3516 
3517  for (j = 0; j < aggnode->numCols; ++j)
3518  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
3519 
3520  phasedata->grouped_cols[i] = cols;
3521 
3522  all_grouped_cols = bms_add_members(all_grouped_cols, cols);
3523  continue;
3524  }
3525  else
3526  {
3527  AggStatePerPhase phasedata = &aggstate->phases[++phase];
3528  int num_sets;
3529 
3530  phasedata->numsets = num_sets = list_length(aggnode->groupingSets);
3531 
3532  if (num_sets)
3533  {
3534  phasedata->gset_lengths = palloc(num_sets * sizeof(int));
3535  phasedata->grouped_cols = palloc(num_sets * sizeof(Bitmapset *));
3536 
3537  i = 0;
3538  foreach(l, aggnode->groupingSets)
3539  {
3540  int current_length = list_length(lfirst(l));
3541  Bitmapset *cols = NULL;
3542 
3543  /* planner forces this to be correct */
3544  for (j = 0; j < current_length; ++j)
3545  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
3546 
3547  phasedata->grouped_cols[i] = cols;
3548  phasedata->gset_lengths[i] = current_length;
3549 
3550  ++i;
3551  }
3552 
3553  all_grouped_cols = bms_add_members(all_grouped_cols,
3554  phasedata->grouped_cols[0]);
3555  }
3556  else
3557  {
3558  Assert(phaseidx == 0);
3559 
3560  phasedata->gset_lengths = NULL;
3561  phasedata->grouped_cols = NULL;
3562  }
3563 
3564  /*
3565  * If we are grouping, precompute fmgr lookup data for inner loop.
3566  */
3567  if (aggnode->aggstrategy == AGG_SORTED)
3568  {
3569  int i = 0;
3570 
3571  Assert(aggnode->numCols > 0);
3572 
3573  /*
3574  * Build a separate function for each subset of columns that
3575  * need to be compared.
3576  */
3577  phasedata->eqfunctions =
3578  (ExprState **) palloc0(aggnode->numCols * sizeof(ExprState *));
3579 
3580  /* for each grouping set */
3581  for (i = 0; i < phasedata->numsets; i++)
3582  {
3583  int length = phasedata->gset_lengths[i];
3584 
3585  if (phasedata->eqfunctions[length - 1] != NULL)
3586  continue;
3587 
3588  phasedata->eqfunctions[length - 1] =
3589  execTuplesMatchPrepare(scanDesc,
3590  length,
3591  aggnode->grpColIdx,
3592  aggnode->grpOperators,
3593  aggnode->grpCollations,
3594  (PlanState *) aggstate);
3595  }
3596 
3597  /* and for all grouped columns, unless already computed */
3598  if (phasedata->eqfunctions[aggnode->numCols - 1] == NULL)
3599  {
3600  phasedata->eqfunctions[aggnode->numCols - 1] =
3601  execTuplesMatchPrepare(scanDesc,
3602  aggnode->numCols,
3603  aggnode->grpColIdx,
3604  aggnode->grpOperators,
3605  aggnode->grpCollations,
3606  (PlanState *) aggstate);
3607  }
3608  }
3609 
3610  phasedata->aggnode = aggnode;
3611  phasedata->aggstrategy = aggnode->aggstrategy;
3612  phasedata->sortnode = sortnode;
3613  }
3614  }
3615 
3616  /*
3617  * Convert all_grouped_cols to a descending-order list.
3618  */
3619  i = -1;
3620  while ((i = bms_next_member(all_grouped_cols, i)) >= 0)
3621  aggstate->all_grouped_cols = lcons_int(i, aggstate->all_grouped_cols);
3622 
3623  /*
3624  * Set up aggregate-result storage in the output expr context, and also
3625  * allocate my private per-agg working storage
3626  */
3627  econtext = aggstate->ss.ps.ps_ExprContext;
3628  econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
3629  econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numaggs);
3630 
3631  peraggs = (AggStatePerAgg) palloc0(sizeof(AggStatePerAggData) * numaggs);
3632  pertransstates = (AggStatePerTrans) palloc0(sizeof(AggStatePerTransData) * numtrans);
3633 
3634  aggstate->peragg = peraggs;
3635  aggstate->pertrans = pertransstates;
3636 
3637 
3638  aggstate->all_pergroups =
3640  * (numGroupingSets + numHashes));
3641  pergroups = aggstate->all_pergroups;
3642 
3643  if (node->aggstrategy != AGG_HASHED)
3644  {
3645  for (i = 0; i < numGroupingSets; i++)
3646  {
3647  pergroups[i] = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData)
3648  * numaggs);
3649  }
3650 
3651  aggstate->pergroups = pergroups;
3652  pergroups += numGroupingSets;
3653  }
3654 
3655  /*
3656  * Hashing can only appear in the initial phase.
3657  */
3658  if (use_hashing)
3659  {
3660  Plan *outerplan = outerPlan(node);
3661  uint64 totalGroups = 0;
3662  int i;
3663 
3664  aggstate->hash_metacxt = AllocSetContextCreate(aggstate->ss.ps.state->es_query_cxt,
3665  "HashAgg meta context",
3667  aggstate->hash_spill_rslot = ExecInitExtraTupleSlot(estate, scanDesc,
3669  aggstate->hash_spill_wslot = ExecInitExtraTupleSlot(estate, scanDesc,
3670  &TTSOpsVirtual);
3671 
3672  /* this is an array of pointers, not structures */
3673  aggstate->hash_pergroup = pergroups;
3674 
3675  aggstate->hashentrysize = hash_agg_entry_size(aggstate->numtrans,
3676  outerplan->plan_width,
3677  node->transitionSpace);
3678 
3679  /*
3680  * Consider all of the grouping sets together when setting the limits
3681  * and estimating the number of partitions. This can be inaccurate
3682  * when there is more than one grouping set, but should still be
3683  * reasonable.
3684  */
3685  for (i = 0; i < aggstate->num_hashes; i++)
3686  totalGroups += aggstate->perhash[i].aggnode->numGroups;
3687 
3688  hash_agg_set_limits(aggstate->hashentrysize, totalGroups, 0,
3689  &aggstate->hash_mem_limit,
3690  &aggstate->hash_ngroups_limit,
3691  &aggstate->hash_planned_partitions);
3692  find_hash_columns(aggstate);
3693 
3694  /* Skip massive memory allocation if we are just doing EXPLAIN */
3695  if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
3696  build_hash_tables(aggstate);
3697 
3698  aggstate->table_filled = false;
3699 
3700  /* Initialize this to 1, meaning nothing spilled, yet */
3701  aggstate->hash_batches_used = 1;
3702  }
3703 
3704  /*
3705  * Initialize current phase-dependent values to initial phase. The initial
3706  * phase is 1 (first sort pass) for all strategies that use sorting (if
3707  * hashing is being done too, then phase 0 is processed last); but if only
3708  * hashing is being done, then phase 0 is all there is.
3709  */
3710  if (node->aggstrategy == AGG_HASHED)
3711  {
3712  aggstate->current_phase = 0;
3713  initialize_phase(aggstate, 0);
3714  select_current_set(aggstate, 0, true);
3715  }
3716  else
3717  {
3718  aggstate->current_phase = 1;
3719  initialize_phase(aggstate, 1);
3720  select_current_set(aggstate, 0, false);
3721  }
3722 
3723  /*
3724  * Perform lookups of aggregate function info, and initialize the
3725  * unchanging fields of the per-agg and per-trans data.
3726  */
3727  foreach(l, aggstate->aggs)
3728  {
3729  Aggref *aggref = lfirst(l);
3730  AggStatePerAgg peragg;
3731  AggStatePerTrans pertrans;
3732  Oid aggTransFnInputTypes[FUNC_MAX_ARGS];
3733  int numAggTransFnArgs;
3734  int numDirectArgs;
3735  HeapTuple aggTuple;
3736  Form_pg_aggregate aggform;
3737  AclResult aclresult;
3738  Oid finalfn_oid;
3739  Oid serialfn_oid,
3740  deserialfn_oid;
3741  Oid aggOwner;
3742  Expr *finalfnexpr;
3743  Oid aggtranstype;
3744 
3745  /* Planner should have assigned aggregate to correct level */
3746  Assert(aggref->agglevelsup == 0);
3747  /* ... and the split mode should match */
3748  Assert(aggref->aggsplit == aggstate->aggsplit);
3749 
3750  peragg = &peraggs[aggref->aggno];
3751 
3752  /* Check if we initialized the state for this aggregate already. */
3753  if (peragg->aggref != NULL)
3754  continue;
3755 
3756  peragg->aggref = aggref;
3757  peragg->transno = aggref->aggtransno;
3758 
3759  /* Fetch the pg_aggregate row */
3760  aggTuple = SearchSysCache1(AGGFNOID,
3761  ObjectIdGetDatum(aggref->aggfnoid));
3762  if (!HeapTupleIsValid(aggTuple))
3763  elog(ERROR, "cache lookup failed for aggregate %u",
3764  aggref->aggfnoid);
3765  aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
3766 
3767  /* Check permission to call aggregate function */
3768  aclresult = pg_proc_aclcheck(aggref->aggfnoid, GetUserId(),
3769  ACL_EXECUTE);
3770  if (aclresult != ACLCHECK_OK)
3771  aclcheck_error(aclresult, OBJECT_AGGREGATE,
3772  get_func_name(aggref->aggfnoid));
3774 
3775  /* planner recorded transition state type in the Aggref itself */
3776  aggtranstype = aggref->aggtranstype;
3777  Assert(OidIsValid(aggtranstype));
3778 
3779  /* Final function only required if we're finalizing the aggregates */
3780  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
3781  peragg->finalfn_oid = finalfn_oid = InvalidOid;
3782  else
3783  peragg->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
3784 
3785  serialfn_oid = InvalidOid;
3786  deserialfn_oid = InvalidOid;
3787 
3788  /*
3789  * Check if serialization/deserialization is required. We only do it
3790  * for aggregates that have transtype INTERNAL.
3791  */
3792  if (aggtranstype == INTERNALOID)
3793  {
3794  /*
3795  * The planner should only have generated a serialize agg node if
3796  * every aggregate with an INTERNAL state has a serialization
3797  * function. Verify that.
3798  */
3799  if (DO_AGGSPLIT_SERIALIZE(aggstate->aggsplit))
3800  {
3801  /* serialization only valid when not running finalfn */
3803 
3804  if (!OidIsValid(aggform->aggserialfn))
3805  elog(ERROR, "serialfunc not provided for serialization aggregation");
3806  serialfn_oid = aggform->aggserialfn;
3807  }
3808 
3809  /* Likewise for deserialization functions */
3810  if (DO_AGGSPLIT_DESERIALIZE(aggstate->aggsplit))
3811  {
3812  /* deserialization only valid when combining states */
3813  Assert(DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
3814 
3815  if (!OidIsValid(aggform->aggdeserialfn))
3816  elog(ERROR, "deserialfunc not provided for deserialization aggregation");
3817  deserialfn_oid = aggform->aggdeserialfn;
3818  }
3819  }
3820 
3821  /* Check that aggregate owner has permission to call component fns */
3822  {
3823  HeapTuple procTuple;
3824 
3825  procTuple = SearchSysCache1(PROCOID,
3826  ObjectIdGetDatum(aggref->aggfnoid));
3827  if (!HeapTupleIsValid(procTuple))
3828  elog(ERROR, "cache lookup failed for function %u",
3829  aggref->aggfnoid);
3830  aggOwner = ((Form_pg_proc) GETSTRUCT(procTuple))->proowner;
3831  ReleaseSysCache(procTuple);
3832 
3833  if (OidIsValid(finalfn_oid))
3834  {
3835  aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
3836  ACL_EXECUTE);
3837  if (aclresult != ACLCHECK_OK)
3838  aclcheck_error(aclresult, OBJECT_FUNCTION,
3839  get_func_name(finalfn_oid));
3840  InvokeFunctionExecuteHook(finalfn_oid);
3841  }
3842  if (OidIsValid(serialfn_oid))
3843  {
3844  aclresult = pg_proc_aclcheck(serialfn_oid, aggOwner,
3845  ACL_EXECUTE);
3846  if (aclresult != ACLCHECK_OK)
3847  aclcheck_error(aclresult, OBJECT_FUNCTION,
3848  get_func_name(serialfn_oid));
3849  InvokeFunctionExecuteHook(serialfn_oid);
3850  }
3851  if (OidIsValid(deserialfn_oid))
3852  {
3853  aclresult = pg_proc_aclcheck(deserialfn_oid, aggOwner,
3854  ACL_EXECUTE);
3855  if (aclresult != ACLCHECK_OK)
3856  aclcheck_error(aclresult, OBJECT_FUNCTION,
3857  get_func_name(deserialfn_oid));
3858  InvokeFunctionExecuteHook(deserialfn_oid);
3859  }
3860  }
3861 
3862  /*
3863  * Get actual datatypes of the (nominal) aggregate inputs. These
3864  * could be different from the agg's declared input types, when the
3865  * agg accepts ANY or a polymorphic type.
3866  */
3867  numAggTransFnArgs = get_aggregate_argtypes(aggref,
3868  aggTransFnInputTypes);
3869 
3870  /* Count the "direct" arguments, if any */
3871  numDirectArgs = list_length(aggref->aggdirectargs);
3872 
3873  /* Detect how many arguments to pass to the finalfn */
3874  if (aggform->aggfinalextra)
3875  peragg->numFinalArgs = numAggTransFnArgs + 1;
3876  else
3877  peragg->numFinalArgs = numDirectArgs + 1;
3878 
3879  /* Initialize any direct-argument expressions */
3880  peragg->aggdirectargs = ExecInitExprList(aggref->aggdirectargs,
3881  (PlanState *) aggstate);
3882 
3883  /*
3884  * build expression trees using actual argument & result types for the
3885  * finalfn, if it exists and is required.
3886  */
3887  if (OidIsValid(finalfn_oid))
3888  {
3889  build_aggregate_finalfn_expr(aggTransFnInputTypes,
3890  peragg->numFinalArgs,
3891  aggtranstype,
3892  aggref->aggtype,
3893  aggref->inputcollid,
3894  finalfn_oid,
3895  &finalfnexpr);
3896  fmgr_info(finalfn_oid, &peragg->finalfn);
3897  fmgr_info_set_expr((Node *) finalfnexpr, &peragg->finalfn);
3898  }
3899 
3900  /* get info about the output value's datatype */
3901  get_typlenbyval(aggref->aggtype,
3902  &peragg->resulttypeLen,
3903  &peragg->resulttypeByVal);
3904 
3905  /*
3906  * Build working state for invoking the transition function, if we
3907  * haven't done it already.
3908  */
3909  pertrans = &pertransstates[aggref->aggtransno];
3910  if (pertrans->aggref == NULL)
3911  {
3912  Datum textInitVal;
3913  Datum initValue;
3914  bool initValueIsNull;
3915  Oid transfn_oid;
3916 
3917  /*
3918  * If this aggregation is performing state combines, then instead
3919  * of using the transition function, we'll use the combine
3920  * function.
3921  */
3922  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
3923  {
3924  transfn_oid = aggform->aggcombinefn;
3925 
3926  /* If not set then the planner messed up */
3927  if (!OidIsValid(transfn_oid))
3928  elog(ERROR, "combinefn not set for aggregate function");
3929  }
3930  else
3931  transfn_oid = aggform->aggtransfn;
3932 
3933  aclresult = pg_proc_aclcheck(transfn_oid, aggOwner, ACL_EXECUTE);
3934  if (aclresult != ACLCHECK_OK)
3935  aclcheck_error(aclresult, OBJECT_FUNCTION,
3936  get_func_name(transfn_oid));
3937  InvokeFunctionExecuteHook(transfn_oid);
3938 
3939  /*
3940  * initval is potentially null, so don't try to access it as a
3941  * struct field. Must do it the hard way with SysCacheGetAttr.
3942  */
3943  textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
3944  Anum_pg_aggregate_agginitval,
3945  &initValueIsNull);
3946  if (initValueIsNull)
3947  initValue = (Datum) 0;
3948  else
3949  initValue = GetAggInitVal(textInitVal, aggtranstype);
3950 
3951  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
3952  {
3953  Oid combineFnInputTypes[] = {aggtranstype,
3954  aggtranstype};
3955 
3956  /*
3957  * When combining there's only one input, the to-be-combined
3958  * transition value. The transition value is not counted
3959  * here.
3960  */
3961  pertrans->numTransInputs = 1;
3962 
3963  /* aggcombinefn always has two arguments of aggtranstype */
3964  build_pertrans_for_aggref(pertrans, aggstate, estate,
3965  aggref, transfn_oid, aggtranstype,
3966  serialfn_oid, deserialfn_oid,
3967  initValue, initValueIsNull,
3968  combineFnInputTypes, 2);
3969 
3970  /*
3971  * Ensure that a combine function to combine INTERNAL states
3972  * is not strict. This should have been checked during CREATE
3973  * AGGREGATE, but the strict property could have been changed
3974  * since then.
3975  */
3976  if (pertrans->transfn.fn_strict && aggtranstype == INTERNALOID)
3977  ereport(ERROR,
3978  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
3979  errmsg("combine function with transition type %s must not be declared STRICT",
3980  format_type_be(aggtranstype))));
3981  }
3982  else
3983  {
3984  /* Detect how many arguments to pass to the transfn */
3985  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
3986  pertrans->numTransInputs = list_length(aggref->args);
3987  else
3988  pertrans->numTransInputs = numAggTransFnArgs;
3989 
3990  build_pertrans_for_aggref(pertrans, aggstate, estate,
3991  aggref, transfn_oid, aggtranstype,
3992  serialfn_oid, deserialfn_oid,
3993  initValue, initValueIsNull,
3994  aggTransFnInputTypes,
3995  numAggTransFnArgs);
3996 
3997  /*
3998  * If the transfn is strict and the initval is NULL, make sure
3999  * input type and transtype are the same (or at least
4000  * binary-compatible), so that it's OK to use the first
4001  * aggregated input value as the initial transValue. This
4002  * should have been checked at agg definition time, but we
4003  * must check again in case the transfn's strictness property
4004  * has been changed.
4005  */
4006  if (pertrans->transfn.fn_strict && pertrans->initValueIsNull)
4007  {
4008  if (numAggTransFnArgs <= numDirectArgs ||
4009  !IsBinaryCoercible(aggTransFnInputTypes[numDirectArgs],
4010  aggtranstype))
4011  ereport(ERROR,
4012  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
4013  errmsg("aggregate %u needs to have compatible input type and transition type",
4014  aggref->aggfnoid)));
4015  }
4016  }
4017  }
4018  else
4019  pertrans->aggshared = true;
4020  ReleaseSysCache(aggTuple);
4021  }
4022 
4023  /*
4024  * Update aggstate->numaggs to be the number of unique aggregates found.
4025  * Also set numstates to the number of unique transition states found.
4026  */
4027  aggstate->numaggs = numaggs;
4028  aggstate->numtrans = numtrans;
4029 
4030  /*
4031  * Last, check whether any more aggregates got added onto the node while
4032  * we processed the expressions for the aggregate arguments (including not
4033  * only the regular arguments and FILTER expressions handled immediately
4034  * above, but any direct arguments we might've handled earlier). If so,
4035  * we have nested aggregate functions, which is semantically nonsensical,
4036  * so complain. (This should have been caught by the parser, so we don't
4037  * need to work hard on a helpful error message; but we defend against it
4038  * here anyway, just to be sure.)
4039  */
4040  if (numaggrefs != list_length(aggstate->aggs))
4041  ereport(ERROR,
4042  (errcode(ERRCODE_GROUPING_ERROR),
4043  errmsg("aggregate function calls cannot be nested")));
4044 
4045  /*
4046  * Build expressions doing all the transition work at once. We build a
4047  * different one for each phase, as the number of transition function
4048  * invocation can differ between phases. Note this'll work both for
4049  * transition and combination functions (although there'll only be one
4050  * phase in the latter case).
4051  */
4052  for (phaseidx = 0; phaseidx < aggstate->numphases; phaseidx++)
4053  {
4054  AggStatePerPhase phase = &aggstate->phases[phaseidx];
4055  bool dohash = false;
4056  bool dosort = false;
4057 
4058  /* phase 0 doesn't necessarily exist */
4059  if (!phase->aggnode)
4060  continue;
4061 
4062  if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 1)
4063  {
4064  /*
4065  * Phase one, and only phase one, in a mixed agg performs both
4066  * sorting and aggregation.
4067  */
4068  dohash = true;
4069  dosort = true;
4070  }
4071  else if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 0)
4072  {
4073  /*
4074  * No need to compute a transition function for an AGG_MIXED phase
4075  * 0 - the contents of the hashtables will have been computed
4076  * during phase 1.
4077  */
4078  continue;
4079  }
4080  else if (phase->aggstrategy == AGG_PLAIN ||
4081  phase->aggstrategy == AGG_SORTED)
4082  {
4083  dohash = false;
4084  dosort = true;
4085  }
4086  else if (phase->aggstrategy == AGG_HASHED)
4087  {
4088  dohash = true;
4089  dosort = false;
4090  }
4091  else
4092  Assert(false);
4093 
4094  phase->evaltrans = ExecBuildAggTrans(aggstate, phase, dosort, dohash,
4095  false);
4096 
4097  /* cache compiled expression for outer slot without NULL check */
4098  phase->evaltrans_cache[0][0] = phase->evaltrans;
4099  }
4100 
4101  return aggstate;
4102 }
struct AggStatePerTransData * AggStatePerTrans
Definition: execnodes.h:2269
ExprState ** eqfunctions
Definition: nodeAgg.h:278
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:2340
#define NIL
Definition: pg_list.h:65
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:2270
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:476
int numCols
Definition: plannodes.h:862
List * qual
Definition: plannodes.h:142
AggStatePerPhase phases
Definition: execnodes.h:2307
double hashentrysize
Definition: execnodes.h:2332
#define AllocSetContextCreate
Definition: memutils.h:173
Datum * ecxt_aggvalues
Definition: execnodes.h:245
uint64 hash_ngroups_limit
Definition: execnodes.h:2329
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1831
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
AttrNumber * grpColIdx
Definition: plannodes.h:863
uint64 transitionSpace
Definition: plannodes.h:867
int aggtransno
Definition: primnodes.h:341
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:499
List * lcons_int(int datum, List *list)
Definition: list.c:486
int numaggs
Definition: execnodes.h:2278
Oid GetUserId(void)
Definition: miscinit.c:478
bool agg_done
Definition: execnodes.h:2296
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
Oid * grpCollations
Definition: plannodes.h:865
TupleTableSlot * sort_slot
Definition: execnodes.h:2310
List * all_grouped_cols
Definition: execnodes.h:2301
Tuplesortstate * sort_out
Definition: execnodes.h:2309
ScanState ss
Definition: execnodes.h:2276
ExprContext * ps_ExprContext
Definition: execnodes.h:1005
ExprState * evaltrans
Definition: nodeAgg.h:283
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
Oid inputcollid
Definition: primnodes.h:326
int current_phase
Definition: execnodes.h:2284
Definition: nodes.h:539
AggSplit aggsplit
Definition: execnodes.h:2281
static TupleTableSlot * ExecAgg(PlanState *pstate)
Definition: nodeAgg.c:2159
int errcode(int sqlerrcode)
Definition: elog.c:698
List * args
Definition: primnodes.h:330
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1380
static void build_pertrans_for_aggref(AggStatePerTrans pertrans, AggState *aggstate, EState *estate, Aggref *aggref, Oid transfn_oid, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, Oid *inputTypes, int numArguments)
Definition: nodeAgg.c:4115
void build_aggregate_finalfn_expr(Oid *agg_input_types, int num_finalfn_inputs, Oid agg_state_type, Oid agg_result_type, Oid agg_input_collation, Oid finalfn_oid, Expr **finalfnexpr)
Definition: parse_agg.c:2081
TupleTableSlot * hash_spill_rslot
Definition: execnodes.h:2322
AggStatePerTrans pertrans
Definition: execnodes.h:2286
EState * state
Definition: execnodes.h:968
int projected_set
Definition: execnodes.h:2297
unsigned int Oid
Definition: postgres_ext.h:31
HeapTuple grp_firstTuple
Definition: execnodes.h:2314
Aggref * aggref
Definition: nodeAgg.h:187
int current_set
Definition: execnodes.h:2299
#define OidIsValid(objectId)
Definition: c.h:710
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:801
int numtrans
Definition: execnodes.h:2279
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:209
ExprContext * tmpcontext
Definition: execnodes.h:2289
FmgrInfo transfn
Definition: nodeAgg.h:81
#define FUNC_MAX_ARGS
Aggref * aggref
Definition: nodeAgg.h:44
Bitmapset ** grouped_cols
Definition: nodeAgg.h:277
PlanState ps
Definition: execnodes.h:1377
int maxsets
Definition: execnodes.h:2306
Size hash_agg_entry_size(int numTrans, Size tupleWidth, Size transitionSpace)
Definition: nodeAgg.c:1695
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3308
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:803
MemoryContext es_query_cxt
Definition: execnodes.h:600
AggStrategy aggstrategy
Definition: plannodes.h:860
bool table_filled
Definition: execnodes.h:2316
AggStrategy aggstrategy
Definition: execnodes.h:2280
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
bool fn_strict
Definition: fmgr.h:61
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1579
MemoryContext hash_metacxt
Definition: execnodes.h:2318
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
static void find_hash_columns(AggState *aggstate)
Definition: nodeAgg.c:1565
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
Tuplesortstate * sort_in
Definition: execnodes.h:2308
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define outerPlanState(node)
Definition: execnodes.h:1062
#define list_nth_node(type, list, n)
Definition: pg_list.h:306
static int initValue(long lng_val)
Definition: informix.c:677
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:535
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:318
Index agglevelsup
Definition: primnodes.h:338
int hash_planned_partitions
Definition: execnodes.h:2330
List * aggdirectargs
Definition: primnodes.h:329
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition: nodeAgg.c:4351
AggStatePerAgg curperagg
Definition: execnodes.h:2292
AggStatePerHash perhash
Definition: execnodes.h:2339
bool outeropsset
Definition: execnodes.h:1049
AggStrategy aggstrategy
Definition: nodeAgg.h:274
ExprState * evaltrans_cache[2][2]
Definition: nodeAgg.h:291
#define EXEC_FLAG_REWIND
Definition: executor.h:57
int hash_batches_used
Definition: execnodes.h:2337
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:191
bool IsBinaryCoercible(Oid srctype, Oid targettype)
#define outerPlan(node)
Definition: plannodes.h:171
int num_hashes
Definition: execnodes.h:2317
Plan plan
Definition: plannodes.h:859
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
bool input_done
Definition: execnodes.h:2295
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
ExprContext * hashcontext
Definition: execnodes.h:2287
bool * ecxt_aggnulls
Definition: execnodes.h:247
void * palloc0(Size size)
Definition: mcxt.c:1093
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:972
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:411
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1388
List * groupingSets
Definition: plannodes.h:870
int16 resulttypeLen
Definition: nodeAgg.h:216
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:498
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
Plan * plan
Definition: execnodes.h:966
#define InvalidOid
Definition: postgres_ext.h:36
Oid aggfnoid
Definition: primnodes.h:323
#define ereport(elevel,...)
Definition: elog.h:157
int aggno
Definition: primnodes.h:340
#define Max(x, y)
Definition: c.h:980
ExprContext ** aggcontexts
Definition: execnodes.h:2288
#define makeNode(_type_)
Definition: nodes.h:587
int plan_width
Definition: plannodes.h:124
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:59
#define EXEC_FLAG_MARK
Definition: executor.h:59
AggSplit aggsplit
Definition: plannodes.h:861
struct AggStatePerAggData * AggStatePerAgg
Definition: execnodes.h:2268
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
AggSplit aggsplit
Definition: primnodes.h:339
AggStatePerGroup * pergroups
Definition: execnodes.h:2312
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:480
static int list_length(const List *l)
Definition: pg_list.h:149
long numGroups
Definition: plannodes.h:866
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:802
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2198
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1799
bool outeropsfixed
Definition: execnodes.h:1045
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:804
Size hash_mem_limit
Definition: execnodes.h:2328
struct Plan * lefttree
Definition: plannodes.h:143
int numphases
Definition: execnodes.h:2283
ExprState * qual
Definition: execnodes.h:987
void hash_agg_set_limits(double hashentrysize, double input_groups, int used_bits, Size *mem_limit, uint64 *ngroups_limit, int *num_partitions)
Definition: nodeAgg.c:1799
Oid * grpOperators
Definition: plannodes.h:864
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
List * chain
Definition: plannodes.h:871
AggStatePerAgg peragg
Definition: execnodes.h:2285
#define ACL_EXECUTE
Definition: parsenodes.h:89
#define elog(elevel,...)
Definition: elog.h:232
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4718
int i
List * aggdirectargs
Definition: nodeAgg.h:210
Oid aggtranstype
Definition: primnodes.h:327
AggStatePerTrans curpertrans
Definition: execnodes.h:2294
Oid aggtype
Definition: primnodes.h:324
bool resulttypeByVal
Definition: nodeAgg.h:217
char aggkind
Definition: primnodes.h:337
Definition: plannodes.h:857
ExprContext * CreateWorkExprContext(EState *estate)
Definition: execUtils.c:316
List * aggs
Definition: execnodes.h:2277
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:682
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1887
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:141
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:56
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
FmgrInfo finalfn
Definition: nodeAgg.h:199
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
TupleTableSlot * hash_spill_wslot
Definition: execnodes.h:2323
static void build_hash_tables(AggState *aggstate)
Definition: nodeAgg.c:1470
const TupleTableSlotOps * outerops
Definition: execnodes.h:1041
ExprState * ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, bool doSort, bool doHash, bool nullcheck)
Definition: execExpr.c:3281
AggStatePerGroup * all_pergroups
Definition: execnodes.h:2345

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

Definition at line 4437 of file nodeAgg.c.

References AggState::agg_done, AGG_HASHED, AGG_MIXED, AggState::aggcontexts, Agg::aggParams, AggState::aggstrategy, bms_overlap(), build_hash_tables(), PlanState::chgParam, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExecClearTuple(), ExecReScan(), AggState::grp_firstTuple, AggState::hash_ever_spilled, AggState::hash_ngroups_current, AggState::hash_spill_mode, hashagg_recompile_expressions(), hashagg_reset_spill_state(), AggState::hashcontext, AggStatePerHashData::hashiter, AggStatePerHashData::hashtable, heap_freetuple(), initialize_phase(), AggState::input_done, Max, AggState::maxsets, MemSet, AggState::numaggs, AggState::numtrans, outerPlan, outerPlanState, AggState::pergroups, AggState::perhash, AggState::pertrans, PlanState::plan, AggState::projected_set, ScanState::ps, PlanState::ps_ExprContext, ReScanExprContext(), ResetTupleHashIterator, select_current_set(), AggStatePerTransData::sortstates, AggState::ss, ScanState::ss_ScanTupleSlot, AggState::table_filled, and tuplesort_end().

Referenced by ExecReScan().

4438 {
4439  ExprContext *econtext = node->ss.ps.ps_ExprContext;
4441  Agg *aggnode = (Agg *) node->ss.ps.plan;
4442  int transno;
4443  int numGroupingSets = Max(node->maxsets, 1);
4444  int setno;
4445 
4446  node->agg_done = false;
4447 
4448  if (node->aggstrategy == AGG_HASHED)
4449  {
4450  /*
4451  * In the hashed case, if we haven't yet built the hash table then we
4452  * can just return; nothing done yet, so nothing to undo. If subnode's
4453  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
4454  * else no reason to re-scan it at all.
4455  */
4456  if (!node->table_filled)
4457  return;
4458 
4459  /*
4460  * If we do have the hash table, and it never spilled, and the subplan
4461  * does not have any parameter changes, and none of our own parameter
4462  * changes affect input expressions of the aggregated functions, then
4463  * we can just rescan the existing hash table; no need to build it
4464  * again.
4465  */
4466  if (outerPlan->chgParam == NULL && !node->hash_ever_spilled &&
4467  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
4468  {
4470  &node->perhash[0].hashiter);
4471  select_current_set(node, 0, true);
4472  return;
4473  }
4474  }
4475 
4476  /* Make sure we have closed any open tuplesorts */
4477  for (transno = 0; transno < node->numtrans; transno++)
4478  {
4479  for (setno = 0; setno < numGroupingSets; setno++)
4480  {
4481  AggStatePerTrans pertrans = &node->pertrans[transno];
4482 
4483  if (pertrans->sortstates[setno])
4484  {
4485  tuplesort_end(pertrans->sortstates[setno]);
4486  pertrans->sortstates[setno] = NULL;
4487  }
4488  }
4489  }
4490 
4491  /*
4492  * We don't need to ReScanExprContext the output tuple context here;
4493  * ExecReScan already did it. But we do need to reset our per-grouping-set
4494  * contexts, which may have transvalues stored in them. (We use rescan
4495  * rather than just reset because transfns may have registered callbacks
4496  * that need to be run now.) For the AGG_HASHED case, see below.
4497  */
4498 
4499  for (setno = 0; setno < numGroupingSets; setno++)
4500  {
4501  ReScanExprContext(node->aggcontexts[setno]);
4502  }
4503 
4504  /* Release first tuple of group, if we have made a copy */
4505  if (node->grp_firstTuple != NULL)
4506  {
4508  node->grp_firstTuple = NULL;
4509  }
4511 
4512  /* Forget current agg values */
4513  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
4514  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
4515 
4516  /*
4517  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
4518  * the hashcontext. This used to be an issue, but now, resetting a context
4519  * automatically deletes sub-contexts too.
4520  */
4521  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
4522  {
4524 
4525  node->hash_ever_spilled = false;
4526  node->hash_spill_mode = false;
4527  node->hash_ngroups_current = 0;
4528 
4530  /* Rebuild an empty hash table */
4531  build_hash_tables(node);
4532  node->table_filled = false;
4533  /* iterator will be reset when the table is filled */
4534 
4535  hashagg_recompile_expressions(node, false, false);
4536  }
4537 
4538  if (node->aggstrategy != AGG_HASHED)
4539  {
4540  /*
4541  * Reset the per-group state (in particular, mark transvalues null)
4542  */
4543  for (setno = 0; setno < numGroupingSets; setno++)
4544  {
4545  MemSet(node->pergroups[setno], 0,
4546  sizeof(AggStatePerGroupData) * node->numaggs);
4547  }
4548 
4549  /* reset to phase 1 */
4550  initialize_phase(node, 1);
4551 
4552  node->input_done = false;
4553  node->projected_set = -1;
4554  }
4555 
4556  if (outerPlan->chgParam == NULL)
4557  ExecReScan(outerPlan);
4558 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3199
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:476
Datum * ecxt_aggvalues
Definition: execnodes.h:245
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
int numaggs
Definition: execnodes.h:2278
bool agg_done
Definition: execnodes.h:2296
ScanState ss
Definition: execnodes.h:2276
ExprContext * ps_ExprContext
Definition: execnodes.h:1005
void ExecReScan(PlanState *node)
Definition: execAmi.c:78
#define MemSet(start, val, len)
Definition: c.h:1008
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1380
AggStatePerTrans pertrans
Definition: execnodes.h:2286
int projected_set
Definition: execnodes.h:2297
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
HeapTuple grp_firstTuple
Definition: execnodes.h:2314
int numtrans
Definition: execnodes.h:2279
bool hash_spill_mode
Definition: execnodes.h:2326
PlanState ps
Definition: execnodes.h:1377
int maxsets
Definition: execnodes.h:2306
bool table_filled
Definition: execnodes.h:2316
AggStrategy aggstrategy
Definition: execnodes.h:2280
#define outerPlanState(node)
Definition: execnodes.h:1062
Tuplesortstate ** sortstates
Definition: nodeAgg.h:154
Bitmapset * aggParams
Definition: plannodes.h:868
AggStatePerHash perhash
Definition: execnodes.h:2339
Bitmapset * chgParam
Definition: execnodes.h:998
#define outerPlan(node)
Definition: plannodes.h:171
TupleHashIterator hashiter
Definition: nodeAgg.h:304
bool input_done
Definition: execnodes.h:2295
ExprContext * hashcontext
Definition: execnodes.h:2287
bool * ecxt_aggnulls
Definition: execnodes.h:247
uintptr_t Datum
Definition: postgres.h:411
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:498
Plan * plan
Definition: execnodes.h:966
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:769
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1742
#define Max(x, y)
Definition: c.h:980
ExprContext ** aggcontexts
Definition: execnodes.h:2288
bool hash_ever_spilled
Definition: execnodes.h:2325
AggStatePerGroup * pergroups
Definition: execnodes.h:2312
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:438
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
uint64 hash_ngroups_current
Definition: execnodes.h:2334
Definition: plannodes.h:857
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1464
TupleHashTable hashtable
Definition: nodeAgg.h:303
static void build_hash_tables(AggState *aggstate)
Definition: nodeAgg.c:1470

◆ hash_agg_entry_size()

Size hash_agg_entry_size ( int  numTrans,
Size  tupleWidth,
Size  transitionSpace 
)

Definition at line 1695 of file nodeAgg.c.

References CHUNKHDRSZ, MAXALIGN, and SizeofMinimalTupleHeader.

Referenced by cost_agg(), estimate_hashagg_tablesize(), and ExecInitAgg().

1696 {
1697  Size tupleChunkSize;
1698  Size pergroupChunkSize;
1699  Size transitionChunkSize;
1700  Size tupleSize = (MAXALIGN(SizeofMinimalTupleHeader) +
1701  tupleWidth);
1702  Size pergroupSize = numTrans * sizeof(AggStatePerGroupData);
1703 
1704  tupleChunkSize = CHUNKHDRSZ + tupleSize;
1705 
1706  if (pergroupSize > 0)
1707  pergroupChunkSize = CHUNKHDRSZ + pergroupSize;
1708  else
1709  pergroupChunkSize = 0;
1710 
1711  if (transitionSpace > 0)
1712  transitionChunkSize = CHUNKHDRSZ + transitionSpace;
1713  else
1714  transitionChunkSize = 0;
1715 
1716  return
1717  sizeof(TupleHashEntryData) +
1718  tupleChunkSize +
1719  pergroupChunkSize +
1720  transitionChunkSize;
1721 }
struct TupleHashEntryData TupleHashEntryData
struct AggStatePerGroupData AggStatePerGroupData
#define SizeofMinimalTupleHeader
Definition: htup_details.h:648
size_t Size
Definition: c.h:540
#define MAXALIGN(LEN)
Definition: c.h:757
#define CHUNKHDRSZ
Definition: nodeAgg.c:312

◆ hash_agg_set_limits()

void hash_agg_set_limits ( double  hashentrysize,
double  input_groups,
int  used_bits,
Size mem_limit,
uint64 *  ngroups_limit,
int *  num_partitions 
)

Definition at line 1799 of file nodeAgg.c.

References get_hash_memory_limit(), hash_choose_num_partitions(), HASHAGG_READ_BUFFER_SIZE, and HASHAGG_WRITE_BUFFER_SIZE.

Referenced by agg_refill_hash_table(), cost_agg(), and ExecInitAgg().

1802 {
1803  int npartitions;
1804  Size partition_mem;
1805  Size hash_mem_limit = get_hash_memory_limit();
1806 
1807  /* if not expected to spill, use all of hash_mem */
1808  if (input_groups * hashentrysize <= hash_mem_limit)
1809  {
1810  if (num_partitions != NULL)
1811  *num_partitions = 0;
1812  *mem_limit = hash_mem_limit;
1813  *ngroups_limit = hash_mem_limit / hashentrysize;
1814  return;
1815  }
1816 
1817  /*
1818  * Calculate expected memory requirements for spilling, which is the size
1819  * of the buffers needed for all the tapes that need to be open at once.
1820  * Then, subtract that from the memory available for holding hash tables.
1821  */
1822  npartitions = hash_choose_num_partitions(input_groups,
1823  hashentrysize,
1824  used_bits,
1825  NULL);
1826  if (num_partitions != NULL)
1827  *num_partitions = npartitions;
1828 
1829  partition_mem =
1831  HASHAGG_WRITE_BUFFER_SIZE * npartitions;
1832 
1833  /*
1834  * Don't set the limit below 3/4 of hash_mem. In that case, we are at the
1835  * minimum number of partitions, so we aren't going to dramatically exceed
1836  * work mem anyway.
1837  */
1838  if (hash_mem_limit > 4 * partition_mem)
1839  *mem_limit = hash_mem_limit - partition_mem;
1840  else
1841  *mem_limit = hash_mem_limit * 0.75;
1842 
1843  if (*mem_limit > hashentrysize)
1844  *ngroups_limit = *mem_limit / hashentrysize;
1845  else
1846  *ngroups_limit = 1;
1847 }
static int hash_choose_num_partitions(double input_groups, double hashentrysize, int used_bits, int *log2_npartittions)
Definition: nodeAgg.c:1992
#define HASHAGG_READ_BUFFER_SIZE
Definition: nodeAgg.c:297
size_t Size
Definition: c.h:540
size_t get_hash_memory_limit(void)
Definition: nodeHash.c:3401
#define HASHAGG_WRITE_BUFFER_SIZE
Definition: nodeAgg.c:298