PostgreSQL Source Code  git master
nodeAgg.h File Reference
#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 numAggs, Size tupleWidth, Size transitionSpace)
 

Macro Definition Documentation

◆ FIELDNO_AGGSTATEPERGROUPDATA_NOTRANSVALUE

#define FIELDNO_AGGSTATEPERGROUPDATA_NOTRANSVALUE   2

Definition at line 248 of file nodeAgg.h.

Referenced by llvm_compile_expr().

◆ FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUE

#define FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUE   0

Definition at line 243 of file nodeAgg.h.

Referenced by llvm_compile_expr().

◆ FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUEISNULL

#define FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUEISNULL   1

Definition at line 245 of file nodeAgg.h.

Referenced by llvm_compile_expr().

Typedef Documentation

◆ AggStatePerAggData

◆ AggStatePerGroupData

◆ AggStatePerHashData

◆ AggStatePerPhaseData

◆ AggStatePerTransData

Function Documentation

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

Definition at line 3409 of file nodeAgg.c.

References AggState::aggcontexts, ExecClearTuple(), ExecEndNode(), ExecFreeExprContext(), AggState::hashcontext, Max, AggState::maxsets, AggState::numtrans, outerPlan, outerPlanState, AggState::pertrans, ScanState::ps, ReScanExprContext(), AggState::sort_in, AggState::sort_out, AggStatePerTransData::sortstates, AggState::ss, ScanState::ss_ScanTupleSlot, and tuplesort_end().

Referenced by ExecEndNode().

3410 {
3412  int transno;
3413  int numGroupingSets = Max(node->maxsets, 1);
3414  int setno;
3415 
3416  /* Make sure we have closed any open tuplesorts */
3417 
3418  if (node->sort_in)
3419  tuplesort_end(node->sort_in);
3420  if (node->sort_out)
3421  tuplesort_end(node->sort_out);
3422 
3423  for (transno = 0; transno < node->numtrans; transno++)
3424  {
3425  AggStatePerTrans pertrans = &node->pertrans[transno];
3426 
3427  for (setno = 0; setno < numGroupingSets; setno++)
3428  {
3429  if (pertrans->sortstates[setno])
3430  tuplesort_end(pertrans->sortstates[setno]);
3431  }
3432  }
3433 
3434  /* And ensure any agg shutdown callbacks have been called */
3435  for (setno = 0; setno < numGroupingSets; setno++)
3436  ReScanExprContext(node->aggcontexts[setno]);
3437  if (node->hashcontext)
3439 
3440  /*
3441  * We don't actually free any ExprContexts here (see comment in
3442  * ExecFreeExprContext), just unlinking the output one from the plan node
3443  * suffices.
3444  */
3445  ExecFreeExprContext(&node->ss.ps);
3446 
3447  /* clean up tuple table */
3449 
3450  outerPlan = outerPlanState(node);
3451  ExecEndNode(outerPlan);
3452 }
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:537
Tuplesortstate * sort_out
Definition: execnodes.h:2073
ScanState ss
Definition: execnodes.h:2043
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1333
AggStatePerTrans pertrans
Definition: execnodes.h:2053
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:614
int numtrans
Definition: execnodes.h:2046
PlanState ps
Definition: execnodes.h:1330
int maxsets
Definition: execnodes.h:2070
Tuplesortstate * sort_in
Definition: execnodes.h:2072
#define outerPlanState(node)
Definition: execnodes.h:1037
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
#define outerPlan(node)
Definition: plannodes.h:172
ExprContext * hashcontext
Definition: execnodes.h:2054
#define Max(x, y)
Definition: c.h:914
ExprContext ** aggcontexts
Definition: execnodes.h:2055
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:402
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1236

◆ ExecInitAgg()

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

Definition at line 2118 of file nodeAgg.c.

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

Referenced by ExecInitNode().

2119 {
2120  AggState *aggstate;
2121  AggStatePerAgg peraggs;
2122  AggStatePerTrans pertransstates;
2123  AggStatePerGroup *pergroups;
2124  Plan *outerPlan;
2125  ExprContext *econtext;
2126  TupleDesc scanDesc;
2127  int numaggs,
2128  transno,
2129  aggno;
2130  int phase;
2131  int phaseidx;
2132  ListCell *l;
2133  Bitmapset *all_grouped_cols = NULL;
2134  int numGroupingSets = 1;
2135  int numPhases;
2136  int numHashes;
2137  int i = 0;
2138  int j = 0;
2139  bool use_hashing = (node->aggstrategy == AGG_HASHED ||
2140  node->aggstrategy == AGG_MIXED);
2141 
2142  /* check for unsupported flags */
2143  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
2144 
2145  /*
2146  * create state structure
2147  */
2148  aggstate = makeNode(AggState);
2149  aggstate->ss.ps.plan = (Plan *) node;
2150  aggstate->ss.ps.state = estate;
2151  aggstate->ss.ps.ExecProcNode = ExecAgg;
2152 
2153  aggstate->aggs = NIL;
2154  aggstate->numaggs = 0;
2155  aggstate->numtrans = 0;
2156  aggstate->aggstrategy = node->aggstrategy;
2157  aggstate->aggsplit = node->aggsplit;
2158  aggstate->maxsets = 0;
2159  aggstate->projected_set = -1;
2160  aggstate->current_set = 0;
2161  aggstate->peragg = NULL;
2162  aggstate->pertrans = NULL;
2163  aggstate->curperagg = NULL;
2164  aggstate->curpertrans = NULL;
2165  aggstate->input_done = false;
2166  aggstate->agg_done = false;
2167  aggstate->pergroups = NULL;
2168  aggstate->grp_firstTuple = NULL;
2169  aggstate->sort_in = NULL;
2170  aggstate->sort_out = NULL;
2171 
2172  /*
2173  * phases[0] always exists, but is dummy in sorted/plain mode
2174  */
2175  numPhases = (use_hashing ? 1 : 2);
2176  numHashes = (use_hashing ? 1 : 0);
2177 
2178  /*
2179  * Calculate the maximum number of grouping sets in any phase; this
2180  * determines the size of some allocations. Also calculate the number of
2181  * phases, since all hashed/mixed nodes contribute to only a single phase.
2182  */
2183  if (node->groupingSets)
2184  {
2185  numGroupingSets = list_length(node->groupingSets);
2186 
2187  foreach(l, node->chain)
2188  {
2189  Agg *agg = lfirst(l);
2190 
2191  numGroupingSets = Max(numGroupingSets,
2192  list_length(agg->groupingSets));
2193 
2194  /*
2195  * additional AGG_HASHED aggs become part of phase 0, but all
2196  * others add an extra phase.
2197  */
2198  if (agg->aggstrategy != AGG_HASHED)
2199  ++numPhases;
2200  else
2201  ++numHashes;
2202  }
2203  }
2204 
2205  aggstate->maxsets = numGroupingSets;
2206  aggstate->numphases = numPhases;
2207 
2208  aggstate->aggcontexts = (ExprContext **)
2209  palloc0(sizeof(ExprContext *) * numGroupingSets);
2210 
2211  /*
2212  * Create expression contexts. We need three or more, one for
2213  * per-input-tuple processing, one for per-output-tuple processing, one
2214  * for all the hashtables, and one for each grouping set. The per-tuple
2215  * memory context of the per-grouping-set ExprContexts (aggcontexts)
2216  * replaces the standalone memory context formerly used to hold transition
2217  * values. We cheat a little by using ExecAssignExprContext() to build
2218  * all of them.
2219  *
2220  * NOTE: the details of what is stored in aggcontexts and what is stored
2221  * in the regular per-query memory context are driven by a simple
2222  * decision: we want to reset the aggcontext at group boundaries (if not
2223  * hashing) and in ExecReScanAgg to recover no-longer-wanted space.
2224  */
2225  ExecAssignExprContext(estate, &aggstate->ss.ps);
2226  aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
2227 
2228  for (i = 0; i < numGroupingSets; ++i)
2229  {
2230  ExecAssignExprContext(estate, &aggstate->ss.ps);
2231  aggstate->aggcontexts[i] = aggstate->ss.ps.ps_ExprContext;
2232  }
2233 
2234  if (use_hashing)
2235  {
2236  ExecAssignExprContext(estate, &aggstate->ss.ps);
2237  aggstate->hashcontext = aggstate->ss.ps.ps_ExprContext;
2238  }
2239 
2240  ExecAssignExprContext(estate, &aggstate->ss.ps);
2241 
2242  /*
2243  * Initialize child nodes.
2244  *
2245  * If we are doing a hashed aggregation then the child plan does not need
2246  * to handle REWIND efficiently; see ExecReScanAgg.
2247  */
2248  if (node->aggstrategy == AGG_HASHED)
2249  eflags &= ~EXEC_FLAG_REWIND;
2250  outerPlan = outerPlan(node);
2251  outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags);
2252 
2253  /*
2254  * initialize source tuple type.
2255  */
2256  aggstate->ss.ps.outerops =
2258  &aggstate->ss.ps.outeropsfixed);
2259  aggstate->ss.ps.outeropsset = true;
2260 
2261  ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss,
2262  aggstate->ss.ps.outerops);
2263  scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
2264 
2265  /*
2266  * If there are more than two phases (including a potential dummy phase
2267  * 0), input will be resorted using tuplesort. Need a slot for that.
2268  */
2269  if (numPhases > 2)
2270  {
2271  aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc,
2273 
2274  /*
2275  * The output of the tuplesort, and the output from the outer child
2276  * might not use the same type of slot. In most cases the child will
2277  * be a Sort, and thus return a TTSOpsMinimalTuple type slot - but the
2278  * input can also be presorted due an index, in which case it could be
2279  * a different type of slot.
2280  *
2281  * XXX: For efficiency it would be good to instead/additionally
2282  * generate expressions with corresponding settings of outerops* for
2283  * the individual phases - deforming is often a bottleneck for
2284  * aggregations with lots of rows per group. If there's multiple
2285  * sorts, we know that all but the first use TTSOpsMinimalTuple (via
2286  * the nodeAgg.c internal tuplesort).
2287  */
2288  if (aggstate->ss.ps.outeropsfixed &&
2289  aggstate->ss.ps.outerops != &TTSOpsMinimalTuple)
2290  aggstate->ss.ps.outeropsfixed = false;
2291  }
2292 
2293  /*
2294  * Initialize result type, slot and projection.
2295  */
2297  ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
2298 
2299  /*
2300  * initialize child expressions
2301  *
2302  * We expect the parser to have checked that no aggs contain other agg
2303  * calls in their arguments (and just to be sure, we verify it again while
2304  * initializing the plan node). This would make no sense under SQL
2305  * semantics, and it's forbidden by the spec. Because it is true, we
2306  * don't need to worry about evaluating the aggs in any particular order.
2307  *
2308  * Note: execExpr.c finds Aggrefs for us, and adds their AggrefExprState
2309  * nodes to aggstate->aggs. Aggrefs in the qual are found here; Aggrefs
2310  * in the targetlist are found during ExecAssignProjectionInfo, below.
2311  */
2312  aggstate->ss.ps.qual =
2313  ExecInitQual(node->plan.qual, (PlanState *) aggstate);
2314 
2315  /*
2316  * We should now have found all Aggrefs in the targetlist and quals.
2317  */
2318  numaggs = aggstate->numaggs;
2319  Assert(numaggs == list_length(aggstate->aggs));
2320 
2321  /*
2322  * For each phase, prepare grouping set data and fmgr lookup data for
2323  * compare functions. Accumulate all_grouped_cols in passing.
2324  */
2325  aggstate->phases = palloc0(numPhases * sizeof(AggStatePerPhaseData));
2326 
2327  aggstate->num_hashes = numHashes;
2328  if (numHashes)
2329  {
2330  aggstate->perhash = palloc0(sizeof(AggStatePerHashData) * numHashes);
2331  aggstate->phases[0].numsets = 0;
2332  aggstate->phases[0].gset_lengths = palloc(numHashes * sizeof(int));
2333  aggstate->phases[0].grouped_cols = palloc(numHashes * sizeof(Bitmapset *));
2334  }
2335 
2336  phase = 0;
2337  for (phaseidx = 0; phaseidx <= list_length(node->chain); ++phaseidx)
2338  {
2339  Agg *aggnode;
2340  Sort *sortnode;
2341 
2342  if (phaseidx > 0)
2343  {
2344  aggnode = list_nth_node(Agg, node->chain, phaseidx - 1);
2345  sortnode = castNode(Sort, aggnode->plan.lefttree);
2346  }
2347  else
2348  {
2349  aggnode = node;
2350  sortnode = NULL;
2351  }
2352 
2353  Assert(phase <= 1 || sortnode);
2354 
2355  if (aggnode->aggstrategy == AGG_HASHED
2356  || aggnode->aggstrategy == AGG_MIXED)
2357  {
2358  AggStatePerPhase phasedata = &aggstate->phases[0];
2359  AggStatePerHash perhash;
2360  Bitmapset *cols = NULL;
2361 
2362  Assert(phase == 0);
2363  i = phasedata->numsets++;
2364  perhash = &aggstate->perhash[i];
2365 
2366  /* phase 0 always points to the "real" Agg in the hash case */
2367  phasedata->aggnode = node;
2368  phasedata->aggstrategy = node->aggstrategy;
2369 
2370  /* but the actual Agg node representing this hash is saved here */
2371  perhash->aggnode = aggnode;
2372 
2373  phasedata->gset_lengths[i] = perhash->numCols = aggnode->numCols;
2374 
2375  for (j = 0; j < aggnode->numCols; ++j)
2376  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
2377 
2378  phasedata->grouped_cols[i] = cols;
2379 
2380  all_grouped_cols = bms_add_members(all_grouped_cols, cols);
2381  continue;
2382  }
2383  else
2384  {
2385  AggStatePerPhase phasedata = &aggstate->phases[++phase];
2386  int num_sets;
2387 
2388  phasedata->numsets = num_sets = list_length(aggnode->groupingSets);
2389 
2390  if (num_sets)
2391  {
2392  phasedata->gset_lengths = palloc(num_sets * sizeof(int));
2393  phasedata->grouped_cols = palloc(num_sets * sizeof(Bitmapset *));
2394 
2395  i = 0;
2396  foreach(l, aggnode->groupingSets)
2397  {
2398  int current_length = list_length(lfirst(l));
2399  Bitmapset *cols = NULL;
2400 
2401  /* planner forces this to be correct */
2402  for (j = 0; j < current_length; ++j)
2403  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
2404 
2405  phasedata->grouped_cols[i] = cols;
2406  phasedata->gset_lengths[i] = current_length;
2407 
2408  ++i;
2409  }
2410 
2411  all_grouped_cols = bms_add_members(all_grouped_cols,
2412  phasedata->grouped_cols[0]);
2413  }
2414  else
2415  {
2416  Assert(phaseidx == 0);
2417 
2418  phasedata->gset_lengths = NULL;
2419  phasedata->grouped_cols = NULL;
2420  }
2421 
2422  /*
2423  * If we are grouping, precompute fmgr lookup data for inner loop.
2424  */
2425  if (aggnode->aggstrategy == AGG_SORTED)
2426  {
2427  int i = 0;
2428 
2429  Assert(aggnode->numCols > 0);
2430 
2431  /*
2432  * Build a separate function for each subset of columns that
2433  * need to be compared.
2434  */
2435  phasedata->eqfunctions =
2436  (ExprState **) palloc0(aggnode->numCols * sizeof(ExprState *));
2437 
2438  /* for each grouping set */
2439  for (i = 0; i < phasedata->numsets; i++)
2440  {
2441  int length = phasedata->gset_lengths[i];
2442 
2443  if (phasedata->eqfunctions[length - 1] != NULL)
2444  continue;
2445 
2446  phasedata->eqfunctions[length - 1] =
2447  execTuplesMatchPrepare(scanDesc,
2448  length,
2449  aggnode->grpColIdx,
2450  aggnode->grpOperators,
2451  aggnode->grpCollations,
2452  (PlanState *) aggstate);
2453  }
2454 
2455  /* and for all grouped columns, unless already computed */
2456  if (phasedata->eqfunctions[aggnode->numCols - 1] == NULL)
2457  {
2458  phasedata->eqfunctions[aggnode->numCols - 1] =
2459  execTuplesMatchPrepare(scanDesc,
2460  aggnode->numCols,
2461  aggnode->grpColIdx,
2462  aggnode->grpOperators,
2463  aggnode->grpCollations,
2464  (PlanState *) aggstate);
2465  }
2466  }
2467 
2468  phasedata->aggnode = aggnode;
2469  phasedata->aggstrategy = aggnode->aggstrategy;
2470  phasedata->sortnode = sortnode;
2471  }
2472  }
2473 
2474  /*
2475  * Convert all_grouped_cols to a descending-order list.
2476  */
2477  i = -1;
2478  while ((i = bms_next_member(all_grouped_cols, i)) >= 0)
2479  aggstate->all_grouped_cols = lcons_int(i, aggstate->all_grouped_cols);
2480 
2481  /*
2482  * Set up aggregate-result storage in the output expr context, and also
2483  * allocate my private per-agg working storage
2484  */
2485  econtext = aggstate->ss.ps.ps_ExprContext;
2486  econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
2487  econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numaggs);
2488 
2489  peraggs = (AggStatePerAgg) palloc0(sizeof(AggStatePerAggData) * numaggs);
2490  pertransstates = (AggStatePerTrans) palloc0(sizeof(AggStatePerTransData) * numaggs);
2491 
2492  aggstate->peragg = peraggs;
2493  aggstate->pertrans = pertransstates;
2494 
2495 
2496  aggstate->all_pergroups =
2498  * (numGroupingSets + numHashes));
2499  pergroups = aggstate->all_pergroups;
2500 
2501  if (node->aggstrategy != AGG_HASHED)
2502  {
2503  for (i = 0; i < numGroupingSets; i++)
2504  {
2505  pergroups[i] = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData)
2506  * numaggs);
2507  }
2508 
2509  aggstate->pergroups = pergroups;
2510  pergroups += numGroupingSets;
2511  }
2512 
2513  /*
2514  * Hashing can only appear in the initial phase.
2515  */
2516  if (use_hashing)
2517  {
2518  /* this is an array of pointers, not structures */
2519  aggstate->hash_pergroup = pergroups;
2520 
2521  find_hash_columns(aggstate);
2522  build_hash_tables(aggstate);
2523  aggstate->table_filled = false;
2524  }
2525 
2526  /*
2527  * Initialize current phase-dependent values to initial phase. The initial
2528  * phase is 1 (first sort pass) for all strategies that use sorting (if
2529  * hashing is being done too, then phase 0 is processed last); but if only
2530  * hashing is being done, then phase 0 is all there is.
2531  */
2532  if (node->aggstrategy == AGG_HASHED)
2533  {
2534  aggstate->current_phase = 0;
2535  initialize_phase(aggstate, 0);
2536  select_current_set(aggstate, 0, true);
2537  }
2538  else
2539  {
2540  aggstate->current_phase = 1;
2541  initialize_phase(aggstate, 1);
2542  select_current_set(aggstate, 0, false);
2543  }
2544 
2545  /* -----------------
2546  * Perform lookups of aggregate function info, and initialize the
2547  * unchanging fields of the per-agg and per-trans data.
2548  *
2549  * We try to optimize by detecting duplicate aggregate functions so that
2550  * their state and final values are re-used, rather than needlessly being
2551  * re-calculated independently. We also detect aggregates that are not
2552  * the same, but which can share the same transition state.
2553  *
2554  * Scenarios:
2555  *
2556  * 1. Identical aggregate function calls appear in the query:
2557  *
2558  * SELECT SUM(x) FROM ... HAVING SUM(x) > 0
2559  *
2560  * Since these aggregates are identical, we only need to calculate
2561  * the value once. Both aggregates will share the same 'aggno' value.
2562  *
2563  * 2. Two different aggregate functions appear in the query, but the
2564  * aggregates have the same arguments, transition functions and
2565  * initial values (and, presumably, different final functions):
2566  *
2567  * SELECT AVG(x), STDDEV(x) FROM ...
2568  *
2569  * In this case we must create a new peragg for the varying aggregate,
2570  * and we need to call the final functions separately, but we need
2571  * only run the transition function once. (This requires that the
2572  * final functions be nondestructive of the transition state, but
2573  * that's required anyway for other reasons.)
2574  *
2575  * For either of these optimizations to be valid, all aggregate properties
2576  * used in the transition phase must be the same, including any modifiers
2577  * such as ORDER BY, DISTINCT and FILTER, and the arguments mustn't
2578  * contain any volatile functions.
2579  * -----------------
2580  */
2581  aggno = -1;
2582  transno = -1;
2583  foreach(l, aggstate->aggs)
2584  {
2585  AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(l);
2586  Aggref *aggref = aggrefstate->aggref;
2587  AggStatePerAgg peragg;
2588  AggStatePerTrans pertrans;
2589  int existing_aggno;
2590  int existing_transno;
2591  List *same_input_transnos;
2592  Oid inputTypes[FUNC_MAX_ARGS];
2593  int numArguments;
2594  int numDirectArgs;
2595  HeapTuple aggTuple;
2596  Form_pg_aggregate aggform;
2597  AclResult aclresult;
2598  Oid transfn_oid,
2599  finalfn_oid;
2600  bool shareable;
2601  Oid serialfn_oid,
2602  deserialfn_oid;
2603  Expr *finalfnexpr;
2604  Oid aggtranstype;
2605  Datum textInitVal;
2606  Datum initValue;
2607  bool initValueIsNull;
2608 
2609  /* Planner should have assigned aggregate to correct level */
2610  Assert(aggref->agglevelsup == 0);
2611  /* ... and the split mode should match */
2612  Assert(aggref->aggsplit == aggstate->aggsplit);
2613 
2614  /* 1. Check for already processed aggs which can be re-used */
2615  existing_aggno = find_compatible_peragg(aggref, aggstate, aggno,
2616  &same_input_transnos);
2617  if (existing_aggno != -1)
2618  {
2619  /*
2620  * Existing compatible agg found. so just point the Aggref to the
2621  * same per-agg struct.
2622  */
2623  aggrefstate->aggno = existing_aggno;
2624  continue;
2625  }
2626 
2627  /* Mark Aggref state node with assigned index in the result array */
2628  peragg = &peraggs[++aggno];
2629  peragg->aggref = aggref;
2630  aggrefstate->aggno = aggno;
2631 
2632  /* Fetch the pg_aggregate row */
2633  aggTuple = SearchSysCache1(AGGFNOID,
2634  ObjectIdGetDatum(aggref->aggfnoid));
2635  if (!HeapTupleIsValid(aggTuple))
2636  elog(ERROR, "cache lookup failed for aggregate %u",
2637  aggref->aggfnoid);
2638  aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
2639 
2640  /* Check permission to call aggregate function */
2641  aclresult = pg_proc_aclcheck(aggref->aggfnoid, GetUserId(),
2642  ACL_EXECUTE);
2643  if (aclresult != ACLCHECK_OK)
2644  aclcheck_error(aclresult, OBJECT_AGGREGATE,
2645  get_func_name(aggref->aggfnoid));
2647 
2648  /* planner recorded transition state type in the Aggref itself */
2649  aggtranstype = aggref->aggtranstype;
2650  Assert(OidIsValid(aggtranstype));
2651 
2652  /*
2653  * If this aggregation is performing state combines, then instead of
2654  * using the transition function, we'll use the combine function
2655  */
2656  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
2657  {
2658  transfn_oid = aggform->aggcombinefn;
2659 
2660  /* If not set then the planner messed up */
2661  if (!OidIsValid(transfn_oid))
2662  elog(ERROR, "combinefn not set for aggregate function");
2663  }
2664  else
2665  transfn_oid = aggform->aggtransfn;
2666 
2667  /* Final function only required if we're finalizing the aggregates */
2668  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
2669  peragg->finalfn_oid = finalfn_oid = InvalidOid;
2670  else
2671  peragg->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
2672 
2673  /*
2674  * If finalfn is marked read-write, we can't share transition states;
2675  * but it is okay to share states for AGGMODIFY_SHAREABLE aggs. Also,
2676  * if we're not executing the finalfn here, we can share regardless.
2677  */
2678  shareable = (aggform->aggfinalmodify != AGGMODIFY_READ_WRITE) ||
2679  (finalfn_oid == InvalidOid);
2680  peragg->shareable = shareable;
2681 
2682  serialfn_oid = InvalidOid;
2683  deserialfn_oid = InvalidOid;
2684 
2685  /*
2686  * Check if serialization/deserialization is required. We only do it
2687  * for aggregates that have transtype INTERNAL.
2688  */
2689  if (aggtranstype == INTERNALOID)
2690  {
2691  /*
2692  * The planner should only have generated a serialize agg node if
2693  * every aggregate with an INTERNAL state has a serialization
2694  * function. Verify that.
2695  */
2696  if (DO_AGGSPLIT_SERIALIZE(aggstate->aggsplit))
2697  {
2698  /* serialization only valid when not running finalfn */
2700 
2701  if (!OidIsValid(aggform->aggserialfn))
2702  elog(ERROR, "serialfunc not provided for serialization aggregation");
2703  serialfn_oid = aggform->aggserialfn;
2704  }
2705 
2706  /* Likewise for deserialization functions */
2707  if (DO_AGGSPLIT_DESERIALIZE(aggstate->aggsplit))
2708  {
2709  /* deserialization only valid when combining states */
2710  Assert(DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
2711 
2712  if (!OidIsValid(aggform->aggdeserialfn))
2713  elog(ERROR, "deserialfunc not provided for deserialization aggregation");
2714  deserialfn_oid = aggform->aggdeserialfn;
2715  }
2716  }
2717 
2718  /* Check that aggregate owner has permission to call component fns */
2719  {
2720  HeapTuple procTuple;
2721  Oid aggOwner;
2722 
2723  procTuple = SearchSysCache1(PROCOID,
2724  ObjectIdGetDatum(aggref->aggfnoid));
2725  if (!HeapTupleIsValid(procTuple))
2726  elog(ERROR, "cache lookup failed for function %u",
2727  aggref->aggfnoid);
2728  aggOwner = ((Form_pg_proc) GETSTRUCT(procTuple))->proowner;
2729  ReleaseSysCache(procTuple);
2730 
2731  aclresult = pg_proc_aclcheck(transfn_oid, aggOwner,
2732  ACL_EXECUTE);
2733  if (aclresult != ACLCHECK_OK)
2734  aclcheck_error(aclresult, OBJECT_FUNCTION,
2735  get_func_name(transfn_oid));
2736  InvokeFunctionExecuteHook(transfn_oid);
2737  if (OidIsValid(finalfn_oid))
2738  {
2739  aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
2740  ACL_EXECUTE);
2741  if (aclresult != ACLCHECK_OK)
2742  aclcheck_error(aclresult, OBJECT_FUNCTION,
2743  get_func_name(finalfn_oid));
2744  InvokeFunctionExecuteHook(finalfn_oid);
2745  }
2746  if (OidIsValid(serialfn_oid))
2747  {
2748  aclresult = pg_proc_aclcheck(serialfn_oid, aggOwner,
2749  ACL_EXECUTE);
2750  if (aclresult != ACLCHECK_OK)
2751  aclcheck_error(aclresult, OBJECT_FUNCTION,
2752  get_func_name(serialfn_oid));
2753  InvokeFunctionExecuteHook(serialfn_oid);
2754  }
2755  if (OidIsValid(deserialfn_oid))
2756  {
2757  aclresult = pg_proc_aclcheck(deserialfn_oid, aggOwner,
2758  ACL_EXECUTE);
2759  if (aclresult != ACLCHECK_OK)
2760  aclcheck_error(aclresult, OBJECT_FUNCTION,
2761  get_func_name(deserialfn_oid));
2762  InvokeFunctionExecuteHook(deserialfn_oid);
2763  }
2764  }
2765 
2766  /*
2767  * Get actual datatypes of the (nominal) aggregate inputs. These
2768  * could be different from the agg's declared input types, when the
2769  * agg accepts ANY or a polymorphic type.
2770  */
2771  numArguments = get_aggregate_argtypes(aggref, inputTypes);
2772 
2773  /* Count the "direct" arguments, if any */
2774  numDirectArgs = list_length(aggref->aggdirectargs);
2775 
2776  /* Detect how many arguments to pass to the finalfn */
2777  if (aggform->aggfinalextra)
2778  peragg->numFinalArgs = numArguments + 1;
2779  else
2780  peragg->numFinalArgs = numDirectArgs + 1;
2781 
2782  /* Initialize any direct-argument expressions */
2783  peragg->aggdirectargs = ExecInitExprList(aggref->aggdirectargs,
2784  (PlanState *) aggstate);
2785 
2786  /*
2787  * build expression trees using actual argument & result types for the
2788  * finalfn, if it exists and is required.
2789  */
2790  if (OidIsValid(finalfn_oid))
2791  {
2792  build_aggregate_finalfn_expr(inputTypes,
2793  peragg->numFinalArgs,
2794  aggtranstype,
2795  aggref->aggtype,
2796  aggref->inputcollid,
2797  finalfn_oid,
2798  &finalfnexpr);
2799  fmgr_info(finalfn_oid, &peragg->finalfn);
2800  fmgr_info_set_expr((Node *) finalfnexpr, &peragg->finalfn);
2801  }
2802 
2803  /* get info about the output value's datatype */
2804  get_typlenbyval(aggref->aggtype,
2805  &peragg->resulttypeLen,
2806  &peragg->resulttypeByVal);
2807 
2808  /*
2809  * initval is potentially null, so don't try to access it as a struct
2810  * field. Must do it the hard way with SysCacheGetAttr.
2811  */
2812  textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
2813  Anum_pg_aggregate_agginitval,
2814  &initValueIsNull);
2815  if (initValueIsNull)
2816  initValue = (Datum) 0;
2817  else
2818  initValue = GetAggInitVal(textInitVal, aggtranstype);
2819 
2820  /*
2821  * 2. Build working state for invoking the transition function, or
2822  * look up previously initialized working state, if we can share it.
2823  *
2824  * find_compatible_peragg() already collected a list of shareable
2825  * per-Trans's with the same inputs. Check if any of them have the
2826  * same transition function and initial value.
2827  */
2828  existing_transno = find_compatible_pertrans(aggstate, aggref,
2829  shareable,
2830  transfn_oid, aggtranstype,
2831  serialfn_oid, deserialfn_oid,
2832  initValue, initValueIsNull,
2833  same_input_transnos);
2834  if (existing_transno != -1)
2835  {
2836  /*
2837  * Existing compatible trans found, so just point the 'peragg' to
2838  * the same per-trans struct, and mark the trans state as shared.
2839  */
2840  pertrans = &pertransstates[existing_transno];
2841  pertrans->aggshared = true;
2842  peragg->transno = existing_transno;
2843  }
2844  else
2845  {
2846  pertrans = &pertransstates[++transno];
2847  build_pertrans_for_aggref(pertrans, aggstate, estate,
2848  aggref, transfn_oid, aggtranstype,
2849  serialfn_oid, deserialfn_oid,
2850  initValue, initValueIsNull,
2851  inputTypes, numArguments);
2852  peragg->transno = transno;
2853  }
2854  ReleaseSysCache(aggTuple);
2855  }
2856 
2857  /*
2858  * Update aggstate->numaggs to be the number of unique aggregates found.
2859  * Also set numstates to the number of unique transition states found.
2860  */
2861  aggstate->numaggs = aggno + 1;
2862  aggstate->numtrans = transno + 1;
2863 
2864  /*
2865  * Last, check whether any more aggregates got added onto the node while
2866  * we processed the expressions for the aggregate arguments (including not
2867  * only the regular arguments and FILTER expressions handled immediately
2868  * above, but any direct arguments we might've handled earlier). If so,
2869  * we have nested aggregate functions, which is semantically nonsensical,
2870  * so complain. (This should have been caught by the parser, so we don't
2871  * need to work hard on a helpful error message; but we defend against it
2872  * here anyway, just to be sure.)
2873  */
2874  if (numaggs != list_length(aggstate->aggs))
2875  ereport(ERROR,
2876  (errcode(ERRCODE_GROUPING_ERROR),
2877  errmsg("aggregate function calls cannot be nested")));
2878 
2879  /*
2880  * Build expressions doing all the transition work at once. We build a
2881  * different one for each phase, as the number of transition function
2882  * invocation can differ between phases. Note this'll work both for
2883  * transition and combination functions (although there'll only be one
2884  * phase in the latter case).
2885  */
2886  for (phaseidx = 0; phaseidx < aggstate->numphases; phaseidx++)
2887  {
2888  AggStatePerPhase phase = &aggstate->phases[phaseidx];
2889  bool dohash = false;
2890  bool dosort = false;
2891 
2892  /* phase 0 doesn't necessarily exist */
2893  if (!phase->aggnode)
2894  continue;
2895 
2896  if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 1)
2897  {
2898  /*
2899  * Phase one, and only phase one, in a mixed agg performs both
2900  * sorting and aggregation.
2901  */
2902  dohash = true;
2903  dosort = true;
2904  }
2905  else if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 0)
2906  {
2907  /*
2908  * No need to compute a transition function for an AGG_MIXED phase
2909  * 0 - the contents of the hashtables will have been computed
2910  * during phase 1.
2911  */
2912  continue;
2913  }
2914  else if (phase->aggstrategy == AGG_PLAIN ||
2915  phase->aggstrategy == AGG_SORTED)
2916  {
2917  dohash = false;
2918  dosort = true;
2919  }
2920  else if (phase->aggstrategy == AGG_HASHED)
2921  {
2922  dohash = true;
2923  dosort = false;
2924  }
2925  else
2926  Assert(false);
2927 
2928  phase->evaltrans = ExecBuildAggTrans(aggstate, phase, dosort, dohash);
2929 
2930  }
2931 
2932  return aggstate;
2933 }
struct AggStatePerTransData * AggStatePerTrans
Definition: execnodes.h:2036
ExprState ** eqfunctions
Definition: nodeAgg.h:277
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:2083
#define NIL
Definition: pg_list.h:65
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:2037
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:305
int numCols
Definition: plannodes.h:811
List * qual
Definition: plannodes.h:143
AggStatePerPhase phases
Definition: execnodes.h:2071
Datum * ecxt_aggvalues
Definition: execnodes.h:243
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1801
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
AttrNumber * grpColIdx
Definition: plannodes.h:812
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:463
List * lcons_int(int datum, List *list)
Definition: list.c:472
int numaggs
Definition: execnodes.h:2045
Oid GetUserId(void)
Definition: miscinit.c:378
bool agg_done
Definition: execnodes.h:2063
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
Oid * grpCollations
Definition: plannodes.h:814
ExprState * ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, bool doSort, bool doHash)
Definition: execExpr.c:2929
TupleTableSlot * sort_slot
Definition: execnodes.h:2074
List * all_grouped_cols
Definition: execnodes.h:2068
Tuplesortstate * sort_out
Definition: execnodes.h:2073
ScanState ss
Definition: execnodes.h:2043
ExprContext * ps_ExprContext
Definition: execnodes.h:982
ExprState * evaltrans
Definition: nodeAgg.h:282
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
Oid inputcollid
Definition: primnodes.h:315
int current_phase
Definition: execnodes.h:2051
Definition: nodes.h:525
AggSplit aggsplit
Definition: execnodes.h:2048
static TupleTableSlot * ExecAgg(PlanState *pstate)
Definition: nodeAgg.c:1573
int errcode(int sqlerrcode)
Definition: elog.c:608
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1333
void build_aggregate_finalfn_expr(Oid *agg_input_types, int num_finalfn_inputs, Oid agg_state_type, Oid agg_result_type, Oid agg_input_collation, Oid finalfn_oid, Expr **finalfnexpr)
Definition: parse_agg.c:2037
static int find_compatible_pertrans(AggState *aggstate, Aggref *newagg, bool shareable, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, List *transnos)
Definition: nodeAgg.c:3358
AggStatePerTrans pertrans
Definition: execnodes.h:2053
EState * state
Definition: execnodes.h:945
int projected_set
Definition: execnodes.h:2064
unsigned int Oid
Definition: postgres_ext.h:31
HeapTuple grp_firstTuple
Definition: execnodes.h:2078
Aggref * aggref
Definition: nodeAgg.h:186
int current_set
Definition: execnodes.h:2066
#define OidIsValid(objectId)
Definition: c.h:644
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:787
int numtrans
Definition: execnodes.h:2046
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:207
ExprContext * tmpcontext
Definition: execnodes.h:2056
#define FUNC_MAX_ARGS
Bitmapset ** grouped_cols
Definition: nodeAgg.h:276
PlanState ps
Definition: execnodes.h:1330
int maxsets
Definition: execnodes.h:2070
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:789
AggStrategy aggstrategy
Definition: plannodes.h:809
bool table_filled
Definition: execnodes.h:2080
AggStrategy aggstrategy
Definition: execnodes.h:2047
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1410
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:124
static void find_hash_columns(AggState *aggstate)
Definition: nodeAgg.c:1362
Tuplesortstate * sort_in
Definition: execnodes.h:2072
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define outerPlanState(node)
Definition: execnodes.h:1037
Aggref * aggref
Definition: execnodes.h:750
#define list_nth_node(type, list, n)
Definition: pg_list.h:305
static int initValue(long lng_val)
Definition: informix.c:677
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:499
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:316
Index agglevelsup
Definition: primnodes.h:327
List * aggdirectargs
Definition: primnodes.h:318
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition: nodeAgg.c:3252
AggStatePerAgg curperagg
Definition: execnodes.h:2059
AggStatePerHash perhash
Definition: execnodes.h:2082
bool outeropsset
Definition: execnodes.h:1024
AggStrategy aggstrategy
Definition: nodeAgg.h:273
#define EXEC_FLAG_REWIND
Definition: executor.h:57
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:191
#define outerPlan(node)
Definition: plannodes.h:172
int num_hashes
Definition: execnodes.h:2081
Plan plan
Definition: plannodes.h:808
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
bool input_done
Definition: execnodes.h:2062
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
ExprContext * hashcontext
Definition: execnodes.h:2054
bool * ecxt_aggnulls
Definition: execnodes.h:245
static int find_compatible_peragg(Aggref *newagg, AggState *aggstate, int lastaggno, List **same_input_transnos)
Definition: nodeAgg.c:3280
void * palloc0(Size size)
Definition: mcxt.c:980
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:949
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1377
List * groupingSets
Definition: plannodes.h:818
int16 resulttypeLen
Definition: nodeAgg.h:215
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:324
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:133
Plan * plan
Definition: execnodes.h:943
#define InvalidOid
Definition: postgres_ext.h:36
Oid aggfnoid
Definition: primnodes.h:312
#define Max(x, y)
Definition: c.h:914
ExprContext ** aggcontexts
Definition: execnodes.h:2055
#define makeNode(_type_)
Definition: nodes.h:573
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:62
#define EXEC_FLAG_MARK
Definition: executor.h:59
AggSplit aggsplit
Definition: plannodes.h:810
struct AggStatePerAggData * AggStatePerAgg
Definition: execnodes.h:2035
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
AggSplit aggsplit
Definition: primnodes.h:328
AggStatePerGroup * pergroups
Definition: execnodes.h:2076
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:444
static int list_length(const List *l)
Definition: pg_list.h:169
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:788
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2029
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1769
bool outeropsfixed
Definition: execnodes.h:1020
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:790
struct Plan * lefttree
Definition: plannodes.h:144
int numphases
Definition: execnodes.h:2050
ExprState * qual
Definition: execnodes.h:964
Oid * grpOperators
Definition: plannodes.h:813
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822
List * chain
Definition: plannodes.h:819
AggStatePerAgg peragg
Definition: execnodes.h:2052
#define ACL_EXECUTE
Definition: parsenodes.h:81
#define elog(elevel,...)
Definition: elog.h:228
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4653
int i
List * aggdirectargs
Definition: nodeAgg.h:209
Oid aggtranstype
Definition: primnodes.h:316
AggStatePerTrans curpertrans
Definition: execnodes.h:2061
Oid aggtype
Definition: primnodes.h:313
bool resulttypeByVal
Definition: nodeAgg.h:216
Definition: plannodes.h:806
List * aggs
Definition: execnodes.h:2044
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:646
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1819
static void build_pertrans_for_aggref(AggStatePerTrans pertrans, AggState *aggstate, EState *estate, Aggref *aggref, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, Oid *inputTypes, int numArguments)
Definition: nodeAgg.c:2944
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:138
Definition: pg_list.h:50
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
FmgrInfo finalfn
Definition: nodeAgg.h:198
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
static void build_hash_tables(AggState *aggstate)
Definition: nodeAgg.c:1280
const TupleTableSlotOps * outerops
Definition: execnodes.h:1016
AggStatePerGroup * all_pergroups
Definition: execnodes.h:2088

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

Definition at line 3455 of file nodeAgg.c.

References AggState::agg_done, AGG_HASHED, AGG_MIXED, AggState::aggcontexts, Agg::aggParams, AggState::aggstrategy, bms_overlap(), build_hash_tables(), PlanState::chgParam, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExecClearTuple(), ExecReScan(), AggState::grp_firstTuple, AggState::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().

3456 {
3457  ExprContext *econtext = node->ss.ps.ps_ExprContext;
3459  Agg *aggnode = (Agg *) node->ss.ps.plan;
3460  int transno;
3461  int numGroupingSets = Max(node->maxsets, 1);
3462  int setno;
3463 
3464  node->agg_done = false;
3465 
3466  if (node->aggstrategy == AGG_HASHED)
3467  {
3468  /*
3469  * In the hashed case, if we haven't yet built the hash table then we
3470  * can just return; nothing done yet, so nothing to undo. If subnode's
3471  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
3472  * else no reason to re-scan it at all.
3473  */
3474  if (!node->table_filled)
3475  return;
3476 
3477  /*
3478  * If we do have the hash table, and the subplan does not have any
3479  * parameter changes, and none of our own parameter changes affect
3480  * input expressions of the aggregated functions, then we can just
3481  * rescan the existing hash table; no need to build it again.
3482  */
3483  if (outerPlan->chgParam == NULL &&
3484  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
3485  {
3487  &node->perhash[0].hashiter);
3488  select_current_set(node, 0, true);
3489  return;
3490  }
3491  }
3492 
3493  /* Make sure we have closed any open tuplesorts */
3494  for (transno = 0; transno < node->numtrans; transno++)
3495  {
3496  for (setno = 0; setno < numGroupingSets; setno++)
3497  {
3498  AggStatePerTrans pertrans = &node->pertrans[transno];
3499 
3500  if (pertrans->sortstates[setno])
3501  {
3502  tuplesort_end(pertrans->sortstates[setno]);
3503  pertrans->sortstates[setno] = NULL;
3504  }
3505  }
3506  }
3507 
3508  /*
3509  * We don't need to ReScanExprContext the output tuple context here;
3510  * ExecReScan already did it. But we do need to reset our per-grouping-set
3511  * contexts, which may have transvalues stored in them. (We use rescan
3512  * rather than just reset because transfns may have registered callbacks
3513  * that need to be run now.) For the AGG_HASHED case, see below.
3514  */
3515 
3516  for (setno = 0; setno < numGroupingSets; setno++)
3517  {
3518  ReScanExprContext(node->aggcontexts[setno]);
3519  }
3520 
3521  /* Release first tuple of group, if we have made a copy */
3522  if (node->grp_firstTuple != NULL)
3523  {
3525  node->grp_firstTuple = NULL;
3526  }
3528 
3529  /* Forget current agg values */
3530  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
3531  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
3532 
3533  /*
3534  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
3535  * the hashcontext. This used to be an issue, but now, resetting a context
3536  * automatically deletes sub-contexts too.
3537  */
3538  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
3539  {
3541  /* Rebuild an empty hash table */
3542  build_hash_tables(node);
3543  node->table_filled = false;
3544  /* iterator will be reset when the table is filled */
3545  }
3546 
3547  if (node->aggstrategy != AGG_HASHED)
3548  {
3549  /*
3550  * Reset the per-group state (in particular, mark transvalues null)
3551  */
3552  for (setno = 0; setno < numGroupingSets; setno++)
3553  {
3554  MemSet(node->pergroups[setno], 0,
3555  sizeof(AggStatePerGroupData) * node->numaggs);
3556  }
3557 
3558  /* reset to phase 1 */
3559  initialize_phase(node, 1);
3560 
3561  node->input_done = false;
3562  node->projected_set = -1;
3563  }
3564 
3565  if (outerPlan->chgParam == NULL)
3566  ExecReScan(outerPlan);
3567 }
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:305
Datum * ecxt_aggvalues
Definition: execnodes.h:243
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
int numaggs
Definition: execnodes.h:2045
bool agg_done
Definition: execnodes.h:2063
ScanState ss
Definition: execnodes.h:2043
ExprContext * ps_ExprContext
Definition: execnodes.h:982
void ExecReScan(PlanState *node)
Definition: execAmi.c:75
#define MemSet(start, val, len)
Definition: c.h:971
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1333
AggStatePerTrans pertrans
Definition: execnodes.h:2053
int projected_set
Definition: execnodes.h:2064
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
HeapTuple grp_firstTuple
Definition: execnodes.h:2078
int numtrans
Definition: execnodes.h:2046
PlanState ps
Definition: execnodes.h:1330
int maxsets
Definition: execnodes.h:2070
bool table_filled
Definition: execnodes.h:2080
AggStrategy aggstrategy
Definition: execnodes.h:2047
#define outerPlanState(node)
Definition: execnodes.h:1037
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
Bitmapset * aggParams
Definition: plannodes.h:816
AggStatePerHash perhash
Definition: execnodes.h:2082
Bitmapset * chgParam
Definition: execnodes.h:975
#define outerPlan(node)
Definition: plannodes.h:172
TupleHashIterator hashiter
Definition: nodeAgg.h:295
bool input_done
Definition: execnodes.h:2062
ExprContext * hashcontext
Definition: execnodes.h:2054
bool * ecxt_aggnulls
Definition: execnodes.h:245
uintptr_t Datum
Definition: postgres.h:367
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:324
Plan * plan
Definition: execnodes.h:943
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:725
#define Max(x, y)
Definition: c.h:914
ExprContext ** aggcontexts
Definition: execnodes.h:2055
AggStatePerGroup * pergroups
Definition: execnodes.h:2076
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:402
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
Definition: plannodes.h:806
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1236
TupleHashTable hashtable
Definition: nodeAgg.h:294
static void build_hash_tables(AggState *aggstate)
Definition: nodeAgg.c:1280

◆ hash_agg_entry_size()

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

Definition at line 1477 of file nodeAgg.c.

References MAXALIGN, and SizeofMinimalTupleHeader.

Referenced by create_distinct_paths(), and estimate_hashagg_tablesize().

1478 {
1479  return
1481  MAXALIGN(tupleWidth) +
1482  MAXALIGN(sizeof(TupleHashEntryData) +
1483  numAggs * sizeof(AggStatePerGroupData)) +
1484  transitionSpace;
1485 }
#define SizeofMinimalTupleHeader
Definition: htup_details.h:649
#define MAXALIGN(LEN)
Definition: c.h:691