PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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 <math.h>
27
28#include "access/htup_details.h"
29#include "catalog/pg_type.h"
30#include "miscadmin.h"
31#include "nodes/makefuncs.h"
32#include "nodes/nodeFuncs.h"
33#include "optimizer/cost.h"
34#include "optimizer/pathnode.h"
35#include "optimizer/paths.h"
36#include "optimizer/planner.h"
37#include "optimizer/prep.h"
38#include "optimizer/tlist.h"
39#include "parser/parse_coerce.h"
40#include "port/pg_bitutils.h"
41#include "utils/selfuncs.h"
42
43
49 bool *istrivial_tlist);
57 double *pNumGroups);
71 Index varno,
72 bool hack_constants,
75 bool *trivial_tlist);
79static List *generate_setop_grouplist(SetOperationStmt *op, List *targetlist);
82
83
84/*
85 * plan_set_operations
86 *
87 * Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT)
88 *
89 * This routine only deals with the setOperations tree of the given query.
90 * Any top-level ORDER BY requested in root->parse->sortClause will be handled
91 * when we return to grouping_planner; likewise for LIMIT.
92 *
93 * What we return is an "upperrel" RelOptInfo containing at least one Path
94 * that implements the set-operation tree. In addition, root->processed_tlist
95 * receives a targetlist representing the output of the topmost setop node.
96 */
99{
100 Query *parse = root->parse;
102 Node *node;
107
108 Assert(topop);
109
110 /* check for unsupported stuff */
111 Assert(parse->jointree->fromlist == NIL);
112 Assert(parse->jointree->quals == NULL);
113 Assert(parse->groupClause == NIL);
114 Assert(parse->havingQual == NULL);
115 Assert(parse->windowClause == NIL);
116 Assert(parse->distinctClause == NIL);
117
118 /*
119 * In the outer query level, equivalence classes are limited to classes
120 * which define that the top-level target entry is equivalent to the
121 * corresponding child target entry. There won't be any equivalence class
122 * merging. Mark that merging is complete to allow us to make pathkeys.
123 */
124 Assert(root->eq_classes == NIL);
125 root->ec_merging_done = true;
126
127 /*
128 * We'll need to build RelOptInfos for each of the leaf subqueries, which
129 * are RTE_SUBQUERY rangetable entries in this Query. Prepare the index
130 * arrays for those, and for AppendRelInfos in case they're needed.
131 */
133
134 /*
135 * Find the leftmost component Query. We need to use its column names for
136 * all generated tlists (else SELECT INTO won't work right).
137 */
138 node = topop->larg;
139 while (node && IsA(node, SetOperationStmt))
140 node = ((SetOperationStmt *) node)->larg;
141 Assert(node && IsA(node, RangeTblRef));
142 leftmostRTE = root->simple_rte_array[((RangeTblRef *) node)->rtindex];
143 leftmostQuery = leftmostRTE->subquery;
145
146 /*
147 * If the topmost node is a recursive union, it needs special processing.
148 */
149 if (root->hasRecursion)
150 {
152 leftmostQuery->targetList,
153 &top_tlist);
154 }
155 else
156 {
157 bool trivial_tlist;
158
159 /*
160 * Recurse on setOperations tree to generate paths for set ops. The
161 * final output paths should have just the column types shown as the
162 * output from the top-level node.
163 */
165 NULL, /* no parent */
166 topop->colTypes, topop->colCollations,
167 leftmostQuery->targetList,
168 &top_tlist,
170 }
171
172 /* Must return the built tlist into root->processed_tlist. */
173 root->processed_tlist = top_tlist;
174
175 return setop_rel;
176}
177
178/*
179 * recurse_set_operations
180 * Recursively handle one step in a tree of set operations
181 *
182 * setOp: current step (could be a SetOperationStmt or a leaf RangeTblRef)
183 * parentOp: parent step, or NULL if none (but see below)
184 * colTypes: OID list of set-op's result column datatypes
185 * colCollations: OID list of set-op's result column collations
186 * refnames_tlist: targetlist to take column names from
187 *
188 * parentOp should be passed as NULL unless that step is interested in
189 * getting sorted output from this step. ("Sorted" means "sorted according
190 * to the default btree opclasses of the result column datatypes".)
191 *
192 * Returns a RelOptInfo for the subtree, as well as these output parameters:
193 * *pTargetList: receives the fully-fledged tlist for the subtree's top plan
194 * *istrivial_tlist: true if, and only if, datatypes between parent and child
195 * match.
196 *
197 * If setOp is a leaf node, this function plans the sub-query but does
198 * not populate the pathlist of the returned RelOptInfo. The caller will
199 * generate SubqueryScan paths using useful path(s) of the subquery (see
200 * build_setop_child_paths). But this function does build the paths for
201 * set-operation nodes.
202 *
203 * The pTargetList output parameter is mostly redundant with the pathtarget
204 * of the returned RelOptInfo, but for the moment we need it because much of
205 * the logic in this file depends on flag columns being marked resjunk.
206 * XXX Now that there are no flag columns and hence no resjunk columns, we
207 * could probably refactor this file to deal only in pathtargets.
208 *
209 * We don't have to care about typmods here: the only allowed difference
210 * between set-op input and output typmods is input is a specific typmod
211 * and output is -1, and that does not require a coercion.
212 */
213static RelOptInfo *
219 bool *istrivial_tlist)
220{
221 RelOptInfo *rel;
222
223 *istrivial_tlist = true; /* for now */
224
225 /* Guard against stack overflow due to overly complex setop nests */
227
228 if (IsA(setOp, RangeTblRef))
229 {
231 RangeTblEntry *rte = root->simple_rte_array[rtr->rtindex];
232 Query *subquery = rte->subquery;
233 PlannerInfo *subroot;
234 List *tlist;
235 bool trivial_tlist;
236 char *plan_name;
237
238 Assert(subquery != NULL);
239
240 /* Build a RelOptInfo for this leaf subquery. */
241 rel = build_simple_rel(root, rtr->rtindex, NULL);
242
243 /* plan_params should not be in use in current query level */
244 Assert(root->plan_params == NIL);
245
246 /*
247 * Generate a subroot and Paths for the subquery. If we have a
248 * parentOp, pass that down to encourage subquery_planner to consider
249 * suitably-sorted Paths.
250 */
251 plan_name = choose_plan_name(root->glob, "setop", true);
252 subroot = rel->subroot = subquery_planner(root->glob, subquery,
253 plan_name, root,
254 false, root->tuple_fraction,
255 parentOp);
256
257 /*
258 * It should not be possible for the primitive query to contain any
259 * cross-references to other primitive queries in the setop tree.
260 */
261 if (root->plan_params)
262 elog(ERROR, "unexpected outer reference in set operation subquery");
263
264 /* Figure out the appropriate target list for this subquery. */
266 rtr->rtindex,
267 true,
268 subroot->processed_tlist,
271 rel->reltarget = create_pathtarget(root, tlist);
272
273 /* Return the fully-fledged tlist to caller, too */
274 *pTargetList = tlist;
276 }
277 else if (IsA(setOp, SetOperationStmt))
278 {
280
281 /* UNIONs are much different from INTERSECT/EXCEPT */
282 if (op->op == SETOP_UNION)
283 rel = generate_union_paths(op, root,
286 else
290
291 /*
292 * If necessary, add a Result node to project the caller-requested
293 * output columns.
294 *
295 * XXX you don't really want to know about this: setrefs.c will apply
296 * fix_upper_expr() to the Result node's tlist. This would fail if the
297 * Vars generated by generate_setop_tlist() were not exactly equal()
298 * to the corresponding tlist entries of the subplan. However, since
299 * the subplan was generated by generate_union_paths() or
300 * generate_nonunion_paths(), and hence its tlist was generated by
301 * generate_append_tlist() or generate_setop_tlist(), this will work.
302 * We just tell generate_setop_tlist() to use varno 0.
303 */
306 {
307 PathTarget *target;
308 bool trivial_tlist;
309 ListCell *lc;
310
312 0,
313 false,
319
320 /* Apply projection to each path */
321 foreach(lc, rel->pathlist)
322 {
323 Path *subpath = (Path *) lfirst(lc);
324 Path *path;
325
326 Assert(subpath->param_info == NULL);
327 path = apply_projection_to_path(root, subpath->parent,
328 subpath, target);
329 /* If we had to add a Result, path is different from subpath */
330 if (path != subpath)
331 lfirst(lc) = path;
332 }
333
334 /* Apply projection to each partial path */
335 foreach(lc, rel->partial_pathlist)
336 {
337 Path *subpath = (Path *) lfirst(lc);
338 Path *path;
339
340 Assert(subpath->param_info == NULL);
341
342 /* avoid apply_projection_to_path, in case of multiple refs */
343 path = (Path *) create_projection_path(root, subpath->parent,
344 subpath, target);
345 lfirst(lc) = path;
346 }
347 }
349 }
350 else
351 {
352 elog(ERROR, "unrecognized node type: %d",
353 (int) nodeTag(setOp));
354 *pTargetList = NIL;
355 rel = NULL; /* keep compiler quiet */
356 }
357
358 return rel;
359}
360
361/*
362 * Generate paths for a recursive UNION node
363 */
364static RelOptInfo *
368{
370 Path *path;
372 *rrel;
373 Path *lpath;
374 Path *rpath;
379 List *tlist;
380 List *groupList;
381 double dNumGroups;
382
383 /* Parser should have rejected other cases */
384 if (setOp->op != SETOP_UNION)
385 elog(ERROR, "only UNION queries can be recursive");
386 /* Worktable ID should be assigned */
387 Assert(root->wt_param_id >= 0);
388
389 /*
390 * Unlike a regular UNION node, process the left and right inputs
391 * separately without any intention of combining them into one Append.
392 */
394 NULL, /* no value in sorted results */
395 setOp->colTypes, setOp->colCollations,
399 if (lrel->rtekind == RTE_SUBQUERY)
401 NIL, NULL);
402 lpath = lrel->cheapest_total_path;
403 /* The right path will want to look at the left one ... */
404 root->non_recursive_path = lpath;
406 NULL, /* no value in sorted results */
407 setOp->colTypes, setOp->colCollations,
411 if (rrel->rtekind == RTE_SUBQUERY)
413 NIL, NULL);
414 rpath = rrel->cheapest_total_path;
415 root->non_recursive_path = NULL;
416
417 /*
418 * Generate tlist for RecursiveUnion path node --- same as in Append cases
419 */
420 tlist = generate_append_tlist(setOp->colTypes, setOp->colCollations,
423
424 *pTargetList = tlist;
425
426 /* Build result relation. */
428 bms_union(lrel->relids, rrel->relids));
429 result_rel->reltarget = create_pathtarget(root, tlist);
430
431 /*
432 * If UNION, identify the grouping operators
433 */
434 if (setOp->all)
435 {
436 groupList = NIL;
437 dNumGroups = 0;
438 }
439 else
440 {
441 /* Identify the grouping semantics */
442 groupList = generate_setop_grouplist(setOp, tlist);
443
444 /* We only support hashing here */
445 if (!grouping_is_hashable(groupList))
448 errmsg("could not implement recursive UNION"),
449 errdetail("All column datatypes must be hashable.")));
450
451 /*
452 * For the moment, take the number of distinct groups as equal to the
453 * total input size, ie, the worst case.
454 */
455 dNumGroups = lpath->rows + rpath->rows * 10;
456 }
457
458 /*
459 * And make the path node.
460 */
463 lpath,
464 rpath,
465 result_rel->reltarget,
466 groupList,
467 root->wt_param_id,
468 dNumGroups);
469
470 add_path(result_rel, path);
472 return result_rel;
473}
474
475/*
476 * build_setop_child_paths
477 * Build paths for the set op child relation denoted by 'rel'.
478 *
479 * 'rel' is an RTE_SUBQUERY relation. We have already generated paths within
480 * the subquery's subroot; the task here is to create SubqueryScan paths for
481 * 'rel', representing scans of the useful subquery paths.
482 *
483 * interesting_pathkeys: if not NIL, also include paths that suit these
484 * pathkeys, sorting any unsorted paths as required.
485 * *pNumGroups: if not NULL, we estimate the number of distinct groups
486 * in the result, and store it there.
487 */
488static void
492{
494 List *setop_pathkeys = rel->subroot->setop_pathkeys;
495 ListCell *lc;
496
497 /* it can't be a set op child rel if it's not a subquery */
498 Assert(rel->rtekind == RTE_SUBQUERY);
499
500 /* when sorting is needed, add child rel equivalences */
503 rel,
506
507 /*
508 * Mark rel with estimated output rows, width, etc. Note that we have to
509 * do this before generating outer-query paths, else cost_subqueryscan is
510 * not happy.
511 */
513
514 /*
515 * Since we may want to add a partial path to this relation, we must set
516 * its consider_parallel flag correctly.
517 */
519 rel->consider_parallel = final_rel->consider_parallel;
520
521 /* Generate subquery scan paths for any interesting path in final_rel */
522 foreach(lc, final_rel->pathlist)
523 {
524 Path *subpath = (Path *) lfirst(lc);
525 List *pathkeys;
526 Path *cheapest_input_path = final_rel->cheapest_total_path;
527 bool is_sorted;
528 int presorted_keys;
529
530 /* If the input rel is dummy, propagate that to this query level */
532 {
533 mark_dummy_rel(rel);
534 continue;
535 }
536
537 /*
538 * Include the cheapest path as-is so that the set operation can be
539 * cheaply implemented using a method which does not require the input
540 * to be sorted.
541 */
543 {
544 /* Convert subpath's pathkeys to outer representation */
545 pathkeys = convert_subquery_pathkeys(root, rel, subpath->pathkeys,
547
548 /* Generate outer path using this subpath */
550 rel,
551 subpath,
553 pathkeys,
554 NULL));
555 }
556
557 /* skip dealing with sorted paths if the setop doesn't need them */
559 continue;
560
561 /*
562 * Create paths to suit final sort order required for setop_pathkeys.
563 * Here we'll sort the cheapest input path (if not sorted already) and
564 * incremental sort any paths which are partially sorted.
565 */
566 is_sorted = pathkeys_count_contained_in(setop_pathkeys,
567 subpath->pathkeys,
568 &presorted_keys);
569
570 if (!is_sorted)
571 {
572 double limittuples = rel->subroot->limit_tuples;
573
574 /*
575 * Try at least sorting the cheapest path and also try
576 * incrementally sorting any path which is partially sorted
577 * already (no need to deal with paths which have presorted keys
578 * when incremental sort is disabled unless it's the cheapest
579 * input path).
580 */
582 (presorted_keys == 0 || !enable_incremental_sort))
583 continue;
584
585 /*
586 * We've no need to consider both a sort and incremental sort.
587 * We'll just do a sort if there are no presorted keys and an
588 * incremental sort when there are presorted keys.
589 */
590 if (presorted_keys == 0 || !enable_incremental_sort)
592 final_rel,
593 subpath,
594 setop_pathkeys,
596 else
598 final_rel,
599 subpath,
600 setop_pathkeys,
601 presorted_keys,
603 }
604
605 /*
606 * subpath is now sorted, so add it to the pathlist. We already added
607 * the cheapest_input_path above, so don't add it again unless we just
608 * sorted it.
609 */
611 {
612 /* Convert subpath's pathkeys to outer representation */
613 pathkeys = convert_subquery_pathkeys(root, rel, subpath->pathkeys,
615
616 /* Generate outer path using this subpath */
618 rel,
619 subpath,
621 pathkeys,
622 NULL));
623 }
624 }
625
626 /* if consider_parallel is false, there should be no partial paths */
627 Assert(final_rel->consider_parallel ||
628 final_rel->partial_pathlist == NIL);
629
630 /*
631 * If we have a partial path for the child relation, we can use that to
632 * build a partial path for this relation. But there's no point in
633 * considering any path but the cheapest.
634 */
636 final_rel->partial_pathlist != NIL)
637 {
640
641 partial_subpath = linitial(final_rel->partial_pathlist);
642 partial_path = (Path *)
645 NIL, NULL);
647 }
648
650
651 /*
652 * Estimate number of groups if caller wants it. If the subquery used
653 * grouping or aggregation, its output is probably mostly unique anyway;
654 * otherwise do statistical estimation.
655 *
656 * XXX you don't really want to know about this: we do the estimation
657 * using the subroot->parse's original targetlist expressions, not the
658 * subroot->processed_tlist which might seem more appropriate. The reason
659 * is that if the subquery is itself a setop, it may return a
660 * processed_tlist containing "varno 0" Vars generated by
661 * generate_append_tlist, and those would confuse estimate_num_groups
662 * mightily. We ought to get rid of the "varno 0" hack, but that requires
663 * a redesign of the parsetree representation of setops, so that there can
664 * be an RTE corresponding to each setop's output. Note, we use this not
665 * subquery's targetlist but subroot->parse's targetlist, because it was
666 * revised by self-join removal. subquery's targetlist might contain the
667 * references to the removed relids.
668 */
669 if (pNumGroups)
670 {
671 PlannerInfo *subroot = rel->subroot;
672 Query *subquery = subroot->parse;
673
674 if (subquery->groupClause || subquery->groupingSets ||
675 subquery->distinctClause || subroot->hasHavingQual ||
676 subquery->hasAggs)
678 else
680 get_tlist_exprs(subroot->parse->targetList, false),
682 NULL,
683 NULL);
684 }
685}
686
687/*
688 * Generate paths for a UNION or UNION ALL node
689 */
690static RelOptInfo *
694{
695 Relids relids = NULL;
697 ListCell *lc;
698 ListCell *lc2;
699 ListCell *lc3;
701 AppendPathInput ordered = {0};
702 AppendPathInput partial = {0};
703 bool partial_paths_valid = true;
704 bool consider_parallel = true;
705 List *rellist;
708 List *tlist;
709 List *groupList = NIL;
710 Path *apath;
711 Path *gpath = NULL;
712 bool try_sorted = false;
714
715 /*
716 * If any of my children are identical UNION nodes (same op, all-flag, and
717 * colTypes/colCollations) then they can be merged into this node so that
718 * we generate only one Append/MergeAppend and unique-ification for the
719 * lot. Recurse to find such nodes.
720 */
722 op,
724 &tlist_list,
726
727 /*
728 * Generate tlist for Append/MergeAppend plan node.
729 *
730 * The tlist for an Append plan isn't important as far as the Append is
731 * concerned, but we must make it look real anyway for the benefit of the
732 * next plan level up.
733 */
734 tlist = generate_append_tlist(op->colTypes, op->colCollations,
736 *pTargetList = tlist;
737
738 /* For UNIONs (not UNION ALL), try sorting, if sorting is possible */
739 if (!op->all)
740 {
741 /* Identify the grouping semantics */
742 groupList = generate_setop_grouplist(op, tlist);
743
744 if (grouping_is_sortable(op->groupClauses))
745 {
746 try_sorted = true;
747 /* Determine the pathkeys for sorting by the whole target list */
749 tlist);
750
751 root->query_pathkeys = union_pathkeys;
752 }
753 }
754
755 /*
756 * Now that we've got the append target list, we can build the union child
757 * paths.
758 */
760 {
761 RelOptInfo *rel = lfirst(lc);
764
765 /* only build paths for the union children */
766 if (rel->rtekind == RTE_SUBQUERY)
769 }
770
771 /* Build path lists and relid set. */
772 foreach(lc, rellist)
773 {
774 RelOptInfo *rel = lfirst(lc);
776
777 /*
778 * Record the relids so that we can identify the correct
779 * UPPERREL_SETOP RelOptInfo below.
780 */
781 relids = bms_add_members(relids, rel->relids);
782
783 /* Skip any UNION children that are proven not to yield any rows */
784 if (is_dummy_rel(rel))
785 continue;
786
787 cheapest.subpaths = lappend(cheapest.subpaths,
789
790 if (try_sorted)
791 {
794 NULL,
796 false);
797
798 if (ordered_path != NULL)
799 ordered.subpaths = lappend(ordered.subpaths, ordered_path);
800 else
801 {
802 /*
803 * If we can't find a sorted path, just give up trying to
804 * generate a list of correctly sorted child paths. This can
805 * happen when type coercion was added to the targetlist due
806 * to mismatching types from the union children.
807 */
808 try_sorted = false;
809 }
810 }
811
812 if (consider_parallel)
813 {
814 if (!rel->consider_parallel)
815 {
816 consider_parallel = false;
817 partial_paths_valid = false;
818 }
819 else if (rel->partial_pathlist == NIL)
820 partial_paths_valid = false;
821 else
822 partial.partial_subpaths = lappend(partial.partial_subpaths,
824 }
825 }
826
827 /* Build result relation. */
829 result_rel->reltarget = create_setop_pathtarget(root, tlist,
830 cheapest.subpaths);
831 result_rel->consider_parallel = consider_parallel;
832 result_rel->consider_startup = (root->tuple_fraction > 0);
833
834 /* If all UNION children were dummy rels, make the resulting rel dummy */
835 if (cheapest.subpaths == NIL)
836 {
838
839 return result_rel;
840 }
841
842 /*
843 * Append the child results together using the cheapest paths from each
844 * union child.
845 */
847 NIL, NULL, 0, false, -1);
848
849 /*
850 * Estimate number of groups. For now we just assume the output is unique
851 * --- this is certainly true for the UNION case, and we want worst-case
852 * estimates anyway.
853 */
854 result_rel->rows = apath->rows;
855
856 /*
857 * Now consider doing the same thing using the partial paths plus Append
858 * plus Gather.
859 */
861 {
862 Path *papath;
863 int parallel_workers = 0;
864
865 /* Find the highest number of workers requested for any subpath. */
866 foreach(lc, partial.partial_subpaths)
867 {
868 Path *subpath = lfirst(lc);
869
870 parallel_workers = Max(parallel_workers,
871 subpath->parallel_workers);
872 }
873 Assert(parallel_workers > 0);
874
875 /*
876 * If the use of parallel append is permitted, always request at least
877 * log2(# of children) paths. We assume it can be useful to have
878 * extra workers in this case because they will be spread out across
879 * the children. The precise formula is just a guess; see
880 * add_paths_to_append_rel.
881 */
883 {
884 parallel_workers = Max(parallel_workers,
886 parallel_workers = Min(parallel_workers,
888 }
889 Assert(parallel_workers > 0);
890
891 papath = (Path *)
893 NIL, NULL, parallel_workers,
895 gpath = (Path *)
897 result_rel->reltarget, NULL, NULL);
898 }
899
900 if (!op->all)
901 {
902 double dNumGroups;
903 bool can_sort = grouping_is_sortable(groupList);
904 bool can_hash = grouping_is_hashable(groupList);
905 Path *first_path = linitial(cheapest.subpaths);
906
907 /*
908 * Estimate the number of UNION output rows. In the case when only a
909 * single UNION child remains, we can use estimate_num_groups() on
910 * that child. We must be careful not to do this when that child is
911 * the result of some other set operation as the targetlist will
912 * contain Vars with varno==0, which estimate_num_groups() wouldn't
913 * like.
914 */
915 if (list_length(cheapest.subpaths) == 1 &&
916 first_path->parent->reloptkind != RELOPT_UPPER_REL)
917 {
919 first_path->pathtarget->exprs,
920 first_path->rows,
921 NULL,
922 NULL);
923 }
924 else
925 {
926 /*
927 * Otherwise, for the moment, take the number of distinct groups
928 * as equal to the total input size, i.e., the worst case. This
929 * is too conservative, but it's not clear how to get a decent
930 * estimate of the true size. One should note as well the
931 * propensity of novices to write UNION rather than UNION ALL even
932 * when they don't expect any duplicates...
933 */
934 dNumGroups = apath->rows;
935 }
936
937 if (can_hash)
938 {
939 Path *path;
940
941 /*
942 * Try a hash aggregate plan on 'apath'. This is the cheapest
943 * available path containing each append child.
944 */
945 path = (Path *) create_agg_path(root,
947 apath,
948 result_rel->reltarget,
951 groupList,
952 NIL,
953 NULL,
954 dNumGroups);
955 add_path(result_rel, path);
956
957 /* Try hash aggregate on the Gather path, if valid */
958 if (gpath != NULL)
959 {
960 /* Hashed aggregate plan --- no sort needed */
961 path = (Path *) create_agg_path(root,
963 gpath,
964 result_rel->reltarget,
967 groupList,
968 NIL,
969 NULL,
970 dNumGroups);
971 add_path(result_rel, path);
972 }
973 }
974
975 if (can_sort)
976 {
977 Path *path = apath;
978
979 /* Try Sort -> Unique on the Append path */
980 if (groupList != NIL)
981 path = (Path *) create_sort_path(root, result_rel, path,
982 make_pathkeys_for_sortclauses(root, groupList, tlist),
983 -1.0);
984
985 path = (Path *) create_unique_path(root,
987 path,
988 list_length(path->pathkeys),
989 dNumGroups);
990
991 add_path(result_rel, path);
992
993 /* Try Sort -> Unique on the Gather path, if set */
994 if (gpath != NULL)
995 {
996 path = gpath;
997
998 path = (Path *) create_sort_path(root, result_rel, path,
999 make_pathkeys_for_sortclauses(root, groupList, tlist),
1000 -1.0);
1001
1002 path = (Path *) create_unique_path(root,
1003 result_rel,
1004 path,
1005 list_length(path->pathkeys),
1006 dNumGroups);
1007 add_path(result_rel, path);
1008 }
1009 }
1010
1011 /*
1012 * Try making a MergeAppend path if we managed to find a path with the
1013 * correct pathkeys in each union child query.
1014 */
1015 if (try_sorted && groupList != NIL)
1016 {
1017 Path *path;
1018
1020 result_rel,
1021 ordered.subpaths,
1022 NIL,
1024 NULL);
1025
1026 /* and make the MergeAppend unique */
1027 path = (Path *) create_unique_path(root,
1028 result_rel,
1029 path,
1030 list_length(tlist),
1031 dNumGroups);
1032
1033 add_path(result_rel, path);
1034 }
1035 }
1036 else
1037 {
1038 /* UNION ALL */
1040
1041 if (gpath != NULL)
1043 }
1044
1045 return result_rel;
1046}
1047
1048/*
1049 * Generate paths for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node
1050 */
1051static RelOptInfo *
1054 List **pTargetList)
1055{
1058 *rrel;
1059 double save_fraction = root->tuple_fraction;
1060 Path *lpath,
1061 *rpath,
1062 *path;
1064 *rpath_tlist,
1065 *tlist,
1066 *groupList;
1071 double dLeftGroups,
1073 dNumGroups,
1075 bool can_sort;
1076 bool can_hash;
1077 SetOpCmd cmd;
1078
1079 /*
1080 * Tell children to fetch all tuples.
1081 */
1082 root->tuple_fraction = 0.0;
1083
1084 /* Recurse on children */
1086 op,
1087 op->colTypes, op->colCollations,
1089 &lpath_tlist,
1091
1093 op,
1094 op->colTypes, op->colCollations,
1096 &rpath_tlist,
1098
1099 /*
1100 * Generate tlist for SetOp plan node.
1101 *
1102 * The tlist for a SetOp plan isn't important so far as the SetOp is
1103 * concerned, but we must make it look real anyway for the benefit of the
1104 * next plan level up.
1105 */
1106 tlist = generate_setop_tlist(op->colTypes, op->colCollations,
1107 0, false, lpath_tlist, refnames_tlist,
1109
1110 /* We should not have needed any type coercions in the tlist */
1112
1113 *pTargetList = tlist;
1114
1115 /* Identify the grouping semantics */
1116 groupList = generate_setop_grouplist(op, tlist);
1117
1118 /* Check whether the operators support sorting or hashing */
1119 can_sort = grouping_is_sortable(groupList);
1120 can_hash = grouping_is_hashable(groupList);
1121 if (!can_sort && !can_hash)
1122 ereport(ERROR,
1124 /* translator: %s is INTERSECT or EXCEPT */
1125 errmsg("could not implement %s",
1126 (op->op == SETOP_INTERSECT) ? "INTERSECT" : "EXCEPT"),
1127 errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
1128
1129 if (can_sort)
1130 {
1131 /* Determine the pathkeys for sorting by the whole target list */
1133 tlist);
1134
1135 root->query_pathkeys = nonunion_pathkeys;
1136 }
1137
1138 /*
1139 * Now that we've got all that info, we can build the child paths.
1140 */
1141 if (lrel->rtekind == RTE_SUBQUERY)
1144 else
1145 dLeftGroups = lrel->rows;
1146 if (rrel->rtekind == RTE_SUBQUERY)
1149 else
1150 dRightGroups = rrel->rows;
1151
1152 /* Undo effects of forcing tuple_fraction to 0 */
1153 root->tuple_fraction = save_fraction;
1154
1155 /*
1156 * For EXCEPT, we must put the left input first. For INTERSECT, either
1157 * order should give the same results, and we prefer to put the smaller
1158 * input first in order to (a) minimize the size of the hash table in the
1159 * hashing case, and (b) improve our chances of exploiting the executor's
1160 * fast path for empty left-hand input. "Smaller" means the one with the
1161 * fewer groups.
1162 */
1163 if (op->op != SETOP_EXCEPT && dLeftGroups > dRightGroups)
1164 {
1165 /* need to swap the two inputs */
1167 List *tmplist;
1168 double tmpd;
1169
1170 tmprel = lrel;
1171 lrel = rrel;
1172 rrel = tmprel;
1176 tmpd = dLeftGroups;
1179 }
1180
1181 lpath = lrel->cheapest_total_path;
1182 rpath = rrel->cheapest_total_path;
1183
1184 /* Build result relation. */
1186 bms_union(lrel->relids, rrel->relids));
1187
1188 /*
1189 * Create the PathTarget and set the width accordingly. For EXCEPT, since
1190 * the set op result won't contain rows from the rpath, we only account
1191 * for the width of the lpath. For INTERSECT, use both input paths.
1192 */
1193 if (op->op == SETOP_EXCEPT)
1194 result_rel->reltarget = create_setop_pathtarget(root, tlist,
1195 list_make1(lpath));
1196 else
1197 result_rel->reltarget = create_setop_pathtarget(root, tlist,
1198 list_make2(lpath, rpath));
1199
1200 /* Check for provably empty setop inputs and add short-circuit paths. */
1201 if (op->op == SETOP_EXCEPT)
1202 {
1203 /*
1204 * For EXCEPTs, if the left side is dummy then there's no need to
1205 * inspect the right-hand side as scanning the right to find tuples to
1206 * remove won't make the left-hand input any more empty.
1207 */
1208 if (is_dummy_rel(lrel))
1209 {
1211
1212 return result_rel;
1213 }
1214
1215 /* Handle EXCEPTs with dummy right input */
1216 if (is_dummy_rel(rrel))
1217 {
1218 if (op->all)
1219 {
1220 Path *apath;
1221 AppendPathInput append = {0};
1222
1224
1225 /*
1226 * EXCEPT ALL: If the right-hand input is dummy then we can
1227 * simply scan the left-hand input. To keep createplan.c
1228 * happy, use a single child Append to handle the translation
1229 * between the set op targetlist and the targetlist of the
1230 * left input. The Append will be removed in setrefs.c.
1231 */
1233 append, NIL, NULL, 0,
1234 false, -1);
1235
1237
1238 return result_rel;
1239 }
1240 else
1241 {
1242 /*
1243 * To make EXCEPT with a dummy RHS work means having to
1244 * deduplicate the left input. That could be done with
1245 * AggPaths, but it doesn't seem worth the effort. Let the
1246 * normal path generation code below handle this one.
1247 */
1248 }
1249 }
1250 }
1251 else
1252 {
1253 /*
1254 * For INTERSECT, if either input is a dummy rel then we can mark the
1255 * result_rel as dummy since intersecting with an empty relation can
1256 * never yield any results. This is true regardless of INTERSECT or
1257 * INTERSECT ALL.
1258 */
1260 {
1262
1263 return result_rel;
1264 }
1265 }
1266
1267 /*
1268 * Estimate number of distinct groups that we'll need hashtable entries
1269 * for; this is the size of the left-hand input for EXCEPT, or the smaller
1270 * input for INTERSECT. Also estimate the number of eventual output rows.
1271 * In non-ALL cases, we estimate each group produces one output row; in
1272 * ALL cases use the relevant relation size. These are worst-case
1273 * estimates, of course, but we need to be conservative.
1274 */
1275 if (op->op == SETOP_EXCEPT)
1276 {
1278 dNumOutputRows = op->all ? lpath->rows : dNumGroups;
1279 }
1280 else
1281 {
1283 dNumOutputRows = op->all ? Min(lpath->rows, rpath->rows) : dNumGroups;
1284 }
1285 result_rel->rows = dNumOutputRows;
1286
1287 /* Select the SetOpCmd type */
1288 switch (op->op)
1289 {
1290 case SETOP_INTERSECT:
1292 break;
1293 case SETOP_EXCEPT:
1295 break;
1296 default:
1297 elog(ERROR, "unrecognized set op: %d", (int) op->op);
1298 cmd = SETOPCMD_INTERSECT; /* keep compiler quiet */
1299 break;
1300 }
1301
1302 /*
1303 * If we can hash, that just requires a SetOp atop the cheapest inputs.
1304 */
1305 if (can_hash)
1306 {
1307 path = (Path *) create_setop_path(root,
1308 result_rel,
1309 lpath,
1310 rpath,
1311 cmd,
1313 groupList,
1314 dNumGroups,
1316 add_path(result_rel, path);
1317 }
1318
1319 /*
1320 * If we can sort, generate the cheapest sorted input paths, and add a
1321 * SetOp atop those.
1322 */
1323 if (can_sort)
1324 {
1325 List *pathkeys;
1326 Path *slpath,
1327 *srpath;
1328
1329 /* First the left input ... */
1331 groupList,
1332 lpath_tlist);
1333 if (pathkeys_contained_in(pathkeys, lpath->pathkeys))
1334 slpath = lpath; /* cheapest path is already sorted */
1335 else
1336 {
1339 NULL,
1340 TOTAL_COST,
1341 false);
1342 /* Subquery failed to produce any presorted paths? */
1343 if (slpath == NULL)
1345 lpath->parent,
1346 lpath,
1347 pathkeys,
1348 -1.0);
1349 }
1350
1351 /* and now the same for the right. */
1353 groupList,
1354 rpath_tlist);
1355 if (pathkeys_contained_in(pathkeys, rpath->pathkeys))
1356 srpath = rpath; /* cheapest path is already sorted */
1357 else
1358 {
1361 NULL,
1362 TOTAL_COST,
1363 false);
1364 /* Subquery failed to produce any presorted paths? */
1365 if (srpath == NULL)
1367 rpath->parent,
1368 rpath,
1369 pathkeys,
1370 -1.0);
1371 }
1372
1373 path = (Path *) create_setop_path(root,
1374 result_rel,
1375 slpath,
1376 srpath,
1377 cmd,
1379 groupList,
1380 dNumGroups,
1382 add_path(result_rel, path);
1383 }
1384
1385 return result_rel;
1386}
1387
1388/*
1389 * Pull up children of a UNION node that are identically-propertied UNIONs,
1390 * and perform planning of the queries underneath the N-way UNION.
1391 *
1392 * The result is a list of RelOptInfos containing Paths for sub-nodes, with
1393 * one entry for each descendant that is a leaf query or non-identical setop.
1394 * We also return parallel lists of the childrens' targetlists and
1395 * is-trivial-tlist flags.
1396 *
1397 * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
1398 * output rows will be lost anyway.
1399 */
1400static List *
1404 List **tlist_list,
1406{
1408 List *result = NIL;
1410 bool trivial_tlist;
1411
1412 *tlist_list = NIL;
1414
1415 while (pending_rels != NIL)
1416 {
1418
1420
1422 {
1424
1425 if (op->op == top_union->op &&
1426 (op->all == top_union->all || op->all) &&
1427 equal(op->colTypes, top_union->colTypes) &&
1428 equal(op->colCollations, top_union->colCollations))
1429 {
1430 /* Same UNION, so fold children into parent */
1433 continue;
1434 }
1435 }
1436
1437 /*
1438 * Not same, so plan this child separately.
1439 *
1440 * If top_union isn't a UNION ALL, then we are interested in sorted
1441 * output from the child, so pass top_union as parentOp. Note that
1442 * this isn't necessarily the child node's immediate SetOperationStmt
1443 * parent, but that's fine: it's the effective parent.
1444 */
1445 result = lappend(result, recurse_set_operations(setOp, root,
1446 top_union->all ? NULL : top_union,
1447 top_union->colTypes,
1448 top_union->colCollations,
1450 &child_tlist,
1451 &trivial_tlist));
1454 }
1455
1456 return result;
1457}
1458
1459/*
1460 * postprocess_setop_rel - perform steps required after adding paths
1461 */
1462static void
1464{
1465 /*
1466 * We don't currently worry about allowing FDWs to contribute paths to
1467 * this relation, but give extensions a chance.
1468 */
1470 (*create_upper_paths_hook) (root, UPPERREL_SETOP,
1471 NULL, rel, NULL);
1472
1473 /* Select cheapest path */
1474 set_cheapest(rel);
1475}
1476
1477/*
1478 * Generate targetlist for a set-operation plan node
1479 *
1480 * colTypes: OID list of set-op's result column datatypes
1481 * colCollations: OID list of set-op's result column collations
1482 * varno: varno to use in generated Vars
1483 * hack_constants: true to copy up constants (see comments in code)
1484 * input_tlist: targetlist of this node's input node
1485 * refnames_tlist: targetlist to take column names from
1486 * trivial_tlist: output parameter, set to true if targetlist is trivial
1487 */
1488static List *
1490 Index varno,
1491 bool hack_constants,
1494 bool *trivial_tlist)
1495{
1496 List *tlist = NIL;
1497 int resno = 1;
1498 ListCell *ctlc,
1499 *cclc,
1500 *itlc,
1501 *rtlc;
1503 Node *expr;
1504
1505 *trivial_tlist = true; /* until proven differently */
1506
1509 {
1514
1515 Assert(inputtle->resno == resno);
1516 Assert(reftle->resno == resno);
1517 Assert(!inputtle->resjunk);
1518 Assert(!reftle->resjunk);
1519
1520 /*
1521 * Generate columns referencing input columns and having appropriate
1522 * data types and column names. Insert datatype coercions where
1523 * necessary.
1524 *
1525 * HACK: constants in the input's targetlist are copied up as-is
1526 * rather than being referenced as subquery outputs. This is mainly
1527 * to ensure that when we try to coerce them to the output column's
1528 * datatype, the right things happen for UNKNOWN constants. But do
1529 * this only at the first level of subquery-scan plans; we don't want
1530 * phony constants appearing in the output tlists of upper-level
1531 * nodes!
1532 *
1533 * Note that copying a constant doesn't in itself require us to mark
1534 * the tlist nontrivial; see trivial_subqueryscan() in setrefs.c.
1535 */
1536 if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
1537 expr = (Node *) inputtle->expr;
1538 else
1539 expr = (Node *) makeVar(varno,
1540 inputtle->resno,
1541 exprType((Node *) inputtle->expr),
1542 exprTypmod((Node *) inputtle->expr),
1543 exprCollation((Node *) inputtle->expr),
1544 0);
1545
1546 if (exprType(expr) != colType)
1547 {
1548 /*
1549 * Note: it's not really cool to be applying coerce_to_common_type
1550 * here; one notable point is that assign_expr_collations never
1551 * gets run on any generated nodes. For the moment that's not a
1552 * problem because we force the correct exposed collation below.
1553 * It would likely be best to make the parser generate the correct
1554 * output tlist for every set-op to begin with, though.
1555 */
1556 expr = coerce_to_common_type(NULL, /* no UNKNOWNs here */
1557 expr,
1558 colType,
1559 "UNION/INTERSECT/EXCEPT");
1560 *trivial_tlist = false; /* the coercion makes it not trivial */
1561 }
1562
1563 /*
1564 * Ensure the tlist entry's exposed collation matches the set-op. This
1565 * is necessary because plan_set_operations() reports the result
1566 * ordering as a list of SortGroupClauses, which don't carry collation
1567 * themselves but just refer to tlist entries. If we don't show the
1568 * right collation then planner.c might do the wrong thing in
1569 * higher-level queries.
1570 *
1571 * Note we use RelabelType, not CollateExpr, since this expression
1572 * will reach the executor without any further processing.
1573 */
1574 if (exprCollation(expr) != colColl)
1575 {
1576 expr = applyRelabelType(expr,
1577 exprType(expr), exprTypmod(expr), colColl,
1578 COERCE_IMPLICIT_CAST, -1, false);
1579 *trivial_tlist = false; /* the relabel makes it not trivial */
1580 }
1581
1582 tle = makeTargetEntry((Expr *) expr,
1583 (AttrNumber) resno++,
1584 pstrdup(reftle->resname),
1585 false);
1586
1587 /*
1588 * By convention, all output columns in a setop tree have
1589 * ressortgroupref equal to their resno. In some cases the ref isn't
1590 * needed, but this is a cleaner way than modifying the tlist later.
1591 */
1592 tle->ressortgroupref = tle->resno;
1593
1594 tlist = lappend(tlist, tle);
1595 }
1596
1597 return tlist;
1598}
1599
1600/*
1601 * Generate targetlist for a set-operation Append node
1602 *
1603 * colTypes: OID list of set-op's result column datatypes
1604 * colCollations: OID list of set-op's result column collations
1605 * input_tlists: list of tlists for sub-plans of the Append
1606 * refnames_tlist: targetlist to take column names from
1607 *
1608 * The entries in the Append's targetlist should always be simple Vars;
1609 * we just have to make sure they have the right datatypes/typmods/collations.
1610 * The Vars are always generated with varno 0.
1611 *
1612 * XXX a problem with the varno-zero approach is that set_pathtarget_cost_width
1613 * cannot figure out a realistic width for the tlist we make here. But we
1614 * ought to refactor this code to produce a PathTarget directly, anyway.
1615 */
1616static List *
1620{
1621 List *tlist = NIL;
1622 int resno = 1;
1626 int colindex;
1628 Node *expr;
1631
1632 /*
1633 * First extract typmods to use.
1634 *
1635 * If the inputs all agree on type and typmod of a particular column, use
1636 * that typmod; else use -1.
1637 */
1639
1640 foreach(tlistl, input_tlists)
1641 {
1642 List *subtlist = (List *) lfirst(tlistl);
1644
1646 colindex = 0;
1647 foreach(subtlistl, subtlist)
1648 {
1650
1651 Assert(!subtle->resjunk);
1653 if (exprType((Node *) subtle->expr) == lfirst_oid(curColType))
1654 {
1655 /* If first subplan, copy the typmod; else compare */
1656 int32 subtypmod = exprTypmod((Node *) subtle->expr);
1657
1660 else if (subtypmod != colTypmods[colindex])
1661 colTypmods[colindex] = -1;
1662 }
1663 else
1664 {
1665 /* types disagree, so force typmod to -1 */
1666 colTypmods[colindex] = -1;
1667 }
1669 colindex++;
1670 }
1672 }
1673
1674 /*
1675 * Now we can build the tlist for the Append.
1676 */
1677 colindex = 0;
1680 {
1685
1686 Assert(reftle->resno == resno);
1687 Assert(!reftle->resjunk);
1688 expr = (Node *) makeVar(0,
1689 resno,
1690 colType,
1691 colTypmod,
1692 colColl,
1693 0);
1694 tle = makeTargetEntry((Expr *) expr,
1695 (AttrNumber) resno++,
1696 pstrdup(reftle->resname),
1697 false);
1698
1699 /*
1700 * By convention, all output columns in a setop tree have
1701 * ressortgroupref equal to their resno. In some cases the ref isn't
1702 * needed, but this is a cleaner way than modifying the tlist later.
1703 */
1704 tle->ressortgroupref = tle->resno;
1705
1706 tlist = lappend(tlist, tle);
1707 }
1708
1710
1711 return tlist;
1712}
1713
1714/*
1715 * generate_setop_grouplist
1716 * Build a SortGroupClause list defining the sort/grouping properties
1717 * of the setop's output columns.
1718 *
1719 * Parse analysis already determined the properties and built a suitable
1720 * list, except that the entries do not have sortgrouprefs set because
1721 * the parser output representation doesn't include a tlist for each
1722 * setop. So what we need to do here is copy that list and install
1723 * proper sortgrouprefs into it (copying those from the targetlist).
1724 */
1725static List *
1727{
1728 List *grouplist = copyObject(op->groupClauses);
1729 ListCell *lg;
1730 ListCell *lt;
1731
1733 foreach(lt, targetlist)
1734 {
1735 TargetEntry *tle = (TargetEntry *) lfirst(lt);
1737
1738 Assert(!tle->resjunk);
1739
1740 /* non-resjunk columns should have sortgroupref = resno */
1741 Assert(tle->ressortgroupref == tle->resno);
1742
1743 /* non-resjunk columns should have grouping clauses */
1744 Assert(lg != NULL);
1746 lg = lnext(grouplist, lg);
1747 Assert(sgc->tleSortGroupRef == 0);
1748
1749 sgc->tleSortGroupRef = tle->ressortgroupref;
1750 }
1751 Assert(lg == NULL);
1752 return grouplist;
1753}
1754
1755/*
1756 * create_setop_pathtarget
1757 * Do the normal create_pathtarget() work, plus set the resulting
1758 * PathTarget's width to the average width of the Paths in child_pathlist
1759 * weighted using the estimated row count of each path.
1760 *
1761 * Note: This is required because set op target lists use varno==0, which
1762 * results in a type default width estimate rather than one that's based on
1763 * statistics of the columns from the set op children.
1764 */
1765static PathTarget *
1767{
1768 PathTarget *reltarget;
1769 ListCell *lc;
1770 double parent_rows = 0;
1771 double parent_size = 0;
1772
1773 reltarget = create_pathtarget(root, tlist);
1774
1775 /* Calculate the total rows and total size. */
1776 foreach(lc, child_pathlist)
1777 {
1778 Path *path = (Path *) lfirst(lc);
1779
1780 parent_rows += path->rows;
1781 parent_size += path->parent->reltarget->width * path->rows;
1782 }
1783
1784 if (parent_rows > 0)
1785 reltarget->width = rint(parent_size / parent_rows);
1786
1787 return reltarget;
1788}
int16 AttrNumber
Definition attnum.h:21
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:901
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:251
#define bms_is_empty(a)
Definition bitmapset.h:118
#define Min(x, y)
Definition c.h:1093
#define Max(x, y)
Definition c.h:1087
#define Assert(condition)
Definition c.h:945
int32_t int32
Definition c.h:614
unsigned int Index
Definition c.h:700
int max_parallel_workers_per_gather
Definition costsize.c:144
void set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel)
Definition costsize.c:6046
bool enable_parallel_append
Definition costsize.c:162
bool enable_incremental_sort
Definition costsize.c:152
int errcode(int sqlerrcode)
Definition elog.c:874
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223
void add_setop_child_rel_equivalences(PlannerInfo *root, RelOptInfo *child_rel, List *child_tlist, List *setop_pathkeys)
#define palloc_array(type, count)
Definition fe_memutils.h:76
void parse(int)
Definition parse.c:49
bool is_dummy_rel(RelOptInfo *rel)
Definition joinrels.c:1464
void mark_dummy_rel(RelOptInfo *rel)
Definition joinrels.c:1513
List * lappend(List *list, void *datum)
Definition list.c:339
List * list_delete_first(List *list)
Definition list.c:943
List * lappend_int(List *list, int datum)
Definition list.c:357
List * lcons(void *datum, List *list)
Definition list.c:495
Datum subpath(PG_FUNCTION_ARGS)
Definition ltree_op.c:311
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition makefuncs.c:66
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition makefuncs.c:289
char * pstrdup(const char *in)
Definition mcxt.c:1781
void pfree(void *pointer)
Definition mcxt.c:1616
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition nodeFuncs.c:304
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:826
Node * applyRelabelType(Node *arg, Oid rtype, int32 rtypmod, Oid rcollid, CoercionForm rformat, int rlocation, bool overwrite_ok)
Definition nodeFuncs.c:641
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:164
#define copyObject(obj)
Definition nodes.h:232
#define nodeTag(nodeptr)
Definition nodes.h:139
@ AGG_HASHED
Definition nodes.h:366
@ AGGSPLIT_SIMPLE
Definition nodes.h:387
#define castNode(_type_, nodeptr)
Definition nodes.h:182
static char * errmsg
Node * coerce_to_common_type(ParseState *pstate, Node *node, Oid targetTypeId, const char *context)
@ SETOP_INTERSECT
@ SETOP_UNION
@ SETOP_EXCEPT
@ RTE_SUBQUERY
Path * get_cheapest_path_for_pathkeys(List *paths, List *pathkeys, Relids required_outer, CostSelector cost_criterion, bool require_parallel_safe)
Definition pathkeys.c:620
bool pathkeys_count_contained_in(List *keys1, List *keys2, int *n_common)
Definition pathkeys.c:558
List * make_pathkeys_for_sortclauses(PlannerInfo *root, List *sortclauses, List *tlist)
Definition pathkeys.c:1336
List * convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel, List *subquery_pathkeys, List *subquery_tlist)
Definition pathkeys.c:1054
bool pathkeys_contained_in(List *keys1, List *keys2)
Definition pathkeys.c:343
SetOpPath * create_setop_path(PlannerInfo *root, RelOptInfo *rel, Path *leftpath, Path *rightpath, SetOpCmd cmd, SetOpStrategy strategy, List *groupList, double numGroups, double outputRows)
Definition pathnode.c:3466
ProjectionPath * create_projection_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
Definition pathnode.c:2587
Path * apply_projection_to_path(PlannerInfo *root, RelOptInfo *rel, Path *path, PathTarget *target)
Definition pathnode.c:2696
void set_cheapest(RelOptInfo *parent_rel)
Definition pathnode.c:268
void add_partial_path(RelOptInfo *parent_rel, Path *new_path)
Definition pathnode.c:793
SubqueryScanPath * create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, bool trivial_pathtarget, List *pathkeys, Relids required_outer)
Definition pathnode.c:1909
IncrementalSortPath * create_incremental_sort_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, int presorted_keys, double limit_tuples)
Definition pathnode.c:2855
SortPath * create_sort_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, double limit_tuples)
Definition pathnode.c:2904
MergeAppendPath * create_merge_append_path(PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *child_append_relid_sets, List *pathkeys, Relids required_outer)
Definition pathnode.c:1524
GatherPath * create_gather_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, Relids required_outer, double *rows)
Definition pathnode.c:1865
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition pathnode.c:459
AppendPath * create_append_path(PlannerInfo *root, RelOptInfo *rel, AppendPathInput input, List *pathkeys, Relids required_outer, int parallel_workers, bool parallel_aware, double rows)
Definition pathnode.c:1352
UniquePath * create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, int numCols, double numGroups)
Definition pathnode.c:3005
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:3057
RecursiveUnionPath * create_recursiveunion_path(PlannerInfo *root, RelOptInfo *rel, Path *leftpath, Path *rightpath, PathTarget *target, List *distinctList, int wtParam, double numGroups)
Definition pathnode.c:3585
@ TOTAL_COST
Definition pathnodes.h:111
@ UPPERREL_SETOP
Definition pathnodes.h:144
@ UPPERREL_FINAL
Definition pathnodes.h:152
@ RELOPT_UPPER_REL
Definition pathnodes.h:969
static int pg_leftmost_one_pos32(uint32 word)
Definition pg_bitutils.h:41
#define lfirst(lc)
Definition pg_list.h:172
#define lfirst_node(type, lc)
Definition pg_list.h:176
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
#define lfirst_int(lc)
Definition pg_list.h:173
#define list_make1(x1)
Definition pg_list.h:212
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition pg_list.h:563
#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 * list_head(const List *l)
Definition pg_list.h:128
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
char * choose_plan_name(PlannerGlobal *glob, const char *name, bool always_number)
Definition planner.c:9024
PlannerInfo * subquery_planner(PlannerGlobal *glob, Query *parse, char *plan_name, PlannerInfo *parent_root, bool hasRecursion, double tuple_fraction, SetOperationStmt *setops)
Definition planner.c:743
create_upper_paths_hook_type create_upper_paths_hook
Definition planner.c:83
unsigned int Oid
static int fb(int x)
RelOptInfo * plan_set_operations(PlannerInfo *root)
Definition prepunion.c:98
static List * generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
Definition prepunion.c:1726
static RelOptInfo * generate_union_paths(SetOperationStmt *op, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition prepunion.c:691
static RelOptInfo * generate_nonunion_paths(SetOperationStmt *op, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition prepunion.c:1052
static PathTarget * create_setop_pathtarget(PlannerInfo *root, List *tlist, List *child_pathlist)
Definition prepunion.c:1766
static void postprocess_setop_rel(PlannerInfo *root, RelOptInfo *rel)
Definition prepunion.c:1463
static List * generate_setop_tlist(List *colTypes, List *colCollations, Index varno, bool hack_constants, List *input_tlist, List *refnames_tlist, bool *trivial_tlist)
Definition prepunion.c:1489
static RelOptInfo * recurse_set_operations(Node *setOp, PlannerInfo *root, SetOperationStmt *parentOp, List *colTypes, List *colCollations, List *refnames_tlist, List **pTargetList, bool *istrivial_tlist)
Definition prepunion.c:214
static RelOptInfo * generate_recursion_path(SetOperationStmt *setOp, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition prepunion.c:365
static List * generate_append_tlist(List *colTypes, List *colCollations, List *input_tlists, List *refnames_tlist)
Definition prepunion.c:1617
static List * plan_union_children(PlannerInfo *root, SetOperationStmt *top_union, List *refnames_tlist, List **tlist_list, List **istrivial_tlist)
Definition prepunion.c:1401
static void build_setop_child_paths(PlannerInfo *root, RelOptInfo *rel, bool trivial_tlist, List *child_tlist, List *interesting_pathkeys, double *pNumGroups)
Definition prepunion.c:489
@ COERCE_IMPLICIT_CAST
Definition primnodes.h:769
tree ctl root
Definition radixtree.h:1857
void setup_simple_rel_arrays(PlannerInfo *root)
Definition relnode.c:114
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition relnode.c:1617
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition relnode.c:212
double estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, List **pgset, EstimationInfo *estinfo)
Definition selfuncs.c:3788
void check_stack_depth(void)
Definition stack_depth.c:95
List * subpaths
Definition pathnode.h:36
List * partial_subpaths
Definition pathnode.h:37
Definition pg_list.h:54
Definition nodes.h:135
List * pathkeys
Definition pathnodes.h:1999
Cardinality rows
Definition pathnodes.h:1993
List * processed_tlist
Definition pathnodes.h:581
bool hasHavingQual
Definition pathnodes.h:621
Query * parse
Definition pathnodes.h:309
Cardinality limit_tuples
Definition pathnodes.h:608
List * setop_pathkeys
Definition pathnodes.h:523
List * groupClause
Definition parsenodes.h:216
List * targetList
Definition parsenodes.h:198
List * groupingSets
Definition parsenodes.h:220
List * distinctClause
Definition parsenodes.h:226
Relids relids
Definition pathnodes.h:1009
struct PathTarget * reltarget
Definition pathnodes.h:1033
bool consider_parallel
Definition pathnodes.h:1025
Relids lateral_relids
Definition pathnodes.h:1052
List * pathlist
Definition pathnodes.h:1038
struct Path * cheapest_total_path
Definition pathnodes.h:1042
List * partial_pathlist
Definition pathnodes.h:1040
PlannerInfo * subroot
Definition pathnodes.h:1088
RTEKind rtekind
Definition pathnodes.h:1061
SetOperation op
bool tlist_same_collations(List *tlist, List *colCollations, bool junkOK)
Definition tlist.c:291
bool grouping_is_sortable(List *groupClause)
Definition tlist.c:549
List * make_tlist_from_pathtarget(PathTarget *target)
Definition tlist.c:633
List * get_tlist_exprs(List *tlist, bool includeJunk)
Definition tlist.c:172
bool grouping_is_hashable(List *groupClause)
Definition tlist.c:569
bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
Definition tlist.c:257
#define create_pathtarget(root, tlist)
Definition tlist.h:58