PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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/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 379 of file prepagg.c.

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}
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:537
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
List * lappend_int(List *list, int datum)
Definition: list.c:357
void list_free(List *list)
Definition: list.c:1546
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define linitial_node(type, l)
Definition: pg_list.h:181
#define NIL
Definition: pg_list.h:68
tree ctl root
Definition: radixtree.h:1857
bool shareable
Definition: pathnodes.h:3396
List * aggrefs
Definition: pathnodes.h:3387
int transno
Definition: pathnodes.h:3390
Oid aggfnoid
Definition: primnodes.h:460
List * aggdistinct
Definition: primnodes.h:490
List * aggdirectargs
Definition: primnodes.h:481
List * args
Definition: primnodes.h:484
Expr * aggfilter
Definition: primnodes.h:493
List * aggorder
Definition: primnodes.h:487
Definition: nodes.h:129

References Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggorder, AggInfo::aggrefs, Aggref::args, contain_volatile_functions(), equal(), lappend_int(), lfirst_node, linitial_node, list_free(), NIL, root, AggInfo::shareable, and AggInfo::transno.

Referenced by preprocess_aggref().

◆ 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 457 of file prepagg.c.

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}
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:223
static int initValue(long lng_val)
Definition: informix.c:702
#define lfirst_int(lc)
Definition: pg_list.h:173
#define list_nth_node(type, list, n)
Definition: pg_list.h:327
Oid combinefn_oid
Definition: pathnodes.h:3429
Oid deserialfn_oid
Definition: pathnodes.h:3426
bool initValueIsNull
Definition: pathnodes.h:3444
Oid serialfn_oid
Definition: pathnodes.h:3423
Oid aggtranstype
Definition: pathnodes.h:3432

References AggTransInfo::aggtranstype, AggTransInfo::combinefn_oid, datumIsEqual(), AggTransInfo::deserialfn_oid, initValue(), AggTransInfo::initValueIsNull, lfirst_int, list_nth_node, root, AggTransInfo::serialfn_oid, and AggTransInfo::transfn_oid.

Referenced by preprocess_aggref().

◆ get_agg_clause_costs()

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

Definition at line 559 of file prepagg.c.

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 MAXALIGN(LEN)
Definition: c.h:768
int32_t int32
Definition: c.h:484
#define OidIsValid(objectId)
Definition: c.h:732
void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
Definition: costsize.c:4758
int32 get_typavgwidth(Oid typid, int32 typmod)
Definition: lsyscache.c:2578
#define ALLOCSET_SMALL_INITSIZE
Definition: memutils.h:168
#define ALLOCSET_DEFAULT_INITSIZE
Definition: memutils.h:158
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:386
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:388
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:385
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:387
void add_function_cost(PlannerInfo *root, Oid funcid, Node *node, QualCost *cost)
Definition: plancat.c:2109
QualCost finalCost
Definition: pathnodes.h:61
Size transitionSpace
Definition: pathnodes.h:62
QualCost transCost
Definition: pathnodes.h:60
Oid finalfn_oid
Definition: pathnodes.h:3399
List * args
Definition: pathnodes.h:3416
int32 aggtransspace
Definition: pathnodes.h:3440
bool transtypeByVal
Definition: pathnodes.h:3437
int32 aggtranstypmod
Definition: pathnodes.h:3435
Expr * aggfilter
Definition: pathnodes.h:3417
Cost per_tuple
Definition: pathnodes.h:48
Cost startup
Definition: pathnodes.h:47

References add_function_cost(), Aggref::aggdirectargs, AggTransInfo::aggfilter, AggInfo::aggrefs, 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_node, linitial_node, MAXALIGN, OidIsValid, QualCost::per_tuple, root, 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().

◆ GetAggInitVal()

static Datum GetAggInitVal ( Datum  textInitVal,
Oid  transtype 
)
static

Definition at line 521 of file prepagg.c.

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}
#define TextDatumGetCString(d)
Definition: builtins.h:98
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1754
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2874
void pfree(void *pointer)
Definition: mcxt.c:1521
uintptr_t Datum
Definition: postgres.h:69
unsigned int Oid
Definition: postgres_ext.h:32

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

Referenced by preprocess_aggref().

◆ preprocess_aggref()

static void preprocess_aggref ( Aggref aggref,
PlannerInfo root 
)
static

Definition at line 116 of file prepagg.c.

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}
#define Assert(condition)
Definition: c.h:815
int16_t int16
Definition: c.h:483
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
List * lappend(List *list, void *datum)
Definition: list.c:339
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2251
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:301
#define makeNode(_type_)
Definition: nodes.h:155
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
static int list_length(const List *l)
Definition: pg_list.h:152
#define list_make1(x1)
Definition: pg_list.h:212
#define linitial(l)
Definition: pg_list.h:178
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition: prepagg.c:521
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
int transtypeLen
Definition: pathnodes.h:3436
Definition: pg_list.h:54
Expr * expr
Definition: primnodes.h:2245
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

References agg_args_support_sendreceive(), Aggref::aggdistinct, AggTransInfo::aggfilter, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggorder, AggInfo::aggrefs, AggTransInfo::aggtransspace, AggTransInfo::aggtranstype, AggTransInfo::aggtranstypmod, AggTransInfo::args, Aggref::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, HeapTupleIsValid, initValue(), AggTransInfo::initValueIsNull, lappend(), linitial, list_length(), list_make1, list_nth_node, makeNode, NIL, ObjectIdGetDatum(), OidIsValid, ReleaseSysCache(), resolve_aggregate_transtype(), root, SearchSysCache1(), AggTransInfo::serialfn_oid, AggInfo::shareable, SysCacheGetAttr(), AggTransInfo::transfn_oid, AggInfo::transno, AggTransInfo::transtypeByVal, and AggTransInfo::transtypeLen.

Referenced by preprocess_aggrefs_walker().

◆ preprocess_aggrefs()

void preprocess_aggrefs ( PlannerInfo root,
Node clause 
)

Definition at line 110 of file prepagg.c.

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

References preprocess_aggrefs_walker(), and root.

Referenced by grouping_planner().

◆ preprocess_aggrefs_walker()

static bool preprocess_aggrefs_walker ( Node node,
PlannerInfo root 
)
static

Definition at line 344 of file prepagg.c.

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}
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
static void preprocess_aggref(Aggref *aggref, PlannerInfo *root)
Definition: prepagg.c:116

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

Referenced by preprocess_aggrefs(), and preprocess_aggrefs_walker().