1 /*-------------------------------------------------------------------------
4 * Routines to plan set-operation queries. The filename is a leftover
5 * from a time when only UNIONs were implemented.
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.
15 * There is also some code here to support planning of queries that use
16 * inheritance (SELECT FROM foo*). Inheritance trees are converted into
17 * append relations, and thenceforth share code with the UNION ALL case.
20 * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
21 * Portions Copyright (c) 1994, Regents of the University of California
25 * src/backend/optimizer/prep/prepunion.c
27 *-------------------------------------------------------------------------
33 #include "access/heapam.h"
34 #include "access/htup_details.h"
35 #include "access/sysattr.h"
36 #include "catalog/pg_inherits_fn.h"
37 #include "catalog/pg_type.h"
38 #include "miscadmin.h"
39 #include "nodes/makefuncs.h"
40 #include "nodes/nodeFuncs.h"
41 #include "optimizer/cost.h"
42 #include "optimizer/pathnode.h"
43 #include "optimizer/planmain.h"
44 #include "optimizer/planner.h"
45 #include "optimizer/prep.h"
46 #include "optimizer/tlist.h"
47 #include "parser/parse_coerce.h"
48 #include "parser/parsetree.h"
49 #include "utils/lsyscache.h"
50 #include "utils/rel.h"
51 #include "utils/selfuncs.h"
57 AppendRelInfo *appinfo;
58 } adjust_appendrel_attrs_context;
60 static Plan *recurse_set_operations(Node *setOp, PlannerInfo *root,
61 double tuple_fraction,
62 List *colTypes, List *colCollations,
64 int flag, List *refnames_tlist,
65 List **sortClauses, double *pNumGroups);
66 static Plan *generate_recursion_plan(SetOperationStmt *setOp,
67 PlannerInfo *root, double tuple_fraction,
70 static Plan *generate_union_plan(SetOperationStmt *op, PlannerInfo *root,
71 double tuple_fraction,
73 List **sortClauses, double *pNumGroups);
74 static Plan *generate_nonunion_plan(SetOperationStmt *op, PlannerInfo *root,
75 double tuple_fraction,
77 List **sortClauses, double *pNumGroups);
78 static List *recurse_union_children(Node *setOp, PlannerInfo *root,
79 double tuple_fraction,
80 SetOperationStmt *top_union,
81 List *refnames_tlist);
82 static Plan *make_union_unique(SetOperationStmt *op, Plan *plan,
83 PlannerInfo *root, double tuple_fraction,
85 static bool choose_hashed_setop(PlannerInfo *root, List *groupClauses,
87 double dNumGroups, double dNumOutputRows,
88 double tuple_fraction,
89 const char *construct);
90 static List *generate_setop_tlist(List *colTypes, List *colCollations,
95 List *refnames_tlist);
96 static List *generate_append_tlist(List *colTypes, List *colCollations,
99 List *refnames_tlist);
100 static List *generate_setop_grouplist(SetOperationStmt *op, List *targetlist);
101 static void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte,
103 static void make_inh_translation_list(Relation oldrelation,
104 Relation newrelation,
106 List **translated_vars);
107 static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
108 List *translated_vars);
109 static Node *adjust_appendrel_attrs_mutator(Node *node,
110 adjust_appendrel_attrs_context *context);
111 static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid);
112 static List *adjust_inherited_tlist(List *tlist,
113 AppendRelInfo *context);
117 * plan_set_operations
119 * Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT)
121 * This routine only deals with the setOperations tree of the given query.
122 * Any top-level ORDER BY requested in root->parse->sortClause will be added
123 * when we return to grouping_planner.
125 * tuple_fraction is the fraction of tuples we expect will be retrieved.
126 * tuple_fraction is interpreted as for grouping_planner(); in particular,
127 * zero means "all the tuples will be fetched". Any LIMIT present at the
128 * top level has already been factored into tuple_fraction.
130 * *sortClauses is an output argument: it is set to a list of SortGroupClauses
131 * representing the result ordering of the topmost set operation. (This will
132 * be NIL if the output isn't ordered.)
135 plan_set_operations(PlannerInfo *root, double tuple_fraction,
138 Query *parse = root->parse;
139 SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;
141 RangeTblEntry *leftmostRTE;
142 Query *leftmostQuery;
144 Assert(topop && IsA(topop, SetOperationStmt));
146 /* check for unsupported stuff */
147 Assert(parse->jointree->fromlist == NIL);
148 Assert(parse->jointree->quals == NULL);
149 Assert(parse->groupClause == NIL);
150 Assert(parse->havingQual == NULL);
151 Assert(parse->windowClause == NIL);
152 Assert(parse->distinctClause == NIL);
155 * We'll need to build RelOptInfos for each of the leaf subqueries, which
156 * are RTE_SUBQUERY rangetable entries in this Query. Prepare the index
159 setup_simple_rel_arrays(root);
162 * Find the leftmost component Query. We need to use its column names for
163 * all generated tlists (else SELECT INTO won't work right).
166 while (node && IsA(node, SetOperationStmt))
167 node = ((SetOperationStmt *) node)->larg;
168 Assert(node && IsA(node, RangeTblRef));
169 leftmostRTE = root->simple_rte_array[((RangeTblRef *) node)->rtindex];
170 leftmostQuery = leftmostRTE->subquery;
171 Assert(leftmostQuery != NULL);
174 * If the topmost node is a recursive union, it needs special processing.
176 if (root->hasRecursion)
177 return generate_recursion_plan(topop, root, tuple_fraction,
178 leftmostQuery->targetList,
182 * Recurse on setOperations tree to generate plans for set ops. The final
183 * output plan should have just the column types shown as the output from
184 * the top-level node, plus possibly resjunk working columns (we can rely
185 * on upper-level nodes to deal with that).
187 return recurse_set_operations((Node *) topop, root, tuple_fraction,
188 topop->colTypes, topop->colCollations,
190 leftmostQuery->targetList,
195 * recurse_set_operations
196 * Recursively handle one step in a tree of set operations
198 * tuple_fraction: fraction of tuples we expect to retrieve from node
199 * colTypes: OID list of set-op's result column datatypes
200 * colCollations: OID list of set-op's result column collations
201 * junkOK: if true, child resjunk columns may be left in the result
202 * flag: if >= 0, add a resjunk output column indicating value of flag
203 * refnames_tlist: targetlist to take column names from
205 * Returns a plan for the subtree, as well as these output parameters:
206 * *sortClauses: receives list of SortGroupClauses for result plan, if any
207 * *pNumGroups: if not NULL, we estimate the number of distinct groups
208 * in the result, and store it there
210 * We don't have to care about typmods here: the only allowed difference
211 * between set-op input and output typmods is input is a specific typmod
212 * and output is -1, and that does not require a coercion.
215 recurse_set_operations(Node *setOp, PlannerInfo *root,
216 double tuple_fraction,
217 List *colTypes, List *colCollations,
219 int flag, List *refnames_tlist,
220 List **sortClauses, double *pNumGroups)
222 if (IsA(setOp, RangeTblRef))
224 RangeTblRef *rtr = (RangeTblRef *) setOp;
225 RangeTblEntry *rte = root->simple_rte_array[rtr->rtindex];
226 Query *subquery = rte->subquery;
228 PlannerInfo *subroot;
232 Assert(subquery != NULL);
235 * We need to build a RelOptInfo for each leaf subquery. This isn't
236 * used for anything here, but it carries the subroot data structures
237 * forward to setrefs.c processing.
239 rel = build_simple_rel(root, rtr->rtindex, RELOPT_BASEREL);
241 /* plan_params should not be in use in current query level */
242 Assert(root->plan_params == NIL);
245 * Generate plan for primitive subquery
247 subplan = subquery_planner(root->glob, subquery,
249 false, tuple_fraction,
252 /* Save subroot and subplan in RelOptInfo for setrefs.c */
253 rel->subplan = subplan;
254 rel->subroot = subroot;
257 * It should not be possible for the primitive query to contain any
258 * cross-references to other primitive queries in the setop tree.
260 if (root->plan_params)
261 elog(ERROR, "unexpected outer reference in set operation subquery");
264 * Estimate number of groups if caller wants it. If the subquery used
265 * grouping or aggregation, its output is probably mostly unique
266 * anyway; otherwise do statistical estimation.
270 if (subquery->groupClause || subquery->distinctClause ||
271 subroot->hasHavingQual || subquery->hasAggs)
272 *pNumGroups = subplan->plan_rows;
274 *pNumGroups = estimate_num_groups(subroot,
275 get_tlist_exprs(subquery->targetList, false),
280 * Add a SubqueryScan with the caller-requested targetlist
283 make_subqueryscan(generate_setop_tlist(colTypes, colCollations,
294 * We don't bother to determine the subquery's output ordering since
295 * it won't be reflected in the set-op result anyhow.
301 else if (IsA(setOp, SetOperationStmt))
303 SetOperationStmt *op = (SetOperationStmt *) setOp;
306 /* UNIONs are much different from INTERSECT/EXCEPT */
307 if (op->op == SETOP_UNION)
308 plan = generate_union_plan(op, root, tuple_fraction,
310 sortClauses, pNumGroups);
312 plan = generate_nonunion_plan(op, root, tuple_fraction,
314 sortClauses, pNumGroups);
317 * If necessary, add a Result node to project the caller-requested
320 * XXX you don't really want to know about this: setrefs.c will apply
321 * fix_upper_expr() to the Result node's tlist. This would fail if the
322 * Vars generated by generate_setop_tlist() were not exactly equal()
323 * to the corresponding tlist entries of the subplan. However, since
324 * the subplan was generated by generate_union_plan() or
325 * generate_nonunion_plan(), and hence its tlist was generated by
326 * generate_append_tlist(), this will work. We just tell
327 * generate_setop_tlist() to use varno 0.
330 !tlist_same_datatypes(plan->targetlist, colTypes, junkOK) ||
331 !tlist_same_collations(plan->targetlist, colCollations, junkOK))
335 generate_setop_tlist(colTypes, colCollations,
348 elog(ERROR, "unrecognized node type: %d",
349 (int) nodeTag(setOp));
350 return NULL; /* keep compiler quiet */
355 * Generate plan for a recursive UNION node
358 generate_recursion_plan(SetOperationStmt *setOp, PlannerInfo *root,
359 double tuple_fraction,
360 List *refnames_tlist,
370 /* Parser should have rejected other cases */
371 if (setOp->op != SETOP_UNION)
372 elog(ERROR, "only UNION queries can be recursive");
373 /* Worktable ID should be assigned */
374 Assert(root->wt_param_id >= 0);
377 * Unlike a regular UNION node, process the left and right inputs
378 * separately without any intention of combining them into one Append.
380 lplan = recurse_set_operations(setOp->larg, root, tuple_fraction,
381 setOp->colTypes, setOp->colCollations,
383 refnames_tlist, sortClauses, NULL);
384 /* The right plan will want to look at the left one ... */
385 root->non_recursive_plan = lplan;
386 rplan = recurse_set_operations(setOp->rarg, root, tuple_fraction,
387 setOp->colTypes, setOp->colCollations,
389 refnames_tlist, sortClauses, NULL);
390 root->non_recursive_plan = NULL;
393 * Generate tlist for RecursiveUnion plan node --- same as in Append cases
395 tlist = generate_append_tlist(setOp->colTypes, setOp->colCollations, false,
396 list_make2(lplan, rplan),
400 * If UNION, identify the grouping operators
411 /* Identify the grouping semantics */
412 groupList = generate_setop_grouplist(setOp, tlist);
414 /* We only support hashing here */
415 if (!grouping_is_hashable(groupList))
417 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
418 errmsg("could not implement recursive UNION"),
419 errdetail("All column datatypes must be hashable.")));
422 * For the moment, take the number of distinct groups as equal to the
423 * total input size, ie, the worst case.
425 dNumGroups = lplan->plan_rows + rplan->plan_rows * 10;
427 /* Also convert to long int --- but 'ware overflow! */
428 numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
432 * And make the plan node.
434 plan = (Plan *) make_recursive_union(tlist, lplan, rplan,
436 groupList, numGroups);
438 *sortClauses = NIL; /* RecursiveUnion result is always unsorted */
444 * Generate plan for a UNION or UNION ALL node
447 generate_union_plan(SetOperationStmt *op, PlannerInfo *root,
448 double tuple_fraction,
449 List *refnames_tlist,
450 List **sortClauses, double *pNumGroups)
457 * If plain UNION, tell children to fetch all tuples.
459 * Note: in UNION ALL, we pass the top-level tuple_fraction unmodified to
460 * each arm of the UNION ALL. One could make a case for reducing the
461 * tuple fraction for later arms (discounting by the expected size of the
462 * earlier arms' results) but it seems not worth the trouble. The normal
463 * case where tuple_fraction isn't already zero is a LIMIT at top level,
464 * and passing it down as-is is usually enough to get the desired result
465 * of preferring fast-start plans.
468 tuple_fraction = 0.0;
471 * If any of my children are identical UNION nodes (same op, all-flag, and
472 * colTypes) then they can be merged into this node so that we generate
473 * only one Append and unique-ification for the lot. Recurse to find such
474 * nodes and compute their children's plans.
476 planlist = list_concat(recurse_union_children(op->larg, root,
479 recurse_union_children(op->rarg, root,
481 op, refnames_tlist));
484 * Generate tlist for Append plan node.
486 * The tlist for an Append plan isn't important as far as the Append is
487 * concerned, but we must make it look real anyway for the benefit of the
488 * next plan level up.
490 tlist = generate_append_tlist(op->colTypes, op->colCollations, false,
491 planlist, refnames_tlist);
494 * Append the child results together.
496 plan = (Plan *) make_append(planlist, tlist);
499 * For UNION ALL, we just need the Append plan. For UNION, need to add
500 * node(s) to remove duplicates.
503 *sortClauses = NIL; /* result of UNION ALL is always unsorted */
505 plan = make_union_unique(op, plan, root, tuple_fraction, sortClauses);
508 * Estimate number of groups if caller wants it. For now we just assume
509 * the output is unique --- this is certainly true for the UNION case, and
510 * we want worst-case estimates anyway.
513 *pNumGroups = plan->plan_rows;
519 * Generate plan for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node
522 generate_nonunion_plan(SetOperationStmt *op, PlannerInfo *root,
523 double tuple_fraction,
524 List *refnames_tlist,
525 List **sortClauses, double *pNumGroups)
543 /* Recurse on children, ensuring their outputs are marked */
544 lplan = recurse_set_operations(op->larg, root,
545 0.0 /* all tuples needed */ ,
546 op->colTypes, op->colCollations,
549 &child_sortclauses, &dLeftGroups);
550 rplan = recurse_set_operations(op->rarg, root,
551 0.0 /* all tuples needed */ ,
552 op->colTypes, op->colCollations,
555 &child_sortclauses, &dRightGroups);
558 * For EXCEPT, we must put the left input first. For INTERSECT, either
559 * order should give the same results, and we prefer to put the smaller
560 * input first in order to minimize the size of the hash table in the
561 * hashing case. "Smaller" means the one with the fewer groups.
563 if (op->op == SETOP_EXCEPT || dLeftGroups <= dRightGroups)
565 planlist = list_make2(lplan, rplan);
570 planlist = list_make2(rplan, lplan);
575 * Generate tlist for Append plan node.
577 * The tlist for an Append plan isn't important as far as the Append is
578 * concerned, but we must make it look real anyway for the benefit of the
579 * next plan level up. In fact, it has to be real enough that the flag
580 * column is shown as a variable not a constant, else setrefs.c will get
583 tlist = generate_append_tlist(op->colTypes, op->colCollations, true,
584 planlist, refnames_tlist);
587 * Append the child results together.
589 plan = (Plan *) make_append(planlist, tlist);
591 /* Identify the grouping semantics */
592 groupList = generate_setop_grouplist(op, tlist);
594 /* punt if nothing to group on (can this happen?) */
595 if (groupList == NIL)
602 * Estimate number of distinct groups that we'll need hashtable entries
603 * for; this is the size of the left-hand input for EXCEPT, or the smaller
604 * input for INTERSECT. Also estimate the number of eventual output rows.
605 * In non-ALL cases, we estimate each group produces one output row; in
606 * ALL cases use the relevant relation size. These are worst-case
607 * estimates, of course, but we need to be conservative.
609 if (op->op == SETOP_EXCEPT)
611 dNumGroups = dLeftGroups;
612 dNumOutputRows = op->all ? lplan->plan_rows : dNumGroups;
616 dNumGroups = Min(dLeftGroups, dRightGroups);
617 dNumOutputRows = op->all ? Min(lplan->plan_rows, rplan->plan_rows) : dNumGroups;
620 /* Also convert to long int --- but 'ware overflow! */
621 numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
624 * Decide whether to hash or sort, and add a sort node if needed.
626 use_hash = choose_hashed_setop(root, groupList, plan,
627 dNumGroups, dNumOutputRows, tuple_fraction,
628 (op->op == SETOP_INTERSECT) ? "INTERSECT" : "EXCEPT");
631 plan = (Plan *) make_sort_from_sortclauses(root, groupList, plan);
634 * Finally, add a SetOp plan node to generate the correct output.
638 case SETOP_INTERSECT:
639 cmd = op->all ? SETOPCMD_INTERSECT_ALL : SETOPCMD_INTERSECT;
642 cmd = op->all ? SETOPCMD_EXCEPT_ALL : SETOPCMD_EXCEPT;
645 elog(ERROR, "unrecognized set op: %d", (int) op->op);
646 cmd = SETOPCMD_INTERSECT; /* keep compiler quiet */
649 plan = (Plan *) make_setop(cmd, use_hash ? SETOP_HASHED : SETOP_SORTED,
651 list_length(op->colTypes) + 1,
652 use_hash ? firstFlag : -1,
653 numGroups, dNumOutputRows);
655 /* Result is sorted only if we're not hashing */
656 *sortClauses = use_hash ? NIL : groupList;
659 *pNumGroups = dNumGroups;
665 * Pull up children of a UNION node that are identically-propertied UNIONs.
667 * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
668 * output rows will be lost anyway.
670 * NOTE: currently, we ignore collations while determining if a child has
671 * the same properties. This is semantically sound only so long as all
672 * collations have the same notion of equality. It is valid from an
673 * implementation standpoint because we don't care about the ordering of
674 * a UNION child's result: UNION ALL results are always unordered, and
675 * generate_union_plan will force a fresh sort if the top level is a UNION.
678 recurse_union_children(Node *setOp, PlannerInfo *root,
679 double tuple_fraction,
680 SetOperationStmt *top_union,
681 List *refnames_tlist)
683 List *child_sortclauses;
685 if (IsA(setOp, SetOperationStmt))
687 SetOperationStmt *op = (SetOperationStmt *) setOp;
689 if (op->op == top_union->op &&
690 (op->all == top_union->all || op->all) &&
691 equal(op->colTypes, top_union->colTypes))
693 /* Same UNION, so fold children into parent's subplan list */
694 return list_concat(recurse_union_children(op->larg, root,
698 recurse_union_children(op->rarg, root,
706 * Not same, so plan this child separately.
708 * Note we disallow any resjunk columns in child results. This is
709 * necessary since the Append node that implements the union won't do any
710 * projection, and upper levels will get confused if some of our output
711 * tuples have junk and some don't. This case only arises when we have an
712 * EXCEPT or INTERSECT as child, else there won't be resjunk anyway.
714 return list_make1(recurse_set_operations(setOp, root,
717 top_union->colCollations,
720 &child_sortclauses, NULL));
724 * Add nodes to the given plan tree to unique-ify the result of a UNION.
727 make_union_unique(SetOperationStmt *op, Plan *plan,
728 PlannerInfo *root, double tuple_fraction,
735 /* Identify the grouping semantics */
736 groupList = generate_setop_grouplist(op, plan->targetlist);
738 /* punt if nothing to group on (can this happen?) */
739 if (groupList == NIL)
746 * XXX for the moment, take the number of distinct groups as equal to the
747 * total input size, ie, the worst case. This is too conservative, but we
748 * don't want to risk having the hashtable overrun memory; also, it's not
749 * clear how to get a decent estimate of the true size. One should note
750 * as well the propensity of novices to write UNION rather than UNION ALL
751 * even when they don't expect any duplicates...
753 dNumGroups = plan->plan_rows;
755 /* Also convert to long int --- but 'ware overflow! */
756 numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
758 /* Decide whether to hash or sort */
759 if (choose_hashed_setop(root, groupList, plan,
760 dNumGroups, dNumGroups, tuple_fraction,
763 /* Hashed aggregate plan --- no sort needed */
764 plan = (Plan *) make_agg(root,
769 list_length(groupList),
770 extract_grouping_cols(groupList,
772 extract_grouping_ops(groupList),
775 /* Hashed aggregation produces randomly-ordered results */
780 /* Sort and Unique */
781 plan = (Plan *) make_sort_from_sortclauses(root, groupList, plan);
782 plan = (Plan *) make_unique(plan, groupList);
783 plan->plan_rows = dNumGroups;
784 /* We know the sort order of the result */
785 *sortClauses = groupList;
792 * choose_hashed_setop - should we use hashing for a set operation?
795 choose_hashed_setop(PlannerInfo *root, List *groupClauses,
797 double dNumGroups, double dNumOutputRows,
798 double tuple_fraction,
799 const char *construct)
801 int numGroupCols = list_length(groupClauses);
808 /* Check whether the operators support sorting or hashing */
809 can_sort = grouping_is_sortable(groupClauses);
810 can_hash = grouping_is_hashable(groupClauses);
811 if (can_hash && can_sort)
813 /* we have a meaningful choice to make, continue ... */
821 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
822 /* translator: %s is UNION, INTERSECT, or EXCEPT */
823 errmsg("could not implement %s", construct),
824 errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
826 /* Prefer sorting when enable_hashagg is off */
831 * Don't do it if it doesn't look like the hashtable will fit into
834 hashentrysize = MAXALIGN(input_plan->plan_width) + MAXALIGN(sizeof(MinimalTupleData));
836 if (hashentrysize * dNumGroups > work_mem * 1024L)
840 * See if the estimated cost is no more than doing it the other way.
842 * We need to consider input_plan + hashagg versus input_plan + sort +
843 * group. Note that the actual result plan might involve a SetOp or
844 * Unique node, not Agg or Group, but the cost estimates for Agg and Group
845 * should be close enough for our purposes here.
847 * These path variables are dummies that just hold cost fields; we don't
848 * make actual Paths for these steps.
850 cost_agg(&hashed_p, root, AGG_HASHED, NULL,
851 numGroupCols, dNumGroups,
852 input_plan->startup_cost, input_plan->total_cost,
853 input_plan->plan_rows);
856 * Now for the sorted case. Note that the input is *always* unsorted,
857 * since it was made by appending unrelated sub-relations together.
859 sorted_p.startup_cost = input_plan->startup_cost;
860 sorted_p.total_cost = input_plan->total_cost;
861 /* XXX cost_sort doesn't actually look at pathkeys, so just pass NIL */
862 cost_sort(&sorted_p, root, NIL, sorted_p.total_cost,
863 input_plan->plan_rows, input_plan->plan_width,
864 0.0, work_mem, -1.0);
865 cost_group(&sorted_p, root, numGroupCols, dNumGroups,
866 sorted_p.startup_cost, sorted_p.total_cost,
867 input_plan->plan_rows);
870 * Now make the decision using the top-level tuple fraction. First we
871 * have to convert an absolute count (LIMIT) into fractional form.
873 if (tuple_fraction >= 1.0)
874 tuple_fraction /= dNumOutputRows;
876 if (compare_fractional_path_costs(&hashed_p, &sorted_p,
879 /* Hashed is cheaper, so use it */
886 * Generate targetlist for a set-operation plan node
888 * colTypes: OID list of set-op's result column datatypes
889 * colCollations: OID list of set-op's result column collations
890 * flag: -1 if no flag column needed, 0 or 1 to create a const flag column
891 * varno: varno to use in generated Vars
892 * hack_constants: true to copy up constants (see comments in code)
893 * input_tlist: targetlist of this node's input node
894 * refnames_tlist: targetlist to take column names from
897 generate_setop_tlist(List *colTypes, List *colCollations,
902 List *refnames_tlist)
913 /* there's no forfour() so we must chase one list manually */
914 rtlc = list_head(refnames_tlist);
915 forthree(ctlc, colTypes, cclc, colCollations, itlc, input_tlist)
917 Oid colType = lfirst_oid(ctlc);
918 Oid colColl = lfirst_oid(cclc);
919 TargetEntry *inputtle = (TargetEntry *) lfirst(itlc);
920 TargetEntry *reftle = (TargetEntry *) lfirst(rtlc);
924 Assert(inputtle->resno == resno);
925 Assert(reftle->resno == resno);
926 Assert(!inputtle->resjunk);
927 Assert(!reftle->resjunk);
930 * Generate columns referencing input columns and having appropriate
931 * data types and column names. Insert datatype coercions where
934 * HACK: constants in the input's targetlist are copied up as-is
935 * rather than being referenced as subquery outputs. This is mainly
936 * to ensure that when we try to coerce them to the output column's
937 * datatype, the right things happen for UNKNOWN constants. But do
938 * this only at the first level of subquery-scan plans; we don't want
939 * phony constants appearing in the output tlists of upper-level
942 if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
943 expr = (Node *) inputtle->expr;
945 expr = (Node *) makeVar(varno,
947 exprType((Node *) inputtle->expr),
948 exprTypmod((Node *) inputtle->expr),
949 exprCollation((Node *) inputtle->expr),
952 if (exprType(expr) != colType)
955 * Note: it's not really cool to be applying coerce_to_common_type
956 * here; one notable point is that assign_expr_collations never
957 * gets run on any generated nodes. For the moment that's not a
958 * problem because we force the correct exposed collation below.
959 * It would likely be best to make the parser generate the correct
960 * output tlist for every set-op to begin with, though.
962 expr = coerce_to_common_type(NULL, /* no UNKNOWNs here */
965 "UNION/INTERSECT/EXCEPT");
969 * Ensure the tlist entry's exposed collation matches the set-op. This
970 * is necessary because plan_set_operations() reports the result
971 * ordering as a list of SortGroupClauses, which don't carry collation
972 * themselves but just refer to tlist entries. If we don't show the
973 * right collation then planner.c might do the wrong thing in
974 * higher-level queries.
976 * Note we use RelabelType, not CollateExpr, since this expression
977 * will reach the executor without any further processing.
979 if (exprCollation(expr) != colColl)
981 expr = (Node *) makeRelabelType((Expr *) expr,
988 tle = makeTargetEntry((Expr *) expr,
989 (AttrNumber) resno++,
990 pstrdup(reftle->resname),
992 tlist = lappend(tlist, tle);
997 /* Add a resjunk flag column */
998 /* flag value is the given constant */
999 expr = (Node *) makeConst(INT4OID,
1003 Int32GetDatum(flag),
1006 tle = makeTargetEntry((Expr *) expr,
1007 (AttrNumber) resno++,
1010 tlist = lappend(tlist, tle);
1017 * Generate targetlist for a set-operation Append node
1019 * colTypes: OID list of set-op's result column datatypes
1020 * colCollations: OID list of set-op's result column collations
1021 * flag: true to create a flag column copied up from subplans
1022 * input_plans: list of sub-plans of the Append
1023 * refnames_tlist: targetlist to take column names from
1025 * The entries in the Append's targetlist should always be simple Vars;
1026 * we just have to make sure they have the right datatypes/typmods/collations.
1027 * The Vars are always generated with varno 0.
1030 generate_append_tlist(List *colTypes, List *colCollations,
1033 List *refnames_tlist)
1037 ListCell *curColType;
1038 ListCell *curColCollation;
1039 ListCell *ref_tl_item;
1047 * First extract typmods to use.
1049 * If the inputs all agree on type and typmod of a particular column, use
1050 * that typmod; else use -1.
1052 colTypmods = (int32 *) palloc(list_length(colTypes) * sizeof(int32));
1054 foreach(planl, input_plans)
1056 Plan *subplan = (Plan *) lfirst(planl);
1059 curColType = list_head(colTypes);
1061 foreach(subtlist, subplan->targetlist)
1063 TargetEntry *subtle = (TargetEntry *) lfirst(subtlist);
1065 if (subtle->resjunk)
1067 Assert(curColType != NULL);
1068 if (exprType((Node *) subtle->expr) == lfirst_oid(curColType))
1070 /* If first subplan, copy the typmod; else compare */
1071 int32 subtypmod = exprTypmod((Node *) subtle->expr);
1073 if (planl == list_head(input_plans))
1074 colTypmods[colindex] = subtypmod;
1075 else if (subtypmod != colTypmods[colindex])
1076 colTypmods[colindex] = -1;
1080 /* types disagree, so force typmod to -1 */
1081 colTypmods[colindex] = -1;
1083 curColType = lnext(curColType);
1086 Assert(curColType == NULL);
1090 * Now we can build the tlist for the Append.
1093 forthree(curColType, colTypes, curColCollation, colCollations,
1094 ref_tl_item, refnames_tlist)
1096 Oid colType = lfirst_oid(curColType);
1097 int32 colTypmod = colTypmods[colindex++];
1098 Oid colColl = lfirst_oid(curColCollation);
1099 TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item);
1101 Assert(reftle->resno == resno);
1102 Assert(!reftle->resjunk);
1103 expr = (Node *) makeVar(0,
1109 tle = makeTargetEntry((Expr *) expr,
1110 (AttrNumber) resno++,
1111 pstrdup(reftle->resname),
1113 tlist = lappend(tlist, tle);
1118 /* Add a resjunk flag column */
1119 /* flag value is shown as copied up from subplan */
1120 expr = (Node *) makeVar(0,
1126 tle = makeTargetEntry((Expr *) expr,
1127 (AttrNumber) resno++,
1130 tlist = lappend(tlist, tle);
1139 * generate_setop_grouplist
1140 * Build a SortGroupClause list defining the sort/grouping properties
1141 * of the setop's output columns.
1143 * Parse analysis already determined the properties and built a suitable
1144 * list, except that the entries do not have sortgrouprefs set because
1145 * the parser output representation doesn't include a tlist for each
1146 * setop. So what we need to do here is copy that list and install
1147 * proper sortgrouprefs into it and into the targetlist.
1150 generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
1152 List *grouplist = (List *) copyObject(op->groupClauses);
1157 lg = list_head(grouplist);
1158 foreach(lt, targetlist)
1160 TargetEntry *tle = (TargetEntry *) lfirst(lt);
1161 SortGroupClause *sgc;
1163 /* tlist shouldn't have any sortgrouprefs yet */
1164 Assert(tle->ressortgroupref == 0);
1167 continue; /* ignore resjunk columns */
1169 /* non-resjunk columns should have grouping clauses */
1171 sgc = (SortGroupClause *) lfirst(lg);
1173 Assert(sgc->tleSortGroupRef == 0);
1175 /* we could use assignSortGroupRef here, but seems a bit silly */
1176 sgc->tleSortGroupRef = tle->ressortgroupref = refno++;
1184 * expand_inherited_tables
1185 * Expand each rangetable entry that represents an inheritance set
1186 * into an "append relation". At the conclusion of this process,
1187 * the "inh" flag is set in all and only those RTEs that are append
1191 expand_inherited_tables(PlannerInfo *root)
1198 * expand_inherited_rtentry may add RTEs to parse->rtable; there is no
1199 * need to scan them since they can't have inh=true. So just scan as far
1200 * as the original end of the rtable list.
1202 nrtes = list_length(root->parse->rtable);
1203 rl = list_head(root->parse->rtable);
1204 for (rti = 1; rti <= nrtes; rti++)
1206 RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);
1208 expand_inherited_rtentry(root, rte, rti);
1214 * expand_inherited_rtentry
1215 * Check whether a rangetable entry represents an inheritance set.
1216 * If so, add entries for all the child tables to the query's
1217 * rangetable, and build AppendRelInfo nodes for all the child tables
1218 * and add them to root->append_rel_list. If not, clear the entry's
1219 * "inh" flag to prevent later code from looking for AppendRelInfos.
1221 * Note that the original RTE is considered to represent the whole
1222 * inheritance set. The first of the generated RTEs is an RTE for the same
1223 * table, but with inh = false, to represent the parent table in its role
1224 * as a simple member of the inheritance set.
1226 * A childless table is never considered to be an inheritance set; therefore
1227 * a parent RTE must always have at least two associated AppendRelInfos.
1230 expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
1232 Query *parse = root->parse;
1235 Relation oldrelation;
1241 /* Does RT entry allow inheritance? */
1244 /* Ignore any already-expanded UNION ALL nodes */
1245 if (rte->rtekind != RTE_RELATION)
1247 Assert(rte->rtekind == RTE_SUBQUERY);
1250 /* Fast path for common case of childless table */
1251 parentOID = rte->relid;
1252 if (!has_subclass(parentOID))
1254 /* Clear flag before returning */
1260 * The rewriter should already have obtained an appropriate lock on each
1261 * relation named in the query. However, for each child relation we add
1262 * to the query, we must obtain an appropriate lock, because this will be
1263 * the first use of those relations in the parse/rewrite/plan pipeline.
1265 * If the parent relation is the query's result relation, then we need
1266 * RowExclusiveLock. Otherwise, if it's accessed FOR UPDATE/SHARE, we
1267 * need RowShareLock; otherwise AccessShareLock. We can't just grab
1268 * AccessShareLock because then the executor would be trying to upgrade
1269 * the lock, leading to possible deadlocks. (This code should match the
1270 * parser and rewriter.)
1272 oldrc = get_plan_rowmark(root->rowMarks, rti);
1273 if (rti == parse->resultRelation)
1274 lockmode = RowExclusiveLock;
1275 else if (oldrc && RowMarkRequiresRowShareLock(oldrc->markType))
1276 lockmode = RowShareLock;
1278 lockmode = AccessShareLock;
1280 /* Scan for all members of inheritance set, acquire needed locks */
1281 inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
1284 * Check that there's at least one descendant, else treat as no-child
1285 * case. This could happen despite above has_subclass() check, if table
1286 * once had a child but no longer does.
1288 if (list_length(inhOIDs) < 2)
1290 /* Clear flag before returning */
1296 * If parent relation is selected FOR UPDATE/SHARE, we need to mark its
1297 * PlanRowMark as isParent = true, and generate a new PlanRowMark for each
1301 oldrc->isParent = true;
1304 * Must open the parent relation to examine its tupdesc. We need not lock
1305 * it; we assume the rewriter already did.
1307 oldrelation = heap_open(parentOID, NoLock);
1309 /* Scan the inheritance set and expand it */
1313 Oid childOID = lfirst_oid(l);
1314 Relation newrelation;
1315 RangeTblEntry *childrte;
1317 AppendRelInfo *appinfo;
1319 /* Open rel if needed; we already have required locks */
1320 if (childOID != parentOID)
1321 newrelation = heap_open(childOID, NoLock);
1323 newrelation = oldrelation;
1326 * It is possible that the parent table has children that are temp
1327 * tables of other backends. We cannot safely access such tables
1328 * (because of buffering issues), and the best thing to do seems to be
1329 * to silently ignore them.
1331 if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
1333 heap_close(newrelation, lockmode);
1338 * Build an RTE for the child, and attach to query's rangetable list.
1339 * We copy most fields of the parent's RTE, but replace relation OID,
1340 * and set inh = false. Also, set requiredPerms to zero since all
1341 * required permissions checks are done on the original RTE.
1343 childrte = copyObject(rte);
1344 childrte->relid = childOID;
1345 childrte->inh = false;
1346 childrte->requiredPerms = 0;
1347 parse->rtable = lappend(parse->rtable, childrte);
1348 childRTindex = list_length(parse->rtable);
1351 * Build an AppendRelInfo for this parent and child.
1353 appinfo = makeNode(AppendRelInfo);
1354 appinfo->parent_relid = rti;
1355 appinfo->child_relid = childRTindex;
1356 appinfo->parent_reltype = oldrelation->rd_rel->reltype;
1357 appinfo->child_reltype = newrelation->rd_rel->reltype;
1358 make_inh_translation_list(oldrelation, newrelation, childRTindex,
1359 &appinfo->translated_vars);
1360 appinfo->parent_reloid = parentOID;
1361 appinfos = lappend(appinfos, appinfo);
1364 * Translate the column permissions bitmaps to the child's attnums (we
1365 * have to build the translated_vars list before we can do this). But
1366 * if this is the parent table, leave copyObject's result alone.
1368 * Note: we need to do this even though the executor won't run any
1369 * permissions checks on the child RTE. The modifiedCols bitmap may
1370 * be examined for trigger-firing purposes.
1372 if (childOID != parentOID)
1374 childrte->selectedCols = translate_col_privs(rte->selectedCols,
1375 appinfo->translated_vars);
1376 childrte->modifiedCols = translate_col_privs(rte->modifiedCols,
1377 appinfo->translated_vars);
1381 * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
1385 PlanRowMark *newrc = makeNode(PlanRowMark);
1387 newrc->rti = childRTindex;
1389 newrc->rowmarkId = oldrc->rowmarkId;
1390 newrc->markType = oldrc->markType;
1391 newrc->noWait = oldrc->noWait;
1392 newrc->isParent = false;
1394 root->rowMarks = lappend(root->rowMarks, newrc);
1397 /* Close child relations, but keep locks */
1398 if (childOID != parentOID)
1399 heap_close(newrelation, NoLock);
1402 heap_close(oldrelation, NoLock);
1405 * If all the children were temp tables, pretend it's a non-inheritance
1406 * situation. The duplicate RTE we added for the parent table is
1407 * harmless, so we don't bother to get rid of it.
1409 if (list_length(appinfos) < 2)
1411 /* Clear flag before returning */
1416 /* Otherwise, OK to add to root->append_rel_list */
1417 root->append_rel_list = list_concat(root->append_rel_list, appinfos);
1421 * make_inh_translation_list
1422 * Build the list of translations from parent Vars to child Vars for
1423 * an inheritance child.
1425 * For paranoia's sake, we match type/collation as well as attribute name.
1428 make_inh_translation_list(Relation oldrelation, Relation newrelation,
1430 List **translated_vars)
1433 TupleDesc old_tupdesc = RelationGetDescr(oldrelation);
1434 TupleDesc new_tupdesc = RelationGetDescr(newrelation);
1435 int oldnatts = old_tupdesc->natts;
1436 int newnatts = new_tupdesc->natts;
1439 for (old_attno = 0; old_attno < oldnatts; old_attno++)
1441 Form_pg_attribute att;
1448 att = old_tupdesc->attrs[old_attno];
1449 if (att->attisdropped)
1451 /* Just put NULL into this list entry */
1452 vars = lappend(vars, NULL);
1455 attname = NameStr(att->attname);
1456 atttypid = att->atttypid;
1457 atttypmod = att->atttypmod;
1458 attcollation = att->attcollation;
1461 * When we are generating the "translation list" for the parent table
1462 * of an inheritance set, no need to search for matches.
1464 if (oldrelation == newrelation)
1466 vars = lappend(vars, makeVar(newvarno,
1467 (AttrNumber) (old_attno + 1),
1476 * Otherwise we have to search for the matching column by name.
1477 * There's no guarantee it'll have the same column position, because
1478 * of cases like ALTER TABLE ADD COLUMN and multiple inheritance.
1479 * However, in simple cases it will be the same column number, so try
1480 * that before we go groveling through all the columns.
1482 * Note: the test for (att = ...) != NULL cannot fail, it's just a
1483 * notational device to include the assignment into the if-clause.
1485 if (old_attno < newnatts &&
1486 (att = new_tupdesc->attrs[old_attno]) != NULL &&
1487 !att->attisdropped && att->attinhcount != 0 &&
1488 strcmp(attname, NameStr(att->attname)) == 0)
1489 new_attno = old_attno;
1492 for (new_attno = 0; new_attno < newnatts; new_attno++)
1494 att = new_tupdesc->attrs[new_attno];
1495 if (!att->attisdropped && att->attinhcount != 0 &&
1496 strcmp(attname, NameStr(att->attname)) == 0)
1499 if (new_attno >= newnatts)
1500 elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
1501 attname, RelationGetRelationName(newrelation));
1504 /* Found it, check type and collation match */
1505 if (atttypid != att->atttypid || atttypmod != att->atttypmod)
1506 elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type",
1507 attname, RelationGetRelationName(newrelation));
1508 if (attcollation != att->attcollation)
1509 elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's collation",
1510 attname, RelationGetRelationName(newrelation));
1512 vars = lappend(vars, makeVar(newvarno,
1513 (AttrNumber) (new_attno + 1),
1520 *translated_vars = vars;
1524 * translate_col_privs
1525 * Translate a bitmapset representing per-column privileges from the
1526 * parent rel's attribute numbering to the child's.
1528 * The only surprise here is that we don't translate a parent whole-row
1529 * reference into a child whole-row reference. That would mean requiring
1530 * permissions on all child columns, which is overly strict, since the
1531 * query is really only going to reference the inherited columns. Instead
1532 * we set the per-column bits for all inherited columns.
1535 translate_col_privs(const Bitmapset *parent_privs,
1536 List *translated_vars)
1538 Bitmapset *child_privs = NULL;
1543 /* System attributes have the same numbers in all tables */
1544 for (attno = FirstLowInvalidHeapAttributeNumber + 1; attno < 0; attno++)
1546 if (bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
1548 child_privs = bms_add_member(child_privs,
1549 attno - FirstLowInvalidHeapAttributeNumber);
1552 /* Check if parent has whole-row reference */
1553 whole_row = bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber,
1556 /* And now translate the regular user attributes, using the vars list */
1557 attno = InvalidAttrNumber;
1558 foreach(lc, translated_vars)
1560 Var *var = (Var *) lfirst(lc);
1563 if (var == NULL) /* ignore dropped columns */
1565 Assert(IsA(var, Var));
1567 bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
1569 child_privs = bms_add_member(child_privs,
1570 var->varattno - FirstLowInvalidHeapAttributeNumber);
1577 * adjust_appendrel_attrs
1578 * Copy the specified query or expression and translate Vars referring
1579 * to the parent rel of the specified AppendRelInfo to refer to the
1580 * child rel instead. We also update rtindexes appearing outside Vars,
1581 * such as resultRelation and jointree relids.
1583 * Note: this is only applied after conversion of sublinks to subplans,
1584 * so we don't need to cope with recursion into sub-queries.
1586 * Note: this is not hugely different from what pullup_replace_vars() does;
1587 * maybe we should try to fold the two routines together.
1590 adjust_appendrel_attrs(PlannerInfo *root, Node *node, AppendRelInfo *appinfo)
1593 adjust_appendrel_attrs_context context;
1595 context.root = root;
1596 context.appinfo = appinfo;
1599 * Must be prepared to start with a Query or a bare expression tree.
1601 if (node && IsA(node, Query))
1605 newnode = query_tree_mutator((Query *) node,
1606 adjust_appendrel_attrs_mutator,
1608 QTW_IGNORE_RC_SUBQUERIES);
1609 if (newnode->resultRelation == appinfo->parent_relid)
1611 newnode->resultRelation = appinfo->child_relid;
1612 /* Fix tlist resnos too, if it's inherited UPDATE */
1613 if (newnode->commandType == CMD_UPDATE)
1614 newnode->targetList =
1615 adjust_inherited_tlist(newnode->targetList,
1618 result = (Node *) newnode;
1621 result = adjust_appendrel_attrs_mutator(node, &context);
1627 adjust_appendrel_attrs_mutator(Node *node,
1628 adjust_appendrel_attrs_context *context)
1630 AppendRelInfo *appinfo = context->appinfo;
1636 Var *var = (Var *) copyObject(node);
1638 if (var->varlevelsup == 0 &&
1639 var->varno == appinfo->parent_relid)
1641 var->varno = appinfo->child_relid;
1642 var->varnoold = appinfo->child_relid;
1643 if (var->varattno > 0)
1647 if (var->varattno > list_length(appinfo->translated_vars))
1648 elog(ERROR, "attribute %d of relation \"%s\" does not exist",
1649 var->varattno, get_rel_name(appinfo->parent_reloid));
1650 newnode = copyObject(list_nth(appinfo->translated_vars,
1651 var->varattno - 1));
1652 if (newnode == NULL)
1653 elog(ERROR, "attribute %d of relation \"%s\" does not exist",
1654 var->varattno, get_rel_name(appinfo->parent_reloid));
1657 else if (var->varattno == 0)
1660 * Whole-row Var: if we are dealing with named rowtypes, we
1661 * can use a whole-row Var for the child table plus a coercion
1662 * step to convert the tuple layout to the parent's rowtype.
1663 * Otherwise we have to generate a RowExpr.
1665 if (OidIsValid(appinfo->child_reltype))
1667 Assert(var->vartype == appinfo->parent_reltype);
1668 if (appinfo->parent_reltype != appinfo->child_reltype)
1670 ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);
1672 r->arg = (Expr *) var;
1673 r->resulttype = appinfo->parent_reltype;
1674 r->convertformat = COERCE_IMPLICIT_CAST;
1676 /* Make sure the Var node has the right type ID, too */
1677 var->vartype = appinfo->child_reltype;
1684 * Build a RowExpr containing the translated variables.
1686 * In practice var->vartype will always be RECORDOID here,
1687 * so we need to come up with some suitable column names.
1688 * We use the parent RTE's column names.
1690 * Note: we can't get here for inheritance cases, so there
1691 * is no need to worry that translated_vars might contain
1698 rte = rt_fetch(appinfo->parent_relid,
1699 context->root->parse->rtable);
1700 fields = (List *) copyObject(appinfo->translated_vars);
1701 rowexpr = makeNode(RowExpr);
1702 rowexpr->args = fields;
1703 rowexpr->row_typeid = var->vartype;
1704 rowexpr->row_format = COERCE_IMPLICIT_CAST;
1705 rowexpr->colnames = copyObject(rte->eref->colnames);
1706 rowexpr->location = -1;
1708 return (Node *) rowexpr;
1711 /* system attributes don't need any other translation */
1713 return (Node *) var;
1715 if (IsA(node, CurrentOfExpr))
1717 CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
1719 if (cexpr->cvarno == appinfo->parent_relid)
1720 cexpr->cvarno = appinfo->child_relid;
1721 return (Node *) cexpr;
1723 if (IsA(node, RangeTblRef))
1725 RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
1727 if (rtr->rtindex == appinfo->parent_relid)
1728 rtr->rtindex = appinfo->child_relid;
1729 return (Node *) rtr;
1731 if (IsA(node, JoinExpr))
1733 /* Copy the JoinExpr node with correct mutation of subnodes */
1736 j = (JoinExpr *) expression_tree_mutator(node,
1737 adjust_appendrel_attrs_mutator,
1739 /* now fix JoinExpr's rtindex (probably never happens) */
1740 if (j->rtindex == appinfo->parent_relid)
1741 j->rtindex = appinfo->child_relid;
1744 if (IsA(node, PlaceHolderVar))
1746 /* Copy the PlaceHolderVar node with correct mutation of subnodes */
1747 PlaceHolderVar *phv;
1749 phv = (PlaceHolderVar *) expression_tree_mutator(node,
1750 adjust_appendrel_attrs_mutator,
1752 /* now fix PlaceHolderVar's relid sets */
1753 if (phv->phlevelsup == 0)
1754 phv->phrels = adjust_relid_set(phv->phrels,
1755 appinfo->parent_relid,
1756 appinfo->child_relid);
1757 return (Node *) phv;
1759 /* Shouldn't need to handle planner auxiliary nodes here */
1760 Assert(!IsA(node, SpecialJoinInfo));
1761 Assert(!IsA(node, LateralJoinInfo));
1762 Assert(!IsA(node, AppendRelInfo));
1763 Assert(!IsA(node, PlaceHolderInfo));
1764 Assert(!IsA(node, MinMaxAggInfo));
1767 * We have to process RestrictInfo nodes specially. (Note: although
1768 * set_append_rel_pathlist will hide RestrictInfos in the parent's
1769 * baserestrictinfo list from us, it doesn't hide those in joininfo.)
1771 if (IsA(node, RestrictInfo))
1773 RestrictInfo *oldinfo = (RestrictInfo *) node;
1774 RestrictInfo *newinfo = makeNode(RestrictInfo);
1776 /* Copy all flat-copiable fields */
1777 memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
1779 /* Recursively fix the clause itself */
1780 newinfo->clause = (Expr *)
1781 adjust_appendrel_attrs_mutator((Node *) oldinfo->clause, context);
1783 /* and the modified version, if an OR clause */
1784 newinfo->orclause = (Expr *)
1785 adjust_appendrel_attrs_mutator((Node *) oldinfo->orclause, context);
1787 /* adjust relid sets too */
1788 newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids,
1789 appinfo->parent_relid,
1790 appinfo->child_relid);
1791 newinfo->required_relids = adjust_relid_set(oldinfo->required_relids,
1792 appinfo->parent_relid,
1793 appinfo->child_relid);
1794 newinfo->outer_relids = adjust_relid_set(oldinfo->outer_relids,
1795 appinfo->parent_relid,
1796 appinfo->child_relid);
1797 newinfo->nullable_relids = adjust_relid_set(oldinfo->nullable_relids,
1798 appinfo->parent_relid,
1799 appinfo->child_relid);
1800 newinfo->left_relids = adjust_relid_set(oldinfo->left_relids,
1801 appinfo->parent_relid,
1802 appinfo->child_relid);
1803 newinfo->right_relids = adjust_relid_set(oldinfo->right_relids,
1804 appinfo->parent_relid,
1805 appinfo->child_relid);
1808 * Reset cached derivative fields, since these might need to have
1809 * different values when considering the child relation. Note we
1810 * don't reset left_ec/right_ec: each child variable is implicitly
1811 * equivalent to its parent, so still a member of the same EC if any.
1813 newinfo->eval_cost.startup = -1;
1814 newinfo->norm_selec = -1;
1815 newinfo->outer_selec = -1;
1816 newinfo->left_em = NULL;
1817 newinfo->right_em = NULL;
1818 newinfo->scansel_cache = NIL;
1819 newinfo->left_bucketsize = -1;
1820 newinfo->right_bucketsize = -1;
1822 return (Node *) newinfo;
1826 * NOTE: we do not need to recurse into sublinks, because they should
1827 * already have been converted to subplans before we see them.
1829 Assert(!IsA(node, SubLink));
1830 Assert(!IsA(node, Query));
1832 return expression_tree_mutator(node, adjust_appendrel_attrs_mutator,
1837 * Substitute newrelid for oldrelid in a Relid set
1840 adjust_relid_set(Relids relids, Index oldrelid, Index newrelid)
1842 if (bms_is_member(oldrelid, relids))
1844 /* Ensure we have a modifiable copy */
1845 relids = bms_copy(relids);
1846 /* Remove old, add new */
1847 relids = bms_del_member(relids, oldrelid);
1848 relids = bms_add_member(relids, newrelid);
1854 * Adjust the targetlist entries of an inherited UPDATE operation
1856 * The expressions have already been fixed, but we have to make sure that
1857 * the target resnos match the child table (they may not, in the case of
1858 * a column that was added after-the-fact by ALTER TABLE). In some cases
1859 * this can force us to re-order the tlist to preserve resno ordering.
1860 * (We do all this work in special cases so that preptlist.c is fast for
1861 * the typical case.)
1863 * The given tlist has already been through expression_tree_mutator;
1864 * therefore the TargetEntry nodes are fresh copies that it's okay to
1867 * Note that this is not needed for INSERT because INSERT isn't inheritable.
1870 adjust_inherited_tlist(List *tlist, AppendRelInfo *context)
1872 bool changed_it = false;
1878 /* This should only happen for an inheritance case, not UNION ALL */
1879 Assert(OidIsValid(context->parent_reloid));
1881 /* Scan tlist and update resnos to match attnums of child rel */
1884 TargetEntry *tle = (TargetEntry *) lfirst(tl);
1888 continue; /* ignore junk items */
1890 /* Look up the translation of this column: it must be a Var */
1891 if (tle->resno <= 0 ||
1892 tle->resno > list_length(context->translated_vars))
1893 elog(ERROR, "attribute %d of relation \"%s\" does not exist",
1894 tle->resno, get_rel_name(context->parent_reloid));
1895 childvar = (Var *) list_nth(context->translated_vars, tle->resno - 1);
1896 if (childvar == NULL || !IsA(childvar, Var))
1897 elog(ERROR, "attribute %d of relation \"%s\" does not exist",
1898 tle->resno, get_rel_name(context->parent_reloid));
1900 if (tle->resno != childvar->varattno)
1902 tle->resno = childvar->varattno;
1908 * If we changed anything, re-sort the tlist by resno, and make sure
1909 * resjunk entries have resnos above the last real resno. The sort
1910 * algorithm is a bit stupid, but for such a seldom-taken path, small is
1911 * probably better than fast.
1918 for (attrno = 1; more; attrno++)
1923 TargetEntry *tle = (TargetEntry *) lfirst(tl);
1926 continue; /* ignore junk items */
1928 if (tle->resno == attrno)
1929 new_tlist = lappend(new_tlist, tle);
1930 else if (tle->resno > attrno)
1937 TargetEntry *tle = (TargetEntry *) lfirst(tl);
1940 continue; /* here, ignore non-junk items */
1942 tle->resno = attrno;
1943 new_tlist = lappend(new_tlist, tle);