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-2024, 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 subroot->parse'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  * Note, we use this not subquery's targetlist but subroot->parse's
336  * targetlist, because it was revised by self-join removal. subquery's
337  * targetlist might contain the references to the removed relids.
338  */
339  if (pNumGroups)
340  {
341  if (subquery->groupClause || subquery->groupingSets ||
342  subquery->distinctClause ||
343  subroot->hasHavingQual || subquery->hasAggs)
344  *pNumGroups = subpath->rows;
345  else
346  *pNumGroups = estimate_num_groups(subroot,
347  get_tlist_exprs(subroot->parse->targetList, false),
348  subpath->rows,
349  NULL,
350  NULL);
351  }
352  }
353  else if (IsA(setOp, SetOperationStmt))
354  {
355  SetOperationStmt *op = (SetOperationStmt *) setOp;
356 
357  /* UNIONs are much different from INTERSECT/EXCEPT */
358  if (op->op == SETOP_UNION)
359  rel = generate_union_paths(op, root,
360  refnames_tlist,
361  pTargetList);
362  else
363  rel = generate_nonunion_paths(op, root,
364  refnames_tlist,
365  pTargetList);
366  if (pNumGroups)
367  *pNumGroups = rel->rows;
368 
369  /*
370  * If necessary, add a Result node to project the caller-requested
371  * output columns.
372  *
373  * XXX you don't really want to know about this: setrefs.c will apply
374  * fix_upper_expr() to the Result node's tlist. This would fail if the
375  * Vars generated by generate_setop_tlist() were not exactly equal()
376  * to the corresponding tlist entries of the subplan. However, since
377  * the subplan was generated by generate_union_paths() or
378  * generate_nonunion_paths(), and hence its tlist was generated by
379  * generate_append_tlist(), this will work. We just tell
380  * generate_setop_tlist() to use varno 0.
381  */
382  if (flag >= 0 ||
383  !tlist_same_datatypes(*pTargetList, colTypes, junkOK) ||
384  !tlist_same_collations(*pTargetList, colCollations, junkOK))
385  {
386  PathTarget *target;
387  bool trivial_tlist;
388  ListCell *lc;
389 
390  *pTargetList = generate_setop_tlist(colTypes, colCollations,
391  flag,
392  0,
393  false,
394  *pTargetList,
395  refnames_tlist,
396  &trivial_tlist);
397  target = create_pathtarget(root, *pTargetList);
398 
399  /* Apply projection to each path */
400  foreach(lc, rel->pathlist)
401  {
402  Path *subpath = (Path *) lfirst(lc);
403  Path *path;
404 
405  Assert(subpath->param_info == NULL);
406  path = apply_projection_to_path(root, subpath->parent,
407  subpath, target);
408  /* If we had to add a Result, path is different from subpath */
409  if (path != subpath)
410  lfirst(lc) = path;
411  }
412 
413  /* Apply projection to each partial path */
414  foreach(lc, rel->partial_pathlist)
415  {
416  Path *subpath = (Path *) lfirst(lc);
417  Path *path;
418 
419  Assert(subpath->param_info == NULL);
420 
421  /* avoid apply_projection_to_path, in case of multiple refs */
422  path = (Path *) create_projection_path(root, subpath->parent,
423  subpath, target);
424  lfirst(lc) = path;
425  }
426  }
427  }
428  else
429  {
430  elog(ERROR, "unrecognized node type: %d",
431  (int) nodeTag(setOp));
432  *pTargetList = NIL;
433  }
434 
435  postprocess_setop_rel(root, rel);
436 
437  return rel;
438 }
439 
440 /*
441  * Generate paths for a recursive UNION node
442  */
443 static RelOptInfo *
445  List *refnames_tlist,
446  List **pTargetList)
447 {
448  RelOptInfo *result_rel;
449  Path *path;
450  RelOptInfo *lrel,
451  *rrel;
452  Path *lpath;
453  Path *rpath;
454  List *lpath_tlist;
455  List *rpath_tlist;
456  List *tlist;
457  List *groupList;
458  double dNumGroups;
459 
460  /* Parser should have rejected other cases */
461  if (setOp->op != SETOP_UNION)
462  elog(ERROR, "only UNION queries can be recursive");
463  /* Worktable ID should be assigned */
464  Assert(root->wt_param_id >= 0);
465 
466  /*
467  * Unlike a regular UNION node, process the left and right inputs
468  * separately without any intention of combining them into one Append.
469  */
470  lrel = recurse_set_operations(setOp->larg, root,
471  setOp->colTypes, setOp->colCollations,
472  false, -1,
473  refnames_tlist,
474  &lpath_tlist,
475  NULL);
476  lpath = lrel->cheapest_total_path;
477  /* The right path will want to look at the left one ... */
478  root->non_recursive_path = lpath;
479  rrel = recurse_set_operations(setOp->rarg, root,
480  setOp->colTypes, setOp->colCollations,
481  false, -1,
482  refnames_tlist,
483  &rpath_tlist,
484  NULL);
485  rpath = rrel->cheapest_total_path;
486  root->non_recursive_path = NULL;
487 
488  /*
489  * Generate tlist for RecursiveUnion path node --- same as in Append cases
490  */
491  tlist = generate_append_tlist(setOp->colTypes, setOp->colCollations, false,
492  list_make2(lpath_tlist, rpath_tlist),
493  refnames_tlist);
494 
495  *pTargetList = tlist;
496 
497  /* Build result relation. */
498  result_rel = fetch_upper_rel(root, UPPERREL_SETOP,
499  bms_union(lrel->relids, rrel->relids));
500  result_rel->reltarget = create_pathtarget(root, tlist);
501 
502  /*
503  * If UNION, identify the grouping operators
504  */
505  if (setOp->all)
506  {
507  groupList = NIL;
508  dNumGroups = 0;
509  }
510  else
511  {
512  /* Identify the grouping semantics */
513  groupList = generate_setop_grouplist(setOp, tlist);
514 
515  /* We only support hashing here */
516  if (!grouping_is_hashable(groupList))
517  ereport(ERROR,
518  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
519  errmsg("could not implement recursive UNION"),
520  errdetail("All column datatypes must be hashable.")));
521 
522  /*
523  * For the moment, take the number of distinct groups as equal to the
524  * total input size, ie, the worst case.
525  */
526  dNumGroups = lpath->rows + rpath->rows * 10;
527  }
528 
529  /*
530  * And make the path node.
531  */
532  path = (Path *) create_recursiveunion_path(root,
533  result_rel,
534  lpath,
535  rpath,
536  result_rel->reltarget,
537  groupList,
538  root->wt_param_id,
539  dNumGroups);
540 
541  add_path(result_rel, path);
542  postprocess_setop_rel(root, result_rel);
543  return result_rel;
544 }
545 
546 /*
547  * Generate paths for a UNION or UNION ALL node
548  */
549 static RelOptInfo *
551  List *refnames_tlist,
552  List **pTargetList)
553 {
554  Relids relids = NULL;
555  RelOptInfo *result_rel;
556  double save_fraction = root->tuple_fraction;
557  ListCell *lc;
558  List *pathlist = NIL;
559  List *partial_pathlist = NIL;
560  bool partial_paths_valid = true;
561  bool consider_parallel = true;
562  List *rellist;
563  List *tlist_list;
564  List *tlist;
565  Path *path;
566 
567  /*
568  * If plain UNION, tell children to fetch all tuples.
569  *
570  * Note: in UNION ALL, we pass the top-level tuple_fraction unmodified to
571  * each arm of the UNION ALL. One could make a case for reducing the
572  * tuple fraction for later arms (discounting by the expected size of the
573  * earlier arms' results) but it seems not worth the trouble. The normal
574  * case where tuple_fraction isn't already zero is a LIMIT at top level,
575  * and passing it down as-is is usually enough to get the desired result
576  * of preferring fast-start plans.
577  */
578  if (!op->all)
579  root->tuple_fraction = 0.0;
580 
581  /*
582  * If any of my children are identical UNION nodes (same op, all-flag, and
583  * colTypes) then they can be merged into this node so that we generate
584  * only one Append and unique-ification for the lot. Recurse to find such
585  * nodes and compute their children's paths.
586  */
587  rellist = plan_union_children(root, op, refnames_tlist, &tlist_list);
588 
589  /*
590  * Generate tlist for Append plan node.
591  *
592  * The tlist for an Append plan isn't important as far as the Append is
593  * concerned, but we must make it look real anyway for the benefit of the
594  * next plan level up.
595  */
596  tlist = generate_append_tlist(op->colTypes, op->colCollations, false,
597  tlist_list, refnames_tlist);
598 
599  *pTargetList = tlist;
600 
601  /* Build path lists and relid set. */
602  foreach(lc, rellist)
603  {
604  RelOptInfo *rel = lfirst(lc);
605 
606  pathlist = lappend(pathlist, rel->cheapest_total_path);
607 
608  if (consider_parallel)
609  {
610  if (!rel->consider_parallel)
611  {
612  consider_parallel = false;
613  partial_paths_valid = false;
614  }
615  else if (rel->partial_pathlist == NIL)
616  partial_paths_valid = false;
617  else
618  partial_pathlist = lappend(partial_pathlist,
619  linitial(rel->partial_pathlist));
620  }
621 
622  relids = bms_union(relids, rel->relids);
623  }
624 
625  /* Build result relation. */
626  result_rel = fetch_upper_rel(root, UPPERREL_SETOP, relids);
627  result_rel->reltarget = create_pathtarget(root, tlist);
628  result_rel->consider_parallel = consider_parallel;
629 
630  /*
631  * Append the child results together.
632  */
633  path = (Path *) create_append_path(root, result_rel, pathlist, NIL,
634  NIL, NULL, 0, false, -1);
635 
636  /*
637  * For UNION ALL, we just need the Append path. For UNION, need to add
638  * node(s) to remove duplicates.
639  */
640  if (!op->all)
641  path = make_union_unique(op, path, tlist, root);
642 
643  add_path(result_rel, path);
644 
645  /*
646  * Estimate number of groups. For now we just assume the output is unique
647  * --- this is certainly true for the UNION case, and we want worst-case
648  * estimates anyway.
649  */
650  result_rel->rows = path->rows;
651 
652  /*
653  * Now consider doing the same thing using the partial paths plus Append
654  * plus Gather.
655  */
656  if (partial_paths_valid)
657  {
658  Path *ppath;
659  int parallel_workers = 0;
660 
661  /* Find the highest number of workers requested for any subpath. */
662  foreach(lc, partial_pathlist)
663  {
664  Path *subpath = lfirst(lc);
665 
666  parallel_workers = Max(parallel_workers,
667  subpath->parallel_workers);
668  }
669  Assert(parallel_workers > 0);
670 
671  /*
672  * If the use of parallel append is permitted, always request at least
673  * log2(# of children) paths. We assume it can be useful to have
674  * extra workers in this case because they will be spread out across
675  * the children. The precise formula is just a guess; see
676  * add_paths_to_append_rel.
677  */
679  {
680  parallel_workers = Max(parallel_workers,
681  pg_leftmost_one_pos32(list_length(partial_pathlist)) + 1);
682  parallel_workers = Min(parallel_workers,
684  }
685  Assert(parallel_workers > 0);
686 
687  ppath = (Path *)
688  create_append_path(root, result_rel, NIL, partial_pathlist,
689  NIL, NULL,
690  parallel_workers, enable_parallel_append,
691  -1);
692  ppath = (Path *)
693  create_gather_path(root, result_rel, ppath,
694  result_rel->reltarget, NULL, NULL);
695  if (!op->all)
696  ppath = make_union_unique(op, ppath, tlist, root);
697  add_path(result_rel, ppath);
698  }
699 
700  /* Undo effects of possibly forcing tuple_fraction to 0 */
701  root->tuple_fraction = save_fraction;
702 
703  return result_rel;
704 }
705 
706 /*
707  * Generate paths for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node
708  */
709 static RelOptInfo *
711  List *refnames_tlist,
712  List **pTargetList)
713 {
714  RelOptInfo *result_rel;
715  RelOptInfo *lrel,
716  *rrel;
717  double save_fraction = root->tuple_fraction;
718  Path *lpath,
719  *rpath,
720  *path;
721  List *lpath_tlist,
722  *rpath_tlist,
723  *tlist_list,
724  *tlist,
725  *groupList,
726  *pathlist;
727  double dLeftGroups,
728  dRightGroups,
729  dNumGroups,
730  dNumOutputRows;
731  bool use_hash;
732  SetOpCmd cmd;
733  int firstFlag;
734 
735  /*
736  * Tell children to fetch all tuples.
737  */
738  root->tuple_fraction = 0.0;
739 
740  /* Recurse on children, ensuring their outputs are marked */
741  lrel = recurse_set_operations(op->larg, root,
742  op->colTypes, op->colCollations,
743  false, 0,
744  refnames_tlist,
745  &lpath_tlist,
746  &dLeftGroups);
747  lpath = lrel->cheapest_total_path;
748  rrel = recurse_set_operations(op->rarg, root,
749  op->colTypes, op->colCollations,
750  false, 1,
751  refnames_tlist,
752  &rpath_tlist,
753  &dRightGroups);
754  rpath = rrel->cheapest_total_path;
755 
756  /* Undo effects of forcing tuple_fraction to 0 */
757  root->tuple_fraction = save_fraction;
758 
759  /*
760  * For EXCEPT, we must put the left input first. For INTERSECT, either
761  * order should give the same results, and we prefer to put the smaller
762  * input first in order to minimize the size of the hash table in the
763  * hashing case. "Smaller" means the one with the fewer groups.
764  */
765  if (op->op == SETOP_EXCEPT || dLeftGroups <= dRightGroups)
766  {
767  pathlist = list_make2(lpath, rpath);
768  tlist_list = list_make2(lpath_tlist, rpath_tlist);
769  firstFlag = 0;
770  }
771  else
772  {
773  pathlist = list_make2(rpath, lpath);
774  tlist_list = list_make2(rpath_tlist, lpath_tlist);
775  firstFlag = 1;
776  }
777 
778  /*
779  * Generate tlist for Append plan node.
780  *
781  * The tlist for an Append plan isn't important as far as the Append is
782  * concerned, but we must make it look real anyway for the benefit of the
783  * next plan level up. In fact, it has to be real enough that the flag
784  * column is shown as a variable not a constant, else setrefs.c will get
785  * confused.
786  */
787  tlist = generate_append_tlist(op->colTypes, op->colCollations, true,
788  tlist_list, refnames_tlist);
789 
790  *pTargetList = tlist;
791 
792  /* Build result relation. */
793  result_rel = fetch_upper_rel(root, UPPERREL_SETOP,
794  bms_union(lrel->relids, rrel->relids));
795  result_rel->reltarget = create_pathtarget(root, tlist);
796 
797  /*
798  * Append the child results together.
799  */
800  path = (Path *) create_append_path(root, result_rel, pathlist, NIL,
801  NIL, NULL, 0, false, -1);
802 
803  /* Identify the grouping semantics */
804  groupList = generate_setop_grouplist(op, tlist);
805 
806  /*
807  * Estimate number of distinct groups that we'll need hashtable entries
808  * for; this is the size of the left-hand input for EXCEPT, or the smaller
809  * input for INTERSECT. Also estimate the number of eventual output rows.
810  * In non-ALL cases, we estimate each group produces one output row; in
811  * ALL cases use the relevant relation size. These are worst-case
812  * estimates, of course, but we need to be conservative.
813  */
814  if (op->op == SETOP_EXCEPT)
815  {
816  dNumGroups = dLeftGroups;
817  dNumOutputRows = op->all ? lpath->rows : dNumGroups;
818  }
819  else
820  {
821  dNumGroups = Min(dLeftGroups, dRightGroups);
822  dNumOutputRows = op->all ? Min(lpath->rows, rpath->rows) : dNumGroups;
823  }
824 
825  /*
826  * Decide whether to hash or sort, and add a sort node if needed.
827  */
828  use_hash = choose_hashed_setop(root, groupList, path,
829  dNumGroups, dNumOutputRows,
830  (op->op == SETOP_INTERSECT) ? "INTERSECT" : "EXCEPT");
831 
832  if (groupList && !use_hash)
833  path = (Path *) create_sort_path(root,
834  result_rel,
835  path,
837  groupList,
838  tlist),
839  -1.0);
840 
841  /*
842  * Finally, add a SetOp path node to generate the correct output.
843  */
844  switch (op->op)
845  {
846  case SETOP_INTERSECT:
848  break;
849  case SETOP_EXCEPT:
851  break;
852  default:
853  elog(ERROR, "unrecognized set op: %d", (int) op->op);
854  cmd = SETOPCMD_INTERSECT; /* keep compiler quiet */
855  break;
856  }
857  path = (Path *) create_setop_path(root,
858  result_rel,
859  path,
860  cmd,
861  use_hash ? SETOP_HASHED : SETOP_SORTED,
862  groupList,
863  list_length(op->colTypes) + 1,
864  use_hash ? firstFlag : -1,
865  dNumGroups,
866  dNumOutputRows);
867 
868  result_rel->rows = path->rows;
869  add_path(result_rel, path);
870  return result_rel;
871 }
872 
873 /*
874  * Pull up children of a UNION node that are identically-propertied UNIONs.
875  *
876  * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
877  * output rows will be lost anyway.
878  *
879  * NOTE: currently, we ignore collations while determining if a child has
880  * the same properties. This is semantically sound only so long as all
881  * collations have the same notion of equality. It is valid from an
882  * implementation standpoint because we don't care about the ordering of
883  * a UNION child's result: UNION ALL results are always unordered, and
884  * generate_union_paths will force a fresh sort if the top level is a UNION.
885  */
886 static List *
888  SetOperationStmt *top_union,
889  List *refnames_tlist,
890  List **tlist_list)
891 {
892  List *pending_rels = list_make1(top_union);
893  List *result = NIL;
894  List *child_tlist;
895 
896  *tlist_list = NIL;
897 
898  while (pending_rels != NIL)
899  {
900  Node *setOp = linitial(pending_rels);
901 
902  pending_rels = list_delete_first(pending_rels);
903 
904  if (IsA(setOp, SetOperationStmt))
905  {
906  SetOperationStmt *op = (SetOperationStmt *) setOp;
907 
908  if (op->op == top_union->op &&
909  (op->all == top_union->all || op->all) &&
910  equal(op->colTypes, top_union->colTypes))
911  {
912  /* Same UNION, so fold children into parent */
913  pending_rels = lcons(op->rarg, pending_rels);
914  pending_rels = lcons(op->larg, pending_rels);
915  continue;
916  }
917  }
918 
919  /*
920  * Not same, so plan this child separately.
921  *
922  * Note we disallow any resjunk columns in child results. This is
923  * necessary since the Append node that implements the union won't do
924  * any projection, and upper levels will get confused if some of our
925  * output tuples have junk and some don't. This case only arises when
926  * we have an EXCEPT or INTERSECT as child, else there won't be
927  * resjunk anyway.
928  */
929  result = lappend(result, recurse_set_operations(setOp, root,
930  top_union->colTypes,
931  top_union->colCollations,
932  false, -1,
933  refnames_tlist,
934  &child_tlist,
935  NULL));
936  *tlist_list = lappend(*tlist_list, child_tlist);
937  }
938 
939  return result;
940 }
941 
942 /*
943  * Add nodes to the given path tree to unique-ify the result of a UNION.
944  */
945 static Path *
947  PlannerInfo *root)
948 {
949  RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
950  List *groupList;
951  double dNumGroups;
952 
953  /* Identify the grouping semantics */
954  groupList = generate_setop_grouplist(op, tlist);
955 
956  /*
957  * XXX for the moment, take the number of distinct groups as equal to the
958  * total input size, ie, the worst case. This is too conservative, but
959  * it's not clear how to get a decent estimate of the true size. One
960  * should note as well the propensity of novices to write UNION rather
961  * than UNION ALL even when they don't expect any duplicates...
962  */
963  dNumGroups = path->rows;
964 
965  /* Decide whether to hash or sort */
966  if (choose_hashed_setop(root, groupList, path,
967  dNumGroups, dNumGroups,
968  "UNION"))
969  {
970  /* Hashed aggregate plan --- no sort needed */
971  path = (Path *) create_agg_path(root,
972  result_rel,
973  path,
974  create_pathtarget(root, tlist),
975  AGG_HASHED,
977  groupList,
978  NIL,
979  NULL,
980  dNumGroups);
981  }
982  else
983  {
984  /* Sort and Unique */
985  if (groupList)
986  path = (Path *)
987  create_sort_path(root,
988  result_rel,
989  path,
991  groupList,
992  tlist),
993  -1.0);
994  path = (Path *) create_upper_unique_path(root,
995  result_rel,
996  path,
997  list_length(path->pathkeys),
998  dNumGroups);
999  }
1000 
1001  return path;
1002 }
1003 
1004 /*
1005  * postprocess_setop_rel - perform steps required after adding paths
1006  */
1007 static void
1009 {
1010  /*
1011  * We don't currently worry about allowing FDWs to contribute paths to
1012  * this relation, but give extensions a chance.
1013  */
1015  (*create_upper_paths_hook) (root, UPPERREL_SETOP,
1016  NULL, rel, NULL);
1017 
1018  /* Select cheapest path */
1019  set_cheapest(rel);
1020 }
1021 
1022 /*
1023  * choose_hashed_setop - should we use hashing for a set operation?
1024  */
1025 static bool
1026 choose_hashed_setop(PlannerInfo *root, List *groupClauses,
1027  Path *input_path,
1028  double dNumGroups, double dNumOutputRows,
1029  const char *construct)
1030 {
1031  int numGroupCols = list_length(groupClauses);
1032  Size hash_mem_limit = get_hash_memory_limit();
1033  bool can_sort;
1034  bool can_hash;
1035  Size hashentrysize;
1036  Path hashed_p;
1037  Path sorted_p;
1038  double tuple_fraction;
1039 
1040  /* Check whether the operators support sorting or hashing */
1041  can_sort = grouping_is_sortable(groupClauses);
1042  can_hash = grouping_is_hashable(groupClauses);
1043  if (can_hash && can_sort)
1044  {
1045  /* we have a meaningful choice to make, continue ... */
1046  }
1047  else if (can_hash)
1048  return true;
1049  else if (can_sort)
1050  return false;
1051  else
1052  ereport(ERROR,
1053  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1054  /* translator: %s is UNION, INTERSECT, or EXCEPT */
1055  errmsg("could not implement %s", construct),
1056  errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
1057 
1058  /* Prefer sorting when enable_hashagg is off */
1059  if (!enable_hashagg)
1060  return false;
1061 
1062  /*
1063  * Don't do it if it doesn't look like the hashtable will fit into
1064  * hash_mem.
1065  */
1066  hashentrysize = MAXALIGN(input_path->pathtarget->width) + MAXALIGN(SizeofMinimalTupleHeader);
1067 
1068  if (hashentrysize * dNumGroups > hash_mem_limit)
1069  return false;
1070 
1071  /*
1072  * See if the estimated cost is no more than doing it the other way.
1073  *
1074  * We need to consider input_plan + hashagg versus input_plan + sort +
1075  * group. Note that the actual result plan might involve a SetOp or
1076  * Unique node, not Agg or Group, but the cost estimates for Agg and Group
1077  * should be close enough for our purposes here.
1078  *
1079  * These path variables are dummies that just hold cost fields; we don't
1080  * make actual Paths for these steps.
1081  */
1082  cost_agg(&hashed_p, root, AGG_HASHED, NULL,
1083  numGroupCols, dNumGroups,
1084  NIL,
1085  input_path->startup_cost, input_path->total_cost,
1086  input_path->rows, input_path->pathtarget->width);
1087 
1088  /*
1089  * Now for the sorted case. Note that the input is *always* unsorted,
1090  * since it was made by appending unrelated sub-relations together.
1091  */
1092  sorted_p.startup_cost = input_path->startup_cost;
1093  sorted_p.total_cost = input_path->total_cost;
1094  /* XXX cost_sort doesn't actually look at pathkeys, so just pass NIL */
1095  cost_sort(&sorted_p, root, NIL, sorted_p.total_cost,
1096  input_path->rows, input_path->pathtarget->width,
1097  0.0, work_mem, -1.0);
1098  cost_group(&sorted_p, root, numGroupCols, dNumGroups,
1099  NIL,
1100  sorted_p.startup_cost, sorted_p.total_cost,
1101  input_path->rows);
1102 
1103  /*
1104  * Now make the decision using the top-level tuple fraction. First we
1105  * have to convert an absolute count (LIMIT) into fractional form.
1106  */
1107  tuple_fraction = root->tuple_fraction;
1108  if (tuple_fraction >= 1.0)
1109  tuple_fraction /= dNumOutputRows;
1110 
1111  if (compare_fractional_path_costs(&hashed_p, &sorted_p,
1112  tuple_fraction) < 0)
1113  {
1114  /* Hashed is cheaper, so use it */
1115  return true;
1116  }
1117  return false;
1118 }
1119 
1120 /*
1121  * Generate targetlist for a set-operation plan node
1122  *
1123  * colTypes: OID list of set-op's result column datatypes
1124  * colCollations: OID list of set-op's result column collations
1125  * flag: -1 if no flag column needed, 0 or 1 to create a const flag column
1126  * varno: varno to use in generated Vars
1127  * hack_constants: true to copy up constants (see comments in code)
1128  * input_tlist: targetlist of this node's input node
1129  * refnames_tlist: targetlist to take column names from
1130  * trivial_tlist: output parameter, set to true if targetlist is trivial
1131  */
1132 static List *
1133 generate_setop_tlist(List *colTypes, List *colCollations,
1134  int flag,
1135  Index varno,
1136  bool hack_constants,
1137  List *input_tlist,
1138  List *refnames_tlist,
1139  bool *trivial_tlist)
1140 {
1141  List *tlist = NIL;
1142  int resno = 1;
1143  ListCell *ctlc,
1144  *cclc,
1145  *itlc,
1146  *rtlc;
1147  TargetEntry *tle;
1148  Node *expr;
1149 
1150  *trivial_tlist = true; /* until proven differently */
1151 
1152  forfour(ctlc, colTypes, cclc, colCollations,
1153  itlc, input_tlist, rtlc, refnames_tlist)
1154  {
1155  Oid colType = lfirst_oid(ctlc);
1156  Oid colColl = lfirst_oid(cclc);
1157  TargetEntry *inputtle = (TargetEntry *) lfirst(itlc);
1158  TargetEntry *reftle = (TargetEntry *) lfirst(rtlc);
1159 
1160  Assert(inputtle->resno == resno);
1161  Assert(reftle->resno == resno);
1162  Assert(!inputtle->resjunk);
1163  Assert(!reftle->resjunk);
1164 
1165  /*
1166  * Generate columns referencing input columns and having appropriate
1167  * data types and column names. Insert datatype coercions where
1168  * necessary.
1169  *
1170  * HACK: constants in the input's targetlist are copied up as-is
1171  * rather than being referenced as subquery outputs. This is mainly
1172  * to ensure that when we try to coerce them to the output column's
1173  * datatype, the right things happen for UNKNOWN constants. But do
1174  * this only at the first level of subquery-scan plans; we don't want
1175  * phony constants appearing in the output tlists of upper-level
1176  * nodes!
1177  *
1178  * Note that copying a constant doesn't in itself require us to mark
1179  * the tlist nontrivial; see trivial_subqueryscan() in setrefs.c.
1180  */
1181  if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
1182  expr = (Node *) inputtle->expr;
1183  else
1184  expr = (Node *) makeVar(varno,
1185  inputtle->resno,
1186  exprType((Node *) inputtle->expr),
1187  exprTypmod((Node *) inputtle->expr),
1188  exprCollation((Node *) inputtle->expr),
1189  0);
1190 
1191  if (exprType(expr) != colType)
1192  {
1193  /*
1194  * Note: it's not really cool to be applying coerce_to_common_type
1195  * here; one notable point is that assign_expr_collations never
1196  * gets run on any generated nodes. For the moment that's not a
1197  * problem because we force the correct exposed collation below.
1198  * It would likely be best to make the parser generate the correct
1199  * output tlist for every set-op to begin with, though.
1200  */
1201  expr = coerce_to_common_type(NULL, /* no UNKNOWNs here */
1202  expr,
1203  colType,
1204  "UNION/INTERSECT/EXCEPT");
1205  *trivial_tlist = false; /* the coercion makes it not trivial */
1206  }
1207 
1208  /*
1209  * Ensure the tlist entry's exposed collation matches the set-op. This
1210  * is necessary because plan_set_operations() reports the result
1211  * ordering as a list of SortGroupClauses, which don't carry collation
1212  * themselves but just refer to tlist entries. If we don't show the
1213  * right collation then planner.c might do the wrong thing in
1214  * higher-level queries.
1215  *
1216  * Note we use RelabelType, not CollateExpr, since this expression
1217  * will reach the executor without any further processing.
1218  */
1219  if (exprCollation(expr) != colColl)
1220  {
1221  expr = applyRelabelType(expr,
1222  exprType(expr), exprTypmod(expr), colColl,
1223  COERCE_IMPLICIT_CAST, -1, false);
1224  *trivial_tlist = false; /* the relabel makes it not trivial */
1225  }
1226 
1227  tle = makeTargetEntry((Expr *) expr,
1228  (AttrNumber) resno++,
1229  pstrdup(reftle->resname),
1230  false);
1231 
1232  /*
1233  * By convention, all non-resjunk columns in a setop tree have
1234  * ressortgroupref equal to their resno. In some cases the ref isn't
1235  * needed, but this is a cleaner way than modifying the tlist later.
1236  */
1237  tle->ressortgroupref = tle->resno;
1238 
1239  tlist = lappend(tlist, tle);
1240  }
1241 
1242  if (flag >= 0)
1243  {
1244  /* Add a resjunk flag column */
1245  /* flag value is the given constant */
1246  expr = (Node *) makeConst(INT4OID,
1247  -1,
1248  InvalidOid,
1249  sizeof(int32),
1251  false,
1252  true);
1253  tle = makeTargetEntry((Expr *) expr,
1254  (AttrNumber) resno++,
1255  pstrdup("flag"),
1256  true);
1257  tlist = lappend(tlist, tle);
1258  *trivial_tlist = false; /* the extra entry makes it not trivial */
1259  }
1260 
1261  return tlist;
1262 }
1263 
1264 /*
1265  * Generate targetlist for a set-operation Append node
1266  *
1267  * colTypes: OID list of set-op's result column datatypes
1268  * colCollations: OID list of set-op's result column collations
1269  * flag: true to create a flag column copied up from subplans
1270  * input_tlists: list of tlists for sub-plans of the Append
1271  * refnames_tlist: targetlist to take column names from
1272  *
1273  * The entries in the Append's targetlist should always be simple Vars;
1274  * we just have to make sure they have the right datatypes/typmods/collations.
1275  * The Vars are always generated with varno 0.
1276  *
1277  * XXX a problem with the varno-zero approach is that set_pathtarget_cost_width
1278  * cannot figure out a realistic width for the tlist we make here. But we
1279  * ought to refactor this code to produce a PathTarget directly, anyway.
1280  */
1281 static List *
1282 generate_append_tlist(List *colTypes, List *colCollations,
1283  bool flag,
1284  List *input_tlists,
1285  List *refnames_tlist)
1286 {
1287  List *tlist = NIL;
1288  int resno = 1;
1289  ListCell *curColType;
1290  ListCell *curColCollation;
1291  ListCell *ref_tl_item;
1292  int colindex;
1293  TargetEntry *tle;
1294  Node *expr;
1295  ListCell *tlistl;
1296  int32 *colTypmods;
1297 
1298  /*
1299  * First extract typmods to use.
1300  *
1301  * If the inputs all agree on type and typmod of a particular column, use
1302  * that typmod; else use -1.
1303  */
1304  colTypmods = (int32 *) palloc(list_length(colTypes) * sizeof(int32));
1305 
1306  foreach(tlistl, input_tlists)
1307  {
1308  List *subtlist = (List *) lfirst(tlistl);
1309  ListCell *subtlistl;
1310 
1311  curColType = list_head(colTypes);
1312  colindex = 0;
1313  foreach(subtlistl, subtlist)
1314  {
1315  TargetEntry *subtle = (TargetEntry *) lfirst(subtlistl);
1316 
1317  if (subtle->resjunk)
1318  continue;
1319  Assert(curColType != NULL);
1320  if (exprType((Node *) subtle->expr) == lfirst_oid(curColType))
1321  {
1322  /* If first subplan, copy the typmod; else compare */
1323  int32 subtypmod = exprTypmod((Node *) subtle->expr);
1324 
1325  if (tlistl == list_head(input_tlists))
1326  colTypmods[colindex] = subtypmod;
1327  else if (subtypmod != colTypmods[colindex])
1328  colTypmods[colindex] = -1;
1329  }
1330  else
1331  {
1332  /* types disagree, so force typmod to -1 */
1333  colTypmods[colindex] = -1;
1334  }
1335  curColType = lnext(colTypes, curColType);
1336  colindex++;
1337  }
1338  Assert(curColType == NULL);
1339  }
1340 
1341  /*
1342  * Now we can build the tlist for the Append.
1343  */
1344  colindex = 0;
1345  forthree(curColType, colTypes, curColCollation, colCollations,
1346  ref_tl_item, refnames_tlist)
1347  {
1348  Oid colType = lfirst_oid(curColType);
1349  int32 colTypmod = colTypmods[colindex++];
1350  Oid colColl = lfirst_oid(curColCollation);
1351  TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item);
1352 
1353  Assert(reftle->resno == resno);
1354  Assert(!reftle->resjunk);
1355  expr = (Node *) makeVar(0,
1356  resno,
1357  colType,
1358  colTypmod,
1359  colColl,
1360  0);
1361  tle = makeTargetEntry((Expr *) expr,
1362  (AttrNumber) resno++,
1363  pstrdup(reftle->resname),
1364  false);
1365 
1366  /*
1367  * By convention, all non-resjunk columns in a setop tree have
1368  * ressortgroupref equal to their resno. In some cases the ref isn't
1369  * needed, but this is a cleaner way than modifying the tlist later.
1370  */
1371  tle->ressortgroupref = tle->resno;
1372 
1373  tlist = lappend(tlist, tle);
1374  }
1375 
1376  if (flag)
1377  {
1378  /* Add a resjunk flag column */
1379  /* flag value is shown as copied up from subplan */
1380  expr = (Node *) makeVar(0,
1381  resno,
1382  INT4OID,
1383  -1,
1384  InvalidOid,
1385  0);
1386  tle = makeTargetEntry((Expr *) expr,
1387  (AttrNumber) resno++,
1388  pstrdup("flag"),
1389  true);
1390  tlist = lappend(tlist, tle);
1391  }
1392 
1393  pfree(colTypmods);
1394 
1395  return tlist;
1396 }
1397 
1398 /*
1399  * generate_setop_grouplist
1400  * Build a SortGroupClause list defining the sort/grouping properties
1401  * of the setop's output columns.
1402  *
1403  * Parse analysis already determined the properties and built a suitable
1404  * list, except that the entries do not have sortgrouprefs set because
1405  * the parser output representation doesn't include a tlist for each
1406  * setop. So what we need to do here is copy that list and install
1407  * proper sortgrouprefs into it (copying those from the targetlist).
1408  */
1409 static List *
1411 {
1412  List *grouplist = copyObject(op->groupClauses);
1413  ListCell *lg;
1414  ListCell *lt;
1415 
1416  lg = list_head(grouplist);
1417  foreach(lt, targetlist)
1418  {
1419  TargetEntry *tle = (TargetEntry *) lfirst(lt);
1420  SortGroupClause *sgc;
1421 
1422  if (tle->resjunk)
1423  {
1424  /* resjunk columns should not have sortgrouprefs */
1425  Assert(tle->ressortgroupref == 0);
1426  continue; /* ignore resjunk columns */
1427  }
1428 
1429  /* non-resjunk columns should have sortgroupref = resno */
1430  Assert(tle->ressortgroupref == tle->resno);
1431 
1432  /* non-resjunk columns should have grouping clauses */
1433  Assert(lg != NULL);
1434  sgc = (SortGroupClause *) lfirst(lg);
1435  lg = lnext(grouplist, lg);
1436  Assert(sgc->tleSortGroupRef == 0);
1437 
1438  sgc->tleSortGroupRef = tle->ressortgroupref;
1439  }
1440  Assert(lg == NULL);
1441  return grouplist;
1442 }
int16 AttrNumber
Definition: attnum.h:21
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:264
#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:2651
void set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel)
Definition: costsize.c:5823
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:2125
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:3164
int errdetail(const char *fmt,...)
Definition: elog.c:1208
int errcode(int sqlerrcode)
Definition: elog.c:860
int errmsg(const char *fmt,...)
Definition: elog.c:1075
#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:128
#define SizeofMinimalTupleHeader
Definition: htup_details.h:647
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:339
List * list_delete_first(List *list)
Definition: list.c:943
List * lcons(void *datum, List *list)
Definition: list.c:495
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:1619
void pfree(void *pointer)
Definition: mcxt.c:1431
void * palloc(Size size)
Definition: mcxt.c:1201
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:3596
SetOpCmd
Definition: nodes.h:386
@ SETOPCMD_EXCEPT
Definition: nodes.h:389
@ SETOPCMD_EXCEPT_ALL
Definition: nodes.h:390
@ SETOPCMD_INTERSECT_ALL
Definition: nodes.h:388
@ SETOPCMD_INTERSECT
Definition: nodes.h:387
@ SETOP_HASHED
Definition: nodes.h:396
@ SETOP_SORTED
Definition: nodes.h:395
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define copyObject(obj)
Definition: nodes.h:223
#define nodeTag(nodeptr)
Definition: nodes.h:133
@ AGG_HASHED
Definition: nodes.h:345
@ AGGSPLIT_SIMPLE
Definition: nodes.h:366
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
Node * coerce_to_common_type(ParseState *pstate, Node *node, Oid targetTypeId, const char *context)
@ SETOP_INTERSECT
Definition: parsenodes.h:1950
@ SETOP_UNION
Definition: parsenodes.h:1949
@ SETOP_EXCEPT
Definition: parsenodes.h:1951
List * make_pathkeys_for_sortclauses(PlannerInfo *root, List *sortclauses, List *tlist)
Definition: pathkeys.c:1349
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:1246
SortPath * create_sort_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, double limit_tuples)
Definition: pathnode.c:2990
ProjectionPath * create_projection_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
Definition: pathnode.c:2675
UpperUniquePath * create_upper_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, int numCols, double numGroups)
Definition: pathnode.c:3093
GatherPath * create_gather_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, Relids required_outer, double *rows)
Definition: pathnode.c:1973
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:2017
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:3542
RecursiveUnionPath * create_recursiveunion_path(PlannerInfo *root, RelOptInfo *rel, Path *leftpath, Path *rightpath, PathTarget *target, List *distinctList, int wtParam, double numGroups)
Definition: pathnode.c:3604
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:3145
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:2783
@ 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:563
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:575
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:625
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:6248
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:1133
static Path * make_union_unique(SetOperationStmt *op, Path *path, List *tlist, PlannerInfo *root)
Definition: prepunion.c:946
static List * generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
Definition: prepunion.c:1410
static RelOptInfo * generate_union_paths(SetOperationStmt *op, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition: prepunion.c:550
static List * plan_union_children(PlannerInfo *root, SetOperationStmt *top_union, List *refnames_tlist, List **tlist_list)
Definition: prepunion.c:887
static RelOptInfo * generate_nonunion_paths(SetOperationStmt *op, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition: prepunion.c:710
static void postprocess_setop_rel(PlannerInfo *root, RelOptInfo *rel)
Definition: prepunion.c:1008
static bool choose_hashed_setop(PlannerInfo *root, List *groupClauses, Path *input_path, double dNumGroups, double dNumOutputRows, const char *construct)
Definition: prepunion.c:1026
static List * generate_append_tlist(List *colTypes, List *colCollations, bool flag, List *input_tlists, List *refnames_tlist)
Definition: prepunion.c:1282
static RelOptInfo * generate_recursion_path(SetOperationStmt *setOp, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition: prepunion.c:444
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:671
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:94
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:192
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1463
double estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, List **pgset, EstimationInfo *estinfo)
Definition: selfuncs.c:3416
Definition: pg_list.h:54
Definition: nodes.h:129
List * pathkeys
Definition: pathnodes.h:1645
Cardinality rows
Definition: pathnodes.h:1640
Cost startup_cost
Definition: pathnodes.h:1641
Cost total_cost
Definition: pathnodes.h:1642
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:190
List * targetList
Definition: parsenodes.h:181
List * groupingSets
Definition: parsenodes.h:193
List * distinctClause
Definition: parsenodes.h:199
Query * subquery
Definition: parsenodes.h:1073
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:934
Cardinality rows
Definition: pathnodes.h:862
SetOperation op
Definition: parsenodes.h:2026
Index tleSortGroupRef
Definition: parsenodes.h:1385
Expr * expr
Definition: primnodes.h:1922
AttrNumber resno
Definition: primnodes.h:1924
Index ressortgroupref
Definition: primnodes.h:1928
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