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
 

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)
 
Datum aggregate_dummy (PG_FUNCTION_ARGS)
 

Typedef Documentation

◆ AggStatePerAggData

◆ AggStatePerGroupData

◆ AggStatePerHashData

◆ AggStatePerPhaseData

◆ AggStatePerTransData

Function Documentation

◆ aggregate_dummy()

Datum aggregate_dummy ( PG_FUNCTION_ARGS  )

Definition at line 3663 of file nodeAgg.c.

References elog, and ERROR.

3664 {
3665  elog(ERROR, "aggregate function %u called as normal function",
3666  fcinfo->flinfo->fn_oid);
3667  return (Datum) 0; /* keep compiler quiet */
3668 }
#define ERROR
Definition: elog.h:43
uintptr_t Datum
Definition: postgres.h:365
#define elog
Definition: elog.h:219

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

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

3309 {
3311  int transno;
3312  int numGroupingSets = Max(node->maxsets, 1);
3313  int setno;
3314 
3315  /* Make sure we have closed any open tuplesorts */
3316 
3317  if (node->sort_in)
3318  tuplesort_end(node->sort_in);
3319  if (node->sort_out)
3320  tuplesort_end(node->sort_out);
3321 
3322  for (transno = 0; transno < node->numtrans; transno++)
3323  {
3324  AggStatePerTrans pertrans = &node->pertrans[transno];
3325 
3326  for (setno = 0; setno < numGroupingSets; setno++)
3327  {
3328  if (pertrans->sortstates[setno])
3329  tuplesort_end(pertrans->sortstates[setno]);
3330  }
3331  }
3332 
3333  /* And ensure any agg shutdown callbacks have been called */
3334  for (setno = 0; setno < numGroupingSets; setno++)
3335  ReScanExprContext(node->aggcontexts[setno]);
3336  if (node->hashcontext)
3338 
3339  /*
3340  * We don't actually free any ExprContexts here (see comment in
3341  * ExecFreeExprContext), just unlinking the output one from the plan node
3342  * suffices.
3343  */
3344  ExecFreeExprContext(&node->ss.ps);
3345 
3346  /* clean up tuple table */
3348 
3349  outerPlan = outerPlanState(node);
3350  ExecEndNode(outerPlan);
3351 }
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:539
Tuplesortstate * sort_out
Definition: execnodes.h:1854
ScanState ss
Definition: execnodes.h:1827
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:475
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1127
AggStatePerTrans pertrans
Definition: execnodes.h:1837
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:561
int numtrans
Definition: execnodes.h:1830
PlanState ps
Definition: execnodes.h:1124
int maxsets
Definition: execnodes.h:1851
Tuplesortstate * sort_in
Definition: execnodes.h:1853
#define outerPlanState(node)
Definition: execnodes.h:914
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
#define outerPlan(node)
Definition: plannodes.h:174
ExprContext * hashcontext
Definition: execnodes.h:1838
#define Max(x, y)
Definition: c.h:840
ExprContext ** aggcontexts
Definition: execnodes.h:1839
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:383
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1236

◆ ExecInitAgg()

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

Definition at line 2077 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, AGGMODIFY_READ_WRITE, 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, Anum_pg_aggregate_agginitval, Assert, bms_add_member(), bms_add_members(), bms_next_member(), build_aggregate_finalfn_expr(), build_hash_table(), 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(), 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::grpOperators, AggStatePerPhaseData::gset_lengths, AggState::hashcontext, HeapTupleIsValid, i, initialize_phase(), initValue(), AggState::input_done, Aggref::inputcollid, INTERNALOID, InvalidOid, InvokeFunctionExecuteHook, lcons_int(), Plan::lefttree, length(), 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, 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::sharable, AggState::sort_in, AggState::sort_out, AggState::sort_slot, AggStatePerPhaseData::sortnode, AggState::ss, ScanState::ss_ScanTupleSlot, PlanState::state, SysCacheGetAttr(), AggState::tmpcontext, AggStatePerAggData::transno, and TupleTableSlot::tts_tupleDescriptor.

Referenced by ExecInitNode().

2078 {
2079  AggState *aggstate;
2080  AggStatePerAgg peraggs;
2081  AggStatePerTrans pertransstates;
2082  AggStatePerGroup *pergroups;
2083  Plan *outerPlan;
2084  ExprContext *econtext;
2085  TupleDesc scanDesc;
2086  int numaggs,
2087  transno,
2088  aggno;
2089  int phase;
2090  int phaseidx;
2091  ListCell *l;
2092  Bitmapset *all_grouped_cols = NULL;
2093  int numGroupingSets = 1;
2094  int numPhases;
2095  int numHashes;
2096  int i = 0;
2097  int j = 0;
2098  bool use_hashing = (node->aggstrategy == AGG_HASHED ||
2099  node->aggstrategy == AGG_MIXED);
2100 
2101  /* check for unsupported flags */
2102  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
2103 
2104  /*
2105  * create state structure
2106  */
2107  aggstate = makeNode(AggState);
2108  aggstate->ss.ps.plan = (Plan *) node;
2109  aggstate->ss.ps.state = estate;
2110  aggstate->ss.ps.ExecProcNode = ExecAgg;
2111 
2112  aggstate->aggs = NIL;
2113  aggstate->numaggs = 0;
2114  aggstate->numtrans = 0;
2115  aggstate->aggstrategy = node->aggstrategy;
2116  aggstate->aggsplit = node->aggsplit;
2117  aggstate->maxsets = 0;
2118  aggstate->projected_set = -1;
2119  aggstate->current_set = 0;
2120  aggstate->peragg = NULL;
2121  aggstate->pertrans = NULL;
2122  aggstate->curperagg = NULL;
2123  aggstate->curpertrans = NULL;
2124  aggstate->input_done = false;
2125  aggstate->agg_done = false;
2126  aggstate->pergroups = NULL;
2127  aggstate->grp_firstTuple = NULL;
2128  aggstate->sort_in = NULL;
2129  aggstate->sort_out = NULL;
2130 
2131  /*
2132  * phases[0] always exists, but is dummy in sorted/plain mode
2133  */
2134  numPhases = (use_hashing ? 1 : 2);
2135  numHashes = (use_hashing ? 1 : 0);
2136 
2137  /*
2138  * Calculate the maximum number of grouping sets in any phase; this
2139  * determines the size of some allocations. Also calculate the number of
2140  * phases, since all hashed/mixed nodes contribute to only a single phase.
2141  */
2142  if (node->groupingSets)
2143  {
2144  numGroupingSets = list_length(node->groupingSets);
2145 
2146  foreach(l, node->chain)
2147  {
2148  Agg *agg = lfirst(l);
2149 
2150  numGroupingSets = Max(numGroupingSets,
2151  list_length(agg->groupingSets));
2152 
2153  /*
2154  * additional AGG_HASHED aggs become part of phase 0, but all
2155  * others add an extra phase.
2156  */
2157  if (agg->aggstrategy != AGG_HASHED)
2158  ++numPhases;
2159  else
2160  ++numHashes;
2161  }
2162  }
2163 
2164  aggstate->maxsets = numGroupingSets;
2165  aggstate->numphases = numPhases;
2166 
2167  aggstate->aggcontexts = (ExprContext **)
2168  palloc0(sizeof(ExprContext *) * numGroupingSets);
2169 
2170  /*
2171  * Create expression contexts. We need three or more, one for
2172  * per-input-tuple processing, one for per-output-tuple processing, one
2173  * for all the hashtables, and one for each grouping set. The per-tuple
2174  * memory context of the per-grouping-set ExprContexts (aggcontexts)
2175  * replaces the standalone memory context formerly used to hold transition
2176  * values. We cheat a little by using ExecAssignExprContext() to build
2177  * all of them.
2178  *
2179  * NOTE: the details of what is stored in aggcontexts and what is stored
2180  * in the regular per-query memory context are driven by a simple
2181  * decision: we want to reset the aggcontext at group boundaries (if not
2182  * hashing) and in ExecReScanAgg to recover no-longer-wanted space.
2183  */
2184  ExecAssignExprContext(estate, &aggstate->ss.ps);
2185  aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
2186 
2187  for (i = 0; i < numGroupingSets; ++i)
2188  {
2189  ExecAssignExprContext(estate, &aggstate->ss.ps);
2190  aggstate->aggcontexts[i] = aggstate->ss.ps.ps_ExprContext;
2191  }
2192 
2193  if (use_hashing)
2194  {
2195  ExecAssignExprContext(estate, &aggstate->ss.ps);
2196  aggstate->hashcontext = aggstate->ss.ps.ps_ExprContext;
2197  }
2198 
2199  ExecAssignExprContext(estate, &aggstate->ss.ps);
2200 
2201  /*
2202  * Initialize child nodes.
2203  *
2204  * If we are doing a hashed aggregation then the child plan does not need
2205  * to handle REWIND efficiently; see ExecReScanAgg.
2206  */
2207  if (node->aggstrategy == AGG_HASHED)
2208  eflags &= ~EXEC_FLAG_REWIND;
2209  outerPlan = outerPlan(node);
2210  outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags);
2211 
2212  /*
2213  * initialize source tuple type.
2214  */
2215  ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss);
2216  scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
2217  if (node->chain)
2218  aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc);
2219 
2220  /*
2221  * Initialize result type, slot and projection.
2222  */
2223  ExecInitResultTupleSlotTL(estate, &aggstate->ss.ps);
2224  ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
2225 
2226  /*
2227  * initialize child expressions
2228  *
2229  * We expect the parser to have checked that no aggs contain other agg
2230  * calls in their arguments (and just to be sure, we verify it again while
2231  * initializing the plan node). This would make no sense under SQL
2232  * semantics, and it's forbidden by the spec. Because it is true, we
2233  * don't need to worry about evaluating the aggs in any particular order.
2234  *
2235  * Note: execExpr.c finds Aggrefs for us, and adds their AggrefExprState
2236  * nodes to aggstate->aggs. Aggrefs in the qual are found here; Aggrefs
2237  * in the targetlist are found during ExecAssignProjectionInfo, below.
2238  */
2239  aggstate->ss.ps.qual =
2240  ExecInitQual(node->plan.qual, (PlanState *) aggstate);
2241 
2242  /*
2243  * We should now have found all Aggrefs in the targetlist and quals.
2244  */
2245  numaggs = aggstate->numaggs;
2246  Assert(numaggs == list_length(aggstate->aggs));
2247 
2248  /*
2249  * For each phase, prepare grouping set data and fmgr lookup data for
2250  * compare functions. Accumulate all_grouped_cols in passing.
2251  */
2252  aggstate->phases = palloc0(numPhases * sizeof(AggStatePerPhaseData));
2253 
2254  aggstate->num_hashes = numHashes;
2255  if (numHashes)
2256  {
2257  aggstate->perhash = palloc0(sizeof(AggStatePerHashData) * numHashes);
2258  aggstate->phases[0].numsets = 0;
2259  aggstate->phases[0].gset_lengths = palloc(numHashes * sizeof(int));
2260  aggstate->phases[0].grouped_cols = palloc(numHashes * sizeof(Bitmapset *));
2261  }
2262 
2263  phase = 0;
2264  for (phaseidx = 0; phaseidx <= list_length(node->chain); ++phaseidx)
2265  {
2266  Agg *aggnode;
2267  Sort *sortnode;
2268 
2269  if (phaseidx > 0)
2270  {
2271  aggnode = list_nth_node(Agg, node->chain, phaseidx - 1);
2272  sortnode = castNode(Sort, aggnode->plan.lefttree);
2273  }
2274  else
2275  {
2276  aggnode = node;
2277  sortnode = NULL;
2278  }
2279 
2280  Assert(phase <= 1 || sortnode);
2281 
2282  if (aggnode->aggstrategy == AGG_HASHED
2283  || aggnode->aggstrategy == AGG_MIXED)
2284  {
2285  AggStatePerPhase phasedata = &aggstate->phases[0];
2286  AggStatePerHash perhash;
2287  Bitmapset *cols = NULL;
2288 
2289  Assert(phase == 0);
2290  i = phasedata->numsets++;
2291  perhash = &aggstate->perhash[i];
2292 
2293  /* phase 0 always points to the "real" Agg in the hash case */
2294  phasedata->aggnode = node;
2295  phasedata->aggstrategy = node->aggstrategy;
2296 
2297  /* but the actual Agg node representing this hash is saved here */
2298  perhash->aggnode = aggnode;
2299 
2300  phasedata->gset_lengths[i] = perhash->numCols = aggnode->numCols;
2301 
2302  for (j = 0; j < aggnode->numCols; ++j)
2303  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
2304 
2305  phasedata->grouped_cols[i] = cols;
2306 
2307  all_grouped_cols = bms_add_members(all_grouped_cols, cols);
2308  continue;
2309  }
2310  else
2311  {
2312  AggStatePerPhase phasedata = &aggstate->phases[++phase];
2313  int num_sets;
2314 
2315  phasedata->numsets = num_sets = list_length(aggnode->groupingSets);
2316 
2317  if (num_sets)
2318  {
2319  phasedata->gset_lengths = palloc(num_sets * sizeof(int));
2320  phasedata->grouped_cols = palloc(num_sets * sizeof(Bitmapset *));
2321 
2322  i = 0;
2323  foreach(l, aggnode->groupingSets)
2324  {
2325  int current_length = list_length(lfirst(l));
2326  Bitmapset *cols = NULL;
2327 
2328  /* planner forces this to be correct */
2329  for (j = 0; j < current_length; ++j)
2330  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
2331 
2332  phasedata->grouped_cols[i] = cols;
2333  phasedata->gset_lengths[i] = current_length;
2334 
2335  ++i;
2336  }
2337 
2338  all_grouped_cols = bms_add_members(all_grouped_cols,
2339  phasedata->grouped_cols[0]);
2340  }
2341  else
2342  {
2343  Assert(phaseidx == 0);
2344 
2345  phasedata->gset_lengths = NULL;
2346  phasedata->grouped_cols = NULL;
2347  }
2348 
2349  /*
2350  * If we are grouping, precompute fmgr lookup data for inner loop.
2351  */
2352  if (aggnode->aggstrategy == AGG_SORTED)
2353  {
2354  int i = 0;
2355 
2356  Assert(aggnode->numCols > 0);
2357 
2358  /*
2359  * Build a separate function for each subset of columns that
2360  * need to be compared.
2361  */
2362  phasedata->eqfunctions =
2363  (ExprState **) palloc0(aggnode->numCols * sizeof(ExprState *));
2364 
2365  /* for each grouping set */
2366  for (i = 0; i < phasedata->numsets; i++)
2367  {
2368  int length = phasedata->gset_lengths[i];
2369 
2370  if (phasedata->eqfunctions[length - 1] != NULL)
2371  continue;
2372 
2373  phasedata->eqfunctions[length - 1] =
2374  execTuplesMatchPrepare(scanDesc,
2375  length,
2376  aggnode->grpColIdx,
2377  aggnode->grpOperators,
2378  (PlanState *) aggstate);
2379  }
2380 
2381  /* and for all grouped columns, unless already computed */
2382  if (phasedata->eqfunctions[aggnode->numCols - 1] == NULL)
2383  {
2384  phasedata->eqfunctions[aggnode->numCols - 1] =
2385  execTuplesMatchPrepare(scanDesc,
2386  aggnode->numCols,
2387  aggnode->grpColIdx,
2388  aggnode->grpOperators,
2389  (PlanState *) aggstate);
2390  }
2391  }
2392 
2393  phasedata->aggnode = aggnode;
2394  phasedata->aggstrategy = aggnode->aggstrategy;
2395  phasedata->sortnode = sortnode;
2396  }
2397  }
2398 
2399  /*
2400  * Convert all_grouped_cols to a descending-order list.
2401  */
2402  i = -1;
2403  while ((i = bms_next_member(all_grouped_cols, i)) >= 0)
2404  aggstate->all_grouped_cols = lcons_int(i, aggstate->all_grouped_cols);
2405 
2406  /*
2407  * Set up aggregate-result storage in the output expr context, and also
2408  * allocate my private per-agg working storage
2409  */
2410  econtext = aggstate->ss.ps.ps_ExprContext;
2411  econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
2412  econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numaggs);
2413 
2414  peraggs = (AggStatePerAgg) palloc0(sizeof(AggStatePerAggData) * numaggs);
2415  pertransstates = (AggStatePerTrans) palloc0(sizeof(AggStatePerTransData) * numaggs);
2416 
2417  aggstate->peragg = peraggs;
2418  aggstate->pertrans = pertransstates;
2419 
2420 
2421  aggstate->all_pergroups =
2423  * (numGroupingSets + numHashes));
2424  pergroups = aggstate->all_pergroups;
2425 
2426  if (node->aggstrategy != AGG_HASHED)
2427  {
2428  for (i = 0; i < numGroupingSets; i++)
2429  {
2430  pergroups[i] = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData)
2431  * numaggs);
2432  }
2433 
2434  aggstate->pergroups = pergroups;
2435  pergroups += numGroupingSets;
2436  }
2437 
2438  /*
2439  * Hashing can only appear in the initial phase.
2440  */
2441  if (use_hashing)
2442  {
2443  /* this is an array of pointers, not structures */
2444  aggstate->hash_pergroup = pergroups;
2445 
2446  find_hash_columns(aggstate);
2447  build_hash_table(aggstate);
2448  aggstate->table_filled = false;
2449  }
2450 
2451  /*
2452  * Initialize current phase-dependent values to initial phase. The initial
2453  * phase is 1 (first sort pass) for all strategies that use sorting (if
2454  * hashing is being done too, then phase 0 is processed last); but if only
2455  * hashing is being done, then phase 0 is all there is.
2456  */
2457  if (node->aggstrategy == AGG_HASHED)
2458  {
2459  aggstate->current_phase = 0;
2460  initialize_phase(aggstate, 0);
2461  select_current_set(aggstate, 0, true);
2462  }
2463  else
2464  {
2465  aggstate->current_phase = 1;
2466  initialize_phase(aggstate, 1);
2467  select_current_set(aggstate, 0, false);
2468  }
2469 
2470  /* -----------------
2471  * Perform lookups of aggregate function info, and initialize the
2472  * unchanging fields of the per-agg and per-trans data.
2473  *
2474  * We try to optimize by detecting duplicate aggregate functions so that
2475  * their state and final values are re-used, rather than needlessly being
2476  * re-calculated independently. We also detect aggregates that are not
2477  * the same, but which can share the same transition state.
2478  *
2479  * Scenarios:
2480  *
2481  * 1. Identical aggregate function calls appear in the query:
2482  *
2483  * SELECT SUM(x) FROM ... HAVING SUM(x) > 0
2484  *
2485  * Since these aggregates are identical, we only need to calculate
2486  * the value once. Both aggregates will share the same 'aggno' value.
2487  *
2488  * 2. Two different aggregate functions appear in the query, but the
2489  * aggregates have the same arguments, transition functions and
2490  * initial values (and, presumably, different final functions):
2491  *
2492  * SELECT AVG(x), STDDEV(x) FROM ...
2493  *
2494  * In this case we must create a new peragg for the varying aggregate,
2495  * and we need to call the final functions separately, but we need
2496  * only run the transition function once. (This requires that the
2497  * final functions be nondestructive of the transition state, but
2498  * that's required anyway for other reasons.)
2499  *
2500  * For either of these optimizations to be valid, all aggregate properties
2501  * used in the transition phase must be the same, including any modifiers
2502  * such as ORDER BY, DISTINCT and FILTER, and the arguments mustn't
2503  * contain any volatile functions.
2504  * -----------------
2505  */
2506  aggno = -1;
2507  transno = -1;
2508  foreach(l, aggstate->aggs)
2509  {
2510  AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(l);
2511  Aggref *aggref = aggrefstate->aggref;
2512  AggStatePerAgg peragg;
2513  AggStatePerTrans pertrans;
2514  int existing_aggno;
2515  int existing_transno;
2516  List *same_input_transnos;
2517  Oid inputTypes[FUNC_MAX_ARGS];
2518  int numArguments;
2519  int numDirectArgs;
2520  HeapTuple aggTuple;
2521  Form_pg_aggregate aggform;
2522  AclResult aclresult;
2523  Oid transfn_oid,
2524  finalfn_oid;
2525  bool sharable;
2526  Oid serialfn_oid,
2527  deserialfn_oid;
2528  Expr *finalfnexpr;
2529  Oid aggtranstype;
2530  Datum textInitVal;
2531  Datum initValue;
2532  bool initValueIsNull;
2533 
2534  /* Planner should have assigned aggregate to correct level */
2535  Assert(aggref->agglevelsup == 0);
2536  /* ... and the split mode should match */
2537  Assert(aggref->aggsplit == aggstate->aggsplit);
2538 
2539  /* 1. Check for already processed aggs which can be re-used */
2540  existing_aggno = find_compatible_peragg(aggref, aggstate, aggno,
2541  &same_input_transnos);
2542  if (existing_aggno != -1)
2543  {
2544  /*
2545  * Existing compatible agg found. so just point the Aggref to the
2546  * same per-agg struct.
2547  */
2548  aggrefstate->aggno = existing_aggno;
2549  continue;
2550  }
2551 
2552  /* Mark Aggref state node with assigned index in the result array */
2553  peragg = &peraggs[++aggno];
2554  peragg->aggref = aggref;
2555  aggrefstate->aggno = aggno;
2556 
2557  /* Fetch the pg_aggregate row */
2558  aggTuple = SearchSysCache1(AGGFNOID,
2559  ObjectIdGetDatum(aggref->aggfnoid));
2560  if (!HeapTupleIsValid(aggTuple))
2561  elog(ERROR, "cache lookup failed for aggregate %u",
2562  aggref->aggfnoid);
2563  aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
2564 
2565  /* Check permission to call aggregate function */
2566  aclresult = pg_proc_aclcheck(aggref->aggfnoid, GetUserId(),
2567  ACL_EXECUTE);
2568  if (aclresult != ACLCHECK_OK)
2569  aclcheck_error(aclresult, OBJECT_AGGREGATE,
2570  get_func_name(aggref->aggfnoid));
2572 
2573  /* planner recorded transition state type in the Aggref itself */
2574  aggtranstype = aggref->aggtranstype;
2575  Assert(OidIsValid(aggtranstype));
2576 
2577  /*
2578  * If this aggregation is performing state combines, then instead of
2579  * using the transition function, we'll use the combine function
2580  */
2581  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
2582  {
2583  transfn_oid = aggform->aggcombinefn;
2584 
2585  /* If not set then the planner messed up */
2586  if (!OidIsValid(transfn_oid))
2587  elog(ERROR, "combinefn not set for aggregate function");
2588  }
2589  else
2590  transfn_oid = aggform->aggtransfn;
2591 
2592  /* Final function only required if we're finalizing the aggregates */
2593  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
2594  peragg->finalfn_oid = finalfn_oid = InvalidOid;
2595  else
2596  peragg->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
2597 
2598  /*
2599  * If finalfn is marked read-write, we can't share transition states;
2600  * but it is okay to share states for AGGMODIFY_SHARABLE aggs. Also,
2601  * if we're not executing the finalfn here, we can share regardless.
2602  */
2603  sharable = (aggform->aggfinalmodify != AGGMODIFY_READ_WRITE) ||
2604  (finalfn_oid == InvalidOid);
2605  peragg->sharable = sharable;
2606 
2607  serialfn_oid = InvalidOid;
2608  deserialfn_oid = InvalidOid;
2609 
2610  /*
2611  * Check if serialization/deserialization is required. We only do it
2612  * for aggregates that have transtype INTERNAL.
2613  */
2614  if (aggtranstype == INTERNALOID)
2615  {
2616  /*
2617  * The planner should only have generated a serialize agg node if
2618  * every aggregate with an INTERNAL state has a serialization
2619  * function. Verify that.
2620  */
2621  if (DO_AGGSPLIT_SERIALIZE(aggstate->aggsplit))
2622  {
2623  /* serialization only valid when not running finalfn */
2625 
2626  if (!OidIsValid(aggform->aggserialfn))
2627  elog(ERROR, "serialfunc not provided for serialization aggregation");
2628  serialfn_oid = aggform->aggserialfn;
2629  }
2630 
2631  /* Likewise for deserialization functions */
2632  if (DO_AGGSPLIT_DESERIALIZE(aggstate->aggsplit))
2633  {
2634  /* deserialization only valid when combining states */
2635  Assert(DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
2636 
2637  if (!OidIsValid(aggform->aggdeserialfn))
2638  elog(ERROR, "deserialfunc not provided for deserialization aggregation");
2639  deserialfn_oid = aggform->aggdeserialfn;
2640  }
2641  }
2642 
2643  /* Check that aggregate owner has permission to call component fns */
2644  {
2645  HeapTuple procTuple;
2646  Oid aggOwner;
2647 
2648  procTuple = SearchSysCache1(PROCOID,
2649  ObjectIdGetDatum(aggref->aggfnoid));
2650  if (!HeapTupleIsValid(procTuple))
2651  elog(ERROR, "cache lookup failed for function %u",
2652  aggref->aggfnoid);
2653  aggOwner = ((Form_pg_proc) GETSTRUCT(procTuple))->proowner;
2654  ReleaseSysCache(procTuple);
2655 
2656  aclresult = pg_proc_aclcheck(transfn_oid, aggOwner,
2657  ACL_EXECUTE);
2658  if (aclresult != ACLCHECK_OK)
2659  aclcheck_error(aclresult, OBJECT_FUNCTION,
2660  get_func_name(transfn_oid));
2661  InvokeFunctionExecuteHook(transfn_oid);
2662  if (OidIsValid(finalfn_oid))
2663  {
2664  aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
2665  ACL_EXECUTE);
2666  if (aclresult != ACLCHECK_OK)
2667  aclcheck_error(aclresult, OBJECT_FUNCTION,
2668  get_func_name(finalfn_oid));
2669  InvokeFunctionExecuteHook(finalfn_oid);
2670  }
2671  if (OidIsValid(serialfn_oid))
2672  {
2673  aclresult = pg_proc_aclcheck(serialfn_oid, aggOwner,
2674  ACL_EXECUTE);
2675  if (aclresult != ACLCHECK_OK)
2676  aclcheck_error(aclresult, OBJECT_FUNCTION,
2677  get_func_name(serialfn_oid));
2678  InvokeFunctionExecuteHook(serialfn_oid);
2679  }
2680  if (OidIsValid(deserialfn_oid))
2681  {
2682  aclresult = pg_proc_aclcheck(deserialfn_oid, aggOwner,
2683  ACL_EXECUTE);
2684  if (aclresult != ACLCHECK_OK)
2685  aclcheck_error(aclresult, OBJECT_FUNCTION,
2686  get_func_name(deserialfn_oid));
2687  InvokeFunctionExecuteHook(deserialfn_oid);
2688  }
2689  }
2690 
2691  /*
2692  * Get actual datatypes of the (nominal) aggregate inputs. These
2693  * could be different from the agg's declared input types, when the
2694  * agg accepts ANY or a polymorphic type.
2695  */
2696  numArguments = get_aggregate_argtypes(aggref, inputTypes);
2697 
2698  /* Count the "direct" arguments, if any */
2699  numDirectArgs = list_length(aggref->aggdirectargs);
2700 
2701  /* Detect how many arguments to pass to the finalfn */
2702  if (aggform->aggfinalextra)
2703  peragg->numFinalArgs = numArguments + 1;
2704  else
2705  peragg->numFinalArgs = numDirectArgs + 1;
2706 
2707  /* Initialize any direct-argument expressions */
2708  peragg->aggdirectargs = ExecInitExprList(aggref->aggdirectargs,
2709  (PlanState *) aggstate);
2710 
2711  /*
2712  * build expression trees using actual argument & result types for the
2713  * finalfn, if it exists and is required.
2714  */
2715  if (OidIsValid(finalfn_oid))
2716  {
2717  build_aggregate_finalfn_expr(inputTypes,
2718  peragg->numFinalArgs,
2719  aggtranstype,
2720  aggref->aggtype,
2721  aggref->inputcollid,
2722  finalfn_oid,
2723  &finalfnexpr);
2724  fmgr_info(finalfn_oid, &peragg->finalfn);
2725  fmgr_info_set_expr((Node *) finalfnexpr, &peragg->finalfn);
2726  }
2727 
2728  /* get info about the output value's datatype */
2729  get_typlenbyval(aggref->aggtype,
2730  &peragg->resulttypeLen,
2731  &peragg->resulttypeByVal);
2732 
2733  /*
2734  * initval is potentially null, so don't try to access it as a struct
2735  * field. Must do it the hard way with SysCacheGetAttr.
2736  */
2737  textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
2739  &initValueIsNull);
2740  if (initValueIsNull)
2741  initValue = (Datum) 0;
2742  else
2743  initValue = GetAggInitVal(textInitVal, aggtranstype);
2744 
2745  /*
2746  * 2. Build working state for invoking the transition function, or
2747  * look up previously initialized working state, if we can share it.
2748  *
2749  * find_compatible_peragg() already collected a list of sharable
2750  * per-Trans's with the same inputs. Check if any of them have the
2751  * same transition function and initial value.
2752  */
2753  existing_transno = find_compatible_pertrans(aggstate, aggref,
2754  sharable,
2755  transfn_oid, aggtranstype,
2756  serialfn_oid, deserialfn_oid,
2757  initValue, initValueIsNull,
2758  same_input_transnos);
2759  if (existing_transno != -1)
2760  {
2761  /*
2762  * Existing compatible trans found, so just point the 'peragg' to
2763  * the same per-trans struct, and mark the trans state as shared.
2764  */
2765  pertrans = &pertransstates[existing_transno];
2766  pertrans->aggshared = true;
2767  peragg->transno = existing_transno;
2768  }
2769  else
2770  {
2771  pertrans = &pertransstates[++transno];
2772  build_pertrans_for_aggref(pertrans, aggstate, estate,
2773  aggref, transfn_oid, aggtranstype,
2774  serialfn_oid, deserialfn_oid,
2775  initValue, initValueIsNull,
2776  inputTypes, numArguments);
2777  peragg->transno = transno;
2778  }
2779  ReleaseSysCache(aggTuple);
2780  }
2781 
2782  /*
2783  * Update aggstate->numaggs to be the number of unique aggregates found.
2784  * Also set numstates to the number of unique transition states found.
2785  */
2786  aggstate->numaggs = aggno + 1;
2787  aggstate->numtrans = transno + 1;
2788 
2789  /*
2790  * Last, check whether any more aggregates got added onto the node while
2791  * we processed the expressions for the aggregate arguments (including not
2792  * only the regular arguments and FILTER expressions handled immediately
2793  * above, but any direct arguments we might've handled earlier). If so,
2794  * we have nested aggregate functions, which is semantically nonsensical,
2795  * so complain. (This should have been caught by the parser, so we don't
2796  * need to work hard on a helpful error message; but we defend against it
2797  * here anyway, just to be sure.)
2798  */
2799  if (numaggs != list_length(aggstate->aggs))
2800  ereport(ERROR,
2801  (errcode(ERRCODE_GROUPING_ERROR),
2802  errmsg("aggregate function calls cannot be nested")));
2803 
2804  /*
2805  * Build expressions doing all the transition work at once. We build a
2806  * different one for each phase, as the number of transition function
2807  * invocation can differ between phases. Note this'll work both for
2808  * transition and combination functions (although there'll only be one
2809  * phase in the latter case).
2810  */
2811  for (phaseidx = 0; phaseidx < aggstate->numphases; phaseidx++)
2812  {
2813  AggStatePerPhase phase = &aggstate->phases[phaseidx];
2814  bool dohash = false;
2815  bool dosort = false;
2816 
2817  /* phase 0 doesn't necessarily exist */
2818  if (!phase->aggnode)
2819  continue;
2820 
2821  if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 1)
2822  {
2823  /*
2824  * Phase one, and only phase one, in a mixed agg performs both
2825  * sorting and aggregation.
2826  */
2827  dohash = true;
2828  dosort = true;
2829  }
2830  else if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 0)
2831  {
2832  /*
2833  * No need to compute a transition function for an AGG_MIXED phase
2834  * 0 - the contents of the hashtables will have been computed
2835  * during phase 1.
2836  */
2837  continue;
2838  }
2839  else if (phase->aggstrategy == AGG_PLAIN ||
2840  phase->aggstrategy == AGG_SORTED)
2841  {
2842  dohash = false;
2843  dosort = true;
2844  }
2845  else if (phase->aggstrategy == AGG_HASHED)
2846  {
2847  dohash = true;
2848  dosort = false;
2849  }
2850  else
2851  Assert(false);
2852 
2853  phase->evaltrans = ExecBuildAggTrans(aggstate, phase, dosort, dohash);
2854 
2855  }
2856 
2857  return aggstate;
2858 }
struct AggStatePerTransData * AggStatePerTrans
Definition: execnodes.h:1820
ExprState ** eqfunctions
Definition: nodeAgg.h:274
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:1864
#define NIL
Definition: pg_list.h:69
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:1821
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:303
int length(const List *list)
Definition: list.c:1333
int numCols
Definition: plannodes.h:787
List * qual
Definition: plannodes.h:145
AggStatePerPhase phases
Definition: execnodes.h:1852
Datum * ecxt_aggvalues
Definition: execnodes.h:227
#define AGGMODIFY_READ_WRITE
Definition: pg_aggregate.h:145
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
AttrNumber * grpColIdx
Definition: plannodes.h:788
#define Anum_pg_aggregate_agginitval
Definition: pg_aggregate.h:117
List * lcons_int(int datum, List *list)
Definition: list.c:277
int numaggs
Definition: execnodes.h:1829
Oid GetUserId(void)
Definition: miscinit.c:284
bool agg_done
Definition: execnodes.h:1845
#define castNode(_type_, nodeptr)
Definition: nodes.h:582
ExprState * ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, bool doSort, bool doHash)
Definition: execExpr.c:2812
TupleTableSlot * sort_slot
Definition: execnodes.h:1855
List * all_grouped_cols
Definition: execnodes.h:1849
Tuplesortstate * sort_out
Definition: execnodes.h:1854
ScanState ss
Definition: execnodes.h:1827
ExprContext * ps_ExprContext
Definition: execnodes.h:902
ExprState * evaltrans
Definition: nodeAgg.h:279
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1053
Oid inputcollid
Definition: primnodes.h:297
int current_phase
Definition: execnodes.h:1835
Definition: nodes.h:513
AggSplit aggsplit
Definition: execnodes.h:1832
static TupleTableSlot * ExecAgg(PlanState *pstate)
Definition: nodeAgg.c:1530
int errcode(int sqlerrcode)
Definition: elog.c:575
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1127
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:2038
AggStatePerTrans pertrans
Definition: execnodes.h:1837
EState * state
Definition: execnodes.h:870
int projected_set
Definition: execnodes.h:1846
unsigned int Oid
Definition: postgres_ext.h:31
HeapTuple grp_firstTuple
Definition: execnodes.h:1859
Aggref * aggref
Definition: nodeAgg.h:186
int current_set
Definition: execnodes.h:1847
#define OidIsValid(objectId)
Definition: c.h:594
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:772
int numtrans
Definition: execnodes.h:1830
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc)
Definition: execTuples.c:910
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:204
ExprContext * tmpcontext
Definition: execnodes.h:1840
#define FUNC_MAX_ARGS
Bitmapset ** grouped_cols
Definition: nodeAgg.h:273
PlanState ps
Definition: execnodes.h:1124
int maxsets
Definition: execnodes.h:1851
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:774
AggStrategy aggstrategy
Definition: plannodes.h:785
bool table_filled
Definition: execnodes.h:1861
AggStrategy aggstrategy
Definition: execnodes.h:1831
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1397
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate)
Definition: execUtils.c:593
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:122
static void find_hash_columns(AggState *aggstate)
Definition: nodeAgg.c:1315
Tuplesortstate * sort_in
Definition: execnodes.h:1853
#define EXEC_FLAG_BACKWARD
Definition: executor.h:61
#define outerPlanState(node)
Definition: execnodes.h:914
Aggref * aggref
Definition: execnodes.h:677
#define list_nth_node(type, list, n)
Definition: pg_list.h:227
static int initValue(long lng_val)
Definition: informix.c:702
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:453
static void build_hash_table(AggState *aggstate)
Definition: nodeAgg.c:1264
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:104
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:313
Index agglevelsup
Definition: primnodes.h:309
List * aggdirectargs
Definition: primnodes.h:300
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition: nodeAgg.c:3151
AggStatePerAgg curperagg
Definition: execnodes.h:1842
AggStatePerHash perhash
Definition: execnodes.h:1863
AggStrategy aggstrategy
Definition: nodeAgg.h:270
#define EXEC_FLAG_REWIND
Definition: executor.h:60
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:179
#define outerPlan(node)
Definition: plannodes.h:174
int num_hashes
Definition: execnodes.h:1862
Plan plan
Definition: plannodes.h:784
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
bool input_done
Definition: execnodes.h:1844
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
ExprContext * hashcontext
Definition: execnodes.h:1838
bool * ecxt_aggnulls
Definition: execnodes.h:228
static int find_compatible_peragg(Aggref *newagg, AggState *aggstate, int lastaggno, List **same_input_transnos)
Definition: nodeAgg.c:3179
void * palloc0(Size size)
Definition: mcxt.c:864
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:874
AclResult
Definition: acl.h:178
uintptr_t Datum
Definition: postgres.h:365
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
List * groupingSets
Definition: plannodes.h:793
int16 resulttypeLen
Definition: nodeAgg.h:215
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:322
void ExecInitResultTupleSlotTL(EState *estate, PlanState *planstate)
Definition: execTuples.c:870
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:83
Plan * plan
Definition: execnodes.h:868
#define InvalidOid
Definition: postgres_ext.h:36
Oid aggfnoid
Definition: primnodes.h:294
#define INTERNALOID
Definition: pg_type.h:698
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, AttrNumber *keyColIdx, Oid *eqOperators, PlanState *parent)
Definition: execGrouping.c:60
#define Max(x, y)
Definition: c.h:840
ExprContext ** aggcontexts
Definition: execnodes.h:1839
#define makeNode(_type_)
Definition: nodes.h:561
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:688
#define lfirst(lc)
Definition: pg_list.h:106
#define EXEC_FLAG_MARK
Definition: executor.h:62
AggSplit aggsplit
Definition: plannodes.h:786
struct AggStatePerAggData * AggStatePerAgg
Definition: execnodes.h:1819
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:89
AggSplit aggsplit
Definition: primnodes.h:310
AggStatePerGroup * pergroups
Definition: execnodes.h:1857
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:425
static int list_length(const List *l)
Definition: pg_list.h:89
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:773
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2005
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:742
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:775
struct Plan * lefttree
Definition: plannodes.h:146
int numphases
Definition: execnodes.h:1834
ExprState * qual
Definition: execnodes.h:886
Oid * grpOperators
Definition: plannodes.h:789
void * palloc(Size size)
Definition: mcxt.c:835
int errmsg(const char *fmt,...)
Definition: elog.c:797
List * chain
Definition: plannodes.h:794
AggStatePerAgg peragg
Definition: execnodes.h:1836
#define ACL_EXECUTE
Definition: parsenodes.h:79
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4652
int i
List * aggdirectargs
Definition: nodeAgg.h:209
Oid aggtranstype
Definition: primnodes.h:298
static int find_compatible_pertrans(AggState *aggstate, Aggref *newagg, bool sharable, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, List *transnos)
Definition: nodeAgg.c:3257
AggStatePerTrans curpertrans
Definition: execnodes.h:1843
Oid aggtype
Definition: primnodes.h:295
bool resulttypeByVal
Definition: nodeAgg.h:216
Definition: plannodes.h:782
#define elog
Definition: elog.h:219
List * aggs
Definition: execnodes.h:1828
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1820
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:2869
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
Definition: pg_list.h:45
FmgrInfo finalfn
Definition: nodeAgg.h:198
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:799
AggStatePerGroup * all_pergroups
Definition: execnodes.h:1868

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

Definition at line 3354 of file nodeAgg.c.

References AggState::agg_done, AGG_HASHED, AGG_MIXED, AggState::aggcontexts, Agg::aggParams, AggState::aggstrategy, bms_overlap(), build_hash_table(), 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().

3355 {
3356  ExprContext *econtext = node->ss.ps.ps_ExprContext;
3358  Agg *aggnode = (Agg *) node->ss.ps.plan;
3359  int transno;
3360  int numGroupingSets = Max(node->maxsets, 1);
3361  int setno;
3362 
3363  node->agg_done = false;
3364 
3365  if (node->aggstrategy == AGG_HASHED)
3366  {
3367  /*
3368  * In the hashed case, if we haven't yet built the hash table then we
3369  * can just return; nothing done yet, so nothing to undo. If subnode's
3370  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
3371  * else no reason to re-scan it at all.
3372  */
3373  if (!node->table_filled)
3374  return;
3375 
3376  /*
3377  * If we do have the hash table, and the subplan does not have any
3378  * parameter changes, and none of our own parameter changes affect
3379  * input expressions of the aggregated functions, then we can just
3380  * rescan the existing hash table; no need to build it again.
3381  */
3382  if (outerPlan->chgParam == NULL &&
3383  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
3384  {
3386  &node->perhash[0].hashiter);
3387  select_current_set(node, 0, true);
3388  return;
3389  }
3390  }
3391 
3392  /* Make sure we have closed any open tuplesorts */
3393  for (transno = 0; transno < node->numtrans; transno++)
3394  {
3395  for (setno = 0; setno < numGroupingSets; setno++)
3396  {
3397  AggStatePerTrans pertrans = &node->pertrans[transno];
3398 
3399  if (pertrans->sortstates[setno])
3400  {
3401  tuplesort_end(pertrans->sortstates[setno]);
3402  pertrans->sortstates[setno] = NULL;
3403  }
3404  }
3405  }
3406 
3407  /*
3408  * We don't need to ReScanExprContext the output tuple context here;
3409  * ExecReScan already did it. But we do need to reset our per-grouping-set
3410  * contexts, which may have transvalues stored in them. (We use rescan
3411  * rather than just reset because transfns may have registered callbacks
3412  * that need to be run now.) For the AGG_HASHED case, see below.
3413  */
3414 
3415  for (setno = 0; setno < numGroupingSets; setno++)
3416  {
3417  ReScanExprContext(node->aggcontexts[setno]);
3418  }
3419 
3420  /* Release first tuple of group, if we have made a copy */
3421  if (node->grp_firstTuple != NULL)
3422  {
3424  node->grp_firstTuple = NULL;
3425  }
3427 
3428  /* Forget current agg values */
3429  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
3430  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
3431 
3432  /*
3433  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
3434  * the hashcontext. This used to be an issue, but now, resetting a context
3435  * automatically deletes sub-contexts too.
3436  */
3437  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
3438  {
3440  /* Rebuild an empty hash table */
3441  build_hash_table(node);
3442  node->table_filled = false;
3443  /* iterator will be reset when the table is filled */
3444  }
3445 
3446  if (node->aggstrategy != AGG_HASHED)
3447  {
3448  /*
3449  * Reset the per-group state (in particular, mark transvalues null)
3450  */
3451  for (setno = 0; setno < numGroupingSets; setno++)
3452  {
3453  MemSet(node->pergroups[setno], 0,
3454  sizeof(AggStatePerGroupData) * node->numaggs);
3455  }
3456 
3457  /* reset to phase 1 */
3458  initialize_phase(node, 1);
3459 
3460  node->input_done = false;
3461  node->projected_set = -1;
3462  }
3463 
3464  if (outerPlan->chgParam == NULL)
3465  ExecReScan(outerPlan);
3466 }
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:303
Datum * ecxt_aggvalues
Definition: execnodes.h:227
int numaggs
Definition: execnodes.h:1829
bool agg_done
Definition: execnodes.h:1845
ScanState ss
Definition: execnodes.h:1827
ExprContext * ps_ExprContext
Definition: execnodes.h:902
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:475
#define MemSet(start, val, len)
Definition: c.h:897
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1127
AggStatePerTrans pertrans
Definition: execnodes.h:1837
int projected_set
Definition: execnodes.h:1846
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
HeapTuple grp_firstTuple
Definition: execnodes.h:1859
int numtrans
Definition: execnodes.h:1830
PlanState ps
Definition: execnodes.h:1124
int maxsets
Definition: execnodes.h:1851
bool table_filled
Definition: execnodes.h:1861
AggStrategy aggstrategy
Definition: execnodes.h:1831
#define outerPlanState(node)
Definition: execnodes.h:914
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
Bitmapset * aggParams
Definition: plannodes.h:791
static void build_hash_table(AggState *aggstate)
Definition: nodeAgg.c:1264
AggStatePerHash perhash
Definition: execnodes.h:1863
Bitmapset * chgParam
Definition: execnodes.h:896
#define outerPlan(node)
Definition: plannodes.h:174
TupleHashIterator hashiter
Definition: nodeAgg.h:292
bool input_done
Definition: execnodes.h:1844
ExprContext * hashcontext
Definition: execnodes.h:1838
bool * ecxt_aggnulls
Definition: execnodes.h:228
uintptr_t Datum
Definition: postgres.h:365
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:322
Plan * plan
Definition: execnodes.h:868
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:652
#define Max(x, y)
Definition: c.h:840
ExprContext ** aggcontexts
Definition: execnodes.h:1839
AggStatePerGroup * pergroups
Definition: execnodes.h:1857
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:383
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:487
Definition: plannodes.h:782
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1236
TupleHashTable hashtable
Definition: nodeAgg.h:291

◆ hash_agg_entry_size()

Size hash_agg_entry_size ( int  numAggs)

Definition at line 1424 of file nodeAgg.c.

References MAXALIGN.

Referenced by create_distinct_paths(), and estimate_hashagg_tablesize().

1425 {
1426  Size entrysize;
1427 
1428  /* This must match build_hash_table */
1429  entrysize = sizeof(TupleHashEntryData) +
1430  numAggs * sizeof(AggStatePerGroupData);
1431  entrysize = MAXALIGN(entrysize);
1432 
1433  return entrysize;
1434 }
struct TupleHashEntryData TupleHashEntryData
size_t Size
Definition: c.h:422
#define MAXALIGN(LEN)
Definition: c.h:641