1 /*-------------------------------------------------------------------------
4 * Routines to plan set-operation queries. The filename is a leftover
5 * from a time when only UNIONs were implemented.
7 * There is also some code here to support planning of queries that use
8 * inheritance (SELECT FROM foo*). This no longer has much connection
9 * to the processing of UNION queries, but it's still here.
12 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
13 * Portions Copyright (c) 1994, Regents of the University of California
17 * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.124 2005/06/10 02:21:05 tgl Exp $
19 *-------------------------------------------------------------------------
24 #include "access/heapam.h"
25 #include "catalog/pg_type.h"
26 #include "nodes/makefuncs.h"
27 #include "optimizer/clauses.h"
28 #include "optimizer/plancat.h"
29 #include "optimizer/planmain.h"
30 #include "optimizer/planner.h"
31 #include "optimizer/prep.h"
32 #include "optimizer/tlist.h"
33 #include "parser/parse_clause.h"
34 #include "parser/parse_coerce.h"
35 #include "parser/parse_expr.h"
36 #include "parser/parsetree.h"
37 #include "utils/lsyscache.h"
46 TupleDesc old_tupdesc;
47 TupleDesc new_tupdesc;
50 } adjust_inherited_attrs_context;
52 static Plan *recurse_set_operations(Node *setOp, PlannerInfo *root,
53 double tuple_fraction,
54 List *colTypes, bool junkOK,
55 int flag, List *refnames_tlist,
57 static Plan *generate_union_plan(SetOperationStmt *op, PlannerInfo *root,
58 double tuple_fraction,
59 List *refnames_tlist, List **sortClauses);
60 static Plan *generate_nonunion_plan(SetOperationStmt *op, PlannerInfo *root,
61 List *refnames_tlist, List **sortClauses);
62 static List *recurse_union_children(Node *setOp, PlannerInfo *root,
63 double tuple_fraction,
64 SetOperationStmt *top_union,
65 List *refnames_tlist);
66 static List *generate_setop_tlist(List *colTypes, int flag,
70 List *refnames_tlist);
71 static List *generate_append_tlist(List *colTypes, bool flag,
73 List *refnames_tlist);
74 static bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK);
75 static Node *adjust_inherited_attrs_mutator(Node *node,
76 adjust_inherited_attrs_context *context);
77 static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid);
78 static List *adjust_inherited_tlist(List *tlist,
79 adjust_inherited_attrs_context *context);
85 * Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT)
87 * This routine only deals with the setOperations tree of the given query.
88 * Any top-level ORDER BY requested in root->parse->sortClause will be added
89 * when we return to grouping_planner.
91 * tuple_fraction is the fraction of tuples we expect will be retrieved.
92 * tuple_fraction is interpreted as for grouping_planner(); in particular,
93 * zero means "all the tuples will be fetched". Any LIMIT present at the
94 * top level has already been factored into tuple_fraction.
96 * *sortClauses is an output argument: it is set to a list of SortClauses
97 * representing the result ordering of the topmost set operation.
100 plan_set_operations(PlannerInfo *root, double tuple_fraction,
103 Query *parse = root->parse;
104 SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;
106 Query *leftmostQuery;
108 Assert(topop && IsA(topop, SetOperationStmt));
110 /* check for unsupported stuff */
111 Assert(parse->utilityStmt == NULL);
112 Assert(parse->jointree->fromlist == NIL);
113 Assert(parse->jointree->quals == NULL);
114 Assert(parse->groupClause == NIL);
115 Assert(parse->havingQual == NULL);
116 Assert(parse->distinctClause == NIL);
119 * Find the leftmost component Query. We need to use its column names
120 * for all generated tlists (else SELECT INTO won't work right).
123 while (node && IsA(node, SetOperationStmt))
124 node = ((SetOperationStmt *) node)->larg;
125 Assert(node && IsA(node, RangeTblRef));
126 leftmostQuery = rt_fetch(((RangeTblRef *) node)->rtindex,
127 parse->rtable)->subquery;
128 Assert(leftmostQuery != NULL);
131 * Recurse on setOperations tree to generate plans for set ops. The
132 * final output plan should have just the column types shown as the
133 * output from the top-level node, plus possibly resjunk working
134 * columns (we can rely on upper-level nodes to deal with that).
136 return recurse_set_operations((Node *) topop, root, tuple_fraction,
137 topop->colTypes, true, -1,
138 leftmostQuery->targetList,
143 * recurse_set_operations
144 * Recursively handle one step in a tree of set operations
146 * tuple_fraction: fraction of tuples we expect to retrieve from node
147 * colTypes: list of type OIDs of expected output columns
148 * junkOK: if true, child resjunk columns may be left in the result
149 * flag: if >= 0, add a resjunk output column indicating value of flag
150 * refnames_tlist: targetlist to take column names from
151 * *sortClauses: receives list of SortClauses for result plan, if any
154 recurse_set_operations(Node *setOp, PlannerInfo *root,
155 double tuple_fraction,
156 List *colTypes, bool junkOK,
157 int flag, List *refnames_tlist,
160 if (IsA(setOp, RangeTblRef))
162 RangeTblRef *rtr = (RangeTblRef *) setOp;
163 RangeTblEntry *rte = rt_fetch(rtr->rtindex, root->parse->rtable);
164 Query *subquery = rte->subquery;
168 Assert(subquery != NULL);
171 * Generate plan for primitive subquery
173 subplan = subquery_planner(subquery, tuple_fraction, NULL);
176 * Add a SubqueryScan with the caller-requested targetlist
179 make_subqueryscan(generate_setop_tlist(colTypes, flag,
189 * We don't bother to determine the subquery's output ordering
190 * since it won't be reflected in the set-op result anyhow.
196 else if (IsA(setOp, SetOperationStmt))
198 SetOperationStmt *op = (SetOperationStmt *) setOp;
201 /* UNIONs are much different from INTERSECT/EXCEPT */
202 if (op->op == SETOP_UNION)
203 plan = generate_union_plan(op, root, tuple_fraction,
207 plan = generate_nonunion_plan(op, root,
212 * If necessary, add a Result node to project the caller-requested
215 * XXX you don't really want to know about this: setrefs.c will apply
216 * replace_vars_with_subplan_refs() to the Result node's tlist.
217 * This would fail if the Vars generated by generate_setop_tlist()
218 * were not exactly equal() to the corresponding tlist entries of
219 * the subplan. However, since the subplan was generated by
220 * generate_union_plan() or generate_nonunion_plan(), and hence
221 * its tlist was generated by generate_append_tlist(), this will
222 * work. We just tell generate_setop_tlist() to use varno 0.
225 !tlist_same_datatypes(plan->targetlist, colTypes, junkOK))
228 make_result(generate_setop_tlist(colTypes, flag,
240 elog(ERROR, "unrecognized node type: %d",
241 (int) nodeTag(setOp));
242 return NULL; /* keep compiler quiet */
247 * Generate plan for a UNION or UNION ALL node
250 generate_union_plan(SetOperationStmt *op, PlannerInfo *root,
251 double tuple_fraction,
252 List *refnames_tlist,
260 * If plain UNION, tell children to fetch all tuples.
262 * Note: in UNION ALL, we pass the top-level tuple_fraction unmodified
263 * to each arm of the UNION ALL. One could make a case for reducing
264 * the tuple fraction for later arms (discounting by the expected size
265 * of the earlier arms' results) but it seems not worth the trouble.
266 * The normal case where tuple_fraction isn't already zero is a LIMIT
267 * at top level, and passing it down as-is is usually enough to get the
268 * desired result of preferring fast-start plans.
271 tuple_fraction = 0.0;
274 * If any of my children are identical UNION nodes (same op, all-flag,
275 * and colTypes) then they can be merged into this node so that we
276 * generate only one Append and Sort for the lot. Recurse to find
277 * such nodes and compute their children's plans.
279 planlist = list_concat(recurse_union_children(op->larg, root,
282 recurse_union_children(op->rarg, root,
284 op, refnames_tlist));
287 * Generate tlist for Append plan node.
289 * The tlist for an Append plan isn't important as far as the Append is
290 * concerned, but we must make it look real anyway for the benefit of
291 * the next plan level up.
293 tlist = generate_append_tlist(op->colTypes, false,
294 planlist, refnames_tlist);
297 * Append the child results together.
299 plan = (Plan *) make_append(planlist, false, tlist);
302 * For UNION ALL, we just need the Append plan. For UNION, need to
303 * add Sort and Unique nodes to produce unique output.
309 sortList = addAllTargetsToSortList(NULL, NIL, tlist, false);
312 plan = (Plan *) make_sort_from_sortclauses(root, sortList, plan);
313 plan = (Plan *) make_unique(plan, sortList);
315 *sortClauses = sortList;
324 * Generate plan for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node
327 generate_nonunion_plan(SetOperationStmt *op, PlannerInfo *root,
328 List *refnames_tlist,
340 /* Recurse on children, ensuring their outputs are marked */
341 lplan = recurse_set_operations(op->larg, root,
342 0.0 /* all tuples needed */,
343 op->colTypes, false, 0,
346 rplan = recurse_set_operations(op->rarg, root,
347 0.0 /* all tuples needed */,
348 op->colTypes, false, 1,
351 planlist = list_make2(lplan, rplan);
354 * Generate tlist for Append plan node.
356 * The tlist for an Append plan isn't important as far as the Append is
357 * concerned, but we must make it look real anyway for the benefit of
358 * the next plan level up. In fact, it has to be real enough that the
359 * flag column is shown as a variable not a constant, else setrefs.c
362 tlist = generate_append_tlist(op->colTypes, true,
363 planlist, refnames_tlist);
366 * Append the child results together.
368 plan = (Plan *) make_append(planlist, false, tlist);
371 * Sort the child results, then add a SetOp plan node to generate the
374 sortList = addAllTargetsToSortList(NULL, NIL, tlist, false);
376 if (sortList == NIL) /* nothing to sort on? */
382 plan = (Plan *) make_sort_from_sortclauses(root, sortList, plan);
385 case SETOP_INTERSECT:
386 cmd = op->all ? SETOPCMD_INTERSECT_ALL : SETOPCMD_INTERSECT;
389 cmd = op->all ? SETOPCMD_EXCEPT_ALL : SETOPCMD_EXCEPT;
392 elog(ERROR, "unrecognized set op: %d",
394 cmd = SETOPCMD_INTERSECT; /* keep compiler quiet */
397 plan = (Plan *) make_setop(cmd, plan, sortList, list_length(op->colTypes) + 1);
399 *sortClauses = sortList;
405 * Pull up children of a UNION node that are identically-propertied UNIONs.
407 * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
408 * output rows will be lost anyway.
411 recurse_union_children(Node *setOp, PlannerInfo *root,
412 double tuple_fraction,
413 SetOperationStmt *top_union,
414 List *refnames_tlist)
416 List *child_sortclauses;
418 if (IsA(setOp, SetOperationStmt))
420 SetOperationStmt *op = (SetOperationStmt *) setOp;
422 if (op->op == top_union->op &&
423 (op->all == top_union->all || op->all) &&
424 equal(op->colTypes, top_union->colTypes))
426 /* Same UNION, so fold children into parent's subplan list */
427 return list_concat(recurse_union_children(op->larg, root,
431 recurse_union_children(op->rarg, root,
439 * Not same, so plan this child separately.
441 * Note we disallow any resjunk columns in child results. This is
442 * necessary since the Append node that implements the union won't do
443 * any projection, and upper levels will get confused if some of our
444 * output tuples have junk and some don't. This case only arises when
445 * we have an EXCEPT or INTERSECT as child, else there won't be
448 return list_make1(recurse_set_operations(setOp, root,
450 top_union->colTypes, false,
452 &child_sortclauses));
456 * Generate targetlist for a set-operation plan node
458 * colTypes: column datatypes for non-junk columns
459 * flag: -1 if no flag column needed, 0 or 1 to create a const flag column
460 * varno: varno to use in generated Vars
461 * hack_constants: true to copy up constants (see comments in code)
462 * input_tlist: targetlist of this node's input node
463 * refnames_tlist: targetlist to take column names from
466 generate_setop_tlist(List *colTypes, int flag,
470 List *refnames_tlist)
480 j = list_head(input_tlist);
481 k = list_head(refnames_tlist);
484 Oid colType = lfirst_oid(i);
485 TargetEntry *inputtle = (TargetEntry *) lfirst(j);
486 TargetEntry *reftle = (TargetEntry *) lfirst(k);
488 Assert(inputtle->resno == resno);
489 Assert(reftle->resno == resno);
490 Assert(!inputtle->resjunk);
491 Assert(!reftle->resjunk);
494 * Generate columns referencing input columns and having
495 * appropriate data types and column names. Insert datatype
496 * coercions where necessary.
498 * HACK: constants in the input's targetlist are copied up as-is
499 * rather than being referenced as subquery outputs. This is
500 * mainly to ensure that when we try to coerce them to the output
501 * column's datatype, the right things happen for UNKNOWN
502 * constants. But do this only at the first level of
503 * subquery-scan plans; we don't want phony constants appearing in
504 * the output tlists of upper-level nodes!
506 if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
507 expr = (Node *) inputtle->expr;
509 expr = (Node *) makeVar(varno,
511 exprType((Node *) inputtle->expr),
512 exprTypmod((Node *) inputtle->expr),
514 if (exprType(expr) != colType)
516 expr = coerce_to_common_type(NULL, /* no UNKNOWNs here */
519 "UNION/INTERSECT/EXCEPT");
521 tle = makeTargetEntry((Expr *) expr,
522 (AttrNumber) resno++,
523 pstrdup(reftle->resname),
525 tlist = lappend(tlist, tle);
533 /* Add a resjunk flag column */
534 /* flag value is the given constant */
535 expr = (Node *) makeConst(INT4OID,
540 tle = makeTargetEntry((Expr *) expr,
541 (AttrNumber) resno++,
544 tlist = lappend(tlist, tle);
551 * Generate targetlist for a set-operation Append node
553 * colTypes: column datatypes for non-junk columns
554 * flag: true to create a flag column copied up from subplans
555 * input_plans: list of sub-plans of the Append
556 * refnames_tlist: targetlist to take column names from
558 * The entries in the Append's targetlist should always be simple Vars;
559 * we just have to make sure they have the right datatypes and typmods.
560 * The Vars are always generated with varno 0.
563 generate_append_tlist(List *colTypes, bool flag,
565 List *refnames_tlist)
569 ListCell *curColType;
570 ListCell *ref_tl_item;
578 * First extract typmods to use.
580 * If the inputs all agree on type and typmod of a particular column, use
581 * that typmod; else use -1.
583 colTypmods = (int32 *) palloc(list_length(colTypes) * sizeof(int32));
585 foreach(planl, input_plans)
587 Plan *subplan = (Plan *) lfirst(planl);
590 curColType = list_head(colTypes);
592 foreach(subtlist, subplan->targetlist)
594 TargetEntry *subtle = (TargetEntry *) lfirst(subtlist);
598 Assert(curColType != NULL);
599 if (exprType((Node *) subtle->expr) == lfirst_oid(curColType))
601 /* If first subplan, copy the typmod; else compare */
602 int32 subtypmod = exprTypmod((Node *) subtle->expr);
604 if (planl == list_head(input_plans))
605 colTypmods[colindex] = subtypmod;
606 else if (subtypmod != colTypmods[colindex])
607 colTypmods[colindex] = -1;
611 /* types disagree, so force typmod to -1 */
612 colTypmods[colindex] = -1;
614 curColType = lnext(curColType);
617 Assert(curColType == NULL);
621 * Now we can build the tlist for the Append.
624 forboth(curColType, colTypes, ref_tl_item, refnames_tlist)
626 Oid colType = lfirst_oid(curColType);
627 int32 colTypmod = colTypmods[colindex++];
628 TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item);
630 Assert(reftle->resno == resno);
631 Assert(!reftle->resjunk);
632 expr = (Node *) makeVar(0,
637 tle = makeTargetEntry((Expr *) expr,
638 (AttrNumber) resno++,
639 pstrdup(reftle->resname),
641 tlist = lappend(tlist, tle);
646 /* Add a resjunk flag column */
647 /* flag value is shown as copied up from subplan */
648 expr = (Node *) makeVar(0,
653 tle = makeTargetEntry((Expr *) expr,
654 (AttrNumber) resno++,
657 tlist = lappend(tlist, tle);
666 * Does tlist have same datatypes as requested colTypes?
668 * Resjunk columns are ignored if junkOK is true; otherwise presence of
669 * a resjunk column will always cause a 'false' result.
672 tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
675 ListCell *curColType = list_head(colTypes);
679 TargetEntry *tle = (TargetEntry *) lfirst(l);
688 if (curColType == NULL)
690 if (exprType((Node *) tle->expr) != lfirst_oid(curColType))
692 curColType = lnext(curColType);
695 if (curColType != NULL)
702 * find_all_inheritors -
703 * Returns a list of relation OIDs including the given rel plus
704 * all relations that inherit from it, directly or indirectly.
707 find_all_inheritors(Oid parentrel)
709 List *examined_relids = NIL;
710 List *unexamined_relids = list_make1_oid(parentrel);
713 * While the queue of unexamined relids is nonempty, remove the first
714 * element, mark it examined, and find its direct descendants. NB:
715 * cannot use foreach(), since we modify the queue inside loop.
717 while (unexamined_relids != NIL)
719 Oid currentrel = linitial_oid(unexamined_relids);
720 List *currentchildren;
722 unexamined_relids = list_delete_first(unexamined_relids);
723 examined_relids = lappend_oid(examined_relids, currentrel);
724 currentchildren = find_inheritance_children(currentrel);
727 * Add to the queue only those children not already seen. This
728 * avoids making duplicate entries in case of multiple inheritance
729 * paths from the same parent. (It'll also keep us from getting
730 * into an infinite loop, though theoretically there can't be any
731 * cycles in the inheritance graph anyway.)
733 currentchildren = list_difference_oid(currentchildren, examined_relids);
734 unexamined_relids = list_union_oid(unexamined_relids, currentchildren);
737 return examined_relids;
741 * expand_inherited_rtentry
742 * Check whether a rangetable entry represents an inheritance set.
743 * If so, add entries for all the child tables to the query's
744 * rangetable, and return an integer list of RT indexes for the
745 * whole inheritance set (parent and children).
746 * If not, return NIL.
748 * Note that the original RTE is considered to represent the whole
749 * inheritance set. The first member of the returned list is an RTE
750 * for the same table, but with inh = false, to represent the parent table
751 * in its role as a simple member of the set. The original RT index is
752 * never a member of the returned list.
754 * A childless table is never considered to be an inheritance set; therefore
755 * the result will never be a one-element list. It'll be either empty
756 * or have two or more elements.
758 * Note: there are cases in which this routine will be invoked multiple
759 * times on the same RTE. We will generate a separate set of child RTEs
760 * for each invocation. This is somewhat wasteful but seems not worth
764 expand_inherited_rtentry(PlannerInfo *root, Index rti)
766 Query *parse = root->parse;
767 RangeTblEntry *rte = rt_fetch(rti, parse->rtable);
773 /* Does RT entry allow inheritance? */
776 Assert(rte->rtekind == RTE_RELATION);
777 /* Fast path for common case of childless table */
778 parentOID = rte->relid;
779 if (!has_subclass(parentOID))
781 /* Clear flag to save repeated tests if called again */
785 /* Scan for all members of inheritance set */
786 inhOIDs = find_all_inheritors(parentOID);
789 * Check that there's at least one descendant, else treat as no-child
790 * case. This could happen despite above has_subclass() check, if
791 * table once had a child but no longer does.
793 if (list_length(inhOIDs) < 2)
795 /* Clear flag to save repeated tests if called again */
800 /* OK, it's an inheritance set; expand it */
804 Oid childOID = lfirst_oid(l);
805 RangeTblEntry *childrte;
809 * Build an RTE for the child, and attach to query's rangetable
810 * list. We copy most fields of the parent's RTE, but replace
811 * relation OID, and set inh = false.
813 childrte = copyObject(rte);
814 childrte->relid = childOID;
815 childrte->inh = false;
816 parse->rtable = lappend(parse->rtable, childrte);
817 childRTindex = list_length(parse->rtable);
818 inhRTIs = lappend_int(inhRTIs, childRTindex);
822 * The executor will check the parent table's access permissions when
823 * it examines the parent's inheritlist entry. There's no need to
824 * check twice, so turn off access check bits in the original RTE.
825 * (If we are invoked more than once, extra copies of the child RTEs
826 * will also not cause duplicate permission checks.)
828 rte->requiredPerms = 0;
834 * adjust_inherited_attrs
835 * Copy the specified query or expression and translate Vars referring
836 * to old_rt_index to refer to new_rt_index.
838 * We also adjust varattno to match the new table by column name, rather
839 * than column number. This hack makes it possible for child tables to have
840 * different column positions for the "same" attribute as a parent, which
841 * is necessary for ALTER TABLE ADD COLUMN.
844 adjust_inherited_attrs(Node *node,
845 Index old_rt_index, Oid old_relid,
846 Index new_rt_index, Oid new_relid)
849 adjust_inherited_attrs_context context;
850 Relation oldrelation;
851 Relation newrelation;
853 /* Handle simple case simply... */
854 if (old_rt_index == new_rt_index)
856 Assert(old_relid == new_relid);
857 return copyObject(node);
861 * We assume that by now the planner has acquired at least
862 * AccessShareLock on both rels, and so we need no additional lock
865 oldrelation = heap_open(old_relid, NoLock);
866 newrelation = heap_open(new_relid, NoLock);
868 context.old_rt_index = old_rt_index;
869 context.new_rt_index = new_rt_index;
870 context.old_rel_type = oldrelation->rd_rel->reltype;
871 context.new_rel_type = newrelation->rd_rel->reltype;
872 context.old_tupdesc = RelationGetDescr(oldrelation);
873 context.new_tupdesc = RelationGetDescr(newrelation);
874 context.old_rel_name = RelationGetRelationName(oldrelation);
875 context.new_rel_name = RelationGetRelationName(newrelation);
878 * Must be prepared to start with a Query or a bare expression tree.
880 if (node && IsA(node, Query))
884 newnode = query_tree_mutator((Query *) node,
885 adjust_inherited_attrs_mutator,
887 QTW_IGNORE_RT_SUBQUERIES);
888 if (newnode->resultRelation == old_rt_index)
890 newnode->resultRelation = new_rt_index;
891 /* Fix tlist resnos too, if it's inherited UPDATE */
892 if (newnode->commandType == CMD_UPDATE)
893 newnode->targetList =
894 adjust_inherited_tlist(newnode->targetList,
897 result = (Node *) newnode;
900 result = adjust_inherited_attrs_mutator(node, &context);
902 heap_close(oldrelation, NoLock);
903 heap_close(newrelation, NoLock);
909 * Translate parent's attribute number into child's.
911 * For paranoia's sake, we match type as well as attribute name.
914 translate_inherited_attnum(AttrNumber old_attno,
915 adjust_inherited_attrs_context *context)
917 Form_pg_attribute att;
924 if (old_attno <= 0 || old_attno > context->old_tupdesc->natts)
925 elog(ERROR, "attribute %d of relation \"%s\" does not exist",
926 (int) old_attno, context->old_rel_name);
927 att = context->old_tupdesc->attrs[old_attno - 1];
928 if (att->attisdropped)
929 elog(ERROR, "attribute %d of relation \"%s\" does not exist",
930 (int) old_attno, context->old_rel_name);
931 attname = NameStr(att->attname);
932 atttypid = att->atttypid;
933 atttypmod = att->atttypmod;
935 newnatts = context->new_tupdesc->natts;
936 for (i = 0; i < newnatts; i++)
938 att = context->new_tupdesc->attrs[i];
939 if (att->attisdropped)
941 if (strcmp(attname, NameStr(att->attname)) == 0)
943 /* Found it, check type */
944 if (atttypid != att->atttypid || atttypmod != att->atttypmod)
945 elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type",
946 attname, context->new_rel_name);
947 return (AttrNumber) (i + 1);
951 elog(ERROR, "attribute \"%s\" of relation \"%s\" does not exist",
952 attname, context->new_rel_name);
953 return 0; /* keep compiler quiet */
957 adjust_inherited_attrs_mutator(Node *node,
958 adjust_inherited_attrs_context *context)
964 Var *var = (Var *) copyObject(node);
966 if (var->varlevelsup == 0 &&
967 var->varno == context->old_rt_index)
969 var->varno = context->new_rt_index;
970 var->varnoold = context->new_rt_index;
971 if (var->varattno > 0)
973 var->varattno = translate_inherited_attnum(var->varattno,
975 var->varoattno = var->varattno;
977 else if (var->varattno == 0)
980 * Whole-row Var: we need to insert a coercion step to convert
981 * the tuple layout to the parent's rowtype.
983 if (context->old_rel_type != context->new_rel_type)
985 ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);
987 r->arg = (Expr *) var;
988 r->resulttype = context->old_rel_type;
989 r->convertformat = COERCE_IMPLICIT_CAST;
990 /* Make sure the Var node has the right type ID, too */
991 Assert(var->vartype == context->old_rel_type);
992 var->vartype = context->new_rel_type;
996 /* system attributes don't need any translation */
1000 if (IsA(node, RangeTblRef))
1002 RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
1004 if (rtr->rtindex == context->old_rt_index)
1005 rtr->rtindex = context->new_rt_index;
1006 return (Node *) rtr;
1008 if (IsA(node, JoinExpr))
1010 /* Copy the JoinExpr node with correct mutation of subnodes */
1013 j = (JoinExpr *) expression_tree_mutator(node,
1014 adjust_inherited_attrs_mutator,
1016 /* now fix JoinExpr's rtindex */
1017 if (j->rtindex == context->old_rt_index)
1018 j->rtindex = context->new_rt_index;
1021 if (IsA(node, InClauseInfo))
1023 /* Copy the InClauseInfo node with correct mutation of subnodes */
1024 InClauseInfo *ininfo;
1026 ininfo = (InClauseInfo *) expression_tree_mutator(node,
1027 adjust_inherited_attrs_mutator,
1029 /* now fix InClauseInfo's relid sets */
1030 ininfo->lefthand = adjust_relid_set(ininfo->lefthand,
1031 context->old_rt_index,
1032 context->new_rt_index);
1033 ininfo->righthand = adjust_relid_set(ininfo->righthand,
1034 context->old_rt_index,
1035 context->new_rt_index);
1036 return (Node *) ininfo;
1040 * We have to process RestrictInfo nodes specially.
1042 if (IsA(node, RestrictInfo))
1044 RestrictInfo *oldinfo = (RestrictInfo *) node;
1045 RestrictInfo *newinfo = makeNode(RestrictInfo);
1047 /* Copy all flat-copiable fields */
1048 memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
1050 /* Recursively fix the clause itself */
1051 newinfo->clause = (Expr *)
1052 adjust_inherited_attrs_mutator((Node *) oldinfo->clause, context);
1054 /* and the modified version, if an OR clause */
1055 newinfo->orclause = (Expr *)
1056 adjust_inherited_attrs_mutator((Node *) oldinfo->orclause, context);
1058 /* adjust relid sets too */
1059 newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids,
1060 context->old_rt_index,
1061 context->new_rt_index);
1062 newinfo->required_relids = adjust_relid_set(oldinfo->required_relids,
1063 context->old_rt_index,
1064 context->new_rt_index);
1065 newinfo->left_relids = adjust_relid_set(oldinfo->left_relids,
1066 context->old_rt_index,
1067 context->new_rt_index);
1068 newinfo->right_relids = adjust_relid_set(oldinfo->right_relids,
1069 context->old_rt_index,
1070 context->new_rt_index);
1073 * Reset cached derivative fields, since these might need to have
1074 * different values when considering the child relation.
1076 newinfo->eval_cost.startup = -1;
1077 newinfo->this_selec = -1;
1078 newinfo->left_pathkey = NIL;
1079 newinfo->right_pathkey = NIL;
1080 newinfo->left_mergescansel = -1;
1081 newinfo->right_mergescansel = -1;
1082 newinfo->left_bucketsize = -1;
1083 newinfo->right_bucketsize = -1;
1085 return (Node *) newinfo;
1089 * NOTE: we do not need to recurse into sublinks, because they should
1090 * already have been converted to subplans before we see them.
1092 Assert(!IsA(node, SubLink));
1093 Assert(!IsA(node, Query));
1096 * BUT: although we don't need to recurse into subplans, we do need to
1097 * make sure that they are copied, not just referenced as
1098 * expression_tree_mutator will do by default. Otherwise we'll have
1099 * the same subplan node referenced from each arm of the inheritance
1100 * APPEND plan, which will cause trouble in the executor. This is a
1101 * kluge that should go away when we redesign querytrees.
1103 if (is_subplan(node))
1107 /* Copy the node and process subplan args */
1108 node = expression_tree_mutator(node, adjust_inherited_attrs_mutator,
1110 /* Make sure we have separate copies of subplan and its rtable */
1111 subplan = (SubPlan *) node;
1112 subplan->plan = copyObject(subplan->plan);
1113 subplan->rtable = copyObject(subplan->rtable);
1117 return expression_tree_mutator(node, adjust_inherited_attrs_mutator,
1122 * Substitute newrelid for oldrelid in a Relid set
1125 adjust_relid_set(Relids relids, Index oldrelid, Index newrelid)
1127 if (bms_is_member(oldrelid, relids))
1129 /* Ensure we have a modifiable copy */
1130 relids = bms_copy(relids);
1131 /* Remove old, add new */
1132 relids = bms_del_member(relids, oldrelid);
1133 relids = bms_add_member(relids, newrelid);
1139 * Adjust the targetlist entries of an inherited UPDATE operation
1141 * The expressions have already been fixed, but we have to make sure that
1142 * the target resnos match the child table (they may not, in the case of
1143 * a column that was added after-the-fact by ALTER TABLE). In some cases
1144 * this can force us to re-order the tlist to preserve resno ordering.
1145 * (We do all this work in special cases so that preptlist.c is fast for
1146 * the typical case.)
1148 * The given tlist has already been through expression_tree_mutator;
1149 * therefore the TargetEntry nodes are fresh copies that it's okay to
1152 * Note that this is not needed for INSERT because INSERT isn't inheritable.
1155 adjust_inherited_tlist(List *tlist,
1156 adjust_inherited_attrs_context *context)
1158 bool changed_it = false;
1164 /* Scan tlist and update resnos to match attnums of new_relid */
1167 TargetEntry *tle = (TargetEntry *) lfirst(tl);
1170 continue; /* ignore junk items */
1172 attrno = translate_inherited_attnum(tle->resno, context);
1174 if (tle->resno != attrno)
1176 tle->resno = attrno;
1182 * If we changed anything, re-sort the tlist by resno, and make sure
1183 * resjunk entries have resnos above the last real resno. The sort
1184 * algorithm is a bit stupid, but for such a seldom-taken path, small
1185 * is probably better than fast.
1192 for (attrno = 1; more; attrno++)
1197 TargetEntry *tle = (TargetEntry *) lfirst(tl);
1200 continue; /* ignore junk items */
1202 if (tle->resno == attrno)
1203 new_tlist = lappend(new_tlist, tle);
1204 else if (tle->resno > attrno)
1211 TargetEntry *tle = (TargetEntry *) lfirst(tl);
1214 continue; /* here, ignore non-junk items */
1216 tle->resno = attrno;
1217 new_tlist = lappend(new_tlist, tle);