PostgreSQL Source Code  git master
prepagg.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_type.h"
#include "nodes/nodeFuncs.h"
#include "nodes/pathnodes.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/optimizer.h"
#include "optimizer/plancat.h"
#include "optimizer/prep.h"
#include "parser/parse_agg.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
Include dependency graph for prepagg.c:

Go to the source code of this file.

Functions

static bool preprocess_aggrefs_walker (Node *node, PlannerInfo *root)
 
static int find_compatible_agg (PlannerInfo *root, Aggref *newagg, List **same_input_transnos)
 
static int find_compatible_trans (PlannerInfo *root, Aggref *newagg, bool shareable, Oid aggtransfn, Oid aggtranstype, int transtypeLen, bool transtypeByVal, Oid aggcombinefn, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, List *transnos)
 
static Datum GetAggInitVal (Datum textInitVal, Oid transtype)
 
void preprocess_aggrefs (PlannerInfo *root, Node *clause)
 
static void preprocess_aggref (Aggref *aggref, PlannerInfo *root)
 
void get_agg_clause_costs (PlannerInfo *root, AggSplit aggsplit, AggClauseCosts *costs)
 

Function Documentation

◆ find_compatible_agg()

static int find_compatible_agg ( PlannerInfo root,
Aggref newagg,
List **  same_input_transnos 
)
static

Definition at line 360 of file prepagg.c.

References Aggref::aggcollid, Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggfnoid, PlannerInfo::agginfos, Aggref::aggkind, Aggref::aggorder, Aggref::aggstar, Aggref::aggtranstype, Aggref::aggtype, Aggref::aggvariadic, Aggref::args, contain_volatile_functions(), equal(), Aggref::inputcollid, lappend_int(), lfirst, list_free(), NIL, AggInfo::representative_aggref, AggInfo::shareable, and AggInfo::transno.

Referenced by preprocess_aggref().

362 {
363  ListCell *lc;
364  int aggno;
365 
366  *same_input_transnos = NIL;
367 
368  /* we mustn't reuse the aggref if it contains volatile function calls */
369  if (contain_volatile_functions((Node *) newagg))
370  return -1;
371 
372  /*
373  * Search through the list of already seen aggregates. If we find an
374  * existing identical aggregate call, then we can re-use that one. While
375  * searching, we'll also collect a list of Aggrefs with the same input
376  * parameters. If no matching Aggref is found, the caller can potentially
377  * still re-use the transition state of one of them. (At this stage we
378  * just compare the parsetrees; whether different aggregates share the
379  * same transition function will be checked later.)
380  */
381  aggno = -1;
382  foreach(lc, root->agginfos)
383  {
384  AggInfo *agginfo = (AggInfo *) lfirst(lc);
385  Aggref *existingRef;
386 
387  aggno++;
388 
389  existingRef = agginfo->representative_aggref;
390 
391  /* all of the following must be the same or it's no match */
392  if (newagg->inputcollid != existingRef->inputcollid ||
393  newagg->aggtranstype != existingRef->aggtranstype ||
394  newagg->aggstar != existingRef->aggstar ||
395  newagg->aggvariadic != existingRef->aggvariadic ||
396  newagg->aggkind != existingRef->aggkind ||
397  !equal(newagg->args, existingRef->args) ||
398  !equal(newagg->aggorder, existingRef->aggorder) ||
399  !equal(newagg->aggdistinct, existingRef->aggdistinct) ||
400  !equal(newagg->aggfilter, existingRef->aggfilter))
401  continue;
402 
403  /* if it's the same aggregate function then report exact match */
404  if (newagg->aggfnoid == existingRef->aggfnoid &&
405  newagg->aggtype == existingRef->aggtype &&
406  newagg->aggcollid == existingRef->aggcollid &&
407  equal(newagg->aggdirectargs, existingRef->aggdirectargs))
408  {
409  list_free(*same_input_transnos);
410  *same_input_transnos = NIL;
411  return aggno;
412  }
413 
414  /*
415  * Not identical, but it had the same inputs. If the final function
416  * permits sharing, return its transno to the caller, in case we can
417  * re-use its per-trans state. (If there's already sharing going on,
418  * we might report a transno more than once. find_compatible_trans is
419  * cheap enough that it's not worth spending cycles to avoid that.)
420  */
421  if (agginfo->shareable)
422  *same_input_transnos = lappend_int(*same_input_transnos,
423  agginfo->transno);
424  }
425 
426  return -1;
427 }
List * aggdistinct
Definition: primnodes.h:332
#define NIL
Definition: pg_list.h:65
bool aggvariadic
Definition: primnodes.h:335
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3149
Oid inputcollid
Definition: primnodes.h:326
Definition: nodes.h:536
List * args
Definition: primnodes.h:330
List * agginfos
Definition: pathnodes.h:357
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:452
bool aggstar
Definition: primnodes.h:334
List * aggorder
Definition: primnodes.h:331
List * aggdirectargs
Definition: primnodes.h:329
bool shareable
Definition: pathnodes.h:2678
List * lappend_int(List *list, int datum)
Definition: list.c:354
int transno
Definition: pathnodes.h:2672
Oid aggfnoid
Definition: primnodes.h:323
#define lfirst(lc)
Definition: pg_list.h:169
Expr * aggfilter
Definition: primnodes.h:333
Oid aggcollid
Definition: primnodes.h:325
void list_free(List *list)
Definition: list.c:1391
Oid aggtranstype
Definition: primnodes.h:327
Oid aggtype
Definition: primnodes.h:324
char aggkind
Definition: primnodes.h:337
Aggref * representative_aggref
Definition: pathnodes.h:2670

◆ find_compatible_trans()

static int find_compatible_trans ( PlannerInfo root,
Aggref newagg,
bool  shareable,
Oid  aggtransfn,
Oid  aggtranstype,
int  transtypeLen,
bool  transtypeByVal,
Oid  aggcombinefn,
Oid  aggserialfn,
Oid  aggdeserialfn,
Datum  initValue,
bool  initValueIsNull,
List transnos 
)
static

Definition at line 438 of file prepagg.c.

References PlannerInfo::aggtransinfos, AggTransInfo::aggtranstype, AggTransInfo::combinefn_oid, datumIsEqual(), AggTransInfo::deserialfn_oid, AggTransInfo::initValue, AggTransInfo::initValueIsNull, lfirst_int, list_nth(), AggTransInfo::serialfn_oid, and AggTransInfo::transfn_oid.

Referenced by preprocess_aggref().

445 {
446  ListCell *lc;
447 
448  /* If this aggregate can't share transition states, give up */
449  if (!shareable)
450  return -1;
451 
452  foreach(lc, transnos)
453  {
454  int transno = lfirst_int(lc);
455  AggTransInfo *pertrans = (AggTransInfo *) list_nth(root->aggtransinfos, transno);
456 
457  /*
458  * if the transfns or transition state types are not the same then the
459  * state can't be shared.
460  */
461  if (aggtransfn != pertrans->transfn_oid ||
462  aggtranstype != pertrans->aggtranstype)
463  continue;
464 
465  /*
466  * The serialization and deserialization functions must match, if
467  * present, as we're unable to share the trans state for aggregates
468  * which will serialize or deserialize into different formats.
469  * Remember that these will be InvalidOid if they're not required for
470  * this agg node.
471  */
472  if (aggserialfn != pertrans->serialfn_oid ||
473  aggdeserialfn != pertrans->deserialfn_oid)
474  continue;
475 
476  /*
477  * Combine function must also match. We only care about the combine
478  * function with partial aggregates, but it's too early in the
479  * planning to know if we will do partial aggregation, so be
480  * conservative.
481  */
482  if (aggcombinefn != pertrans->combinefn_oid)
483  continue;
484 
485  /*
486  * Check that the initial condition matches, too.
487  */
488  if (initValueIsNull && pertrans->initValueIsNull)
489  return transno;
490 
491  if (!initValueIsNull && !pertrans->initValueIsNull &&
492  datumIsEqual(initValue, pertrans->initValue,
493  transtypeByVal, transtypeLen))
494  return transno;
495  }
496  return -1;
497 }
Oid serialfn_oid
Definition: pathnodes.h:2701
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:222
Oid combinefn_oid
Definition: pathnodes.h:2707
#define lfirst_int(lc)
Definition: pg_list.h:170
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
List * aggtransinfos
Definition: pathnodes.h:358
bool initValueIsNull
Definition: pathnodes.h:2720
static int initValue(long lng_val)
Definition: informix.c:677
Oid aggtranstype
Definition: pathnodes.h:2710
Datum initValue
Definition: pathnodes.h:2719
Oid deserialfn_oid
Definition: pathnodes.h:2704

◆ get_agg_clause_costs()

void get_agg_clause_costs ( PlannerInfo root,
AggSplit  aggsplit,
AggClauseCosts costs 
)

Definition at line 538 of file prepagg.c.

References add_function_cost(), Aggref::aggdirectargs, AggTransInfo::aggfilter, PlannerInfo::agginfos, PlannerInfo::aggtransinfos, AggTransInfo::aggtransspace, AggTransInfo::aggtranstype, AggTransInfo::aggtranstypmod, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_SMALL_INITSIZE, AggTransInfo::args, AggTransInfo::combinefn_oid, cost_qual_eval_node(), AggTransInfo::deserialfn_oid, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_DESERIALIZE, DO_AGGSPLIT_SERIALIZE, DO_AGGSPLIT_SKIPFINAL, AggClauseCosts::finalCost, AggInfo::finalfn_oid, get_typavgwidth(), lfirst, MAXALIGN, OidIsValid, QualCost::per_tuple, AggInfo::representative_aggref, AggTransInfo::serialfn_oid, QualCost::startup, AggClauseCosts::transCost, AggTransInfo::transfn_oid, AggClauseCosts::transitionSpace, and AggTransInfo::transtypeByVal.

Referenced by create_grouping_paths(), create_partial_grouping_paths(), and estimate_path_cost_size().

539 {
540  ListCell *lc;
541 
542  foreach(lc, root->aggtransinfos)
543  {
544  AggTransInfo *transinfo = (AggTransInfo *) lfirst(lc);
545 
546  /*
547  * Add the appropriate component function execution costs to
548  * appropriate totals.
549  */
550  if (DO_AGGSPLIT_COMBINE(aggsplit))
551  {
552  /* charge for combining previously aggregated states */
553  add_function_cost(root, transinfo->combinefn_oid, NULL,
554  &costs->transCost);
555  }
556  else
557  add_function_cost(root, transinfo->transfn_oid, NULL,
558  &costs->transCost);
559  if (DO_AGGSPLIT_DESERIALIZE(aggsplit) &&
560  OidIsValid(transinfo->deserialfn_oid))
561  add_function_cost(root, transinfo->deserialfn_oid, NULL,
562  &costs->transCost);
563  if (DO_AGGSPLIT_SERIALIZE(aggsplit) &&
564  OidIsValid(transinfo->serialfn_oid))
565  add_function_cost(root, transinfo->serialfn_oid, NULL,
566  &costs->finalCost);
567 
568  /*
569  * These costs are incurred only by the initial aggregate node, so we
570  * mustn't include them again at upper levels.
571  */
572  if (!DO_AGGSPLIT_COMBINE(aggsplit))
573  {
574  /* add the input expressions' cost to per-input-row costs */
575  QualCost argcosts;
576 
577  cost_qual_eval_node(&argcosts, (Node *) transinfo->args, root);
578  costs->transCost.startup += argcosts.startup;
579  costs->transCost.per_tuple += argcosts.per_tuple;
580 
581  /*
582  * Add any filter's cost to per-input-row costs.
583  *
584  * XXX Ideally we should reduce input expression costs according
585  * to filter selectivity, but it's not clear it's worth the
586  * trouble.
587  */
588  if (transinfo->aggfilter)
589  {
590  cost_qual_eval_node(&argcosts, (Node *) transinfo->aggfilter,
591  root);
592  costs->transCost.startup += argcosts.startup;
593  costs->transCost.per_tuple += argcosts.per_tuple;
594  }
595  }
596 
597  /*
598  * If the transition type is pass-by-value then it doesn't add
599  * anything to the required size of the hashtable. If it is
600  * pass-by-reference then we have to add the estimated size of the
601  * value itself, plus palloc overhead.
602  */
603  if (!transinfo->transtypeByVal)
604  {
605  int32 avgwidth;
606 
607  /* Use average width if aggregate definition gave one */
608  if (transinfo->aggtransspace > 0)
609  avgwidth = transinfo->aggtransspace;
610  else if (transinfo->transfn_oid == F_ARRAY_APPEND)
611  {
612  /*
613  * If the transition function is array_append(), it'll use an
614  * expanded array as transvalue, which will occupy at least
615  * ALLOCSET_SMALL_INITSIZE and possibly more. Use that as the
616  * estimate for lack of a better idea.
617  */
618  avgwidth = ALLOCSET_SMALL_INITSIZE;
619  }
620  else
621  {
622  avgwidth = get_typavgwidth(transinfo->aggtranstype, transinfo->aggtranstypmod);
623  }
624 
625  avgwidth = MAXALIGN(avgwidth);
626  costs->transitionSpace += avgwidth + 2 * sizeof(void *);
627  }
628  else if (transinfo->aggtranstype == INTERNALOID)
629  {
630  /*
631  * INTERNAL transition type is a special case: although INTERNAL
632  * is pass-by-value, it's almost certainly being used as a pointer
633  * to some large data structure. The aggregate definition can
634  * provide an estimate of the size. If it doesn't, then we assume
635  * ALLOCSET_DEFAULT_INITSIZE, which is a good guess if the data is
636  * being kept in a private memory context, as is done by
637  * array_agg() for instance.
638  */
639  if (transinfo->aggtransspace > 0)
640  costs->transitionSpace += transinfo->aggtransspace;
641  else
643  }
644  }
645 
646  foreach(lc, root->agginfos)
647  {
648  AggInfo *agginfo = (AggInfo *) lfirst(lc);
649  Aggref *aggref = agginfo->representative_aggref;
650 
651  /*
652  * Add the appropriate component function execution costs to
653  * appropriate totals.
654  */
655  if (!DO_AGGSPLIT_SKIPFINAL(aggsplit) &&
656  OidIsValid(agginfo->finalfn_oid))
657  add_function_cost(root, agginfo->finalfn_oid, NULL,
658  &costs->finalCost);
659 
660  /*
661  * If there are direct arguments, treat their evaluation cost like the
662  * cost of the finalfn.
663  */
664  if (aggref->aggdirectargs)
665  {
666  QualCost argcosts;
667 
668  cost_qual_eval_node(&argcosts, (Node *) aggref->aggdirectargs,
669  root);
670  costs->finalCost.startup += argcosts.startup;
671  costs->finalCost.per_tuple += argcosts.per_tuple;
672  }
673  }
674 }
Oid serialfn_oid
Definition: pathnodes.h:2701
void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
Definition: costsize.c:4334
Oid finalfn_oid
Definition: pathnodes.h:2681
QualCost finalCost
Definition: pathnodes.h:59
Definition: nodes.h:536
void add_function_cost(PlannerInfo *root, Oid funcid, Node *node, QualCost *cost)
Definition: plancat.c:1967
bool transtypeByVal
Definition: pathnodes.h:2713
Expr * aggfilter
Definition: pathnodes.h:2695
List * agginfos
Definition: pathnodes.h:357
Oid combinefn_oid
Definition: pathnodes.h:2707
QualCost transCost
Definition: pathnodes.h:58
#define OidIsValid(objectId)
Definition: c.h:710
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:799
Cost startup
Definition: pathnodes.h:45
signed int int32
Definition: c.h:429
Cost per_tuple
Definition: pathnodes.h:46
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:801
List * aggtransinfos
Definition: pathnodes.h:358
int32 aggtransspace
Definition: pathnodes.h:2714
List * aggdirectargs
Definition: primnodes.h:329
Oid aggtranstype
Definition: pathnodes.h:2710
int32 aggtranstypmod
Definition: pathnodes.h:2711
#define ALLOCSET_SMALL_INITSIZE
Definition: memutils.h:203
int32 get_typavgwidth(Oid typid, int32 typmod)
Definition: lsyscache.c:2525
List * args
Definition: pathnodes.h:2694
#define lfirst(lc)
Definition: pg_list.h:169
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:800
#define MAXALIGN(LEN)
Definition: c.h:757
Oid deserialfn_oid
Definition: pathnodes.h:2704
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:802
#define ALLOCSET_DEFAULT_INITSIZE
Definition: memutils.h:193
Size transitionSpace
Definition: pathnodes.h:60
Aggref * representative_aggref
Definition: pathnodes.h:2670

◆ GetAggInitVal()

static Datum GetAggInitVal ( Datum  textInitVal,
Oid  transtype 
)
static

Definition at line 500 of file prepagg.c.

References getTypeInputInfo(), OidInputFunctionCall(), pfree(), and TextDatumGetCString.

Referenced by preprocess_aggref().

501 {
502  Oid typinput,
503  typioparam;
504  char *strInitVal;
505  Datum initVal;
506 
507  getTypeInputInfo(transtype, &typinput, &typioparam);
508  strInitVal = TextDatumGetCString(textInitVal);
509  initVal = OidInputFunctionCall(typinput, strInitVal,
510  typioparam, -1);
511  pfree(strInitVal);
512  return initVal;
513 }
unsigned int Oid
Definition: postgres_ext.h:31
void pfree(void *pointer)
Definition: mcxt.c:1169
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2821
#define TextDatumGetCString(d)
Definition: builtins.h:87
uintptr_t Datum
Definition: postgres.h:411
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1644

◆ preprocess_aggref()

static void preprocess_aggref ( Aggref aggref,
PlannerInfo root 
)
static

Definition at line 117 of file prepagg.c.

References Aggref::aggdistinct, Aggref::aggfilter, AggTransInfo::aggfilter, AGGFNOID, Aggref::aggfnoid, PlannerInfo::agginfos, Aggref::agglevelsup, Aggref::aggno, Aggref::aggorder, PlannerInfo::aggtransinfos, Aggref::aggtransno, AggTransInfo::aggtransspace, Aggref::aggtranstype, AggTransInfo::aggtranstype, AggTransInfo::aggtranstypmod, Aggref::aggtype, Aggref::args, AggTransInfo::args, Assert, AggTransInfo::combinefn_oid, AggTransInfo::deserialfn_oid, elog, ERROR, TargetEntry::expr, exprType(), exprTypmod(), AggInfo::finalfn_oid, find_compatible_agg(), find_compatible_trans(), FUNC_MAX_ARGS, get_aggregate_argtypes(), get_typlenbyval(), GetAggInitVal(), GETSTRUCT, PlannerInfo::hasNonPartialAggs, PlannerInfo::hasNonSerialAggs, HeapTupleIsValid, initValue(), AggTransInfo::initValue, AggTransInfo::initValueIsNull, lappend(), linitial, list_length(), list_nth(), NIL, PlannerInfo::numOrderedAggs, ObjectIdGetDatum, OidIsValid, palloc(), ReleaseSysCache(), AggInfo::representative_aggref, resolve_aggregate_transtype(), SearchSysCache1(), AggTransInfo::serialfn_oid, AggInfo::shareable, SysCacheGetAttr(), AggTransInfo::transfn_oid, AggInfo::transno, AggTransInfo::transtypeByVal, and AggTransInfo::transtypeLen.

Referenced by preprocess_aggrefs_walker().

118 {
119  HeapTuple aggTuple;
120  Form_pg_aggregate aggform;
121  Oid aggtransfn;
122  Oid aggfinalfn;
123  Oid aggcombinefn;
124  Oid aggserialfn;
125  Oid aggdeserialfn;
126  Oid aggtranstype;
127  int32 aggtranstypmod;
128  int32 aggtransspace;
129  bool shareable;
130  int aggno;
131  int transno;
132  List *same_input_transnos;
133  int16 resulttypeLen;
134  bool resulttypeByVal;
135  Datum textInitVal;
137  bool initValueIsNull;
138  bool transtypeByVal;
139  int16 transtypeLen;
140  Oid inputTypes[FUNC_MAX_ARGS];
141  int numArguments;
142 
143  Assert(aggref->agglevelsup == 0);
144 
145  /*
146  * Fetch info about the aggregate from pg_aggregate. Note it's correct to
147  * ignore the moving-aggregate variant, since what we're concerned with
148  * here is aggregates not window functions.
149  */
150  aggTuple = SearchSysCache1(AGGFNOID,
151  ObjectIdGetDatum(aggref->aggfnoid));
152  if (!HeapTupleIsValid(aggTuple))
153  elog(ERROR, "cache lookup failed for aggregate %u",
154  aggref->aggfnoid);
155  aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
156  aggtransfn = aggform->aggtransfn;
157  aggfinalfn = aggform->aggfinalfn;
158  aggcombinefn = aggform->aggcombinefn;
159  aggserialfn = aggform->aggserialfn;
160  aggdeserialfn = aggform->aggdeserialfn;
161  aggtranstype = aggform->aggtranstype;
162  aggtransspace = aggform->aggtransspace;
163 
164  /*
165  * Resolve the possibly-polymorphic aggregate transition type.
166  */
167 
168  /* extract argument types (ignoring any ORDER BY expressions) */
169  numArguments = get_aggregate_argtypes(aggref, inputTypes);
170 
171  /* resolve actual type of transition state, if polymorphic */
172  aggtranstype = resolve_aggregate_transtype(aggref->aggfnoid,
173  aggtranstype,
174  inputTypes,
175  numArguments);
176  aggref->aggtranstype = aggtranstype;
177 
178  /*
179  * If transition state is of same type as first aggregated input, assume
180  * it's the same typmod (same width) as well. This works for cases like
181  * MAX/MIN and is probably somewhat reasonable otherwise.
182  */
183  aggtranstypmod = -1;
184  if (aggref->args)
185  {
186  TargetEntry *tle = (TargetEntry *) linitial(aggref->args);
187 
188  if (aggtranstype == exprType((Node *) tle->expr))
189  aggtranstypmod = exprTypmod((Node *) tle->expr);
190  }
191 
192  /*
193  * If finalfn is marked read-write, we can't share transition states; but
194  * it is okay to share states for AGGMODIFY_SHAREABLE aggs.
195  *
196  * In principle, in a partial aggregate, we could share the transition
197  * state even if the final function is marked as read-write, because the
198  * partial aggregate doesn't execute the final function. But it's too
199  * early to know whether we're going perform a partial aggregate.
200  */
201  shareable = (aggform->aggfinalmodify != AGGMODIFY_READ_WRITE);
202 
203  /* get info about the output value's datatype */
204  get_typlenbyval(aggref->aggtype,
205  &resulttypeLen,
206  &resulttypeByVal);
207 
208  /* get initial value */
209  textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
210  Anum_pg_aggregate_agginitval,
211  &initValueIsNull);
212  if (initValueIsNull)
213  initValue = (Datum) 0;
214  else
215  initValue = GetAggInitVal(textInitVal, aggtranstype);
216 
217  ReleaseSysCache(aggTuple);
218 
219  /*
220  * 1. See if this is identical to another aggregate function call that
221  * we've seen already.
222  */
223  aggno = find_compatible_agg(root, aggref, &same_input_transnos);
224  if (aggno != -1)
225  {
226  AggInfo *agginfo = list_nth(root->agginfos, aggno);
227 
228  transno = agginfo->transno;
229  }
230  else
231  {
232  AggInfo *agginfo = palloc(sizeof(AggInfo));
233 
234  agginfo->finalfn_oid = aggfinalfn;
235  agginfo->representative_aggref = aggref;
236  agginfo->shareable = shareable;
237 
238  aggno = list_length(root->agginfos);
239  root->agginfos = lappend(root->agginfos, agginfo);
240 
241  /*
242  * Count it, and check for cases requiring ordered input. Note that
243  * ordered-set aggs always have nonempty aggorder. Any ordered-input
244  * case also defeats partial aggregation.
245  */
246  if (aggref->aggorder != NIL || aggref->aggdistinct != NIL)
247  {
248  root->numOrderedAggs++;
249  root->hasNonPartialAggs = true;
250  }
251 
252  get_typlenbyval(aggtranstype,
253  &transtypeLen,
254  &transtypeByVal);
255 
256  /*
257  * 2. See if this aggregate can share transition state with another
258  * aggregate that we've initialized already.
259  */
260  transno = find_compatible_trans(root, aggref, shareable,
261  aggtransfn, aggtranstype,
262  transtypeLen, transtypeByVal,
263  aggcombinefn,
264  aggserialfn, aggdeserialfn,
265  initValue, initValueIsNull,
266  same_input_transnos);
267  if (transno == -1)
268  {
269  AggTransInfo *transinfo = palloc(sizeof(AggTransInfo));
270 
271  transinfo->args = aggref->args;
272  transinfo->aggfilter = aggref->aggfilter;
273  transinfo->transfn_oid = aggtransfn;
274  transinfo->combinefn_oid = aggcombinefn;
275  transinfo->serialfn_oid = aggserialfn;
276  transinfo->deserialfn_oid = aggdeserialfn;
277  transinfo->aggtranstype = aggtranstype;
278  transinfo->aggtranstypmod = aggtranstypmod;
279  transinfo->transtypeLen = transtypeLen;
280  transinfo->transtypeByVal = transtypeByVal;
281  transinfo->aggtransspace = aggtransspace;
282  transinfo->initValue = initValue;
283  transinfo->initValueIsNull = initValueIsNull;
284 
285  transno = list_length(root->aggtransinfos);
286  root->aggtransinfos = lappend(root->aggtransinfos, transinfo);
287 
288  /*
289  * Check whether partial aggregation is feasible, unless we
290  * already found out that we can't do it.
291  */
292  if (!root->hasNonPartialAggs)
293  {
294  /*
295  * If there is no combine function, then partial aggregation
296  * is not possible.
297  */
298  if (!OidIsValid(transinfo->combinefn_oid))
299  root->hasNonPartialAggs = true;
300 
301  /*
302  * If we have any aggs with transtype INTERNAL then we must
303  * check whether they have serialization/deserialization
304  * functions; if not, we can't serialize partial-aggregation
305  * results.
306  */
307  else if (transinfo->aggtranstype == INTERNALOID &&
308  (!OidIsValid(transinfo->serialfn_oid) ||
309  !OidIsValid(transinfo->deserialfn_oid)))
310  root->hasNonSerialAggs = true;
311  }
312  }
313  agginfo->transno = transno;
314  }
315 
316  /*
317  * Fill in the fields in the Aggref (aggtranstype was set above already)
318  */
319  aggref->aggno = aggno;
320  aggref->aggtransno = transno;
321 }
Oid serialfn_oid
Definition: pathnodes.h:2701
List * aggdistinct
Definition: primnodes.h:332
signed short int16
Definition: c.h:428
#define NIL
Definition: pg_list.h:65
Oid finalfn_oid
Definition: pathnodes.h:2681
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
int aggtransno
Definition: primnodes.h:341
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:267
Definition: nodes.h:536
List * args
Definition: primnodes.h:330
bool transtypeByVal
Definition: pathnodes.h:2713
Expr * aggfilter
Definition: pathnodes.h:2695
Oid combinefn_oid
Definition: pathnodes.h:2707
List * agginfos
Definition: pathnodes.h:357
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
int transtypeLen
Definition: pathnodes.h:2712
signed int int32
Definition: c.h:429
#define FUNC_MAX_ARGS
#define linitial(l)
Definition: pg_list.h:174
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
static int find_compatible_agg(PlannerInfo *root, Aggref *newagg, List **same_input_transnos)
Definition: prepagg.c:360
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
List * aggtransinfos
Definition: pathnodes.h:358
bool initValueIsNull
Definition: pathnodes.h:2720
int numOrderedAggs
Definition: pathnodes.h:359
bool hasNonSerialAggs
Definition: pathnodes.h:361
int32 aggtransspace
Definition: pathnodes.h:2714
static int initValue(long lng_val)
Definition: informix.c:677
List * aggorder
Definition: primnodes.h:331
Index agglevelsup
Definition: primnodes.h:338
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition: prepagg.c:500
bool shareable
Definition: pathnodes.h:2678
Oid aggtranstype
Definition: pathnodes.h:2710
List * lappend(List *list, void *datum)
Definition: list.c:336
int32 aggtranstypmod
Definition: pathnodes.h:2711
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
Datum initValue
Definition: pathnodes.h:2719
int transno
Definition: pathnodes.h:2672
uintptr_t Datum
Definition: postgres.h:411
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1388
Oid aggfnoid
Definition: primnodes.h:323
List * args
Definition: pathnodes.h:2694
int aggno
Definition: primnodes.h:340
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
Expr * expr
Definition: primnodes.h:1455
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:149
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2198
Expr * aggfilter
Definition: primnodes.h:333
Oid deserialfn_oid
Definition: pathnodes.h:2704
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
Oid aggtranstype
Definition: primnodes.h:327
Oid aggtype
Definition: primnodes.h:324
bool hasNonPartialAggs
Definition: pathnodes.h:360
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1880
Definition: pg_list.h:50
static int find_compatible_trans(PlannerInfo *root, Aggref *newagg, bool shareable, Oid aggtransfn, Oid aggtranstype, int transtypeLen, bool transtypeByVal, Oid aggcombinefn, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, List *transnos)
Definition: prepagg.c:438
Aggref * representative_aggref
Definition: pathnodes.h:2670
Oid resolve_aggregate_transtype(Oid aggfuncid, Oid aggtranstype, Oid *inputTypes, int numArguments)
Definition: parse_agg.c:1906

◆ preprocess_aggrefs()

void preprocess_aggrefs ( PlannerInfo root,
Node clause 
)

Definition at line 111 of file prepagg.c.

References preprocess_aggrefs_walker().

Referenced by grouping_planner().

112 {
113  (void) preprocess_aggrefs_walker(clause, root);
114 }
static bool preprocess_aggrefs_walker(Node *node, PlannerInfo *root)
Definition: prepagg.c:324

◆ preprocess_aggrefs_walker()

static bool preprocess_aggrefs_walker ( Node node,
PlannerInfo root 
)
static

Definition at line 324 of file prepagg.c.

References Assert, expression_tree_walker(), IsA, and preprocess_aggref().

Referenced by preprocess_aggrefs().

325 {
326  if (node == NULL)
327  return false;
328  if (IsA(node, Aggref))
329  {
330  Aggref *aggref = (Aggref *) node;
331 
332  preprocess_aggref(aggref, root);
333 
334  /*
335  * We assume that the parser checked that there are no aggregates (of
336  * this level anyway) in the aggregated arguments, direct arguments,
337  * or filter clause. Hence, we need not recurse into any of them.
338  */
339  return false;
340  }
341  Assert(!IsA(node, SubLink));
343  (void *) root);
344 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
static bool preprocess_aggrefs_walker(Node *node, PlannerInfo *root)
Definition: prepagg.c:324
#define Assert(condition)
Definition: c.h:804
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1904
static void preprocess_aggref(Aggref *aggref, PlannerInfo *root)
Definition: prepagg.c:117