PostgreSQL Source Code git master
planagg.c File Reference
Include dependency graph for planagg.c:

Go to the source code of this file.

Functions

static bool can_minmax_aggs (PlannerInfo *root, List **context)
 
static bool build_minmax_path (PlannerInfo *root, MinMaxAggInfo *mminfo, Oid eqop, Oid sortop, bool reverse_sort, bool nulls_first)
 
static void minmax_qp_callback (PlannerInfo *root, void *extra)
 
static Oid fetch_agg_sort_op (Oid aggfnoid)
 
void preprocess_minmax_aggregates (PlannerInfo *root)
 

Function Documentation

◆ build_minmax_path()

static bool build_minmax_path ( PlannerInfo root,
MinMaxAggInfo mminfo,
Oid  eqop,
Oid  sortop,
bool  reverse_sort,
bool  nulls_first 
)
static

Definition at line 317 of file planagg.c.

319{
320 PlannerInfo *subroot;
321 Query *parse;
322 TargetEntry *tle;
323 List *tlist;
324 NullTest *ntest;
325 SortGroupClause *sortcl;
326 RelOptInfo *final_rel;
327 Path *sorted_path;
328 Cost path_cost;
329 double path_fraction;
330
331 /*
332 * We are going to construct what is effectively a sub-SELECT query, so
333 * clone the current query level's state and adjust it to make it look
334 * like a subquery. Any outer references will now be one level higher
335 * than before. (This means that when we are done, there will be no Vars
336 * of level 1, which is why the subquery can become an initplan.)
337 */
338 subroot = (PlannerInfo *) palloc(sizeof(PlannerInfo));
339 memcpy(subroot, root, sizeof(PlannerInfo));
340 subroot->query_level++;
341 subroot->parent_root = root;
342 /* reset subplan-related stuff */
343 subroot->plan_params = NIL;
344 subroot->outer_params = NULL;
345 subroot->init_plans = NIL;
346 subroot->agginfos = NIL;
347 subroot->aggtransinfos = NIL;
348
349 subroot->parse = parse = copyObject(root->parse);
351
352 /* append_rel_list might contain outer Vars? */
353 subroot->append_rel_list = copyObject(root->append_rel_list);
354 IncrementVarSublevelsUp((Node *) subroot->append_rel_list, 1, 1);
355 /* There shouldn't be any OJ info to translate, as yet */
356 Assert(subroot->join_info_list == NIL);
357 /* and we haven't made equivalence classes, either */
358 Assert(subroot->eq_classes == NIL);
359 /* and we haven't created PlaceHolderInfos, either */
360 Assert(subroot->placeholder_list == NIL);
361
362 /*----------
363 * Generate modified query of the form
364 * (SELECT col FROM tab
365 * WHERE col IS NOT NULL AND existing-quals
366 * ORDER BY col ASC/DESC
367 * LIMIT 1)
368 *----------
369 */
370 /* single tlist entry that is the aggregate target */
371 tle = makeTargetEntry(copyObject(mminfo->target),
372 (AttrNumber) 1,
373 pstrdup("agg_target"),
374 false);
375 tlist = list_make1(tle);
376 subroot->processed_tlist = parse->targetList = tlist;
377
378 /* No HAVING, no DISTINCT, no aggregates anymore */
379 parse->havingQual = NULL;
380 subroot->hasHavingQual = false;
381 parse->distinctClause = NIL;
382 parse->hasDistinctOn = false;
383 parse->hasAggs = false;
384
385 /* Build "target IS NOT NULL" expression */
386 ntest = makeNode(NullTest);
387 ntest->nulltesttype = IS_NOT_NULL;
388 ntest->arg = copyObject(mminfo->target);
389 /* we checked it wasn't a rowtype in can_minmax_aggs */
390 ntest->argisrow = false;
391 ntest->location = -1;
392
393 /* User might have had that in WHERE already */
394 if (!list_member((List *) parse->jointree->quals, ntest))
395 parse->jointree->quals = (Node *)
396 lcons(ntest, (List *) parse->jointree->quals);
397
398 /* Build suitable ORDER BY clause */
399 sortcl = makeNode(SortGroupClause);
400 sortcl->tleSortGroupRef = assignSortGroupRef(tle, subroot->processed_tlist);
401 sortcl->eqop = eqop;
402 sortcl->sortop = sortop;
403 sortcl->reverse_sort = reverse_sort;
404 sortcl->nulls_first = nulls_first;
405 sortcl->hashable = false; /* no need to make this accurate */
406 parse->sortClause = list_make1(sortcl);
407
408 /* set up expressions for LIMIT 1 */
409 parse->limitOffset = NULL;
410 parse->limitCount = (Node *) makeConst(INT8OID, -1, InvalidOid,
411 sizeof(int64),
412 Int64GetDatum(1), false,
414
415 /*
416 * Generate the best paths for this query, telling query_planner that we
417 * have LIMIT 1.
418 */
419 subroot->tuple_fraction = 1.0;
420 subroot->limit_tuples = 1.0;
421
422 final_rel = query_planner(subroot, minmax_qp_callback, NULL);
423
424 /*
425 * Since we didn't go through subquery_planner() to handle the subquery,
426 * we have to do some of the same cleanup it would do, in particular cope
427 * with params and initplans used within this subquery. (This won't
428 * matter if we end up not using the subplan.)
429 */
431 SS_charge_for_initplans(subroot, final_rel);
432
433 /*
434 * Get the best presorted path, that being the one that's cheapest for
435 * fetching just one row. If there's no such path, fail.
436 */
437 if (final_rel->rows > 1.0)
438 path_fraction = 1.0 / final_rel->rows;
439 else
440 path_fraction = 1.0;
441
442 sorted_path =
444 subroot->query_pathkeys,
445 NULL,
446 path_fraction);
447 if (!sorted_path)
448 return false;
449
450 /*
451 * The path might not return exactly what we want, so fix that. (We
452 * assume that this won't change any conclusions about which was the
453 * cheapest path.)
454 */
455 sorted_path = apply_projection_to_path(subroot, final_rel, sorted_path,
456 create_pathtarget(subroot,
457 subroot->processed_tlist));
458
459 /*
460 * Determine cost to get just the first row of the presorted path.
461 *
462 * Note: cost calculation here should match
463 * compare_fractional_path_costs().
464 */
465 path_cost = sorted_path->startup_cost +
466 path_fraction * (sorted_path->total_cost - sorted_path->startup_cost);
467
468 /* Save state for further processing */
469 mminfo->subroot = subroot;
470 mminfo->path = sorted_path;
471 mminfo->pathcost = path_cost;
472
473 return true;
474}
int16 AttrNumber
Definition: attnum.h:21
#define Assert(condition)
Definition: c.h:815
int64_t int64
Definition: c.h:485
#define FLOAT8PASSBYVAL
Definition: c.h:592
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
List * lcons(void *datum, List *list)
Definition: list.c:495
bool list_member(const List *list, const void *datum)
Definition: list.c:661
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:242
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:303
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void * palloc(Size size)
Definition: mcxt.c:1317
#define copyObject(obj)
Definition: nodes.h:224
double Cost
Definition: nodes.h:251
#define makeNode(_type_)
Definition: nodes.h:155
Index assignSortGroupRef(TargetEntry *tle, List *tlist)
Path * get_cheapest_fractional_path_for_pathkeys(List *paths, List *pathkeys, Relids required_outer, double fraction)
Definition: pathkeys.c:666
Path * apply_projection_to_path(PlannerInfo *root, RelOptInfo *rel, Path *path, PathTarget *target)
Definition: pathnode.c:2873
#define NIL
Definition: pg_list.h:68
#define list_make1(x1)
Definition: pg_list.h:212
static void minmax_qp_callback(PlannerInfo *root, void *extra)
Definition: planagg.c:480
RelOptInfo * query_planner(PlannerInfo *root, query_pathkeys_callback qp_callback, void *qp_extra)
Definition: planmain.c:54
#define InvalidOid
Definition: postgres_ext.h:37
@ IS_NOT_NULL
Definition: primnodes.h:1983
tree ctl root
Definition: radixtree.h:1857
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:849
Definition: pg_list.h:54
Expr * target
Definition: pathnodes.h:3129
Definition: nodes.h:129
NullTestType nulltesttype
Definition: primnodes.h:1990
ParseLoc location
Definition: primnodes.h:1993
Expr * arg
Definition: primnodes.h:1989
Cost startup_cost
Definition: pathnodes.h:1673
Cost total_cost
Definition: pathnodes.h:1674
List * aggtransinfos
Definition: pathnodes.h:524
List * processed_tlist
Definition: pathnodes.h:462
List * init_plans
Definition: pathnodes.h:299
bool hasHavingQual
Definition: pathnodes.h:502
Bitmapset * outer_params
Definition: pathnodes.h:221
Index query_level
Definition: pathnodes.h:208
List * append_rel_list
Definition: pathnodes.h:365
List * placeholder_list
Definition: pathnodes.h:374
List * eq_classes
Definition: pathnodes.h:314
List * agginfos
Definition: pathnodes.h:522
List * plan_params
Definition: pathnodes.h:220
Query * parse
Definition: pathnodes.h:202
Cardinality limit_tuples
Definition: pathnodes.h:489
List * query_pathkeys
Definition: pathnodes.h:385
Selectivity tuple_fraction
Definition: pathnodes.h:487
List * join_info_list
Definition: pathnodes.h:340
List * pathlist
Definition: pathnodes.h:898
Cardinality rows
Definition: pathnodes.h:877
Index tleSortGroupRef
Definition: parsenodes.h:1447
void SS_identify_outer_params(PlannerInfo *root)
Definition: subselect.c:2104
void SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel)
Definition: subselect.c:2168
#define create_pathtarget(root, tlist)
Definition: tlist.h:53

References PlannerInfo::agginfos, PlannerInfo::aggtransinfos, PlannerInfo::append_rel_list, apply_projection_to_path(), NullTest::arg, Assert, assignSortGroupRef(), copyObject, create_pathtarget, PlannerInfo::eq_classes, SortGroupClause::eqop, FLOAT8PASSBYVAL, get_cheapest_fractional_path_for_pathkeys(), PlannerInfo::hasHavingQual, IncrementVarSublevelsUp(), PlannerInfo::init_plans, Int64GetDatum(), InvalidOid, IS_NOT_NULL, PlannerInfo::join_info_list, lcons(), PlannerInfo::limit_tuples, list_make1, list_member(), NullTest::location, makeConst(), makeNode, makeTargetEntry(), minmax_qp_callback(), NIL, SortGroupClause::nulls_first, NullTest::nulltesttype, PlannerInfo::outer_params, palloc(), parse(), PlannerInfo::parse, MinMaxAggInfo::path, MinMaxAggInfo::pathcost, RelOptInfo::pathlist, PlannerInfo::placeholder_list, PlannerInfo::plan_params, PlannerInfo::processed_tlist, pstrdup(), PlannerInfo::query_level, PlannerInfo::query_pathkeys, query_planner(), SortGroupClause::reverse_sort, root, RelOptInfo::rows, SortGroupClause::sortop, SS_charge_for_initplans(), SS_identify_outer_params(), Path::startup_cost, MinMaxAggInfo::target, SortGroupClause::tleSortGroupRef, Path::total_cost, and PlannerInfo::tuple_fraction.

Referenced by preprocess_minmax_aggregates().

◆ can_minmax_aggs()

static bool can_minmax_aggs ( PlannerInfo root,
List **  context 
)
static

Definition at line 237 of file planagg.c.

238{
239 ListCell *lc;
240
241 /*
242 * This function used to have to scan the query for itself, but now we can
243 * just thumb through the AggInfo list made by preprocess_aggrefs.
244 */
245 foreach(lc, root->agginfos)
246 {
247 AggInfo *agginfo = lfirst_node(AggInfo, lc);
248 Aggref *aggref = linitial_node(Aggref, agginfo->aggrefs);
249 Oid aggsortop;
250 TargetEntry *curTarget;
251 MinMaxAggInfo *mminfo;
252
253 Assert(aggref->agglevelsup == 0);
254 if (list_length(aggref->args) != 1)
255 return false; /* it couldn't be MIN/MAX */
256
257 /*
258 * ORDER BY is usually irrelevant for MIN/MAX, but it can change the
259 * outcome if the aggsortop's operator class recognizes non-identical
260 * values as equal. For example, 4.0 and 4.00 are equal according to
261 * numeric_ops, yet distinguishable. If MIN() receives more than one
262 * value equal to 4.0 and no value less than 4.0, it is unspecified
263 * which of those equal values MIN() returns. An ORDER BY expression
264 * that differs for each of those equal values of the argument
265 * expression makes the result predictable once again. This is a
266 * niche requirement, and we do not implement it with subquery paths.
267 * In any case, this test lets us reject ordered-set aggregates
268 * quickly.
269 */
270 if (aggref->aggorder != NIL)
271 return false;
272 /* note: we do not care if DISTINCT is mentioned ... */
273
274 /*
275 * We might implement the optimization when a FILTER clause is present
276 * by adding the filter to the quals of the generated subquery. For
277 * now, just punt.
278 */
279 if (aggref->aggfilter != NULL)
280 return false;
281
282 aggsortop = fetch_agg_sort_op(aggref->aggfnoid);
283 if (!OidIsValid(aggsortop))
284 return false; /* not a MIN/MAX aggregate */
285
286 curTarget = (TargetEntry *) linitial(aggref->args);
287
288 if (contain_mutable_functions((Node *) curTarget->expr))
289 return false; /* not potentially indexable */
290
291 if (type_is_rowtype(exprType((Node *) curTarget->expr)))
292 return false; /* IS NOT NULL would have weird semantics */
293
294 mminfo = makeNode(MinMaxAggInfo);
295 mminfo->aggfnoid = aggref->aggfnoid;
296 mminfo->aggsortop = aggsortop;
297 mminfo->target = curTarget->expr;
298 mminfo->subroot = NULL; /* don't compute path yet */
299 mminfo->path = NULL;
300 mminfo->pathcost = 0;
301 mminfo->param = NULL;
302
303 *context = lappend(*context, mminfo);
304 }
305 return true;
306}
#define OidIsValid(objectId)
Definition: c.h:732
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:369
List * lappend(List *list, void *datum)
Definition: list.c:339
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2655
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
#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 linitial(l)
Definition: pg_list.h:178
static Oid fetch_agg_sort_op(Oid aggfnoid)
Definition: planagg.c:499
unsigned int Oid
Definition: postgres_ext.h:32
List * aggrefs
Definition: pathnodes.h:3387
Oid aggfnoid
Definition: primnodes.h:460
List * args
Definition: primnodes.h:484
Expr * aggfilter
Definition: primnodes.h:493
List * aggorder
Definition: primnodes.h:487
Param * param
Definition: pathnodes.h:3144
Expr * expr
Definition: primnodes.h:2245

References Aggref::aggfilter, MinMaxAggInfo::aggfnoid, Aggref::aggfnoid, Aggref::aggorder, AggInfo::aggrefs, MinMaxAggInfo::aggsortop, Aggref::args, Assert, contain_mutable_functions(), TargetEntry::expr, exprType(), fetch_agg_sort_op(), lappend(), lfirst_node, linitial, linitial_node, list_length(), makeNode, NIL, OidIsValid, MinMaxAggInfo::param, MinMaxAggInfo::path, MinMaxAggInfo::pathcost, root, MinMaxAggInfo::target, and type_is_rowtype().

Referenced by preprocess_minmax_aggregates().

◆ fetch_agg_sort_op()

static Oid fetch_agg_sort_op ( Oid  aggfnoid)
static

Definition at line 499 of file planagg.c.

500{
501 HeapTuple aggTuple;
502 Form_pg_aggregate aggform;
503 Oid aggsortop;
504
505 /* fetch aggregate entry from pg_aggregate */
506 aggTuple = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(aggfnoid));
507 if (!HeapTupleIsValid(aggTuple))
508 return InvalidOid;
509 aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
510 aggsortop = aggform->aggsortop;
511 ReleaseSysCache(aggTuple);
512
513 return aggsortop;
514}
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

References GETSTRUCT, HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), ReleaseSysCache(), and SearchSysCache1().

Referenced by can_minmax_aggs().

◆ minmax_qp_callback()

static void minmax_qp_callback ( PlannerInfo root,
void *  extra 
)
static

Definition at line 480 of file planagg.c.

481{
482 root->group_pathkeys = NIL;
483 root->window_pathkeys = NIL;
484 root->distinct_pathkeys = NIL;
485
486 root->sort_pathkeys =
488 root->parse->sortClause,
489 root->parse->targetList);
490
491 root->query_pathkeys = root->sort_pathkeys;
492}
List * make_pathkeys_for_sortclauses(PlannerInfo *root, List *sortclauses, List *tlist)
Definition: pathkeys.c:1335

References make_pathkeys_for_sortclauses(), NIL, and root.

Referenced by build_minmax_path().

◆ preprocess_minmax_aggregates()

void preprocess_minmax_aggregates ( PlannerInfo root)

Definition at line 73 of file planagg.c.

74{
75 Query *parse = root->parse;
76 FromExpr *jtnode;
77 RangeTblRef *rtr;
78 RangeTblEntry *rte;
79 List *aggs_list;
80 RelOptInfo *grouped_rel;
81 ListCell *lc;
82
83 /* minmax_aggs list should be empty at this point */
84 Assert(root->minmax_aggs == NIL);
85
86 /* Nothing to do if query has no aggregates */
87 if (!parse->hasAggs)
88 return;
89
90 Assert(!parse->setOperations); /* shouldn't get here if a setop */
91 Assert(parse->rowMarks == NIL); /* nor if FOR UPDATE */
92
93 /*
94 * Reject unoptimizable cases.
95 *
96 * We don't handle GROUP BY or windowing, because our current
97 * implementations of grouping require looking at all the rows anyway, and
98 * so there's not much point in optimizing MIN/MAX.
99 */
100 if (parse->groupClause || list_length(parse->groupingSets) > 1 ||
101 parse->hasWindowFuncs)
102 return;
103
104 /*
105 * Reject if query contains any CTEs; there's no way to build an indexscan
106 * on one so we couldn't succeed here. (If the CTEs are unreferenced,
107 * that's not true, but it doesn't seem worth expending cycles to check.)
108 */
109 if (parse->cteList)
110 return;
111
112 /*
113 * We also restrict the query to reference exactly one table, since join
114 * conditions can't be handled reasonably. (We could perhaps handle a
115 * query containing cartesian-product joins, but it hardly seems worth the
116 * trouble.) However, the single table could be buried in several levels
117 * of FromExpr due to subqueries. Note the "single" table could be an
118 * inheritance parent, too, including the case of a UNION ALL subquery
119 * that's been flattened to an appendrel.
120 */
121 jtnode = parse->jointree;
122 while (IsA(jtnode, FromExpr))
123 {
124 if (list_length(jtnode->fromlist) != 1)
125 return;
126 jtnode = linitial(jtnode->fromlist);
127 }
128 if (!IsA(jtnode, RangeTblRef))
129 return;
130 rtr = (RangeTblRef *) jtnode;
131 rte = planner_rt_fetch(rtr->rtindex, root);
132 if (rte->rtekind == RTE_RELATION)
133 /* ordinary relation, ok */ ;
134 else if (rte->rtekind == RTE_SUBQUERY && rte->inh)
135 /* flattened UNION ALL subquery, ok */ ;
136 else
137 return;
138
139 /*
140 * Examine all the aggregates and verify all are MIN/MAX aggregates. Stop
141 * as soon as we find one that isn't.
142 */
143 aggs_list = NIL;
144 if (!can_minmax_aggs(root, &aggs_list))
145 return;
146
147 /*
148 * OK, there is at least the possibility of performing the optimization.
149 * Build an access path for each aggregate. If any of the aggregates
150 * prove to be non-indexable, give up; there is no point in optimizing
151 * just some of them.
152 */
153 foreach(lc, aggs_list)
154 {
155 MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
156 Oid eqop;
157 bool reverse;
158
159 /*
160 * We'll need the equality operator that goes with the aggregate's
161 * ordering operator.
162 */
163 eqop = get_equality_op_for_ordering_op(mminfo->aggsortop, &reverse);
164 if (!OidIsValid(eqop)) /* shouldn't happen */
165 elog(ERROR, "could not find equality operator for ordering operator %u",
166 mminfo->aggsortop);
167
168 /*
169 * We can use either an ordering that gives NULLS FIRST or one that
170 * gives NULLS LAST; furthermore there's unlikely to be much
171 * performance difference between them, so it doesn't seem worth
172 * costing out both ways if we get a hit on the first one. NULLS
173 * FIRST is more likely to be available if the operator is a
174 * reverse-sort operator, so try that first if reverse.
175 */
176 if (build_minmax_path(root, mminfo, eqop, mminfo->aggsortop, reverse, reverse))
177 continue;
178 if (build_minmax_path(root, mminfo, eqop, mminfo->aggsortop, reverse, !reverse))
179 continue;
180
181 /* No indexable path for this aggregate, so fail */
182 return;
183 }
184
185 /*
186 * OK, we can do the query this way. Prepare to create a MinMaxAggPath
187 * node.
188 *
189 * First, create an output Param node for each agg. (If we end up not
190 * using the MinMaxAggPath, we'll waste a PARAM_EXEC slot for each agg,
191 * which is not worth worrying about. We can't wait till create_plan time
192 * to decide whether to make the Param, unfortunately.)
193 */
194 foreach(lc, aggs_list)
195 {
196 MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
197
198 mminfo->param =
200 exprType((Node *) mminfo->target),
201 -1,
202 exprCollation((Node *) mminfo->target));
203 }
204
205 /*
206 * Create a MinMaxAggPath node with the appropriate estimated costs and
207 * other needed data, and add it to the UPPERREL_GROUP_AGG upperrel, where
208 * it will compete against the standard aggregate implementation. (It
209 * will likely always win, but we need not assume that here.)
210 *
211 * Note: grouping_planner won't have created this upperrel yet, but it's
212 * fine for us to create it first. We will not have inserted the correct
213 * consider_parallel value in it, but MinMaxAggPath paths are currently
214 * never parallel-safe anyway, so that doesn't matter. Likewise, it
215 * doesn't matter that we haven't filled FDW-related fields in the rel.
216 * Also, because there are no rowmarks, we know that the processed_tlist
217 * doesn't need to change anymore, so making the pathtarget now is safe.
218 */
219 grouped_rel = fetch_upper_rel(root, UPPERREL_GROUP_AGG, NULL);
220 add_path(grouped_rel, (Path *)
221 create_minmaxagg_path(root, grouped_rel,
223 root->processed_tlist),
224 aggs_list,
225 (List *) parse->havingQual));
226}
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
Oid get_equality_op_for_ordering_op(Oid opno, bool *reverse)
Definition: lsyscache.c:267
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:821
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
@ RTE_SUBQUERY
Definition: parsenodes.h:1027
@ RTE_RELATION
Definition: parsenodes.h:1026
MinMaxAggPath * create_minmaxagg_path(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *mmaggregates, List *quals)
Definition: pathnode.c:3486
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:461
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:570
@ UPPERREL_GROUP_AGG
Definition: pathnodes.h:74
#define lfirst(lc)
Definition: pg_list.h:172
static bool can_minmax_aggs(PlannerInfo *root, List **context)
Definition: planagg.c:237
static bool build_minmax_path(PlannerInfo *root, MinMaxAggInfo *mminfo, Oid eqop, Oid sortop, bool reverse_sort, bool nulls_first)
Definition: planagg.c:317
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1458
List * fromlist
Definition: primnodes.h:2363
RTEKind rtekind
Definition: parsenodes.h:1056
Param * SS_make_initplan_output_param(PlannerInfo *root, Oid resulttype, int32 resulttypmod, Oid resultcollation)
Definition: subselect.c:3033

References add_path(), MinMaxAggInfo::aggsortop, Assert, build_minmax_path(), can_minmax_aggs(), create_minmaxagg_path(), create_pathtarget, elog, ERROR, exprCollation(), exprType(), fetch_upper_rel(), FromExpr::fromlist, get_equality_op_for_ordering_op(), RangeTblEntry::inh, IsA, lfirst, linitial, list_length(), NIL, OidIsValid, MinMaxAggInfo::param, parse(), planner_rt_fetch, root, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, RangeTblRef::rtindex, SS_make_initplan_output_param(), MinMaxAggInfo::target, and UPPERREL_GROUP_AGG.

Referenced by grouping_planner().