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)
 

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

3388 {
3390  int transno;
3391  int numGroupingSets = Max(node->maxsets, 1);
3392  int setno;
3393 
3394  /* Make sure we have closed any open tuplesorts */
3395 
3396  if (node->sort_in)
3397  tuplesort_end(node->sort_in);
3398  if (node->sort_out)
3399  tuplesort_end(node->sort_out);
3400 
3401  for (transno = 0; transno < node->numtrans; transno++)
3402  {
3403  AggStatePerTrans pertrans = &node->pertrans[transno];
3404 
3405  for (setno = 0; setno < numGroupingSets; setno++)
3406  {
3407  if (pertrans->sortstates[setno])
3408  tuplesort_end(pertrans->sortstates[setno]);
3409  }
3410  }
3411 
3412  /* And ensure any agg shutdown callbacks have been called */
3413  for (setno = 0; setno < numGroupingSets; setno++)
3414  ReScanExprContext(node->aggcontexts[setno]);
3415  if (node->hashcontext)
3417 
3418  /*
3419  * We don't actually free any ExprContexts here (see comment in
3420  * ExecFreeExprContext), just unlinking the output one from the plan node
3421  * suffices.
3422  */
3423  ExecFreeExprContext(&node->ss.ps);
3424 
3425  /* clean up tuple table */
3427 
3428  outerPlan = outerPlanState(node);
3429  ExecEndNode(outerPlan);
3430 }
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:537
Tuplesortstate * sort_out
Definition: execnodes.h:2065
ScanState ss
Definition: execnodes.h:2035
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1333
AggStatePerTrans pertrans
Definition: execnodes.h:2045
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:614
int numtrans
Definition: execnodes.h:2038
PlanState ps
Definition: execnodes.h:1330
int maxsets
Definition: execnodes.h:2062
Tuplesortstate * sort_in
Definition: execnodes.h:2064
#define outerPlanState(node)
Definition: execnodes.h:1033
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
#define outerPlan(node)
Definition: plannodes.h:170
ExprContext * hashcontext
Definition: execnodes.h:2046
#define Max(x, y)
Definition: c.h:905
ExprContext ** aggcontexts
Definition: execnodes.h:2047
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 2096 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_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(), 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().

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

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

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

3434 {
3435  ExprContext *econtext = node->ss.ps.ps_ExprContext;
3437  Agg *aggnode = (Agg *) node->ss.ps.plan;
3438  int transno;
3439  int numGroupingSets = Max(node->maxsets, 1);
3440  int setno;
3441 
3442  node->agg_done = false;
3443 
3444  if (node->aggstrategy == AGG_HASHED)
3445  {
3446  /*
3447  * In the hashed case, if we haven't yet built the hash table then we
3448  * can just return; nothing done yet, so nothing to undo. If subnode's
3449  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
3450  * else no reason to re-scan it at all.
3451  */
3452  if (!node->table_filled)
3453  return;
3454 
3455  /*
3456  * If we do have the hash table, and the subplan does not have any
3457  * parameter changes, and none of our own parameter changes affect
3458  * input expressions of the aggregated functions, then we can just
3459  * rescan the existing hash table; no need to build it again.
3460  */
3461  if (outerPlan->chgParam == NULL &&
3462  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
3463  {
3465  &node->perhash[0].hashiter);
3466  select_current_set(node, 0, true);
3467  return;
3468  }
3469  }
3470 
3471  /* Make sure we have closed any open tuplesorts */
3472  for (transno = 0; transno < node->numtrans; transno++)
3473  {
3474  for (setno = 0; setno < numGroupingSets; setno++)
3475  {
3476  AggStatePerTrans pertrans = &node->pertrans[transno];
3477 
3478  if (pertrans->sortstates[setno])
3479  {
3480  tuplesort_end(pertrans->sortstates[setno]);
3481  pertrans->sortstates[setno] = NULL;
3482  }
3483  }
3484  }
3485 
3486  /*
3487  * We don't need to ReScanExprContext the output tuple context here;
3488  * ExecReScan already did it. But we do need to reset our per-grouping-set
3489  * contexts, which may have transvalues stored in them. (We use rescan
3490  * rather than just reset because transfns may have registered callbacks
3491  * that need to be run now.) For the AGG_HASHED case, see below.
3492  */
3493 
3494  for (setno = 0; setno < numGroupingSets; setno++)
3495  {
3496  ReScanExprContext(node->aggcontexts[setno]);
3497  }
3498 
3499  /* Release first tuple of group, if we have made a copy */
3500  if (node->grp_firstTuple != NULL)
3501  {
3503  node->grp_firstTuple = NULL;
3504  }
3506 
3507  /* Forget current agg values */
3508  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
3509  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
3510 
3511  /*
3512  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
3513  * the hashcontext. This used to be an issue, but now, resetting a context
3514  * automatically deletes sub-contexts too.
3515  */
3516  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
3517  {
3519  /* Rebuild an empty hash table */
3520  build_hash_table(node);
3521  node->table_filled = false;
3522  /* iterator will be reset when the table is filled */
3523  }
3524 
3525  if (node->aggstrategy != AGG_HASHED)
3526  {
3527  /*
3528  * Reset the per-group state (in particular, mark transvalues null)
3529  */
3530  for (setno = 0; setno < numGroupingSets; setno++)
3531  {
3532  MemSet(node->pergroups[setno], 0,
3533  sizeof(AggStatePerGroupData) * node->numaggs);
3534  }
3535 
3536  /* reset to phase 1 */
3537  initialize_phase(node, 1);
3538 
3539  node->input_done = false;
3540  node->projected_set = -1;
3541  }
3542 
3543  if (outerPlan->chgParam == NULL)
3544  ExecReScan(outerPlan);
3545 }
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:302
Datum * ecxt_aggvalues
Definition: execnodes.h:242
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
int numaggs
Definition: execnodes.h:2037
bool agg_done
Definition: execnodes.h:2055
ScanState ss
Definition: execnodes.h:2035
ExprContext * ps_ExprContext
Definition: execnodes.h:978
void ExecReScan(PlanState *node)
Definition: execAmi.c:75
#define MemSet(start, val, len)
Definition: c.h:962
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1333
AggStatePerTrans pertrans
Definition: execnodes.h:2045
int projected_set
Definition: execnodes.h:2056
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
HeapTuple grp_firstTuple
Definition: execnodes.h:2070
int numtrans
Definition: execnodes.h:2038
PlanState ps
Definition: execnodes.h:1330
int maxsets
Definition: execnodes.h:2062
bool table_filled
Definition: execnodes.h:2072
AggStrategy aggstrategy
Definition: execnodes.h:2039
#define outerPlanState(node)
Definition: execnodes.h:1033
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
Bitmapset * aggParams
Definition: plannodes.h:812
static void build_hash_table(AggState *aggstate)
Definition: nodeAgg.c:1264
AggStatePerHash perhash
Definition: execnodes.h:2074
Bitmapset * chgParam
Definition: execnodes.h:971
#define outerPlan(node)
Definition: plannodes.h:170
TupleHashIterator hashiter
Definition: nodeAgg.h:295
bool input_done
Definition: execnodes.h:2054
ExprContext * hashcontext
Definition: execnodes.h:2046
bool * ecxt_aggnulls
Definition: execnodes.h:244
uintptr_t Datum
Definition: postgres.h:367
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:321
Plan * plan
Definition: execnodes.h:939
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:721
#define Max(x, y)
Definition: c.h:905
ExprContext ** aggcontexts
Definition: execnodes.h:2047
AggStatePerGroup * pergroups
Definition: execnodes.h:2068
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:402
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
Definition: plannodes.h:802
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1236
TupleHashTable hashtable
Definition: nodeAgg.h:294

◆ hash_agg_entry_size()

Size hash_agg_entry_size ( int  numAggs)

Definition at line 1445 of file nodeAgg.c.

References MAXALIGN.

Referenced by create_distinct_paths(), and estimate_hashagg_tablesize().

1446 {
1447  Size entrysize;
1448 
1449  /* This must match build_hash_table */
1450  entrysize = sizeof(TupleHashEntryData) +
1451  numAggs * sizeof(AggStatePerGroupData);
1452  entrysize = MAXALIGN(entrysize);
1453 
1454  return entrysize;
1455 }
struct TupleHashEntryData TupleHashEntryData
size_t Size
Definition: c.h:467
#define MAXALIGN(LEN)
Definition: c.h:692