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

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

◆ aggregate_dummy()

Datum aggregate_dummy ( PG_FUNCTION_ARGS  )

Definition at line 3663 of file nodeAgg.c.

References elog, and ERROR.

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

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

Definition at line 3308 of file nodeAgg.c.

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

Referenced by ExecEndNode().

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

◆ ExecInitAgg()

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

Definition at line 2077 of file nodeAgg.c.

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, AggState::agg_done, AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, AggState::aggcontexts, AggStatePerAggData::aggdirectargs, Aggref::aggdirectargs, AGGFNOID, Aggref::aggfnoid, Aggref::agglevelsup, 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(), ExecInitExprList(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlotTL(), PlanState::ExecProcNode, execTuplesMatchPrepare(), AggStatePerAggData::finalfn, AggStatePerAggData::finalfn_oid, find_compatible_peragg(), find_compatible_pertrans(), find_hash_columns(), fmgr_info(), fmgr_info_set_expr, FUNC_MAX_ARGS, get_aggregate_argtypes(), get_func_name(), get_typlenbyval(), GetAggInitVal(), GETSTRUCT, GetUserId(), AggStatePerPhaseData::grouped_cols, Agg::groupingSets, AggState::grp_firstTuple, Agg::grpColIdx, Agg::grpOperators, AggStatePerPhaseData::gset_lengths, AggState::hashcontext, HeapTupleIsValid, i, initialize_phase(), initValue(), AggState::input_done, Aggref::inputcollid, InvalidOid, InvokeFunctionExecuteHook, lcons_int(), Plan::lefttree, length(), lfirst, list_length(), list_nth_node, makeNode, Max, AggState::maxsets, NIL, AggState::numaggs, AggStatePerHashData::numCols, Agg::numCols, AggStatePerAggData::numFinalArgs, AggState::numphases, AggStatePerPhaseData::numsets, AggState::numtrans, OBJECT_AGGREGATE, OBJECT_FUNCTION, ObjectIdGetDatum, OidIsValid, outerPlan, outerPlanState, palloc(), palloc0(), AggState::peragg, AggState::pergroups, AggState::pertrans, pg_proc_aclcheck(), Agg::plan, PlanState::plan, PROCOID, AggState::projected_set, ScanState::ps, PlanState::ps_ExprContext, Plan::qual, PlanState::qual, ReleaseSysCache(), AggStatePerAggData::resulttypeByVal, AggStatePerAggData::resulttypeLen, SearchSysCache1(), select_current_set(), AggStatePerAggData::sharable, AggState::sort_in, AggState::sort_out, AggState::sort_slot, AggStatePerPhaseData::sortnode, AggState::ss, ScanState::ss_ScanTupleSlot, PlanState::state, SysCacheGetAttr(), AggState::tmpcontext, AggStatePerAggData::transno, and TupleTableSlot::tts_tupleDescriptor.

Referenced by ExecInitNode().

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

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

Definition at line 3354 of file nodeAgg.c.

References AggState::agg_done, AGG_HASHED, AGG_MIXED, AggState::aggcontexts, Agg::aggParams, AggState::aggstrategy, bms_overlap(), build_hash_table(), PlanState::chgParam, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExecClearTuple(), ExecReScan(), AggState::grp_firstTuple, AggState::hashcontext, AggStatePerHashData::hashiter, AggStatePerHashData::hashtable, heap_freetuple(), initialize_phase(), AggState::input_done, Max, AggState::maxsets, MemSet, AggState::numaggs, AggState::numtrans, outerPlan, outerPlanState, AggState::pergroups, AggState::perhash, AggState::pertrans, PlanState::plan, AggState::projected_set, ScanState::ps, PlanState::ps_ExprContext, ReScanExprContext(), ResetTupleHashIterator, select_current_set(), AggStatePerTransData::sortstates, AggState::ss, ScanState::ss_ScanTupleSlot, AggState::table_filled, and tuplesort_end().

Referenced by ExecReScan().

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

◆ hash_agg_entry_size()

Size hash_agg_entry_size ( int  numAggs)

Definition at line 1424 of file nodeAgg.c.

References MAXALIGN.

Referenced by create_distinct_paths(), and estimate_hashagg_tablesize().

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