]> granicus.if.org Git - postgresql/blob - src/backend/optimizer/prep/prepunion.c
cd7952aefde0023f6119a41366e36691f8cc66b4
[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 are two code paths in the planner for set-operation queries.
8  * If a subquery consists entirely of simple UNION ALL operations, it
9  * is converted into an "append relation".      Otherwise, it is handled
10  * by the general code in this module (plan_set_operations and its
11  * subroutines).  There is some support code here for the append-relation
12  * case, but most of the heavy lifting for that is done elsewhere,
13  * notably in prepjointree.c and allpaths.c.
14  *
15  * There is also some code here to support planning of queries that use
16  * inheritance (SELECT FROM foo*).      Inheritance trees are converted into
17  * append relations, and thenceforth share code with the UNION ALL case.
18  *
19  *
20  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
21  * Portions Copyright (c) 1994, Regents of the University of California
22  *
23  *
24  * IDENTIFICATION
25  *        $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.135 2007/01/05 22:19:32 momjian Exp $
26  *
27  *-------------------------------------------------------------------------
28  */
29 #include "postgres.h"
30
31
32 #include "access/heapam.h"
33 #include "catalog/namespace.h"
34 #include "catalog/pg_type.h"
35 #include "nodes/makefuncs.h"
36 #include "optimizer/clauses.h"
37 #include "optimizer/plancat.h"
38 #include "optimizer/planmain.h"
39 #include "optimizer/planner.h"
40 #include "optimizer/prep.h"
41 #include "optimizer/tlist.h"
42 #include "parser/parse_clause.h"
43 #include "parser/parse_coerce.h"
44 #include "parser/parse_expr.h"
45 #include "parser/parsetree.h"
46 #include "utils/lsyscache.h"
47
48
49 static Plan *recurse_set_operations(Node *setOp, PlannerInfo *root,
50                                            double tuple_fraction,
51                                            List *colTypes, bool junkOK,
52                                            int flag, List *refnames_tlist,
53                                            List **sortClauses);
54 static Plan *generate_union_plan(SetOperationStmt *op, PlannerInfo *root,
55                                         double tuple_fraction,
56                                         List *refnames_tlist, List **sortClauses);
57 static Plan *generate_nonunion_plan(SetOperationStmt *op, PlannerInfo *root,
58                                            List *refnames_tlist, List **sortClauses);
59 static List *recurse_union_children(Node *setOp, PlannerInfo *root,
60                                            double tuple_fraction,
61                                            SetOperationStmt *top_union,
62                                            List *refnames_tlist);
63 static List *generate_setop_tlist(List *colTypes, int flag,
64                                          Index varno,
65                                          bool hack_constants,
66                                          List *input_tlist,
67                                          List *refnames_tlist);
68 static List *generate_append_tlist(List *colTypes, bool flag,
69                                           List *input_plans,
70                                           List *refnames_tlist);
71 static void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte,
72                                                  Index rti);
73 static void make_inh_translation_lists(Relation oldrelation,
74                                                    Relation newrelation,
75                                                    Index newvarno,
76                                                    List **col_mappings,
77                                                    List **translated_vars);
78 static Node *adjust_appendrel_attrs_mutator(Node *node,
79                                                            AppendRelInfo *context);
80 static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid);
81 static List *adjust_inherited_tlist(List *tlist,
82                                            AppendRelInfo *context);
83
84
85 /*
86  * plan_set_operations
87  *
88  *        Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT)
89  *
90  * This routine only deals with the setOperations tree of the given query.
91  * Any top-level ORDER BY requested in root->parse->sortClause will be added
92  * when we return to grouping_planner.
93  *
94  * tuple_fraction is the fraction of tuples we expect will be retrieved.
95  * tuple_fraction is interpreted as for grouping_planner(); in particular,
96  * zero means "all the tuples will be fetched".  Any LIMIT present at the
97  * top level has already been factored into tuple_fraction.
98  *
99  * *sortClauses is an output argument: it is set to a list of SortClauses
100  * representing the result ordering of the topmost set operation.
101  */
102 Plan *
103 plan_set_operations(PlannerInfo *root, double tuple_fraction,
104                                         List **sortClauses)
105 {
106         Query      *parse = root->parse;
107         SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;
108         Node       *node;
109         Query      *leftmostQuery;
110
111         Assert(topop && IsA(topop, SetOperationStmt));
112
113         /* check for unsupported stuff */
114         Assert(parse->utilityStmt == NULL);
115         Assert(parse->jointree->fromlist == NIL);
116         Assert(parse->jointree->quals == NULL);
117         Assert(parse->groupClause == NIL);
118         Assert(parse->havingQual == NULL);
119         Assert(parse->distinctClause == NIL);
120
121         /*
122          * Find the leftmost component Query.  We need to use its column names for
123          * all generated tlists (else SELECT INTO won't work right).
124          */
125         node = topop->larg;
126         while (node && IsA(node, SetOperationStmt))
127                 node = ((SetOperationStmt *) node)->larg;
128         Assert(node && IsA(node, RangeTblRef));
129         leftmostQuery = rt_fetch(((RangeTblRef *) node)->rtindex,
130                                                          parse->rtable)->subquery;
131         Assert(leftmostQuery != NULL);
132
133         /*
134          * Recurse on setOperations tree to generate plans for set ops. The final
135          * output plan should have just the column types shown as the output from
136          * the top-level node, plus possibly resjunk working columns (we can rely
137          * on upper-level nodes to deal with that).
138          */
139         return recurse_set_operations((Node *) topop, root, tuple_fraction,
140                                                                   topop->colTypes, true, -1,
141                                                                   leftmostQuery->targetList,
142                                                                   sortClauses);
143 }
144
145 /*
146  * recurse_set_operations
147  *        Recursively handle one step in a tree of set operations
148  *
149  * tuple_fraction: fraction of tuples we expect to retrieve from node
150  * colTypes: list of type OIDs of expected output columns
151  * junkOK: if true, child resjunk columns may be left in the result
152  * flag: if >= 0, add a resjunk output column indicating value of flag
153  * refnames_tlist: targetlist to take column names from
154  * *sortClauses: receives list of SortClauses for result plan, if any
155  *
156  * We don't have to care about typmods here: the only allowed difference
157  * between set-op input and output typmods is input is a specific typmod
158  * and output is -1, and that does not require a coercion.
159  */
160 static Plan *
161 recurse_set_operations(Node *setOp, PlannerInfo *root,
162                                            double tuple_fraction,
163                                            List *colTypes, bool junkOK,
164                                            int flag, List *refnames_tlist,
165                                            List **sortClauses)
166 {
167         if (IsA(setOp, RangeTblRef))
168         {
169                 RangeTblRef *rtr = (RangeTblRef *) setOp;
170                 RangeTblEntry *rte = rt_fetch(rtr->rtindex, root->parse->rtable);
171                 Query      *subquery = rte->subquery;
172                 Plan       *subplan,
173                                    *plan;
174
175                 Assert(subquery != NULL);
176
177                 /*
178                  * Generate plan for primitive subquery
179                  */
180                 subplan = subquery_planner(subquery, tuple_fraction, NULL);
181
182                 /*
183                  * Add a SubqueryScan with the caller-requested targetlist
184                  */
185                 plan = (Plan *)
186                         make_subqueryscan(generate_setop_tlist(colTypes, flag,
187                                                                                                    rtr->rtindex,
188                                                                                                    true,
189                                                                                                    subplan->targetlist,
190                                                                                                    refnames_tlist),
191                                                           NIL,
192                                                           rtr->rtindex,
193                                                           subplan);
194
195                 /*
196                  * We don't bother to determine the subquery's output ordering since
197                  * it won't be reflected in the set-op result anyhow.
198                  */
199                 *sortClauses = NIL;
200
201                 return plan;
202         }
203         else if (IsA(setOp, SetOperationStmt))
204         {
205                 SetOperationStmt *op = (SetOperationStmt *) setOp;
206                 Plan       *plan;
207
208                 /* UNIONs are much different from INTERSECT/EXCEPT */
209                 if (op->op == SETOP_UNION)
210                         plan = generate_union_plan(op, root, tuple_fraction,
211                                                                            refnames_tlist,
212                                                                            sortClauses);
213                 else
214                         plan = generate_nonunion_plan(op, root,
215                                                                                   refnames_tlist,
216                                                                                   sortClauses);
217
218                 /*
219                  * If necessary, add a Result node to project the caller-requested
220                  * output columns.
221                  *
222                  * XXX you don't really want to know about this: setrefs.c will apply
223                  * replace_vars_with_subplan_refs() to the Result node's tlist. This
224                  * would fail if the Vars generated by generate_setop_tlist() were not
225                  * exactly equal() to the corresponding tlist entries of the subplan.
226                  * However, since the subplan was generated by generate_union_plan()
227                  * or generate_nonunion_plan(), and hence its tlist was generated by
228                  * generate_append_tlist(), this will work.  We just tell
229                  * generate_setop_tlist() to use varno 0.
230                  */
231                 if (flag >= 0 ||
232                         !tlist_same_datatypes(plan->targetlist, colTypes, junkOK))
233                 {
234                         plan = (Plan *)
235                                 make_result(generate_setop_tlist(colTypes, flag,
236                                                                                                  0,
237                                                                                                  false,
238                                                                                                  plan->targetlist,
239                                                                                                  refnames_tlist),
240                                                         NULL,
241                                                         plan);
242                 }
243                 return plan;
244         }
245         else
246         {
247                 elog(ERROR, "unrecognized node type: %d",
248                          (int) nodeTag(setOp));
249                 return NULL;                    /* keep compiler quiet */
250         }
251 }
252
253 /*
254  * Generate plan for a UNION or UNION ALL node
255  */
256 static Plan *
257 generate_union_plan(SetOperationStmt *op, PlannerInfo *root,
258                                         double tuple_fraction,
259                                         List *refnames_tlist,
260                                         List **sortClauses)
261 {
262         List       *planlist;
263         List       *tlist;
264         Plan       *plan;
265
266         /*
267          * If plain UNION, tell children to fetch all tuples.
268          *
269          * Note: in UNION ALL, we pass the top-level tuple_fraction unmodified to
270          * each arm of the UNION ALL.  One could make a case for reducing the
271          * tuple fraction for later arms (discounting by the expected size of the
272          * earlier arms' results) but it seems not worth the trouble. The normal
273          * case where tuple_fraction isn't already zero is a LIMIT at top level,
274          * and passing it down as-is is usually enough to get the desired result
275          * of preferring fast-start plans.
276          */
277         if (!op->all)
278                 tuple_fraction = 0.0;
279
280         /*
281          * If any of my children are identical UNION nodes (same op, all-flag, and
282          * colTypes) then they can be merged into this node so that we generate
283          * only one Append and Sort for the lot.  Recurse to find such nodes and
284          * compute their children's plans.
285          */
286         planlist = list_concat(recurse_union_children(op->larg, root,
287                                                                                                   tuple_fraction,
288                                                                                                   op, refnames_tlist),
289                                                    recurse_union_children(op->rarg, root,
290                                                                                                   tuple_fraction,
291                                                                                                   op, refnames_tlist));
292
293         /*
294          * Generate tlist for Append plan node.
295          *
296          * The tlist for an Append plan isn't important as far as the Append is
297          * concerned, but we must make it look real anyway for the benefit of the
298          * next plan level up.
299          */
300         tlist = generate_append_tlist(op->colTypes, false,
301                                                                   planlist, refnames_tlist);
302
303         /*
304          * Append the child results together.
305          */
306         plan = (Plan *) make_append(planlist, false, tlist);
307
308         /*
309          * For UNION ALL, we just need the Append plan.  For UNION, need to add
310          * Sort and Unique nodes to produce unique output.
311          */
312         if (!op->all)
313         {
314                 List       *sortList;
315
316                 sortList = addAllTargetsToSortList(NULL, NIL, tlist, false);
317                 if (sortList)
318                 {
319                         plan = (Plan *) make_sort_from_sortclauses(root, sortList, plan);
320                         plan = (Plan *) make_unique(plan, sortList);
321                 }
322                 *sortClauses = sortList;
323         }
324         else
325                 *sortClauses = NIL;
326
327         return plan;
328 }
329
330 /*
331  * Generate plan for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node
332  */
333 static Plan *
334 generate_nonunion_plan(SetOperationStmt *op, PlannerInfo *root,
335                                            List *refnames_tlist,
336                                            List **sortClauses)
337 {
338         Plan       *lplan,
339                            *rplan,
340                            *plan;
341         List       *tlist,
342                            *sortList,
343                            *planlist,
344                            *child_sortclauses;
345         SetOpCmd        cmd;
346
347         /* Recurse on children, ensuring their outputs are marked */
348         lplan = recurse_set_operations(op->larg, root,
349                                                                    0.0 /* all tuples needed */ ,
350                                                                    op->colTypes, false, 0,
351                                                                    refnames_tlist,
352                                                                    &child_sortclauses);
353         rplan = recurse_set_operations(op->rarg, root,
354                                                                    0.0 /* all tuples needed */ ,
355                                                                    op->colTypes, false, 1,
356                                                                    refnames_tlist,
357                                                                    &child_sortclauses);
358         planlist = list_make2(lplan, rplan);
359
360         /*
361          * Generate tlist for Append plan node.
362          *
363          * The tlist for an Append plan isn't important as far as the Append is
364          * concerned, but we must make it look real anyway for the benefit of the
365          * next plan level up.  In fact, it has to be real enough that the flag
366          * column is shown as a variable not a constant, else setrefs.c will get
367          * confused.
368          */
369         tlist = generate_append_tlist(op->colTypes, true,
370                                                                   planlist, refnames_tlist);
371
372         /*
373          * Append the child results together.
374          */
375         plan = (Plan *) make_append(planlist, false, tlist);
376
377         /*
378          * Sort the child results, then add a SetOp plan node to generate the
379          * correct output.
380          */
381         sortList = addAllTargetsToSortList(NULL, NIL, tlist, false);
382
383         if (sortList == NIL)            /* nothing to sort on? */
384         {
385                 *sortClauses = NIL;
386                 return plan;
387         }
388
389         plan = (Plan *) make_sort_from_sortclauses(root, sortList, plan);
390         switch (op->op)
391         {
392                 case SETOP_INTERSECT:
393                         cmd = op->all ? SETOPCMD_INTERSECT_ALL : SETOPCMD_INTERSECT;
394                         break;
395                 case SETOP_EXCEPT:
396                         cmd = op->all ? SETOPCMD_EXCEPT_ALL : SETOPCMD_EXCEPT;
397                         break;
398                 default:
399                         elog(ERROR, "unrecognized set op: %d",
400                                  (int) op->op);
401                         cmd = SETOPCMD_INTERSECT;       /* keep compiler quiet */
402                         break;
403         }
404         plan = (Plan *) make_setop(cmd, plan, sortList, list_length(op->colTypes) + 1);
405
406         *sortClauses = sortList;
407
408         return plan;
409 }
410
411 /*
412  * Pull up children of a UNION node that are identically-propertied UNIONs.
413  *
414  * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
415  * output rows will be lost anyway.
416  */
417 static List *
418 recurse_union_children(Node *setOp, PlannerInfo *root,
419                                            double tuple_fraction,
420                                            SetOperationStmt *top_union,
421                                            List *refnames_tlist)
422 {
423         List       *child_sortclauses;
424
425         if (IsA(setOp, SetOperationStmt))
426         {
427                 SetOperationStmt *op = (SetOperationStmt *) setOp;
428
429                 if (op->op == top_union->op &&
430                         (op->all == top_union->all || op->all) &&
431                         equal(op->colTypes, top_union->colTypes))
432                 {
433                         /* Same UNION, so fold children into parent's subplan list */
434                         return list_concat(recurse_union_children(op->larg, root,
435                                                                                                           tuple_fraction,
436                                                                                                           top_union,
437                                                                                                           refnames_tlist),
438                                                            recurse_union_children(op->rarg, root,
439                                                                                                           tuple_fraction,
440                                                                                                           top_union,
441                                                                                                           refnames_tlist));
442                 }
443         }
444
445         /*
446          * Not same, so plan this child separately.
447          *
448          * Note we disallow any resjunk columns in child results.  This is
449          * necessary since the Append node that implements the union won't do any
450          * projection, and upper levels will get confused if some of our output
451          * tuples have junk and some don't.  This case only arises when we have an
452          * EXCEPT or INTERSECT as child, else there won't be resjunk anyway.
453          */
454         return list_make1(recurse_set_operations(setOp, root,
455                                                                                          tuple_fraction,
456                                                                                          top_union->colTypes, false,
457                                                                                          -1, refnames_tlist,
458                                                                                          &child_sortclauses));
459 }
460
461 /*
462  * Generate targetlist for a set-operation plan node
463  *
464  * colTypes: column datatypes for non-junk columns
465  * flag: -1 if no flag column needed, 0 or 1 to create a const flag column
466  * varno: varno to use in generated Vars
467  * hack_constants: true to copy up constants (see comments in code)
468  * input_tlist: targetlist of this node's input node
469  * refnames_tlist: targetlist to take column names from
470  */
471 static List *
472 generate_setop_tlist(List *colTypes, int flag,
473                                          Index varno,
474                                          bool hack_constants,
475                                          List *input_tlist,
476                                          List *refnames_tlist)
477 {
478         List       *tlist = NIL;
479         int                     resno = 1;
480         ListCell   *i,
481                            *j,
482                            *k;
483         TargetEntry *tle;
484         Node       *expr;
485
486         j = list_head(input_tlist);
487         k = list_head(refnames_tlist);
488         foreach(i, colTypes)
489         {
490                 Oid                     colType = lfirst_oid(i);
491                 TargetEntry *inputtle = (TargetEntry *) lfirst(j);
492                 TargetEntry *reftle = (TargetEntry *) lfirst(k);
493
494                 Assert(inputtle->resno == resno);
495                 Assert(reftle->resno == resno);
496                 Assert(!inputtle->resjunk);
497                 Assert(!reftle->resjunk);
498
499                 /*
500                  * Generate columns referencing input columns and having appropriate
501                  * data types and column names.  Insert datatype coercions where
502                  * necessary.
503                  *
504                  * HACK: constants in the input's targetlist are copied up as-is
505                  * rather than being referenced as subquery outputs.  This is mainly
506                  * to ensure that when we try to coerce them to the output column's
507                  * datatype, the right things happen for UNKNOWN constants.  But do
508                  * this only at the first level of subquery-scan plans; we don't want
509                  * phony constants appearing in the output tlists of upper-level
510                  * nodes!
511                  */
512                 if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
513                         expr = (Node *) inputtle->expr;
514                 else
515                         expr = (Node *) makeVar(varno,
516                                                                         inputtle->resno,
517                                                                         exprType((Node *) inputtle->expr),
518                                                                         exprTypmod((Node *) inputtle->expr),
519                                                                         0);
520                 if (exprType(expr) != colType)
521                 {
522                         expr = coerce_to_common_type(NULL,      /* no UNKNOWNs here */
523                                                                                  expr,
524                                                                                  colType,
525                                                                                  "UNION/INTERSECT/EXCEPT");
526                 }
527                 tle = makeTargetEntry((Expr *) expr,
528                                                           (AttrNumber) resno++,
529                                                           pstrdup(reftle->resname),
530                                                           false);
531                 tlist = lappend(tlist, tle);
532
533                 j = lnext(j);
534                 k = lnext(k);
535         }
536
537         if (flag >= 0)
538         {
539                 /* Add a resjunk flag column */
540                 /* flag value is the given constant */
541                 expr = (Node *) makeConst(INT4OID,
542                                                                   sizeof(int4),
543                                                                   Int32GetDatum(flag),
544                                                                   false,
545                                                                   true);
546                 tle = makeTargetEntry((Expr *) expr,
547                                                           (AttrNumber) resno++,
548                                                           pstrdup("flag"),
549                                                           true);
550                 tlist = lappend(tlist, tle);
551         }
552
553         return tlist;
554 }
555
556 /*
557  * Generate targetlist for a set-operation Append node
558  *
559  * colTypes: column datatypes for non-junk columns
560  * flag: true to create a flag column copied up from subplans
561  * input_plans: list of sub-plans of the Append
562  * refnames_tlist: targetlist to take column names from
563  *
564  * The entries in the Append's targetlist should always be simple Vars;
565  * we just have to make sure they have the right datatypes and typmods.
566  * The Vars are always generated with varno 0.
567  */
568 static List *
569 generate_append_tlist(List *colTypes, bool flag,
570                                           List *input_plans,
571                                           List *refnames_tlist)
572 {
573         List       *tlist = NIL;
574         int                     resno = 1;
575         ListCell   *curColType;
576         ListCell   *ref_tl_item;
577         int                     colindex;
578         TargetEntry *tle;
579         Node       *expr;
580         ListCell   *planl;
581         int32      *colTypmods;
582
583         /*
584          * First extract typmods to use.
585          *
586          * If the inputs all agree on type and typmod of a particular column, use
587          * that typmod; else use -1.
588          */
589         colTypmods = (int32 *) palloc(list_length(colTypes) * sizeof(int32));
590
591         foreach(planl, input_plans)
592         {
593                 Plan       *subplan = (Plan *) lfirst(planl);
594                 ListCell   *subtlist;
595
596                 curColType = list_head(colTypes);
597                 colindex = 0;
598                 foreach(subtlist, subplan->targetlist)
599                 {
600                         TargetEntry *subtle = (TargetEntry *) lfirst(subtlist);
601
602                         if (subtle->resjunk)
603                                 continue;
604                         Assert(curColType != NULL);
605                         if (exprType((Node *) subtle->expr) == lfirst_oid(curColType))
606                         {
607                                 /* If first subplan, copy the typmod; else compare */
608                                 int32           subtypmod = exprTypmod((Node *) subtle->expr);
609
610                                 if (planl == list_head(input_plans))
611                                         colTypmods[colindex] = subtypmod;
612                                 else if (subtypmod != colTypmods[colindex])
613                                         colTypmods[colindex] = -1;
614                         }
615                         else
616                         {
617                                 /* types disagree, so force typmod to -1 */
618                                 colTypmods[colindex] = -1;
619                         }
620                         curColType = lnext(curColType);
621                         colindex++;
622                 }
623                 Assert(curColType == NULL);
624         }
625
626         /*
627          * Now we can build the tlist for the Append.
628          */
629         colindex = 0;
630         forboth(curColType, colTypes, ref_tl_item, refnames_tlist)
631         {
632                 Oid                     colType = lfirst_oid(curColType);
633                 int32           colTypmod = colTypmods[colindex++];
634                 TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item);
635
636                 Assert(reftle->resno == resno);
637                 Assert(!reftle->resjunk);
638                 expr = (Node *) makeVar(0,
639                                                                 resno,
640                                                                 colType,
641                                                                 colTypmod,
642                                                                 0);
643                 tle = makeTargetEntry((Expr *) expr,
644                                                           (AttrNumber) resno++,
645                                                           pstrdup(reftle->resname),
646                                                           false);
647                 tlist = lappend(tlist, tle);
648         }
649
650         if (flag)
651         {
652                 /* Add a resjunk flag column */
653                 /* flag value is shown as copied up from subplan */
654                 expr = (Node *) makeVar(0,
655                                                                 resno,
656                                                                 INT4OID,
657                                                                 -1,
658                                                                 0);
659                 tle = makeTargetEntry((Expr *) expr,
660                                                           (AttrNumber) resno++,
661                                                           pstrdup("flag"),
662                                                           true);
663                 tlist = lappend(tlist, tle);
664         }
665
666         pfree(colTypmods);
667
668         return tlist;
669 }
670
671
672 /*
673  * find_all_inheritors -
674  *              Returns a list of relation OIDs including the given rel plus
675  *              all relations that inherit from it, directly or indirectly.
676  */
677 List *
678 find_all_inheritors(Oid parentrel)
679 {
680         List       *rels_list;
681         ListCell   *l;
682
683         /*
684          * We build a list starting with the given rel and adding all direct and
685          * indirect children.  We can use a single list as both the record of
686          * already-found rels and the agenda of rels yet to be scanned for more
687          * children.  This is a bit tricky but works because the foreach() macro
688          * doesn't fetch the next list element until the bottom of the loop.
689          */
690         rels_list = list_make1_oid(parentrel);
691
692         foreach(l, rels_list)
693         {
694                 Oid                     currentrel = lfirst_oid(l);
695                 List       *currentchildren;
696
697                 /* Get the direct children of this rel */
698                 currentchildren = find_inheritance_children(currentrel);
699
700                 /*
701                  * Add to the queue only those children not already seen. This avoids
702                  * making duplicate entries in case of multiple inheritance paths from
703                  * the same parent.  (It'll also keep us from getting into an infinite
704                  * loop, though theoretically there can't be any cycles in the
705                  * inheritance graph anyway.)
706                  */
707                 rels_list = list_concat_unique_oid(rels_list, currentchildren);
708         }
709
710         return rels_list;
711 }
712
713 /*
714  * expand_inherited_tables
715  *              Expand each rangetable entry that represents an inheritance set
716  *              into an "append relation".      At the conclusion of this process,
717  *              the "inh" flag is set in all and only those RTEs that are append
718  *              relation parents.
719  */
720 void
721 expand_inherited_tables(PlannerInfo *root)
722 {
723         Index           nrtes;
724         Index           rti;
725         ListCell   *rl;
726
727         /*
728          * expand_inherited_rtentry may add RTEs to parse->rtable; there is no
729          * need to scan them since they can't have inh=true.  So just scan as far
730          * as the original end of the rtable list.
731          */
732         nrtes = list_length(root->parse->rtable);
733         rl = list_head(root->parse->rtable);
734         for (rti = 1; rti <= nrtes; rti++)
735         {
736                 RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);
737
738                 expand_inherited_rtentry(root, rte, rti);
739                 rl = lnext(rl);
740         }
741 }
742
743 /*
744  * expand_inherited_rtentry
745  *              Check whether a rangetable entry represents an inheritance set.
746  *              If so, add entries for all the child tables to the query's
747  *              rangetable, and build AppendRelInfo nodes for all the child tables
748  *              and add them to root->append_rel_list.  If not, clear the entry's
749  *              "inh" flag to prevent later code from looking for AppendRelInfos.
750  *
751  * Note that the original RTE is considered to represent the whole
752  * inheritance set.  The first of the generated RTEs is an RTE for the same
753  * table, but with inh = false, to represent the parent table in its role
754  * as a simple member of the inheritance set.
755  *
756  * A childless table is never considered to be an inheritance set; therefore
757  * a parent RTE must always have at least two associated AppendRelInfos.
758  */
759 static void
760 expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
761 {
762         Query      *parse = root->parse;
763         Oid                     parentOID;
764         Relation        oldrelation;
765         LOCKMODE        lockmode;
766         List       *inhOIDs;
767         List       *appinfos;
768         ListCell   *l;
769
770         /* Does RT entry allow inheritance? */
771         if (!rte->inh)
772                 return;
773         /* Ignore any already-expanded UNION ALL nodes */
774         if (rte->rtekind != RTE_RELATION)
775         {
776                 Assert(rte->rtekind == RTE_SUBQUERY);
777                 return;
778         }
779         /* Fast path for common case of childless table */
780         parentOID = rte->relid;
781         if (!has_subclass(parentOID))
782         {
783                 /* Clear flag before returning */
784                 rte->inh = false;
785                 return;
786         }
787
788         /* Scan for all members of inheritance set */
789         inhOIDs = find_all_inheritors(parentOID);
790
791         /*
792          * Check that there's at least one descendant, else treat as no-child
793          * case.  This could happen despite above has_subclass() check, if table
794          * once had a child but no longer does.
795          */
796         if (list_length(inhOIDs) < 2)
797         {
798                 /* Clear flag before returning */
799                 rte->inh = false;
800                 return;
801         }
802
803         /*
804          * Must open the parent relation to examine its tupdesc.  We need not lock
805          * it since the rewriter already obtained at least AccessShareLock on each
806          * relation used in the query.
807          */
808         oldrelation = heap_open(parentOID, NoLock);
809
810         /*
811          * However, for each child relation we add to the query, we must obtain an
812          * appropriate lock, because this will be the first use of those relations
813          * in the parse/rewrite/plan pipeline.
814          *
815          * If the parent relation is the query's result relation, then we need
816          * RowExclusiveLock.  Otherwise, check to see if the relation is accessed
817          * FOR UPDATE/SHARE or not.  We can't just grab AccessShareLock because
818          * then the executor would be trying to upgrade the lock, leading to
819          * possible deadlocks.  (This code should match the parser and rewriter.)
820          */
821         if (rti == parse->resultRelation)
822                 lockmode = RowExclusiveLock;
823         else if (get_rowmark(parse, rti))
824                 lockmode = RowShareLock;
825         else
826                 lockmode = AccessShareLock;
827
828         /* Scan the inheritance set and expand it */
829         appinfos = NIL;
830         foreach(l, inhOIDs)
831         {
832                 Oid                     childOID = lfirst_oid(l);
833                 Relation        newrelation;
834                 RangeTblEntry *childrte;
835                 Index           childRTindex;
836                 AppendRelInfo *appinfo;
837
838                 /*
839                  * It is possible that the parent table has children that are temp
840                  * tables of other backends.  We cannot safely access such tables
841                  * (because of buffering issues), and the best thing to do seems to be
842                  * to silently ignore them.
843                  */
844                 if (childOID != parentOID &&
845                         isOtherTempNamespace(get_rel_namespace(childOID)))
846                         continue;
847
848                 /* Open rel, acquire the appropriate lock type */
849                 if (childOID != parentOID)
850                         newrelation = heap_open(childOID, lockmode);
851                 else
852                         newrelation = oldrelation;
853
854                 /*
855                  * Build an RTE for the child, and attach to query's rangetable list.
856                  * We copy most fields of the parent's RTE, but replace relation OID,
857                  * and set inh = false.
858                  */
859                 childrte = copyObject(rte);
860                 childrte->relid = childOID;
861                 childrte->inh = false;
862                 parse->rtable = lappend(parse->rtable, childrte);
863                 childRTindex = list_length(parse->rtable);
864
865                 /*
866                  * Build an AppendRelInfo for this parent and child.
867                  */
868                 appinfo = makeNode(AppendRelInfo);
869                 appinfo->parent_relid = rti;
870                 appinfo->child_relid = childRTindex;
871                 appinfo->parent_reltype = oldrelation->rd_rel->reltype;
872                 appinfo->child_reltype = newrelation->rd_rel->reltype;
873                 make_inh_translation_lists(oldrelation, newrelation, childRTindex,
874                                                                    &appinfo->col_mappings,
875                                                                    &appinfo->translated_vars);
876                 appinfo->parent_reloid = parentOID;
877                 appinfos = lappend(appinfos, appinfo);
878
879                 /* Close child relations, but keep locks */
880                 if (childOID != parentOID)
881                         heap_close(newrelation, NoLock);
882         }
883
884         heap_close(oldrelation, NoLock);
885
886         /*
887          * If all the children were temp tables, pretend it's a non-inheritance
888          * situation.  The duplicate RTE we added for the parent table is
889          * harmless, so we don't bother to get rid of it.
890          */
891         if (list_length(appinfos) < 2)
892         {
893                 /* Clear flag before returning */
894                 rte->inh = false;
895                 return;
896         }
897
898         /* Otherwise, OK to add to root->append_rel_list */
899         root->append_rel_list = list_concat(root->append_rel_list, appinfos);
900
901         /*
902          * The executor will check the parent table's access permissions when it
903          * examines the parent's added RTE entry.  There's no need to check twice,
904          * so turn off access check bits in the original RTE.
905          */
906         rte->requiredPerms = 0;
907 }
908
909 /*
910  * make_inh_translation_lists
911  *        Build the lists of translations from parent Vars to child Vars for
912  *        an inheritance child.  We need both a column number mapping list
913  *        and a list of Vars representing the child columns.
914  *
915  * For paranoia's sake, we match type as well as attribute name.
916  */
917 static void
918 make_inh_translation_lists(Relation oldrelation, Relation newrelation,
919                                                    Index newvarno,
920                                                    List **col_mappings, List **translated_vars)
921 {
922         List       *numbers = NIL;
923         List       *vars = NIL;
924         TupleDesc       old_tupdesc = RelationGetDescr(oldrelation);
925         TupleDesc       new_tupdesc = RelationGetDescr(newrelation);
926         int                     oldnatts = old_tupdesc->natts;
927         int                     newnatts = new_tupdesc->natts;
928         int                     old_attno;
929
930         for (old_attno = 0; old_attno < oldnatts; old_attno++)
931         {
932                 Form_pg_attribute att;
933                 char       *attname;
934                 Oid                     atttypid;
935                 int32           atttypmod;
936                 int                     new_attno;
937
938                 att = old_tupdesc->attrs[old_attno];
939                 if (att->attisdropped)
940                 {
941                         /* Just put 0/NULL into this list entry */
942                         numbers = lappend_int(numbers, 0);
943                         vars = lappend(vars, NULL);
944                         continue;
945                 }
946                 attname = NameStr(att->attname);
947                 atttypid = att->atttypid;
948                 atttypmod = att->atttypmod;
949
950                 /*
951                  * When we are generating the "translation list" for the parent table
952                  * of an inheritance set, no need to search for matches.
953                  */
954                 if (oldrelation == newrelation)
955                 {
956                         numbers = lappend_int(numbers, old_attno + 1);
957                         vars = lappend(vars, makeVar(newvarno,
958                                                                                  (AttrNumber) (old_attno + 1),
959                                                                                  atttypid,
960                                                                                  atttypmod,
961                                                                                  0));
962                         continue;
963                 }
964
965                 /*
966                  * Otherwise we have to search for the matching column by name.
967                  * There's no guarantee it'll have the same column position, because
968                  * of cases like ALTER TABLE ADD COLUMN and multiple inheritance.
969                  */
970                 for (new_attno = 0; new_attno < newnatts; new_attno++)
971                 {
972                         att = new_tupdesc->attrs[new_attno];
973                         if (att->attisdropped || att->attinhcount == 0)
974                                 continue;
975                         if (strcmp(attname, NameStr(att->attname)) != 0)
976                                 continue;
977                         /* Found it, check type */
978                         if (atttypid != att->atttypid || atttypmod != att->atttypmod)
979                                 elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type",
980                                          attname, RelationGetRelationName(newrelation));
981
982                         numbers = lappend_int(numbers, new_attno + 1);
983                         vars = lappend(vars, makeVar(newvarno,
984                                                                                  (AttrNumber) (new_attno + 1),
985                                                                                  atttypid,
986                                                                                  atttypmod,
987                                                                                  0));
988                         break;
989                 }
990
991                 if (new_attno >= newnatts)
992                         elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
993                                  attname, RelationGetRelationName(newrelation));
994         }
995
996         *col_mappings = numbers;
997         *translated_vars = vars;
998 }
999
1000 /*
1001  * adjust_appendrel_attrs
1002  *        Copy the specified query or expression and translate Vars referring
1003  *        to the parent rel of the specified AppendRelInfo to refer to the
1004  *        child rel instead.  We also update rtindexes appearing outside Vars,
1005  *        such as resultRelation and jointree relids.
1006  *
1007  * Note: this is only applied after conversion of sublinks to subplans,
1008  * so we don't need to cope with recursion into sub-queries.
1009  *
1010  * Note: this is not hugely different from what ResolveNew() does; maybe
1011  * we should try to fold the two routines together.
1012  */
1013 Node *
1014 adjust_appendrel_attrs(Node *node, AppendRelInfo *appinfo)
1015 {
1016         Node       *result;
1017
1018         /*
1019          * Must be prepared to start with a Query or a bare expression tree.
1020          */
1021         if (node && IsA(node, Query))
1022         {
1023                 Query      *newnode;
1024
1025                 newnode = query_tree_mutator((Query *) node,
1026                                                                          adjust_appendrel_attrs_mutator,
1027                                                                          (void *) appinfo,
1028                                                                          QTW_IGNORE_RT_SUBQUERIES);
1029                 if (newnode->resultRelation == appinfo->parent_relid)
1030                 {
1031                         newnode->resultRelation = appinfo->child_relid;
1032                         /* Fix tlist resnos too, if it's inherited UPDATE */
1033                         if (newnode->commandType == CMD_UPDATE)
1034                                 newnode->targetList =
1035                                         adjust_inherited_tlist(newnode->targetList,
1036                                                                                    appinfo);
1037                 }
1038                 result = (Node *) newnode;
1039         }
1040         else
1041                 result = adjust_appendrel_attrs_mutator(node, appinfo);
1042
1043         return result;
1044 }
1045
1046 static Node *
1047 adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
1048 {
1049         if (node == NULL)
1050                 return NULL;
1051         if (IsA(node, Var))
1052         {
1053                 Var                *var = (Var *) copyObject(node);
1054
1055                 if (var->varlevelsup == 0 &&
1056                         var->varno == context->parent_relid)
1057                 {
1058                         var->varno = context->child_relid;
1059                         var->varnoold = context->child_relid;
1060                         if (var->varattno > 0)
1061                         {
1062                                 Node       *newnode;
1063
1064                                 if (var->varattno > list_length(context->translated_vars))
1065                                         elog(ERROR, "attribute %d of relation \"%s\" does not exist",
1066                                                  var->varattno, get_rel_name(context->parent_reloid));
1067                                 newnode = copyObject(list_nth(context->translated_vars,
1068                                                                                           var->varattno - 1));
1069                                 if (newnode == NULL)
1070                                         elog(ERROR, "attribute %d of relation \"%s\" does not exist",
1071                                                  var->varattno, get_rel_name(context->parent_reloid));
1072                                 return newnode;
1073                         }
1074                         else if (var->varattno == 0)
1075                         {
1076                                 /*
1077                                  * Whole-row Var: if we are dealing with named rowtypes, we
1078                                  * can use a whole-row Var for the child table plus a coercion
1079                                  * step to convert the tuple layout to the parent's rowtype.
1080                                  * Otherwise we have to generate a RowExpr.
1081                                  */
1082                                 if (OidIsValid(context->child_reltype))
1083                                 {
1084                                         Assert(var->vartype == context->parent_reltype);
1085                                         if (context->parent_reltype != context->child_reltype)
1086                                         {
1087                                                 ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);
1088
1089                                                 r->arg = (Expr *) var;
1090                                                 r->resulttype = context->parent_reltype;
1091                                                 r->convertformat = COERCE_IMPLICIT_CAST;
1092                                                 /* Make sure the Var node has the right type ID, too */
1093                                                 var->vartype = context->child_reltype;
1094                                                 return (Node *) r;
1095                                         }
1096                                 }
1097                                 else
1098                                 {
1099                                         /*
1100                                          * Build a RowExpr containing the translated variables.
1101                                          */
1102                                         RowExpr    *rowexpr;
1103                                         List       *fields;
1104
1105                                         fields = (List *) copyObject(context->translated_vars);
1106                                         rowexpr = makeNode(RowExpr);
1107                                         rowexpr->args = fields;
1108                                         rowexpr->row_typeid = var->vartype;
1109                                         rowexpr->row_format = COERCE_IMPLICIT_CAST;
1110                                         return (Node *) rowexpr;
1111                                 }
1112                         }
1113                         /* system attributes don't need any other translation */
1114                 }
1115                 return (Node *) var;
1116         }
1117         if (IsA(node, RangeTblRef))
1118         {
1119                 RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
1120
1121                 if (rtr->rtindex == context->parent_relid)
1122                         rtr->rtindex = context->child_relid;
1123                 return (Node *) rtr;
1124         }
1125         if (IsA(node, JoinExpr))
1126         {
1127                 /* Copy the JoinExpr node with correct mutation of subnodes */
1128                 JoinExpr   *j;
1129
1130                 j = (JoinExpr *) expression_tree_mutator(node,
1131                                                                                           adjust_appendrel_attrs_mutator,
1132                                                                                                  (void *) context);
1133                 /* now fix JoinExpr's rtindex (probably never happens) */
1134                 if (j->rtindex == context->parent_relid)
1135                         j->rtindex = context->child_relid;
1136                 return (Node *) j;
1137         }
1138         if (IsA(node, InClauseInfo))
1139         {
1140                 /* Copy the InClauseInfo node with correct mutation of subnodes */
1141                 InClauseInfo *ininfo;
1142
1143                 ininfo = (InClauseInfo *) expression_tree_mutator(node,
1144                                                                                           adjust_appendrel_attrs_mutator,
1145                                                                                                                   (void *) context);
1146                 /* now fix InClauseInfo's relid sets */
1147                 ininfo->lefthand = adjust_relid_set(ininfo->lefthand,
1148                                                                                         context->parent_relid,
1149                                                                                         context->child_relid);
1150                 ininfo->righthand = adjust_relid_set(ininfo->righthand,
1151                                                                                          context->parent_relid,
1152                                                                                          context->child_relid);
1153                 return (Node *) ininfo;
1154         }
1155         /* Shouldn't need to handle OuterJoinInfo or AppendRelInfo here */
1156         Assert(!IsA(node, OuterJoinInfo));
1157         Assert(!IsA(node, AppendRelInfo));
1158
1159         /*
1160          * We have to process RestrictInfo nodes specially.
1161          */
1162         if (IsA(node, RestrictInfo))
1163         {
1164                 RestrictInfo *oldinfo = (RestrictInfo *) node;
1165                 RestrictInfo *newinfo = makeNode(RestrictInfo);
1166
1167                 /* Copy all flat-copiable fields */
1168                 memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
1169
1170                 /* Recursively fix the clause itself */
1171                 newinfo->clause = (Expr *)
1172                         adjust_appendrel_attrs_mutator((Node *) oldinfo->clause, context);
1173
1174                 /* and the modified version, if an OR clause */
1175                 newinfo->orclause = (Expr *)
1176                         adjust_appendrel_attrs_mutator((Node *) oldinfo->orclause, context);
1177
1178                 /* adjust relid sets too */
1179                 newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids,
1180                                                                                                   context->parent_relid,
1181                                                                                                   context->child_relid);
1182                 newinfo->required_relids = adjust_relid_set(oldinfo->required_relids,
1183                                                                                                         context->parent_relid,
1184                                                                                                         context->child_relid);
1185                 newinfo->left_relids = adjust_relid_set(oldinfo->left_relids,
1186                                                                                                 context->parent_relid,
1187                                                                                                 context->child_relid);
1188                 newinfo->right_relids = adjust_relid_set(oldinfo->right_relids,
1189                                                                                                  context->parent_relid,
1190                                                                                                  context->child_relid);
1191
1192                 /*
1193                  * Reset cached derivative fields, since these might need to have
1194                  * different values when considering the child relation.
1195                  */
1196                 newinfo->eval_cost.startup = -1;
1197                 newinfo->this_selec = -1;
1198                 newinfo->left_pathkey = NIL;
1199                 newinfo->right_pathkey = NIL;
1200                 newinfo->left_mergescansel = -1;
1201                 newinfo->right_mergescansel = -1;
1202                 newinfo->left_bucketsize = -1;
1203                 newinfo->right_bucketsize = -1;
1204
1205                 return (Node *) newinfo;
1206         }
1207
1208         /*
1209          * NOTE: we do not need to recurse into sublinks, because they should
1210          * already have been converted to subplans before we see them.
1211          */
1212         Assert(!IsA(node, SubLink));
1213         Assert(!IsA(node, Query));
1214
1215         /*
1216          * BUT: although we don't need to recurse into subplans, we do need to
1217          * make sure that they are copied, not just referenced as
1218          * expression_tree_mutator will do by default.  Otherwise we'll have the
1219          * same subplan node referenced from each arm of the finished APPEND plan,
1220          * which will cause trouble in the executor.  This is a kluge that should
1221          * go away when we redesign querytrees.
1222          */
1223         if (is_subplan(node))
1224         {
1225                 SubPlan    *subplan;
1226
1227                 /* Copy the node and process subplan args */
1228                 node = expression_tree_mutator(node, adjust_appendrel_attrs_mutator,
1229                                                                            (void *) context);
1230                 /* Make sure we have separate copies of subplan and its rtable */
1231                 subplan = (SubPlan *) node;
1232                 subplan->plan = copyObject(subplan->plan);
1233                 subplan->rtable = copyObject(subplan->rtable);
1234                 return node;
1235         }
1236
1237         return expression_tree_mutator(node, adjust_appendrel_attrs_mutator,
1238                                                                    (void *) context);
1239 }
1240
1241 /*
1242  * Substitute newrelid for oldrelid in a Relid set
1243  */
1244 static Relids
1245 adjust_relid_set(Relids relids, Index oldrelid, Index newrelid)
1246 {
1247         if (bms_is_member(oldrelid, relids))
1248         {
1249                 /* Ensure we have a modifiable copy */
1250                 relids = bms_copy(relids);
1251                 /* Remove old, add new */
1252                 relids = bms_del_member(relids, oldrelid);
1253                 relids = bms_add_member(relids, newrelid);
1254         }
1255         return relids;
1256 }
1257
1258 /*
1259  * adjust_appendrel_attr_needed
1260  *              Adjust an attr_needed[] array to reference a member rel instead of
1261  *              the original appendrel
1262  *
1263  * oldrel: source of data (we use the attr_needed, min_attr, max_attr fields)
1264  * appinfo: supplies parent_relid, child_relid, col_mappings
1265  * new_min_attr, new_max_attr: desired bounds of new attr_needed array
1266  *
1267  * The relid sets are adjusted by substituting child_relid for parent_relid.
1268  * (NOTE: oldrel is not necessarily the parent_relid relation!)  We are also
1269  * careful to map attribute numbers within the array properly.  User
1270  * attributes have to be mapped through col_mappings, but system attributes
1271  * and whole-row references always have the same attno.
1272  *
1273  * Returns a palloc'd array with the specified bounds
1274  */
1275 Relids *
1276 adjust_appendrel_attr_needed(RelOptInfo *oldrel, AppendRelInfo *appinfo,
1277                                                          AttrNumber new_min_attr, AttrNumber new_max_attr)
1278 {
1279         Relids     *new_attr_needed;
1280         Index           parent_relid = appinfo->parent_relid;
1281         Index           child_relid = appinfo->child_relid;
1282         int                     parent_attr;
1283         ListCell   *lm;
1284
1285         /* Create empty result array */
1286         Assert(new_min_attr <= oldrel->min_attr);
1287         Assert(new_max_attr >= oldrel->max_attr);
1288         new_attr_needed = (Relids *)
1289                 palloc0((new_max_attr - new_min_attr + 1) * sizeof(Relids));
1290         /* Process user attributes, with appropriate attno mapping */
1291         parent_attr = 1;
1292         foreach(lm, appinfo->col_mappings)
1293         {
1294                 int                     child_attr = lfirst_int(lm);
1295
1296                 if (child_attr > 0)
1297                 {
1298                         Relids          attrneeded;
1299
1300                         Assert(parent_attr <= oldrel->max_attr);
1301                         Assert(child_attr <= new_max_attr);
1302                         attrneeded = oldrel->attr_needed[parent_attr - oldrel->min_attr];
1303                         attrneeded = adjust_relid_set(attrneeded,
1304                                                                                   parent_relid, child_relid);
1305                         new_attr_needed[child_attr - new_min_attr] = attrneeded;
1306                 }
1307                 parent_attr++;
1308         }
1309         /* Process system attributes, including whole-row references */
1310         for (parent_attr = oldrel->min_attr; parent_attr <= 0; parent_attr++)
1311         {
1312                 Relids          attrneeded;
1313
1314                 attrneeded = oldrel->attr_needed[parent_attr - oldrel->min_attr];
1315                 attrneeded = adjust_relid_set(attrneeded,
1316                                                                           parent_relid, child_relid);
1317                 new_attr_needed[parent_attr - new_min_attr] = attrneeded;
1318         }
1319
1320         return new_attr_needed;
1321 }
1322
1323 /*
1324  * Adjust the targetlist entries of an inherited UPDATE operation
1325  *
1326  * The expressions have already been fixed, but we have to make sure that
1327  * the target resnos match the child table (they may not, in the case of
1328  * a column that was added after-the-fact by ALTER TABLE).      In some cases
1329  * this can force us to re-order the tlist to preserve resno ordering.
1330  * (We do all this work in special cases so that preptlist.c is fast for
1331  * the typical case.)
1332  *
1333  * The given tlist has already been through expression_tree_mutator;
1334  * therefore the TargetEntry nodes are fresh copies that it's okay to
1335  * scribble on.
1336  *
1337  * Note that this is not needed for INSERT because INSERT isn't inheritable.
1338  */
1339 static List *
1340 adjust_inherited_tlist(List *tlist, AppendRelInfo *context)
1341 {
1342         bool            changed_it = false;
1343         ListCell   *tl;
1344         List       *new_tlist;
1345         bool            more;
1346         int                     attrno;
1347
1348         /* This should only happen for an inheritance case, not UNION ALL */
1349         Assert(OidIsValid(context->parent_reloid));
1350
1351         /* Scan tlist and update resnos to match attnums of child rel */
1352         foreach(tl, tlist)
1353         {
1354                 TargetEntry *tle = (TargetEntry *) lfirst(tl);
1355                 int                     newattno;
1356
1357                 if (tle->resjunk)
1358                         continue;                       /* ignore junk items */
1359
1360                 /* Look up the translation of this column */
1361                 if (tle->resno <= 0 ||
1362                         tle->resno > list_length(context->col_mappings))
1363                         elog(ERROR, "attribute %d of relation \"%s\" does not exist",
1364                                  tle->resno, get_rel_name(context->parent_reloid));
1365                 newattno = list_nth_int(context->col_mappings, tle->resno - 1);
1366                 if (newattno <= 0)
1367                         elog(ERROR, "attribute %d of relation \"%s\" does not exist",
1368                                  tle->resno, get_rel_name(context->parent_reloid));
1369
1370                 if (tle->resno != newattno)
1371                 {
1372                         tle->resno = newattno;
1373                         changed_it = true;
1374                 }
1375         }
1376
1377         /*
1378          * If we changed anything, re-sort the tlist by resno, and make sure
1379          * resjunk entries have resnos above the last real resno.  The sort
1380          * algorithm is a bit stupid, but for such a seldom-taken path, small is
1381          * probably better than fast.
1382          */
1383         if (!changed_it)
1384                 return tlist;
1385
1386         new_tlist = NIL;
1387         more = true;
1388         for (attrno = 1; more; attrno++)
1389         {
1390                 more = false;
1391                 foreach(tl, tlist)
1392                 {
1393                         TargetEntry *tle = (TargetEntry *) lfirst(tl);
1394
1395                         if (tle->resjunk)
1396                                 continue;               /* ignore junk items */
1397
1398                         if (tle->resno == attrno)
1399                                 new_tlist = lappend(new_tlist, tle);
1400                         else if (tle->resno > attrno)
1401                                 more = true;
1402                 }
1403         }
1404
1405         foreach(tl, tlist)
1406         {
1407                 TargetEntry *tle = (TargetEntry *) lfirst(tl);
1408
1409                 if (!tle->resjunk)
1410                         continue;                       /* here, ignore non-junk items */
1411
1412                 tle->resno = attrno;
1413                 new_tlist = lappend(new_tlist, tle);
1414                 attrno++;
1415         }
1416
1417         return new_tlist;
1418 }