PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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-2025, 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"
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
55static int find_compatible_agg(PlannerInfo *root, Aggref *newagg,
56 List **same_input_transnos);
57static 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);
65static 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 */
109void
111{
112 (void) preprocess_aggrefs_walker(clause, root);
113}
114
115static 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
343static 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}
364
365
366/*
367 * find_compatible_agg - search for a previously initialized per-Agg struct
368 *
369 * Searches the previously looked at aggregates to find one which is compatible
370 * with this one, with the same input parameters. If no compatible aggregate
371 * can be found, returns -1.
372 *
373 * As a side-effect, this also collects a list of existing, shareable per-Trans
374 * structs with matching inputs. If no identical Aggref is found, the list is
375 * passed later to find_compatible_trans, to see if we can at least reuse
376 * the state value of another aggregate.
377 */
378static int
380 List **same_input_transnos)
381{
382 ListCell *lc;
383 int aggno;
384
385 *same_input_transnos = NIL;
386
387 /* we mustn't reuse the aggref if it contains volatile function calls */
388 if (contain_volatile_functions((Node *) newagg))
389 return -1;
390
391 /*
392 * Search through the list of already seen aggregates. If we find an
393 * existing identical aggregate call, then we can re-use that one. While
394 * searching, we'll also collect a list of Aggrefs with the same input
395 * parameters. If no matching Aggref is found, the caller can potentially
396 * still re-use the transition state of one of them. (At this stage we
397 * just compare the parsetrees; whether different aggregates share the
398 * same transition function will be checked later.)
399 */
400 aggno = -1;
401 foreach(lc, root->agginfos)
402 {
403 AggInfo *agginfo = lfirst_node(AggInfo, lc);
404 Aggref *existingRef;
405
406 aggno++;
407
408 existingRef = linitial_node(Aggref, agginfo->aggrefs);
409
410 /* all of the following must be the same or it's no match */
411 if (newagg->inputcollid != existingRef->inputcollid ||
412 newagg->aggtranstype != existingRef->aggtranstype ||
413 newagg->aggstar != existingRef->aggstar ||
414 newagg->aggvariadic != existingRef->aggvariadic ||
415 newagg->aggkind != existingRef->aggkind ||
416 !equal(newagg->args, existingRef->args) ||
417 !equal(newagg->aggorder, existingRef->aggorder) ||
418 !equal(newagg->aggdistinct, existingRef->aggdistinct) ||
419 !equal(newagg->aggfilter, existingRef->aggfilter))
420 continue;
421
422 /* if it's the same aggregate function then report exact match */
423 if (newagg->aggfnoid == existingRef->aggfnoid &&
424 newagg->aggtype == existingRef->aggtype &&
425 newagg->aggcollid == existingRef->aggcollid &&
426 equal(newagg->aggdirectargs, existingRef->aggdirectargs))
427 {
428 list_free(*same_input_transnos);
429 *same_input_transnos = NIL;
430 return aggno;
431 }
432
433 /*
434 * Not identical, but it had the same inputs. If the final function
435 * permits sharing, return its transno to the caller, in case we can
436 * re-use its per-trans state. (If there's already sharing going on,
437 * we might report a transno more than once. find_compatible_trans is
438 * cheap enough that it's not worth spending cycles to avoid that.)
439 */
440 if (agginfo->shareable)
441 *same_input_transnos = lappend_int(*same_input_transnos,
442 agginfo->transno);
443 }
444
445 return -1;
446}
447
448/*
449 * find_compatible_trans - search for a previously initialized per-Trans
450 * struct
451 *
452 * Searches the list of transnos for a per-Trans struct with the same
453 * transition function and initial condition. (The inputs have already been
454 * verified to match.)
455 */
456static int
458 Oid aggtransfn, Oid aggtranstype,
459 int transtypeLen, bool transtypeByVal,
460 Oid aggcombinefn,
461 Oid aggserialfn, Oid aggdeserialfn,
462 Datum initValue, bool initValueIsNull,
463 List *transnos)
464{
465 ListCell *lc;
466
467 /* If this aggregate can't share transition states, give up */
468 if (!shareable)
469 return -1;
470
471 foreach(lc, transnos)
472 {
473 int transno = lfirst_int(lc);
475 root->aggtransinfos,
476 transno);
477
478 /*
479 * if the transfns or transition state types are not the same then the
480 * state can't be shared.
481 */
482 if (aggtransfn != pertrans->transfn_oid ||
483 aggtranstype != pertrans->aggtranstype)
484 continue;
485
486 /*
487 * The serialization and deserialization functions must match, if
488 * present, as we're unable to share the trans state for aggregates
489 * which will serialize or deserialize into different formats.
490 * Remember that these will be InvalidOid if they're not required for
491 * this agg node.
492 */
493 if (aggserialfn != pertrans->serialfn_oid ||
494 aggdeserialfn != pertrans->deserialfn_oid)
495 continue;
496
497 /*
498 * Combine function must also match. We only care about the combine
499 * function with partial aggregates, but it's too early in the
500 * planning to know if we will do partial aggregation, so be
501 * conservative.
502 */
503 if (aggcombinefn != pertrans->combinefn_oid)
504 continue;
505
506 /*
507 * Check that the initial condition matches, too.
508 */
509 if (initValueIsNull && pertrans->initValueIsNull)
510 return transno;
511
512 if (!initValueIsNull && !pertrans->initValueIsNull &&
513 datumIsEqual(initValue, pertrans->initValue,
514 transtypeByVal, transtypeLen))
515 return transno;
516 }
517 return -1;
518}
519
520static Datum
521GetAggInitVal(Datum textInitVal, Oid transtype)
522{
523 Oid typinput,
524 typioparam;
525 char *strInitVal;
526 Datum initVal;
527
528 getTypeInputInfo(transtype, &typinput, &typioparam);
529 strInitVal = TextDatumGetCString(textInitVal);
530 initVal = OidInputFunctionCall(typinput, strInitVal,
531 typioparam, -1);
532 pfree(strInitVal);
533 return initVal;
534}
535
536
537/*
538 * get_agg_clause_costs
539 * Process the PlannerInfo's 'aggtransinfos' and 'agginfos' lists
540 * accumulating the cost information about them.
541 *
542 * 'aggsplit' tells us the expected partial-aggregation mode, which affects
543 * the cost estimates.
544 *
545 * NOTE that the costs are ADDED to those already in *costs ... so the caller
546 * is responsible for zeroing the struct initially.
547 *
548 * For each AggTransInfo, we add the cost of an aggregate transition using
549 * either the transfn or combinefn depending on the 'aggsplit' value. We also
550 * account for the costs of any aggfilters and any serializations and
551 * deserializations of the transition state and also estimate the total space
552 * needed for the transition states as if each aggregate's state was stored in
553 * memory concurrently (as would be done in a HashAgg plan).
554 *
555 * For each AggInfo in the 'agginfos' list we add the cost of running the
556 * final function and the direct args, if any.
557 */
558void
560{
561 ListCell *lc;
562
563 foreach(lc, root->aggtransinfos)
564 {
565 AggTransInfo *transinfo = lfirst_node(AggTransInfo, lc);
566
567 /*
568 * Add the appropriate component function execution costs to
569 * appropriate totals.
570 */
571 if (DO_AGGSPLIT_COMBINE(aggsplit))
572 {
573 /* charge for combining previously aggregated states */
574 add_function_cost(root, transinfo->combinefn_oid, NULL,
575 &costs->transCost);
576 }
577 else
578 add_function_cost(root, transinfo->transfn_oid, NULL,
579 &costs->transCost);
580 if (DO_AGGSPLIT_DESERIALIZE(aggsplit) &&
581 OidIsValid(transinfo->deserialfn_oid))
582 add_function_cost(root, transinfo->deserialfn_oid, NULL,
583 &costs->transCost);
584 if (DO_AGGSPLIT_SERIALIZE(aggsplit) &&
585 OidIsValid(transinfo->serialfn_oid))
586 add_function_cost(root, transinfo->serialfn_oid, NULL,
587 &costs->finalCost);
588
589 /*
590 * These costs are incurred only by the initial aggregate node, so we
591 * mustn't include them again at upper levels.
592 */
593 if (!DO_AGGSPLIT_COMBINE(aggsplit))
594 {
595 /* add the input expressions' cost to per-input-row costs */
596 QualCost argcosts;
597
598 cost_qual_eval_node(&argcosts, (Node *) transinfo->args, root);
599 costs->transCost.startup += argcosts.startup;
600 costs->transCost.per_tuple += argcosts.per_tuple;
601
602 /*
603 * Add any filter's cost to per-input-row costs.
604 *
605 * XXX Ideally we should reduce input expression costs according
606 * to filter selectivity, but it's not clear it's worth the
607 * trouble.
608 */
609 if (transinfo->aggfilter)
610 {
611 cost_qual_eval_node(&argcosts, (Node *) transinfo->aggfilter,
612 root);
613 costs->transCost.startup += argcosts.startup;
614 costs->transCost.per_tuple += argcosts.per_tuple;
615 }
616 }
617
618 /*
619 * If the transition type is pass-by-value then it doesn't add
620 * anything to the required size of the hashtable. If it is
621 * pass-by-reference then we have to add the estimated size of the
622 * value itself, plus palloc overhead.
623 */
624 if (!transinfo->transtypeByVal)
625 {
626 int32 avgwidth;
627
628 /* Use average width if aggregate definition gave one */
629 if (transinfo->aggtransspace > 0)
630 avgwidth = transinfo->aggtransspace;
631 else if (transinfo->transfn_oid == F_ARRAY_APPEND)
632 {
633 /*
634 * If the transition function is array_append(), it'll use an
635 * expanded array as transvalue, which will occupy at least
636 * ALLOCSET_SMALL_INITSIZE and possibly more. Use that as the
637 * estimate for lack of a better idea.
638 */
639 avgwidth = ALLOCSET_SMALL_INITSIZE;
640 }
641 else
642 {
643 avgwidth = get_typavgwidth(transinfo->aggtranstype, transinfo->aggtranstypmod);
644 }
645
646 avgwidth = MAXALIGN(avgwidth);
647 costs->transitionSpace += avgwidth + 2 * sizeof(void *);
648 }
649 else if (transinfo->aggtranstype == INTERNALOID)
650 {
651 /*
652 * INTERNAL transition type is a special case: although INTERNAL
653 * is pass-by-value, it's almost certainly being used as a pointer
654 * to some large data structure. The aggregate definition can
655 * provide an estimate of the size. If it doesn't, then we assume
656 * ALLOCSET_DEFAULT_INITSIZE, which is a good guess if the data is
657 * being kept in a private memory context, as is done by
658 * array_agg() for instance.
659 */
660 if (transinfo->aggtransspace > 0)
661 costs->transitionSpace += transinfo->aggtransspace;
662 else
664 }
665 }
666
667 foreach(lc, root->agginfos)
668 {
669 AggInfo *agginfo = lfirst_node(AggInfo, lc);
670 Aggref *aggref = linitial_node(Aggref, agginfo->aggrefs);
671
672 /*
673 * Add the appropriate component function execution costs to
674 * appropriate totals.
675 */
676 if (!DO_AGGSPLIT_SKIPFINAL(aggsplit) &&
677 OidIsValid(agginfo->finalfn_oid))
678 add_function_cost(root, agginfo->finalfn_oid, NULL,
679 &costs->finalCost);
680
681 /*
682 * If there are direct arguments, treat their evaluation cost like the
683 * cost of the finalfn.
684 */
685 if (aggref->aggdirectargs)
686 {
687 QualCost argcosts;
688
689 cost_qual_eval_node(&argcosts, (Node *) aggref->aggdirectargs,
690 root);
691 costs->finalCost.startup += argcosts.startup;
692 costs->finalCost.per_tuple += argcosts.per_tuple;
693 }
694 }
695}
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define MAXALIGN(LEN)
Definition: c.h:782
int16_t int16
Definition: c.h:497
int32_t int32
Definition: c.h:498
#define OidIsValid(objectId)
Definition: c.h:746
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:539
void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
Definition: costsize.c:4767
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:226
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
Assert(PointerIsAligned(start, uint64))
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
static int initValue(long lng_val)
Definition: informix.c:702
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:2391
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:3014
int32 get_typavgwidth(Oid typid, int32 typmod)
Definition: lsyscache.c:2718
void pfree(void *pointer)
Definition: mcxt.c:2147
#define ALLOCSET_SMALL_INITSIZE
Definition: memutils.h:188
#define ALLOCSET_DEFAULT_INITSIZE
Definition: memutils.h:178
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:301
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:392
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:394
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:391
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:393
AggSplit
Definition: nodes.h:381
#define makeNode(_type_)
Definition: nodes.h:161
Oid resolve_aggregate_transtype(Oid aggfuncid, Oid aggtranstype, Oid *inputTypes, int numArguments)
Definition: parse_agg.c:2023
bool agg_args_support_sendreceive(Aggref *aggref)
Definition: parse_agg.c:2059
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1997
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:2111
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
unsigned int Oid
Definition: postgres_ext.h:30
static bool preprocess_aggrefs_walker(Node *node, PlannerInfo *root)
Definition: prepagg.c:344
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition: prepagg.c:521
void get_agg_clause_costs(PlannerInfo *root, AggSplit aggsplit, AggClauseCosts *costs)
Definition: prepagg.c:559
static int find_compatible_agg(PlannerInfo *root, Aggref *newagg, List **same_input_transnos)
Definition: prepagg.c:379
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:457
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:1857
QualCost finalCost
Definition: pathnodes.h:61
Size transitionSpace
Definition: pathnodes.h:62
QualCost transCost
Definition: pathnodes.h:60
bool shareable
Definition: pathnodes.h:3521
List * aggrefs
Definition: pathnodes.h:3512
int transno
Definition: pathnodes.h:3515
Oid finalfn_oid
Definition: pathnodes.h:3524
List * args
Definition: pathnodes.h:3541
int32 aggtransspace
Definition: pathnodes.h:3565
bool transtypeByVal
Definition: pathnodes.h:3562
Oid combinefn_oid
Definition: pathnodes.h:3554
Oid deserialfn_oid
Definition: pathnodes.h:3551
int32 aggtranstypmod
Definition: pathnodes.h:3560
int transtypeLen
Definition: pathnodes.h:3561
bool initValueIsNull
Definition: pathnodes.h:3569
Oid serialfn_oid
Definition: pathnodes.h:3548
Oid aggtranstype
Definition: pathnodes.h:3557
Expr * aggfilter
Definition: pathnodes.h:3542
Oid aggfnoid
Definition: primnodes.h:461
List * aggdistinct
Definition: primnodes.h:491
List * aggdirectargs
Definition: primnodes.h:482
List * args
Definition: primnodes.h:485
Expr * aggfilter
Definition: primnodes.h:494
List * aggorder
Definition: primnodes.h:488
Definition: pg_list.h:54
Definition: nodes.h:135
Cost per_tuple
Definition: pathnodes.h:48
Cost startup
Definition: pathnodes.h:47
Expr * expr
Definition: primnodes.h:2219
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600