]> granicus.if.org Git - postgresql/blob - src/backend/optimizer/prep/prepunion.c
5e44a64c01246a0715ebc5a4eda4723150def204
[postgresql] / src / backend / optimizer / prep / prepunion.c
1 /*-------------------------------------------------------------------------
2  *
3  * prepunion.c
4  *        Routines to plan set-operation queries.  The filename is a leftover
5  *        from a time when only UNIONs were implemented.
6  *
7  * There 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.
10  *
11  *
12  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
13  * Portions Copyright (c) 1994, Regents of the University of California
14  *
15  *
16  * IDENTIFICATION
17  *        $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.83 2002/12/14 00:17:57 tgl Exp $
18  *
19  *-------------------------------------------------------------------------
20  */
21 #include "postgres.h"
22
23
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"
36
37 /* macros borrowed from expression_tree_mutator */
38
39 #define FLATCOPY(newnode, node, nodetype)  \
40         ( (newnode) = makeNode(nodetype), \
41           memcpy((newnode), (node), sizeof(nodetype)) )
42
43 typedef struct
44 {
45         Index           old_rt_index;
46         Index           new_rt_index;
47         Oid                     old_relid;
48         Oid                     new_relid;
49 } adjust_inherited_attrs_context;
50
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,
62                                          bool hack_constants,
63                                          List *input_tlist,
64                                          List *refnames_tlist);
65 static List *generate_append_tlist(List *colTypes, bool flag,
66                                           List *input_plans,
67                                           List *refnames_tlist);
68 static Node *adjust_inherited_attrs_mutator(Node *node,
69                                                            adjust_inherited_attrs_context *context);
70
71
72 /*
73  * plan_set_operations
74  *
75  *        Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT)
76  *
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.
80  */
81 Plan *
82 plan_set_operations(Query *parse)
83 {
84         SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;
85         Node       *node;
86         Query      *leftmostQuery;
87
88         Assert(topop && IsA(topop, SetOperationStmt));
89
90         /*
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).
93          */
94         node = topop->larg;
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);
101
102         /*
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).
107          */
108         return recurse_set_operations((Node *) topop, parse,
109                                                                   topop->colTypes, true, -1,
110                                                                   leftmostQuery->targetList);
111 }
112
113 /*
114  * recurse_set_operations
115  *        Recursively handle one step in a tree of set operations
116  *
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
121  */
122 static Plan *
123 recurse_set_operations(Node *setOp, Query *parse,
124                                            List *colTypes, bool junkOK,
125                                            int flag, List *refnames_tlist)
126 {
127         if (IsA(setOp, RangeTblRef))
128         {
129                 RangeTblRef *rtr = (RangeTblRef *) setOp;
130                 RangeTblEntry *rte = rt_fetch(rtr->rtindex, parse->rtable);
131                 Query      *subquery = rte->subquery;
132                 Plan       *subplan,
133                                    *plan;
134
135                 Assert(subquery != NULL);
136
137                 /*
138                  * Generate plan for primitive subquery
139                  */
140                 subplan = subquery_planner(subquery,
141                                                                    -1.0 /* default case */ );
142
143                 /*
144                  * Add a SubqueryScan with the caller-requested targetlist
145                  */
146                 plan = (Plan *)
147                         make_subqueryscan(generate_setop_tlist(colTypes, flag, true,
148                                                                                                    subplan->targetlist,
149                                                                                                    refnames_tlist),
150                                                           NIL,
151                                                           rtr->rtindex,
152                                                           subplan);
153                 return plan;
154         }
155         else if (IsA(setOp, SetOperationStmt))
156         {
157                 SetOperationStmt *op = (SetOperationStmt *) setOp;
158                 Plan       *plan;
159
160                 /* UNIONs are much different from INTERSECT/EXCEPT */
161                 if (op->op == SETOP_UNION)
162                         plan = generate_union_plan(op, parse, refnames_tlist);
163                 else
164                         plan = generate_nonunion_plan(op, parse, refnames_tlist);
165
166                 /*
167                  * If necessary, add a Result node to project the caller-requested
168                  * output columns.
169                  *
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
177                  * work.
178                  */
179                 if (flag >= 0 ||
180                         !tlist_same_datatypes(plan->targetlist, colTypes, junkOK))
181                 {
182                         plan = (Plan *)
183                                 make_result(generate_setop_tlist(colTypes, flag, false,
184                                                                                                  plan->targetlist,
185                                                                                                  refnames_tlist),
186                                                         NULL,
187                                                         plan);
188                 }
189                 return plan;
190         }
191         else
192         {
193                 elog(ERROR, "recurse_set_operations: unexpected node %d",
194                          (int) nodeTag(setOp));
195                 return NULL;                    /* keep compiler quiet */
196         }
197 }
198
199 /*
200  * Generate plan for a UNION or UNION ALL node
201  */
202 static Plan *
203 generate_union_plan(SetOperationStmt *op, Query *parse,
204                                         List *refnames_tlist)
205 {
206         List       *planlist;
207         List       *tlist;
208         Plan       *plan;
209
210         /*
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.
215          */
216         planlist = nconc(recurse_union_children(op->larg, parse,
217                                                                                         op, refnames_tlist),
218                                          recurse_union_children(op->rarg, parse,
219                                                                                         op, refnames_tlist));
220
221         /*
222          * Generate tlist for Append plan node.
223          *
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.
227          */
228         tlist = generate_append_tlist(op->colTypes, false,
229                                                                   planlist, refnames_tlist);
230
231         /*
232          * Append the child results together.
233          */
234         plan = (Plan *) make_append(planlist, false, tlist);
235
236         /*
237          * For UNION ALL, we just need the Append plan.  For UNION, need to
238          * add Sort and Unique nodes to produce unique output.
239          */
240         if (!op->all)
241         {
242                 List       *sortList;
243
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));
248         }
249         return plan;
250 }
251
252 /*
253  * Generate plan for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node
254  */
255 static Plan *
256 generate_nonunion_plan(SetOperationStmt *op, Query *parse,
257                                            List *refnames_tlist)
258 {
259         Plan       *lplan,
260                            *rplan,
261                            *plan;
262         List       *tlist,
263                            *sortList,
264                            *planlist;
265         SetOpCmd        cmd;
266
267         /* Recurse on children, ensuring their outputs are marked */
268         lplan = recurse_set_operations(op->larg, parse,
269                                                                    op->colTypes, false, 0,
270                                                                    refnames_tlist);
271         rplan = recurse_set_operations(op->rarg, parse,
272                                                                    op->colTypes, false, 1,
273                                                                    refnames_tlist);
274         planlist = makeList2(lplan, rplan);
275
276         /*
277          * Generate tlist for Append plan node.
278          *
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
283          * will get confused.
284          */
285         tlist = generate_append_tlist(op->colTypes, true,
286                                                                   planlist, refnames_tlist);
287
288         /*
289          * Append the child results together.
290          */
291         plan = (Plan *) make_append(planlist, false, tlist);
292
293         /*
294          * Sort the child results, then add a SetOp plan node to generate the
295          * correct output.
296          */
297         tlist = new_unsorted_tlist(tlist);
298         sortList = addAllTargetsToSortList(NIL, tlist);
299         plan = make_sortplan(parse, tlist, plan, sortList);
300         switch (op->op)
301         {
302                 case SETOP_INTERSECT:
303                         cmd = op->all ? SETOPCMD_INTERSECT_ALL : SETOPCMD_INTERSECT;
304                         break;
305                 case SETOP_EXCEPT:
306                         cmd = op->all ? SETOPCMD_EXCEPT_ALL : SETOPCMD_EXCEPT;
307                         break;
308                 default:
309                         elog(ERROR, "generate_nonunion_plan: bogus operation code");
310                         cmd = SETOPCMD_INTERSECT;       /* keep compiler quiet */
311                         break;
312         }
313         plan = (Plan *) make_setop(cmd, tlist, plan, sortList,
314                                                            length(op->colTypes) + 1);
315         return plan;
316 }
317
318 /*
319  * Pull up children of a UNION node that are identically-propertied UNIONs.
320  *
321  * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
322  * output rows will be lost anyway.
323  */
324 static List *
325 recurse_union_children(Node *setOp, Query *parse,
326                                            SetOperationStmt *top_union,
327                                            List *refnames_tlist)
328 {
329         if (IsA(setOp, SetOperationStmt))
330         {
331                 SetOperationStmt *op = (SetOperationStmt *) setOp;
332
333                 if (op->op == top_union->op &&
334                         (op->all == top_union->all || op->all) &&
335                         equali(op->colTypes, top_union->colTypes))
336                 {
337                         /* Same UNION, so fold children into parent's subplan list */
338                         return nconc(recurse_union_children(op->larg, parse,
339                                                                                                 top_union,
340                                                                                                 refnames_tlist),
341                                                  recurse_union_children(op->rarg, parse,
342                                                                                                 top_union,
343                                                                                                 refnames_tlist));
344                 }
345         }
346
347         /*
348          * Not same, so plan this child separately.
349          *
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
355          * resjunk anyway.
356          */
357         return makeList1(recurse_set_operations(setOp, parse,
358                                                                                         top_union->colTypes, false,
359                                                                                         -1, refnames_tlist));
360 }
361
362 /*
363  * Generate targetlist for a set-operation plan node
364  *
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
370  */
371 static List *
372 generate_setop_tlist(List *colTypes, int flag,
373                                          bool hack_constants,
374                                          List *input_tlist,
375                                          List *refnames_tlist)
376 {
377         List       *tlist = NIL;
378         int                     resno = 1;
379         List       *i;
380         Resdom     *resdom;
381         Node       *expr;
382
383         foreach(i, colTypes)
384         {
385                 Oid                     colType = (Oid) lfirsti(i);
386                 TargetEntry *inputtle = (TargetEntry *) lfirst(input_tlist);
387                 TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist);
388                 int32           colTypmod;
389
390                 Assert(inputtle->resdom->resno == resno);
391                 Assert(reftle->resdom->resno == resno);
392                 Assert(!inputtle->resdom->resjunk);
393                 Assert(!reftle->resdom->resjunk);
394
395                 /*
396                  * Generate columns referencing input columns and having
397                  * appropriate data types and column names.  Insert datatype
398                  * coercions where necessary.
399                  *
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!
407                  */
408                 if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
409                         expr = (Node *) inputtle->expr;
410                 else
411                         expr = (Node *) makeVar(0,
412                                                                         inputtle->resdom->resno,
413                                                                         inputtle->resdom->restype,
414                                                                         inputtle->resdom->restypmod,
415                                                                         0);
416                 if (inputtle->resdom->restype == colType)
417                 {
418                         /* no coercion needed, and believe the input typmod */
419                         colTypmod = inputtle->resdom->restypmod;
420                 }
421                 else
422                 {
423                         expr = coerce_to_common_type(expr,
424                                                                                  colType,
425                                                                                  "UNION/INTERSECT/EXCEPT");
426                         colTypmod = -1;
427                 }
428                 resdom = makeResdom((AttrNumber) resno++,
429                                                         colType,
430                                                         colTypmod,
431                                                         pstrdup(reftle->resdom->resname),
432                                                         false);
433                 tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
434                 input_tlist = lnext(input_tlist);
435                 refnames_tlist = lnext(refnames_tlist);
436         }
437
438         if (flag >= 0)
439         {
440                 /* Add a resjunk flag column */
441                 resdom = makeResdom((AttrNumber) resno++,
442                                                         INT4OID,
443                                                         -1,
444                                                         pstrdup("flag"),
445                                                         true);
446                 /* flag value is the given constant */
447                 expr = (Node *) makeConst(INT4OID,
448                                                                   sizeof(int4),
449                                                                   Int32GetDatum(flag),
450                                                                   false,
451                                                                   true);
452                 tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
453         }
454
455         return tlist;
456 }
457
458 /*
459  * Generate targetlist for a set-operation Append node
460  *
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
465  *
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.
468  */
469 static List *
470 generate_append_tlist(List *colTypes, bool flag,
471                                           List *input_plans,
472                                           List *refnames_tlist)
473 {
474         List       *tlist = NIL;
475         int                     resno = 1;
476         List       *curColType;
477         int                     colindex;
478         Resdom     *resdom;
479         Node       *expr;
480         List       *planl;
481         int32      *colTypmods;
482
483         /*
484          * First extract typmods to use.
485          *
486          * If the inputs all agree on type and typmod of a particular column, use
487          * that typmod; else use -1.
488          */
489         colTypmods = (int32 *) palloc(length(colTypes) * sizeof(int32));
490
491         foreach(planl, input_plans)
492         {
493                 Plan       *subplan = (Plan *) lfirst(planl);
494                 List       *subtlist;
495
496                 curColType = colTypes;
497                 colindex = 0;
498                 foreach(subtlist, subplan->targetlist)
499                 {
500                         TargetEntry *subtle = (TargetEntry *) lfirst(subtlist);
501
502                         if (subtle->resdom->resjunk)
503                                 continue;
504                         Assert(curColType != NIL);
505                         if (subtle->resdom->restype == (Oid) lfirsti(curColType))
506                         {
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;
512                         }
513                         else
514                         {
515                                 /* types disagree, so force typmod to -1 */
516                                 colTypmods[colindex] = -1;
517                         }
518                         curColType = lnext(curColType);
519                         colindex++;
520                 }
521                 Assert(curColType == NIL);
522         }
523
524         /*
525          * Now we can build the tlist for the Append.
526          */
527         colindex = 0;
528         foreach(curColType, colTypes)
529         {
530                 Oid                     colType = (Oid) lfirsti(curColType);
531                 int32           colTypmod = colTypmods[colindex++];
532                 TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist);
533
534                 Assert(reftle->resdom->resno == resno);
535                 Assert(!reftle->resdom->resjunk);
536                 expr = (Node *) makeVar(0,
537                                                                 resno,
538                                                                 colType,
539                                                                 colTypmod,
540                                                                 0);
541                 resdom = makeResdom((AttrNumber) resno++,
542                                                         colType,
543                                                         colTypmod,
544                                                         pstrdup(reftle->resdom->resname),
545                                                         false);
546                 tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
547                 refnames_tlist = lnext(refnames_tlist);
548         }
549
550         if (flag)
551         {
552                 /* Add a resjunk flag column */
553                 resdom = makeResdom((AttrNumber) resno++,
554                                                         INT4OID,
555                                                         -1,
556                                                         pstrdup("flag"),
557                                                         true);
558                 /* flag value is shown as copied up from subplan */
559                 expr = (Node *) makeVar(0,
560                                                                 resdom->resno,
561                                                                 INT4OID,
562                                                                 -1,
563                                                                 0);
564                 tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
565         }
566
567         pfree(colTypmods);
568
569         return tlist;
570 }
571
572 /*
573  * Does tlist have same datatypes as requested colTypes?
574  *
575  * Resjunk columns are ignored if junkOK is true; otherwise presence of
576  * a resjunk column will always cause a 'false' result.
577  */
578 bool
579 tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
580 {
581         List       *i;
582
583         foreach(i, tlist)
584         {
585                 TargetEntry *tle = (TargetEntry *) lfirst(i);
586
587                 if (tle->resdom->resjunk)
588                 {
589                         if (!junkOK)
590                                 return false;
591                 }
592                 else
593                 {
594                         if (colTypes == NIL)
595                                 return false;
596                         if (tle->resdom->restype != (Oid) lfirsti(colTypes))
597                                 return false;
598                         colTypes = lnext(colTypes);
599                 }
600         }
601         if (colTypes != NIL)
602                 return false;
603         return true;
604 }
605
606
607 /*
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.
611  */
612 List *
613 find_all_inheritors(Oid parentrel)
614 {
615         List       *examined_relids = NIL;
616         List       *unexamined_relids = makeListi1(parentrel);
617
618         /*
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.
622          */
623         while (unexamined_relids != NIL)
624         {
625                 Oid                     currentrel = lfirsti(unexamined_relids);
626                 List       *currentchildren;
627
628                 unexamined_relids = lnext(unexamined_relids);
629                 examined_relids = lappendi(examined_relids, currentrel);
630                 currentchildren = find_inheritance_children(currentrel);
631
632                 /*
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.)
638                  */
639                 currentchildren = set_differencei(currentchildren, examined_relids);
640                 unexamined_relids = set_unioni(unexamined_relids, currentchildren);
641         }
642
643         return examined_relids;
644 }
645
646 /*
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.
653  *
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
657  * parent table.
658  *
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.
662  *
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.
667  */
668 List *
669 expand_inherted_rtentry(Query *parse, Index rti, bool dup_parent)
670 {
671         RangeTblEntry *rte = rt_fetch(rti, parse->rtable);
672         Oid                     parentOID;
673         List       *inhOIDs;
674         List       *inhRTIs;
675         List       *l;
676
677         /* Does RT entry allow inheritance? */
678         if (!rte->inh)
679                 return NIL;
680         Assert(rte->rtekind == RTE_RELATION);
681         /* Always clear the parent's inh flag, see above comments */
682         rte->inh = false;
683         /* Fast path for common case of childless table */
684         parentOID = rte->relid;
685         if (!has_subclass(parentOID))
686                 return NIL;
687         /* Scan for all members of inheritance set */
688         inhOIDs = find_all_inheritors(parentOID);
689
690         /*
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.
694          */
695         if (lnext(inhOIDs) == NIL)
696                 return NIL;
697         /* OK, it's an inheritance set; expand it */
698         if (dup_parent)
699                 inhRTIs = NIL;
700         else
701                 inhRTIs = makeListi1(rti);              /* include original RTE in result */
702
703         foreach(l, inhOIDs)
704         {
705                 Oid                     childOID = (Oid) lfirsti(l);
706                 RangeTblEntry *childrte;
707                 Index           childRTindex;
708
709                 /* parent will be in the list too; skip it if not dup requested */
710                 if (childOID == parentOID && !dup_parent)
711                         continue;
712
713                 /*
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
717                  * this point.
718                  */
719                 childrte = copyObject(rte);
720                 childrte->relid = childOID;
721                 parse->rtable = lappend(parse->rtable, childrte);
722                 childRTindex = length(parse->rtable);
723
724                 inhRTIs = lappendi(inhRTIs, childRTindex);
725         }
726
727         return inhRTIs;
728 }
729
730 /*
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.
734  *
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...
742  */
743 Node *
744 adjust_inherited_attrs(Node *node,
745                                            Index old_rt_index, Oid old_relid,
746                                            Index new_rt_index, Oid new_relid)
747 {
748         adjust_inherited_attrs_context context;
749
750         /* Handle simple case simply... */
751         if (old_rt_index == new_rt_index)
752         {
753                 Assert(old_relid == new_relid);
754                 return copyObject(node);
755         }
756
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;
761
762         /*
763          * Must be prepared to start with a Query or a bare expression tree.
764          */
765         if (node && IsA(node, Query))
766         {
767                 Query      *query = (Query *) node;
768                 Query      *newnode;
769
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;
776         }
777         else
778                 return adjust_inherited_attrs_mutator(node, &context);
779 }
780
781 static Node *
782 adjust_inherited_attrs_mutator(Node *node,
783                                                            adjust_inherited_attrs_context *context)
784 {
785         if (node == NULL)
786                 return NULL;
787         if (IsA(node, Var))
788         {
789                 Var                *var = (Var *) copyObject(node);
790
791                 if (var->varlevelsup == 0 &&
792                         var->varno == context->old_rt_index)
793                 {
794                         var->varno = context->new_rt_index;
795                         if (var->varattno > 0)
796                         {
797                                 char       *attname = get_attname(context->old_relid,
798                                                                                                   var->varattno);
799
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);
804                                 pfree(attname);
805                         }
806                 }
807                 return (Node *) var;
808         }
809         if (IsA(node, RangeTblRef))
810         {
811                 RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
812
813                 if (rtr->rtindex == context->old_rt_index)
814                         rtr->rtindex = context->new_rt_index;
815                 return (Node *) rtr;
816         }
817         if (IsA(node, JoinExpr))
818         {
819                 /* Copy the JoinExpr node with correct mutation of subnodes */
820                 JoinExpr   *j;
821
822                 j = (JoinExpr *) expression_tree_mutator(node,
823                                                                                   adjust_inherited_attrs_mutator,
824                                                                                                  (void *) context);
825                 /* now fix JoinExpr's rtindex */
826                 if (j->rtindex == context->old_rt_index)
827                         j->rtindex = context->new_rt_index;
828                 return (Node *) j;
829         }
830
831         /*
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.
835          */
836         if (IsA(node, RestrictInfo))
837         {
838                 RestrictInfo *oldinfo = (RestrictInfo *) node;
839                 RestrictInfo *newinfo = makeNode(RestrictInfo);
840
841                 /* Copy all flat-copiable fields */
842                 memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
843
844                 newinfo->clause = (Expr *)
845                         adjust_inherited_attrs_mutator((Node *) oldinfo->clause, context);
846
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;
856
857                 return (Node *) newinfo;
858         }
859
860         /*
861          * NOTE: we do not need to recurse into sublinks, because they should
862          * already have been converted to subplans before we see them.
863          */
864
865         /*
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.
872          */
873         if (is_subplan(node))
874         {
875                 SubPlan *subplan;
876
877                 /* Copy the node and process subplan args */
878                 node = expression_tree_mutator(node, adjust_inherited_attrs_mutator,
879                                                                            (void *) context);
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);
884                 return node;
885         }
886
887         return expression_tree_mutator(node, adjust_inherited_attrs_mutator,
888                                                                    (void *) context);
889 }