PostgreSQL Source Code  git master
prepunion.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * prepunion.c
4  * Routines to plan set-operation queries. The filename is a leftover
5  * from a time when only UNIONs were implemented.
6  *
7  * There are two code paths in the planner for set-operation queries.
8  * If a subquery consists entirely of simple UNION ALL operations, it
9  * is converted into an "append relation". Otherwise, it is handled
10  * by the general code in this module (plan_set_operations and its
11  * subroutines). There is some support code here for the append-relation
12  * case, but most of the heavy lifting for that is done elsewhere,
13  * notably in prepjointree.c and allpaths.c.
14  *
15  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
16  * Portions Copyright (c) 1994, Regents of the University of California
17  *
18  *
19  * IDENTIFICATION
20  * src/backend/optimizer/prep/prepunion.c
21  *
22  *-------------------------------------------------------------------------
23  */
24 #include "postgres.h"
25 
26 #include "access/htup_details.h"
27 #include "access/sysattr.h"
28 #include "catalog/partition.h"
29 #include "catalog/pg_inherits.h"
30 #include "catalog/pg_type.h"
31 #include "miscadmin.h"
32 #include "nodes/makefuncs.h"
33 #include "nodes/nodeFuncs.h"
34 #include "optimizer/cost.h"
35 #include "optimizer/pathnode.h"
36 #include "optimizer/paths.h"
37 #include "optimizer/planmain.h"
38 #include "optimizer/planner.h"
39 #include "optimizer/prep.h"
40 #include "optimizer/tlist.h"
41 #include "parser/parse_coerce.h"
42 #include "parser/parsetree.h"
43 #include "utils/lsyscache.h"
44 #include "utils/rel.h"
45 #include "utils/selfuncs.h"
46 #include "utils/syscache.h"
47 
48 
50  List *colTypes, List *colCollations,
51  bool junkOK,
52  int flag, List *refnames_tlist,
53  List **pTargetList,
54  double *pNumGroups);
56  PlannerInfo *root,
57  List *refnames_tlist,
58  List **pTargetList);
60  List *refnames_tlist,
61  List **pTargetList);
63  List *refnames_tlist,
64  List **pTargetList);
66  SetOperationStmt *top_union,
67  List *refnames_tlist,
68  List **tlist_list);
69 static Path *make_union_unique(SetOperationStmt *op, Path *path, List *tlist,
70  PlannerInfo *root);
71 static void postprocess_setop_rel(PlannerInfo *root, RelOptInfo *rel);
72 static bool choose_hashed_setop(PlannerInfo *root, List *groupClauses,
73  Path *input_path,
74  double dNumGroups, double dNumOutputRows,
75  const char *construct);
76 static List *generate_setop_tlist(List *colTypes, List *colCollations,
77  int flag,
78  Index varno,
79  bool hack_constants,
80  List *input_tlist,
81  List *refnames_tlist,
82  bool *trivial_tlist);
83 static List *generate_append_tlist(List *colTypes, List *colCollations,
84  bool flag,
85  List *input_tlists,
86  List *refnames_tlist);
87 static List *generate_setop_grouplist(SetOperationStmt *op, List *targetlist);
88 
89 
90 /*
91  * plan_set_operations
92  *
93  * Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT)
94  *
95  * This routine only deals with the setOperations tree of the given query.
96  * Any top-level ORDER BY requested in root->parse->sortClause will be handled
97  * when we return to grouping_planner; likewise for LIMIT.
98  *
99  * What we return is an "upperrel" RelOptInfo containing at least one Path
100  * that implements the set-operation tree. In addition, root->processed_tlist
101  * receives a targetlist representing the output of the topmost setop node.
102  */
103 RelOptInfo *
105 {
106  Query *parse = root->parse;
107  SetOperationStmt *topop = castNode(SetOperationStmt, parse->setOperations);
108  Node *node;
109  RangeTblEntry *leftmostRTE;
110  Query *leftmostQuery;
111  RelOptInfo *setop_rel;
112  List *top_tlist;
113 
114  Assert(topop);
115 
116  /* check for unsupported stuff */
117  Assert(parse->jointree->fromlist == NIL);
118  Assert(parse->jointree->quals == NULL);
119  Assert(parse->groupClause == NIL);
120  Assert(parse->havingQual == NULL);
121  Assert(parse->windowClause == NIL);
122  Assert(parse->distinctClause == NIL);
123 
124  /*
125  * In the outer query level, we won't have any true equivalences to deal
126  * with; but we do want to be able to make pathkeys, which will require
127  * single-member EquivalenceClasses. Indicate that EC merging is complete
128  * so that pathkeys.c won't complain.
129  */
130  Assert(root->eq_classes == NIL);
131  root->ec_merging_done = true;
132 
133  /*
134  * We'll need to build RelOptInfos for each of the leaf subqueries, which
135  * are RTE_SUBQUERY rangetable entries in this Query. Prepare the index
136  * arrays for those, and for AppendRelInfos in case they're needed.
137  */
139 
140  /*
141  * Find the leftmost component Query. We need to use its column names for
142  * all generated tlists (else SELECT INTO won't work right).
143  */
144  node = topop->larg;
145  while (node && IsA(node, SetOperationStmt))
146  node = ((SetOperationStmt *) node)->larg;
147  Assert(node && IsA(node, RangeTblRef));
148  leftmostRTE = root->simple_rte_array[((RangeTblRef *) node)->rtindex];
149  leftmostQuery = leftmostRTE->subquery;
150  Assert(leftmostQuery != NULL);
151 
152  /*
153  * If the topmost node is a recursive union, it needs special processing.
154  */
155  if (root->hasRecursion)
156  {
157  setop_rel = generate_recursion_path(topop, root,
158  leftmostQuery->targetList,
159  &top_tlist);
160  }
161  else
162  {
163  /*
164  * Recurse on setOperations tree to generate paths for set ops. The
165  * final output paths should have just the column types shown as the
166  * output from the top-level node, plus possibly resjunk working
167  * columns (we can rely on upper-level nodes to deal with that).
168  */
169  setop_rel = recurse_set_operations((Node *) topop, root,
170  topop->colTypes, topop->colCollations,
171  true, -1,
172  leftmostQuery->targetList,
173  &top_tlist,
174  NULL);
175  }
176 
177  /* Must return the built tlist into root->processed_tlist. */
178  root->processed_tlist = top_tlist;
179 
180  return setop_rel;
181 }
182 
183 /*
184  * recurse_set_operations
185  * Recursively handle one step in a tree of set operations
186  *
187  * colTypes: OID list of set-op's result column datatypes
188  * colCollations: OID list of set-op's result column collations
189  * junkOK: if true, child resjunk columns may be left in the result
190  * flag: if >= 0, add a resjunk output column indicating value of flag
191  * refnames_tlist: targetlist to take column names from
192  *
193  * Returns a RelOptInfo for the subtree, as well as these output parameters:
194  * *pTargetList: receives the fully-fledged tlist for the subtree's top plan
195  * *pNumGroups: if not NULL, we estimate the number of distinct groups
196  * in the result, and store it there
197  *
198  * The pTargetList output parameter is mostly redundant with the pathtarget
199  * of the returned RelOptInfo, but for the moment we need it because much of
200  * the logic in this file depends on flag columns being marked resjunk.
201  * Pending a redesign of how that works, this is the easy way out.
202  *
203  * We don't have to care about typmods here: the only allowed difference
204  * between set-op input and output typmods is input is a specific typmod
205  * and output is -1, and that does not require a coercion.
206  */
207 static RelOptInfo *
209  List *colTypes, List *colCollations,
210  bool junkOK,
211  int flag, List *refnames_tlist,
212  List **pTargetList,
213  double *pNumGroups)
214 {
215  RelOptInfo *rel = NULL; /* keep compiler quiet */
216 
217  /* Guard against stack overflow due to overly complex setop nests */
219 
220  if (IsA(setOp, RangeTblRef))
221  {
222  RangeTblRef *rtr = (RangeTblRef *) setOp;
223  RangeTblEntry *rte = root->simple_rte_array[rtr->rtindex];
224  Query *subquery = rte->subquery;
225  PlannerInfo *subroot;
226  RelOptInfo *final_rel;
227  Path *subpath;
228  Path *path;
229  List *tlist;
230  bool trivial_tlist;
231 
232  Assert(subquery != NULL);
233 
234  /* Build a RelOptInfo for this leaf subquery. */
235  rel = build_simple_rel(root, rtr->rtindex, NULL);
236 
237  /* plan_params should not be in use in current query level */
238  Assert(root->plan_params == NIL);
239 
240  /* Generate a subroot and Paths for the subquery */
241  subroot = rel->subroot = subquery_planner(root->glob, subquery,
242  root,
243  false,
244  root->tuple_fraction);
245 
246  /*
247  * It should not be possible for the primitive query to contain any
248  * cross-references to other primitive queries in the setop tree.
249  */
250  if (root->plan_params)
251  elog(ERROR, "unexpected outer reference in set operation subquery");
252 
253  /* Figure out the appropriate target list for this subquery. */
254  tlist = generate_setop_tlist(colTypes, colCollations,
255  flag,
256  rtr->rtindex,
257  true,
258  subroot->processed_tlist,
259  refnames_tlist,
260  &trivial_tlist);
261  rel->reltarget = create_pathtarget(root, tlist);
262 
263  /* Return the fully-fledged tlist to caller, too */
264  *pTargetList = tlist;
265 
266  /*
267  * Mark rel with estimated output rows, width, etc. Note that we have
268  * to do this before generating outer-query paths, else
269  * cost_subqueryscan is not happy.
270  */
271  set_subquery_size_estimates(root, rel);
272 
273  /*
274  * Since we may want to add a partial path to this relation, we must
275  * set its consider_parallel flag correctly.
276  */
277  final_rel = fetch_upper_rel(subroot, UPPERREL_FINAL, NULL);
278  rel->consider_parallel = final_rel->consider_parallel;
279 
280  /*
281  * For the moment, we consider only a single Path for the subquery.
282  * This should change soon (make it look more like
283  * set_subquery_pathlist).
284  */
286  root->tuple_fraction);
287 
288  /*
289  * Stick a SubqueryScanPath atop that.
290  *
291  * We don't bother to determine the subquery's output ordering since
292  * it won't be reflected in the set-op result anyhow; so just label
293  * the SubqueryScanPath with nil pathkeys. (XXX that should change
294  * soon too, likely.)
295  */
296  path = (Path *) create_subqueryscan_path(root, rel, subpath,
297  trivial_tlist,
298  NIL, NULL);
299 
300  add_path(rel, path);
301 
302  /*
303  * If we have a partial path for the child relation, we can use that
304  * to build a partial path for this relation. But there's no point in
305  * considering any path but the cheapest.
306  */
307  if (rel->consider_parallel && bms_is_empty(rel->lateral_relids) &&
308  final_rel->partial_pathlist != NIL)
309  {
310  Path *partial_subpath;
311  Path *partial_path;
312 
313  partial_subpath = linitial(final_rel->partial_pathlist);
314  partial_path = (Path *)
315  create_subqueryscan_path(root, rel, partial_subpath,
316  trivial_tlist,
317  NIL, NULL);
318  add_partial_path(rel, partial_path);
319  }
320 
321  /*
322  * Estimate number of groups if caller wants it. If the subquery used
323  * grouping or aggregation, its output is probably mostly unique
324  * anyway; otherwise do statistical estimation.
325  *
326  * XXX you don't really want to know about this: we do the estimation
327  * using the subquery's original targetlist expressions, not the
328  * subroot->processed_tlist which might seem more appropriate. The
329  * reason is that if the subquery is itself a setop, it may return a
330  * processed_tlist containing "varno 0" Vars generated by
331  * generate_append_tlist, and those would confuse estimate_num_groups
332  * mightily. We ought to get rid of the "varno 0" hack, but that
333  * requires a redesign of the parsetree representation of setops, so
334  * that there can be an RTE corresponding to each setop's output.
335  */
336  if (pNumGroups)
337  {
338  if (subquery->groupClause || subquery->groupingSets ||
339  subquery->distinctClause ||
340  subroot->hasHavingQual || subquery->hasAggs)
341  *pNumGroups = subpath->rows;
342  else
343  *pNumGroups = estimate_num_groups(subroot,
344  get_tlist_exprs(subquery->targetList, false),
345  subpath->rows,
346  NULL,
347  NULL);
348  }
349  }
350  else if (IsA(setOp, SetOperationStmt))
351  {
352  SetOperationStmt *op = (SetOperationStmt *) setOp;
353 
354  /* UNIONs are much different from INTERSECT/EXCEPT */
355  if (op->op == SETOP_UNION)
356  rel = generate_union_paths(op, root,
357  refnames_tlist,
358  pTargetList);
359  else
360  rel = generate_nonunion_paths(op, root,
361  refnames_tlist,
362  pTargetList);
363  if (pNumGroups)
364  *pNumGroups = rel->rows;
365 
366  /*
367  * If necessary, add a Result node to project the caller-requested
368  * output columns.
369  *
370  * XXX you don't really want to know about this: setrefs.c will apply
371  * fix_upper_expr() to the Result node's tlist. This would fail if the
372  * Vars generated by generate_setop_tlist() were not exactly equal()
373  * to the corresponding tlist entries of the subplan. However, since
374  * the subplan was generated by generate_union_paths() or
375  * generate_nonunion_paths(), and hence its tlist was generated by
376  * generate_append_tlist(), this will work. We just tell
377  * generate_setop_tlist() to use varno 0.
378  */
379  if (flag >= 0 ||
380  !tlist_same_datatypes(*pTargetList, colTypes, junkOK) ||
381  !tlist_same_collations(*pTargetList, colCollations, junkOK))
382  {
383  PathTarget *target;
384  bool trivial_tlist;
385  ListCell *lc;
386 
387  *pTargetList = generate_setop_tlist(colTypes, colCollations,
388  flag,
389  0,
390  false,
391  *pTargetList,
392  refnames_tlist,
393  &trivial_tlist);
394  target = create_pathtarget(root, *pTargetList);
395 
396  /* Apply projection to each path */
397  foreach(lc, rel->pathlist)
398  {
399  Path *subpath = (Path *) lfirst(lc);
400  Path *path;
401 
402  Assert(subpath->param_info == NULL);
403  path = apply_projection_to_path(root, subpath->parent,
404  subpath, target);
405  /* If we had to add a Result, path is different from subpath */
406  if (path != subpath)
407  lfirst(lc) = path;
408  }
409 
410  /* Apply projection to each partial path */
411  foreach(lc, rel->partial_pathlist)
412  {
413  Path *subpath = (Path *) lfirst(lc);
414  Path *path;
415 
416  Assert(subpath->param_info == NULL);
417 
418  /* avoid apply_projection_to_path, in case of multiple refs */
419  path = (Path *) create_projection_path(root, subpath->parent,
420  subpath, target);
421  lfirst(lc) = path;
422  }
423  }
424  }
425  else
426  {
427  elog(ERROR, "unrecognized node type: %d",
428  (int) nodeTag(setOp));
429  *pTargetList = NIL;
430  }
431 
432  postprocess_setop_rel(root, rel);
433 
434  return rel;
435 }
436 
437 /*
438  * Generate paths for a recursive UNION node
439  */
440 static RelOptInfo *
442  List *refnames_tlist,
443  List **pTargetList)
444 {
445  RelOptInfo *result_rel;
446  Path *path;
447  RelOptInfo *lrel,
448  *rrel;
449  Path *lpath;
450  Path *rpath;
451  List *lpath_tlist;
452  List *rpath_tlist;
453  List *tlist;
454  List *groupList;
455  double dNumGroups;
456 
457  /* Parser should have rejected other cases */
458  if (setOp->op != SETOP_UNION)
459  elog(ERROR, "only UNION queries can be recursive");
460  /* Worktable ID should be assigned */
461  Assert(root->wt_param_id >= 0);
462 
463  /*
464  * Unlike a regular UNION node, process the left and right inputs
465  * separately without any intention of combining them into one Append.
466  */
467  lrel = recurse_set_operations(setOp->larg, root,
468  setOp->colTypes, setOp->colCollations,
469  false, -1,
470  refnames_tlist,
471  &lpath_tlist,
472  NULL);
473  lpath = lrel->cheapest_total_path;
474  /* The right path will want to look at the left one ... */
475  root->non_recursive_path = lpath;
476  rrel = recurse_set_operations(setOp->rarg, root,
477  setOp->colTypes, setOp->colCollations,
478  false, -1,
479  refnames_tlist,
480  &rpath_tlist,
481  NULL);
482  rpath = rrel->cheapest_total_path;
483  root->non_recursive_path = NULL;
484 
485  /*
486  * Generate tlist for RecursiveUnion path node --- same as in Append cases
487  */
488  tlist = generate_append_tlist(setOp->colTypes, setOp->colCollations, false,
489  list_make2(lpath_tlist, rpath_tlist),
490  refnames_tlist);
491 
492  *pTargetList = tlist;
493 
494  /* Build result relation. */
495  result_rel = fetch_upper_rel(root, UPPERREL_SETOP,
496  bms_union(lrel->relids, rrel->relids));
497  result_rel->reltarget = create_pathtarget(root, tlist);
498 
499  /*
500  * If UNION, identify the grouping operators
501  */
502  if (setOp->all)
503  {
504  groupList = NIL;
505  dNumGroups = 0;
506  }
507  else
508  {
509  /* Identify the grouping semantics */
510  groupList = generate_setop_grouplist(setOp, tlist);
511 
512  /* We only support hashing here */
513  if (!grouping_is_hashable(groupList))
514  ereport(ERROR,
515  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
516  errmsg("could not implement recursive UNION"),
517  errdetail("All column datatypes must be hashable.")));
518 
519  /*
520  * For the moment, take the number of distinct groups as equal to the
521  * total input size, ie, the worst case.
522  */
523  dNumGroups = lpath->rows + rpath->rows * 10;
524  }
525 
526  /*
527  * And make the path node.
528  */
529  path = (Path *) create_recursiveunion_path(root,
530  result_rel,
531  lpath,
532  rpath,
533  result_rel->reltarget,
534  groupList,
535  root->wt_param_id,
536  dNumGroups);
537 
538  add_path(result_rel, path);
539  postprocess_setop_rel(root, result_rel);
540  return result_rel;
541 }
542 
543 /*
544  * Generate paths for a UNION or UNION ALL node
545  */
546 static RelOptInfo *
548  List *refnames_tlist,
549  List **pTargetList)
550 {
551  Relids relids = NULL;
552  RelOptInfo *result_rel;
553  double save_fraction = root->tuple_fraction;
554  ListCell *lc;
555  List *pathlist = NIL;
556  List *partial_pathlist = NIL;
557  bool partial_paths_valid = true;
558  bool consider_parallel = true;
559  List *rellist;
560  List *tlist_list;
561  List *tlist;
562  Path *path;
563 
564  /*
565  * If plain UNION, tell children to fetch all tuples.
566  *
567  * Note: in UNION ALL, we pass the top-level tuple_fraction unmodified to
568  * each arm of the UNION ALL. One could make a case for reducing the
569  * tuple fraction for later arms (discounting by the expected size of the
570  * earlier arms' results) but it seems not worth the trouble. The normal
571  * case where tuple_fraction isn't already zero is a LIMIT at top level,
572  * and passing it down as-is is usually enough to get the desired result
573  * of preferring fast-start plans.
574  */
575  if (!op->all)
576  root->tuple_fraction = 0.0;
577 
578  /*
579  * If any of my children are identical UNION nodes (same op, all-flag, and
580  * colTypes) then they can be merged into this node so that we generate
581  * only one Append and unique-ification for the lot. Recurse to find such
582  * nodes and compute their children's paths.
583  */
584  rellist = plan_union_children(root, op, refnames_tlist, &tlist_list);
585 
586  /*
587  * Generate tlist for Append plan node.
588  *
589  * The tlist for an Append plan isn't important as far as the Append is
590  * concerned, but we must make it look real anyway for the benefit of the
591  * next plan level up.
592  */
593  tlist = generate_append_tlist(op->colTypes, op->colCollations, false,
594  tlist_list, refnames_tlist);
595 
596  *pTargetList = tlist;
597 
598  /* Build path lists and relid set. */
599  foreach(lc, rellist)
600  {
601  RelOptInfo *rel = lfirst(lc);
602 
603  pathlist = lappend(pathlist, rel->cheapest_total_path);
604 
605  if (consider_parallel)
606  {
607  if (!rel->consider_parallel)
608  {
609  consider_parallel = false;
610  partial_paths_valid = false;
611  }
612  else if (rel->partial_pathlist == NIL)
613  partial_paths_valid = false;
614  else
615  partial_pathlist = lappend(partial_pathlist,
616  linitial(rel->partial_pathlist));
617  }
618 
619  relids = bms_union(relids, rel->relids);
620  }
621 
622  /* Build result relation. */
623  result_rel = fetch_upper_rel(root, UPPERREL_SETOP, relids);
624  result_rel->reltarget = create_pathtarget(root, tlist);
625  result_rel->consider_parallel = consider_parallel;
626 
627  /*
628  * Append the child results together.
629  */
630  path = (Path *) create_append_path(root, result_rel, pathlist, NIL,
631  NIL, NULL, 0, false, -1);
632 
633  /*
634  * For UNION ALL, we just need the Append path. For UNION, need to add
635  * node(s) to remove duplicates.
636  */
637  if (!op->all)
638  path = make_union_unique(op, path, tlist, root);
639 
640  add_path(result_rel, path);
641 
642  /*
643  * Estimate number of groups. For now we just assume the output is unique
644  * --- this is certainly true for the UNION case, and we want worst-case
645  * estimates anyway.
646  */
647  result_rel->rows = path->rows;
648 
649  /*
650  * Now consider doing the same thing using the partial paths plus Append
651  * plus Gather.
652  */
653  if (partial_paths_valid)
654  {
655  Path *ppath;
656  int parallel_workers = 0;
657 
658  /* Find the highest number of workers requested for any subpath. */
659  foreach(lc, partial_pathlist)
660  {
661  Path *subpath = lfirst(lc);
662 
663  parallel_workers = Max(parallel_workers,
664  subpath->parallel_workers);
665  }
666  Assert(parallel_workers > 0);
667 
668  /*
669  * If the use of parallel append is permitted, always request at least
670  * log2(# of children) paths. We assume it can be useful to have
671  * extra workers in this case because they will be spread out across
672  * the children. The precise formula is just a guess; see
673  * add_paths_to_append_rel.
674  */
676  {
677  parallel_workers = Max(parallel_workers,
678  pg_leftmost_one_pos32(list_length(partial_pathlist)) + 1);
679  parallel_workers = Min(parallel_workers,
681  }
682  Assert(parallel_workers > 0);
683 
684  ppath = (Path *)
685  create_append_path(root, result_rel, NIL, partial_pathlist,
686  NIL, NULL,
687  parallel_workers, enable_parallel_append,
688  -1);
689  ppath = (Path *)
690  create_gather_path(root, result_rel, ppath,
691  result_rel->reltarget, NULL, NULL);
692  if (!op->all)
693  ppath = make_union_unique(op, ppath, tlist, root);
694  add_path(result_rel, ppath);
695  }
696 
697  /* Undo effects of possibly forcing tuple_fraction to 0 */
698  root->tuple_fraction = save_fraction;
699 
700  return result_rel;
701 }
702 
703 /*
704  * Generate paths for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node
705  */
706 static RelOptInfo *
708  List *refnames_tlist,
709  List **pTargetList)
710 {
711  RelOptInfo *result_rel;
712  RelOptInfo *lrel,
713  *rrel;
714  double save_fraction = root->tuple_fraction;
715  Path *lpath,
716  *rpath,
717  *path;
718  List *lpath_tlist,
719  *rpath_tlist,
720  *tlist_list,
721  *tlist,
722  *groupList,
723  *pathlist;
724  double dLeftGroups,
725  dRightGroups,
726  dNumGroups,
727  dNumOutputRows;
728  bool use_hash;
729  SetOpCmd cmd;
730  int firstFlag;
731 
732  /*
733  * Tell children to fetch all tuples.
734  */
735  root->tuple_fraction = 0.0;
736 
737  /* Recurse on children, ensuring their outputs are marked */
738  lrel = recurse_set_operations(op->larg, root,
739  op->colTypes, op->colCollations,
740  false, 0,
741  refnames_tlist,
742  &lpath_tlist,
743  &dLeftGroups);
744  lpath = lrel->cheapest_total_path;
745  rrel = recurse_set_operations(op->rarg, root,
746  op->colTypes, op->colCollations,
747  false, 1,
748  refnames_tlist,
749  &rpath_tlist,
750  &dRightGroups);
751  rpath = rrel->cheapest_total_path;
752 
753  /* Undo effects of forcing tuple_fraction to 0 */
754  root->tuple_fraction = save_fraction;
755 
756  /*
757  * For EXCEPT, we must put the left input first. For INTERSECT, either
758  * order should give the same results, and we prefer to put the smaller
759  * input first in order to minimize the size of the hash table in the
760  * hashing case. "Smaller" means the one with the fewer groups.
761  */
762  if (op->op == SETOP_EXCEPT || dLeftGroups <= dRightGroups)
763  {
764  pathlist = list_make2(lpath, rpath);
765  tlist_list = list_make2(lpath_tlist, rpath_tlist);
766  firstFlag = 0;
767  }
768  else
769  {
770  pathlist = list_make2(rpath, lpath);
771  tlist_list = list_make2(rpath_tlist, lpath_tlist);
772  firstFlag = 1;
773  }
774 
775  /*
776  * Generate tlist for Append plan node.
777  *
778  * The tlist for an Append plan isn't important as far as the Append is
779  * concerned, but we must make it look real anyway for the benefit of the
780  * next plan level up. In fact, it has to be real enough that the flag
781  * column is shown as a variable not a constant, else setrefs.c will get
782  * confused.
783  */
784  tlist = generate_append_tlist(op->colTypes, op->colCollations, true,
785  tlist_list, refnames_tlist);
786 
787  *pTargetList = tlist;
788 
789  /* Build result relation. */
790  result_rel = fetch_upper_rel(root, UPPERREL_SETOP,
791  bms_union(lrel->relids, rrel->relids));
792  result_rel->reltarget = create_pathtarget(root, tlist);
793 
794  /*
795  * Append the child results together.
796  */
797  path = (Path *) create_append_path(root, result_rel, pathlist, NIL,
798  NIL, NULL, 0, false, -1);
799 
800  /* Identify the grouping semantics */
801  groupList = generate_setop_grouplist(op, tlist);
802 
803  /*
804  * Estimate number of distinct groups that we'll need hashtable entries
805  * for; this is the size of the left-hand input for EXCEPT, or the smaller
806  * input for INTERSECT. Also estimate the number of eventual output rows.
807  * In non-ALL cases, we estimate each group produces one output row; in
808  * ALL cases use the relevant relation size. These are worst-case
809  * estimates, of course, but we need to be conservative.
810  */
811  if (op->op == SETOP_EXCEPT)
812  {
813  dNumGroups = dLeftGroups;
814  dNumOutputRows = op->all ? lpath->rows : dNumGroups;
815  }
816  else
817  {
818  dNumGroups = Min(dLeftGroups, dRightGroups);
819  dNumOutputRows = op->all ? Min(lpath->rows, rpath->rows) : dNumGroups;
820  }
821 
822  /*
823  * Decide whether to hash or sort, and add a sort node if needed.
824  */
825  use_hash = choose_hashed_setop(root, groupList, path,
826  dNumGroups, dNumOutputRows,
827  (op->op == SETOP_INTERSECT) ? "INTERSECT" : "EXCEPT");
828 
829  if (groupList && !use_hash)
830  path = (Path *) create_sort_path(root,
831  result_rel,
832  path,
834  groupList,
835  tlist),
836  -1.0);
837 
838  /*
839  * Finally, add a SetOp path node to generate the correct output.
840  */
841  switch (op->op)
842  {
843  case SETOP_INTERSECT:
845  break;
846  case SETOP_EXCEPT:
848  break;
849  default:
850  elog(ERROR, "unrecognized set op: %d", (int) op->op);
851  cmd = SETOPCMD_INTERSECT; /* keep compiler quiet */
852  break;
853  }
854  path = (Path *) create_setop_path(root,
855  result_rel,
856  path,
857  cmd,
858  use_hash ? SETOP_HASHED : SETOP_SORTED,
859  groupList,
860  list_length(op->colTypes) + 1,
861  use_hash ? firstFlag : -1,
862  dNumGroups,
863  dNumOutputRows);
864 
865  result_rel->rows = path->rows;
866  add_path(result_rel, path);
867  return result_rel;
868 }
869 
870 /*
871  * Pull up children of a UNION node that are identically-propertied UNIONs.
872  *
873  * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
874  * output rows will be lost anyway.
875  *
876  * NOTE: currently, we ignore collations while determining if a child has
877  * the same properties. This is semantically sound only so long as all
878  * collations have the same notion of equality. It is valid from an
879  * implementation standpoint because we don't care about the ordering of
880  * a UNION child's result: UNION ALL results are always unordered, and
881  * generate_union_paths will force a fresh sort if the top level is a UNION.
882  */
883 static List *
885  SetOperationStmt *top_union,
886  List *refnames_tlist,
887  List **tlist_list)
888 {
889  List *pending_rels = list_make1(top_union);
890  List *result = NIL;
891  List *child_tlist;
892 
893  *tlist_list = NIL;
894 
895  while (pending_rels != NIL)
896  {
897  Node *setOp = linitial(pending_rels);
898 
899  pending_rels = list_delete_first(pending_rels);
900 
901  if (IsA(setOp, SetOperationStmt))
902  {
903  SetOperationStmt *op = (SetOperationStmt *) setOp;
904 
905  if (op->op == top_union->op &&
906  (op->all == top_union->all || op->all) &&
907  equal(op->colTypes, top_union->colTypes))
908  {
909  /* Same UNION, so fold children into parent */
910  pending_rels = lcons(op->rarg, pending_rels);
911  pending_rels = lcons(op->larg, pending_rels);
912  continue;
913  }
914  }
915 
916  /*
917  * Not same, so plan this child separately.
918  *
919  * Note we disallow any resjunk columns in child results. This is
920  * necessary since the Append node that implements the union won't do
921  * any projection, and upper levels will get confused if some of our
922  * output tuples have junk and some don't. This case only arises when
923  * we have an EXCEPT or INTERSECT as child, else there won't be
924  * resjunk anyway.
925  */
926  result = lappend(result, recurse_set_operations(setOp, root,
927  top_union->colTypes,
928  top_union->colCollations,
929  false, -1,
930  refnames_tlist,
931  &child_tlist,
932  NULL));
933  *tlist_list = lappend(*tlist_list, child_tlist);
934  }
935 
936  return result;
937 }
938 
939 /*
940  * Add nodes to the given path tree to unique-ify the result of a UNION.
941  */
942 static Path *
944  PlannerInfo *root)
945 {
946  RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
947  List *groupList;
948  double dNumGroups;
949 
950  /* Identify the grouping semantics */
951  groupList = generate_setop_grouplist(op, tlist);
952 
953  /*
954  * XXX for the moment, take the number of distinct groups as equal to the
955  * total input size, ie, the worst case. This is too conservative, but
956  * it's not clear how to get a decent estimate of the true size. One
957  * should note as well the propensity of novices to write UNION rather
958  * than UNION ALL even when they don't expect any duplicates...
959  */
960  dNumGroups = path->rows;
961 
962  /* Decide whether to hash or sort */
963  if (choose_hashed_setop(root, groupList, path,
964  dNumGroups, dNumGroups,
965  "UNION"))
966  {
967  /* Hashed aggregate plan --- no sort needed */
968  path = (Path *) create_agg_path(root,
969  result_rel,
970  path,
971  create_pathtarget(root, tlist),
972  AGG_HASHED,
974  groupList,
975  NIL,
976  NULL,
977  dNumGroups);
978  }
979  else
980  {
981  /* Sort and Unique */
982  if (groupList)
983  path = (Path *)
984  create_sort_path(root,
985  result_rel,
986  path,
988  groupList,
989  tlist),
990  -1.0);
991  path = (Path *) create_upper_unique_path(root,
992  result_rel,
993  path,
994  list_length(path->pathkeys),
995  dNumGroups);
996  }
997 
998  return path;
999 }
1000 
1001 /*
1002  * postprocess_setop_rel - perform steps required after adding paths
1003  */
1004 static void
1006 {
1007  /*
1008  * We don't currently worry about allowing FDWs to contribute paths to
1009  * this relation, but give extensions a chance.
1010  */
1012  (*create_upper_paths_hook) (root, UPPERREL_SETOP,
1013  NULL, rel, NULL);
1014 
1015  /* Select cheapest path */
1016  set_cheapest(rel);
1017 }
1018 
1019 /*
1020  * choose_hashed_setop - should we use hashing for a set operation?
1021  */
1022 static bool
1023 choose_hashed_setop(PlannerInfo *root, List *groupClauses,
1024  Path *input_path,
1025  double dNumGroups, double dNumOutputRows,
1026  const char *construct)
1027 {
1028  int numGroupCols = list_length(groupClauses);
1029  Size hash_mem_limit = get_hash_memory_limit();
1030  bool can_sort;
1031  bool can_hash;
1032  Size hashentrysize;
1033  Path hashed_p;
1034  Path sorted_p;
1035  double tuple_fraction;
1036 
1037  /* Check whether the operators support sorting or hashing */
1038  can_sort = grouping_is_sortable(groupClauses);
1039  can_hash = grouping_is_hashable(groupClauses);
1040  if (can_hash && can_sort)
1041  {
1042  /* we have a meaningful choice to make, continue ... */
1043  }
1044  else if (can_hash)
1045  return true;
1046  else if (can_sort)
1047  return false;
1048  else
1049  ereport(ERROR,
1050  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1051  /* translator: %s is UNION, INTERSECT, or EXCEPT */
1052  errmsg("could not implement %s", construct),
1053  errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
1054 
1055  /* Prefer sorting when enable_hashagg is off */
1056  if (!enable_hashagg)
1057  return false;
1058 
1059  /*
1060  * Don't do it if it doesn't look like the hashtable will fit into
1061  * hash_mem.
1062  */
1063  hashentrysize = MAXALIGN(input_path->pathtarget->width) + MAXALIGN(SizeofMinimalTupleHeader);
1064 
1065  if (hashentrysize * dNumGroups > hash_mem_limit)
1066  return false;
1067 
1068  /*
1069  * See if the estimated cost is no more than doing it the other way.
1070  *
1071  * We need to consider input_plan + hashagg versus input_plan + sort +
1072  * group. Note that the actual result plan might involve a SetOp or
1073  * Unique node, not Agg or Group, but the cost estimates for Agg and Group
1074  * should be close enough for our purposes here.
1075  *
1076  * These path variables are dummies that just hold cost fields; we don't
1077  * make actual Paths for these steps.
1078  */
1079  cost_agg(&hashed_p, root, AGG_HASHED, NULL,
1080  numGroupCols, dNumGroups,
1081  NIL,
1082  input_path->startup_cost, input_path->total_cost,
1083  input_path->rows, input_path->pathtarget->width);
1084 
1085  /*
1086  * Now for the sorted case. Note that the input is *always* unsorted,
1087  * since it was made by appending unrelated sub-relations together.
1088  */
1089  sorted_p.startup_cost = input_path->startup_cost;
1090  sorted_p.total_cost = input_path->total_cost;
1091  /* XXX cost_sort doesn't actually look at pathkeys, so just pass NIL */
1092  cost_sort(&sorted_p, root, NIL, sorted_p.total_cost,
1093  input_path->rows, input_path->pathtarget->width,
1094  0.0, work_mem, -1.0);
1095  cost_group(&sorted_p, root, numGroupCols, dNumGroups,
1096  NIL,
1097  sorted_p.startup_cost, sorted_p.total_cost,
1098  input_path->rows);
1099 
1100  /*
1101  * Now make the decision using the top-level tuple fraction. First we
1102  * have to convert an absolute count (LIMIT) into fractional form.
1103  */
1104  tuple_fraction = root->tuple_fraction;
1105  if (tuple_fraction >= 1.0)
1106  tuple_fraction /= dNumOutputRows;
1107 
1108  if (compare_fractional_path_costs(&hashed_p, &sorted_p,
1109  tuple_fraction) < 0)
1110  {
1111  /* Hashed is cheaper, so use it */
1112  return true;
1113  }
1114  return false;
1115 }
1116 
1117 /*
1118  * Generate targetlist for a set-operation plan node
1119  *
1120  * colTypes: OID list of set-op's result column datatypes
1121  * colCollations: OID list of set-op's result column collations
1122  * flag: -1 if no flag column needed, 0 or 1 to create a const flag column
1123  * varno: varno to use in generated Vars
1124  * hack_constants: true to copy up constants (see comments in code)
1125  * input_tlist: targetlist of this node's input node
1126  * refnames_tlist: targetlist to take column names from
1127  * trivial_tlist: output parameter, set to true if targetlist is trivial
1128  */
1129 static List *
1130 generate_setop_tlist(List *colTypes, List *colCollations,
1131  int flag,
1132  Index varno,
1133  bool hack_constants,
1134  List *input_tlist,
1135  List *refnames_tlist,
1136  bool *trivial_tlist)
1137 {
1138  List *tlist = NIL;
1139  int resno = 1;
1140  ListCell *ctlc,
1141  *cclc,
1142  *itlc,
1143  *rtlc;
1144  TargetEntry *tle;
1145  Node *expr;
1146 
1147  *trivial_tlist = true; /* until proven differently */
1148 
1149  forfour(ctlc, colTypes, cclc, colCollations,
1150  itlc, input_tlist, rtlc, refnames_tlist)
1151  {
1152  Oid colType = lfirst_oid(ctlc);
1153  Oid colColl = lfirst_oid(cclc);
1154  TargetEntry *inputtle = (TargetEntry *) lfirst(itlc);
1155  TargetEntry *reftle = (TargetEntry *) lfirst(rtlc);
1156 
1157  Assert(inputtle->resno == resno);
1158  Assert(reftle->resno == resno);
1159  Assert(!inputtle->resjunk);
1160  Assert(!reftle->resjunk);
1161 
1162  /*
1163  * Generate columns referencing input columns and having appropriate
1164  * data types and column names. Insert datatype coercions where
1165  * necessary.
1166  *
1167  * HACK: constants in the input's targetlist are copied up as-is
1168  * rather than being referenced as subquery outputs. This is mainly
1169  * to ensure that when we try to coerce them to the output column's
1170  * datatype, the right things happen for UNKNOWN constants. But do
1171  * this only at the first level of subquery-scan plans; we don't want
1172  * phony constants appearing in the output tlists of upper-level
1173  * nodes!
1174  *
1175  * Note that copying a constant doesn't in itself require us to mark
1176  * the tlist nontrivial; see trivial_subqueryscan() in setrefs.c.
1177  */
1178  if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
1179  expr = (Node *) inputtle->expr;
1180  else
1181  expr = (Node *) makeVar(varno,
1182  inputtle->resno,
1183  exprType((Node *) inputtle->expr),
1184  exprTypmod((Node *) inputtle->expr),
1185  exprCollation((Node *) inputtle->expr),
1186  0);
1187 
1188  if (exprType(expr) != colType)
1189  {
1190  /*
1191  * Note: it's not really cool to be applying coerce_to_common_type
1192  * here; one notable point is that assign_expr_collations never
1193  * gets run on any generated nodes. For the moment that's not a
1194  * problem because we force the correct exposed collation below.
1195  * It would likely be best to make the parser generate the correct
1196  * output tlist for every set-op to begin with, though.
1197  */
1198  expr = coerce_to_common_type(NULL, /* no UNKNOWNs here */
1199  expr,
1200  colType,
1201  "UNION/INTERSECT/EXCEPT");
1202  *trivial_tlist = false; /* the coercion makes it not trivial */
1203  }
1204 
1205  /*
1206  * Ensure the tlist entry's exposed collation matches the set-op. This
1207  * is necessary because plan_set_operations() reports the result
1208  * ordering as a list of SortGroupClauses, which don't carry collation
1209  * themselves but just refer to tlist entries. If we don't show the
1210  * right collation then planner.c might do the wrong thing in
1211  * higher-level queries.
1212  *
1213  * Note we use RelabelType, not CollateExpr, since this expression
1214  * will reach the executor without any further processing.
1215  */
1216  if (exprCollation(expr) != colColl)
1217  {
1218  expr = applyRelabelType(expr,
1219  exprType(expr), exprTypmod(expr), colColl,
1220  COERCE_IMPLICIT_CAST, -1, false);
1221  *trivial_tlist = false; /* the relabel makes it not trivial */
1222  }
1223 
1224  tle = makeTargetEntry((Expr *) expr,
1225  (AttrNumber) resno++,
1226  pstrdup(reftle->resname),
1227  false);
1228 
1229  /*
1230  * By convention, all non-resjunk columns in a setop tree have
1231  * ressortgroupref equal to their resno. In some cases the ref isn't
1232  * needed, but this is a cleaner way than modifying the tlist later.
1233  */
1234  tle->ressortgroupref = tle->resno;
1235 
1236  tlist = lappend(tlist, tle);
1237  }
1238 
1239  if (flag >= 0)
1240  {
1241  /* Add a resjunk flag column */
1242  /* flag value is the given constant */
1243  expr = (Node *) makeConst(INT4OID,
1244  -1,
1245  InvalidOid,
1246  sizeof(int32),
1248  false,
1249  true);
1250  tle = makeTargetEntry((Expr *) expr,
1251  (AttrNumber) resno++,
1252  pstrdup("flag"),
1253  true);
1254  tlist = lappend(tlist, tle);
1255  *trivial_tlist = false; /* the extra entry makes it not trivial */
1256  }
1257 
1258  return tlist;
1259 }
1260 
1261 /*
1262  * Generate targetlist for a set-operation Append node
1263  *
1264  * colTypes: OID list of set-op's result column datatypes
1265  * colCollations: OID list of set-op's result column collations
1266  * flag: true to create a flag column copied up from subplans
1267  * input_tlists: list of tlists for sub-plans of the Append
1268  * refnames_tlist: targetlist to take column names from
1269  *
1270  * The entries in the Append's targetlist should always be simple Vars;
1271  * we just have to make sure they have the right datatypes/typmods/collations.
1272  * The Vars are always generated with varno 0.
1273  *
1274  * XXX a problem with the varno-zero approach is that set_pathtarget_cost_width
1275  * cannot figure out a realistic width for the tlist we make here. But we
1276  * ought to refactor this code to produce a PathTarget directly, anyway.
1277  */
1278 static List *
1279 generate_append_tlist(List *colTypes, List *colCollations,
1280  bool flag,
1281  List *input_tlists,
1282  List *refnames_tlist)
1283 {
1284  List *tlist = NIL;
1285  int resno = 1;
1286  ListCell *curColType;
1287  ListCell *curColCollation;
1288  ListCell *ref_tl_item;
1289  int colindex;
1290  TargetEntry *tle;
1291  Node *expr;
1292  ListCell *tlistl;
1293  int32 *colTypmods;
1294 
1295  /*
1296  * First extract typmods to use.
1297  *
1298  * If the inputs all agree on type and typmod of a particular column, use
1299  * that typmod; else use -1.
1300  */
1301  colTypmods = (int32 *) palloc(list_length(colTypes) * sizeof(int32));
1302 
1303  foreach(tlistl, input_tlists)
1304  {
1305  List *subtlist = (List *) lfirst(tlistl);
1306  ListCell *subtlistl;
1307 
1308  curColType = list_head(colTypes);
1309  colindex = 0;
1310  foreach(subtlistl, subtlist)
1311  {
1312  TargetEntry *subtle = (TargetEntry *) lfirst(subtlistl);
1313 
1314  if (subtle->resjunk)
1315  continue;
1316  Assert(curColType != NULL);
1317  if (exprType((Node *) subtle->expr) == lfirst_oid(curColType))
1318  {
1319  /* If first subplan, copy the typmod; else compare */
1320  int32 subtypmod = exprTypmod((Node *) subtle->expr);
1321 
1322  if (tlistl == list_head(input_tlists))
1323  colTypmods[colindex] = subtypmod;
1324  else if (subtypmod != colTypmods[colindex])
1325  colTypmods[colindex] = -1;
1326  }
1327  else
1328  {
1329  /* types disagree, so force typmod to -1 */
1330  colTypmods[colindex] = -1;
1331  }
1332  curColType = lnext(colTypes, curColType);
1333  colindex++;
1334  }
1335  Assert(curColType == NULL);
1336  }
1337 
1338  /*
1339  * Now we can build the tlist for the Append.
1340  */
1341  colindex = 0;
1342  forthree(curColType, colTypes, curColCollation, colCollations,
1343  ref_tl_item, refnames_tlist)
1344  {
1345  Oid colType = lfirst_oid(curColType);
1346  int32 colTypmod = colTypmods[colindex++];
1347  Oid colColl = lfirst_oid(curColCollation);
1348  TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item);
1349 
1350  Assert(reftle->resno == resno);
1351  Assert(!reftle->resjunk);
1352  expr = (Node *) makeVar(0,
1353  resno,
1354  colType,
1355  colTypmod,
1356  colColl,
1357  0);
1358  tle = makeTargetEntry((Expr *) expr,
1359  (AttrNumber) resno++,
1360  pstrdup(reftle->resname),
1361  false);
1362 
1363  /*
1364  * By convention, all non-resjunk columns in a setop tree have
1365  * ressortgroupref equal to their resno. In some cases the ref isn't
1366  * needed, but this is a cleaner way than modifying the tlist later.
1367  */
1368  tle->ressortgroupref = tle->resno;
1369 
1370  tlist = lappend(tlist, tle);
1371  }
1372 
1373  if (flag)
1374  {
1375  /* Add a resjunk flag column */
1376  /* flag value is shown as copied up from subplan */
1377  expr = (Node *) makeVar(0,
1378  resno,
1379  INT4OID,
1380  -1,
1381  InvalidOid,
1382  0);
1383  tle = makeTargetEntry((Expr *) expr,
1384  (AttrNumber) resno++,
1385  pstrdup("flag"),
1386  true);
1387  tlist = lappend(tlist, tle);
1388  }
1389 
1390  pfree(colTypmods);
1391 
1392  return tlist;
1393 }
1394 
1395 /*
1396  * generate_setop_grouplist
1397  * Build a SortGroupClause list defining the sort/grouping properties
1398  * of the setop's output columns.
1399  *
1400  * Parse analysis already determined the properties and built a suitable
1401  * list, except that the entries do not have sortgrouprefs set because
1402  * the parser output representation doesn't include a tlist for each
1403  * setop. So what we need to do here is copy that list and install
1404  * proper sortgrouprefs into it (copying those from the targetlist).
1405  */
1406 static List *
1408 {
1409  List *grouplist = copyObject(op->groupClauses);
1410  ListCell *lg;
1411  ListCell *lt;
1412 
1413  lg = list_head(grouplist);
1414  foreach(lt, targetlist)
1415  {
1416  TargetEntry *tle = (TargetEntry *) lfirst(lt);
1417  SortGroupClause *sgc;
1418 
1419  if (tle->resjunk)
1420  {
1421  /* resjunk columns should not have sortgrouprefs */
1422  Assert(tle->ressortgroupref == 0);
1423  continue; /* ignore resjunk columns */
1424  }
1425 
1426  /* non-resjunk columns should have sortgroupref = resno */
1427  Assert(tle->ressortgroupref == tle->resno);
1428 
1429  /* non-resjunk columns should have grouping clauses */
1430  Assert(lg != NULL);
1431  sgc = (SortGroupClause *) lfirst(lg);
1432  lg = lnext(grouplist, lg);
1433  Assert(sgc->tleSortGroupRef == 0);
1434 
1435  sgc->tleSortGroupRef = tle->ressortgroupref;
1436  }
1437  Assert(lg == NULL);
1438  return grouplist;
1439 }
int16 AttrNumber
Definition: attnum.h:21
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:211
#define bms_is_empty(a)
Definition: bitmapset.h:105
#define Min(x, y)
Definition: c.h:993
#define MAXALIGN(LEN)
Definition: c.h:800
signed int int32
Definition: c.h:483
#define Max(x, y)
Definition: c.h:987
unsigned int Index
Definition: c.h:603
size_t Size
Definition: c.h:594
int max_parallel_workers_per_gather
Definition: costsize.c:133
void cost_agg(Path *path, PlannerInfo *root, AggStrategy aggstrategy, const AggClauseCosts *aggcosts, int numGroupCols, double numGroups, List *quals, Cost input_startup_cost, Cost input_total_cost, double input_tuples, double input_width)
Definition: costsize.c:2622
void set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel)
Definition: costsize.c:5794
bool enable_parallel_append
Definition: costsize.c:151
bool enable_hashagg
Definition: costsize.c:142
void cost_sort(Path *path, PlannerInfo *root, List *pathkeys, Cost input_cost, double tuples, int width, Cost comparison_cost, int sort_mem, double limit_tuples)
Definition: costsize.c:2096
void cost_group(Path *path, PlannerInfo *root, int numGroupCols, double numGroups, List *quals, Cost input_startup_cost, Cost input_total_cost, double input_tuples)
Definition: costsize.c:3135
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
int work_mem
Definition: globals.c:125
#define SizeofMinimalTupleHeader
Definition: htup_details.h:647
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
List * list_delete_first(List *list)
Definition: list.c:942
List * lcons(void *datum, List *list)
Definition: list.c:494
Datum subpath(PG_FUNCTION_ARGS)
Definition: ltree_op.c:241
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:241
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:302
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
char * pstrdup(const char *in)
Definition: mcxt.c:1644
void pfree(void *pointer)
Definition: mcxt.c:1456
void * palloc(Size size)
Definition: mcxt.c:1226
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:282
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:786
Node * applyRelabelType(Node *arg, Oid rtype, int32 rtypmod, Oid rcollid, CoercionForm rformat, int rlocation, bool overwrite_ok)
Definition: nodeFuncs.c:601
size_t get_hash_memory_limit(void)
Definition: nodeHash.c:3592
SetOpCmd
Definition: nodes.h:407
@ SETOPCMD_EXCEPT
Definition: nodes.h:410
@ SETOPCMD_EXCEPT_ALL
Definition: nodes.h:411
@ SETOPCMD_INTERSECT_ALL
Definition: nodes.h:409
@ SETOPCMD_INTERSECT
Definition: nodes.h:408
@ SETOP_HASHED
Definition: nodes.h:417
@ SETOP_SORTED
Definition: nodes.h:416
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
#define copyObject(obj)
Definition: nodes.h:244
#define nodeTag(nodeptr)
Definition: nodes.h:133
@ AGG_HASHED
Definition: nodes.h:366
@ AGGSPLIT_SIMPLE
Definition: nodes.h:387
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
Node * coerce_to_common_type(ParseState *pstate, Node *node, Oid targetTypeId, const char *context)
@ SETOP_INTERSECT
Definition: parsenodes.h:1974
@ SETOP_UNION
Definition: parsenodes.h:1973
@ SETOP_EXCEPT
Definition: parsenodes.h:1975
List * make_pathkeys_for_sortclauses(PlannerInfo *root, List *sortclauses, List *tlist)
Definition: pathkeys.c:1133
AppendPath * create_append_path(PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *partial_subpaths, List *pathkeys, Relids required_outer, int parallel_workers, bool parallel_aware, double rows)
Definition: pathnode.c:1242
SortPath * create_sort_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, double limit_tuples)
Definition: pathnode.c:2959
ProjectionPath * create_projection_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
Definition: pathnode.c:2644
UpperUniquePath * create_upper_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, int numCols, double numGroups)
Definition: pathnode.c:3062
GatherPath * create_gather_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, Relids required_outer, double *rows)
Definition: pathnode.c:1964
void set_cheapest(RelOptInfo *parent_rel)
Definition: pathnode.c:244
SubqueryScanPath * create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, bool trivial_pathtarget, List *pathkeys, Relids required_outer)
Definition: pathnode.c:2008
void add_partial_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:749
int compare_fractional_path_costs(Path *path1, Path *path2, double fraction)
Definition: pathnode.c:117
SetOpPath * create_setop_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, SetOpCmd cmd, SetOpStrategy strategy, List *distinctList, AttrNumber flagColIdx, int firstFlag, double numGroups, double outputRows)
Definition: pathnode.c:3495
RecursiveUnionPath * create_recursiveunion_path(PlannerInfo *root, RelOptInfo *rel, Path *leftpath, Path *rightpath, PathTarget *target, List *distinctList, int wtParam, double numGroups)
Definition: pathnode.c:3557
AggPath * create_agg_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, AggStrategy aggstrategy, AggSplit aggsplit, List *groupClause, List *qual, const AggClauseCosts *aggcosts, double numGroups)
Definition: pathnode.c:3114
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:422
Path * apply_projection_to_path(PlannerInfo *root, RelOptInfo *rel, Path *path, PathTarget *target)
Definition: pathnode.c:2752
@ UPPERREL_SETOP
Definition: pathnodes.h:71
@ UPPERREL_FINAL
Definition: pathnodes.h:79
static int pg_leftmost_one_pos32(uint32 word)
Definition: pg_bitutils.h:41
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define list_make1(x1)
Definition: pg_list.h:212
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition: pg_list.h:512
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
#define linitial(l)
Definition: pg_list.h:178
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4)
Definition: pg_list.h:524
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define lfirst_oid(lc)
Definition: pg_list.h:174
#define list_make2(x1, x2)
Definition: pg_list.h:214
PlannerInfo * subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, bool hasRecursion, double tuple_fraction)
Definition: planner.c:623
create_upper_paths_hook_type create_upper_paths_hook
Definition: planner.c:80
Path * get_cheapest_fractional_path(RelOptInfo *rel, double tuple_fraction)
Definition: planner.c:6329
void check_stack_depth(void)
Definition: postgres.c:3523
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
static List * generate_setop_tlist(List *colTypes, List *colCollations, int flag, Index varno, bool hack_constants, List *input_tlist, List *refnames_tlist, bool *trivial_tlist)
Definition: prepunion.c:1130
static Path * make_union_unique(SetOperationStmt *op, Path *path, List *tlist, PlannerInfo *root)
Definition: prepunion.c:943
static List * generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
Definition: prepunion.c:1407
static RelOptInfo * generate_union_paths(SetOperationStmt *op, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition: prepunion.c:547
static List * plan_union_children(PlannerInfo *root, SetOperationStmt *top_union, List *refnames_tlist, List **tlist_list)
Definition: prepunion.c:884
static RelOptInfo * generate_nonunion_paths(SetOperationStmt *op, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition: prepunion.c:707
static void postprocess_setop_rel(PlannerInfo *root, RelOptInfo *rel)
Definition: prepunion.c:1005
static bool choose_hashed_setop(PlannerInfo *root, List *groupClauses, Path *input_path, double dNumGroups, double dNumOutputRows, const char *construct)
Definition: prepunion.c:1023
static List * generate_append_tlist(List *colTypes, List *colCollations, bool flag, List *input_tlists, List *refnames_tlist)
Definition: prepunion.c:1279
static RelOptInfo * generate_recursion_path(SetOperationStmt *setOp, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition: prepunion.c:441
static RelOptInfo * recurse_set_operations(Node *setOp, PlannerInfo *root, List *colTypes, List *colCollations, bool junkOK, int flag, List *refnames_tlist, List **pTargetList, double *pNumGroups)
Definition: prepunion.c:208
RelOptInfo * plan_set_operations(PlannerInfo *root)
Definition: prepunion.c:104
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:663
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:715
void setup_simple_rel_arrays(PlannerInfo *root)
Definition: relnode.c:93
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:191
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1445
double estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, List **pgset, EstimationInfo *estinfo)
Definition: selfuncs.c:3386
Definition: pg_list.h:54
Definition: nodes.h:129
List * pathkeys
Definition: pathnodes.h:1633
Cardinality rows
Definition: pathnodes.h:1628
Cost startup_cost
Definition: pathnodes.h:1629
Cost total_cost
Definition: pathnodes.h:1630
List * processed_tlist
Definition: pathnodes.h:453
bool hasRecursion
Definition: pathnodes.h:501
bool hasHavingQual
Definition: pathnodes.h:493
bool ec_merging_done
Definition: pathnodes.h:314
struct Path * non_recursive_path
Definition: pathnodes.h:523
PlannerGlobal * glob
Definition: pathnodes.h:202
List * eq_classes
Definition: pathnodes.h:311
int wt_param_id
Definition: pathnodes.h:521
List * plan_params
Definition: pathnodes.h:217
Query * parse
Definition: pathnodes.h:199
Selectivity tuple_fraction
Definition: pathnodes.h:478
List * groupClause
Definition: parsenodes.h:197
List * targetList
Definition: parsenodes.h:188
List * groupingSets
Definition: parsenodes.h:200
List * distinctClause
Definition: parsenodes.h:206
Query * subquery
Definition: parsenodes.h:1080
Relids relids
Definition: pathnodes.h:856
struct PathTarget * reltarget
Definition: pathnodes.h:878
bool consider_parallel
Definition: pathnodes.h:872
Relids lateral_relids
Definition: pathnodes.h:898
List * pathlist
Definition: pathnodes.h:883
struct Path * cheapest_total_path
Definition: pathnodes.h:887
List * partial_pathlist
Definition: pathnodes.h:885
PlannerInfo * subroot
Definition: pathnodes.h:932
Cardinality rows
Definition: pathnodes.h:862
SetOperation op
Definition: parsenodes.h:2050
Index tleSortGroupRef
Definition: parsenodes.h:1392
Expr * expr
Definition: primnodes.h:1895
AttrNumber resno
Definition: primnodes.h:1897
Index ressortgroupref
Definition: primnodes.h:1901
char * flag(int b)
Definition: test-ctype.c:33
bool tlist_same_collations(List *tlist, List *colCollations, bool junkOK)
Definition: tlist.c:282
List * get_tlist_exprs(List *tlist, bool includeJunk)
Definition: tlist.c:163
bool grouping_is_sortable(List *groupClause)
Definition: tlist.c:540
bool grouping_is_hashable(List *groupClause)
Definition: tlist.c:560
bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
Definition: tlist.c:248
#define create_pathtarget(root, tlist)
Definition: tlist.h:53