PostgreSQL Source Code  git master
planagg.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * planagg.c
4  * Special planning for aggregate queries.
5  *
6  * This module tries to replace MIN/MAX aggregate functions by subqueries
7  * of the form
8  * (SELECT col FROM tab
9  * WHERE col IS NOT NULL AND existing-quals
10  * ORDER BY col ASC/DESC
11  * LIMIT 1)
12  * Given a suitable index on tab.col, this can be much faster than the
13  * generic scan-all-the-rows aggregation plan. We can handle multiple
14  * MIN/MAX aggregates by generating multiple subqueries, and their
15  * orderings can be different. However, if the query contains any
16  * non-optimizable aggregates, there's no point since we'll have to
17  * scan all the rows anyway.
18  *
19  *
20  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
21  * Portions Copyright (c) 1994, Regents of the University of California
22  *
23  *
24  * IDENTIFICATION
25  * src/backend/optimizer/plan/planagg.c
26  *
27  *-------------------------------------------------------------------------
28  */
29 #include "postgres.h"
30 
31 #include "access/htup_details.h"
32 #include "catalog/pg_aggregate.h"
33 #include "catalog/pg_type.h"
34 #include "nodes/makefuncs.h"
35 #include "nodes/nodeFuncs.h"
36 #include "optimizer/clauses.h"
37 #include "optimizer/cost.h"
38 #include "optimizer/optimizer.h"
39 #include "optimizer/pathnode.h"
40 #include "optimizer/paths.h"
41 #include "optimizer/planmain.h"
42 #include "optimizer/subselect.h"
43 #include "optimizer/tlist.h"
44 #include "parser/parsetree.h"
45 #include "parser/parse_clause.h"
46 #include "rewrite/rewriteManip.h"
47 #include "utils/lsyscache.h"
48 #include "utils/syscache.h"
49 
50 
51 static bool find_minmax_aggs_walker(Node *node, List **context);
52 static bool build_minmax_path(PlannerInfo *root, MinMaxAggInfo *mminfo,
53  Oid eqop, Oid sortop, bool nulls_first);
54 static void minmax_qp_callback(PlannerInfo *root, void *extra);
55 static Oid fetch_agg_sort_op(Oid aggfnoid);
56 
57 
58 /*
59  * preprocess_minmax_aggregates - preprocess MIN/MAX aggregates
60  *
61  * Check to see whether the query contains MIN/MAX aggregate functions that
62  * might be optimizable via indexscans. If it does, and all the aggregates
63  * are potentially optimizable, then create a MinMaxAggPath and add it to
64  * the (UPPERREL_GROUP_AGG, NULL) upperrel.
65  *
66  * This should be called by grouping_planner() just before it's ready to call
67  * query_planner(), because we generate indexscan paths by cloning the
68  * planner's state and invoking query_planner() on a modified version of
69  * the query parsetree. Thus, all preprocessing needed before query_planner()
70  * must already be done.
71  */
72 void
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  * Scan the tlist and HAVING qual to find all the aggregates and verify
141  * all are MIN/MAX aggregates. Stop as soon as we find one that isn't.
142  */
143  aggs_list = NIL;
144  if (find_minmax_aggs_walker((Node *) root->processed_tlist, &aggs_list))
145  return;
146  if (find_minmax_aggs_walker(parse->havingQual, &aggs_list))
147  return;
148 
149  /*
150  * OK, there is at least the possibility of performing the optimization.
151  * Build an access path for each aggregate. If any of the aggregates
152  * prove to be non-indexable, give up; there is no point in optimizing
153  * just some of them.
154  */
155  foreach(lc, aggs_list)
156  {
157  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
158  Oid eqop;
159  bool reverse;
160 
161  /*
162  * We'll need the equality operator that goes with the aggregate's
163  * ordering operator.
164  */
165  eqop = get_equality_op_for_ordering_op(mminfo->aggsortop, &reverse);
166  if (!OidIsValid(eqop)) /* shouldn't happen */
167  elog(ERROR, "could not find equality operator for ordering operator %u",
168  mminfo->aggsortop);
169 
170  /*
171  * We can use either an ordering that gives NULLS FIRST or one that
172  * gives NULLS LAST; furthermore there's unlikely to be much
173  * performance difference between them, so it doesn't seem worth
174  * costing out both ways if we get a hit on the first one. NULLS
175  * FIRST is more likely to be available if the operator is a
176  * reverse-sort operator, so try that first if reverse.
177  */
178  if (build_minmax_path(root, mminfo, eqop, mminfo->aggsortop, reverse))
179  continue;
180  if (build_minmax_path(root, mminfo, eqop, mminfo->aggsortop, !reverse))
181  continue;
182 
183  /* No indexable path for this aggregate, so fail */
184  return;
185  }
186 
187  /*
188  * OK, we can do the query this way. Prepare to create a MinMaxAggPath
189  * node.
190  *
191  * First, create an output Param node for each agg. (If we end up not
192  * using the MinMaxAggPath, we'll waste a PARAM_EXEC slot for each agg,
193  * which is not worth worrying about. We can't wait till create_plan time
194  * to decide whether to make the Param, unfortunately.)
195  */
196  foreach(lc, aggs_list)
197  {
198  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
199 
200  mminfo->param =
202  exprType((Node *) mminfo->target),
203  -1,
204  exprCollation((Node *) mminfo->target));
205  }
206 
207  /*
208  * Create a MinMaxAggPath node with the appropriate estimated costs and
209  * other needed data, and add it to the UPPERREL_GROUP_AGG upperrel, where
210  * it will compete against the standard aggregate implementation. (It
211  * will likely always win, but we need not assume that here.)
212  *
213  * Note: grouping_planner won't have created this upperrel yet, but it's
214  * fine for us to create it first. We will not have inserted the correct
215  * consider_parallel value in it, but MinMaxAggPath paths are currently
216  * never parallel-safe anyway, so that doesn't matter. Likewise, it
217  * doesn't matter that we haven't filled FDW-related fields in the rel.
218  * Also, because there are no rowmarks, we know that the processed_tlist
219  * doesn't need to change anymore, so making the pathtarget now is safe.
220  */
221  grouped_rel = fetch_upper_rel(root, UPPERREL_GROUP_AGG, NULL);
222  add_path(grouped_rel, (Path *)
223  create_minmaxagg_path(root, grouped_rel,
224  create_pathtarget(root,
225  root->processed_tlist),
226  aggs_list,
227  (List *) parse->havingQual));
228 }
229 
230 /*
231  * find_minmax_aggs_walker
232  * Recursively scan the Aggref nodes in an expression tree, and check
233  * that each one is a MIN/MAX aggregate. If so, build a list of the
234  * distinct aggregate calls in the tree.
235  *
236  * Returns true if a non-MIN/MAX aggregate is found, false otherwise.
237  * (This seemingly-backward definition is used because expression_tree_walker
238  * aborts the scan on true return, which is what we want.)
239  *
240  * Found aggregates are added to the list at *context; it's up to the caller
241  * to initialize the list to NIL.
242  *
243  * This does not descend into subqueries, and so should be used only after
244  * reduction of sublinks to subplans. There mustn't be outer-aggregate
245  * references either.
246  */
247 static bool
249 {
250  if (node == NULL)
251  return false;
252  if (IsA(node, Aggref))
253  {
254  Aggref *aggref = (Aggref *) node;
255  Oid aggsortop;
256  TargetEntry *curTarget;
257  MinMaxAggInfo *mminfo;
258  ListCell *l;
259 
260  Assert(aggref->agglevelsup == 0);
261  if (list_length(aggref->args) != 1)
262  return true; /* it couldn't be MIN/MAX */
263 
264  /*
265  * ORDER BY is usually irrelevant for MIN/MAX, but it can change the
266  * outcome if the aggsortop's operator class recognizes non-identical
267  * values as equal. For example, 4.0 and 4.00 are equal according to
268  * numeric_ops, yet distinguishable. If MIN() receives more than one
269  * value equal to 4.0 and no value less than 4.0, it is unspecified
270  * which of those equal values MIN() returns. An ORDER BY expression
271  * that differs for each of those equal values of the argument
272  * expression makes the result predictable once again. This is a
273  * niche requirement, and we do not implement it with subquery paths.
274  * In any case, this test lets us reject ordered-set aggregates
275  * quickly.
276  */
277  if (aggref->aggorder != NIL)
278  return true;
279  /* note: we do not care if DISTINCT is mentioned ... */
280 
281  /*
282  * We might implement the optimization when a FILTER clause is present
283  * by adding the filter to the quals of the generated subquery. For
284  * now, just punt.
285  */
286  if (aggref->aggfilter != NULL)
287  return true;
288 
289  aggsortop = fetch_agg_sort_op(aggref->aggfnoid);
290  if (!OidIsValid(aggsortop))
291  return true; /* not a MIN/MAX aggregate */
292 
293  curTarget = (TargetEntry *) linitial(aggref->args);
294 
295  if (contain_mutable_functions((Node *) curTarget->expr))
296  return true; /* not potentially indexable */
297 
298  if (type_is_rowtype(exprType((Node *) curTarget->expr)))
299  return true; /* IS NOT NULL would have weird semantics */
300 
301  /*
302  * Check whether it's already in the list, and add it if not.
303  */
304  foreach(l, *context)
305  {
306  mminfo = (MinMaxAggInfo *) lfirst(l);
307  if (mminfo->aggfnoid == aggref->aggfnoid &&
308  equal(mminfo->target, curTarget->expr))
309  return false;
310  }
311 
312  mminfo = makeNode(MinMaxAggInfo);
313  mminfo->aggfnoid = aggref->aggfnoid;
314  mminfo->aggsortop = aggsortop;
315  mminfo->target = curTarget->expr;
316  mminfo->subroot = NULL; /* don't compute path yet */
317  mminfo->path = NULL;
318  mminfo->pathcost = 0;
319  mminfo->param = NULL;
320 
321  *context = lappend(*context, mminfo);
322 
323  /*
324  * We need not recurse into the argument, since it can't contain any
325  * aggregates.
326  */
327  return false;
328  }
329  Assert(!IsA(node, SubLink));
331  (void *) context);
332 }
333 
334 /*
335  * build_minmax_path
336  * Given a MIN/MAX aggregate, try to build an indexscan Path it can be
337  * optimized with.
338  *
339  * If successful, stash the best path in *mminfo and return true.
340  * Otherwise, return false.
341  */
342 static bool
344  Oid eqop, Oid sortop, bool nulls_first)
345 {
346  PlannerInfo *subroot;
347  Query *parse;
348  TargetEntry *tle;
349  List *tlist;
350  NullTest *ntest;
351  SortGroupClause *sortcl;
352  RelOptInfo *final_rel;
353  Path *sorted_path;
354  Cost path_cost;
355  double path_fraction;
356 
357  /*
358  * We are going to construct what is effectively a sub-SELECT query, so
359  * clone the current query level's state and adjust it to make it look
360  * like a subquery. Any outer references will now be one level higher
361  * than before. (This means that when we are done, there will be no Vars
362  * of level 1, which is why the subquery can become an initplan.)
363  */
364  subroot = (PlannerInfo *) palloc(sizeof(PlannerInfo));
365  memcpy(subroot, root, sizeof(PlannerInfo));
366  subroot->query_level++;
367  subroot->parent_root = root;
368  /* reset subplan-related stuff */
369  subroot->plan_params = NIL;
370  subroot->outer_params = NULL;
371  subroot->init_plans = NIL;
372 
373  subroot->parse = parse = copyObject(root->parse);
374  IncrementVarSublevelsUp((Node *) parse, 1, 1);
375 
376  /* append_rel_list might contain outer Vars? */
377  subroot->append_rel_list = copyObject(root->append_rel_list);
378  IncrementVarSublevelsUp((Node *) subroot->append_rel_list, 1, 1);
379  /* There shouldn't be any OJ info to translate, as yet */
380  Assert(subroot->join_info_list == NIL);
381  /* and we haven't made equivalence classes, either */
382  Assert(subroot->eq_classes == NIL);
383  /* and we haven't created PlaceHolderInfos, either */
384  Assert(subroot->placeholder_list == NIL);
385 
386  /*----------
387  * Generate modified query of the form
388  * (SELECT col FROM tab
389  * WHERE col IS NOT NULL AND existing-quals
390  * ORDER BY col ASC/DESC
391  * LIMIT 1)
392  *----------
393  */
394  /* single tlist entry that is the aggregate target */
395  tle = makeTargetEntry(copyObject(mminfo->target),
396  (AttrNumber) 1,
397  pstrdup("agg_target"),
398  false);
399  tlist = list_make1(tle);
400  subroot->processed_tlist = parse->targetList = tlist;
401 
402  /* No HAVING, no DISTINCT, no aggregates anymore */
403  parse->havingQual = NULL;
404  subroot->hasHavingQual = false;
405  parse->distinctClause = NIL;
406  parse->hasDistinctOn = false;
407  parse->hasAggs = false;
408 
409  /* Build "target IS NOT NULL" expression */
410  ntest = makeNode(NullTest);
411  ntest->nulltesttype = IS_NOT_NULL;
412  ntest->arg = copyObject(mminfo->target);
413  /* we checked it wasn't a rowtype in find_minmax_aggs_walker */
414  ntest->argisrow = false;
415  ntest->location = -1;
416 
417  /* User might have had that in WHERE already */
418  if (!list_member((List *) parse->jointree->quals, ntest))
419  parse->jointree->quals = (Node *)
420  lcons(ntest, (List *) parse->jointree->quals);
421 
422  /* Build suitable ORDER BY clause */
423  sortcl = makeNode(SortGroupClause);
424  sortcl->tleSortGroupRef = assignSortGroupRef(tle, subroot->processed_tlist);
425  sortcl->eqop = eqop;
426  sortcl->sortop = sortop;
427  sortcl->nulls_first = nulls_first;
428  sortcl->hashable = false; /* no need to make this accurate */
429  parse->sortClause = list_make1(sortcl);
430 
431  /* set up expressions for LIMIT 1 */
432  parse->limitOffset = NULL;
433  parse->limitCount = (Node *) makeConst(INT8OID, -1, InvalidOid,
434  sizeof(int64),
435  Int64GetDatum(1), false,
436  FLOAT8PASSBYVAL);
437 
438  /*
439  * Generate the best paths for this query, telling query_planner that we
440  * have LIMIT 1.
441  */
442  subroot->tuple_fraction = 1.0;
443  subroot->limit_tuples = 1.0;
444 
445  final_rel = query_planner(subroot, minmax_qp_callback, NULL);
446 
447  /*
448  * Since we didn't go through subquery_planner() to handle the subquery,
449  * we have to do some of the same cleanup it would do, in particular cope
450  * with params and initplans used within this subquery. (This won't
451  * matter if we end up not using the subplan.)
452  */
453  SS_identify_outer_params(subroot);
454  SS_charge_for_initplans(subroot, final_rel);
455 
456  /*
457  * Get the best presorted path, that being the one that's cheapest for
458  * fetching just one row. If there's no such path, fail.
459  */
460  if (final_rel->rows > 1.0)
461  path_fraction = 1.0 / final_rel->rows;
462  else
463  path_fraction = 1.0;
464 
465  sorted_path =
467  subroot->query_pathkeys,
468  NULL,
469  path_fraction);
470  if (!sorted_path)
471  return false;
472 
473  /*
474  * The path might not return exactly what we want, so fix that. (We
475  * assume that this won't change any conclusions about which was the
476  * cheapest path.)
477  */
478  sorted_path = apply_projection_to_path(subroot, final_rel, sorted_path,
479  create_pathtarget(subroot,
480  subroot->processed_tlist));
481 
482  /*
483  * Determine cost to get just the first row of the presorted path.
484  *
485  * Note: cost calculation here should match
486  * compare_fractional_path_costs().
487  */
488  path_cost = sorted_path->startup_cost +
489  path_fraction * (sorted_path->total_cost - sorted_path->startup_cost);
490 
491  /* Save state for further processing */
492  mminfo->subroot = subroot;
493  mminfo->path = sorted_path;
494  mminfo->pathcost = path_cost;
495 
496  return true;
497 }
498 
499 /*
500  * Compute query_pathkeys and other pathkeys during query_planner()
501  */
502 static void
503 minmax_qp_callback(PlannerInfo *root, void *extra)
504 {
505  root->group_pathkeys = NIL;
506  root->window_pathkeys = NIL;
507  root->distinct_pathkeys = NIL;
508 
509  root->sort_pathkeys =
511  root->parse->sortClause,
512  root->parse->targetList);
513 
514  root->query_pathkeys = root->sort_pathkeys;
515 }
516 
517 /*
518  * Get the OID of the sort operator, if any, associated with an aggregate.
519  * Returns InvalidOid if there is no such operator.
520  */
521 static Oid
523 {
524  HeapTuple aggTuple;
525  Form_pg_aggregate aggform;
526  Oid aggsortop;
527 
528  /* fetch aggregate entry from pg_aggregate */
529  aggTuple = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(aggfnoid));
530  if (!HeapTupleIsValid(aggTuple))
531  return InvalidOid;
532  aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
533  aggsortop = aggform->aggsortop;
534  ReleaseSysCache(aggTuple);
535 
536  return aggsortop;
537 }
Path * apply_projection_to_path(PlannerInfo *root, RelOptInfo *rel, Path *path, PathTarget *target)
Definition: pathnode.c:2611
List * group_pathkeys
Definition: pathnodes.h:298
#define NIL
Definition: pg_list.h:65
static void minmax_qp_callback(PlannerInfo *root, void *extra)
Definition: planagg.c:503
static bool find_minmax_aggs_walker(Node *node, List **context)
Definition: planagg.c:248
MinMaxAggPath * create_minmaxagg_path(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *mmaggregates, List *quals)
Definition: pathnode.c:3145
Index assignSortGroupRef(TargetEntry *tle, List *tlist)
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Query * parse
Definition: pathnodes.h:177
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:423
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
List * plan_params
Definition: pathnodes.h:191
List * sortClause
Definition: parsenodes.h:158
List * query_pathkeys
Definition: pathnodes.h:296
List * join_info_list
Definition: pathnodes.h:281
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:773
FromExpr * jointree
Definition: parsenodes.h:138
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3008
List * make_pathkeys_for_sortclauses(PlannerInfo *root, List *sortclauses, List *tlist)
Definition: pathkeys.c:1071
PlannerInfo * parent_root
Definition: pathnodes.h:183
char * pstrdup(const char *in)
Definition: mcxt.c:1186
bool hasAggs
Definition: parsenodes.h:125
Oid get_equality_op_for_ordering_op(Oid opno, bool *reverse)
Definition: lsyscache.c:264
Param * param
Definition: pathnodes.h:2282
void SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel)
Definition: subselect.c:2061
Index tleSortGroupRef
Definition: parsenodes.h:1234
List * groupingSets
Definition: parsenodes.h:150
Definition: nodes.h:525
RelOptInfo * query_planner(PlannerInfo *root, query_pathkeys_callback qp_callback, void *qp_extra)
Definition: planmain.c:55
List * args
Definition: primnodes.h:305
List * minmax_aggs
Definition: pathnodes.h:327
List * fromlist
Definition: primnodes.h:1496
unsigned int Oid
Definition: postgres_ext.h:31
List * rowMarks
Definition: parsenodes.h:163
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:297
#define OidIsValid(objectId)
Definition: c.h:638
List * targetList
Definition: parsenodes.h:140
void preprocess_minmax_aggregates(PlannerInfo *root)
Definition: planagg.c:73
#define list_make1(x1)
Definition: pg_list.h:227
double tuple_fraction
Definition: pathnodes.h:334
#define linitial(l)
Definition: pg_list.h:195
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
bool list_member(const List *list, const void *datum)
Definition: list.c:614
double limit_tuples
Definition: pathnodes.h:335
Cost startup_cost
Definition: pathnodes.h:1125
Expr * arg
Definition: primnodes.h:1205
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:371
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1164
List * aggorder
Definition: primnodes.h:306
Index agglevelsup
Definition: primnodes.h:313
#define create_pathtarget(root, tlist)
Definition: tlist.h:54
Path * get_cheapest_fractional_path_for_pathkeys(List *paths, List *pathkeys, Relids required_outer, double fraction)
Definition: pathkeys.c:395
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2433
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1699
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:236
List * sort_pathkeys
Definition: pathnodes.h:301
List * lappend(List *list, void *datum)
Definition: list.c:322
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
List * window_pathkeys
Definition: pathnodes.h:299
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
List * append_rel_list
Definition: pathnodes.h:288
NullTestType nulltesttype
Definition: primnodes.h:1206
List * init_plans
Definition: pathnodes.h:257
double rows
Definition: pathnodes.h:644
#define InvalidOid
Definition: postgres_ext.h:36
List * distinct_pathkeys
Definition: pathnodes.h:300
Oid aggfnoid
Definition: primnodes.h:298
Cost total_cost
Definition: pathnodes.h:1126
List * lcons(void *datum, List *list)
Definition: list.c:454
#define makeNode(_type_)
Definition: nodes.h:573
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
Expr * target
Definition: pathnodes.h:2278
bool hasWindowFuncs
Definition: parsenodes.h:126
void SS_identify_outer_params(PlannerInfo *root)
Definition: subselect.c:1999
List * eq_classes
Definition: pathnodes.h:264
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
Param * SS_make_initplan_output_param(PlannerInfo *root, Oid resulttype, int32 resulttypmod, Oid resultcollation)
Definition: subselect.c:2873
Expr * expr
Definition: primnodes.h:1393
Bitmapset * outer_params
Definition: pathnodes.h:192
int location
Definition: primnodes.h:1208
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1840
static int list_length(const List *l)
Definition: pg_list.h:169
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:720
Expr * aggfilter
Definition: primnodes.h:308
static bool build_minmax_path(PlannerInfo *root, MinMaxAggInfo *mminfo, Oid eqop, Oid sortop, bool nulls_first)
Definition: planagg.c:343
Index query_level
Definition: pathnodes.h:181
RTEKind rtekind
Definition: parsenodes.h:974
List * cteList
Definition: parsenodes.h:135
Node * setOperations
Definition: parsenodes.h:165
List * groupClause
Definition: parsenodes.h:148
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:226
List * placeholder_list
Definition: pathnodes.h:292
bool hasHavingQual
Definition: pathnodes.h:345
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:645
bool argisrow
Definition: primnodes.h:1207
List * pathlist
Definition: pathnodes.h:655
#define copyObject(obj)
Definition: nodes.h:641
Node * havingQual
Definition: parsenodes.h:152
List * processed_tlist
Definition: pathnodes.h:323
static Oid fetch_agg_sort_op(Oid aggfnoid)
Definition: planagg.c:522
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
double Cost
Definition: nodes.h:659
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:648
PlannerInfo * subroot
Definition: pathnodes.h:2279