PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 4682 of file nodeAgg.c.

4683 {
4684  Size size;
4685 
4686  /* don't need this if not instrumenting or no workers */
4687  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4688  return;
4689 
4690  size = mul_size(pcxt->nworkers, sizeof(AggregateInstrumentation));
4691  size = add_size(size, offsetof(SharedAggInfo, sinstrument));
4693  shm_toc_estimate_keys(&pcxt->estimator, 1);
4694 }
size_t Size
Definition: c.h:584
#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:488
Size mul_size(Size s1, Size s2)
Definition: shmem.c:505
static pg_noinline void Size size
Definition: slab.c:607
ScanState ss
Definition: execnodes.h:2497
shm_toc_estimator estimator
Definition: parallel.h:41
Instrumentation * instrument
Definition: execnodes.h:1137
PlanState ps
Definition: execnodes.h:1574

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

Referenced by ExecParallelEstimate().

◆ ExecAggInitializeDSM()

void ExecAggInitializeDSM ( AggState node,
ParallelContext pcxt 
)

Definition at line 4703 of file nodeAgg.c.

4704 {
4705  Size size;
4706 
4707  /* don't need this if not instrumenting or no workers */
4708  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4709  return;
4710 
4711  size = offsetof(SharedAggInfo, sinstrument)
4712  + pcxt->nworkers * sizeof(AggregateInstrumentation);
4713  node->shared_info = shm_toc_allocate(pcxt->toc, size);
4714  /* ensure any unfilled slots will contain zeroes */
4715  memset(node->shared_info, 0, size);
4716  node->shared_info->num_workers = pcxt->nworkers;
4717  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
4718  node->shared_info);
4719 }
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:2568
shm_toc * toc
Definition: parallel.h:44
Plan * plan
Definition: execnodes.h:1127
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(), size, AggState::ss, and ParallelContext::toc.

Referenced by ExecParallelInitializeDSM().

◆ ExecAggInitializeWorker()

void ExecAggInitializeWorker ( AggState node,
ParallelWorkerContext pwcxt 
)

Definition at line 4728 of file nodeAgg.c.

4729 {
4730  node->shared_info =
4731  shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
4732 }
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 4741 of file nodeAgg.c.

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

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

Referenced by ExecParallelRetrieveInstrumentation().

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

Definition at line 4303 of file nodeAgg.c.

4304 {
4306  int transno;
4307  int numGroupingSets = Max(node->maxsets, 1);
4308  int setno;
4309 
4310  /*
4311  * When ending a parallel worker, copy the statistics gathered by the
4312  * worker back into shared memory so that it can be picked up by the main
4313  * process to report in EXPLAIN ANALYZE.
4314  */
4315  if (node->shared_info && IsParallelWorker())
4316  {
4318 
4319  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
4322  si->hash_disk_used = node->hash_disk_used;
4323  si->hash_mem_peak = node->hash_mem_peak;
4324  }
4325 
4326  /* Make sure we have closed any open tuplesorts */
4327 
4328  if (node->sort_in)
4329  tuplesort_end(node->sort_in);
4330  if (node->sort_out)
4331  tuplesort_end(node->sort_out);
4332 
4334 
4335  if (node->hash_metacxt != NULL)
4336  {
4338  node->hash_metacxt = NULL;
4339  }
4340 
4341  for (transno = 0; transno < node->numtrans; transno++)
4342  {
4343  AggStatePerTrans pertrans = &node->pertrans[transno];
4344 
4345  for (setno = 0; setno < numGroupingSets; setno++)
4346  {
4347  if (pertrans->sortstates[setno])
4348  tuplesort_end(pertrans->sortstates[setno]);
4349  }
4350  }
4351 
4352  /* And ensure any agg shutdown callbacks have been called */
4353  for (setno = 0; setno < numGroupingSets; setno++)
4354  ReScanExprContext(node->aggcontexts[setno]);
4355  if (node->hashcontext)
4357 
4358  outerPlan = outerPlanState(node);
4360 }
int ParallelWorkerNumber
Definition: parallel.c:114
#define Max(x, y)
Definition: c.h:977
#define Assert(condition)
Definition: c.h:837
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:562
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:443
#define outerPlanState(node)
Definition: execnodes.h:1223
#define IsParallelWorker()
Definition: parallel.h:60
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3132
#define outerPlan(node)
Definition: plannodes.h:183
Tuplesortstate ** sortstates
Definition: nodeAgg.h:162
MemoryContext hash_metacxt
Definition: execnodes.h:2539
Tuplesortstate * sort_out
Definition: execnodes.h:2530
uint64 hash_disk_used
Definition: execnodes.h:2557
AggStatePerTrans pertrans
Definition: execnodes.h:2507
int numtrans
Definition: execnodes.h:2500
ExprContext * hashcontext
Definition: execnodes.h:2508
Size hash_mem_peak
Definition: execnodes.h:2554
int hash_batches_used
Definition: execnodes.h:2558
Tuplesortstate * sort_in
Definition: execnodes.h:2529
int maxsets
Definition: execnodes.h:2527
ExprContext ** aggcontexts
Definition: execnodes.h:2509
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2473
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:951

References AggState::aggcontexts, Assert, ExecEndNode(), 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, ReScanExprContext(), AggState::shared_info, SharedAggInfo::sinstrument, AggState::sort_in, AggState::sort_out, AggStatePerTransData::sortstates, and tuplesort_end().

Referenced by ExecEndNode().

◆ ExecInitAgg()

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

Definition at line 3172 of file nodeAgg.c.

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

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, AggStatePerPhaseData::aggnode, AggStatePerHashData::aggnode, AggStatePerTransData::aggref, AggStatePerAggData::aggref, AggState::aggs, AggStatePerTransData::aggshared, AggState::aggsplit, Agg::aggsplit, AggStatePerPhaseData::aggstrategy, AggState::aggstrategy, Agg::aggstrategy, 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, 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, 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 4363 of file nodeAgg.c.

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

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

1694 {
1695  Size tupleChunkSize;
1696  Size pergroupChunkSize;
1697  Size transitionChunkSize;
1698  Size tupleSize = (MAXALIGN(SizeofMinimalTupleHeader) +
1699  tupleWidth);
1700  Size pergroupSize = numTrans * sizeof(AggStatePerGroupData);
1701 
1702  tupleChunkSize = CHUNKHDRSZ + tupleSize;
1703 
1704  if (pergroupSize > 0)
1705  pergroupChunkSize = CHUNKHDRSZ + pergroupSize;
1706  else
1707  pergroupChunkSize = 0;
1708 
1709  if (transitionSpace > 0)
1710  transitionChunkSize = CHUNKHDRSZ + transitionSpace;
1711  else
1712  transitionChunkSize = 0;
1713 
1714  return
1715  sizeof(TupleHashEntryData) +
1716  tupleChunkSize +
1717  pergroupChunkSize +
1718  transitionChunkSize;
1719 }
#define MAXALIGN(LEN)
Definition: c.h:790
struct TupleHashEntryData TupleHashEntryData
#define SizeofMinimalTupleHeader
Definition: htup_details.h:647
#define CHUNKHDRSZ
Definition: nodeAgg.c:320
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 1797 of file nodeAgg.c.

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

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