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 257 of file nodeAgg.h.

◆ FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUE

#define FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUE   0

Definition at line 252 of file nodeAgg.h.

◆ FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUEISNULL

#define FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUEISNULL   1

Definition at line 254 of file nodeAgg.h.

Typedef Documentation

◆ AggStatePerAggData

◆ AggStatePerGroupData

◆ AggStatePerHashData

◆ AggStatePerPhaseData

◆ AggStatePerTransData

Function Documentation

◆ ExecAggEstimate()

void ExecAggEstimate ( AggState node,
ParallelContext pcxt 
)

Definition at line 4681 of file nodeAgg.c.

4682 {
4683  Size size;
4684 
4685  /* don't need this if not instrumenting or no workers */
4686  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4687  return;
4688 
4689  size = mul_size(pcxt->nworkers, sizeof(AggregateInstrumentation));
4690  size = add_size(size, offsetof(SharedAggInfo, sinstrument));
4691  shm_toc_estimate_chunk(&pcxt->estimator, size);
4692  shm_toc_estimate_keys(&pcxt->estimator, 1);
4693 }
size_t Size
Definition: c.h:541
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
ScanState ss
Definition: execnodes.h:2358
shm_toc_estimator estimator
Definition: parallel.h:42
Instrumentation * instrument
Definition: execnodes.h:1039
PlanState ps
Definition: execnodes.h:1454

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

Referenced by ExecParallelEstimate().

◆ ExecAggInitializeDSM()

void ExecAggInitializeDSM ( AggState node,
ParallelContext pcxt 
)

Definition at line 4702 of file nodeAgg.c.

4703 {
4704  Size size;
4705 
4706  /* don't need this if not instrumenting or no workers */
4707  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4708  return;
4709 
4710  size = offsetof(SharedAggInfo, sinstrument)
4711  + pcxt->nworkers * sizeof(AggregateInstrumentation);
4712  node->shared_info = shm_toc_allocate(pcxt->toc, size);
4713  /* ensure any unfilled slots will contain zeroes */
4714  memset(node->shared_info, 0, size);
4715  node->shared_info->num_workers = pcxt->nworkers;
4716  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
4717  node->shared_info);
4718 }
struct AggregateInstrumentation AggregateInstrumentation
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
SharedAggInfo * shared_info
Definition: execnodes.h:2430
shm_toc * toc
Definition: parallel.h:45
Plan * plan
Definition: execnodes.h:1029
int plan_node_id
Definition: plannodes.h:152

References PlanState::instrument, SharedAggInfo::num_workers, ParallelContext::nworkers, 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().

◆ ExecAggInitializeWorker()

void ExecAggInitializeWorker ( AggState node,
ParallelWorkerContext pwcxt 
)

Definition at line 4727 of file nodeAgg.c.

4728 {
4729  node->shared_info =
4730  shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
4731 }
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

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

Referenced by ExecParallelInitializeWorker().

◆ ExecAggRetrieveInstrumentation()

void ExecAggRetrieveInstrumentation ( AggState node)

Definition at line 4740 of file nodeAgg.c.

4741 {
4742  Size size;
4743  SharedAggInfo *si;
4744 
4745  if (node->shared_info == NULL)
4746  return;
4747 
4748  size = offsetof(SharedAggInfo, sinstrument)
4750  si = palloc(size);
4751  memcpy(si, node->shared_info, size);
4752  node->shared_info = si;
4753 }
void * palloc(Size size)
Definition: mcxt.c:1199

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

Referenced by ExecParallelRetrieveInstrumentation().

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

Definition at line 4292 of file nodeAgg.c.

4293 {
4295  int transno;
4296  int numGroupingSets = Max(node->maxsets, 1);
4297  int setno;
4298 
4299  /*
4300  * When ending a parallel worker, copy the statistics gathered by the
4301  * worker back into shared memory so that it can be picked up by the main
4302  * process to report in EXPLAIN ANALYZE.
4303  */
4304  if (node->shared_info && IsParallelWorker())
4305  {
4307 
4308  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
4311  si->hash_disk_used = node->hash_disk_used;
4312  si->hash_mem_peak = node->hash_mem_peak;
4313  }
4314 
4315  /* Make sure we have closed any open tuplesorts */
4316 
4317  if (node->sort_in)
4318  tuplesort_end(node->sort_in);
4319  if (node->sort_out)
4320  tuplesort_end(node->sort_out);
4321 
4323 
4324  if (node->hash_metacxt != NULL)
4325  {
4327  node->hash_metacxt = NULL;
4328  }
4329 
4330  for (transno = 0; transno < node->numtrans; transno++)
4331  {
4332  AggStatePerTrans pertrans = &node->pertrans[transno];
4333 
4334  for (setno = 0; setno < numGroupingSets; setno++)
4335  {
4336  if (pertrans->sortstates[setno])
4337  tuplesort_end(pertrans->sortstates[setno]);
4338  }
4339  }
4340 
4341  /* And ensure any agg shutdown callbacks have been called */
4342  for (setno = 0; setno < numGroupingSets; setno++)
4343  ReScanExprContext(node->aggcontexts[setno]);
4344  if (node->hashcontext)
4346 
4347  /*
4348  * We don't actually free any ExprContexts here (see comment in
4349  * ExecFreeExprContext), just unlinking the output one from the plan node
4350  * suffices.
4351  */
4352  ExecFreeExprContext(&node->ss.ps);
4353 
4354  /* clean up tuple table */
4356 
4357  outerPlan = outerPlanState(node);
4359 }
int ParallelWorkerNumber
Definition: parallel.c:113
#define Max(x, y)
Definition: c.h:931
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:557
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:440
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:652
#define outerPlanState(node)
Definition: execnodes.h:1125
#define IsParallelWorker()
Definition: parallel.h:61
Assert(fmt[strlen(fmt) - 1] !='\n')
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:376
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3125
#define outerPlan(node)
Definition: plannodes.h:183
Tuplesortstate ** sortstates
Definition: nodeAgg.h:162
MemoryContext hash_metacxt
Definition: execnodes.h:2400
Tuplesortstate * sort_out
Definition: execnodes.h:2391
uint64 hash_disk_used
Definition: execnodes.h:2418
AggStatePerTrans pertrans
Definition: execnodes.h:2368
int numtrans
Definition: execnodes.h:2361
ExprContext * hashcontext
Definition: execnodes.h:2369
Size hash_mem_peak
Definition: execnodes.h:2415
int hash_batches_used
Definition: execnodes.h:2419
Tuplesortstate * sort_in
Definition: execnodes.h:2390
int maxsets
Definition: execnodes.h:2388
ExprContext ** aggcontexts
Definition: execnodes.h:2370
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1457
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2334
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:972
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:433

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

◆ ExecInitAgg()

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

Definition at line 3165 of file nodeAgg.c.

3166 {
3167  AggState *aggstate;
3168  AggStatePerAgg peraggs;
3169  AggStatePerTrans pertransstates;
3170  AggStatePerGroup *pergroups;
3171  Plan *outerPlan;
3172  ExprContext *econtext;
3173  TupleDesc scanDesc;
3174  int max_aggno;
3175  int max_transno;
3176  int numaggrefs;
3177  int numaggs;
3178  int numtrans;
3179  int phase;
3180  int phaseidx;
3181  ListCell *l;
3182  Bitmapset *all_grouped_cols = NULL;
3183  int numGroupingSets = 1;
3184  int numPhases;
3185  int numHashes;
3186  int i = 0;
3187  int j = 0;
3188  bool use_hashing = (node->aggstrategy == AGG_HASHED ||
3189  node->aggstrategy == AGG_MIXED);
3190 
3191  /* check for unsupported flags */
3192  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
3193 
3194  /*
3195  * create state structure
3196  */
3197  aggstate = makeNode(AggState);
3198  aggstate->ss.ps.plan = (Plan *) node;
3199  aggstate->ss.ps.state = estate;
3200  aggstate->ss.ps.ExecProcNode = ExecAgg;
3201 
3202  aggstate->aggs = NIL;
3203  aggstate->numaggs = 0;
3204  aggstate->numtrans = 0;
3205  aggstate->aggstrategy = node->aggstrategy;
3206  aggstate->aggsplit = node->aggsplit;
3207  aggstate->maxsets = 0;
3208  aggstate->projected_set = -1;
3209  aggstate->current_set = 0;
3210  aggstate->peragg = NULL;
3211  aggstate->pertrans = NULL;
3212  aggstate->curperagg = NULL;
3213  aggstate->curpertrans = NULL;
3214  aggstate->input_done = false;
3215  aggstate->agg_done = false;
3216  aggstate->pergroups = NULL;
3217  aggstate->grp_firstTuple = NULL;
3218  aggstate->sort_in = NULL;
3219  aggstate->sort_out = NULL;
3220 
3221  /*
3222  * phases[0] always exists, but is dummy in sorted/plain mode
3223  */
3224  numPhases = (use_hashing ? 1 : 2);
3225  numHashes = (use_hashing ? 1 : 0);
3226 
3227  /*
3228  * Calculate the maximum number of grouping sets in any phase; this
3229  * determines the size of some allocations. Also calculate the number of
3230  * phases, since all hashed/mixed nodes contribute to only a single phase.
3231  */
3232  if (node->groupingSets)
3233  {
3234  numGroupingSets = list_length(node->groupingSets);
3235 
3236  foreach(l, node->chain)
3237  {
3238  Agg *agg = lfirst(l);
3239 
3240  numGroupingSets = Max(numGroupingSets,
3241  list_length(agg->groupingSets));
3242 
3243  /*
3244  * additional AGG_HASHED aggs become part of phase 0, but all
3245  * others add an extra phase.
3246  */
3247  if (agg->aggstrategy != AGG_HASHED)
3248  ++numPhases;
3249  else
3250  ++numHashes;
3251  }
3252  }
3253 
3254  aggstate->maxsets = numGroupingSets;
3255  aggstate->numphases = numPhases;
3256 
3257  aggstate->aggcontexts = (ExprContext **)
3258  palloc0(sizeof(ExprContext *) * numGroupingSets);
3259 
3260  /*
3261  * Create expression contexts. We need three or more, one for
3262  * per-input-tuple processing, one for per-output-tuple processing, one
3263  * for all the hashtables, and one for each grouping set. The per-tuple
3264  * memory context of the per-grouping-set ExprContexts (aggcontexts)
3265  * replaces the standalone memory context formerly used to hold transition
3266  * values. We cheat a little by using ExecAssignExprContext() to build
3267  * all of them.
3268  *
3269  * NOTE: the details of what is stored in aggcontexts and what is stored
3270  * in the regular per-query memory context are driven by a simple
3271  * decision: we want to reset the aggcontext at group boundaries (if not
3272  * hashing) and in ExecReScanAgg to recover no-longer-wanted space.
3273  */
3274  ExecAssignExprContext(estate, &aggstate->ss.ps);
3275  aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
3276 
3277  for (i = 0; i < numGroupingSets; ++i)
3278  {
3279  ExecAssignExprContext(estate, &aggstate->ss.ps);
3280  aggstate->aggcontexts[i] = aggstate->ss.ps.ps_ExprContext;
3281  }
3282 
3283  if (use_hashing)
3284  aggstate->hashcontext = CreateWorkExprContext(estate);
3285 
3286  ExecAssignExprContext(estate, &aggstate->ss.ps);
3287 
3288  /*
3289  * Initialize child nodes.
3290  *
3291  * If we are doing a hashed aggregation then the child plan does not need
3292  * to handle REWIND efficiently; see ExecReScanAgg.
3293  */
3294  if (node->aggstrategy == AGG_HASHED)
3295  eflags &= ~EXEC_FLAG_REWIND;
3296  outerPlan = outerPlan(node);
3297  outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags);
3298 
3299  /*
3300  * initialize source tuple type.
3301  */
3302  aggstate->ss.ps.outerops =
3304  &aggstate->ss.ps.outeropsfixed);
3305  aggstate->ss.ps.outeropsset = true;
3306 
3307  ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss,
3308  aggstate->ss.ps.outerops);
3309  scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
3310 
3311  /*
3312  * If there are more than two phases (including a potential dummy phase
3313  * 0), input will be resorted using tuplesort. Need a slot for that.
3314  */
3315  if (numPhases > 2)
3316  {
3317  aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc,
3319 
3320  /*
3321  * The output of the tuplesort, and the output from the outer child
3322  * might not use the same type of slot. In most cases the child will
3323  * be a Sort, and thus return a TTSOpsMinimalTuple type slot - but the
3324  * input can also be presorted due an index, in which case it could be
3325  * a different type of slot.
3326  *
3327  * XXX: For efficiency it would be good to instead/additionally
3328  * generate expressions with corresponding settings of outerops* for
3329  * the individual phases - deforming is often a bottleneck for
3330  * aggregations with lots of rows per group. If there's multiple
3331  * sorts, we know that all but the first use TTSOpsMinimalTuple (via
3332  * the nodeAgg.c internal tuplesort).
3333  */
3334  if (aggstate->ss.ps.outeropsfixed &&
3335  aggstate->ss.ps.outerops != &TTSOpsMinimalTuple)
3336  aggstate->ss.ps.outeropsfixed = false;
3337  }
3338 
3339  /*
3340  * Initialize result type, slot and projection.
3341  */
3343  ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
3344 
3345  /*
3346  * initialize child expressions
3347  *
3348  * We expect the parser to have checked that no aggs contain other agg
3349  * calls in their arguments (and just to be sure, we verify it again while
3350  * initializing the plan node). This would make no sense under SQL
3351  * semantics, and it's forbidden by the spec. Because it is true, we
3352  * don't need to worry about evaluating the aggs in any particular order.
3353  *
3354  * Note: execExpr.c finds Aggrefs for us, and adds them to aggstate->aggs.
3355  * Aggrefs in the qual are found here; Aggrefs in the targetlist are found
3356  * during ExecAssignProjectionInfo, above.
3357  */
3358  aggstate->ss.ps.qual =
3359  ExecInitQual(node->plan.qual, (PlanState *) aggstate);
3360 
3361  /*
3362  * We should now have found all Aggrefs in the targetlist and quals.
3363  */
3364  numaggrefs = list_length(aggstate->aggs);
3365  max_aggno = -1;
3366  max_transno = -1;
3367  foreach(l, aggstate->aggs)
3368  {
3369  Aggref *aggref = (Aggref *) lfirst(l);
3370 
3371  max_aggno = Max(max_aggno, aggref->aggno);
3372  max_transno = Max(max_transno, aggref->aggtransno);
3373  }
3374  numaggs = max_aggno + 1;
3375  numtrans = max_transno + 1;
3376 
3377  /*
3378  * For each phase, prepare grouping set data and fmgr lookup data for
3379  * compare functions. Accumulate all_grouped_cols in passing.
3380  */
3381  aggstate->phases = palloc0(numPhases * sizeof(AggStatePerPhaseData));
3382 
3383  aggstate->num_hashes = numHashes;
3384  if (numHashes)
3385  {
3386  aggstate->perhash = palloc0(sizeof(AggStatePerHashData) * numHashes);
3387  aggstate->phases[0].numsets = 0;
3388  aggstate->phases[0].gset_lengths = palloc(numHashes * sizeof(int));
3389  aggstate->phases[0].grouped_cols = palloc(numHashes * sizeof(Bitmapset *));
3390  }
3391 
3392  phase = 0;
3393  for (phaseidx = 0; phaseidx <= list_length(node->chain); ++phaseidx)
3394  {
3395  Agg *aggnode;
3396  Sort *sortnode;
3397 
3398  if (phaseidx > 0)
3399  {
3400  aggnode = list_nth_node(Agg, node->chain, phaseidx - 1);
3401  sortnode = castNode(Sort, outerPlan(aggnode));
3402  }
3403  else
3404  {
3405  aggnode = node;
3406  sortnode = NULL;
3407  }
3408 
3409  Assert(phase <= 1 || sortnode);
3410 
3411  if (aggnode->aggstrategy == AGG_HASHED
3412  || aggnode->aggstrategy == AGG_MIXED)
3413  {
3414  AggStatePerPhase phasedata = &aggstate->phases[0];
3415  AggStatePerHash perhash;
3416  Bitmapset *cols = NULL;
3417 
3418  Assert(phase == 0);
3419  i = phasedata->numsets++;
3420  perhash = &aggstate->perhash[i];
3421 
3422  /* phase 0 always points to the "real" Agg in the hash case */
3423  phasedata->aggnode = node;
3424  phasedata->aggstrategy = node->aggstrategy;
3425 
3426  /* but the actual Agg node representing this hash is saved here */
3427  perhash->aggnode = aggnode;
3428 
3429  phasedata->gset_lengths[i] = perhash->numCols = aggnode->numCols;
3430 
3431  for (j = 0; j < aggnode->numCols; ++j)
3432  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
3433 
3434  phasedata->grouped_cols[i] = cols;
3435 
3436  all_grouped_cols = bms_add_members(all_grouped_cols, cols);
3437  continue;
3438  }
3439  else
3440  {
3441  AggStatePerPhase phasedata = &aggstate->phases[++phase];
3442  int num_sets;
3443 
3444  phasedata->numsets = num_sets = list_length(aggnode->groupingSets);
3445 
3446  if (num_sets)
3447  {
3448  phasedata->gset_lengths = palloc(num_sets * sizeof(int));
3449  phasedata->grouped_cols = palloc(num_sets * sizeof(Bitmapset *));
3450 
3451  i = 0;
3452  foreach(l, aggnode->groupingSets)
3453  {
3454  int current_length = list_length(lfirst(l));
3455  Bitmapset *cols = NULL;
3456 
3457  /* planner forces this to be correct */
3458  for (j = 0; j < current_length; ++j)
3459  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
3460 
3461  phasedata->grouped_cols[i] = cols;
3462  phasedata->gset_lengths[i] = current_length;
3463 
3464  ++i;
3465  }
3466 
3467  all_grouped_cols = bms_add_members(all_grouped_cols,
3468  phasedata->grouped_cols[0]);
3469  }
3470  else
3471  {
3472  Assert(phaseidx == 0);
3473 
3474  phasedata->gset_lengths = NULL;
3475  phasedata->grouped_cols = NULL;
3476  }
3477 
3478  /*
3479  * If we are grouping, precompute fmgr lookup data for inner loop.
3480  */
3481  if (aggnode->aggstrategy == AGG_SORTED)
3482  {
3483  Assert(aggnode->numCols > 0);
3484 
3485  /*
3486  * Build a separate function for each subset of columns that
3487  * need to be compared.
3488  */
3489  phasedata->eqfunctions =
3490  (ExprState **) palloc0(aggnode->numCols * sizeof(ExprState *));
3491 
3492  /* for each grouping set */
3493  for (int k = 0; k < phasedata->numsets; k++)
3494  {
3495  int length = phasedata->gset_lengths[k];
3496 
3497  if (phasedata->eqfunctions[length - 1] != NULL)
3498  continue;
3499 
3500  phasedata->eqfunctions[length - 1] =
3501  execTuplesMatchPrepare(scanDesc,
3502  length,
3503  aggnode->grpColIdx,
3504  aggnode->grpOperators,
3505  aggnode->grpCollations,
3506  (PlanState *) aggstate);
3507  }
3508 
3509  /* and for all grouped columns, unless already computed */
3510  if (phasedata->eqfunctions[aggnode->numCols - 1] == NULL)
3511  {
3512  phasedata->eqfunctions[aggnode->numCols - 1] =
3513  execTuplesMatchPrepare(scanDesc,
3514  aggnode->numCols,
3515  aggnode->grpColIdx,
3516  aggnode->grpOperators,
3517  aggnode->grpCollations,
3518  (PlanState *) aggstate);
3519  }
3520  }
3521 
3522  phasedata->aggnode = aggnode;
3523  phasedata->aggstrategy = aggnode->aggstrategy;
3524  phasedata->sortnode = sortnode;
3525  }
3526  }
3527 
3528  /*
3529  * Convert all_grouped_cols to a descending-order list.
3530  */
3531  i = -1;
3532  while ((i = bms_next_member(all_grouped_cols, i)) >= 0)
3533  aggstate->all_grouped_cols = lcons_int(i, aggstate->all_grouped_cols);
3534 
3535  /*
3536  * Set up aggregate-result storage in the output expr context, and also
3537  * allocate my private per-agg working storage
3538  */
3539  econtext = aggstate->ss.ps.ps_ExprContext;
3540  econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
3541  econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numaggs);
3542 
3543  peraggs = (AggStatePerAgg) palloc0(sizeof(AggStatePerAggData) * numaggs);
3544  pertransstates = (AggStatePerTrans) palloc0(sizeof(AggStatePerTransData) * numtrans);
3545 
3546  aggstate->peragg = peraggs;
3547  aggstate->pertrans = pertransstates;
3548 
3549 
3550  aggstate->all_pergroups =
3552  * (numGroupingSets + numHashes));
3553  pergroups = aggstate->all_pergroups;
3554 
3555  if (node->aggstrategy != AGG_HASHED)
3556  {
3557  for (i = 0; i < numGroupingSets; i++)
3558  {
3559  pergroups[i] = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData)
3560  * numaggs);
3561  }
3562 
3563  aggstate->pergroups = pergroups;
3564  pergroups += numGroupingSets;
3565  }
3566 
3567  /*
3568  * Hashing can only appear in the initial phase.
3569  */
3570  if (use_hashing)
3571  {
3572  Plan *outerplan = outerPlan(node);
3573  uint64 totalGroups = 0;
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 (int k = 0; k < aggstate->num_hashes; k++)
3597  totalGroups += aggstate->perhash[k].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 = object_aclcheck(ProcedureRelationId, 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 = object_aclcheck(ProcedureRelationId, 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 = object_aclcheck(ProcedureRelationId, 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 = object_aclcheck(ProcedureRelationId, 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 = object_aclcheck(ProcedureRelationId, 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 }
AclResult
Definition: acl.h:183
@ ACLCHECK_OK
Definition: acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3485
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:4598
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1047
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:739
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:796
#define OidIsValid(objectId)
Definition: c.h:711
int errcode(int sqlerrcode)
Definition: elog.c:695
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define ERROR
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:145
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:319
ExprState * ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, bool doSort, bool doHash, bool nullcheck)
Definition: execExpr.c:3263
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:210
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:59
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:142
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1831
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1799
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
ExprContext * CreateWorkExprContext(EState *estate)
Definition: execUtils.c:318
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:501
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:684
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:482
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:537
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:2352
struct AggStatePerTransData * AggStatePerTrans
Definition: execnodes.h:2351
struct AggStatePerAggData * AggStatePerAgg
Definition: execnodes.h:2350
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define EXEC_FLAG_REWIND
Definition: executor.h:57
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:56
#define EXEC_FLAG_MARK
Definition: executor.h:59
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
static int initValue(long lng_val)
Definition: informix.c:677
int j
Definition: isn.c:74
int i
Definition: isn.c:73
List * lcons_int(int datum, List *list)
Definition: list.c:512
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2209
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1590
void * palloc0(Size size)
Definition: mcxt.c:1230
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
Oid GetUserId(void)
Definition: miscinit.c:497
static void find_hash_columns(AggState *aggstate)
Definition: nodeAgg.c:1556
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition: nodeAgg.c:4276
static TupleTableSlot * ExecAgg(PlanState *pstate)
Definition: nodeAgg.c:2150
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:478
Size hash_agg_entry_size(int numTrans, Size tupleWidth, Size transitionSpace)
Definition: nodeAgg.c:1686
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
static void build_hash_tables(AggState *aggstate)
Definition: nodeAgg.c:1461
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:456
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:1790
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:383
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:385
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:382
@ AGG_SORTED
Definition: nodes.h:352
@ AGG_HASHED
Definition: nodes.h:353
@ AGG_MIXED
Definition: nodes.h:354
@ AGG_PLAIN
Definition: nodes.h:351
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:384
#define makeNode(_type_)
Definition: nodes.h:165
#define castNode(_type_, nodeptr)
Definition: nodes.h:186
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:213
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:2084
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1890
bool IsBinaryCoercible(Oid srctype, Oid targettype)
@ OBJECT_AGGREGATE
Definition: parsenodes.h:1863
@ OBJECT_FUNCTION
Definition: parsenodes.h:1881
#define ACL_EXECUTE
Definition: parsenodes.h:90
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
#define FUNC_MAX_ARGS
#define lfirst(lc)
Definition: pg_list.h:170
static int list_length(const List *l)
Definition: pg_list.h:150
#define NIL
Definition: pg_list.h:66
#define list_nth_node(type, list, n)
Definition: pg_list.h:325
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
uintptr_t Datum
Definition: postgres.h:412
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:600
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
FmgrInfo finalfn
Definition: nodeAgg.h:207
bool resulttypeByVal
Definition: nodeAgg.h:225
List * aggdirectargs
Definition: nodeAgg.h:218
Aggref * aggref
Definition: nodeAgg.h:195
int16 resulttypeLen
Definition: nodeAgg.h:224
Bitmapset ** grouped_cols
Definition: nodeAgg.h:285
ExprState * evaltrans
Definition: nodeAgg.h:291
ExprState * evaltrans_cache[2][2]
Definition: nodeAgg.h:299
ExprState ** eqfunctions
Definition: nodeAgg.h:286
AggStrategy aggstrategy
Definition: nodeAgg.h:282
FmgrInfo transfn
Definition: nodeAgg.h:86
Aggref * aggref
Definition: nodeAgg.h:44
AggStatePerGroup * all_pergroups
Definition: execnodes.h:2427
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:2422
List * aggs
Definition: execnodes.h:2359
ExprContext * tmpcontext
Definition: execnodes.h:2371
int hash_planned_partitions
Definition: execnodes.h:2412
HeapTuple grp_firstTuple
Definition: execnodes.h:2396
Size hash_mem_limit
Definition: execnodes.h:2410
AggStatePerTrans curpertrans
Definition: execnodes.h:2376
bool table_filled
Definition: execnodes.h:2398
int current_set
Definition: execnodes.h:2381
AggStrategy aggstrategy
Definition: execnodes.h:2362
AggSplit aggsplit
Definition: execnodes.h:2363
int projected_set
Definition: execnodes.h:2379
uint64 hash_ngroups_limit
Definition: execnodes.h:2411
bool input_done
Definition: execnodes.h:2377
AggStatePerPhase phases
Definition: execnodes.h:2389
List * all_grouped_cols
Definition: execnodes.h:2383
AggStatePerGroup * pergroups
Definition: execnodes.h:2394
AggStatePerHash perhash
Definition: execnodes.h:2421
double hashentrysize
Definition: execnodes.h:2414
int numphases
Definition: execnodes.h:2365
TupleTableSlot * hash_spill_wslot
Definition: execnodes.h:2405
AggStatePerAgg curperagg
Definition: execnodes.h:2374
TupleTableSlot * sort_slot
Definition: execnodes.h:2392
int numaggs
Definition: execnodes.h:2360
int num_hashes
Definition: execnodes.h:2399
AggStatePerAgg peragg
Definition: execnodes.h:2367
TupleTableSlot * hash_spill_rslot
Definition: execnodes.h:2404
int current_phase
Definition: execnodes.h:2366
bool agg_done
Definition: execnodes.h:2378
Definition: plannodes.h:993
AggSplit aggsplit
Definition: plannodes.h:1000
List * chain
Definition: plannodes.h:1027
long numGroups
Definition: plannodes.h:1013
List * groupingSets
Definition: plannodes.h:1024
Plan plan
Definition: plannodes.h:994
int numCols
Definition: plannodes.h:1003
uint64 transitionSpace
Definition: plannodes.h:1016
AggStrategy aggstrategy
Definition: plannodes.h:997
Oid aggfnoid
Definition: primnodes.h:373
List * aggdirectargs
Definition: primnodes.h:394
char aggkind
Definition: primnodes.h:418
int aggtransno
Definition: primnodes.h:433
Index agglevelsup
Definition: primnodes.h:424
List * args
Definition: primnodes.h:397
Oid inputcollid
Definition: primnodes.h:382
Oid aggtype
Definition: primnodes.h:376
AggSplit aggsplit
Definition: primnodes.h:427
int aggno
Definition: primnodes.h:430
MemoryContext es_query_cxt
Definition: execnodes.h:655
Datum * ecxt_aggvalues
Definition: execnodes.h:266
bool * ecxt_aggnulls
Definition: execnodes.h:268
bool fn_strict
Definition: fmgr.h:61
Definition: nodes.h:118
bool outeropsset
Definition: execnodes.h:1112
const TupleTableSlotOps * outerops
Definition: execnodes.h:1104
ExprState * qual
Definition: execnodes.h:1050
bool outeropsfixed
Definition: execnodes.h:1108
EState * state
Definition: execnodes.h:1031
ExprContext * ps_ExprContext
Definition: execnodes.h:1068
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1035
List * qual
Definition: plannodes.h:154
int plan_width
Definition: plannodes.h:136
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1434
@ AGGFNOID
Definition: syscache.h:34
@ PROCOID
Definition: syscache.h:79

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, AggState::agg_done, AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, AggState::aggcontexts, AggStatePerAggData::aggdirectargs, Aggref::aggdirectargs, Aggref::aggfnoid, AGGFNOID, Aggref::aggkind, Aggref::agglevelsup, Aggref::aggno, AggStatePerPhaseData::aggnode, AggStatePerHashData::aggnode, AggStatePerTransData::aggref, AggStatePerAggData::aggref, AggState::aggs, AggStatePerTransData::aggshared, AggState::aggsplit, Agg::aggsplit, Aggref::aggsplit, AggStatePerPhaseData::aggstrategy, AggState::aggstrategy, Agg::aggstrategy, Aggref::aggtransno, Aggref::aggtype, AggState::all_grouped_cols, AggState::all_pergroups, 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_phase, 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, AggStatePerPhaseData::gset_lengths, hash_agg_entry_size(), hash_agg_set_limits(), AggState::hash_batches_used, AggState::hash_mem_limit, AggState::hash_metacxt, AggState::hash_ngroups_limit, AggState::hash_pergroup, AggState::hash_planned_partitions, AggState::hash_spill_rslot, AggState::hash_spill_wslot, AggState::hashcontext, AggState::hashentrysize, HeapTupleIsValid, i, initialize_phase(), initValue(), AggStatePerTransData::initValueIsNull, AggState::input_done, Aggref::inputcollid, InvalidOid, InvokeFunctionExecuteHook, IsBinaryCoercible(), j, lcons_int(), lfirst, list_length(), list_nth_node, makeNode, Max, AggState::maxsets, NIL, AggState::num_hashes, AggState::numaggs, AggStatePerHashData::numCols, Agg::numCols, AggStatePerAggData::numFinalArgs, Agg::numGroups, AggState::numphases, AggStatePerPhaseData::numsets, AggState::numtrans, AggStatePerTransData::numTransInputs, object_aclcheck(), OBJECT_AGGREGATE, OBJECT_FUNCTION, ObjectIdGetDatum(), OidIsValid, PlanState::outerops, PlanState::outeropsfixed, PlanState::outeropsset, outerPlan, outerPlanState, palloc(), palloc0(), AggState::peragg, AggState::pergroups, AggState::perhash, AggState::pertrans, AggState::phases, PlanState::plan, Agg::plan, Plan::plan_width, PROCOID, AggState::projected_set, ScanState::ps, PlanState::ps_ExprContext, PlanState::qual, Plan::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::table_filled, AggState::tmpcontext, AggStatePerTransData::transfn, Agg::transitionSpace, AggStatePerAggData::transno, TupleTableSlot::tts_tupleDescriptor, TTSOpsMinimalTuple, and TTSOpsVirtual.

Referenced by ExecInitNode().

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

Definition at line 4362 of file nodeAgg.c.

4363 {
4364  ExprContext *econtext = node->ss.ps.ps_ExprContext;
4366  Agg *aggnode = (Agg *) node->ss.ps.plan;
4367  int transno;
4368  int numGroupingSets = Max(node->maxsets, 1);
4369  int setno;
4370 
4371  node->agg_done = false;
4372 
4373  if (node->aggstrategy == AGG_HASHED)
4374  {
4375  /*
4376  * In the hashed case, if we haven't yet built the hash table then we
4377  * can just return; nothing done yet, so nothing to undo. If subnode's
4378  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
4379  * else no reason to re-scan it at all.
4380  */
4381  if (!node->table_filled)
4382  return;
4383 
4384  /*
4385  * If we do have the hash table, and it never spilled, and the subplan
4386  * does not have any parameter changes, and none of our own parameter
4387  * changes affect input expressions of the aggregated functions, then
4388  * we can just rescan the existing hash table; no need to build it
4389  * again.
4390  */
4391  if (outerPlan->chgParam == NULL && !node->hash_ever_spilled &&
4392  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
4393  {
4395  &node->perhash[0].hashiter);
4396  select_current_set(node, 0, true);
4397  return;
4398  }
4399  }
4400 
4401  /* Make sure we have closed any open tuplesorts */
4402  for (transno = 0; transno < node->numtrans; transno++)
4403  {
4404  for (setno = 0; setno < numGroupingSets; setno++)
4405  {
4406  AggStatePerTrans pertrans = &node->pertrans[transno];
4407 
4408  if (pertrans->sortstates[setno])
4409  {
4410  tuplesort_end(pertrans->sortstates[setno]);
4411  pertrans->sortstates[setno] = NULL;
4412  }
4413  }
4414  }
4415 
4416  /*
4417  * We don't need to ReScanExprContext the output tuple context here;
4418  * ExecReScan already did it. But we do need to reset our per-grouping-set
4419  * contexts, which may have transvalues stored in them. (We use rescan
4420  * rather than just reset because transfns may have registered callbacks
4421  * that need to be run now.) For the AGG_HASHED case, see below.
4422  */
4423 
4424  for (setno = 0; setno < numGroupingSets; setno++)
4425  {
4426  ReScanExprContext(node->aggcontexts[setno]);
4427  }
4428 
4429  /* Release first tuple of group, if we have made a copy */
4430  if (node->grp_firstTuple != NULL)
4431  {
4433  node->grp_firstTuple = NULL;
4434  }
4436 
4437  /* Forget current agg values */
4438  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
4439  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
4440 
4441  /*
4442  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
4443  * the hashcontext. This used to be an issue, but now, resetting a context
4444  * automatically deletes sub-contexts too.
4445  */
4446  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
4447  {
4449 
4450  node->hash_ever_spilled = false;
4451  node->hash_spill_mode = false;
4452  node->hash_ngroups_current = 0;
4453 
4455  /* Rebuild an empty hash table */
4456  build_hash_tables(node);
4457  node->table_filled = false;
4458  /* iterator will be reset when the table is filled */
4459 
4460  hashagg_recompile_expressions(node, false, false);
4461  }
4462 
4463  if (node->aggstrategy != AGG_HASHED)
4464  {
4465  /*
4466  * Reset the per-group state (in particular, mark transvalues null)
4467  */
4468  for (setno = 0; setno < numGroupingSets; setno++)
4469  {
4470  MemSet(node->pergroups[setno], 0,
4471  sizeof(AggStatePerGroupData) * node->numaggs);
4472  }
4473 
4474  /* reset to phase 1 */
4475  initialize_phase(node, 1);
4476 
4477  node->input_done = false;
4478  node->projected_set = -1;
4479  }
4480 
4481  if (outerPlan->chgParam == NULL)
4483 }
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:495
#define MemSet(start, val, len)
Definition: c.h:953
void ExecReScan(PlanState *node)
Definition: execAmi.c:78
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:830
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1733
TupleHashTable hashtable
Definition: nodeAgg.h:311
TupleHashIterator hashiter
Definition: nodeAgg.h:312
bool hash_spill_mode
Definition: execnodes.h:2408
uint64 hash_ngroups_current
Definition: execnodes.h:2416
bool hash_ever_spilled
Definition: execnodes.h:2407
Bitmapset * aggParams
Definition: plannodes.h:1019
Bitmapset * chgParam
Definition: execnodes.h:1061

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

◆ hash_agg_entry_size()

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

Definition at line 1686 of file nodeAgg.c.

1687 {
1688  Size tupleChunkSize;
1689  Size pergroupChunkSize;
1690  Size transitionChunkSize;
1691  Size tupleSize = (MAXALIGN(SizeofMinimalTupleHeader) +
1692  tupleWidth);
1693  Size pergroupSize = numTrans * sizeof(AggStatePerGroupData);
1694 
1695  tupleChunkSize = CHUNKHDRSZ + tupleSize;
1696 
1697  if (pergroupSize > 0)
1698  pergroupChunkSize = CHUNKHDRSZ + pergroupSize;
1699  else
1700  pergroupChunkSize = 0;
1701 
1702  if (transitionSpace > 0)
1703  transitionChunkSize = CHUNKHDRSZ + transitionSpace;
1704  else
1705  transitionChunkSize = 0;
1706 
1707  return
1708  sizeof(TupleHashEntryData) +
1709  tupleChunkSize +
1710  pergroupChunkSize +
1711  transitionChunkSize;
1712 }
#define MAXALIGN(LEN)
Definition: c.h:747
struct TupleHashEntryData TupleHashEntryData
#define SizeofMinimalTupleHeader
Definition: htup_details.h:643
#define CHUNKHDRSZ
Definition: nodeAgg.c:321
struct AggStatePerGroupData AggStatePerGroupData

References CHUNKHDRSZ, MAXALIGN, and SizeofMinimalTupleHeader.

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

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

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

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

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