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

4969 {
4970  Size size;
4971 
4972  /* don't need this if not instrumenting or no workers */
4973  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4974  return;
4975 
4976  size = mul_size(pcxt->nworkers, sizeof(AggregateInstrumentation));
4977  size = add_size(size, offsetof(SharedAggInfo, sinstrument));
4978  shm_toc_estimate_chunk(&pcxt->estimator, size);
4979  shm_toc_estimate_keys(&pcxt->estimator, 1);
4980 }
Instrumentation * instrument
Definition: execnodes.h:949
ScanState ss
Definition: execnodes.h:2143
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:1328
Size mul_size(Size s1, Size s2)
Definition: shmem.c:515
Size add_size(Size s1, Size s2)
Definition: shmem.c:498
size_t Size
Definition: c.h:474
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
#define offsetof(type, field)
Definition: c.h:669

◆ ExecAggInitializeDSM()

void ExecAggInitializeDSM ( AggState node,
ParallelContext pcxt 
)

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

4990 {
4991  Size size;
4992 
4993  /* don't need this if not instrumenting or no workers */
4994  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4995  return;
4996 
4997  size = offsetof(SharedAggInfo, sinstrument)
4998  + pcxt->nworkers * sizeof(AggregateInstrumentation);
4999  node->shared_info = shm_toc_allocate(pcxt->toc, size);
5000  /* ensure any unfilled slots will contain zeroes */
5001  memset(node->shared_info, 0, size);
5002  node->shared_info->num_workers = pcxt->nworkers;
5003  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
5004  node->shared_info);
5005 }
Instrumentation * instrument
Definition: execnodes.h:949
ScanState ss
Definition: execnodes.h:2143
int plan_node_id
Definition: plannodes.h:135
PlanState ps
Definition: execnodes.h:1328
struct AggregateInstrumentation AggregateInstrumentation
Plan * plan
Definition: execnodes.h:939
size_t Size
Definition: c.h:474
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:2215
#define offsetof(type, field)
Definition: c.h:669
shm_toc * toc
Definition: parallel.h:45

◆ ExecAggInitializeWorker()

void ExecAggInitializeWorker ( AggState node,
ParallelWorkerContext pwcxt 
)

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

5015 {
5016  node->shared_info =
5017  shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
5018 }
ScanState ss
Definition: execnodes.h:2143
int plan_node_id
Definition: plannodes.h:135
PlanState ps
Definition: execnodes.h:1328
Plan * plan
Definition: execnodes.h:939
SharedAggInfo * shared_info
Definition: execnodes.h:2215
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

◆ ExecAggRetrieveInstrumentation()

void ExecAggRetrieveInstrumentation ( AggState node)

Definition at line 5027 of file nodeAgg.c.

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

Referenced by ExecParallelRetrieveInstrumentation().

5028 {
5029  Size size;
5030  SharedAggInfo *si;
5031 
5032  if (node->shared_info == NULL)
5033  return;
5034 
5035  size = offsetof(SharedAggInfo, sinstrument)
5037  si = palloc(size);
5038  memcpy(si, node->shared_info, size);
5039  node->shared_info = si;
5040 }
struct AggregateInstrumentation AggregateInstrumentation
size_t Size
Definition: c.h:474
void * palloc(Size size)
Definition: mcxt.c:950
SharedAggInfo * shared_info
Definition: execnodes.h:2215
#define offsetof(type, field)
Definition: c.h:669

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

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

4562 {
4564  int transno;
4565  int numGroupingSets = Max(node->maxsets, 1);
4566  int setno;
4567 
4568  /*
4569  * When ending a parallel worker, copy the statistics gathered by the
4570  * worker back into shared memory so that it can be picked up by the main
4571  * process to report in EXPLAIN ANALYZE.
4572  */
4573  if (node->shared_info && IsParallelWorker())
4574  {
4576 
4577  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
4580  si->hash_disk_used = node->hash_disk_used;
4581  si->hash_mem_peak = node->hash_mem_peak;
4582  }
4583 
4584  /* Make sure we have closed any open tuplesorts */
4585 
4586  if (node->sort_in)
4587  tuplesort_end(node->sort_in);
4588  if (node->sort_out)
4589  tuplesort_end(node->sort_out);
4590 
4592 
4593  if (node->hash_metacxt != NULL)
4594  {
4596  node->hash_metacxt = NULL;
4597  }
4598 
4599  for (transno = 0; transno < node->numtrans; transno++)
4600  {
4601  AggStatePerTrans pertrans = &node->pertrans[transno];
4602 
4603  for (setno = 0; setno < numGroupingSets; setno++)
4604  {
4605  if (pertrans->sortstates[setno])
4606  tuplesort_end(pertrans->sortstates[setno]);
4607  }
4608  }
4609 
4610  /* And ensure any agg shutdown callbacks have been called */
4611  for (setno = 0; setno < numGroupingSets; setno++)
4612  ReScanExprContext(node->aggcontexts[setno]);
4613  if (node->hashcontext)
4615 
4616  /*
4617  * We don't actually free any ExprContexts here (see comment in
4618  * ExecFreeExprContext), just unlinking the output one from the plan node
4619  * suffices.
4620  */
4621  ExecFreeExprContext(&node->ss.ps);
4622 
4623  /* clean up tuple table */
4625 
4626  outerPlan = outerPlanState(node);
4627  ExecEndNode(outerPlan);
4628 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3186
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:212
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:543
Tuplesortstate * sort_out
Definition: execnodes.h:2176
ScanState ss
Definition: execnodes.h:2143
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1331
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2119
AggStatePerTrans pertrans
Definition: execnodes.h:2153
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:649
int numtrans
Definition: execnodes.h:2146
PlanState ps
Definition: execnodes.h:1328
int maxsets
Definition: execnodes.h:2173
MemoryContext hash_metacxt
Definition: execnodes.h:2185
Tuplesortstate * sort_in
Definition: execnodes.h:2175
#define outerPlanState(node)
Definition: execnodes.h:1033
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:2204
#define outerPlan(node)
Definition: plannodes.h:166
ExprContext * hashcontext
Definition: execnodes.h:2154
uint64 hash_disk_used
Definition: execnodes.h:2203
#define Max(x, y)
Definition: c.h:922
ExprContext ** aggcontexts
Definition: execnodes.h:2155
#define Assert(condition)
Definition: c.h:746
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:437
Size hash_mem_peak
Definition: execnodes.h:2200
SharedAggInfo * shared_info
Definition: execnodes.h:2215
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1445

◆ ExecInitAgg()

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

Definition at line 3238 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::agglevelsup, AggrefExprState::aggno, AggStatePerPhaseData::aggnode, AggStatePerHashData::aggnode, AggStatePerAggData::aggref, AggrefExprState::aggref, AggState::aggs, AggStatePerTransData::aggshared, Aggref::aggsplit, Agg::aggsplit, AggState::aggsplit, AggStatePerPhaseData::aggstrategy, Agg::aggstrategy, AggState::aggstrategy, Aggref::aggtranstype, Aggref::aggtype, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, 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_MARK, EXEC_FLAG_REWIND, ExecAgg(), ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecBuildAggTrans(), ExecCreateScanSlotFromOuterPlan(), ExecGetResultSlotOps(), ExecInitExprList(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlotTL(), PlanState::ExecProcNode, execTuplesMatchPrepare(), AggStatePerAggData::finalfn, AggStatePerAggData::finalfn_oid, find_compatible_peragg(), find_compatible_pertrans(), find_hash_columns(), fmgr_info(), fmgr_info_set_expr, 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(), AggState::input_done, Aggref::inputcollid, InvalidOid, InvokeFunctionExecuteHook, 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, 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(), AggStatePerAggData::shareable, AggState::sort_in, AggState::sort_out, AggState::sort_slot, AggStatePerPhaseData::sortnode, AggState::ss, ScanState::ss_ScanTupleSlot, PlanState::state, SysCacheGetAttr(), AggState::tmpcontext, Agg::transitionSpace, AggStatePerAggData::transno, TupleTableSlot::tts_tupleDescriptor, TTSOpsMinimalTuple, and TTSOpsVirtual.

Referenced by ExecInitNode().

3239 {
3240  AggState *aggstate;
3241  AggStatePerAgg peraggs;
3242  AggStatePerTrans pertransstates;
3243  AggStatePerGroup *pergroups;
3244  Plan *outerPlan;
3245  ExprContext *econtext;
3246  TupleDesc scanDesc;
3247  int numaggs,
3248  transno,
3249  aggno;
3250  int phase;
3251  int phaseidx;
3252  ListCell *l;
3253  Bitmapset *all_grouped_cols = NULL;
3254  int numGroupingSets = 1;
3255  int numPhases;
3256  int numHashes;
3257  int i = 0;
3258  int j = 0;
3259  bool use_hashing = (node->aggstrategy == AGG_HASHED ||
3260  node->aggstrategy == AGG_MIXED);
3261 
3262  /* check for unsupported flags */
3263  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
3264 
3265  /*
3266  * create state structure
3267  */
3268  aggstate = makeNode(AggState);
3269  aggstate->ss.ps.plan = (Plan *) node;
3270  aggstate->ss.ps.state = estate;
3271  aggstate->ss.ps.ExecProcNode = ExecAgg;
3272 
3273  aggstate->aggs = NIL;
3274  aggstate->numaggs = 0;
3275  aggstate->numtrans = 0;
3276  aggstate->aggstrategy = node->aggstrategy;
3277  aggstate->aggsplit = node->aggsplit;
3278  aggstate->maxsets = 0;
3279  aggstate->projected_set = -1;
3280  aggstate->current_set = 0;
3281  aggstate->peragg = NULL;
3282  aggstate->pertrans = NULL;
3283  aggstate->curperagg = NULL;
3284  aggstate->curpertrans = NULL;
3285  aggstate->input_done = false;
3286  aggstate->agg_done = false;
3287  aggstate->pergroups = NULL;
3288  aggstate->grp_firstTuple = NULL;
3289  aggstate->sort_in = NULL;
3290  aggstate->sort_out = NULL;
3291 
3292  /*
3293  * phases[0] always exists, but is dummy in sorted/plain mode
3294  */
3295  numPhases = (use_hashing ? 1 : 2);
3296  numHashes = (use_hashing ? 1 : 0);
3297 
3298  /*
3299  * Calculate the maximum number of grouping sets in any phase; this
3300  * determines the size of some allocations. Also calculate the number of
3301  * phases, since all hashed/mixed nodes contribute to only a single phase.
3302  */
3303  if (node->groupingSets)
3304  {
3305  numGroupingSets = list_length(node->groupingSets);
3306 
3307  foreach(l, node->chain)
3308  {
3309  Agg *agg = lfirst(l);
3310 
3311  numGroupingSets = Max(numGroupingSets,
3312  list_length(agg->groupingSets));
3313 
3314  /*
3315  * additional AGG_HASHED aggs become part of phase 0, but all
3316  * others add an extra phase.
3317  */
3318  if (agg->aggstrategy != AGG_HASHED)
3319  ++numPhases;
3320  else
3321  ++numHashes;
3322  }
3323  }
3324 
3325  aggstate->maxsets = numGroupingSets;
3326  aggstate->numphases = numPhases;
3327 
3328  aggstate->aggcontexts = (ExprContext **)
3329  palloc0(sizeof(ExprContext *) * numGroupingSets);
3330 
3331  /*
3332  * Create expression contexts. We need three or more, one for
3333  * per-input-tuple processing, one for per-output-tuple processing, one
3334  * for all the hashtables, and one for each grouping set. The per-tuple
3335  * memory context of the per-grouping-set ExprContexts (aggcontexts)
3336  * replaces the standalone memory context formerly used to hold transition
3337  * values. We cheat a little by using ExecAssignExprContext() to build
3338  * all of them.
3339  *
3340  * NOTE: the details of what is stored in aggcontexts and what is stored
3341  * in the regular per-query memory context are driven by a simple
3342  * decision: we want to reset the aggcontext at group boundaries (if not
3343  * hashing) and in ExecReScanAgg to recover no-longer-wanted space.
3344  */
3345  ExecAssignExprContext(estate, &aggstate->ss.ps);
3346  aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
3347 
3348  for (i = 0; i < numGroupingSets; ++i)
3349  {
3350  ExecAssignExprContext(estate, &aggstate->ss.ps);
3351  aggstate->aggcontexts[i] = aggstate->ss.ps.ps_ExprContext;
3352  }
3353 
3354  if (use_hashing)
3355  aggstate->hashcontext = CreateWorkExprContext(estate);
3356 
3357  ExecAssignExprContext(estate, &aggstate->ss.ps);
3358 
3359  /*
3360  * Initialize child nodes.
3361  *
3362  * If we are doing a hashed aggregation then the child plan does not need
3363  * to handle REWIND efficiently; see ExecReScanAgg.
3364  */
3365  if (node->aggstrategy == AGG_HASHED)
3366  eflags &= ~EXEC_FLAG_REWIND;
3367  outerPlan = outerPlan(node);
3368  outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags);
3369 
3370  /*
3371  * initialize source tuple type.
3372  */
3373  aggstate->ss.ps.outerops =
3375  &aggstate->ss.ps.outeropsfixed);
3376  aggstate->ss.ps.outeropsset = true;
3377 
3378  ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss,
3379  aggstate->ss.ps.outerops);
3380  scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
3381 
3382  /*
3383  * If there are more than two phases (including a potential dummy phase
3384  * 0), input will be resorted using tuplesort. Need a slot for that.
3385  */
3386  if (numPhases > 2)
3387  {
3388  aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc,
3390 
3391  /*
3392  * The output of the tuplesort, and the output from the outer child
3393  * might not use the same type of slot. In most cases the child will
3394  * be a Sort, and thus return a TTSOpsMinimalTuple type slot - but the
3395  * input can also be presorted due an index, in which case it could be
3396  * a different type of slot.
3397  *
3398  * XXX: For efficiency it would be good to instead/additionally
3399  * generate expressions with corresponding settings of outerops* for
3400  * the individual phases - deforming is often a bottleneck for
3401  * aggregations with lots of rows per group. If there's multiple
3402  * sorts, we know that all but the first use TTSOpsMinimalTuple (via
3403  * the nodeAgg.c internal tuplesort).
3404  */
3405  if (aggstate->ss.ps.outeropsfixed &&
3406  aggstate->ss.ps.outerops != &TTSOpsMinimalTuple)
3407  aggstate->ss.ps.outeropsfixed = false;
3408  }
3409 
3410  /*
3411  * Initialize result type, slot and projection.
3412  */
3414  ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
3415 
3416  /*
3417  * initialize child expressions
3418  *
3419  * We expect the parser to have checked that no aggs contain other agg
3420  * calls in their arguments (and just to be sure, we verify it again while
3421  * initializing the plan node). This would make no sense under SQL
3422  * semantics, and it's forbidden by the spec. Because it is true, we
3423  * don't need to worry about evaluating the aggs in any particular order.
3424  *
3425  * Note: execExpr.c finds Aggrefs for us, and adds their AggrefExprState
3426  * nodes to aggstate->aggs. Aggrefs in the qual are found here; Aggrefs
3427  * in the targetlist are found during ExecAssignProjectionInfo, below.
3428  */
3429  aggstate->ss.ps.qual =
3430  ExecInitQual(node->plan.qual, (PlanState *) aggstate);
3431 
3432  /*
3433  * We should now have found all Aggrefs in the targetlist and quals.
3434  */
3435  numaggs = aggstate->numaggs;
3436  Assert(numaggs == list_length(aggstate->aggs));
3437 
3438  /*
3439  * For each phase, prepare grouping set data and fmgr lookup data for
3440  * compare functions. Accumulate all_grouped_cols in passing.
3441  */
3442  aggstate->phases = palloc0(numPhases * sizeof(AggStatePerPhaseData));
3443 
3444  aggstate->num_hashes = numHashes;
3445  if (numHashes)
3446  {
3447  aggstate->perhash = palloc0(sizeof(AggStatePerHashData) * numHashes);
3448  aggstate->phases[0].numsets = 0;
3449  aggstate->phases[0].gset_lengths = palloc(numHashes * sizeof(int));
3450  aggstate->phases[0].grouped_cols = palloc(numHashes * sizeof(Bitmapset *));
3451  }
3452 
3453  phase = 0;
3454  for (phaseidx = 0; phaseidx <= list_length(node->chain); ++phaseidx)
3455  {
3456  Agg *aggnode;
3457  Sort *sortnode;
3458 
3459  if (phaseidx > 0)
3460  {
3461  aggnode = list_nth_node(Agg, node->chain, phaseidx - 1);
3462  sortnode = castNode(Sort, aggnode->plan.lefttree);
3463  }
3464  else
3465  {
3466  aggnode = node;
3467  sortnode = NULL;
3468  }
3469 
3470  Assert(phase <= 1 || sortnode);
3471 
3472  if (aggnode->aggstrategy == AGG_HASHED
3473  || aggnode->aggstrategy == AGG_MIXED)
3474  {
3475  AggStatePerPhase phasedata = &aggstate->phases[0];
3476  AggStatePerHash perhash;
3477  Bitmapset *cols = NULL;
3478 
3479  Assert(phase == 0);
3480  i = phasedata->numsets++;
3481  perhash = &aggstate->perhash[i];
3482 
3483  /* phase 0 always points to the "real" Agg in the hash case */
3484  phasedata->aggnode = node;
3485  phasedata->aggstrategy = node->aggstrategy;
3486 
3487  /* but the actual Agg node representing this hash is saved here */
3488  perhash->aggnode = aggnode;
3489 
3490  phasedata->gset_lengths[i] = perhash->numCols = aggnode->numCols;
3491 
3492  for (j = 0; j < aggnode->numCols; ++j)
3493  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
3494 
3495  phasedata->grouped_cols[i] = cols;
3496 
3497  all_grouped_cols = bms_add_members(all_grouped_cols, cols);
3498  continue;
3499  }
3500  else
3501  {
3502  AggStatePerPhase phasedata = &aggstate->phases[++phase];
3503  int num_sets;
3504 
3505  phasedata->numsets = num_sets = list_length(aggnode->groupingSets);
3506 
3507  if (num_sets)
3508  {
3509  phasedata->gset_lengths = palloc(num_sets * sizeof(int));
3510  phasedata->grouped_cols = palloc(num_sets * sizeof(Bitmapset *));
3511 
3512  i = 0;
3513  foreach(l, aggnode->groupingSets)
3514  {
3515  int current_length = list_length(lfirst(l));
3516  Bitmapset *cols = NULL;
3517 
3518  /* planner forces this to be correct */
3519  for (j = 0; j < current_length; ++j)
3520  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
3521 
3522  phasedata->grouped_cols[i] = cols;
3523  phasedata->gset_lengths[i] = current_length;
3524 
3525  ++i;
3526  }
3527 
3528  all_grouped_cols = bms_add_members(all_grouped_cols,
3529  phasedata->grouped_cols[0]);
3530  }
3531  else
3532  {
3533  Assert(phaseidx == 0);
3534 
3535  phasedata->gset_lengths = NULL;
3536  phasedata->grouped_cols = NULL;
3537  }
3538 
3539  /*
3540  * If we are grouping, precompute fmgr lookup data for inner loop.
3541  */
3542  if (aggnode->aggstrategy == AGG_SORTED)
3543  {
3544  int i = 0;
3545 
3546  Assert(aggnode->numCols > 0);
3547 
3548  /*
3549  * Build a separate function for each subset of columns that
3550  * need to be compared.
3551  */
3552  phasedata->eqfunctions =
3553  (ExprState **) palloc0(aggnode->numCols * sizeof(ExprState *));
3554 
3555  /* for each grouping set */
3556  for (i = 0; i < phasedata->numsets; i++)
3557  {
3558  int length = phasedata->gset_lengths[i];
3559 
3560  if (phasedata->eqfunctions[length - 1] != NULL)
3561  continue;
3562 
3563  phasedata->eqfunctions[length - 1] =
3564  execTuplesMatchPrepare(scanDesc,
3565  length,
3566  aggnode->grpColIdx,
3567  aggnode->grpOperators,
3568  aggnode->grpCollations,
3569  (PlanState *) aggstate);
3570  }
3571 
3572  /* and for all grouped columns, unless already computed */
3573  if (phasedata->eqfunctions[aggnode->numCols - 1] == NULL)
3574  {
3575  phasedata->eqfunctions[aggnode->numCols - 1] =
3576  execTuplesMatchPrepare(scanDesc,
3577  aggnode->numCols,
3578  aggnode->grpColIdx,
3579  aggnode->grpOperators,
3580  aggnode->grpCollations,
3581  (PlanState *) aggstate);
3582  }
3583  }
3584 
3585  phasedata->aggnode = aggnode;
3586  phasedata->aggstrategy = aggnode->aggstrategy;
3587  phasedata->sortnode = sortnode;
3588  }
3589  }
3590 
3591  /*
3592  * Convert all_grouped_cols to a descending-order list.
3593  */
3594  i = -1;
3595  while ((i = bms_next_member(all_grouped_cols, i)) >= 0)
3596  aggstate->all_grouped_cols = lcons_int(i, aggstate->all_grouped_cols);
3597 
3598  /*
3599  * Set up aggregate-result storage in the output expr context, and also
3600  * allocate my private per-agg working storage
3601  */
3602  econtext = aggstate->ss.ps.ps_ExprContext;
3603  econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
3604  econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numaggs);
3605 
3606  peraggs = (AggStatePerAgg) palloc0(sizeof(AggStatePerAggData) * numaggs);
3607  pertransstates = (AggStatePerTrans) palloc0(sizeof(AggStatePerTransData) * numaggs);
3608 
3609  aggstate->peragg = peraggs;
3610  aggstate->pertrans = pertransstates;
3611 
3612 
3613  aggstate->all_pergroups =
3615  * (numGroupingSets + numHashes));
3616  pergroups = aggstate->all_pergroups;
3617 
3618  if (node->aggstrategy != AGG_HASHED)
3619  {
3620  for (i = 0; i < numGroupingSets; i++)
3621  {
3622  pergroups[i] = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData)
3623  * numaggs);
3624  }
3625 
3626  aggstate->pergroups = pergroups;
3627  pergroups += numGroupingSets;
3628  }
3629 
3630  /*
3631  * Hashing can only appear in the initial phase.
3632  */
3633  if (use_hashing)
3634  {
3635  Plan *outerplan = outerPlan(node);
3636  uint64 totalGroups = 0;
3637  int i;
3638 
3639  aggstate->hash_metacxt = AllocSetContextCreate(aggstate->ss.ps.state->es_query_cxt,
3640  "HashAgg meta context",
3642  aggstate->hash_spill_rslot = ExecInitExtraTupleSlot(estate, scanDesc,
3644  aggstate->hash_spill_wslot = ExecInitExtraTupleSlot(estate, scanDesc,
3645  &TTSOpsVirtual);
3646 
3647  /* this is an array of pointers, not structures */
3648  aggstate->hash_pergroup = pergroups;
3649 
3650  aggstate->hashentrysize = hash_agg_entry_size(aggstate->numtrans,
3651  outerplan->plan_width,
3652  node->transitionSpace);
3653 
3654  /*
3655  * Consider all of the grouping sets together when setting the limits
3656  * and estimating the number of partitions. This can be inaccurate
3657  * when there is more than one grouping set, but should still be
3658  * reasonable.
3659  */
3660  for (i = 0; i < aggstate->num_hashes; i++)
3661  totalGroups += aggstate->perhash[i].aggnode->numGroups;
3662 
3663  hash_agg_set_limits(aggstate->hashentrysize, totalGroups, 0,
3664  &aggstate->hash_mem_limit,
3665  &aggstate->hash_ngroups_limit,
3666  &aggstate->hash_planned_partitions);
3667  find_hash_columns(aggstate);
3668  build_hash_tables(aggstate);
3669  aggstate->table_filled = false;
3670 
3671  /* Initialize this to 1, meaning nothing spilled, yet */
3672  aggstate->hash_batches_used = 1;
3673  }
3674 
3675  /*
3676  * Initialize current phase-dependent values to initial phase. The initial
3677  * phase is 1 (first sort pass) for all strategies that use sorting (if
3678  * hashing is being done too, then phase 0 is processed last); but if only
3679  * hashing is being done, then phase 0 is all there is.
3680  */
3681  if (node->aggstrategy == AGG_HASHED)
3682  {
3683  aggstate->current_phase = 0;
3684  initialize_phase(aggstate, 0);
3685  select_current_set(aggstate, 0, true);
3686  }
3687  else
3688  {
3689  aggstate->current_phase = 1;
3690  initialize_phase(aggstate, 1);
3691  select_current_set(aggstate, 0, false);
3692  }
3693 
3694  /* -----------------
3695  * Perform lookups of aggregate function info, and initialize the
3696  * unchanging fields of the per-agg and per-trans data.
3697  *
3698  * We try to optimize by detecting duplicate aggregate functions so that
3699  * their state and final values are re-used, rather than needlessly being
3700  * re-calculated independently. We also detect aggregates that are not
3701  * the same, but which can share the same transition state.
3702  *
3703  * Scenarios:
3704  *
3705  * 1. Identical aggregate function calls appear in the query:
3706  *
3707  * SELECT SUM(x) FROM ... HAVING SUM(x) > 0
3708  *
3709  * Since these aggregates are identical, we only need to calculate
3710  * the value once. Both aggregates will share the same 'aggno' value.
3711  *
3712  * 2. Two different aggregate functions appear in the query, but the
3713  * aggregates have the same arguments, transition functions and
3714  * initial values (and, presumably, different final functions):
3715  *
3716  * SELECT AVG(x), STDDEV(x) FROM ...
3717  *
3718  * In this case we must create a new peragg for the varying aggregate,
3719  * and we need to call the final functions separately, but we need
3720  * only run the transition function once. (This requires that the
3721  * final functions be nondestructive of the transition state, but
3722  * that's required anyway for other reasons.)
3723  *
3724  * For either of these optimizations to be valid, all aggregate properties
3725  * used in the transition phase must be the same, including any modifiers
3726  * such as ORDER BY, DISTINCT and FILTER, and the arguments mustn't
3727  * contain any volatile functions.
3728  * -----------------
3729  */
3730  aggno = -1;
3731  transno = -1;
3732  foreach(l, aggstate->aggs)
3733  {
3734  AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(l);
3735  Aggref *aggref = aggrefstate->aggref;
3736  AggStatePerAgg peragg;
3737  AggStatePerTrans pertrans;
3738  int existing_aggno;
3739  int existing_transno;
3740  List *same_input_transnos;
3741  Oid inputTypes[FUNC_MAX_ARGS];
3742  int numArguments;
3743  int numDirectArgs;
3744  HeapTuple aggTuple;
3745  Form_pg_aggregate aggform;
3746  AclResult aclresult;
3747  Oid transfn_oid,
3748  finalfn_oid;
3749  bool shareable;
3750  Oid serialfn_oid,
3751  deserialfn_oid;
3752  Expr *finalfnexpr;
3753  Oid aggtranstype;
3754  Datum textInitVal;
3755  Datum initValue;
3756  bool initValueIsNull;
3757 
3758  /* Planner should have assigned aggregate to correct level */
3759  Assert(aggref->agglevelsup == 0);
3760  /* ... and the split mode should match */
3761  Assert(aggref->aggsplit == aggstate->aggsplit);
3762 
3763  /* 1. Check for already processed aggs which can be re-used */
3764  existing_aggno = find_compatible_peragg(aggref, aggstate, aggno,
3765  &same_input_transnos);
3766  if (existing_aggno != -1)
3767  {
3768  /*
3769  * Existing compatible agg found. so just point the Aggref to the
3770  * same per-agg struct.
3771  */
3772  aggrefstate->aggno = existing_aggno;
3773  continue;
3774  }
3775 
3776  /* Mark Aggref state node with assigned index in the result array */
3777  peragg = &peraggs[++aggno];
3778  peragg->aggref = aggref;
3779  aggrefstate->aggno = aggno;
3780 
3781  /* Fetch the pg_aggregate row */
3782  aggTuple = SearchSysCache1(AGGFNOID,
3783  ObjectIdGetDatum(aggref->aggfnoid));
3784  if (!HeapTupleIsValid(aggTuple))
3785  elog(ERROR, "cache lookup failed for aggregate %u",
3786  aggref->aggfnoid);
3787  aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
3788 
3789  /* Check permission to call aggregate function */
3790  aclresult = pg_proc_aclcheck(aggref->aggfnoid, GetUserId(),
3791  ACL_EXECUTE);
3792  if (aclresult != ACLCHECK_OK)
3793  aclcheck_error(aclresult, OBJECT_AGGREGATE,
3794  get_func_name(aggref->aggfnoid));
3796 
3797  /* planner recorded transition state type in the Aggref itself */
3798  aggtranstype = aggref->aggtranstype;
3799  Assert(OidIsValid(aggtranstype));
3800 
3801  /*
3802  * If this aggregation is performing state combines, then instead of
3803  * using the transition function, we'll use the combine function
3804  */
3805  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
3806  {
3807  transfn_oid = aggform->aggcombinefn;
3808 
3809  /* If not set then the planner messed up */
3810  if (!OidIsValid(transfn_oid))
3811  elog(ERROR, "combinefn not set for aggregate function");
3812  }
3813  else
3814  transfn_oid = aggform->aggtransfn;
3815 
3816  /* Final function only required if we're finalizing the aggregates */
3817  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
3818  peragg->finalfn_oid = finalfn_oid = InvalidOid;
3819  else
3820  peragg->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
3821 
3822  /*
3823  * If finalfn is marked read-write, we can't share transition states;
3824  * but it is okay to share states for AGGMODIFY_SHAREABLE aggs. Also,
3825  * if we're not executing the finalfn here, we can share regardless.
3826  */
3827  shareable = (aggform->aggfinalmodify != AGGMODIFY_READ_WRITE) ||
3828  (finalfn_oid == InvalidOid);
3829  peragg->shareable = shareable;
3830 
3831  serialfn_oid = InvalidOid;
3832  deserialfn_oid = InvalidOid;
3833 
3834  /*
3835  * Check if serialization/deserialization is required. We only do it
3836  * for aggregates that have transtype INTERNAL.
3837  */
3838  if (aggtranstype == INTERNALOID)
3839  {
3840  /*
3841  * The planner should only have generated a serialize agg node if
3842  * every aggregate with an INTERNAL state has a serialization
3843  * function. Verify that.
3844  */
3845  if (DO_AGGSPLIT_SERIALIZE(aggstate->aggsplit))
3846  {
3847  /* serialization only valid when not running finalfn */
3849 
3850  if (!OidIsValid(aggform->aggserialfn))
3851  elog(ERROR, "serialfunc not provided for serialization aggregation");
3852  serialfn_oid = aggform->aggserialfn;
3853  }
3854 
3855  /* Likewise for deserialization functions */
3856  if (DO_AGGSPLIT_DESERIALIZE(aggstate->aggsplit))
3857  {
3858  /* deserialization only valid when combining states */
3859  Assert(DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
3860 
3861  if (!OidIsValid(aggform->aggdeserialfn))
3862  elog(ERROR, "deserialfunc not provided for deserialization aggregation");
3863  deserialfn_oid = aggform->aggdeserialfn;
3864  }
3865  }
3866 
3867  /* Check that aggregate owner has permission to call component fns */
3868  {
3869  HeapTuple procTuple;
3870  Oid aggOwner;
3871 
3872  procTuple = SearchSysCache1(PROCOID,
3873  ObjectIdGetDatum(aggref->aggfnoid));
3874  if (!HeapTupleIsValid(procTuple))
3875  elog(ERROR, "cache lookup failed for function %u",
3876  aggref->aggfnoid);
3877  aggOwner = ((Form_pg_proc) GETSTRUCT(procTuple))->proowner;
3878  ReleaseSysCache(procTuple);
3879 
3880  aclresult = pg_proc_aclcheck(transfn_oid, aggOwner,
3881  ACL_EXECUTE);
3882  if (aclresult != ACLCHECK_OK)
3883  aclcheck_error(aclresult, OBJECT_FUNCTION,
3884  get_func_name(transfn_oid));
3885  InvokeFunctionExecuteHook(transfn_oid);
3886  if (OidIsValid(finalfn_oid))
3887  {
3888  aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
3889  ACL_EXECUTE);
3890  if (aclresult != ACLCHECK_OK)
3891  aclcheck_error(aclresult, OBJECT_FUNCTION,
3892  get_func_name(finalfn_oid));
3893  InvokeFunctionExecuteHook(finalfn_oid);
3894  }
3895  if (OidIsValid(serialfn_oid))
3896  {
3897  aclresult = pg_proc_aclcheck(serialfn_oid, aggOwner,
3898  ACL_EXECUTE);
3899  if (aclresult != ACLCHECK_OK)
3900  aclcheck_error(aclresult, OBJECT_FUNCTION,
3901  get_func_name(serialfn_oid));
3902  InvokeFunctionExecuteHook(serialfn_oid);
3903  }
3904  if (OidIsValid(deserialfn_oid))
3905  {
3906  aclresult = pg_proc_aclcheck(deserialfn_oid, aggOwner,
3907  ACL_EXECUTE);
3908  if (aclresult != ACLCHECK_OK)
3909  aclcheck_error(aclresult, OBJECT_FUNCTION,
3910  get_func_name(deserialfn_oid));
3911  InvokeFunctionExecuteHook(deserialfn_oid);
3912  }
3913  }
3914 
3915  /*
3916  * Get actual datatypes of the (nominal) aggregate inputs. These
3917  * could be different from the agg's declared input types, when the
3918  * agg accepts ANY or a polymorphic type.
3919  */
3920  numArguments = get_aggregate_argtypes(aggref, inputTypes);
3921 
3922  /* Count the "direct" arguments, if any */
3923  numDirectArgs = list_length(aggref->aggdirectargs);
3924 
3925  /* Detect how many arguments to pass to the finalfn */
3926  if (aggform->aggfinalextra)
3927  peragg->numFinalArgs = numArguments + 1;
3928  else
3929  peragg->numFinalArgs = numDirectArgs + 1;
3930 
3931  /* Initialize any direct-argument expressions */
3932  peragg->aggdirectargs = ExecInitExprList(aggref->aggdirectargs,
3933  (PlanState *) aggstate);
3934 
3935  /*
3936  * build expression trees using actual argument & result types for the
3937  * finalfn, if it exists and is required.
3938  */
3939  if (OidIsValid(finalfn_oid))
3940  {
3941  build_aggregate_finalfn_expr(inputTypes,
3942  peragg->numFinalArgs,
3943  aggtranstype,
3944  aggref->aggtype,
3945  aggref->inputcollid,
3946  finalfn_oid,
3947  &finalfnexpr);
3948  fmgr_info(finalfn_oid, &peragg->finalfn);
3949  fmgr_info_set_expr((Node *) finalfnexpr, &peragg->finalfn);
3950  }
3951 
3952  /* get info about the output value's datatype */
3953  get_typlenbyval(aggref->aggtype,
3954  &peragg->resulttypeLen,
3955  &peragg->resulttypeByVal);
3956 
3957  /*
3958  * initval is potentially null, so don't try to access it as a struct
3959  * field. Must do it the hard way with SysCacheGetAttr.
3960  */
3961  textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
3962  Anum_pg_aggregate_agginitval,
3963  &initValueIsNull);
3964  if (initValueIsNull)
3965  initValue = (Datum) 0;
3966  else
3967  initValue = GetAggInitVal(textInitVal, aggtranstype);
3968 
3969  /*
3970  * 2. Build working state for invoking the transition function, or
3971  * look up previously initialized working state, if we can share it.
3972  *
3973  * find_compatible_peragg() already collected a list of shareable
3974  * per-Trans's with the same inputs. Check if any of them have the
3975  * same transition function and initial value.
3976  */
3977  existing_transno = find_compatible_pertrans(aggstate, aggref,
3978  shareable,
3979  transfn_oid, aggtranstype,
3980  serialfn_oid, deserialfn_oid,
3981  initValue, initValueIsNull,
3982  same_input_transnos);
3983  if (existing_transno != -1)
3984  {
3985  /*
3986  * Existing compatible trans found, so just point the 'peragg' to
3987  * the same per-trans struct, and mark the trans state as shared.
3988  */
3989  pertrans = &pertransstates[existing_transno];
3990  pertrans->aggshared = true;
3991  peragg->transno = existing_transno;
3992  }
3993  else
3994  {
3995  pertrans = &pertransstates[++transno];
3996  build_pertrans_for_aggref(pertrans, aggstate, estate,
3997  aggref, transfn_oid, aggtranstype,
3998  serialfn_oid, deserialfn_oid,
3999  initValue, initValueIsNull,
4000  inputTypes, numArguments);
4001  peragg->transno = transno;
4002  }
4003  ReleaseSysCache(aggTuple);
4004  }
4005 
4006  /*
4007  * Update aggstate->numaggs to be the number of unique aggregates found.
4008  * Also set numstates to the number of unique transition states found.
4009  */
4010  aggstate->numaggs = aggno + 1;
4011  aggstate->numtrans = transno + 1;
4012 
4013  /*
4014  * Last, check whether any more aggregates got added onto the node while
4015  * we processed the expressions for the aggregate arguments (including not
4016  * only the regular arguments and FILTER expressions handled immediately
4017  * above, but any direct arguments we might've handled earlier). If so,
4018  * we have nested aggregate functions, which is semantically nonsensical,
4019  * so complain. (This should have been caught by the parser, so we don't
4020  * need to work hard on a helpful error message; but we defend against it
4021  * here anyway, just to be sure.)
4022  */
4023  if (numaggs != list_length(aggstate->aggs))
4024  ereport(ERROR,
4025  (errcode(ERRCODE_GROUPING_ERROR),
4026  errmsg("aggregate function calls cannot be nested")));
4027 
4028  /*
4029  * Build expressions doing all the transition work at once. We build a
4030  * different one for each phase, as the number of transition function
4031  * invocation can differ between phases. Note this'll work both for
4032  * transition and combination functions (although there'll only be one
4033  * phase in the latter case).
4034  */
4035  for (phaseidx = 0; phaseidx < aggstate->numphases; phaseidx++)
4036  {
4037  AggStatePerPhase phase = &aggstate->phases[phaseidx];
4038  bool dohash = false;
4039  bool dosort = false;
4040 
4041  /* phase 0 doesn't necessarily exist */
4042  if (!phase->aggnode)
4043  continue;
4044 
4045  if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 1)
4046  {
4047  /*
4048  * Phase one, and only phase one, in a mixed agg performs both
4049  * sorting and aggregation.
4050  */
4051  dohash = true;
4052  dosort = true;
4053  }
4054  else if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 0)
4055  {
4056  /*
4057  * No need to compute a transition function for an AGG_MIXED phase
4058  * 0 - the contents of the hashtables will have been computed
4059  * during phase 1.
4060  */
4061  continue;
4062  }
4063  else if (phase->aggstrategy == AGG_PLAIN ||
4064  phase->aggstrategy == AGG_SORTED)
4065  {
4066  dohash = false;
4067  dosort = true;
4068  }
4069  else if (phase->aggstrategy == AGG_HASHED)
4070  {
4071  dohash = true;
4072  dosort = false;
4073  }
4074  else
4075  Assert(false);
4076 
4077  phase->evaltrans = ExecBuildAggTrans(aggstate, phase, dosort, dohash,
4078  false);
4079 
4080  /* cache compiled expression for outer slot without NULL check */
4081  phase->evaltrans_cache[0][0] = phase->evaltrans;
4082  }
4083 
4084  return aggstate;
4085 }
struct AggStatePerTransData * AggStatePerTrans
Definition: execnodes.h:2136
ExprState ** eqfunctions
Definition: nodeAgg.h:278
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:2207
#define NIL
Definition: pg_list.h:65
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:2137
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:483
int numCols
Definition: plannodes.h:821
List * qual
Definition: plannodes.h:137
AggStatePerPhase phases
Definition: execnodes.h:2174
double hashentrysize
Definition: execnodes.h:2199
#define AllocSetContextCreate
Definition: memutils.h:170
Datum * ecxt_aggvalues
Definition: execnodes.h:244
uint64 hash_ngroups_limit
Definition: execnodes.h:2196
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1801
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
AttrNumber * grpColIdx
Definition: plannodes.h:822
uint64 transitionSpace
Definition: plannodes.h:826
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:498
List * lcons_int(int datum, List *list)
Definition: list.c:471
int numaggs
Definition: execnodes.h:2145
Oid GetUserId(void)
Definition: miscinit.c:476
bool agg_done
Definition: execnodes.h:2163
#define castNode(_type_, nodeptr)
Definition: nodes.h:597
Oid * grpCollations
Definition: plannodes.h:824
TupleTableSlot * sort_slot
Definition: execnodes.h:2177
List * all_grouped_cols
Definition: execnodes.h:2168
Tuplesortstate * sort_out
Definition: execnodes.h:2176
ScanState ss
Definition: execnodes.h:2143
ExprContext * ps_ExprContext
Definition: execnodes.h:978
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:315
int current_phase
Definition: execnodes.h:2151
Definition: nodes.h:528
AggSplit aggsplit
Definition: execnodes.h:2148
static TupleTableSlot * ExecAgg(PlanState *pstate)
Definition: nodeAgg.c:2150
int errcode(int sqlerrcode)
Definition: elog.c:610
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1331
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:2037
TupleTableSlot * hash_spill_rslot
Definition: execnodes.h:2189
static int find_compatible_pertrans(AggState *aggstate, Aggref *newagg, bool shareable, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, List *transnos)
Definition: nodeAgg.c:4510
AggStatePerTrans pertrans
Definition: execnodes.h:2153
EState * state
Definition: execnodes.h:941
int projected_set
Definition: execnodes.h:2164
unsigned int Oid
Definition: postgres_ext.h:31
HeapTuple grp_firstTuple
Definition: execnodes.h:2181
Aggref * aggref
Definition: nodeAgg.h:187
int current_set
Definition: execnodes.h:2166
#define OidIsValid(objectId)
Definition: c.h:652
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:790
int numtrans
Definition: execnodes.h:2146
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:209
ExprContext * tmpcontext
Definition: execnodes.h:2156
#define FUNC_MAX_ARGS
Bitmapset ** grouped_cols
Definition: nodeAgg.h:277
PlanState ps
Definition: execnodes.h:1328
int maxsets
Definition: execnodes.h:2173
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:3294
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:792
MemoryContext es_query_cxt
Definition: execnodes.h:559
AggStrategy aggstrategy
Definition: plannodes.h:819
bool table_filled
Definition: execnodes.h:2183
AggStrategy aggstrategy
Definition: execnodes.h:2147
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1520
MemoryContext hash_metacxt
Definition: execnodes.h:2185
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
static void find_hash_columns(AggState *aggstate)
Definition: nodeAgg.c:1566
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
Tuplesortstate * sort_in
Definition: execnodes.h:2175
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define outerPlanState(node)
Definition: execnodes.h:1033
Aggref * aggref
Definition: execnodes.h:756
#define list_nth_node(type, list, n)
Definition: pg_list.h:294
static int initValue(long lng_val)
Definition: informix.c:677
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:534
#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:327
int hash_planned_partitions
Definition: execnodes.h:2197
List * aggdirectargs
Definition: primnodes.h:318
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition: nodeAgg.c:4404
AggStatePerAgg curperagg
Definition: execnodes.h:2159
AggStatePerHash perhash
Definition: execnodes.h:2206
bool outeropsset
Definition: execnodes.h:1020
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:2204
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:191
#define outerPlan(node)
Definition: plannodes.h:166
int num_hashes
Definition: execnodes.h:2184
Plan plan
Definition: plannodes.h:818
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
bool input_done
Definition: execnodes.h:2162
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
ExprContext * hashcontext
Definition: execnodes.h:2154
bool * ecxt_aggnulls
Definition: execnodes.h:246
static int find_compatible_peragg(Aggref *newagg, AggState *aggstate, int lastaggno, List **same_input_transnos)
Definition: nodeAgg.c:4432
void * palloc0(Size size)
Definition: mcxt.c:981
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:945
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1377
List * groupingSets
Definition: plannodes.h:829
int16 resulttypeLen
Definition: nodeAgg.h:216
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:505
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:133
Plan * plan
Definition: execnodes.h:939
#define InvalidOid
Definition: postgres_ext.h:36
Oid aggfnoid
Definition: primnodes.h:312
#define ereport(elevel,...)
Definition: elog.h:144
#define Max(x, y)
Definition: c.h:922
ExprContext ** aggcontexts
Definition: execnodes.h:2155
#define makeNode(_type_)
Definition: nodes.h:576
int plan_width
Definition: plannodes.h:124
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:746
#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:820
struct AggStatePerAggData * AggStatePerAgg
Definition: execnodes.h:2135
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
AggSplit aggsplit
Definition: primnodes.h:328
AggStatePerGroup * pergroups
Definition: execnodes.h:2179
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:479
static int list_length(const List *l)
Definition: pg_list.h:149
long numGroups
Definition: plannodes.h:825
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:791
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2139
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1769
bool outeropsfixed
Definition: execnodes.h:1016
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:793
Size hash_mem_limit
Definition: execnodes.h:2195
struct Plan * lefttree
Definition: plannodes.h:138
int numphases
Definition: execnodes.h:2150
ExprState * qual
Definition: execnodes.h:960
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:1793
Oid * grpOperators
Definition: plannodes.h:823
void * palloc(Size size)
Definition: mcxt.c:950
int errmsg(const char *fmt,...)
Definition: elog.c:821
List * chain
Definition: plannodes.h:830
AggStatePerAgg peragg
Definition: execnodes.h:2152
#define ACL_EXECUTE
Definition: parsenodes.h:81
#define elog(elevel,...)
Definition: elog.h:214
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4587
int i
List * aggdirectargs
Definition: nodeAgg.h:210
Oid aggtranstype
Definition: primnodes.h:316
AggStatePerTrans curpertrans
Definition: execnodes.h:2161
Oid aggtype
Definition: primnodes.h:313
bool resulttypeByVal
Definition: nodeAgg.h:217
Definition: plannodes.h:816
ExprContext * CreateWorkExprContext(EState *estate)
Definition: execUtils.c:315
List * aggs
Definition: execnodes.h:2144
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:681
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1819
static void build_pertrans_for_aggref(AggStatePerTrans pertrans, AggState *aggstate, EState *estate, Aggref *aggref, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, Oid *inputTypes, int numArguments)
Definition: nodeAgg.c:4096
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
Definition: pg_list.h:50
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:2190
static void build_hash_tables(AggState *aggstate)
Definition: nodeAgg.c:1471
const TupleTableSlotOps * outerops
Definition: execnodes.h:1012
ExprState * ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, bool doSort, bool doHash, bool nullcheck)
Definition: execExpr.c:2917
AggStatePerGroup * all_pergroups
Definition: execnodes.h:2212

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

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

4632 {
4633  ExprContext *econtext = node->ss.ps.ps_ExprContext;
4635  Agg *aggnode = (Agg *) node->ss.ps.plan;
4636  int transno;
4637  int numGroupingSets = Max(node->maxsets, 1);
4638  int setno;
4639 
4640  node->agg_done = false;
4641 
4642  if (node->aggstrategy == AGG_HASHED)
4643  {
4644  /*
4645  * In the hashed case, if we haven't yet built the hash table then we
4646  * can just return; nothing done yet, so nothing to undo. If subnode's
4647  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
4648  * else no reason to re-scan it at all.
4649  */
4650  if (!node->table_filled)
4651  return;
4652 
4653  /*
4654  * If we do have the hash table, and it never spilled, and the subplan
4655  * does not have any parameter changes, and none of our own parameter
4656  * changes affect input expressions of the aggregated functions, then
4657  * we can just rescan the existing hash table; no need to build it
4658  * again.
4659  */
4660  if (outerPlan->chgParam == NULL && !node->hash_ever_spilled &&
4661  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
4662  {
4664  &node->perhash[0].hashiter);
4665  select_current_set(node, 0, true);
4666  return;
4667  }
4668  }
4669 
4670  /* Make sure we have closed any open tuplesorts */
4671  for (transno = 0; transno < node->numtrans; transno++)
4672  {
4673  for (setno = 0; setno < numGroupingSets; setno++)
4674  {
4675  AggStatePerTrans pertrans = &node->pertrans[transno];
4676 
4677  if (pertrans->sortstates[setno])
4678  {
4679  tuplesort_end(pertrans->sortstates[setno]);
4680  pertrans->sortstates[setno] = NULL;
4681  }
4682  }
4683  }
4684 
4685  /*
4686  * We don't need to ReScanExprContext the output tuple context here;
4687  * ExecReScan already did it. But we do need to reset our per-grouping-set
4688  * contexts, which may have transvalues stored in them. (We use rescan
4689  * rather than just reset because transfns may have registered callbacks
4690  * that need to be run now.) For the AGG_HASHED case, see below.
4691  */
4692 
4693  for (setno = 0; setno < numGroupingSets; setno++)
4694  {
4695  ReScanExprContext(node->aggcontexts[setno]);
4696  }
4697 
4698  /* Release first tuple of group, if we have made a copy */
4699  if (node->grp_firstTuple != NULL)
4700  {
4702  node->grp_firstTuple = NULL;
4703  }
4705 
4706  /* Forget current agg values */
4707  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
4708  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
4709 
4710  /*
4711  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
4712  * the hashcontext. This used to be an issue, but now, resetting a context
4713  * automatically deletes sub-contexts too.
4714  */
4715  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
4716  {
4718 
4719  node->hash_ever_spilled = false;
4720  node->hash_spill_mode = false;
4721  node->hash_ngroups_current = 0;
4722 
4724  /* Rebuild an empty hash table */
4725  build_hash_tables(node);
4726  node->table_filled = false;
4727  /* iterator will be reset when the table is filled */
4728 
4729  hashagg_recompile_expressions(node, false, false);
4730  }
4731 
4732  if (node->aggstrategy != AGG_HASHED)
4733  {
4734  /*
4735  * Reset the per-group state (in particular, mark transvalues null)
4736  */
4737  for (setno = 0; setno < numGroupingSets; setno++)
4738  {
4739  MemSet(node->pergroups[setno], 0,
4740  sizeof(AggStatePerGroupData) * node->numaggs);
4741  }
4742 
4743  /* reset to phase 1 */
4744  initialize_phase(node, 1);
4745 
4746  node->input_done = false;
4747  node->projected_set = -1;
4748  }
4749 
4750  if (outerPlan->chgParam == NULL)
4751  ExecReScan(outerPlan);
4752 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3186
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:483
Datum * ecxt_aggvalues
Definition: execnodes.h:244
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
int numaggs
Definition: execnodes.h:2145
bool agg_done
Definition: execnodes.h:2163
ScanState ss
Definition: execnodes.h:2143
ExprContext * ps_ExprContext
Definition: execnodes.h:978
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
#define MemSet(start, val, len)
Definition: c.h:950
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1331
AggStatePerTrans pertrans
Definition: execnodes.h:2153
int projected_set
Definition: execnodes.h:2164
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
HeapTuple grp_firstTuple
Definition: execnodes.h:2181
int numtrans
Definition: execnodes.h:2146
bool hash_spill_mode
Definition: execnodes.h:2193
PlanState ps
Definition: execnodes.h:1328
int maxsets
Definition: execnodes.h:2173
bool table_filled
Definition: execnodes.h:2183
AggStrategy aggstrategy
Definition: execnodes.h:2147
#define outerPlanState(node)
Definition: execnodes.h:1033
Tuplesortstate ** sortstates
Definition: nodeAgg.h:154
Bitmapset * aggParams
Definition: plannodes.h:827
AggStatePerHash perhash
Definition: execnodes.h:2206
Bitmapset * chgParam
Definition: execnodes.h:971
#define outerPlan(node)
Definition: plannodes.h:166
TupleHashIterator hashiter
Definition: nodeAgg.h:304
bool input_done
Definition: execnodes.h:2162
ExprContext * hashcontext
Definition: execnodes.h:2154
bool * ecxt_aggnulls
Definition: execnodes.h:246
uintptr_t Datum
Definition: postgres.h:367
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:505
Plan * plan
Definition: execnodes.h:939
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:731
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1742
#define Max(x, y)
Definition: c.h:922
ExprContext ** aggcontexts
Definition: execnodes.h:2155
bool hash_ever_spilled
Definition: execnodes.h:2192
AggStatePerGroup * pergroups
Definition: execnodes.h:2179
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:437
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
uint64 hash_ngroups_current
Definition: execnodes.h:2201
Definition: plannodes.h:816
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1445
TupleHashTable hashtable
Definition: nodeAgg.h:303
static void build_hash_tables(AggState *aggstate)
Definition: nodeAgg.c:1471

◆ 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:649
size_t Size
Definition: c.h:474
#define MAXALIGN(LEN)
Definition: c.h:699
#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 1793 of file nodeAgg.c.

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

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

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