PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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-2025, 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 "catalog/pg_type.h"
28#include "miscadmin.h"
29#include "nodes/makefuncs.h"
30#include "nodes/nodeFuncs.h"
31#include "optimizer/cost.h"
32#include "optimizer/pathnode.h"
33#include "optimizer/paths.h"
34#include "optimizer/planner.h"
35#include "optimizer/prep.h"
36#include "optimizer/tlist.h"
37#include "parser/parse_coerce.h"
38#include "utils/selfuncs.h"
39
40
42 SetOperationStmt *parentOp,
43 List *colTypes, List *colCollations,
44 List *refnames_tlist,
45 List **pTargetList,
46 bool *istrivial_tlist);
49 List *refnames_tlist,
50 List **pTargetList);
52 bool trivial_tlist, List *child_tlist,
53 List *interesting_pathkeys,
54 double *pNumGroups);
56 List *refnames_tlist,
57 List **pTargetList);
59 List *refnames_tlist,
60 List **pTargetList);
62 SetOperationStmt *top_union,
63 List *refnames_tlist,
64 List **tlist_list,
65 List **istrivial_tlist);
67static List *generate_setop_tlist(List *colTypes, List *colCollations,
68 Index varno,
69 bool hack_constants,
70 List *input_tlist,
71 List *refnames_tlist,
72 bool *trivial_tlist);
73static List *generate_append_tlist(List *colTypes, List *colCollations,
74 List *input_tlists,
75 List *refnames_tlist);
76static List *generate_setop_grouplist(SetOperationStmt *op, List *targetlist);
77
78
79/*
80 * plan_set_operations
81 *
82 * Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT)
83 *
84 * This routine only deals with the setOperations tree of the given query.
85 * Any top-level ORDER BY requested in root->parse->sortClause will be handled
86 * when we return to grouping_planner; likewise for LIMIT.
87 *
88 * What we return is an "upperrel" RelOptInfo containing at least one Path
89 * that implements the set-operation tree. In addition, root->processed_tlist
90 * receives a targetlist representing the output of the topmost setop node.
91 */
94{
95 Query *parse = root->parse;
96 SetOperationStmt *topop = castNode(SetOperationStmt, parse->setOperations);
97 Node *node;
98 RangeTblEntry *leftmostRTE;
99 Query *leftmostQuery;
100 RelOptInfo *setop_rel;
101 List *top_tlist;
102
103 Assert(topop);
104
105 /* check for unsupported stuff */
106 Assert(parse->jointree->fromlist == NIL);
107 Assert(parse->jointree->quals == NULL);
108 Assert(parse->groupClause == NIL);
109 Assert(parse->havingQual == NULL);
110 Assert(parse->windowClause == NIL);
111 Assert(parse->distinctClause == NIL);
112
113 /*
114 * In the outer query level, equivalence classes are limited to classes
115 * which define that the top-level target entry is equivalent to the
116 * corresponding child target entry. There won't be any equivalence class
117 * merging. Mark that merging is complete to allow us to make pathkeys.
118 */
119 Assert(root->eq_classes == NIL);
120 root->ec_merging_done = true;
121
122 /*
123 * We'll need to build RelOptInfos for each of the leaf subqueries, which
124 * are RTE_SUBQUERY rangetable entries in this Query. Prepare the index
125 * arrays for those, and for AppendRelInfos in case they're needed.
126 */
128
129 /*
130 * Find the leftmost component Query. We need to use its column names for
131 * all generated tlists (else SELECT INTO won't work right).
132 */
133 node = topop->larg;
134 while (node && IsA(node, SetOperationStmt))
135 node = ((SetOperationStmt *) node)->larg;
136 Assert(node && IsA(node, RangeTblRef));
137 leftmostRTE = root->simple_rte_array[((RangeTblRef *) node)->rtindex];
138 leftmostQuery = leftmostRTE->subquery;
139 Assert(leftmostQuery != NULL);
140
141 /*
142 * If the topmost node is a recursive union, it needs special processing.
143 */
144 if (root->hasRecursion)
145 {
146 setop_rel = generate_recursion_path(topop, root,
147 leftmostQuery->targetList,
148 &top_tlist);
149 }
150 else
151 {
152 bool trivial_tlist;
153
154 /*
155 * Recurse on setOperations tree to generate paths for set ops. The
156 * final output paths should have just the column types shown as the
157 * output from the top-level node.
158 */
159 setop_rel = recurse_set_operations((Node *) topop, root,
160 NULL, /* no parent */
161 topop->colTypes, topop->colCollations,
162 leftmostQuery->targetList,
163 &top_tlist,
164 &trivial_tlist);
165 }
166
167 /* Must return the built tlist into root->processed_tlist. */
168 root->processed_tlist = top_tlist;
169
170 return setop_rel;
171}
172
173/*
174 * recurse_set_operations
175 * Recursively handle one step in a tree of set operations
176 *
177 * setOp: current step (could be a SetOperationStmt or a leaf RangeTblRef)
178 * parentOp: parent step, or NULL if none (but see below)
179 * colTypes: OID list of set-op's result column datatypes
180 * colCollations: OID list of set-op's result column collations
181 * refnames_tlist: targetlist to take column names from
182 *
183 * parentOp should be passed as NULL unless that step is interested in
184 * getting sorted output from this step. ("Sorted" means "sorted according
185 * to the default btree opclasses of the result column datatypes".)
186 *
187 * Returns a RelOptInfo for the subtree, as well as these output parameters:
188 * *pTargetList: receives the fully-fledged tlist for the subtree's top plan
189 * *istrivial_tlist: true if, and only if, datatypes between parent and child
190 * match.
191 *
192 * If setOp is a leaf node, this function plans the sub-query but does
193 * not populate the pathlist of the returned RelOptInfo. The caller will
194 * generate SubqueryScan paths using useful path(s) of the subquery (see
195 * build_setop_child_paths). But this function does build the paths for
196 * set-operation nodes.
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 * XXX Now that there are no flag columns and hence no resjunk columns, we
202 * could probably refactor this file to deal only in pathtargets.
203 *
204 * We don't have to care about typmods here: the only allowed difference
205 * between set-op input and output typmods is input is a specific typmod
206 * and output is -1, and that does not require a coercion.
207 */
208static RelOptInfo *
210 SetOperationStmt *parentOp,
211 List *colTypes, List *colCollations,
212 List *refnames_tlist,
213 List **pTargetList,
214 bool *istrivial_tlist)
215{
216 RelOptInfo *rel;
217
218 *istrivial_tlist = true; /* for now */
219
220 /* Guard against stack overflow due to overly complex setop nests */
222
223 if (IsA(setOp, RangeTblRef))
224 {
225 RangeTblRef *rtr = (RangeTblRef *) setOp;
226 RangeTblEntry *rte = root->simple_rte_array[rtr->rtindex];
227 Query *subquery = rte->subquery;
228 PlannerInfo *subroot;
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 /*
241 * Generate a subroot and Paths for the subquery. If we have a
242 * parentOp, pass that down to encourage subquery_planner to consider
243 * suitably-sorted Paths.
244 */
245 subroot = rel->subroot = subquery_planner(root->glob, subquery, root,
246 false, root->tuple_fraction,
247 parentOp);
248
249 /*
250 * It should not be possible for the primitive query to contain any
251 * cross-references to other primitive queries in the setop tree.
252 */
253 if (root->plan_params)
254 elog(ERROR, "unexpected outer reference in set operation subquery");
255
256 /* Figure out the appropriate target list for this subquery. */
257 tlist = generate_setop_tlist(colTypes, colCollations,
258 rtr->rtindex,
259 true,
260 subroot->processed_tlist,
261 refnames_tlist,
262 &trivial_tlist);
263 rel->reltarget = create_pathtarget(root, tlist);
264
265 /* Return the fully-fledged tlist to caller, too */
266 *pTargetList = tlist;
267 *istrivial_tlist = trivial_tlist;
268 }
269 else if (IsA(setOp, SetOperationStmt))
270 {
271 SetOperationStmt *op = (SetOperationStmt *) setOp;
272
273 /* UNIONs are much different from INTERSECT/EXCEPT */
274 if (op->op == SETOP_UNION)
275 rel = generate_union_paths(op, root,
276 refnames_tlist,
277 pTargetList);
278 else
280 refnames_tlist,
281 pTargetList);
282
283 /*
284 * If necessary, add a Result node to project the caller-requested
285 * output columns.
286 *
287 * XXX you don't really want to know about this: setrefs.c will apply
288 * fix_upper_expr() to the Result node's tlist. This would fail if the
289 * Vars generated by generate_setop_tlist() were not exactly equal()
290 * to the corresponding tlist entries of the subplan. However, since
291 * the subplan was generated by generate_union_paths() or
292 * generate_nonunion_paths(), and hence its tlist was generated by
293 * generate_append_tlist() or generate_setop_tlist(), this will work.
294 * We just tell generate_setop_tlist() to use varno 0.
295 */
296 if (!tlist_same_datatypes(*pTargetList, colTypes, false) ||
297 !tlist_same_collations(*pTargetList, colCollations, false))
298 {
299 PathTarget *target;
300 bool trivial_tlist;
301 ListCell *lc;
302
303 *pTargetList = generate_setop_tlist(colTypes, colCollations,
304 0,
305 false,
306 *pTargetList,
307 refnames_tlist,
308 &trivial_tlist);
309 *istrivial_tlist = trivial_tlist;
310 target = create_pathtarget(root, *pTargetList);
311
312 /* Apply projection to each path */
313 foreach(lc, rel->pathlist)
314 {
315 Path *subpath = (Path *) lfirst(lc);
316 Path *path;
317
318 Assert(subpath->param_info == NULL);
319 path = apply_projection_to_path(root, subpath->parent,
320 subpath, target);
321 /* If we had to add a Result, path is different from subpath */
322 if (path != subpath)
323 lfirst(lc) = path;
324 }
325
326 /* Apply projection to each partial path */
327 foreach(lc, rel->partial_pathlist)
328 {
329 Path *subpath = (Path *) lfirst(lc);
330 Path *path;
331
332 Assert(subpath->param_info == NULL);
333
334 /* avoid apply_projection_to_path, in case of multiple refs */
335 path = (Path *) create_projection_path(root, subpath->parent,
336 subpath, target);
337 lfirst(lc) = path;
338 }
339 }
341 }
342 else
343 {
344 elog(ERROR, "unrecognized node type: %d",
345 (int) nodeTag(setOp));
346 *pTargetList = NIL;
347 rel = NULL; /* keep compiler quiet */
348 }
349
350 return rel;
351}
352
353/*
354 * Generate paths for a recursive UNION node
355 */
356static RelOptInfo *
358 List *refnames_tlist,
359 List **pTargetList)
360{
361 RelOptInfo *result_rel;
362 Path *path;
363 RelOptInfo *lrel,
364 *rrel;
365 Path *lpath;
366 Path *rpath;
367 List *lpath_tlist;
368 bool lpath_trivial_tlist;
369 List *rpath_tlist;
370 bool rpath_trivial_tlist;
371 List *tlist;
372 List *groupList;
373 double dNumGroups;
374
375 /* Parser should have rejected other cases */
376 if (setOp->op != SETOP_UNION)
377 elog(ERROR, "only UNION queries can be recursive");
378 /* Worktable ID should be assigned */
379 Assert(root->wt_param_id >= 0);
380
381 /*
382 * Unlike a regular UNION node, process the left and right inputs
383 * separately without any intention of combining them into one Append.
384 */
385 lrel = recurse_set_operations(setOp->larg, root,
386 NULL, /* no value in sorted results */
387 setOp->colTypes, setOp->colCollations,
388 refnames_tlist,
389 &lpath_tlist,
390 &lpath_trivial_tlist);
391 if (lrel->rtekind == RTE_SUBQUERY)
392 build_setop_child_paths(root, lrel, lpath_trivial_tlist, lpath_tlist,
393 NIL, NULL);
394 lpath = lrel->cheapest_total_path;
395 /* The right path will want to look at the left one ... */
396 root->non_recursive_path = lpath;
397 rrel = recurse_set_operations(setOp->rarg, root,
398 NULL, /* no value in sorted results */
399 setOp->colTypes, setOp->colCollations,
400 refnames_tlist,
401 &rpath_tlist,
402 &rpath_trivial_tlist);
403 if (rrel->rtekind == RTE_SUBQUERY)
404 build_setop_child_paths(root, rrel, rpath_trivial_tlist, rpath_tlist,
405 NIL, NULL);
406 rpath = rrel->cheapest_total_path;
407 root->non_recursive_path = NULL;
408
409 /*
410 * Generate tlist for RecursiveUnion path node --- same as in Append cases
411 */
412 tlist = generate_append_tlist(setOp->colTypes, setOp->colCollations,
413 list_make2(lpath_tlist, rpath_tlist),
414 refnames_tlist);
415
416 *pTargetList = tlist;
417
418 /* Build result relation. */
419 result_rel = fetch_upper_rel(root, UPPERREL_SETOP,
420 bms_union(lrel->relids, rrel->relids));
421 result_rel->reltarget = create_pathtarget(root, tlist);
422
423 /*
424 * If UNION, identify the grouping operators
425 */
426 if (setOp->all)
427 {
428 groupList = NIL;
429 dNumGroups = 0;
430 }
431 else
432 {
433 /* Identify the grouping semantics */
434 groupList = generate_setop_grouplist(setOp, tlist);
435
436 /* We only support hashing here */
437 if (!grouping_is_hashable(groupList))
439 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
440 errmsg("could not implement recursive UNION"),
441 errdetail("All column datatypes must be hashable.")));
442
443 /*
444 * For the moment, take the number of distinct groups as equal to the
445 * total input size, ie, the worst case.
446 */
447 dNumGroups = lpath->rows + rpath->rows * 10;
448 }
449
450 /*
451 * And make the path node.
452 */
454 result_rel,
455 lpath,
456 rpath,
457 result_rel->reltarget,
458 groupList,
459 root->wt_param_id,
460 dNumGroups);
461
462 add_path(result_rel, path);
463 postprocess_setop_rel(root, result_rel);
464 return result_rel;
465}
466
467/*
468 * build_setop_child_paths
469 * Build paths for the set op child relation denoted by 'rel'.
470 *
471 * 'rel' is an RTE_SUBQUERY relation. We have already generated paths within
472 * the subquery's subroot; the task here is to create SubqueryScan paths for
473 * 'rel', representing scans of the useful subquery paths.
474 *
475 * interesting_pathkeys: if not NIL, also include paths that suit these
476 * pathkeys, sorting any unsorted paths as required.
477 * *pNumGroups: if not NULL, we estimate the number of distinct groups
478 * in the result, and store it there.
479 */
480static void
482 bool trivial_tlist, List *child_tlist,
483 List *interesting_pathkeys, double *pNumGroups)
484{
485 RelOptInfo *final_rel;
486 List *setop_pathkeys = rel->subroot->setop_pathkeys;
487 ListCell *lc;
488
489 /* it can't be a set op child rel if it's not a subquery */
490 Assert(rel->rtekind == RTE_SUBQUERY);
491
492 /* when sorting is needed, add child rel equivalences */
493 if (interesting_pathkeys != NIL)
495 rel,
496 child_tlist,
497 interesting_pathkeys);
498
499 /*
500 * Mark rel with estimated output rows, width, etc. Note that we have to
501 * do this before generating outer-query paths, else cost_subqueryscan is
502 * not happy.
503 */
505
506 /*
507 * Since we may want to add a partial path to this relation, we must set
508 * its consider_parallel flag correctly.
509 */
510 final_rel = fetch_upper_rel(rel->subroot, UPPERREL_FINAL, NULL);
511 rel->consider_parallel = final_rel->consider_parallel;
512
513 /* Generate subquery scan paths for any interesting path in final_rel */
514 foreach(lc, final_rel->pathlist)
515 {
516 Path *subpath = (Path *) lfirst(lc);
517 List *pathkeys;
518 Path *cheapest_input_path = final_rel->cheapest_total_path;
519 bool is_sorted;
520 int presorted_keys;
521
522 /*
523 * Include the cheapest path as-is so that the set operation can be
524 * cheaply implemented using a method which does not require the input
525 * to be sorted.
526 */
527 if (subpath == cheapest_input_path)
528 {
529 /* Convert subpath's pathkeys to outer representation */
530 pathkeys = convert_subquery_pathkeys(root, rel, subpath->pathkeys,
532
533 /* Generate outer path using this subpath */
535 rel,
536 subpath,
537 trivial_tlist,
538 pathkeys,
539 NULL));
540 }
541
542 /* skip dealing with sorted paths if the setop doesn't need them */
543 if (interesting_pathkeys == NIL)
544 continue;
545
546 /*
547 * Create paths to suit final sort order required for setop_pathkeys.
548 * Here we'll sort the cheapest input path (if not sorted already) and
549 * incremental sort any paths which are partially sorted.
550 */
551 is_sorted = pathkeys_count_contained_in(setop_pathkeys,
552 subpath->pathkeys,
553 &presorted_keys);
554
555 if (!is_sorted)
556 {
557 double limittuples = rel->subroot->limit_tuples;
558
559 /*
560 * Try at least sorting the cheapest path and also try
561 * incrementally sorting any path which is partially sorted
562 * already (no need to deal with paths which have presorted keys
563 * when incremental sort is disabled unless it's the cheapest
564 * input path).
565 */
566 if (subpath != cheapest_input_path &&
567 (presorted_keys == 0 || !enable_incremental_sort))
568 continue;
569
570 /*
571 * We've no need to consider both a sort and incremental sort.
572 * We'll just do a sort if there are no presorted keys and an
573 * incremental sort when there are presorted keys.
574 */
575 if (presorted_keys == 0 || !enable_incremental_sort)
577 final_rel,
578 subpath,
579 setop_pathkeys,
580 limittuples);
581 else
583 final_rel,
584 subpath,
585 setop_pathkeys,
586 presorted_keys,
587 limittuples);
588 }
589
590 /*
591 * subpath is now sorted, so add it to the pathlist. We already added
592 * the cheapest_input_path above, so don't add it again unless we just
593 * sorted it.
594 */
595 if (subpath != cheapest_input_path)
596 {
597 /* Convert subpath's pathkeys to outer representation */
598 pathkeys = convert_subquery_pathkeys(root, rel, subpath->pathkeys,
600
601 /* Generate outer path using this subpath */
603 rel,
604 subpath,
605 trivial_tlist,
606 pathkeys,
607 NULL));
608 }
609 }
610
611 /* if consider_parallel is false, there should be no partial paths */
612 Assert(final_rel->consider_parallel ||
613 final_rel->partial_pathlist == NIL);
614
615 /*
616 * If we have a partial path for the child relation, we can use that to
617 * build a partial path for this relation. But there's no point in
618 * considering any path but the cheapest.
619 */
621 final_rel->partial_pathlist != NIL)
622 {
623 Path *partial_subpath;
624 Path *partial_path;
625
626 partial_subpath = linitial(final_rel->partial_pathlist);
627 partial_path = (Path *)
628 create_subqueryscan_path(root, rel, partial_subpath,
629 trivial_tlist,
630 NIL, NULL);
631 add_partial_path(rel, partial_path);
632 }
633
635
636 /*
637 * Estimate number of groups if caller wants it. If the subquery used
638 * grouping or aggregation, its output is probably mostly unique anyway;
639 * otherwise do statistical estimation.
640 *
641 * XXX you don't really want to know about this: we do the estimation
642 * using the subroot->parse's original targetlist expressions, not the
643 * subroot->processed_tlist which might seem more appropriate. The reason
644 * is that if the subquery is itself a setop, it may return a
645 * processed_tlist containing "varno 0" Vars generated by
646 * generate_append_tlist, and those would confuse estimate_num_groups
647 * mightily. We ought to get rid of the "varno 0" hack, but that requires
648 * a redesign of the parsetree representation of setops, so that there can
649 * be an RTE corresponding to each setop's output. Note, we use this not
650 * subquery's targetlist but subroot->parse's targetlist, because it was
651 * revised by self-join removal. subquery's targetlist might contain the
652 * references to the removed relids.
653 */
654 if (pNumGroups)
655 {
656 PlannerInfo *subroot = rel->subroot;
657 Query *subquery = subroot->parse;
658
659 if (subquery->groupClause || subquery->groupingSets ||
660 subquery->distinctClause || subroot->hasHavingQual ||
661 subquery->hasAggs)
662 *pNumGroups = rel->cheapest_total_path->rows;
663 else
664 *pNumGroups = estimate_num_groups(subroot,
665 get_tlist_exprs(subroot->parse->targetList, false),
667 NULL,
668 NULL);
669 }
670}
671
672/*
673 * Generate paths for a UNION or UNION ALL node
674 */
675static RelOptInfo *
677 List *refnames_tlist,
678 List **pTargetList)
679{
680 Relids relids = NULL;
681 RelOptInfo *result_rel;
682 ListCell *lc;
683 ListCell *lc2;
684 ListCell *lc3;
685 List *cheapest_pathlist = NIL;
686 List *ordered_pathlist = NIL;
687 List *partial_pathlist = NIL;
688 bool partial_paths_valid = true;
689 bool consider_parallel = true;
690 List *rellist;
691 List *tlist_list;
692 List *trivial_tlist_list;
693 List *tlist;
694 List *groupList = NIL;
695 Path *apath;
696 Path *gpath = NULL;
697 bool try_sorted = false;
698 List *union_pathkeys = NIL;
699
700 /*
701 * If any of my children are identical UNION nodes (same op, all-flag, and
702 * colTypes/colCollations) then they can be merged into this node so that
703 * we generate only one Append/MergeAppend and unique-ification for the
704 * lot. Recurse to find such nodes.
705 */
706 rellist = plan_union_children(root,
707 op,
708 refnames_tlist,
709 &tlist_list,
710 &trivial_tlist_list);
711
712 /*
713 * Generate tlist for Append/MergeAppend plan node.
714 *
715 * The tlist for an Append plan isn't important as far as the Append is
716 * concerned, but we must make it look real anyway for the benefit of the
717 * next plan level up.
718 */
719 tlist = generate_append_tlist(op->colTypes, op->colCollations,
720 tlist_list, refnames_tlist);
721 *pTargetList = tlist;
722
723 /* For UNIONs (not UNION ALL), try sorting, if sorting is possible */
724 if (!op->all)
725 {
726 /* Identify the grouping semantics */
727 groupList = generate_setop_grouplist(op, tlist);
728
729 if (grouping_is_sortable(op->groupClauses))
730 {
731 try_sorted = true;
732 /* Determine the pathkeys for sorting by the whole target list */
733 union_pathkeys = make_pathkeys_for_sortclauses(root, groupList,
734 tlist);
735
736 root->query_pathkeys = union_pathkeys;
737 }
738 }
739
740 /*
741 * Now that we've got the append target list, we can build the union child
742 * paths.
743 */
744 forthree(lc, rellist, lc2, trivial_tlist_list, lc3, tlist_list)
745 {
746 RelOptInfo *rel = lfirst(lc);
747 bool trivial_tlist = lfirst_int(lc2);
748 List *child_tlist = lfirst_node(List, lc3);
749
750 /* only build paths for the union children */
751 if (rel->rtekind == RTE_SUBQUERY)
752 build_setop_child_paths(root, rel, trivial_tlist, child_tlist,
753 union_pathkeys, NULL);
754 }
755
756 /* Build path lists and relid set. */
757 foreach(lc, rellist)
758 {
759 RelOptInfo *rel = lfirst(lc);
760 Path *ordered_path;
761
762 cheapest_pathlist = lappend(cheapest_pathlist,
764
765 if (try_sorted)
766 {
767 ordered_path = get_cheapest_path_for_pathkeys(rel->pathlist,
768 union_pathkeys,
769 NULL,
771 false);
772
773 if (ordered_path != NULL)
774 ordered_pathlist = lappend(ordered_pathlist, ordered_path);
775 else
776 {
777 /*
778 * If we can't find a sorted path, just give up trying to
779 * generate a list of correctly sorted child paths. This can
780 * happen when type coercion was added to the targetlist due
781 * to mismatching types from the union children.
782 */
783 try_sorted = false;
784 }
785 }
786
787 if (consider_parallel)
788 {
789 if (!rel->consider_parallel)
790 {
791 consider_parallel = false;
792 partial_paths_valid = false;
793 }
794 else if (rel->partial_pathlist == NIL)
795 partial_paths_valid = false;
796 else
797 partial_pathlist = lappend(partial_pathlist,
799 }
800
801 relids = bms_union(relids, rel->relids);
802 }
803
804 /* Build result relation. */
805 result_rel = fetch_upper_rel(root, UPPERREL_SETOP, relids);
806 result_rel->reltarget = create_pathtarget(root, tlist);
807 result_rel->consider_parallel = consider_parallel;
808 result_rel->consider_startup = (root->tuple_fraction > 0);
809
810 /*
811 * Append the child results together using the cheapest paths from each
812 * union child.
813 */
814 apath = (Path *) create_append_path(root, result_rel, cheapest_pathlist,
815 NIL, NIL, NULL, 0, false, -1);
816
817 /*
818 * Estimate number of groups. For now we just assume the output is unique
819 * --- this is certainly true for the UNION case, and we want worst-case
820 * estimates anyway.
821 */
822 result_rel->rows = apath->rows;
823
824 /*
825 * Now consider doing the same thing using the partial paths plus Append
826 * plus Gather.
827 */
828 if (partial_paths_valid)
829 {
830 Path *papath;
831 int parallel_workers = 0;
832
833 /* Find the highest number of workers requested for any subpath. */
834 foreach(lc, partial_pathlist)
835 {
836 Path *subpath = lfirst(lc);
837
838 parallel_workers = Max(parallel_workers,
839 subpath->parallel_workers);
840 }
841 Assert(parallel_workers > 0);
842
843 /*
844 * If the use of parallel append is permitted, always request at least
845 * log2(# of children) paths. We assume it can be useful to have
846 * extra workers in this case because they will be spread out across
847 * the children. The precise formula is just a guess; see
848 * add_paths_to_append_rel.
849 */
851 {
852 parallel_workers = Max(parallel_workers,
853 pg_leftmost_one_pos32(list_length(partial_pathlist)) + 1);
854 parallel_workers = Min(parallel_workers,
856 }
857 Assert(parallel_workers > 0);
858
859 papath = (Path *)
860 create_append_path(root, result_rel, NIL, partial_pathlist,
861 NIL, NULL, parallel_workers,
863 gpath = (Path *)
864 create_gather_path(root, result_rel, papath,
865 result_rel->reltarget, NULL, NULL);
866 }
867
868 if (!op->all)
869 {
870 double dNumGroups;
871 bool can_sort = grouping_is_sortable(groupList);
872 bool can_hash = grouping_is_hashable(groupList);
873
874 /*
875 * XXX for the moment, take the number of distinct groups as equal to
876 * the total input size, i.e., the worst case. This is too
877 * conservative, but it's not clear how to get a decent estimate of
878 * the true size. One should note as well the propensity of novices
879 * to write UNION rather than UNION ALL even when they don't expect
880 * any duplicates...
881 */
882 dNumGroups = apath->rows;
883
884 if (can_hash)
885 {
886 Path *path;
887
888 /*
889 * Try a hash aggregate plan on 'apath'. This is the cheapest
890 * available path containing each append child.
891 */
892 path = (Path *) create_agg_path(root,
893 result_rel,
894 apath,
895 create_pathtarget(root, tlist),
898 groupList,
899 NIL,
900 NULL,
901 dNumGroups);
902 add_path(result_rel, path);
903
904 /* Try hash aggregate on the Gather path, if valid */
905 if (gpath != NULL)
906 {
907 /* Hashed aggregate plan --- no sort needed */
908 path = (Path *) create_agg_path(root,
909 result_rel,
910 gpath,
911 create_pathtarget(root, tlist),
914 groupList,
915 NIL,
916 NULL,
917 dNumGroups);
918 add_path(result_rel, path);
919 }
920 }
921
922 if (can_sort)
923 {
924 Path *path = apath;
925
926 /* Try Sort -> Unique on the Append path */
927 if (groupList != NIL)
928 path = (Path *) create_sort_path(root, result_rel, path,
929 make_pathkeys_for_sortclauses(root, groupList, tlist),
930 -1.0);
931
933 result_rel,
934 path,
935 list_length(path->pathkeys),
936 dNumGroups);
937
938 add_path(result_rel, path);
939
940 /* Try Sort -> Unique on the Gather path, if set */
941 if (gpath != NULL)
942 {
943 path = gpath;
944
945 path = (Path *) create_sort_path(root, result_rel, path,
946 make_pathkeys_for_sortclauses(root, groupList, tlist),
947 -1.0);
948
950 result_rel,
951 path,
952 list_length(path->pathkeys),
953 dNumGroups);
954 add_path(result_rel, path);
955 }
956 }
957
958 /*
959 * Try making a MergeAppend path if we managed to find a path with the
960 * correct pathkeys in each union child query.
961 */
962 if (try_sorted && groupList != NIL)
963 {
964 Path *path;
965
967 result_rel,
968 ordered_pathlist,
969 union_pathkeys,
970 NULL);
971
972 /* and make the MergeAppend unique */
974 result_rel,
975 path,
976 list_length(tlist),
977 dNumGroups);
978
979 add_path(result_rel, path);
980 }
981 }
982 else
983 {
984 /* UNION ALL */
985 add_path(result_rel, apath);
986
987 if (gpath != NULL)
988 add_path(result_rel, gpath);
989 }
990
991 return result_rel;
992}
993
994/*
995 * Generate paths for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node
996 */
997static RelOptInfo *
999 List *refnames_tlist,
1000 List **pTargetList)
1001{
1002 RelOptInfo *result_rel;
1003 RelOptInfo *lrel,
1004 *rrel;
1005 double save_fraction = root->tuple_fraction;
1006 Path *lpath,
1007 *rpath,
1008 *path;
1009 List *lpath_tlist,
1010 *rpath_tlist,
1011 *tlist,
1012 *groupList;
1013 bool lpath_trivial_tlist,
1014 rpath_trivial_tlist,
1015 result_trivial_tlist;
1016 List *nonunion_pathkeys = NIL;
1017 double dLeftGroups,
1018 dRightGroups,
1019 dNumGroups,
1020 dNumOutputRows;
1021 bool can_sort;
1022 bool can_hash;
1023 SetOpCmd cmd;
1024
1025 /*
1026 * Tell children to fetch all tuples.
1027 */
1028 root->tuple_fraction = 0.0;
1029
1030 /* Recurse on children */
1031 lrel = recurse_set_operations(op->larg, root,
1032 op,
1033 op->colTypes, op->colCollations,
1034 refnames_tlist,
1035 &lpath_tlist,
1036 &lpath_trivial_tlist);
1037
1038 rrel = recurse_set_operations(op->rarg, root,
1039 op,
1040 op->colTypes, op->colCollations,
1041 refnames_tlist,
1042 &rpath_tlist,
1043 &rpath_trivial_tlist);
1044
1045 /*
1046 * Generate tlist for SetOp plan node.
1047 *
1048 * The tlist for a SetOp plan isn't important so far as the SetOp is
1049 * concerned, but we must make it look real anyway for the benefit of the
1050 * next plan level up.
1051 */
1052 tlist = generate_setop_tlist(op->colTypes, op->colCollations,
1053 0, false, lpath_tlist, refnames_tlist,
1054 &result_trivial_tlist);
1055
1056 /* We should not have needed any type coercions in the tlist */
1057 Assert(result_trivial_tlist);
1058
1059 *pTargetList = tlist;
1060
1061 /* Identify the grouping semantics */
1062 groupList = generate_setop_grouplist(op, tlist);
1063
1064 /* Check whether the operators support sorting or hashing */
1065 can_sort = grouping_is_sortable(groupList);
1066 can_hash = grouping_is_hashable(groupList);
1067 if (!can_sort && !can_hash)
1068 ereport(ERROR,
1069 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1070 /* translator: %s is INTERSECT or EXCEPT */
1071 errmsg("could not implement %s",
1072 (op->op == SETOP_INTERSECT) ? "INTERSECT" : "EXCEPT"),
1073 errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
1074
1075 if (can_sort)
1076 {
1077 /* Determine the pathkeys for sorting by the whole target list */
1078 nonunion_pathkeys = make_pathkeys_for_sortclauses(root, groupList,
1079 tlist);
1080
1081 root->query_pathkeys = nonunion_pathkeys;
1082 }
1083
1084 /*
1085 * Now that we've got all that info, we can build the child paths.
1086 */
1087 if (lrel->rtekind == RTE_SUBQUERY)
1088 build_setop_child_paths(root, lrel, lpath_trivial_tlist, lpath_tlist,
1089 nonunion_pathkeys, &dLeftGroups);
1090 else
1091 dLeftGroups = lrel->rows;
1092 if (rrel->rtekind == RTE_SUBQUERY)
1093 build_setop_child_paths(root, rrel, rpath_trivial_tlist, rpath_tlist,
1094 nonunion_pathkeys, &dRightGroups);
1095 else
1096 dRightGroups = rrel->rows;
1097
1098 /* Undo effects of forcing tuple_fraction to 0 */
1099 root->tuple_fraction = save_fraction;
1100
1101 /*
1102 * For EXCEPT, we must put the left input first. For INTERSECT, either
1103 * order should give the same results, and we prefer to put the smaller
1104 * input first in order to (a) minimize the size of the hash table in the
1105 * hashing case, and (b) improve our chances of exploiting the executor's
1106 * fast path for empty left-hand input. "Smaller" means the one with the
1107 * fewer groups.
1108 */
1109 if (op->op != SETOP_EXCEPT && dLeftGroups > dRightGroups)
1110 {
1111 /* need to swap the two inputs */
1112 RelOptInfo *tmprel;
1113 List *tmplist;
1114 double tmpd;
1115
1116 tmprel = lrel;
1117 lrel = rrel;
1118 rrel = tmprel;
1119 tmplist = lpath_tlist;
1120 lpath_tlist = rpath_tlist;
1121 rpath_tlist = tmplist;
1122 tmpd = dLeftGroups;
1123 dLeftGroups = dRightGroups;
1124 dRightGroups = tmpd;
1125 }
1126
1127 lpath = lrel->cheapest_total_path;
1128 rpath = rrel->cheapest_total_path;
1129
1130 /* Build result relation. */
1131 result_rel = fetch_upper_rel(root, UPPERREL_SETOP,
1132 bms_union(lrel->relids, rrel->relids));
1133 result_rel->reltarget = create_pathtarget(root, tlist);
1134
1135 /*
1136 * Estimate number of distinct groups that we'll need hashtable entries
1137 * for; this is the size of the left-hand input for EXCEPT, or the smaller
1138 * input for INTERSECT. Also estimate the number of eventual output rows.
1139 * In non-ALL cases, we estimate each group produces one output row; in
1140 * ALL cases use the relevant relation size. These are worst-case
1141 * estimates, of course, but we need to be conservative.
1142 */
1143 if (op->op == SETOP_EXCEPT)
1144 {
1145 dNumGroups = dLeftGroups;
1146 dNumOutputRows = op->all ? lpath->rows : dNumGroups;
1147 }
1148 else
1149 {
1150 dNumGroups = dLeftGroups;
1151 dNumOutputRows = op->all ? Min(lpath->rows, rpath->rows) : dNumGroups;
1152 }
1153 result_rel->rows = dNumOutputRows;
1154
1155 /* Select the SetOpCmd type */
1156 switch (op->op)
1157 {
1158 case SETOP_INTERSECT:
1160 break;
1161 case SETOP_EXCEPT:
1163 break;
1164 default:
1165 elog(ERROR, "unrecognized set op: %d", (int) op->op);
1166 cmd = SETOPCMD_INTERSECT; /* keep compiler quiet */
1167 break;
1168 }
1169
1170 /*
1171 * If we can hash, that just requires a SetOp atop the cheapest inputs.
1172 */
1173 if (can_hash)
1174 {
1175 path = (Path *) create_setop_path(root,
1176 result_rel,
1177 lpath,
1178 rpath,
1179 cmd,
1181 groupList,
1182 dNumGroups,
1183 dNumOutputRows);
1184 add_path(result_rel, path);
1185 }
1186
1187 /*
1188 * If we can sort, generate the cheapest sorted input paths, and add a
1189 * SetOp atop those.
1190 */
1191 if (can_sort)
1192 {
1193 List *pathkeys;
1194 Path *slpath,
1195 *srpath;
1196
1197 /* First the left input ... */
1199 groupList,
1200 lpath_tlist);
1201 if (pathkeys_contained_in(pathkeys, lpath->pathkeys))
1202 slpath = lpath; /* cheapest path is already sorted */
1203 else
1204 {
1206 nonunion_pathkeys,
1207 NULL,
1208 TOTAL_COST,
1209 false);
1210 /* Subquery failed to produce any presorted paths? */
1211 if (slpath == NULL)
1212 slpath = (Path *) create_sort_path(root,
1213 lpath->parent,
1214 lpath,
1215 pathkeys,
1216 -1.0);
1217 }
1218
1219 /* and now the same for the right. */
1221 groupList,
1222 rpath_tlist);
1223 if (pathkeys_contained_in(pathkeys, rpath->pathkeys))
1224 srpath = rpath; /* cheapest path is already sorted */
1225 else
1226 {
1228 nonunion_pathkeys,
1229 NULL,
1230 TOTAL_COST,
1231 false);
1232 /* Subquery failed to produce any presorted paths? */
1233 if (srpath == NULL)
1234 srpath = (Path *) create_sort_path(root,
1235 rpath->parent,
1236 rpath,
1237 pathkeys,
1238 -1.0);
1239 }
1240
1241 path = (Path *) create_setop_path(root,
1242 result_rel,
1243 slpath,
1244 srpath,
1245 cmd,
1247 groupList,
1248 dNumGroups,
1249 dNumOutputRows);
1250 add_path(result_rel, path);
1251 }
1252
1253 return result_rel;
1254}
1255
1256/*
1257 * Pull up children of a UNION node that are identically-propertied UNIONs,
1258 * and perform planning of the queries underneath the N-way UNION.
1259 *
1260 * The result is a list of RelOptInfos containing Paths for sub-nodes, with
1261 * one entry for each descendant that is a leaf query or non-identical setop.
1262 * We also return parallel lists of the childrens' targetlists and
1263 * is-trivial-tlist flags.
1264 *
1265 * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
1266 * output rows will be lost anyway.
1267 */
1268static List *
1270 SetOperationStmt *top_union,
1271 List *refnames_tlist,
1272 List **tlist_list,
1273 List **istrivial_tlist)
1274{
1275 List *pending_rels = list_make1(top_union);
1276 List *result = NIL;
1277 List *child_tlist;
1278 bool trivial_tlist;
1279
1280 *tlist_list = NIL;
1281 *istrivial_tlist = NIL;
1282
1283 while (pending_rels != NIL)
1284 {
1285 Node *setOp = linitial(pending_rels);
1286
1287 pending_rels = list_delete_first(pending_rels);
1288
1289 if (IsA(setOp, SetOperationStmt))
1290 {
1291 SetOperationStmt *op = (SetOperationStmt *) setOp;
1292
1293 if (op->op == top_union->op &&
1294 (op->all == top_union->all || op->all) &&
1295 equal(op->colTypes, top_union->colTypes) &&
1296 equal(op->colCollations, top_union->colCollations))
1297 {
1298 /* Same UNION, so fold children into parent */
1299 pending_rels = lcons(op->rarg, pending_rels);
1300 pending_rels = lcons(op->larg, pending_rels);
1301 continue;
1302 }
1303 }
1304
1305 /*
1306 * Not same, so plan this child separately.
1307 *
1308 * If top_union isn't a UNION ALL, then we are interested in sorted
1309 * output from the child, so pass top_union as parentOp. Note that
1310 * this isn't necessarily the child node's immediate SetOperationStmt
1311 * parent, but that's fine: it's the effective parent.
1312 */
1313 result = lappend(result, recurse_set_operations(setOp, root,
1314 top_union->all ? NULL : top_union,
1315 top_union->colTypes,
1316 top_union->colCollations,
1317 refnames_tlist,
1318 &child_tlist,
1319 &trivial_tlist));
1320 *tlist_list = lappend(*tlist_list, child_tlist);
1321 *istrivial_tlist = lappend_int(*istrivial_tlist, trivial_tlist);
1322 }
1323
1324 return result;
1325}
1326
1327/*
1328 * postprocess_setop_rel - perform steps required after adding paths
1329 */
1330static void
1332{
1333 /*
1334 * We don't currently worry about allowing FDWs to contribute paths to
1335 * this relation, but give extensions a chance.
1336 */
1338 (*create_upper_paths_hook) (root, UPPERREL_SETOP,
1339 NULL, rel, NULL);
1340
1341 /* Select cheapest path */
1342 set_cheapest(rel);
1343}
1344
1345/*
1346 * Generate targetlist for a set-operation plan node
1347 *
1348 * colTypes: OID list of set-op's result column datatypes
1349 * colCollations: OID list of set-op's result column collations
1350 * varno: varno to use in generated Vars
1351 * hack_constants: true to copy up constants (see comments in code)
1352 * input_tlist: targetlist of this node's input node
1353 * refnames_tlist: targetlist to take column names from
1354 * trivial_tlist: output parameter, set to true if targetlist is trivial
1355 */
1356static List *
1357generate_setop_tlist(List *colTypes, List *colCollations,
1358 Index varno,
1359 bool hack_constants,
1360 List *input_tlist,
1361 List *refnames_tlist,
1362 bool *trivial_tlist)
1363{
1364 List *tlist = NIL;
1365 int resno = 1;
1366 ListCell *ctlc,
1367 *cclc,
1368 *itlc,
1369 *rtlc;
1370 TargetEntry *tle;
1371 Node *expr;
1372
1373 *trivial_tlist = true; /* until proven differently */
1374
1375 forfour(ctlc, colTypes, cclc, colCollations,
1376 itlc, input_tlist, rtlc, refnames_tlist)
1377 {
1378 Oid colType = lfirst_oid(ctlc);
1379 Oid colColl = lfirst_oid(cclc);
1380 TargetEntry *inputtle = (TargetEntry *) lfirst(itlc);
1381 TargetEntry *reftle = (TargetEntry *) lfirst(rtlc);
1382
1383 Assert(inputtle->resno == resno);
1384 Assert(reftle->resno == resno);
1385 Assert(!inputtle->resjunk);
1386 Assert(!reftle->resjunk);
1387
1388 /*
1389 * Generate columns referencing input columns and having appropriate
1390 * data types and column names. Insert datatype coercions where
1391 * necessary.
1392 *
1393 * HACK: constants in the input's targetlist are copied up as-is
1394 * rather than being referenced as subquery outputs. This is mainly
1395 * to ensure that when we try to coerce them to the output column's
1396 * datatype, the right things happen for UNKNOWN constants. But do
1397 * this only at the first level of subquery-scan plans; we don't want
1398 * phony constants appearing in the output tlists of upper-level
1399 * nodes!
1400 *
1401 * Note that copying a constant doesn't in itself require us to mark
1402 * the tlist nontrivial; see trivial_subqueryscan() in setrefs.c.
1403 */
1404 if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
1405 expr = (Node *) inputtle->expr;
1406 else
1407 expr = (Node *) makeVar(varno,
1408 inputtle->resno,
1409 exprType((Node *) inputtle->expr),
1410 exprTypmod((Node *) inputtle->expr),
1411 exprCollation((Node *) inputtle->expr),
1412 0);
1413
1414 if (exprType(expr) != colType)
1415 {
1416 /*
1417 * Note: it's not really cool to be applying coerce_to_common_type
1418 * here; one notable point is that assign_expr_collations never
1419 * gets run on any generated nodes. For the moment that's not a
1420 * problem because we force the correct exposed collation below.
1421 * It would likely be best to make the parser generate the correct
1422 * output tlist for every set-op to begin with, though.
1423 */
1424 expr = coerce_to_common_type(NULL, /* no UNKNOWNs here */
1425 expr,
1426 colType,
1427 "UNION/INTERSECT/EXCEPT");
1428 *trivial_tlist = false; /* the coercion makes it not trivial */
1429 }
1430
1431 /*
1432 * Ensure the tlist entry's exposed collation matches the set-op. This
1433 * is necessary because plan_set_operations() reports the result
1434 * ordering as a list of SortGroupClauses, which don't carry collation
1435 * themselves but just refer to tlist entries. If we don't show the
1436 * right collation then planner.c might do the wrong thing in
1437 * higher-level queries.
1438 *
1439 * Note we use RelabelType, not CollateExpr, since this expression
1440 * will reach the executor without any further processing.
1441 */
1442 if (exprCollation(expr) != colColl)
1443 {
1444 expr = applyRelabelType(expr,
1445 exprType(expr), exprTypmod(expr), colColl,
1446 COERCE_IMPLICIT_CAST, -1, false);
1447 *trivial_tlist = false; /* the relabel makes it not trivial */
1448 }
1449
1450 tle = makeTargetEntry((Expr *) expr,
1451 (AttrNumber) resno++,
1452 pstrdup(reftle->resname),
1453 false);
1454
1455 /*
1456 * By convention, all output columns in a setop tree have
1457 * ressortgroupref equal to their resno. In some cases the ref isn't
1458 * needed, but this is a cleaner way than modifying the tlist later.
1459 */
1460 tle->ressortgroupref = tle->resno;
1461
1462 tlist = lappend(tlist, tle);
1463 }
1464
1465 return tlist;
1466}
1467
1468/*
1469 * Generate targetlist for a set-operation Append node
1470 *
1471 * colTypes: OID list of set-op's result column datatypes
1472 * colCollations: OID list of set-op's result column collations
1473 * input_tlists: list of tlists for sub-plans of the Append
1474 * refnames_tlist: targetlist to take column names from
1475 *
1476 * The entries in the Append's targetlist should always be simple Vars;
1477 * we just have to make sure they have the right datatypes/typmods/collations.
1478 * The Vars are always generated with varno 0.
1479 *
1480 * XXX a problem with the varno-zero approach is that set_pathtarget_cost_width
1481 * cannot figure out a realistic width for the tlist we make here. But we
1482 * ought to refactor this code to produce a PathTarget directly, anyway.
1483 */
1484static List *
1485generate_append_tlist(List *colTypes, List *colCollations,
1486 List *input_tlists,
1487 List *refnames_tlist)
1488{
1489 List *tlist = NIL;
1490 int resno = 1;
1491 ListCell *curColType;
1492 ListCell *curColCollation;
1493 ListCell *ref_tl_item;
1494 int colindex;
1495 TargetEntry *tle;
1496 Node *expr;
1497 ListCell *tlistl;
1498 int32 *colTypmods;
1499
1500 /*
1501 * First extract typmods to use.
1502 *
1503 * If the inputs all agree on type and typmod of a particular column, use
1504 * that typmod; else use -1.
1505 */
1506 colTypmods = (int32 *) palloc(list_length(colTypes) * sizeof(int32));
1507
1508 foreach(tlistl, input_tlists)
1509 {
1510 List *subtlist = (List *) lfirst(tlistl);
1511 ListCell *subtlistl;
1512
1513 curColType = list_head(colTypes);
1514 colindex = 0;
1515 foreach(subtlistl, subtlist)
1516 {
1517 TargetEntry *subtle = (TargetEntry *) lfirst(subtlistl);
1518
1519 Assert(!subtle->resjunk);
1520 Assert(curColType != NULL);
1521 if (exprType((Node *) subtle->expr) == lfirst_oid(curColType))
1522 {
1523 /* If first subplan, copy the typmod; else compare */
1524 int32 subtypmod = exprTypmod((Node *) subtle->expr);
1525
1526 if (tlistl == list_head(input_tlists))
1527 colTypmods[colindex] = subtypmod;
1528 else if (subtypmod != colTypmods[colindex])
1529 colTypmods[colindex] = -1;
1530 }
1531 else
1532 {
1533 /* types disagree, so force typmod to -1 */
1534 colTypmods[colindex] = -1;
1535 }
1536 curColType = lnext(colTypes, curColType);
1537 colindex++;
1538 }
1539 Assert(curColType == NULL);
1540 }
1541
1542 /*
1543 * Now we can build the tlist for the Append.
1544 */
1545 colindex = 0;
1546 forthree(curColType, colTypes, curColCollation, colCollations,
1547 ref_tl_item, refnames_tlist)
1548 {
1549 Oid colType = lfirst_oid(curColType);
1550 int32 colTypmod = colTypmods[colindex++];
1551 Oid colColl = lfirst_oid(curColCollation);
1552 TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item);
1553
1554 Assert(reftle->resno == resno);
1555 Assert(!reftle->resjunk);
1556 expr = (Node *) makeVar(0,
1557 resno,
1558 colType,
1559 colTypmod,
1560 colColl,
1561 0);
1562 tle = makeTargetEntry((Expr *) expr,
1563 (AttrNumber) resno++,
1564 pstrdup(reftle->resname),
1565 false);
1566
1567 /*
1568 * By convention, all output columns in a setop tree have
1569 * ressortgroupref equal to their resno. In some cases the ref isn't
1570 * needed, but this is a cleaner way than modifying the tlist later.
1571 */
1572 tle->ressortgroupref = tle->resno;
1573
1574 tlist = lappend(tlist, tle);
1575 }
1576
1577 pfree(colTypmods);
1578
1579 return tlist;
1580}
1581
1582/*
1583 * generate_setop_grouplist
1584 * Build a SortGroupClause list defining the sort/grouping properties
1585 * of the setop's output columns.
1586 *
1587 * Parse analysis already determined the properties and built a suitable
1588 * list, except that the entries do not have sortgrouprefs set because
1589 * the parser output representation doesn't include a tlist for each
1590 * setop. So what we need to do here is copy that list and install
1591 * proper sortgrouprefs into it (copying those from the targetlist).
1592 */
1593static List *
1595{
1596 List *grouplist = copyObject(op->groupClauses);
1597 ListCell *lg;
1598 ListCell *lt;
1599
1600 lg = list_head(grouplist);
1601 foreach(lt, targetlist)
1602 {
1603 TargetEntry *tle = (TargetEntry *) lfirst(lt);
1604 SortGroupClause *sgc;
1605
1606 Assert(!tle->resjunk);
1607
1608 /* non-resjunk columns should have sortgroupref = resno */
1609 Assert(tle->ressortgroupref == tle->resno);
1610
1611 /* non-resjunk columns should have grouping clauses */
1612 Assert(lg != NULL);
1613 sgc = (SortGroupClause *) lfirst(lg);
1614 lg = lnext(grouplist, lg);
1615 Assert(sgc->tleSortGroupRef == 0);
1616
1617 sgc->tleSortGroupRef = tle->ressortgroupref;
1618 }
1619 Assert(lg == NULL);
1620 return grouplist;
1621}
int16 AttrNumber
Definition: attnum.h:21
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:975
#define Max(x, y)
Definition: c.h:969
int32_t int32
Definition: c.h:498
unsigned int Index
Definition: c.h:585
int max_parallel_workers_per_gather
Definition: costsize.c:143
void set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel)
Definition: costsize.c:5887
bool enable_parallel_append
Definition: costsize.c:161
bool enable_incremental_sort
Definition: costsize.c:151
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
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)
Definition: equivclass.c:2943
Assert(PointerIsAligned(start, uint64))
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:1699
void pfree(void *pointer)
Definition: mcxt.c:1524
void * palloc(Size size)
Definition: mcxt.c:1317
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:301
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:821
Node * applyRelabelType(Node *arg, Oid rtype, int32 rtypmod, Oid rcollid, CoercionForm rformat, int rlocation, bool overwrite_ok)
Definition: nodeFuncs.c:636
SetOpCmd
Definition: nodes.h:403
@ SETOPCMD_EXCEPT
Definition: nodes.h:406
@ SETOPCMD_EXCEPT_ALL
Definition: nodes.h:407
@ SETOPCMD_INTERSECT_ALL
Definition: nodes.h:405
@ SETOPCMD_INTERSECT
Definition: nodes.h:404
@ SETOP_HASHED
Definition: nodes.h:413
@ SETOP_SORTED
Definition: nodes.h:412
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define copyObject(obj)
Definition: nodes.h:230
#define nodeTag(nodeptr)
Definition: nodes.h:139
@ AGG_HASHED
Definition: nodes.h:362
@ AGGSPLIT_SIMPLE
Definition: nodes.h:383
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
Node * coerce_to_common_type(ParseState *pstate, Node *node, Oid targetTypeId, const char *context)
@ SETOP_INTERSECT
Definition: parsenodes.h:2169
@ SETOP_UNION
Definition: parsenodes.h:2168
@ SETOP_EXCEPT
Definition: parsenodes.h:2170
@ RTE_SUBQUERY
Definition: parsenodes.h:1027
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:1335
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:3650
ProjectionPath * create_projection_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
Definition: pathnode.c:2763
Path * apply_projection_to_path(PlannerInfo *root, RelOptInfo *rel, Path *path, PathTarget *target)
Definition: pathnode.c:2873
void set_cheapest(RelOptInfo *parent_rel)
Definition: pathnode.c:269
void add_partial_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:795
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:1300
SubqueryScanPath * create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, bool trivial_pathtarget, List *pathkeys, Relids required_outer)
Definition: pathnode.c:2088
IncrementalSortPath * create_incremental_sort_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, int presorted_keys, double limit_tuples)
Definition: pathnode.c:3032
SortPath * create_sort_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, double limit_tuples)
Definition: pathnode.c:3082
GatherPath * create_gather_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, Relids required_outer, double *rows)
Definition: pathnode.c:2044
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:461
UpperUniquePath * create_upper_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, int numCols, double numGroups)
Definition: pathnode.c:3187
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:3240
RecursiveUnionPath * create_recursiveunion_path(PlannerInfo *root, RelOptInfo *rel, Path *leftpath, Path *rightpath, PathTarget *target, List *distinctList, int wtParam, double numGroups)
Definition: pathnode.c:3768
MergeAppendPath * create_merge_append_path(PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *pathkeys, Relids required_outer)
Definition: pathnode.c:1471
@ TOTAL_COST
Definition: pathnodes.h:38
@ 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
#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
PlannerInfo * subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, bool hasRecursion, double tuple_fraction, SetOperationStmt *setops)
Definition: planner.c:647
create_upper_paths_hook_type create_upper_paths_hook
Definition: planner.c:76
unsigned int Oid
Definition: postgres_ext.h:30
RelOptInfo * plan_set_operations(PlannerInfo *root)
Definition: prepunion.c:93
static List * generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
Definition: prepunion.c:1594
static RelOptInfo * generate_union_paths(SetOperationStmt *op, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition: prepunion.c:676
static RelOptInfo * generate_nonunion_paths(SetOperationStmt *op, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition: prepunion.c:998
static void postprocess_setop_rel(PlannerInfo *root, RelOptInfo *rel)
Definition: prepunion.c:1331
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:1357
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:209
static RelOptInfo * generate_recursion_path(SetOperationStmt *setOp, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition: prepunion.c:357
static List * generate_append_tlist(List *colTypes, List *colCollations, List *input_tlists, List *refnames_tlist)
Definition: prepunion.c:1485
static List * plan_union_children(PlannerInfo *root, SetOperationStmt *top_union, List *refnames_tlist, List **tlist_list, List **istrivial_tlist)
Definition: prepunion.c:1269
static void build_setop_child_paths(PlannerInfo *root, RelOptInfo *rel, bool trivial_tlist, List *child_tlist, List *interesting_pathkeys, double *pNumGroups)
Definition: prepunion.c:481
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:753
tree ctl root
Definition: radixtree.h:1857
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717
void setup_simple_rel_arrays(PlannerInfo *root)
Definition: relnode.c:94
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1458
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:192
double estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, List **pgset, EstimationInfo *estinfo)
Definition: selfuncs.c:3430
void check_stack_depth(void)
Definition: stack_depth.c:95
Definition: pg_list.h:54
Definition: nodes.h:135
List * pathkeys
Definition: pathnodes.h:1704
Cardinality rows
Definition: pathnodes.h:1698
List * processed_tlist
Definition: pathnodes.h:486
bool hasHavingQual
Definition: pathnodes.h:526
Query * parse
Definition: pathnodes.h:226
Cardinality limit_tuples
Definition: pathnodes.h:513
List * setop_pathkeys
Definition: pathnodes.h:428
List * groupClause
Definition: parsenodes.h:211
List * targetList
Definition: parsenodes.h:193
List * groupingSets
Definition: parsenodes.h:214
List * distinctClause
Definition: parsenodes.h:220
Query * subquery
Definition: parsenodes.h:1118
Relids relids
Definition: pathnodes.h:898
struct PathTarget * reltarget
Definition: pathnodes.h:920
bool consider_parallel
Definition: pathnodes.h:914
Relids lateral_relids
Definition: pathnodes.h:940
List * pathlist
Definition: pathnodes.h:925
struct Path * cheapest_total_path
Definition: pathnodes.h:929
bool consider_startup
Definition: pathnodes.h:910
List * partial_pathlist
Definition: pathnodes.h:927
PlannerInfo * subroot
Definition: pathnodes.h:980
Cardinality rows
Definition: pathnodes.h:904
RTEKind rtekind
Definition: pathnodes.h:949
SetOperation op
Definition: parsenodes.h:2247
Index tleSortGroupRef
Definition: parsenodes.h:1452
Expr * expr
Definition: primnodes.h:2219
AttrNumber resno
Definition: primnodes.h:2221
Index ressortgroupref
Definition: primnodes.h:2225
bool tlist_same_collations(List *tlist, List *colCollations, bool junkOK)
Definition: tlist.c:282
bool grouping_is_sortable(List *groupClause)
Definition: tlist.c:540
List * make_tlist_from_pathtarget(PathTarget *target)
Definition: tlist.c:624
List * get_tlist_exprs(List *tlist, bool includeJunk)
Definition: tlist.c:163
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