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 4667 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().

4668 {
4669  Size size;
4670 
4671  /* don't need this if not instrumenting or no workers */
4672  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4673  return;
4674 
4675  size = mul_size(pcxt->nworkers, sizeof(AggregateInstrumentation));
4676  size = add_size(size, offsetof(SharedAggInfo, sinstrument));
4677  shm_toc_estimate_chunk(&pcxt->estimator, size);
4678  shm_toc_estimate_keys(&pcxt->estimator, 1);
4679 }
Instrumentation * instrument
Definition: execnodes.h:977
ScanState ss
Definition: execnodes.h:2277
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:1378
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 4688 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().

4689 {
4690  Size size;
4691 
4692  /* don't need this if not instrumenting or no workers */
4693  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4694  return;
4695 
4696  size = offsetof(SharedAggInfo, sinstrument)
4697  + pcxt->nworkers * sizeof(AggregateInstrumentation);
4698  node->shared_info = shm_toc_allocate(pcxt->toc, size);
4699  /* ensure any unfilled slots will contain zeroes */
4700  memset(node->shared_info, 0, size);
4701  node->shared_info->num_workers = pcxt->nworkers;
4702  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
4703  node->shared_info);
4704 }
Instrumentation * instrument
Definition: execnodes.h:977
ScanState ss
Definition: execnodes.h:2277
int plan_node_id
Definition: plannodes.h:140
PlanState ps
Definition: execnodes.h:1378
struct AggregateInstrumentation AggregateInstrumentation
Plan * plan
Definition: execnodes.h:967
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:2349
#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 4713 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().

4714 {
4715  node->shared_info =
4716  shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
4717 }
ScanState ss
Definition: execnodes.h:2277
int plan_node_id
Definition: plannodes.h:140
PlanState ps
Definition: execnodes.h:1378
Plan * plan
Definition: execnodes.h:967
SharedAggInfo * shared_info
Definition: execnodes.h:2349
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

◆ ExecAggRetrieveInstrumentation()

void ExecAggRetrieveInstrumentation ( AggState node)

Definition at line 4726 of file nodeAgg.c.

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

Referenced by ExecParallelRetrieveInstrumentation().

4727 {
4728  Size size;
4729  SharedAggInfo *si;
4730 
4731  if (node->shared_info == NULL)
4732  return;
4733 
4734  size = offsetof(SharedAggInfo, sinstrument)
4736  si = palloc(size);
4737  memcpy(si, node->shared_info, size);
4738  node->shared_info = si;
4739 }
struct AggregateInstrumentation AggregateInstrumentation
size_t Size
Definition: c.h:540
void * palloc(Size size)
Definition: mcxt.c:1062
SharedAggInfo * shared_info
Definition: execnodes.h:2349
#define offsetof(type, field)
Definition: c.h:727

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

Definition at line 4278 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().

4279 {
4281  int transno;
4282  int numGroupingSets = Max(node->maxsets, 1);
4283  int setno;
4284 
4285  /*
4286  * When ending a parallel worker, copy the statistics gathered by the
4287  * worker back into shared memory so that it can be picked up by the main
4288  * process to report in EXPLAIN ANALYZE.
4289  */
4290  if (node->shared_info && IsParallelWorker())
4291  {
4293 
4294  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
4297  si->hash_disk_used = node->hash_disk_used;
4298  si->hash_mem_peak = node->hash_mem_peak;
4299  }
4300 
4301  /* Make sure we have closed any open tuplesorts */
4302 
4303  if (node->sort_in)
4304  tuplesort_end(node->sort_in);
4305  if (node->sort_out)
4306  tuplesort_end(node->sort_out);
4307 
4309 
4310  if (node->hash_metacxt != NULL)
4311  {
4313  node->hash_metacxt = NULL;
4314  }
4315 
4316  for (transno = 0; transno < node->numtrans; transno++)
4317  {
4318  AggStatePerTrans pertrans = &node->pertrans[transno];
4319 
4320  for (setno = 0; setno < numGroupingSets; setno++)
4321  {
4322  if (pertrans->sortstates[setno])
4323  tuplesort_end(pertrans->sortstates[setno]);
4324  }
4325  }
4326 
4327  /* And ensure any agg shutdown callbacks have been called */
4328  for (setno = 0; setno < numGroupingSets; setno++)
4329  ReScanExprContext(node->aggcontexts[setno]);
4330  if (node->hashcontext)
4332 
4333  /*
4334  * We don't actually free any ExprContexts here (see comment in
4335  * ExecFreeExprContext), just unlinking the output one from the plan node
4336  * suffices.
4337  */
4338  ExecFreeExprContext(&node->ss.ps);
4339 
4340  /* clean up tuple table */
4342 
4343  outerPlan = outerPlanState(node);
4344  ExecEndNode(outerPlan);
4345 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3114
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:2310
ScanState ss
Definition: execnodes.h:2277
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1381
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2253
AggStatePerTrans pertrans
Definition: execnodes.h:2287
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:650
int numtrans
Definition: execnodes.h:2280
PlanState ps
Definition: execnodes.h:1378
int maxsets
Definition: execnodes.h:2307
MemoryContext hash_metacxt
Definition: execnodes.h:2319
Tuplesortstate * sort_in
Definition: execnodes.h:2309
#define outerPlanState(node)
Definition: execnodes.h:1063
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:2338
#define outerPlan(node)
Definition: plannodes.h:171
ExprContext * hashcontext
Definition: execnodes.h:2288
uint64 hash_disk_used
Definition: execnodes.h:2337
#define Max(x, y)
Definition: c.h:980
ExprContext ** aggcontexts
Definition: execnodes.h:2289
#define Assert(condition)
Definition: c.h:804
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:438
Size hash_mem_peak
Definition: execnodes.h:2334
SharedAggInfo * shared_info
Definition: execnodes.h:2349
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1467

◆ ExecInitAgg()

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

Definition at line 3162 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().

3163 {
3164  AggState *aggstate;
3165  AggStatePerAgg peraggs;
3166  AggStatePerTrans pertransstates;
3167  AggStatePerGroup *pergroups;
3168  Plan *outerPlan;
3169  ExprContext *econtext;
3170  TupleDesc scanDesc;
3171  int max_aggno;
3172  int max_transno;
3173  int numaggrefs;
3174  int numaggs;
3175  int numtrans;
3176  int phase;
3177  int phaseidx;
3178  ListCell *l;
3179  Bitmapset *all_grouped_cols = NULL;
3180  int numGroupingSets = 1;
3181  int numPhases;
3182  int numHashes;
3183  int i = 0;
3184  int j = 0;
3185  bool use_hashing = (node->aggstrategy == AGG_HASHED ||
3186  node->aggstrategy == AGG_MIXED);
3187 
3188  /* check for unsupported flags */
3189  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
3190 
3191  /*
3192  * create state structure
3193  */
3194  aggstate = makeNode(AggState);
3195  aggstate->ss.ps.plan = (Plan *) node;
3196  aggstate->ss.ps.state = estate;
3197  aggstate->ss.ps.ExecProcNode = ExecAgg;
3198 
3199  aggstate->aggs = NIL;
3200  aggstate->numaggs = 0;
3201  aggstate->numtrans = 0;
3202  aggstate->aggstrategy = node->aggstrategy;
3203  aggstate->aggsplit = node->aggsplit;
3204  aggstate->maxsets = 0;
3205  aggstate->projected_set = -1;
3206  aggstate->current_set = 0;
3207  aggstate->peragg = NULL;
3208  aggstate->pertrans = NULL;
3209  aggstate->curperagg = NULL;
3210  aggstate->curpertrans = NULL;
3211  aggstate->input_done = false;
3212  aggstate->agg_done = false;
3213  aggstate->pergroups = NULL;
3214  aggstate->grp_firstTuple = NULL;
3215  aggstate->sort_in = NULL;
3216  aggstate->sort_out = NULL;
3217 
3218  /*
3219  * phases[0] always exists, but is dummy in sorted/plain mode
3220  */
3221  numPhases = (use_hashing ? 1 : 2);
3222  numHashes = (use_hashing ? 1 : 0);
3223 
3224  /*
3225  * Calculate the maximum number of grouping sets in any phase; this
3226  * determines the size of some allocations. Also calculate the number of
3227  * phases, since all hashed/mixed nodes contribute to only a single phase.
3228  */
3229  if (node->groupingSets)
3230  {
3231  numGroupingSets = list_length(node->groupingSets);
3232 
3233  foreach(l, node->chain)
3234  {
3235  Agg *agg = lfirst(l);
3236 
3237  numGroupingSets = Max(numGroupingSets,
3238  list_length(agg->groupingSets));
3239 
3240  /*
3241  * additional AGG_HASHED aggs become part of phase 0, but all
3242  * others add an extra phase.
3243  */
3244  if (agg->aggstrategy != AGG_HASHED)
3245  ++numPhases;
3246  else
3247  ++numHashes;
3248  }
3249  }
3250 
3251  aggstate->maxsets = numGroupingSets;
3252  aggstate->numphases = numPhases;
3253 
3254  aggstate->aggcontexts = (ExprContext **)
3255  palloc0(sizeof(ExprContext *) * numGroupingSets);
3256 
3257  /*
3258  * Create expression contexts. We need three or more, one for
3259  * per-input-tuple processing, one for per-output-tuple processing, one
3260  * for all the hashtables, and one for each grouping set. The per-tuple
3261  * memory context of the per-grouping-set ExprContexts (aggcontexts)
3262  * replaces the standalone memory context formerly used to hold transition
3263  * values. We cheat a little by using ExecAssignExprContext() to build
3264  * all of them.
3265  *
3266  * NOTE: the details of what is stored in aggcontexts and what is stored
3267  * in the regular per-query memory context are driven by a simple
3268  * decision: we want to reset the aggcontext at group boundaries (if not
3269  * hashing) and in ExecReScanAgg to recover no-longer-wanted space.
3270  */
3271  ExecAssignExprContext(estate, &aggstate->ss.ps);
3272  aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
3273 
3274  for (i = 0; i < numGroupingSets; ++i)
3275  {
3276  ExecAssignExprContext(estate, &aggstate->ss.ps);
3277  aggstate->aggcontexts[i] = aggstate->ss.ps.ps_ExprContext;
3278  }
3279 
3280  if (use_hashing)
3281  aggstate->hashcontext = CreateWorkExprContext(estate);
3282 
3283  ExecAssignExprContext(estate, &aggstate->ss.ps);
3284 
3285  /*
3286  * Initialize child nodes.
3287  *
3288  * If we are doing a hashed aggregation then the child plan does not need
3289  * to handle REWIND efficiently; see ExecReScanAgg.
3290  */
3291  if (node->aggstrategy == AGG_HASHED)
3292  eflags &= ~EXEC_FLAG_REWIND;
3293  outerPlan = outerPlan(node);
3294  outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags);
3295 
3296  /*
3297  * initialize source tuple type.
3298  */
3299  aggstate->ss.ps.outerops =
3301  &aggstate->ss.ps.outeropsfixed);
3302  aggstate->ss.ps.outeropsset = true;
3303 
3304  ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss,
3305  aggstate->ss.ps.outerops);
3306  scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
3307 
3308  /*
3309  * If there are more than two phases (including a potential dummy phase
3310  * 0), input will be resorted using tuplesort. Need a slot for that.
3311  */
3312  if (numPhases > 2)
3313  {
3314  aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc,
3316 
3317  /*
3318  * The output of the tuplesort, and the output from the outer child
3319  * might not use the same type of slot. In most cases the child will
3320  * be a Sort, and thus return a TTSOpsMinimalTuple type slot - but the
3321  * input can also be presorted due an index, in which case it could be
3322  * a different type of slot.
3323  *
3324  * XXX: For efficiency it would be good to instead/additionally
3325  * generate expressions with corresponding settings of outerops* for
3326  * the individual phases - deforming is often a bottleneck for
3327  * aggregations with lots of rows per group. If there's multiple
3328  * sorts, we know that all but the first use TTSOpsMinimalTuple (via
3329  * the nodeAgg.c internal tuplesort).
3330  */
3331  if (aggstate->ss.ps.outeropsfixed &&
3332  aggstate->ss.ps.outerops != &TTSOpsMinimalTuple)
3333  aggstate->ss.ps.outeropsfixed = false;
3334  }
3335 
3336  /*
3337  * Initialize result type, slot and projection.
3338  */
3340  ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
3341 
3342  /*
3343  * initialize child expressions
3344  *
3345  * We expect the parser to have checked that no aggs contain other agg
3346  * calls in their arguments (and just to be sure, we verify it again while
3347  * initializing the plan node). This would make no sense under SQL
3348  * semantics, and it's forbidden by the spec. Because it is true, we
3349  * don't need to worry about evaluating the aggs in any particular order.
3350  *
3351  * Note: execExpr.c finds Aggrefs for us, and adds them to aggstate->aggs.
3352  * Aggrefs in the qual are found here; Aggrefs in the targetlist are found
3353  * during ExecAssignProjectionInfo, above.
3354  */
3355  aggstate->ss.ps.qual =
3356  ExecInitQual(node->plan.qual, (PlanState *) aggstate);
3357 
3358  /*
3359  * We should now have found all Aggrefs in the targetlist and quals.
3360  */
3361  numaggrefs = list_length(aggstate->aggs);
3362  max_aggno = -1;
3363  max_transno = -1;
3364  foreach(l, aggstate->aggs)
3365  {
3366  Aggref *aggref = (Aggref *) lfirst(l);
3367 
3368  max_aggno = Max(max_aggno, aggref->aggno);
3369  max_transno = Max(max_transno, aggref->aggtransno);
3370  }
3371  numaggs = max_aggno + 1;
3372  numtrans = max_transno + 1;
3373 
3374  /*
3375  * For each phase, prepare grouping set data and fmgr lookup data for
3376  * compare functions. Accumulate all_grouped_cols in passing.
3377  */
3378  aggstate->phases = palloc0(numPhases * sizeof(AggStatePerPhaseData));
3379 
3380  aggstate->num_hashes = numHashes;
3381  if (numHashes)
3382  {
3383  aggstate->perhash = palloc0(sizeof(AggStatePerHashData) * numHashes);
3384  aggstate->phases[0].numsets = 0;
3385  aggstate->phases[0].gset_lengths = palloc(numHashes * sizeof(int));
3386  aggstate->phases[0].grouped_cols = palloc(numHashes * sizeof(Bitmapset *));
3387  }
3388 
3389  phase = 0;
3390  for (phaseidx = 0; phaseidx <= list_length(node->chain); ++phaseidx)
3391  {
3392  Agg *aggnode;
3393  Sort *sortnode;
3394 
3395  if (phaseidx > 0)
3396  {
3397  aggnode = list_nth_node(Agg, node->chain, phaseidx - 1);
3398  sortnode = castNode(Sort, aggnode->plan.lefttree);
3399  }
3400  else
3401  {
3402  aggnode = node;
3403  sortnode = NULL;
3404  }
3405 
3406  Assert(phase <= 1 || sortnode);
3407 
3408  if (aggnode->aggstrategy == AGG_HASHED
3409  || aggnode->aggstrategy == AGG_MIXED)
3410  {
3411  AggStatePerPhase phasedata = &aggstate->phases[0];
3412  AggStatePerHash perhash;
3413  Bitmapset *cols = NULL;
3414 
3415  Assert(phase == 0);
3416  i = phasedata->numsets++;
3417  perhash = &aggstate->perhash[i];
3418 
3419  /* phase 0 always points to the "real" Agg in the hash case */
3420  phasedata->aggnode = node;
3421  phasedata->aggstrategy = node->aggstrategy;
3422 
3423  /* but the actual Agg node representing this hash is saved here */
3424  perhash->aggnode = aggnode;
3425 
3426  phasedata->gset_lengths[i] = perhash->numCols = aggnode->numCols;
3427 
3428  for (j = 0; j < aggnode->numCols; ++j)
3429  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
3430 
3431  phasedata->grouped_cols[i] = cols;
3432 
3433  all_grouped_cols = bms_add_members(all_grouped_cols, cols);
3434  continue;
3435  }
3436  else
3437  {
3438  AggStatePerPhase phasedata = &aggstate->phases[++phase];
3439  int num_sets;
3440 
3441  phasedata->numsets = num_sets = list_length(aggnode->groupingSets);
3442 
3443  if (num_sets)
3444  {
3445  phasedata->gset_lengths = palloc(num_sets * sizeof(int));
3446  phasedata->grouped_cols = palloc(num_sets * sizeof(Bitmapset *));
3447 
3448  i = 0;
3449  foreach(l, aggnode->groupingSets)
3450  {
3451  int current_length = list_length(lfirst(l));
3452  Bitmapset *cols = NULL;
3453 
3454  /* planner forces this to be correct */
3455  for (j = 0; j < current_length; ++j)
3456  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
3457 
3458  phasedata->grouped_cols[i] = cols;
3459  phasedata->gset_lengths[i] = current_length;
3460 
3461  ++i;
3462  }
3463 
3464  all_grouped_cols = bms_add_members(all_grouped_cols,
3465  phasedata->grouped_cols[0]);
3466  }
3467  else
3468  {
3469  Assert(phaseidx == 0);
3470 
3471  phasedata->gset_lengths = NULL;
3472  phasedata->grouped_cols = NULL;
3473  }
3474 
3475  /*
3476  * If we are grouping, precompute fmgr lookup data for inner loop.
3477  */
3478  if (aggnode->aggstrategy == AGG_SORTED)
3479  {
3480  int i = 0;
3481 
3482  Assert(aggnode->numCols > 0);
3483 
3484  /*
3485  * Build a separate function for each subset of columns that
3486  * need to be compared.
3487  */
3488  phasedata->eqfunctions =
3489  (ExprState **) palloc0(aggnode->numCols * sizeof(ExprState *));
3490 
3491  /* for each grouping set */
3492  for (i = 0; i < phasedata->numsets; i++)
3493  {
3494  int length = phasedata->gset_lengths[i];
3495 
3496  if (phasedata->eqfunctions[length - 1] != NULL)
3497  continue;
3498 
3499  phasedata->eqfunctions[length - 1] =
3500  execTuplesMatchPrepare(scanDesc,
3501  length,
3502  aggnode->grpColIdx,
3503  aggnode->grpOperators,
3504  aggnode->grpCollations,
3505  (PlanState *) aggstate);
3506  }
3507 
3508  /* and for all grouped columns, unless already computed */
3509  if (phasedata->eqfunctions[aggnode->numCols - 1] == NULL)
3510  {
3511  phasedata->eqfunctions[aggnode->numCols - 1] =
3512  execTuplesMatchPrepare(scanDesc,
3513  aggnode->numCols,
3514  aggnode->grpColIdx,
3515  aggnode->grpOperators,
3516  aggnode->grpCollations,
3517  (PlanState *) aggstate);
3518  }
3519  }
3520 
3521  phasedata->aggnode = aggnode;
3522  phasedata->aggstrategy = aggnode->aggstrategy;
3523  phasedata->sortnode = sortnode;
3524  }
3525  }
3526 
3527  /*
3528  * Convert all_grouped_cols to a descending-order list.
3529  */
3530  i = -1;
3531  while ((i = bms_next_member(all_grouped_cols, i)) >= 0)
3532  aggstate->all_grouped_cols = lcons_int(i, aggstate->all_grouped_cols);
3533 
3534  /*
3535  * Set up aggregate-result storage in the output expr context, and also
3536  * allocate my private per-agg working storage
3537  */
3538  econtext = aggstate->ss.ps.ps_ExprContext;
3539  econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
3540  econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numaggs);
3541 
3542  peraggs = (AggStatePerAgg) palloc0(sizeof(AggStatePerAggData) * numaggs);
3543  pertransstates = (AggStatePerTrans) palloc0(sizeof(AggStatePerTransData) * numtrans);
3544 
3545  aggstate->peragg = peraggs;
3546  aggstate->pertrans = pertransstates;
3547 
3548 
3549  aggstate->all_pergroups =
3551  * (numGroupingSets + numHashes));
3552  pergroups = aggstate->all_pergroups;
3553 
3554  if (node->aggstrategy != AGG_HASHED)
3555  {
3556  for (i = 0; i < numGroupingSets; i++)
3557  {
3558  pergroups[i] = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData)
3559  * numaggs);
3560  }
3561 
3562  aggstate->pergroups = pergroups;
3563  pergroups += numGroupingSets;
3564  }
3565 
3566  /*
3567  * Hashing can only appear in the initial phase.
3568  */
3569  if (use_hashing)
3570  {
3571  Plan *outerplan = outerPlan(node);
3572  uint64 totalGroups = 0;
3573  int i;
3574 
3575  aggstate->hash_metacxt = AllocSetContextCreate(aggstate->ss.ps.state->es_query_cxt,
3576  "HashAgg meta context",
3578  aggstate->hash_spill_rslot = ExecInitExtraTupleSlot(estate, scanDesc,
3580  aggstate->hash_spill_wslot = ExecInitExtraTupleSlot(estate, scanDesc,
3581  &TTSOpsVirtual);
3582 
3583  /* this is an array of pointers, not structures */
3584  aggstate->hash_pergroup = pergroups;
3585 
3586  aggstate->hashentrysize = hash_agg_entry_size(aggstate->numtrans,
3587  outerplan->plan_width,
3588  node->transitionSpace);
3589 
3590  /*
3591  * Consider all of the grouping sets together when setting the limits
3592  * and estimating the number of partitions. This can be inaccurate
3593  * when there is more than one grouping set, but should still be
3594  * reasonable.
3595  */
3596  for (i = 0; i < aggstate->num_hashes; i++)
3597  totalGroups += aggstate->perhash[i].aggnode->numGroups;
3598 
3599  hash_agg_set_limits(aggstate->hashentrysize, totalGroups, 0,
3600  &aggstate->hash_mem_limit,
3601  &aggstate->hash_ngroups_limit,
3602  &aggstate->hash_planned_partitions);
3603  find_hash_columns(aggstate);
3604 
3605  /* Skip massive memory allocation if we are just doing EXPLAIN */
3606  if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
3607  build_hash_tables(aggstate);
3608 
3609  aggstate->table_filled = false;
3610 
3611  /* Initialize this to 1, meaning nothing spilled, yet */
3612  aggstate->hash_batches_used = 1;
3613  }
3614 
3615  /*
3616  * Initialize current phase-dependent values to initial phase. The initial
3617  * phase is 1 (first sort pass) for all strategies that use sorting (if
3618  * hashing is being done too, then phase 0 is processed last); but if only
3619  * hashing is being done, then phase 0 is all there is.
3620  */
3621  if (node->aggstrategy == AGG_HASHED)
3622  {
3623  aggstate->current_phase = 0;
3624  initialize_phase(aggstate, 0);
3625  select_current_set(aggstate, 0, true);
3626  }
3627  else
3628  {
3629  aggstate->current_phase = 1;
3630  initialize_phase(aggstate, 1);
3631  select_current_set(aggstate, 0, false);
3632  }
3633 
3634  /*
3635  * Perform lookups of aggregate function info, and initialize the
3636  * unchanging fields of the per-agg and per-trans data.
3637  */
3638  foreach(l, aggstate->aggs)
3639  {
3640  Aggref *aggref = lfirst(l);
3641  AggStatePerAgg peragg;
3642  AggStatePerTrans pertrans;
3643  Oid aggTransFnInputTypes[FUNC_MAX_ARGS];
3644  int numAggTransFnArgs;
3645  int numDirectArgs;
3646  HeapTuple aggTuple;
3647  Form_pg_aggregate aggform;
3648  AclResult aclresult;
3649  Oid finalfn_oid;
3650  Oid serialfn_oid,
3651  deserialfn_oid;
3652  Oid aggOwner;
3653  Expr *finalfnexpr;
3654  Oid aggtranstype;
3655 
3656  /* Planner should have assigned aggregate to correct level */
3657  Assert(aggref->agglevelsup == 0);
3658  /* ... and the split mode should match */
3659  Assert(aggref->aggsplit == aggstate->aggsplit);
3660 
3661  peragg = &peraggs[aggref->aggno];
3662 
3663  /* Check if we initialized the state for this aggregate already. */
3664  if (peragg->aggref != NULL)
3665  continue;
3666 
3667  peragg->aggref = aggref;
3668  peragg->transno = aggref->aggtransno;
3669 
3670  /* Fetch the pg_aggregate row */
3671  aggTuple = SearchSysCache1(AGGFNOID,
3672  ObjectIdGetDatum(aggref->aggfnoid));
3673  if (!HeapTupleIsValid(aggTuple))
3674  elog(ERROR, "cache lookup failed for aggregate %u",
3675  aggref->aggfnoid);
3676  aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
3677 
3678  /* Check permission to call aggregate function */
3679  aclresult = pg_proc_aclcheck(aggref->aggfnoid, GetUserId(),
3680  ACL_EXECUTE);
3681  if (aclresult != ACLCHECK_OK)
3682  aclcheck_error(aclresult, OBJECT_AGGREGATE,
3683  get_func_name(aggref->aggfnoid));
3685 
3686  /* planner recorded transition state type in the Aggref itself */
3687  aggtranstype = aggref->aggtranstype;
3688  Assert(OidIsValid(aggtranstype));
3689 
3690  /* Final function only required if we're finalizing the aggregates */
3691  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
3692  peragg->finalfn_oid = finalfn_oid = InvalidOid;
3693  else
3694  peragg->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
3695 
3696  serialfn_oid = InvalidOid;
3697  deserialfn_oid = InvalidOid;
3698 
3699  /*
3700  * Check if serialization/deserialization is required. We only do it
3701  * for aggregates that have transtype INTERNAL.
3702  */
3703  if (aggtranstype == INTERNALOID)
3704  {
3705  /*
3706  * The planner should only have generated a serialize agg node if
3707  * every aggregate with an INTERNAL state has a serialization
3708  * function. Verify that.
3709  */
3710  if (DO_AGGSPLIT_SERIALIZE(aggstate->aggsplit))
3711  {
3712  /* serialization only valid when not running finalfn */
3714 
3715  if (!OidIsValid(aggform->aggserialfn))
3716  elog(ERROR, "serialfunc not provided for serialization aggregation");
3717  serialfn_oid = aggform->aggserialfn;
3718  }
3719 
3720  /* Likewise for deserialization functions */
3721  if (DO_AGGSPLIT_DESERIALIZE(aggstate->aggsplit))
3722  {
3723  /* deserialization only valid when combining states */
3724  Assert(DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
3725 
3726  if (!OidIsValid(aggform->aggdeserialfn))
3727  elog(ERROR, "deserialfunc not provided for deserialization aggregation");
3728  deserialfn_oid = aggform->aggdeserialfn;
3729  }
3730  }
3731 
3732  /* Check that aggregate owner has permission to call component fns */
3733  {
3734  HeapTuple procTuple;
3735 
3736  procTuple = SearchSysCache1(PROCOID,
3737  ObjectIdGetDatum(aggref->aggfnoid));
3738  if (!HeapTupleIsValid(procTuple))
3739  elog(ERROR, "cache lookup failed for function %u",
3740  aggref->aggfnoid);
3741  aggOwner = ((Form_pg_proc) GETSTRUCT(procTuple))->proowner;
3742  ReleaseSysCache(procTuple);
3743 
3744  if (OidIsValid(finalfn_oid))
3745  {
3746  aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
3747  ACL_EXECUTE);
3748  if (aclresult != ACLCHECK_OK)
3749  aclcheck_error(aclresult, OBJECT_FUNCTION,
3750  get_func_name(finalfn_oid));
3751  InvokeFunctionExecuteHook(finalfn_oid);
3752  }
3753  if (OidIsValid(serialfn_oid))
3754  {
3755  aclresult = pg_proc_aclcheck(serialfn_oid, aggOwner,
3756  ACL_EXECUTE);
3757  if (aclresult != ACLCHECK_OK)
3758  aclcheck_error(aclresult, OBJECT_FUNCTION,
3759  get_func_name(serialfn_oid));
3760  InvokeFunctionExecuteHook(serialfn_oid);
3761  }
3762  if (OidIsValid(deserialfn_oid))
3763  {
3764  aclresult = pg_proc_aclcheck(deserialfn_oid, aggOwner,
3765  ACL_EXECUTE);
3766  if (aclresult != ACLCHECK_OK)
3767  aclcheck_error(aclresult, OBJECT_FUNCTION,
3768  get_func_name(deserialfn_oid));
3769  InvokeFunctionExecuteHook(deserialfn_oid);
3770  }
3771  }
3772 
3773  /*
3774  * Get actual datatypes of the (nominal) aggregate inputs. These
3775  * could be different from the agg's declared input types, when the
3776  * agg accepts ANY or a polymorphic type.
3777  */
3778  numAggTransFnArgs = get_aggregate_argtypes(aggref,
3779  aggTransFnInputTypes);
3780 
3781  /* Count the "direct" arguments, if any */
3782  numDirectArgs = list_length(aggref->aggdirectargs);
3783 
3784  /* Detect how many arguments to pass to the finalfn */
3785  if (aggform->aggfinalextra)
3786  peragg->numFinalArgs = numAggTransFnArgs + 1;
3787  else
3788  peragg->numFinalArgs = numDirectArgs + 1;
3789 
3790  /* Initialize any direct-argument expressions */
3791  peragg->aggdirectargs = ExecInitExprList(aggref->aggdirectargs,
3792  (PlanState *) aggstate);
3793 
3794  /*
3795  * build expression trees using actual argument & result types for the
3796  * finalfn, if it exists and is required.
3797  */
3798  if (OidIsValid(finalfn_oid))
3799  {
3800  build_aggregate_finalfn_expr(aggTransFnInputTypes,
3801  peragg->numFinalArgs,
3802  aggtranstype,
3803  aggref->aggtype,
3804  aggref->inputcollid,
3805  finalfn_oid,
3806  &finalfnexpr);
3807  fmgr_info(finalfn_oid, &peragg->finalfn);
3808  fmgr_info_set_expr((Node *) finalfnexpr, &peragg->finalfn);
3809  }
3810 
3811  /* get info about the output value's datatype */
3812  get_typlenbyval(aggref->aggtype,
3813  &peragg->resulttypeLen,
3814  &peragg->resulttypeByVal);
3815 
3816  /*
3817  * Build working state for invoking the transition function, if we
3818  * haven't done it already.
3819  */
3820  pertrans = &pertransstates[aggref->aggtransno];
3821  if (pertrans->aggref == NULL)
3822  {
3823  Datum textInitVal;
3824  Datum initValue;
3825  bool initValueIsNull;
3826  Oid transfn_oid;
3827 
3828  /*
3829  * If this aggregation is performing state combines, then instead
3830  * of using the transition function, we'll use the combine
3831  * function.
3832  */
3833  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
3834  {
3835  transfn_oid = aggform->aggcombinefn;
3836 
3837  /* If not set then the planner messed up */
3838  if (!OidIsValid(transfn_oid))
3839  elog(ERROR, "combinefn not set for aggregate function");
3840  }
3841  else
3842  transfn_oid = aggform->aggtransfn;
3843 
3844  aclresult = pg_proc_aclcheck(transfn_oid, aggOwner, ACL_EXECUTE);
3845  if (aclresult != ACLCHECK_OK)
3846  aclcheck_error(aclresult, OBJECT_FUNCTION,
3847  get_func_name(transfn_oid));
3848  InvokeFunctionExecuteHook(transfn_oid);
3849 
3850  /*
3851  * initval is potentially null, so don't try to access it as a
3852  * struct field. Must do it the hard way with SysCacheGetAttr.
3853  */
3854  textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
3855  Anum_pg_aggregate_agginitval,
3856  &initValueIsNull);
3857  if (initValueIsNull)
3858  initValue = (Datum) 0;
3859  else
3860  initValue = GetAggInitVal(textInitVal, aggtranstype);
3861 
3862  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
3863  {
3864  Oid combineFnInputTypes[] = {aggtranstype,
3865  aggtranstype};
3866 
3867  /*
3868  * When combining there's only one input, the to-be-combined
3869  * transition value. The transition value is not counted
3870  * here.
3871  */
3872  pertrans->numTransInputs = 1;
3873 
3874  /* aggcombinefn always has two arguments of aggtranstype */
3875  build_pertrans_for_aggref(pertrans, aggstate, estate,
3876  aggref, transfn_oid, aggtranstype,
3877  serialfn_oid, deserialfn_oid,
3878  initValue, initValueIsNull,
3879  combineFnInputTypes, 2);
3880 
3881  /*
3882  * Ensure that a combine function to combine INTERNAL states
3883  * is not strict. This should have been checked during CREATE
3884  * AGGREGATE, but the strict property could have been changed
3885  * since then.
3886  */
3887  if (pertrans->transfn.fn_strict && aggtranstype == INTERNALOID)
3888  ereport(ERROR,
3889  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
3890  errmsg("combine function with transition type %s must not be declared STRICT",
3891  format_type_be(aggtranstype))));
3892  }
3893  else
3894  {
3895  /* Detect how many arguments to pass to the transfn */
3896  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
3897  pertrans->numTransInputs = list_length(aggref->args);
3898  else
3899  pertrans->numTransInputs = numAggTransFnArgs;
3900 
3901  build_pertrans_for_aggref(pertrans, aggstate, estate,
3902  aggref, transfn_oid, aggtranstype,
3903  serialfn_oid, deserialfn_oid,
3904  initValue, initValueIsNull,
3905  aggTransFnInputTypes,
3906  numAggTransFnArgs);
3907 
3908  /*
3909  * If the transfn is strict and the initval is NULL, make sure
3910  * input type and transtype are the same (or at least
3911  * binary-compatible), so that it's OK to use the first
3912  * aggregated input value as the initial transValue. This
3913  * should have been checked at agg definition time, but we
3914  * must check again in case the transfn's strictness property
3915  * has been changed.
3916  */
3917  if (pertrans->transfn.fn_strict && pertrans->initValueIsNull)
3918  {
3919  if (numAggTransFnArgs <= numDirectArgs ||
3920  !IsBinaryCoercible(aggTransFnInputTypes[numDirectArgs],
3921  aggtranstype))
3922  ereport(ERROR,
3923  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
3924  errmsg("aggregate %u needs to have compatible input type and transition type",
3925  aggref->aggfnoid)));
3926  }
3927  }
3928  }
3929  else
3930  pertrans->aggshared = true;
3931  ReleaseSysCache(aggTuple);
3932  }
3933 
3934  /*
3935  * Update aggstate->numaggs to be the number of unique aggregates found.
3936  * Also set numstates to the number of unique transition states found.
3937  */
3938  aggstate->numaggs = numaggs;
3939  aggstate->numtrans = numtrans;
3940 
3941  /*
3942  * Last, check whether any more aggregates got added onto the node while
3943  * we processed the expressions for the aggregate arguments (including not
3944  * only the regular arguments and FILTER expressions handled immediately
3945  * above, but any direct arguments we might've handled earlier). If so,
3946  * we have nested aggregate functions, which is semantically nonsensical,
3947  * so complain. (This should have been caught by the parser, so we don't
3948  * need to work hard on a helpful error message; but we defend against it
3949  * here anyway, just to be sure.)
3950  */
3951  if (numaggrefs != list_length(aggstate->aggs))
3952  ereport(ERROR,
3953  (errcode(ERRCODE_GROUPING_ERROR),
3954  errmsg("aggregate function calls cannot be nested")));
3955 
3956  /*
3957  * Build expressions doing all the transition work at once. We build a
3958  * different one for each phase, as the number of transition function
3959  * invocation can differ between phases. Note this'll work both for
3960  * transition and combination functions (although there'll only be one
3961  * phase in the latter case).
3962  */
3963  for (phaseidx = 0; phaseidx < aggstate->numphases; phaseidx++)
3964  {
3965  AggStatePerPhase phase = &aggstate->phases[phaseidx];
3966  bool dohash = false;
3967  bool dosort = false;
3968 
3969  /* phase 0 doesn't necessarily exist */
3970  if (!phase->aggnode)
3971  continue;
3972 
3973  if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 1)
3974  {
3975  /*
3976  * Phase one, and only phase one, in a mixed agg performs both
3977  * sorting and aggregation.
3978  */
3979  dohash = true;
3980  dosort = true;
3981  }
3982  else if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 0)
3983  {
3984  /*
3985  * No need to compute a transition function for an AGG_MIXED phase
3986  * 0 - the contents of the hashtables will have been computed
3987  * during phase 1.
3988  */
3989  continue;
3990  }
3991  else if (phase->aggstrategy == AGG_PLAIN ||
3992  phase->aggstrategy == AGG_SORTED)
3993  {
3994  dohash = false;
3995  dosort = true;
3996  }
3997  else if (phase->aggstrategy == AGG_HASHED)
3998  {
3999  dohash = true;
4000  dosort = false;
4001  }
4002  else
4003  Assert(false);
4004 
4005  phase->evaltrans = ExecBuildAggTrans(aggstate, phase, dosort, dohash,
4006  false);
4007 
4008  /* cache compiled expression for outer slot without NULL check */
4009  phase->evaltrans_cache[0][0] = phase->evaltrans;
4010  }
4011 
4012  return aggstate;
4013 }
struct AggStatePerTransData * AggStatePerTrans
Definition: execnodes.h:2270
ExprState ** eqfunctions
Definition: nodeAgg.h:278
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:2341
#define NIL
Definition: pg_list.h:65
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:2271
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:457
int numCols
Definition: plannodes.h:865
List * qual
Definition: plannodes.h:142
AggStatePerPhase phases
Definition: execnodes.h:2308
double hashentrysize
Definition: execnodes.h:2333
#define AllocSetContextCreate
Definition: memutils.h:173
Datum * ecxt_aggvalues
Definition: execnodes.h:246
uint64 hash_ngroups_limit
Definition: execnodes.h:2330
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:866
uint64 transitionSpace
Definition: plannodes.h:870
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:2279
Oid GetUserId(void)
Definition: miscinit.c:495
bool agg_done
Definition: execnodes.h:2297
#define castNode(_type_, nodeptr)
Definition: nodes.h:607
Oid * grpCollations
Definition: plannodes.h:868
TupleTableSlot * sort_slot
Definition: execnodes.h:2311
List * all_grouped_cols
Definition: execnodes.h:2302
Tuplesortstate * sort_out
Definition: execnodes.h:2310
ScanState ss
Definition: execnodes.h:2277
ExprContext * ps_ExprContext
Definition: execnodes.h:1006
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:2285
Definition: nodes.h:538
AggSplit aggsplit
Definition: execnodes.h:2282
static TupleTableSlot * ExecAgg(PlanState *pstate)
Definition: nodeAgg.c:2140
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:1381
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:4026
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:2074
TupleTableSlot * hash_spill_rslot
Definition: execnodes.h:2323
AggStatePerTrans pertrans
Definition: execnodes.h:2287
EState * state
Definition: execnodes.h:969
int projected_set
Definition: execnodes.h:2298
unsigned int Oid
Definition: postgres_ext.h:31
HeapTuple grp_firstTuple
Definition: execnodes.h:2315
Aggref * aggref
Definition: nodeAgg.h:187
int current_set
Definition: execnodes.h:2300
#define OidIsValid(objectId)
Definition: c.h:710
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:801
int numtrans
Definition: execnodes.h:2280
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:209
ExprContext * tmpcontext
Definition: execnodes.h:2290
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:1378
int maxsets
Definition: execnodes.h:2307
Size hash_agg_entry_size(int numTrans, Size tupleWidth, Size transitionSpace)
Definition: nodeAgg.c:1676
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:601
AggStrategy aggstrategy
Definition: plannodes.h:863
bool table_filled
Definition: execnodes.h:2317
AggStrategy aggstrategy
Definition: execnodes.h:2281
#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:2319
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
static void find_hash_columns(AggState *aggstate)
Definition: nodeAgg.c:1546
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
Tuplesortstate * sort_in
Definition: execnodes.h:2309
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define outerPlanState(node)
Definition: execnodes.h:1063
#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:2331
List * aggdirectargs
Definition: primnodes.h:329
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition: nodeAgg.c:4262
AggStatePerAgg curperagg
Definition: execnodes.h:2293
AggStatePerHash perhash
Definition: execnodes.h:2340
bool outeropsset
Definition: execnodes.h:1050
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:2338
#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:2318
Plan plan
Definition: plannodes.h:862
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1150
bool input_done
Definition: execnodes.h:2296
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
ExprContext * hashcontext
Definition: execnodes.h:2288
bool * ecxt_aggnulls
Definition: execnodes.h:248
void * palloc0(Size size)
Definition: mcxt.c:1093
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:973
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:411
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1198
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1411
List * groupingSets
Definition: plannodes.h:873
int16 resulttypeLen
Definition: nodeAgg.h:216
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:479
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
Plan * plan
Definition: execnodes.h:967
#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:2289
#define makeNode(_type_)
Definition: nodes.h:586
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:864
struct AggStatePerAggData * AggStatePerAgg
Definition: execnodes.h:2269
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
AggSplit aggsplit
Definition: primnodes.h:339
AggStatePerGroup * pergroups
Definition: execnodes.h:2313
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:869
#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:1046
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:2329
struct Plan * lefttree
Definition: plannodes.h:143
int numphases
Definition: execnodes.h:2284
ExprState * qual
Definition: execnodes.h:988
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:1780
Oid * grpOperators
Definition: plannodes.h:867
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
List * chain
Definition: plannodes.h:874
AggStatePerAgg peragg
Definition: execnodes.h:2286
#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:4720
int i
List * aggdirectargs
Definition: nodeAgg.h:210
Oid aggtranstype
Definition: primnodes.h:327
AggStatePerTrans curpertrans
Definition: execnodes.h:2295
Oid aggtype
Definition: primnodes.h:324
bool resulttypeByVal
Definition: nodeAgg.h:217
char aggkind
Definition: primnodes.h:337
Definition: plannodes.h:860
ExprContext * CreateWorkExprContext(EState *estate)
Definition: execUtils.c:316
List * aggs
Definition: execnodes.h:2278
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:1880
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:2324
static void build_hash_tables(AggState *aggstate)
Definition: nodeAgg.c:1451
const TupleTableSlotOps * outerops
Definition: execnodes.h:1042
ExprState * ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, bool doSort, bool doHash, bool nullcheck)
Definition: execExpr.c:3290
AggStatePerGroup * all_pergroups
Definition: execnodes.h:2346

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

Definition at line 4348 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().

4349 {
4350  ExprContext *econtext = node->ss.ps.ps_ExprContext;
4352  Agg *aggnode = (Agg *) node->ss.ps.plan;
4353  int transno;
4354  int numGroupingSets = Max(node->maxsets, 1);
4355  int setno;
4356 
4357  node->agg_done = false;
4358 
4359  if (node->aggstrategy == AGG_HASHED)
4360  {
4361  /*
4362  * In the hashed case, if we haven't yet built the hash table then we
4363  * can just return; nothing done yet, so nothing to undo. If subnode's
4364  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
4365  * else no reason to re-scan it at all.
4366  */
4367  if (!node->table_filled)
4368  return;
4369 
4370  /*
4371  * If we do have the hash table, and it never spilled, and the subplan
4372  * does not have any parameter changes, and none of our own parameter
4373  * changes affect input expressions of the aggregated functions, then
4374  * we can just rescan the existing hash table; no need to build it
4375  * again.
4376  */
4377  if (outerPlan->chgParam == NULL && !node->hash_ever_spilled &&
4378  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
4379  {
4381  &node->perhash[0].hashiter);
4382  select_current_set(node, 0, true);
4383  return;
4384  }
4385  }
4386 
4387  /* Make sure we have closed any open tuplesorts */
4388  for (transno = 0; transno < node->numtrans; transno++)
4389  {
4390  for (setno = 0; setno < numGroupingSets; setno++)
4391  {
4392  AggStatePerTrans pertrans = &node->pertrans[transno];
4393 
4394  if (pertrans->sortstates[setno])
4395  {
4396  tuplesort_end(pertrans->sortstates[setno]);
4397  pertrans->sortstates[setno] = NULL;
4398  }
4399  }
4400  }
4401 
4402  /*
4403  * We don't need to ReScanExprContext the output tuple context here;
4404  * ExecReScan already did it. But we do need to reset our per-grouping-set
4405  * contexts, which may have transvalues stored in them. (We use rescan
4406  * rather than just reset because transfns may have registered callbacks
4407  * that need to be run now.) For the AGG_HASHED case, see below.
4408  */
4409 
4410  for (setno = 0; setno < numGroupingSets; setno++)
4411  {
4412  ReScanExprContext(node->aggcontexts[setno]);
4413  }
4414 
4415  /* Release first tuple of group, if we have made a copy */
4416  if (node->grp_firstTuple != NULL)
4417  {
4419  node->grp_firstTuple = NULL;
4420  }
4422 
4423  /* Forget current agg values */
4424  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
4425  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
4426 
4427  /*
4428  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
4429  * the hashcontext. This used to be an issue, but now, resetting a context
4430  * automatically deletes sub-contexts too.
4431  */
4432  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
4433  {
4435 
4436  node->hash_ever_spilled = false;
4437  node->hash_spill_mode = false;
4438  node->hash_ngroups_current = 0;
4439 
4441  /* Rebuild an empty hash table */
4442  build_hash_tables(node);
4443  node->table_filled = false;
4444  /* iterator will be reset when the table is filled */
4445 
4446  hashagg_recompile_expressions(node, false, false);
4447  }
4448 
4449  if (node->aggstrategy != AGG_HASHED)
4450  {
4451  /*
4452  * Reset the per-group state (in particular, mark transvalues null)
4453  */
4454  for (setno = 0; setno < numGroupingSets; setno++)
4455  {
4456  MemSet(node->pergroups[setno], 0,
4457  sizeof(AggStatePerGroupData) * node->numaggs);
4458  }
4459 
4460  /* reset to phase 1 */
4461  initialize_phase(node, 1);
4462 
4463  node->input_done = false;
4464  node->projected_set = -1;
4465  }
4466 
4467  if (outerPlan->chgParam == NULL)
4468  ExecReScan(outerPlan);
4469 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3114
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:457
Datum * ecxt_aggvalues
Definition: execnodes.h:246
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
int numaggs
Definition: execnodes.h:2279
bool agg_done
Definition: execnodes.h:2297
ScanState ss
Definition: execnodes.h:2277
ExprContext * ps_ExprContext
Definition: execnodes.h:1006
void ExecReScan(PlanState *node)
Definition: execAmi.c:78
#define MemSet(start, val, len)
Definition: c.h:1008
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1381
AggStatePerTrans pertrans
Definition: execnodes.h:2287
int projected_set
Definition: execnodes.h:2298
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
HeapTuple grp_firstTuple
Definition: execnodes.h:2315
int numtrans
Definition: execnodes.h:2280
bool hash_spill_mode
Definition: execnodes.h:2327
PlanState ps
Definition: execnodes.h:1378
int maxsets
Definition: execnodes.h:2307
bool table_filled
Definition: execnodes.h:2317
AggStrategy aggstrategy
Definition: execnodes.h:2281
#define outerPlanState(node)
Definition: execnodes.h:1063
Tuplesortstate ** sortstates
Definition: nodeAgg.h:154
Bitmapset * aggParams
Definition: plannodes.h:871
AggStatePerHash perhash
Definition: execnodes.h:2340
Bitmapset * chgParam
Definition: execnodes.h:999
#define outerPlan(node)
Definition: plannodes.h:171
TupleHashIterator hashiter
Definition: nodeAgg.h:304
bool input_done
Definition: execnodes.h:2296
ExprContext * hashcontext
Definition: execnodes.h:2288
bool * ecxt_aggnulls
Definition: execnodes.h:248
uintptr_t Datum
Definition: postgres.h:411
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:479
Plan * plan
Definition: execnodes.h:967
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:770
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1723
#define Max(x, y)
Definition: c.h:980
ExprContext ** aggcontexts
Definition: execnodes.h:2289
bool hash_ever_spilled
Definition: execnodes.h:2326
AggStatePerGroup * pergroups
Definition: execnodes.h:2313
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:2335
Definition: plannodes.h:860
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1467
TupleHashTable hashtable
Definition: nodeAgg.h:303
static void build_hash_tables(AggState *aggstate)
Definition: nodeAgg.c:1451

◆ hash_agg_entry_size()

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

Definition at line 1676 of file nodeAgg.c.

References CHUNKHDRSZ, MAXALIGN, and SizeofMinimalTupleHeader.

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

1677 {
1678  Size tupleChunkSize;
1679  Size pergroupChunkSize;
1680  Size transitionChunkSize;
1681  Size tupleSize = (MAXALIGN(SizeofMinimalTupleHeader) +
1682  tupleWidth);
1683  Size pergroupSize = numTrans * sizeof(AggStatePerGroupData);
1684 
1685  tupleChunkSize = CHUNKHDRSZ + tupleSize;
1686 
1687  if (pergroupSize > 0)
1688  pergroupChunkSize = CHUNKHDRSZ + pergroupSize;
1689  else
1690  pergroupChunkSize = 0;
1691 
1692  if (transitionSpace > 0)
1693  transitionChunkSize = CHUNKHDRSZ + transitionSpace;
1694  else
1695  transitionChunkSize = 0;
1696 
1697  return
1698  sizeof(TupleHashEntryData) +
1699  tupleChunkSize +
1700  pergroupChunkSize +
1701  transitionChunkSize;
1702 }
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:321

◆ 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 1780 of file nodeAgg.c.

References get_hash_memory_limit(), hash_choose_num_partitions(), HASHAGG_READ_BUFFER_SIZE, HASHAGG_WRITE_BUFFER_SIZE, and HashAggSpill::npartitions.

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

1783 {
1784  int npartitions;
1785  Size partition_mem;
1786  Size hash_mem_limit = get_hash_memory_limit();
1787 
1788  /* if not expected to spill, use all of hash_mem */
1789  if (input_groups * hashentrysize <= hash_mem_limit)
1790  {
1791  if (num_partitions != NULL)
1792  *num_partitions = 0;
1793  *mem_limit = hash_mem_limit;
1794  *ngroups_limit = hash_mem_limit / hashentrysize;
1795  return;
1796  }
1797 
1798  /*
1799  * Calculate expected memory requirements for spilling, which is the size
1800  * of the buffers needed for all the tapes that need to be open at once.
1801  * Then, subtract that from the memory available for holding hash tables.
1802  */
1803  npartitions = hash_choose_num_partitions(input_groups,
1804  hashentrysize,
1805  used_bits,
1806  NULL);
1807  if (num_partitions != NULL)
1808  *num_partitions = npartitions;
1809 
1810  partition_mem =
1812  HASHAGG_WRITE_BUFFER_SIZE * npartitions;
1813 
1814  /*
1815  * Don't set the limit below 3/4 of hash_mem. In that case, we are at the
1816  * minimum number of partitions, so we aren't going to dramatically exceed
1817  * work mem anyway.
1818  */
1819  if (hash_mem_limit > 4 * partition_mem)
1820  *mem_limit = hash_mem_limit - partition_mem;
1821  else
1822  *mem_limit = hash_mem_limit * 0.75;
1823 
1824  if (*mem_limit > hashentrysize)
1825  *ngroups_limit = *mem_limit / hashentrysize;
1826  else
1827  *ngroups_limit = 1;
1828 }
static int hash_choose_num_partitions(double input_groups, double hashentrysize, int used_bits, int *log2_npartittions)
Definition: nodeAgg.c:1973
#define HASHAGG_READ_BUFFER_SIZE
Definition: nodeAgg.c:306
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:307