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

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

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

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

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

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

References MAXALIGN.

Referenced by create_distinct_paths(), and estimate_hashagg_tablesize().

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