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-2024, 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/cost.h"
43 #include "optimizer/optimizer.h"
44 #include "optimizer/plancat.h"
45 #include "optimizer/prep.h"
46 #include "parser/parse_agg.h"
47 #include "utils/builtins.h"
48 #include "utils/datum.h"
49 #include "utils/fmgroids.h"
50 #include "utils/lsyscache.h"
51 #include "utils/memutils.h"
52 #include "utils/syscache.h"
53 
54 static bool preprocess_aggrefs_walker(Node *node, PlannerInfo *root);
55 static int find_compatible_agg(PlannerInfo *root, Aggref *newagg,
56  List **same_input_transnos);
57 static int find_compatible_trans(PlannerInfo *root, Aggref *newagg,
58  bool shareable,
59  Oid aggtransfn, Oid aggtranstype,
60  int transtypeLen, bool transtypeByVal,
61  Oid aggcombinefn,
62  Oid aggserialfn, Oid aggdeserialfn,
63  Datum initValue, bool initValueIsNull,
64  List *transnos);
65 static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
66 
67 /* -----------------
68  * Resolve the transition type of all Aggrefs, and determine which Aggrefs
69  * can share aggregate or transition state.
70  *
71  * Information about the aggregates and transition functions are collected
72  * in the root->agginfos and root->aggtransinfos lists. The 'aggtranstype',
73  * 'aggno', and 'aggtransno' fields of each Aggref are filled in.
74  *
75  * NOTE: This modifies the Aggrefs in the input expression in-place!
76  *
77  * We try to optimize by detecting duplicate aggregate functions so that
78  * their state and final values are re-used, rather than needlessly being
79  * re-calculated independently. We also detect aggregates that are not
80  * the same, but which can share the same transition state.
81  *
82  * Scenarios:
83  *
84  * 1. Identical aggregate function calls appear in the query:
85  *
86  * SELECT SUM(x) FROM ... HAVING SUM(x) > 0
87  *
88  * Since these aggregates are identical, we only need to calculate
89  * the value once. Both aggregates will share the same 'aggno' value.
90  *
91  * 2. Two different aggregate functions appear in the query, but the
92  * aggregates have the same arguments, transition functions and
93  * initial values (and, presumably, different final functions):
94  *
95  * SELECT AVG(x), STDDEV(x) FROM ...
96  *
97  * In this case we must create a new AggInfo for the varying aggregate,
98  * and we need to call the final functions separately, but we need
99  * only run the transition function once. (This requires that the
100  * final functions be nondestructive of the transition state, but
101  * that's required anyway for other reasons.)
102  *
103  * For either of these optimizations to be valid, all aggregate properties
104  * used in the transition phase must be the same, including any modifiers
105  * such as ORDER BY, DISTINCT and FILTER, and the arguments mustn't
106  * contain any volatile functions.
107  * -----------------
108  */
109 void
111 {
112  (void) preprocess_aggrefs_walker(clause, root);
113 }
114 
115 static void
117 {
118  HeapTuple aggTuple;
119  Form_pg_aggregate aggform;
120  Oid aggtransfn;
121  Oid aggfinalfn;
122  Oid aggcombinefn;
123  Oid aggserialfn;
124  Oid aggdeserialfn;
125  Oid aggtranstype;
126  int32 aggtranstypmod;
127  int32 aggtransspace;
128  bool shareable;
129  int aggno;
130  int transno;
131  List *same_input_transnos;
132  int16 resulttypeLen;
133  bool resulttypeByVal;
134  Datum textInitVal;
136  bool initValueIsNull;
137  bool transtypeByVal;
138  int16 transtypeLen;
139  Oid inputTypes[FUNC_MAX_ARGS];
140  int numArguments;
141 
142  Assert(aggref->agglevelsup == 0);
143 
144  /*
145  * Fetch info about the aggregate from pg_aggregate. Note it's correct to
146  * ignore the moving-aggregate variant, since what we're concerned with
147  * here is aggregates not window functions.
148  */
149  aggTuple = SearchSysCache1(AGGFNOID,
150  ObjectIdGetDatum(aggref->aggfnoid));
151  if (!HeapTupleIsValid(aggTuple))
152  elog(ERROR, "cache lookup failed for aggregate %u",
153  aggref->aggfnoid);
154  aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
155  aggtransfn = aggform->aggtransfn;
156  aggfinalfn = aggform->aggfinalfn;
157  aggcombinefn = aggform->aggcombinefn;
158  aggserialfn = aggform->aggserialfn;
159  aggdeserialfn = aggform->aggdeserialfn;
160  aggtranstype = aggform->aggtranstype;
161  aggtransspace = aggform->aggtransspace;
162 
163  /*
164  * Resolve the possibly-polymorphic aggregate transition type.
165  */
166 
167  /* extract argument types (ignoring any ORDER BY expressions) */
168  numArguments = get_aggregate_argtypes(aggref, inputTypes);
169 
170  /* resolve actual type of transition state, if polymorphic */
171  aggtranstype = resolve_aggregate_transtype(aggref->aggfnoid,
172  aggtranstype,
173  inputTypes,
174  numArguments);
175  aggref->aggtranstype = aggtranstype;
176 
177  /*
178  * If transition state is of same type as first aggregated input, assume
179  * it's the same typmod (same width) as well. This works for cases like
180  * MAX/MIN and is probably somewhat reasonable otherwise.
181  */
182  aggtranstypmod = -1;
183  if (aggref->args)
184  {
185  TargetEntry *tle = (TargetEntry *) linitial(aggref->args);
186 
187  if (aggtranstype == exprType((Node *) tle->expr))
188  aggtranstypmod = exprTypmod((Node *) tle->expr);
189  }
190 
191  /*
192  * If finalfn is marked read-write, we can't share transition states; but
193  * it is okay to share states for AGGMODIFY_SHAREABLE aggs.
194  *
195  * In principle, in a partial aggregate, we could share the transition
196  * state even if the final function is marked as read-write, because the
197  * partial aggregate doesn't execute the final function. But it's too
198  * early to know whether we're going perform a partial aggregate.
199  */
200  shareable = (aggform->aggfinalmodify != AGGMODIFY_READ_WRITE);
201 
202  /* get info about the output value's datatype */
203  get_typlenbyval(aggref->aggtype,
204  &resulttypeLen,
205  &resulttypeByVal);
206 
207  /* get initial value */
208  textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
209  Anum_pg_aggregate_agginitval,
210  &initValueIsNull);
211  if (initValueIsNull)
212  initValue = (Datum) 0;
213  else
214  initValue = GetAggInitVal(textInitVal, aggtranstype);
215 
216  ReleaseSysCache(aggTuple);
217 
218  /*
219  * 1. See if this is identical to another aggregate function call that
220  * we've seen already.
221  */
222  aggno = find_compatible_agg(root, aggref, &same_input_transnos);
223  if (aggno != -1)
224  {
225  AggInfo *agginfo = list_nth_node(AggInfo, root->agginfos, aggno);
226 
227  agginfo->aggrefs = lappend(agginfo->aggrefs, aggref);
228  transno = agginfo->transno;
229  }
230  else
231  {
232  AggInfo *agginfo = makeNode(AggInfo);
233 
234  agginfo->finalfn_oid = aggfinalfn;
235  agginfo->aggrefs = list_make1(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 = makeNode(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  {
309 
310  if (!OidIsValid(transinfo->serialfn_oid) ||
311  !OidIsValid(transinfo->deserialfn_oid))
312  root->hasNonSerialAggs = true;
313 
314  /*
315  * array_agg_serialize and array_agg_deserialize make use
316  * of the aggregate non-byval input type's send and
317  * receive functions. There's a chance that the type
318  * being aggregated has one or both of these functions
319  * missing. In this case we must not allow the
320  * aggregate's serial and deserial functions to be used.
321  * It would be nice not to have special case this and
322  * instead provide some sort of supporting function within
323  * the aggregate to do this, but for now, that seems like
324  * overkill for this one case.
325  */
326  if ((transinfo->serialfn_oid == F_ARRAY_AGG_SERIALIZE ||
327  transinfo->deserialfn_oid == F_ARRAY_AGG_DESERIALIZE) &&
329  root->hasNonSerialAggs = true;
330  }
331  }
332  }
333  agginfo->transno = transno;
334  }
335 
336  /*
337  * Fill in the fields in the Aggref (aggtranstype was set above already)
338  */
339  aggref->aggno = aggno;
340  aggref->aggtransno = transno;
341 }
342 
343 static bool
345 {
346  if (node == NULL)
347  return false;
348  if (IsA(node, Aggref))
349  {
350  Aggref *aggref = (Aggref *) node;
351 
352  preprocess_aggref(aggref, root);
353 
354  /*
355  * We assume that the parser checked that there are no aggregates (of
356  * this level anyway) in the aggregated arguments, direct arguments,
357  * or filter clause. Hence, we need not recurse into any of them.
358  */
359  return false;
360  }
361  Assert(!IsA(node, SubLink));
363  (void *) root);
364 }
365 
366 
367 /*
368  * find_compatible_agg - search for a previously initialized per-Agg struct
369  *
370  * Searches the previously looked at aggregates to find one which is compatible
371  * with this one, with the same input parameters. If no compatible aggregate
372  * can be found, returns -1.
373  *
374  * As a side-effect, this also collects a list of existing, shareable per-Trans
375  * structs with matching inputs. If no identical Aggref is found, the list is
376  * passed later to find_compatible_trans, to see if we can at least reuse
377  * the state value of another aggregate.
378  */
379 static int
381  List **same_input_transnos)
382 {
383  ListCell *lc;
384  int aggno;
385 
386  *same_input_transnos = NIL;
387 
388  /* we mustn't reuse the aggref if it contains volatile function calls */
389  if (contain_volatile_functions((Node *) newagg))
390  return -1;
391 
392  /*
393  * Search through the list of already seen aggregates. If we find an
394  * existing identical aggregate call, then we can re-use that one. While
395  * searching, we'll also collect a list of Aggrefs with the same input
396  * parameters. If no matching Aggref is found, the caller can potentially
397  * still re-use the transition state of one of them. (At this stage we
398  * just compare the parsetrees; whether different aggregates share the
399  * same transition function will be checked later.)
400  */
401  aggno = -1;
402  foreach(lc, root->agginfos)
403  {
404  AggInfo *agginfo = lfirst_node(AggInfo, lc);
405  Aggref *existingRef;
406 
407  aggno++;
408 
409  existingRef = linitial_node(Aggref, agginfo->aggrefs);
410 
411  /* all of the following must be the same or it's no match */
412  if (newagg->inputcollid != existingRef->inputcollid ||
413  newagg->aggtranstype != existingRef->aggtranstype ||
414  newagg->aggstar != existingRef->aggstar ||
415  newagg->aggvariadic != existingRef->aggvariadic ||
416  newagg->aggkind != existingRef->aggkind ||
417  !equal(newagg->args, existingRef->args) ||
418  !equal(newagg->aggorder, existingRef->aggorder) ||
419  !equal(newagg->aggdistinct, existingRef->aggdistinct) ||
420  !equal(newagg->aggfilter, existingRef->aggfilter))
421  continue;
422 
423  /* if it's the same aggregate function then report exact match */
424  if (newagg->aggfnoid == existingRef->aggfnoid &&
425  newagg->aggtype == existingRef->aggtype &&
426  newagg->aggcollid == existingRef->aggcollid &&
427  equal(newagg->aggdirectargs, existingRef->aggdirectargs))
428  {
429  list_free(*same_input_transnos);
430  *same_input_transnos = NIL;
431  return aggno;
432  }
433 
434  /*
435  * Not identical, but it had the same inputs. If the final function
436  * permits sharing, return its transno to the caller, in case we can
437  * re-use its per-trans state. (If there's already sharing going on,
438  * we might report a transno more than once. find_compatible_trans is
439  * cheap enough that it's not worth spending cycles to avoid that.)
440  */
441  if (agginfo->shareable)
442  *same_input_transnos = lappend_int(*same_input_transnos,
443  agginfo->transno);
444  }
445 
446  return -1;
447 }
448 
449 /*
450  * find_compatible_trans - search for a previously initialized per-Trans
451  * struct
452  *
453  * Searches the list of transnos for a per-Trans struct with the same
454  * transition function and initial condition. (The inputs have already been
455  * verified to match.)
456  */
457 static int
458 find_compatible_trans(PlannerInfo *root, Aggref *newagg, bool shareable,
459  Oid aggtransfn, Oid aggtranstype,
460  int transtypeLen, bool transtypeByVal,
461  Oid aggcombinefn,
462  Oid aggserialfn, Oid aggdeserialfn,
463  Datum initValue, bool initValueIsNull,
464  List *transnos)
465 {
466  ListCell *lc;
467 
468  /* If this aggregate can't share transition states, give up */
469  if (!shareable)
470  return -1;
471 
472  foreach(lc, transnos)
473  {
474  int transno = lfirst_int(lc);
476  root->aggtransinfos,
477  transno);
478 
479  /*
480  * if the transfns or transition state types are not the same then the
481  * state can't be shared.
482  */
483  if (aggtransfn != pertrans->transfn_oid ||
484  aggtranstype != pertrans->aggtranstype)
485  continue;
486 
487  /*
488  * The serialization and deserialization functions must match, if
489  * present, as we're unable to share the trans state for aggregates
490  * which will serialize or deserialize into different formats.
491  * Remember that these will be InvalidOid if they're not required for
492  * this agg node.
493  */
494  if (aggserialfn != pertrans->serialfn_oid ||
495  aggdeserialfn != pertrans->deserialfn_oid)
496  continue;
497 
498  /*
499  * Combine function must also match. We only care about the combine
500  * function with partial aggregates, but it's too early in the
501  * planning to know if we will do partial aggregation, so be
502  * conservative.
503  */
504  if (aggcombinefn != pertrans->combinefn_oid)
505  continue;
506 
507  /*
508  * Check that the initial condition matches, too.
509  */
510  if (initValueIsNull && pertrans->initValueIsNull)
511  return transno;
512 
513  if (!initValueIsNull && !pertrans->initValueIsNull &&
514  datumIsEqual(initValue, pertrans->initValue,
515  transtypeByVal, transtypeLen))
516  return transno;
517  }
518  return -1;
519 }
520 
521 static Datum
522 GetAggInitVal(Datum textInitVal, Oid transtype)
523 {
524  Oid typinput,
525  typioparam;
526  char *strInitVal;
527  Datum initVal;
528 
529  getTypeInputInfo(transtype, &typinput, &typioparam);
530  strInitVal = TextDatumGetCString(textInitVal);
531  initVal = OidInputFunctionCall(typinput, strInitVal,
532  typioparam, -1);
533  pfree(strInitVal);
534  return initVal;
535 }
536 
537 
538 /*
539  * get_agg_clause_costs
540  * Process the PlannerInfo's 'aggtransinfos' and 'agginfos' lists
541  * accumulating the cost information about them.
542  *
543  * 'aggsplit' tells us the expected partial-aggregation mode, which affects
544  * the cost estimates.
545  *
546  * NOTE that the costs are ADDED to those already in *costs ... so the caller
547  * is responsible for zeroing the struct initially.
548  *
549  * For each AggTransInfo, we add the cost of an aggregate transition using
550  * either the transfn or combinefn depending on the 'aggsplit' value. We also
551  * account for the costs of any aggfilters and any serializations and
552  * deserializations of the transition state and also estimate the total space
553  * needed for the transition states as if each aggregate's state was stored in
554  * memory concurrently (as would be done in a HashAgg plan).
555  *
556  * For each AggInfo in the 'agginfos' list we add the cost of running the
557  * final function and the direct args, if any.
558  */
559 void
561 {
562  ListCell *lc;
563 
564  foreach(lc, root->aggtransinfos)
565  {
566  AggTransInfo *transinfo = lfirst_node(AggTransInfo, lc);
567 
568  /*
569  * Add the appropriate component function execution costs to
570  * appropriate totals.
571  */
572  if (DO_AGGSPLIT_COMBINE(aggsplit))
573  {
574  /* charge for combining previously aggregated states */
575  add_function_cost(root, transinfo->combinefn_oid, NULL,
576  &costs->transCost);
577  }
578  else
579  add_function_cost(root, transinfo->transfn_oid, NULL,
580  &costs->transCost);
581  if (DO_AGGSPLIT_DESERIALIZE(aggsplit) &&
582  OidIsValid(transinfo->deserialfn_oid))
583  add_function_cost(root, transinfo->deserialfn_oid, NULL,
584  &costs->transCost);
585  if (DO_AGGSPLIT_SERIALIZE(aggsplit) &&
586  OidIsValid(transinfo->serialfn_oid))
587  add_function_cost(root, transinfo->serialfn_oid, NULL,
588  &costs->finalCost);
589 
590  /*
591  * These costs are incurred only by the initial aggregate node, so we
592  * mustn't include them again at upper levels.
593  */
594  if (!DO_AGGSPLIT_COMBINE(aggsplit))
595  {
596  /* add the input expressions' cost to per-input-row costs */
597  QualCost argcosts;
598 
599  cost_qual_eval_node(&argcosts, (Node *) transinfo->args, root);
600  costs->transCost.startup += argcosts.startup;
601  costs->transCost.per_tuple += argcosts.per_tuple;
602 
603  /*
604  * Add any filter's cost to per-input-row costs.
605  *
606  * XXX Ideally we should reduce input expression costs according
607  * to filter selectivity, but it's not clear it's worth the
608  * trouble.
609  */
610  if (transinfo->aggfilter)
611  {
612  cost_qual_eval_node(&argcosts, (Node *) transinfo->aggfilter,
613  root);
614  costs->transCost.startup += argcosts.startup;
615  costs->transCost.per_tuple += argcosts.per_tuple;
616  }
617  }
618 
619  /*
620  * If the transition type is pass-by-value then it doesn't add
621  * anything to the required size of the hashtable. If it is
622  * pass-by-reference then we have to add the estimated size of the
623  * value itself, plus palloc overhead.
624  */
625  if (!transinfo->transtypeByVal)
626  {
627  int32 avgwidth;
628 
629  /* Use average width if aggregate definition gave one */
630  if (transinfo->aggtransspace > 0)
631  avgwidth = transinfo->aggtransspace;
632  else if (transinfo->transfn_oid == F_ARRAY_APPEND)
633  {
634  /*
635  * If the transition function is array_append(), it'll use an
636  * expanded array as transvalue, which will occupy at least
637  * ALLOCSET_SMALL_INITSIZE and possibly more. Use that as the
638  * estimate for lack of a better idea.
639  */
640  avgwidth = ALLOCSET_SMALL_INITSIZE;
641  }
642  else
643  {
644  avgwidth = get_typavgwidth(transinfo->aggtranstype, transinfo->aggtranstypmod);
645  }
646 
647  avgwidth = MAXALIGN(avgwidth);
648  costs->transitionSpace += avgwidth + 2 * sizeof(void *);
649  }
650  else if (transinfo->aggtranstype == INTERNALOID)
651  {
652  /*
653  * INTERNAL transition type is a special case: although INTERNAL
654  * is pass-by-value, it's almost certainly being used as a pointer
655  * to some large data structure. The aggregate definition can
656  * provide an estimate of the size. If it doesn't, then we assume
657  * ALLOCSET_DEFAULT_INITSIZE, which is a good guess if the data is
658  * being kept in a private memory context, as is done by
659  * array_agg() for instance.
660  */
661  if (transinfo->aggtransspace > 0)
662  costs->transitionSpace += transinfo->aggtransspace;
663  else
665  }
666  }
667 
668  foreach(lc, root->agginfos)
669  {
670  AggInfo *agginfo = lfirst_node(AggInfo, lc);
671  Aggref *aggref = linitial_node(Aggref, agginfo->aggrefs);
672 
673  /*
674  * Add the appropriate component function execution costs to
675  * appropriate totals.
676  */
677  if (!DO_AGGSPLIT_SKIPFINAL(aggsplit) &&
678  OidIsValid(agginfo->finalfn_oid))
679  add_function_cost(root, agginfo->finalfn_oid, NULL,
680  &costs->finalCost);
681 
682  /*
683  * If there are direct arguments, treat their evaluation cost like the
684  * cost of the finalfn.
685  */
686  if (aggref->aggdirectargs)
687  {
688  QualCost argcosts;
689 
690  cost_qual_eval_node(&argcosts, (Node *) aggref->aggdirectargs,
691  root);
692  costs->finalCost.startup += argcosts.startup;
693  costs->finalCost.per_tuple += argcosts.per_tuple;
694  }
695  }
696 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
signed short int16
Definition: c.h:493
#define MAXALIGN(LEN)
Definition: c.h:811
signed int int32
Definition: c.h:494
#define Assert(condition)
Definition: c.h:858
#define OidIsValid(objectId)
Definition: c.h:775
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:538
void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
Definition: costsize.c:4666
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:223
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
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:1754
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
static int initValue(long lng_val)
Definition: informix.c:683
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lappend_int(List *list, int datum)
Definition: list.c:357
void list_free(List *list)
Definition: list.c:1546
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2251
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2874
int32 get_typavgwidth(Oid typid, int32 typmod)
Definition: lsyscache.c:2578
void pfree(void *pointer)
Definition: mcxt.c:1520
#define ALLOCSET_SMALL_INITSIZE
Definition: memutils.h:168
#define ALLOCSET_DEFAULT_INITSIZE
Definition: memutils.h:158
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:298
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:385
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:387
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:384
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:386
AggSplit
Definition: nodes.h:374
#define makeNode(_type_)
Definition: nodes.h:155
Oid resolve_aggregate_transtype(Oid aggfuncid, Oid aggtranstype, Oid *inputTypes, int numArguments)
Definition: parse_agg.c:1934
bool agg_args_support_sendreceive(Aggref *aggref)
Definition: parse_agg.c:1970
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1908
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:2072
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:344
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition: prepagg.c:522
void get_agg_clause_costs(PlannerInfo *root, AggSplit aggsplit, AggClauseCosts *costs)
Definition: prepagg.c:560
static int find_compatible_agg(PlannerInfo *root, Aggref *newagg, List **same_input_transnos)
Definition: prepagg.c:380
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:458
static void preprocess_aggref(Aggref *aggref, PlannerInfo *root)
Definition: prepagg.c:116
void preprocess_aggrefs(PlannerInfo *root, Node *clause)
Definition: prepagg.c:110
tree ctl root
Definition: radixtree.h:1884
QualCost finalCost
Definition: pathnodes.h:61
Size transitionSpace
Definition: pathnodes.h:62
QualCost transCost
Definition: pathnodes.h:60
bool shareable
Definition: pathnodes.h:3372
List * aggrefs
Definition: pathnodes.h:3363
int transno
Definition: pathnodes.h:3366
Oid finalfn_oid
Definition: pathnodes.h:3375
List * args
Definition: pathnodes.h:3392
int32 aggtransspace
Definition: pathnodes.h:3416
bool transtypeByVal
Definition: pathnodes.h:3413
Oid combinefn_oid
Definition: pathnodes.h:3405
Oid deserialfn_oid
Definition: pathnodes.h:3402
int32 aggtranstypmod
Definition: pathnodes.h:3411
int transtypeLen
Definition: pathnodes.h:3412
bool initValueIsNull
Definition: pathnodes.h:3420
Oid serialfn_oid
Definition: pathnodes.h:3399
Oid aggtranstype
Definition: pathnodes.h:3408
Expr * aggfilter
Definition: pathnodes.h:3393
Oid aggfnoid
Definition: primnodes.h:444
List * aggdistinct
Definition: primnodes.h:474
List * aggdirectargs
Definition: primnodes.h:465
List * args
Definition: primnodes.h:468
Expr * aggfilter
Definition: primnodes.h:477
List * aggorder
Definition: primnodes.h:471
Definition: pg_list.h:54
Definition: nodes.h:129
Cost per_tuple
Definition: pathnodes.h:48
Cost startup
Definition: pathnodes.h:47
Expr * expr
Definition: primnodes.h:2162
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479