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-2002, PostgreSQL Global Development Group
13 * Portions Copyright (c) 1994, Regents of the University of California
17 * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.83 2002/12/14 00:17:57 tgl Exp $
19 *-------------------------------------------------------------------------
24 #include "catalog/pg_type.h"
25 #include "nodes/makefuncs.h"
26 #include "optimizer/clauses.h"
27 #include "optimizer/plancat.h"
28 #include "optimizer/planmain.h"
29 #include "optimizer/planner.h"
30 #include "optimizer/prep.h"
31 #include "optimizer/tlist.h"
32 #include "parser/parse_clause.h"
33 #include "parser/parse_coerce.h"
34 #include "parser/parsetree.h"
35 #include "utils/lsyscache.h"
37 /* macros borrowed from expression_tree_mutator */
39 #define FLATCOPY(newnode, node, nodetype) \
40 ( (newnode) = makeNode(nodetype), \
41 memcpy((newnode), (node), sizeof(nodetype)) )
49 } adjust_inherited_attrs_context;
51 static Plan *recurse_set_operations(Node *setOp, Query *parse,
52 List *colTypes, bool junkOK,
53 int flag, List *refnames_tlist);
54 static Plan *generate_union_plan(SetOperationStmt *op, Query *parse,
55 List *refnames_tlist);
56 static Plan *generate_nonunion_plan(SetOperationStmt *op, Query *parse,
57 List *refnames_tlist);
58 static List *recurse_union_children(Node *setOp, Query *parse,
59 SetOperationStmt *top_union,
60 List *refnames_tlist);
61 static List *generate_setop_tlist(List *colTypes, int flag,
64 List *refnames_tlist);
65 static List *generate_append_tlist(List *colTypes, bool flag,
67 List *refnames_tlist);
68 static Node *adjust_inherited_attrs_mutator(Node *node,
69 adjust_inherited_attrs_context *context);
75 * Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT)
77 * This routine only deals with the setOperations tree of the given query.
78 * Any top-level ORDER BY requested in parse->sortClause will be added
79 * when we return to grouping_planner.
82 plan_set_operations(Query *parse)
84 SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;
88 Assert(topop && IsA(topop, SetOperationStmt));
91 * Find the leftmost component Query. We need to use its column names
92 * for all generated tlists (else SELECT INTO won't work right).
95 while (node && IsA(node, SetOperationStmt))
96 node = ((SetOperationStmt *) node)->larg;
97 Assert(node && IsA(node, RangeTblRef));
98 leftmostQuery = rt_fetch(((RangeTblRef *) node)->rtindex,
99 parse->rtable)->subquery;
100 Assert(leftmostQuery != NULL);
103 * Recurse on setOperations tree to generate plans for set ops. The
104 * final output plan should have just the column types shown as the
105 * output from the top-level node, plus possibly a resjunk working
106 * column (we can rely on upper-level nodes to deal with that).
108 return recurse_set_operations((Node *) topop, parse,
109 topop->colTypes, true, -1,
110 leftmostQuery->targetList);
114 * recurse_set_operations
115 * Recursively handle one step in a tree of set operations
117 * colTypes: integer list of type OIDs of expected output columns
118 * junkOK: if true, child resjunk columns may be left in the result
119 * flag: if >= 0, add a resjunk output column indicating value of flag
120 * refnames_tlist: targetlist to take column names from
123 recurse_set_operations(Node *setOp, Query *parse,
124 List *colTypes, bool junkOK,
125 int flag, List *refnames_tlist)
127 if (IsA(setOp, RangeTblRef))
129 RangeTblRef *rtr = (RangeTblRef *) setOp;
130 RangeTblEntry *rte = rt_fetch(rtr->rtindex, parse->rtable);
131 Query *subquery = rte->subquery;
135 Assert(subquery != NULL);
138 * Generate plan for primitive subquery
140 subplan = subquery_planner(subquery,
141 -1.0 /* default case */ );
144 * Add a SubqueryScan with the caller-requested targetlist
147 make_subqueryscan(generate_setop_tlist(colTypes, flag, true,
155 else if (IsA(setOp, SetOperationStmt))
157 SetOperationStmt *op = (SetOperationStmt *) setOp;
160 /* UNIONs are much different from INTERSECT/EXCEPT */
161 if (op->op == SETOP_UNION)
162 plan = generate_union_plan(op, parse, refnames_tlist);
164 plan = generate_nonunion_plan(op, parse, refnames_tlist);
167 * If necessary, add a Result node to project the caller-requested
170 * XXX you don't really want to know about this: setrefs.c will apply
171 * replace_vars_with_subplan_refs() to the Result node's tlist.
172 * This would fail if the Vars generated by generate_setop_tlist()
173 * were not exactly equal() to the corresponding tlist entries of
174 * the subplan. However, since the subplan was generated by
175 * generate_union_plan() or generate_nonunion_plan(), and hence
176 * its tlist was generated by generate_append_tlist(), this will
180 !tlist_same_datatypes(plan->targetlist, colTypes, junkOK))
183 make_result(generate_setop_tlist(colTypes, flag, false,
193 elog(ERROR, "recurse_set_operations: unexpected node %d",
194 (int) nodeTag(setOp));
195 return NULL; /* keep compiler quiet */
200 * Generate plan for a UNION or UNION ALL node
203 generate_union_plan(SetOperationStmt *op, Query *parse,
204 List *refnames_tlist)
211 * If any of my children are identical UNION nodes (same op, all-flag,
212 * and colTypes) then they can be merged into this node so that we
213 * generate only one Append and Sort for the lot. Recurse to find
214 * such nodes and compute their children's plans.
216 planlist = nconc(recurse_union_children(op->larg, parse,
218 recurse_union_children(op->rarg, parse,
219 op, refnames_tlist));
222 * Generate tlist for Append plan node.
224 * The tlist for an Append plan isn't important as far as the Append is
225 * concerned, but we must make it look real anyway for the benefit of
226 * the next plan level up.
228 tlist = generate_append_tlist(op->colTypes, false,
229 planlist, refnames_tlist);
232 * Append the child results together.
234 plan = (Plan *) make_append(planlist, false, tlist);
237 * For UNION ALL, we just need the Append plan. For UNION, need to
238 * add Sort and Unique nodes to produce unique output.
244 tlist = new_unsorted_tlist(tlist);
245 sortList = addAllTargetsToSortList(NIL, tlist);
246 plan = make_sortplan(parse, tlist, plan, sortList);
247 plan = (Plan *) make_unique(tlist, plan, copyObject(sortList));
253 * Generate plan for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node
256 generate_nonunion_plan(SetOperationStmt *op, Query *parse,
257 List *refnames_tlist)
267 /* Recurse on children, ensuring their outputs are marked */
268 lplan = recurse_set_operations(op->larg, parse,
269 op->colTypes, false, 0,
271 rplan = recurse_set_operations(op->rarg, parse,
272 op->colTypes, false, 1,
274 planlist = makeList2(lplan, rplan);
277 * Generate tlist for Append plan node.
279 * The tlist for an Append plan isn't important as far as the Append is
280 * concerned, but we must make it look real anyway for the benefit of
281 * the next plan level up. In fact, it has to be real enough that the
282 * flag column is shown as a variable not a constant, else setrefs.c
285 tlist = generate_append_tlist(op->colTypes, true,
286 planlist, refnames_tlist);
289 * Append the child results together.
291 plan = (Plan *) make_append(planlist, false, tlist);
294 * Sort the child results, then add a SetOp plan node to generate the
297 tlist = new_unsorted_tlist(tlist);
298 sortList = addAllTargetsToSortList(NIL, tlist);
299 plan = make_sortplan(parse, tlist, plan, sortList);
302 case SETOP_INTERSECT:
303 cmd = op->all ? SETOPCMD_INTERSECT_ALL : SETOPCMD_INTERSECT;
306 cmd = op->all ? SETOPCMD_EXCEPT_ALL : SETOPCMD_EXCEPT;
309 elog(ERROR, "generate_nonunion_plan: bogus operation code");
310 cmd = SETOPCMD_INTERSECT; /* keep compiler quiet */
313 plan = (Plan *) make_setop(cmd, tlist, plan, sortList,
314 length(op->colTypes) + 1);
319 * Pull up children of a UNION node that are identically-propertied UNIONs.
321 * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
322 * output rows will be lost anyway.
325 recurse_union_children(Node *setOp, Query *parse,
326 SetOperationStmt *top_union,
327 List *refnames_tlist)
329 if (IsA(setOp, SetOperationStmt))
331 SetOperationStmt *op = (SetOperationStmt *) setOp;
333 if (op->op == top_union->op &&
334 (op->all == top_union->all || op->all) &&
335 equali(op->colTypes, top_union->colTypes))
337 /* Same UNION, so fold children into parent's subplan list */
338 return nconc(recurse_union_children(op->larg, parse,
341 recurse_union_children(op->rarg, parse,
348 * Not same, so plan this child separately.
350 * Note we disallow any resjunk columns in child results. This is
351 * necessary since the Append node that implements the union won't do
352 * any projection, and upper levels will get confused if some of our
353 * output tuples have junk and some don't. This case only arises when
354 * we have an EXCEPT or INTERSECT as child, else there won't be
357 return makeList1(recurse_set_operations(setOp, parse,
358 top_union->colTypes, false,
359 -1, refnames_tlist));
363 * Generate targetlist for a set-operation plan node
365 * colTypes: column datatypes for non-junk columns
366 * flag: -1 if no flag column needed, 0 or 1 to create a const flag column
367 * hack_constants: true to copy up constants (see comments in code)
368 * input_tlist: targetlist of this node's input node
369 * refnames_tlist: targetlist to take column names from
372 generate_setop_tlist(List *colTypes, int flag,
375 List *refnames_tlist)
385 Oid colType = (Oid) lfirsti(i);
386 TargetEntry *inputtle = (TargetEntry *) lfirst(input_tlist);
387 TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist);
390 Assert(inputtle->resdom->resno == resno);
391 Assert(reftle->resdom->resno == resno);
392 Assert(!inputtle->resdom->resjunk);
393 Assert(!reftle->resdom->resjunk);
396 * Generate columns referencing input columns and having
397 * appropriate data types and column names. Insert datatype
398 * coercions where necessary.
400 * HACK: constants in the input's targetlist are copied up as-is
401 * rather than being referenced as subquery outputs. This is
402 * mainly to ensure that when we try to coerce them to the output
403 * column's datatype, the right things happen for UNKNOWN
404 * constants. But do this only at the first level of
405 * subquery-scan plans; we don't want phony constants appearing in
406 * the output tlists of upper-level nodes!
408 if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
409 expr = (Node *) inputtle->expr;
411 expr = (Node *) makeVar(0,
412 inputtle->resdom->resno,
413 inputtle->resdom->restype,
414 inputtle->resdom->restypmod,
416 if (inputtle->resdom->restype == colType)
418 /* no coercion needed, and believe the input typmod */
419 colTypmod = inputtle->resdom->restypmod;
423 expr = coerce_to_common_type(expr,
425 "UNION/INTERSECT/EXCEPT");
428 resdom = makeResdom((AttrNumber) resno++,
431 pstrdup(reftle->resdom->resname),
433 tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
434 input_tlist = lnext(input_tlist);
435 refnames_tlist = lnext(refnames_tlist);
440 /* Add a resjunk flag column */
441 resdom = makeResdom((AttrNumber) resno++,
446 /* flag value is the given constant */
447 expr = (Node *) makeConst(INT4OID,
452 tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
459 * Generate targetlist for a set-operation Append node
461 * colTypes: column datatypes for non-junk columns
462 * flag: true to create a flag column copied up from subplans
463 * input_plans: list of sub-plans of the Append
464 * refnames_tlist: targetlist to take column names from
466 * The entries in the Append's targetlist should always be simple Vars;
467 * we just have to make sure they have the right datatypes and typmods.
470 generate_append_tlist(List *colTypes, bool flag,
472 List *refnames_tlist)
484 * First extract typmods to use.
486 * If the inputs all agree on type and typmod of a particular column, use
487 * that typmod; else use -1.
489 colTypmods = (int32 *) palloc(length(colTypes) * sizeof(int32));
491 foreach(planl, input_plans)
493 Plan *subplan = (Plan *) lfirst(planl);
496 curColType = colTypes;
498 foreach(subtlist, subplan->targetlist)
500 TargetEntry *subtle = (TargetEntry *) lfirst(subtlist);
502 if (subtle->resdom->resjunk)
504 Assert(curColType != NIL);
505 if (subtle->resdom->restype == (Oid) lfirsti(curColType))
507 /* If first subplan, copy the typmod; else compare */
508 if (planl == input_plans)
509 colTypmods[colindex] = subtle->resdom->restypmod;
510 else if (subtle->resdom->restypmod != colTypmods[colindex])
511 colTypmods[colindex] = -1;
515 /* types disagree, so force typmod to -1 */
516 colTypmods[colindex] = -1;
518 curColType = lnext(curColType);
521 Assert(curColType == NIL);
525 * Now we can build the tlist for the Append.
528 foreach(curColType, colTypes)
530 Oid colType = (Oid) lfirsti(curColType);
531 int32 colTypmod = colTypmods[colindex++];
532 TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist);
534 Assert(reftle->resdom->resno == resno);
535 Assert(!reftle->resdom->resjunk);
536 expr = (Node *) makeVar(0,
541 resdom = makeResdom((AttrNumber) resno++,
544 pstrdup(reftle->resdom->resname),
546 tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
547 refnames_tlist = lnext(refnames_tlist);
552 /* Add a resjunk flag column */
553 resdom = makeResdom((AttrNumber) resno++,
558 /* flag value is shown as copied up from subplan */
559 expr = (Node *) makeVar(0,
564 tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
573 * Does tlist have same datatypes as requested colTypes?
575 * Resjunk columns are ignored if junkOK is true; otherwise presence of
576 * a resjunk column will always cause a 'false' result.
579 tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
585 TargetEntry *tle = (TargetEntry *) lfirst(i);
587 if (tle->resdom->resjunk)
596 if (tle->resdom->restype != (Oid) lfirsti(colTypes))
598 colTypes = lnext(colTypes);
608 * find_all_inheritors -
609 * Returns an integer list of relids including the given rel plus
610 * all relations that inherit from it, directly or indirectly.
613 find_all_inheritors(Oid parentrel)
615 List *examined_relids = NIL;
616 List *unexamined_relids = makeListi1(parentrel);
619 * While the queue of unexamined relids is nonempty, remove the first
620 * element, mark it examined, and find its direct descendants. NB:
621 * cannot use foreach(), since we modify the queue inside loop.
623 while (unexamined_relids != NIL)
625 Oid currentrel = lfirsti(unexamined_relids);
626 List *currentchildren;
628 unexamined_relids = lnext(unexamined_relids);
629 examined_relids = lappendi(examined_relids, currentrel);
630 currentchildren = find_inheritance_children(currentrel);
633 * Add to the queue only those children not already seen. This
634 * avoids making duplicate entries in case of multiple inheritance
635 * paths from the same parent. (It'll also keep us from getting
636 * into an infinite loop, though theoretically there can't be any
637 * cycles in the inheritance graph anyway.)
639 currentchildren = set_differencei(currentchildren, examined_relids);
640 unexamined_relids = set_unioni(unexamined_relids, currentchildren);
643 return examined_relids;
647 * expand_inherted_rtentry
648 * Check whether a rangetable entry represents an inheritance set.
649 * If so, add entries for all the child tables to the query's
650 * rangetable, and return an integer list of RT indexes for the
651 * whole inheritance set (parent and children).
652 * If not, return NIL.
654 * When dup_parent is false, the initially given RT index is part of the
655 * returned list (if any). When dup_parent is true, the given RT index
656 * is *not* in the returned list; a duplicate RTE will be made for the
659 * A childless table is never considered to be an inheritance set; therefore
660 * the result will never be a one-element list. It'll be either empty
661 * or have two or more elements.
663 * NOTE: after this routine executes, the specified RTE will always have
664 * its inh flag cleared, whether or not there were any children. This
665 * ensures we won't expand the same RTE twice, which would otherwise occur
666 * for the case of an inherited UPDATE/DELETE target relation.
669 expand_inherted_rtentry(Query *parse, Index rti, bool dup_parent)
671 RangeTblEntry *rte = rt_fetch(rti, parse->rtable);
677 /* Does RT entry allow inheritance? */
680 Assert(rte->rtekind == RTE_RELATION);
681 /* Always clear the parent's inh flag, see above comments */
683 /* Fast path for common case of childless table */
684 parentOID = rte->relid;
685 if (!has_subclass(parentOID))
687 /* Scan for all members of inheritance set */
688 inhOIDs = find_all_inheritors(parentOID);
691 * Check that there's at least one descendant, else treat as no-child
692 * case. This could happen despite above has_subclass() check, if
693 * table once had a child but no longer does.
695 if (lnext(inhOIDs) == NIL)
697 /* OK, it's an inheritance set; expand it */
701 inhRTIs = makeListi1(rti); /* include original RTE in result */
705 Oid childOID = (Oid) lfirsti(l);
706 RangeTblEntry *childrte;
709 /* parent will be in the list too; skip it if not dup requested */
710 if (childOID == parentOID && !dup_parent)
714 * Build an RTE for the child, and attach to query's rangetable
715 * list. We copy most fields of the parent's RTE, but replace
716 * relation real name and OID. Note that inh will be false at
719 childrte = copyObject(rte);
720 childrte->relid = childOID;
721 parse->rtable = lappend(parse->rtable, childrte);
722 childRTindex = length(parse->rtable);
724 inhRTIs = lappendi(inhRTIs, childRTindex);
731 * adjust_inherited_attrs
732 * Copy the specified query or expression and translate Vars referring
733 * to old_rt_index to refer to new_rt_index.
735 * We also adjust varattno to match the new table by column name, rather
736 * than column number. This hack makes it possible for child tables to have
737 * different column positions for the "same" attribute as a parent, which
738 * helps ALTER TABLE ADD COLUMN. Unfortunately this isn't nearly enough to
739 * make it work transparently; there are other places where things fall down
740 * if children and parents don't have the same column numbers for inherited
741 * attributes. It'd be better to rip this code out and fix ALTER TABLE...
744 adjust_inherited_attrs(Node *node,
745 Index old_rt_index, Oid old_relid,
746 Index new_rt_index, Oid new_relid)
748 adjust_inherited_attrs_context context;
750 /* Handle simple case simply... */
751 if (old_rt_index == new_rt_index)
753 Assert(old_relid == new_relid);
754 return copyObject(node);
757 context.old_rt_index = old_rt_index;
758 context.new_rt_index = new_rt_index;
759 context.old_relid = old_relid;
760 context.new_relid = new_relid;
763 * Must be prepared to start with a Query or a bare expression tree.
765 if (node && IsA(node, Query))
767 Query *query = (Query *) node;
770 FLATCOPY(newnode, query, Query);
771 if (newnode->resultRelation == old_rt_index)
772 newnode->resultRelation = new_rt_index;
773 query_tree_mutator(newnode, adjust_inherited_attrs_mutator,
774 (void *) &context, QTW_IGNORE_SUBQUERIES);
775 return (Node *) newnode;
778 return adjust_inherited_attrs_mutator(node, &context);
782 adjust_inherited_attrs_mutator(Node *node,
783 adjust_inherited_attrs_context *context)
789 Var *var = (Var *) copyObject(node);
791 if (var->varlevelsup == 0 &&
792 var->varno == context->old_rt_index)
794 var->varno = context->new_rt_index;
795 if (var->varattno > 0)
797 char *attname = get_attname(context->old_relid,
800 var->varattno = get_attnum(context->new_relid, attname);
801 if (var->varattno == InvalidAttrNumber)
802 elog(ERROR, "Relation \"%s\" has no column \"%s\"",
803 get_rel_name(context->new_relid), attname);
809 if (IsA(node, RangeTblRef))
811 RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
813 if (rtr->rtindex == context->old_rt_index)
814 rtr->rtindex = context->new_rt_index;
817 if (IsA(node, JoinExpr))
819 /* Copy the JoinExpr node with correct mutation of subnodes */
822 j = (JoinExpr *) expression_tree_mutator(node,
823 adjust_inherited_attrs_mutator,
825 /* now fix JoinExpr's rtindex */
826 if (j->rtindex == context->old_rt_index)
827 j->rtindex = context->new_rt_index;
832 * We have to process RestrictInfo nodes specially: we do NOT want to
833 * copy the original subclauseindices list, since the new rel may have
834 * different indices. The list will be rebuilt during later planning.
836 if (IsA(node, RestrictInfo))
838 RestrictInfo *oldinfo = (RestrictInfo *) node;
839 RestrictInfo *newinfo = makeNode(RestrictInfo);
841 /* Copy all flat-copiable fields */
842 memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
844 newinfo->clause = (Expr *)
845 adjust_inherited_attrs_mutator((Node *) oldinfo->clause, context);
847 newinfo->subclauseindices = NIL;
848 newinfo->eval_cost = -1; /* reset these too */
849 newinfo->this_selec = -1;
850 newinfo->left_pathkey = NIL; /* and these */
851 newinfo->right_pathkey = NIL;
852 newinfo->left_mergescansel = -1;
853 newinfo->right_mergescansel = -1;
854 newinfo->left_bucketsize = -1;
855 newinfo->right_bucketsize = -1;
857 return (Node *) newinfo;
861 * NOTE: we do not need to recurse into sublinks, because they should
862 * already have been converted to subplans before we see them.
866 * BUT: although we don't need to recurse into subplans, we do need to
867 * make sure that they are copied, not just referenced as
868 * expression_tree_mutator will do by default. Otherwise we'll have
869 * the same subplan node referenced from each arm of the inheritance
870 * APPEND plan, which will cause trouble in the executor. This is a
871 * kluge that should go away when we redesign querytrees.
873 if (is_subplan(node))
877 /* Copy the node and process subplan args */
878 node = expression_tree_mutator(node, adjust_inherited_attrs_mutator,
880 /* Make sure we have separate copies of subplan and its rtable */
881 subplan = (SubPlan *) node;
882 subplan->plan = copyObject(subplan->plan);
883 subplan->rtable = copyObject(subplan->rtable);
887 return expression_tree_mutator(node, adjust_inherited_attrs_mutator,