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