PostgreSQL Source Code  git master
prepagg.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * prepagg.c
4  * Routines to preprocess aggregate function calls
5  *
6  * If there are identical aggregate calls in the query, they only need to
7  * be computed once. Also, some aggregate functions can share the same
8  * transition state, so that we only need to call the final function for
9  * them separately. These optimizations are independent of how the
10  * aggregates are executed.
11  *
12  * preprocess_aggrefs() detects those cases, creates AggInfo and
13  * AggTransInfo structs for each aggregate and transition state that needs
14  * to be computed, and sets the 'aggno' and 'transno' fields in the Aggrefs
15  * accordingly. It also resolves polymorphic transition types, and sets
16  * the 'aggtranstype' fields accordingly.
17  *
18  * XXX: The AggInfo and AggTransInfo structs are thrown away after
19  * planning, so executor startup has to perform some of the same lookups
20  * of transition functions and initial values that we do here. One day, we
21  * might want to carry that information to the Agg nodes to save the effort
22  * at executor startup. The Agg nodes are constructed much later in the
23  * planning, however, so it's not trivial.
24  *
25  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
26  * Portions Copyright (c) 1994, Regents of the University of California
27  *
28  *
29  * IDENTIFICATION
30  * src/backend/optimizer/prep/prepagg.c
31  *
32  *-------------------------------------------------------------------------
33  */
34 
35 #include "postgres.h"
36 
37 #include "access/htup_details.h"
38 #include "catalog/pg_aggregate.h"
39 #include "catalog/pg_type.h"
40 #include "nodes/nodeFuncs.h"
41 #include "nodes/pathnodes.h"
42 #include "optimizer/clauses.h"
43 #include "optimizer/cost.h"
44 #include "optimizer/optimizer.h"
45 #include "optimizer/plancat.h"
46 #include "optimizer/prep.h"
47 #include "parser/parse_agg.h"
48 #include "utils/builtins.h"
49 #include "utils/datum.h"
50 #include "utils/fmgroids.h"
51 #include "utils/lsyscache.h"
52 #include "utils/memutils.h"
53 #include "utils/syscache.h"
54 
55 static bool preprocess_aggrefs_walker(Node *node, PlannerInfo *root);
56 static int find_compatible_agg(PlannerInfo *root, Aggref *newagg,
57  List **same_input_transnos);
58 static int find_compatible_trans(PlannerInfo *root, Aggref *newagg,
59  bool shareable,
60  Oid aggtransfn, Oid aggtranstype,
61  int transtypeLen, bool transtypeByVal,
62  Oid aggcombinefn,
63  Oid aggserialfn, Oid aggdeserialfn,
64  Datum initValue, bool initValueIsNull,
65  List *transnos);
66 static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
67 
68 /* -----------------
69  * Resolve the transition type of all Aggrefs, and determine which Aggrefs
70  * can share aggregate or transition state.
71  *
72  * Information about the aggregates and transition functions are collected
73  * in the root->agginfos and root->aggtransinfos lists. The 'aggtranstype',
74  * 'aggno', and 'aggtransno' fields of each Aggref are filled in.
75  *
76  * NOTE: This modifies the Aggrefs in the input expression in-place!
77  *
78  * We try to optimize by detecting duplicate aggregate functions so that
79  * their state and final values are re-used, rather than needlessly being
80  * re-calculated independently. We also detect aggregates that are not
81  * the same, but which can share the same transition state.
82  *
83  * Scenarios:
84  *
85  * 1. Identical aggregate function calls appear in the query:
86  *
87  * SELECT SUM(x) FROM ... HAVING SUM(x) > 0
88  *
89  * Since these aggregates are identical, we only need to calculate
90  * the value once. Both aggregates will share the same 'aggno' value.
91  *
92  * 2. Two different aggregate functions appear in the query, but the
93  * aggregates have the same arguments, transition functions and
94  * initial values (and, presumably, different final functions):
95  *
96  * SELECT AVG(x), STDDEV(x) FROM ...
97  *
98  * In this case we must create a new AggInfo for the varying aggregate,
99  * and we need to call the final functions separately, but we need
100  * only run the transition function once. (This requires that the
101  * final functions be nondestructive of the transition state, but
102  * that's required anyway for other reasons.)
103  *
104  * For either of these optimizations to be valid, all aggregate properties
105  * used in the transition phase must be the same, including any modifiers
106  * such as ORDER BY, DISTINCT and FILTER, and the arguments mustn't
107  * contain any volatile functions.
108  * -----------------
109  */
110 void
112 {
113  (void) preprocess_aggrefs_walker(clause, root);
114 }
115 
116 static void
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_node(AggInfo, root->agginfos, aggno);
227 
228  agginfo->aggrefs = lappend(agginfo->aggrefs, aggref);
229  transno = agginfo->transno;
230  }
231  else
232  {
233  AggInfo *agginfo = makeNode(AggInfo);
234 
235  agginfo->finalfn_oid = aggfinalfn;
236  agginfo->aggrefs = list_make1(aggref);
237  agginfo->shareable = shareable;
238 
239  aggno = list_length(root->agginfos);
240  root->agginfos = lappend(root->agginfos, agginfo);
241 
242  /*
243  * Count it, and check for cases requiring ordered input. Note that
244  * ordered-set aggs always have nonempty aggorder. Any ordered-input
245  * case also defeats partial aggregation.
246  */
247  if (aggref->aggorder != NIL || aggref->aggdistinct != NIL)
248  {
249  root->numOrderedAggs++;
250  root->hasNonPartialAggs = true;
251  }
252 
253  get_typlenbyval(aggtranstype,
254  &transtypeLen,
255  &transtypeByVal);
256 
257  /*
258  * 2. See if this aggregate can share transition state with another
259  * aggregate that we've initialized already.
260  */
261  transno = find_compatible_trans(root, aggref, shareable,
262  aggtransfn, aggtranstype,
263  transtypeLen, transtypeByVal,
264  aggcombinefn,
265  aggserialfn, aggdeserialfn,
266  initValue, initValueIsNull,
267  same_input_transnos);
268  if (transno == -1)
269  {
270  AggTransInfo *transinfo = makeNode(AggTransInfo);
271 
272  transinfo->args = aggref->args;
273  transinfo->aggfilter = aggref->aggfilter;
274  transinfo->transfn_oid = aggtransfn;
275  transinfo->combinefn_oid = aggcombinefn;
276  transinfo->serialfn_oid = aggserialfn;
277  transinfo->deserialfn_oid = aggdeserialfn;
278  transinfo->aggtranstype = aggtranstype;
279  transinfo->aggtranstypmod = aggtranstypmod;
280  transinfo->transtypeLen = transtypeLen;
281  transinfo->transtypeByVal = transtypeByVal;
282  transinfo->aggtransspace = aggtransspace;
283  transinfo->initValue = initValue;
284  transinfo->initValueIsNull = initValueIsNull;
285 
286  transno = list_length(root->aggtransinfos);
287  root->aggtransinfos = lappend(root->aggtransinfos, transinfo);
288 
289  /*
290  * Check whether partial aggregation is feasible, unless we
291  * already found out that we can't do it.
292  */
293  if (!root->hasNonPartialAggs)
294  {
295  /*
296  * If there is no combine function, then partial aggregation
297  * is not possible.
298  */
299  if (!OidIsValid(transinfo->combinefn_oid))
300  root->hasNonPartialAggs = true;
301 
302  /*
303  * If we have any aggs with transtype INTERNAL then we must
304  * check whether they have serialization/deserialization
305  * functions; if not, we can't serialize partial-aggregation
306  * results.
307  */
308  else if (transinfo->aggtranstype == INTERNALOID)
309  {
310 
311  if (!OidIsValid(transinfo->serialfn_oid) ||
312  !OidIsValid(transinfo->deserialfn_oid))
313  root->hasNonSerialAggs = true;
314 
315  /*
316  * array_agg_serialize and array_agg_deserialize make use
317  * of the aggregate non-byval input type's send and
318  * receive functions. There's a chance that the type
319  * being aggregated has one or both of these functions
320  * missing. In this case we must not allow the
321  * aggregate's serial and deserial functions to be used.
322  * It would be nice not to have special case this and
323  * instead provide some sort of supporting function within
324  * the aggregate to do this, but for now, that seems like
325  * overkill for this one case.
326  */
327  if ((transinfo->serialfn_oid == F_ARRAY_AGG_SERIALIZE ||
328  transinfo->deserialfn_oid == F_ARRAY_AGG_DESERIALIZE) &&
330  root->hasNonSerialAggs = true;
331  }
332  }
333  }
334  agginfo->transno = transno;
335  }
336 
337  /*
338  * Fill in the fields in the Aggref (aggtranstype was set above already)
339  */
340  aggref->aggno = aggno;
341  aggref->aggtransno = transno;
342 }
343 
344 static bool
346 {
347  if (node == NULL)
348  return false;
349  if (IsA(node, Aggref))
350  {
351  Aggref *aggref = (Aggref *) node;
352 
353  preprocess_aggref(aggref, root);
354 
355  /*
356  * We assume that the parser checked that there are no aggregates (of
357  * this level anyway) in the aggregated arguments, direct arguments,
358  * or filter clause. Hence, we need not recurse into any of them.
359  */
360  return false;
361  }
362  Assert(!IsA(node, SubLink));
364  (void *) root);
365 }
366 
367 
368 /*
369  * find_compatible_agg - search for a previously initialized per-Agg struct
370  *
371  * Searches the previously looked at aggregates to find one which is compatible
372  * with this one, with the same input parameters. If no compatible aggregate
373  * can be found, returns -1.
374  *
375  * As a side-effect, this also collects a list of existing, shareable per-Trans
376  * structs with matching inputs. If no identical Aggref is found, the list is
377  * passed later to find_compatible_trans, to see if we can at least reuse
378  * the state value of another aggregate.
379  */
380 static int
382  List **same_input_transnos)
383 {
384  ListCell *lc;
385  int aggno;
386 
387  *same_input_transnos = NIL;
388 
389  /* we mustn't reuse the aggref if it contains volatile function calls */
390  if (contain_volatile_functions((Node *) newagg))
391  return -1;
392 
393  /*
394  * Search through the list of already seen aggregates. If we find an
395  * existing identical aggregate call, then we can re-use that one. While
396  * searching, we'll also collect a list of Aggrefs with the same input
397  * parameters. If no matching Aggref is found, the caller can potentially
398  * still re-use the transition state of one of them. (At this stage we
399  * just compare the parsetrees; whether different aggregates share the
400  * same transition function will be checked later.)
401  */
402  aggno = -1;
403  foreach(lc, root->agginfos)
404  {
405  AggInfo *agginfo = lfirst_node(AggInfo, lc);
406  Aggref *existingRef;
407 
408  aggno++;
409 
410  existingRef = linitial_node(Aggref, agginfo->aggrefs);
411 
412  /* all of the following must be the same or it's no match */
413  if (newagg->inputcollid != existingRef->inputcollid ||
414  newagg->aggtranstype != existingRef->aggtranstype ||
415  newagg->aggstar != existingRef->aggstar ||
416  newagg->aggvariadic != existingRef->aggvariadic ||
417  newagg->aggkind != existingRef->aggkind ||
418  !equal(newagg->args, existingRef->args) ||
419  !equal(newagg->aggorder, existingRef->aggorder) ||
420  !equal(newagg->aggdistinct, existingRef->aggdistinct) ||
421  !equal(newagg->aggfilter, existingRef->aggfilter))
422  continue;
423 
424  /* if it's the same aggregate function then report exact match */
425  if (newagg->aggfnoid == existingRef->aggfnoid &&
426  newagg->aggtype == existingRef->aggtype &&
427  newagg->aggcollid == existingRef->aggcollid &&
428  equal(newagg->aggdirectargs, existingRef->aggdirectargs))
429  {
430  list_free(*same_input_transnos);
431  *same_input_transnos = NIL;
432  return aggno;
433  }
434 
435  /*
436  * Not identical, but it had the same inputs. If the final function
437  * permits sharing, return its transno to the caller, in case we can
438  * re-use its per-trans state. (If there's already sharing going on,
439  * we might report a transno more than once. find_compatible_trans is
440  * cheap enough that it's not worth spending cycles to avoid that.)
441  */
442  if (agginfo->shareable)
443  *same_input_transnos = lappend_int(*same_input_transnos,
444  agginfo->transno);
445  }
446 
447  return -1;
448 }
449 
450 /*
451  * find_compatible_trans - search for a previously initialized per-Trans
452  * struct
453  *
454  * Searches the list of transnos for a per-Trans struct with the same
455  * transition function and initial condition. (The inputs have already been
456  * verified to match.)
457  */
458 static int
459 find_compatible_trans(PlannerInfo *root, Aggref *newagg, bool shareable,
460  Oid aggtransfn, Oid aggtranstype,
461  int transtypeLen, bool transtypeByVal,
462  Oid aggcombinefn,
463  Oid aggserialfn, Oid aggdeserialfn,
464  Datum initValue, bool initValueIsNull,
465  List *transnos)
466 {
467  ListCell *lc;
468 
469  /* If this aggregate can't share transition states, give up */
470  if (!shareable)
471  return -1;
472 
473  foreach(lc, transnos)
474  {
475  int transno = lfirst_int(lc);
477  root->aggtransinfos,
478  transno);
479 
480  /*
481  * if the transfns or transition state types are not the same then the
482  * state can't be shared.
483  */
484  if (aggtransfn != pertrans->transfn_oid ||
485  aggtranstype != pertrans->aggtranstype)
486  continue;
487 
488  /*
489  * The serialization and deserialization functions must match, if
490  * present, as we're unable to share the trans state for aggregates
491  * which will serialize or deserialize into different formats.
492  * Remember that these will be InvalidOid if they're not required for
493  * this agg node.
494  */
495  if (aggserialfn != pertrans->serialfn_oid ||
496  aggdeserialfn != pertrans->deserialfn_oid)
497  continue;
498 
499  /*
500  * Combine function must also match. We only care about the combine
501  * function with partial aggregates, but it's too early in the
502  * planning to know if we will do partial aggregation, so be
503  * conservative.
504  */
505  if (aggcombinefn != pertrans->combinefn_oid)
506  continue;
507 
508  /*
509  * Check that the initial condition matches, too.
510  */
511  if (initValueIsNull && pertrans->initValueIsNull)
512  return transno;
513 
514  if (!initValueIsNull && !pertrans->initValueIsNull &&
515  datumIsEqual(initValue, pertrans->initValue,
516  transtypeByVal, transtypeLen))
517  return transno;
518  }
519  return -1;
520 }
521 
522 static Datum
523 GetAggInitVal(Datum textInitVal, Oid transtype)
524 {
525  Oid typinput,
526  typioparam;
527  char *strInitVal;
528  Datum initVal;
529 
530  getTypeInputInfo(transtype, &typinput, &typioparam);
531  strInitVal = TextDatumGetCString(textInitVal);
532  initVal = OidInputFunctionCall(typinput, strInitVal,
533  typioparam, -1);
534  pfree(strInitVal);
535  return initVal;
536 }
537 
538 
539 /*
540  * get_agg_clause_costs
541  * Process the PlannerInfo's 'aggtransinfos' and 'agginfos' lists
542  * accumulating the cost information about them.
543  *
544  * 'aggsplit' tells us the expected partial-aggregation mode, which affects
545  * the cost estimates.
546  *
547  * NOTE that the costs are ADDED to those already in *costs ... so the caller
548  * is responsible for zeroing the struct initially.
549  *
550  * For each AggTransInfo, we add the cost of an aggregate transition using
551  * either the transfn or combinefn depending on the 'aggsplit' value. We also
552  * account for the costs of any aggfilters and any serializations and
553  * deserializations of the transition state and also estimate the total space
554  * needed for the transition states as if each aggregate's state was stored in
555  * memory concurrently (as would be done in a HashAgg plan).
556  *
557  * For each AggInfo in the 'agginfos' list we add the cost of running the
558  * final function and the direct args, if any.
559  */
560 void
562 {
563  ListCell *lc;
564 
565  foreach(lc, root->aggtransinfos)
566  {
567  AggTransInfo *transinfo = lfirst_node(AggTransInfo, lc);
568 
569  /*
570  * Add the appropriate component function execution costs to
571  * appropriate totals.
572  */
573  if (DO_AGGSPLIT_COMBINE(aggsplit))
574  {
575  /* charge for combining previously aggregated states */
576  add_function_cost(root, transinfo->combinefn_oid, NULL,
577  &costs->transCost);
578  }
579  else
580  add_function_cost(root, transinfo->transfn_oid, NULL,
581  &costs->transCost);
582  if (DO_AGGSPLIT_DESERIALIZE(aggsplit) &&
583  OidIsValid(transinfo->deserialfn_oid))
584  add_function_cost(root, transinfo->deserialfn_oid, NULL,
585  &costs->transCost);
586  if (DO_AGGSPLIT_SERIALIZE(aggsplit) &&
587  OidIsValid(transinfo->serialfn_oid))
588  add_function_cost(root, transinfo->serialfn_oid, NULL,
589  &costs->finalCost);
590 
591  /*
592  * These costs are incurred only by the initial aggregate node, so we
593  * mustn't include them again at upper levels.
594  */
595  if (!DO_AGGSPLIT_COMBINE(aggsplit))
596  {
597  /* add the input expressions' cost to per-input-row costs */
598  QualCost argcosts;
599 
600  cost_qual_eval_node(&argcosts, (Node *) transinfo->args, root);
601  costs->transCost.startup += argcosts.startup;
602  costs->transCost.per_tuple += argcosts.per_tuple;
603 
604  /*
605  * Add any filter's cost to per-input-row costs.
606  *
607  * XXX Ideally we should reduce input expression costs according
608  * to filter selectivity, but it's not clear it's worth the
609  * trouble.
610  */
611  if (transinfo->aggfilter)
612  {
613  cost_qual_eval_node(&argcosts, (Node *) transinfo->aggfilter,
614  root);
615  costs->transCost.startup += argcosts.startup;
616  costs->transCost.per_tuple += argcosts.per_tuple;
617  }
618  }
619 
620  /*
621  * If the transition type is pass-by-value then it doesn't add
622  * anything to the required size of the hashtable. If it is
623  * pass-by-reference then we have to add the estimated size of the
624  * value itself, plus palloc overhead.
625  */
626  if (!transinfo->transtypeByVal)
627  {
628  int32 avgwidth;
629 
630  /* Use average width if aggregate definition gave one */
631  if (transinfo->aggtransspace > 0)
632  avgwidth = transinfo->aggtransspace;
633  else if (transinfo->transfn_oid == F_ARRAY_APPEND)
634  {
635  /*
636  * If the transition function is array_append(), it'll use an
637  * expanded array as transvalue, which will occupy at least
638  * ALLOCSET_SMALL_INITSIZE and possibly more. Use that as the
639  * estimate for lack of a better idea.
640  */
641  avgwidth = ALLOCSET_SMALL_INITSIZE;
642  }
643  else
644  {
645  avgwidth = get_typavgwidth(transinfo->aggtranstype, transinfo->aggtranstypmod);
646  }
647 
648  avgwidth = MAXALIGN(avgwidth);
649  costs->transitionSpace += avgwidth + 2 * sizeof(void *);
650  }
651  else if (transinfo->aggtranstype == INTERNALOID)
652  {
653  /*
654  * INTERNAL transition type is a special case: although INTERNAL
655  * is pass-by-value, it's almost certainly being used as a pointer
656  * to some large data structure. The aggregate definition can
657  * provide an estimate of the size. If it doesn't, then we assume
658  * ALLOCSET_DEFAULT_INITSIZE, which is a good guess if the data is
659  * being kept in a private memory context, as is done by
660  * array_agg() for instance.
661  */
662  if (transinfo->aggtransspace > 0)
663  costs->transitionSpace += transinfo->aggtransspace;
664  else
666  }
667  }
668 
669  foreach(lc, root->agginfos)
670  {
671  AggInfo *agginfo = lfirst_node(AggInfo, lc);
672  Aggref *aggref = linitial_node(Aggref, agginfo->aggrefs);
673 
674  /*
675  * Add the appropriate component function execution costs to
676  * appropriate totals.
677  */
678  if (!DO_AGGSPLIT_SKIPFINAL(aggsplit) &&
679  OidIsValid(agginfo->finalfn_oid))
680  add_function_cost(root, agginfo->finalfn_oid, NULL,
681  &costs->finalCost);
682 
683  /*
684  * If there are direct arguments, treat their evaluation cost like the
685  * cost of the finalfn.
686  */
687  if (aggref->aggdirectargs)
688  {
689  QualCost argcosts;
690 
691  cost_qual_eval_node(&argcosts, (Node *) aggref->aggdirectargs,
692  root);
693  costs->finalCost.startup += argcosts.startup;
694  costs->finalCost.per_tuple += argcosts.per_tuple;
695  }
696  }
697 }
#define TextDatumGetCString(d)
Definition: builtins.h:95
signed short int16
Definition: c.h:482
#define MAXALIGN(LEN)
Definition: c.h:800
signed int int32
Definition: c.h:483
#define OidIsValid(objectId)
Definition: c.h:764
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:483
void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
Definition: costsize.c:4638
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:223
#define ERROR
Definition: elog.h:39
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1737
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
static int initValue(long lng_val)
Definition: informix.c:677
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
List * lappend_int(List *list, int datum)
Definition: list.c:356
void list_free(List *list)
Definition: list.c:1545
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2233
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2856
int32 get_typavgwidth(Oid typid, int32 typmod)
Definition: lsyscache.c:2560
void pfree(void *pointer)
Definition: mcxt.c:1456
#define ALLOCSET_SMALL_INITSIZE
Definition: memutils.h:161
#define ALLOCSET_DEFAULT_INITSIZE
Definition: memutils.h:151
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:282
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:396
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:398
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:395
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:397
AggSplit
Definition: nodes.h:385
#define makeNode(_type_)
Definition: nodes.h:176
Oid resolve_aggregate_transtype(Oid aggfuncid, Oid aggtranstype, Oid *inputTypes, int numArguments)
Definition: parse_agg.c:1920
bool agg_args_support_sendreceive(Aggref *aggref)
Definition: parse_agg.c:1956
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1894
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
#define FUNC_MAX_ARGS
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial_node(type, l)
Definition: pg_list.h:181
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
#define list_make1(x1)
Definition: pg_list.h:212
#define linitial(l)
Definition: pg_list.h:178
#define list_nth_node(type, list, n)
Definition: pg_list.h:327
void add_function_cost(PlannerInfo *root, Oid funcid, Node *node, QualCost *cost)
Definition: plancat.c:2043
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
unsigned int Oid
Definition: postgres_ext.h:31
static bool preprocess_aggrefs_walker(Node *node, PlannerInfo *root)
Definition: prepagg.c:345
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition: prepagg.c:523
void get_agg_clause_costs(PlannerInfo *root, AggSplit aggsplit, AggClauseCosts *costs)
Definition: prepagg.c:561
static int find_compatible_agg(PlannerInfo *root, Aggref *newagg, List **same_input_transnos)
Definition: prepagg.c:381
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:459
static void preprocess_aggref(Aggref *aggref, PlannerInfo *root)
Definition: prepagg.c:117
void preprocess_aggrefs(PlannerInfo *root, Node *clause)
Definition: prepagg.c:111
QualCost finalCost
Definition: pathnodes.h:61
Size transitionSpace
Definition: pathnodes.h:62
QualCost transCost
Definition: pathnodes.h:60
bool shareable
Definition: pathnodes.h:3343
List * aggrefs
Definition: pathnodes.h:3334
int transno
Definition: pathnodes.h:3337
Oid finalfn_oid
Definition: pathnodes.h:3346
List * args
Definition: pathnodes.h:3363
int32 aggtransspace
Definition: pathnodes.h:3387
bool transtypeByVal
Definition: pathnodes.h:3384
Oid combinefn_oid
Definition: pathnodes.h:3376
Oid deserialfn_oid
Definition: pathnodes.h:3373
int32 aggtranstypmod
Definition: pathnodes.h:3382
int transtypeLen
Definition: pathnodes.h:3383
bool initValueIsNull
Definition: pathnodes.h:3391
Oid serialfn_oid
Definition: pathnodes.h:3370
Oid aggtranstype
Definition: pathnodes.h:3379
Expr * aggfilter
Definition: pathnodes.h:3364
Oid aggfnoid
Definition: primnodes.h:422
List * aggdistinct
Definition: primnodes.h:452
List * aggdirectargs
Definition: primnodes.h:443
List * args
Definition: primnodes.h:446
Expr * aggfilter
Definition: primnodes.h:455
List * aggorder
Definition: primnodes.h:449
Definition: pg_list.h:54
Definition: nodes.h:129
List * aggtransinfos
Definition: pathnodes.h:509
int numOrderedAggs
Definition: pathnodes.h:511
bool hasNonPartialAggs
Definition: pathnodes.h:513
List * agginfos
Definition: pathnodes.h:507
bool hasNonSerialAggs
Definition: pathnodes.h:515
Cost per_tuple
Definition: pathnodes.h:48
Cost startup
Definition: pathnodes.h:47
Expr * expr
Definition: primnodes.h:1895
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:868
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:820
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1081
@ AGGFNOID
Definition: syscache.h:34