Header And Logo

PostgreSQL
| The world's most advanced open source database.

prepunion.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * prepunion.c
00004  *    Routines to plan set-operation queries.  The filename is a leftover
00005  *    from a time when only UNIONs were implemented.
00006  *
00007  * There are two code paths in the planner for set-operation queries.
00008  * If a subquery consists entirely of simple UNION ALL operations, it
00009  * is converted into an "append relation".  Otherwise, it is handled
00010  * by the general code in this module (plan_set_operations and its
00011  * subroutines).  There is some support code here for the append-relation
00012  * case, but most of the heavy lifting for that is done elsewhere,
00013  * notably in prepjointree.c and allpaths.c.
00014  *
00015  * There is also some code here to support planning of queries that use
00016  * inheritance (SELECT FROM foo*).  Inheritance trees are converted into
00017  * append relations, and thenceforth share code with the UNION ALL case.
00018  *
00019  *
00020  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00021  * Portions Copyright (c) 1994, Regents of the University of California
00022  *
00023  *
00024  * IDENTIFICATION
00025  *    src/backend/optimizer/prep/prepunion.c
00026  *
00027  *-------------------------------------------------------------------------
00028  */
00029 #include "postgres.h"
00030 
00031 #include <limits.h>
00032 
00033 #include "access/heapam.h"
00034 #include "access/htup_details.h"
00035 #include "access/sysattr.h"
00036 #include "catalog/pg_inherits_fn.h"
00037 #include "catalog/pg_type.h"
00038 #include "miscadmin.h"
00039 #include "nodes/makefuncs.h"
00040 #include "nodes/nodeFuncs.h"
00041 #include "optimizer/cost.h"
00042 #include "optimizer/pathnode.h"
00043 #include "optimizer/planmain.h"
00044 #include "optimizer/planner.h"
00045 #include "optimizer/prep.h"
00046 #include "optimizer/tlist.h"
00047 #include "parser/parse_coerce.h"
00048 #include "parser/parsetree.h"
00049 #include "utils/lsyscache.h"
00050 #include "utils/rel.h"
00051 #include "utils/selfuncs.h"
00052 
00053 
00054 typedef struct
00055 {
00056     PlannerInfo *root;
00057     AppendRelInfo *appinfo;
00058 } adjust_appendrel_attrs_context;
00059 
00060 static Plan *recurse_set_operations(Node *setOp, PlannerInfo *root,
00061                        double tuple_fraction,
00062                        List *colTypes, List *colCollations,
00063                        bool junkOK,
00064                        int flag, List *refnames_tlist,
00065                        List **sortClauses, double *pNumGroups);
00066 static Plan *generate_recursion_plan(SetOperationStmt *setOp,
00067                         PlannerInfo *root, double tuple_fraction,
00068                         List *refnames_tlist,
00069                         List **sortClauses);
00070 static Plan *generate_union_plan(SetOperationStmt *op, PlannerInfo *root,
00071                     double tuple_fraction,
00072                     List *refnames_tlist,
00073                     List **sortClauses, double *pNumGroups);
00074 static Plan *generate_nonunion_plan(SetOperationStmt *op, PlannerInfo *root,
00075                        double tuple_fraction,
00076                        List *refnames_tlist,
00077                        List **sortClauses, double *pNumGroups);
00078 static List *recurse_union_children(Node *setOp, PlannerInfo *root,
00079                        double tuple_fraction,
00080                        SetOperationStmt *top_union,
00081                        List *refnames_tlist);
00082 static Plan *make_union_unique(SetOperationStmt *op, Plan *plan,
00083                   PlannerInfo *root, double tuple_fraction,
00084                   List **sortClauses);
00085 static bool choose_hashed_setop(PlannerInfo *root, List *groupClauses,
00086                     Plan *input_plan,
00087                     double dNumGroups, double dNumOutputRows,
00088                     double tuple_fraction,
00089                     const char *construct);
00090 static List *generate_setop_tlist(List *colTypes, List *colCollations,
00091                      int flag,
00092                      Index varno,
00093                      bool hack_constants,
00094                      List *input_tlist,
00095                      List *refnames_tlist);
00096 static List *generate_append_tlist(List *colTypes, List *colCollations,
00097                       bool flag,
00098                       List *input_plans,
00099                       List *refnames_tlist);
00100 static List *generate_setop_grouplist(SetOperationStmt *op, List *targetlist);
00101 static void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte,
00102                          Index rti);
00103 static void make_inh_translation_list(Relation oldrelation,
00104                           Relation newrelation,
00105                           Index newvarno,
00106                           List **translated_vars);
00107 static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
00108                     List *translated_vars);
00109 static Node *adjust_appendrel_attrs_mutator(Node *node,
00110                                adjust_appendrel_attrs_context *context);
00111 static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid);
00112 static List *adjust_inherited_tlist(List *tlist,
00113                        AppendRelInfo *context);
00114 
00115 
00116 /*
00117  * plan_set_operations
00118  *
00119  *    Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT)
00120  *
00121  * This routine only deals with the setOperations tree of the given query.
00122  * Any top-level ORDER BY requested in root->parse->sortClause will be added
00123  * when we return to grouping_planner.
00124  *
00125  * tuple_fraction is the fraction of tuples we expect will be retrieved.
00126  * tuple_fraction is interpreted as for grouping_planner(); in particular,
00127  * zero means "all the tuples will be fetched".  Any LIMIT present at the
00128  * top level has already been factored into tuple_fraction.
00129  *
00130  * *sortClauses is an output argument: it is set to a list of SortGroupClauses
00131  * representing the result ordering of the topmost set operation.  (This will
00132  * be NIL if the output isn't ordered.)
00133  */
00134 Plan *
00135 plan_set_operations(PlannerInfo *root, double tuple_fraction,
00136                     List **sortClauses)
00137 {
00138     Query      *parse = root->parse;
00139     SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;
00140     Node       *node;
00141     RangeTblEntry *leftmostRTE;
00142     Query      *leftmostQuery;
00143 
00144     Assert(topop && IsA(topop, SetOperationStmt));
00145 
00146     /* check for unsupported stuff */
00147     Assert(parse->jointree->fromlist == NIL);
00148     Assert(parse->jointree->quals == NULL);
00149     Assert(parse->groupClause == NIL);
00150     Assert(parse->havingQual == NULL);
00151     Assert(parse->windowClause == NIL);
00152     Assert(parse->distinctClause == NIL);
00153 
00154     /*
00155      * We'll need to build RelOptInfos for each of the leaf subqueries, which
00156      * are RTE_SUBQUERY rangetable entries in this Query.  Prepare the index
00157      * arrays for that.
00158      */
00159     setup_simple_rel_arrays(root);
00160 
00161     /*
00162      * Find the leftmost component Query.  We need to use its column names for
00163      * all generated tlists (else SELECT INTO won't work right).
00164      */
00165     node = topop->larg;
00166     while (node && IsA(node, SetOperationStmt))
00167         node = ((SetOperationStmt *) node)->larg;
00168     Assert(node && IsA(node, RangeTblRef));
00169     leftmostRTE = root->simple_rte_array[((RangeTblRef *) node)->rtindex];
00170     leftmostQuery = leftmostRTE->subquery;
00171     Assert(leftmostQuery != NULL);
00172 
00173     /*
00174      * If the topmost node is a recursive union, it needs special processing.
00175      */
00176     if (root->hasRecursion)
00177         return generate_recursion_plan(topop, root, tuple_fraction,
00178                                        leftmostQuery->targetList,
00179                                        sortClauses);
00180 
00181     /*
00182      * Recurse on setOperations tree to generate plans for set ops. The final
00183      * output plan should have just the column types shown as the output from
00184      * the top-level node, plus possibly resjunk working columns (we can rely
00185      * on upper-level nodes to deal with that).
00186      */
00187     return recurse_set_operations((Node *) topop, root, tuple_fraction,
00188                                   topop->colTypes, topop->colCollations,
00189                                   true, -1,
00190                                   leftmostQuery->targetList,
00191                                   sortClauses, NULL);
00192 }
00193 
00194 /*
00195  * recurse_set_operations
00196  *    Recursively handle one step in a tree of set operations
00197  *
00198  * tuple_fraction: fraction of tuples we expect to retrieve from node
00199  * colTypes: OID list of set-op's result column datatypes
00200  * colCollations: OID list of set-op's result column collations
00201  * junkOK: if true, child resjunk columns may be left in the result
00202  * flag: if >= 0, add a resjunk output column indicating value of flag
00203  * refnames_tlist: targetlist to take column names from
00204  *
00205  * Returns a plan for the subtree, as well as these output parameters:
00206  * *sortClauses: receives list of SortGroupClauses for result plan, if any
00207  * *pNumGroups: if not NULL, we estimate the number of distinct groups
00208  *      in the result, and store it there
00209  *
00210  * We don't have to care about typmods here: the only allowed difference
00211  * between set-op input and output typmods is input is a specific typmod
00212  * and output is -1, and that does not require a coercion.
00213  */
00214 static Plan *
00215 recurse_set_operations(Node *setOp, PlannerInfo *root,
00216                        double tuple_fraction,
00217                        List *colTypes, List *colCollations,
00218                        bool junkOK,
00219                        int flag, List *refnames_tlist,
00220                        List **sortClauses, double *pNumGroups)
00221 {
00222     if (IsA(setOp, RangeTblRef))
00223     {
00224         RangeTblRef *rtr = (RangeTblRef *) setOp;
00225         RangeTblEntry *rte = root->simple_rte_array[rtr->rtindex];
00226         Query      *subquery = rte->subquery;
00227         RelOptInfo *rel;
00228         PlannerInfo *subroot;
00229         Plan       *subplan,
00230                    *plan;
00231 
00232         Assert(subquery != NULL);
00233 
00234         /*
00235          * We need to build a RelOptInfo for each leaf subquery.  This isn't
00236          * used for anything here, but it carries the subroot data structures
00237          * forward to setrefs.c processing.
00238          */
00239         rel = build_simple_rel(root, rtr->rtindex, RELOPT_BASEREL);
00240 
00241         /* plan_params should not be in use in current query level */
00242         Assert(root->plan_params == NIL);
00243 
00244         /*
00245          * Generate plan for primitive subquery
00246          */
00247         subplan = subquery_planner(root->glob, subquery,
00248                                    root,
00249                                    false, tuple_fraction,
00250                                    &subroot);
00251 
00252         /* Save subroot and subplan in RelOptInfo for setrefs.c */
00253         rel->subplan = subplan;
00254         rel->subroot = subroot;
00255 
00256         /*
00257          * It should not be possible for the primitive query to contain any
00258          * cross-references to other primitive queries in the setop tree.
00259          */
00260         if (root->plan_params)
00261             elog(ERROR, "unexpected outer reference in set operation subquery");
00262 
00263         /*
00264          * Estimate number of groups if caller wants it.  If the subquery used
00265          * grouping or aggregation, its output is probably mostly unique
00266          * anyway; otherwise do statistical estimation.
00267          */
00268         if (pNumGroups)
00269         {
00270             if (subquery->groupClause || subquery->distinctClause ||
00271                 subroot->hasHavingQual || subquery->hasAggs)
00272                 *pNumGroups = subplan->plan_rows;
00273             else
00274                 *pNumGroups = estimate_num_groups(subroot,
00275                                 get_tlist_exprs(subquery->targetList, false),
00276                                                   subplan->plan_rows);
00277         }
00278 
00279         /*
00280          * Add a SubqueryScan with the caller-requested targetlist
00281          */
00282         plan = (Plan *)
00283             make_subqueryscan(generate_setop_tlist(colTypes, colCollations,
00284                                                    flag,
00285                                                    rtr->rtindex,
00286                                                    true,
00287                                                    subplan->targetlist,
00288                                                    refnames_tlist),
00289                               NIL,
00290                               rtr->rtindex,
00291                               subplan);
00292 
00293         /*
00294          * We don't bother to determine the subquery's output ordering since
00295          * it won't be reflected in the set-op result anyhow.
00296          */
00297         *sortClauses = NIL;
00298 
00299         return plan;
00300     }
00301     else if (IsA(setOp, SetOperationStmt))
00302     {
00303         SetOperationStmt *op = (SetOperationStmt *) setOp;
00304         Plan       *plan;
00305 
00306         /* UNIONs are much different from INTERSECT/EXCEPT */
00307         if (op->op == SETOP_UNION)
00308             plan = generate_union_plan(op, root, tuple_fraction,
00309                                        refnames_tlist,
00310                                        sortClauses, pNumGroups);
00311         else
00312             plan = generate_nonunion_plan(op, root, tuple_fraction,
00313                                           refnames_tlist,
00314                                           sortClauses, pNumGroups);
00315 
00316         /*
00317          * If necessary, add a Result node to project the caller-requested
00318          * output columns.
00319          *
00320          * XXX you don't really want to know about this: setrefs.c will apply
00321          * fix_upper_expr() to the Result node's tlist. This would fail if the
00322          * Vars generated by generate_setop_tlist() were not exactly equal()
00323          * to the corresponding tlist entries of the subplan. However, since
00324          * the subplan was generated by generate_union_plan() or
00325          * generate_nonunion_plan(), and hence its tlist was generated by
00326          * generate_append_tlist(), this will work.  We just tell
00327          * generate_setop_tlist() to use varno 0.
00328          */
00329         if (flag >= 0 ||
00330             !tlist_same_datatypes(plan->targetlist, colTypes, junkOK) ||
00331             !tlist_same_collations(plan->targetlist, colCollations, junkOK))
00332         {
00333             plan = (Plan *)
00334                 make_result(root,
00335                             generate_setop_tlist(colTypes, colCollations,
00336                                                  flag,
00337                                                  0,
00338                                                  false,
00339                                                  plan->targetlist,
00340                                                  refnames_tlist),
00341                             NULL,
00342                             plan);
00343         }
00344         return plan;
00345     }
00346     else
00347     {
00348         elog(ERROR, "unrecognized node type: %d",
00349              (int) nodeTag(setOp));
00350         return NULL;            /* keep compiler quiet */
00351     }
00352 }
00353 
00354 /*
00355  * Generate plan for a recursive UNION node
00356  */
00357 static Plan *
00358 generate_recursion_plan(SetOperationStmt *setOp, PlannerInfo *root,
00359                         double tuple_fraction,
00360                         List *refnames_tlist,
00361                         List **sortClauses)
00362 {
00363     Plan       *plan;
00364     Plan       *lplan;
00365     Plan       *rplan;
00366     List       *tlist;
00367     List       *groupList;
00368     long        numGroups;
00369 
00370     /* Parser should have rejected other cases */
00371     if (setOp->op != SETOP_UNION)
00372         elog(ERROR, "only UNION queries can be recursive");
00373     /* Worktable ID should be assigned */
00374     Assert(root->wt_param_id >= 0);
00375 
00376     /*
00377      * Unlike a regular UNION node, process the left and right inputs
00378      * separately without any intention of combining them into one Append.
00379      */
00380     lplan = recurse_set_operations(setOp->larg, root, tuple_fraction,
00381                                    setOp->colTypes, setOp->colCollations,
00382                                    false, -1,
00383                                    refnames_tlist, sortClauses, NULL);
00384     /* The right plan will want to look at the left one ... */
00385     root->non_recursive_plan = lplan;
00386     rplan = recurse_set_operations(setOp->rarg, root, tuple_fraction,
00387                                    setOp->colTypes, setOp->colCollations,
00388                                    false, -1,
00389                                    refnames_tlist, sortClauses, NULL);
00390     root->non_recursive_plan = NULL;
00391 
00392     /*
00393      * Generate tlist for RecursiveUnion plan node --- same as in Append cases
00394      */
00395     tlist = generate_append_tlist(setOp->colTypes, setOp->colCollations, false,
00396                                   list_make2(lplan, rplan),
00397                                   refnames_tlist);
00398 
00399     /*
00400      * If UNION, identify the grouping operators
00401      */
00402     if (setOp->all)
00403     {
00404         groupList = NIL;
00405         numGroups = 0;
00406     }
00407     else
00408     {
00409         double      dNumGroups;
00410 
00411         /* Identify the grouping semantics */
00412         groupList = generate_setop_grouplist(setOp, tlist);
00413 
00414         /* We only support hashing here */
00415         if (!grouping_is_hashable(groupList))
00416             ereport(ERROR,
00417                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00418                      errmsg("could not implement recursive UNION"),
00419                      errdetail("All column datatypes must be hashable.")));
00420 
00421         /*
00422          * For the moment, take the number of distinct groups as equal to the
00423          * total input size, ie, the worst case.
00424          */
00425         dNumGroups = lplan->plan_rows + rplan->plan_rows * 10;
00426 
00427         /* Also convert to long int --- but 'ware overflow! */
00428         numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
00429     }
00430 
00431     /*
00432      * And make the plan node.
00433      */
00434     plan = (Plan *) make_recursive_union(tlist, lplan, rplan,
00435                                          root->wt_param_id,
00436                                          groupList, numGroups);
00437 
00438     *sortClauses = NIL;         /* RecursiveUnion result is always unsorted */
00439 
00440     return plan;
00441 }
00442 
00443 /*
00444  * Generate plan for a UNION or UNION ALL node
00445  */
00446 static Plan *
00447 generate_union_plan(SetOperationStmt *op, PlannerInfo *root,
00448                     double tuple_fraction,
00449                     List *refnames_tlist,
00450                     List **sortClauses, double *pNumGroups)
00451 {
00452     List       *planlist;
00453     List       *tlist;
00454     Plan       *plan;
00455 
00456     /*
00457      * If plain UNION, tell children to fetch all tuples.
00458      *
00459      * Note: in UNION ALL, we pass the top-level tuple_fraction unmodified to
00460      * each arm of the UNION ALL.  One could make a case for reducing the
00461      * tuple fraction for later arms (discounting by the expected size of the
00462      * earlier arms' results) but it seems not worth the trouble. The normal
00463      * case where tuple_fraction isn't already zero is a LIMIT at top level,
00464      * and passing it down as-is is usually enough to get the desired result
00465      * of preferring fast-start plans.
00466      */
00467     if (!op->all)
00468         tuple_fraction = 0.0;
00469 
00470     /*
00471      * If any of my children are identical UNION nodes (same op, all-flag, and
00472      * colTypes) then they can be merged into this node so that we generate
00473      * only one Append and unique-ification for the lot.  Recurse to find such
00474      * nodes and compute their children's plans.
00475      */
00476     planlist = list_concat(recurse_union_children(op->larg, root,
00477                                                   tuple_fraction,
00478                                                   op, refnames_tlist),
00479                            recurse_union_children(op->rarg, root,
00480                                                   tuple_fraction,
00481                                                   op, refnames_tlist));
00482 
00483     /*
00484      * Generate tlist for Append plan node.
00485      *
00486      * The tlist for an Append plan isn't important as far as the Append is
00487      * concerned, but we must make it look real anyway for the benefit of the
00488      * next plan level up.
00489      */
00490     tlist = generate_append_tlist(op->colTypes, op->colCollations, false,
00491                                   planlist, refnames_tlist);
00492 
00493     /*
00494      * Append the child results together.
00495      */
00496     plan = (Plan *) make_append(planlist, tlist);
00497 
00498     /*
00499      * For UNION ALL, we just need the Append plan.  For UNION, need to add
00500      * node(s) to remove duplicates.
00501      */
00502     if (op->all)
00503         *sortClauses = NIL;     /* result of UNION ALL is always unsorted */
00504     else
00505         plan = make_union_unique(op, plan, root, tuple_fraction, sortClauses);
00506 
00507     /*
00508      * Estimate number of groups if caller wants it.  For now we just assume
00509      * the output is unique --- this is certainly true for the UNION case, and
00510      * we want worst-case estimates anyway.
00511      */
00512     if (pNumGroups)
00513         *pNumGroups = plan->plan_rows;
00514 
00515     return plan;
00516 }
00517 
00518 /*
00519  * Generate plan for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node
00520  */
00521 static Plan *
00522 generate_nonunion_plan(SetOperationStmt *op, PlannerInfo *root,
00523                        double tuple_fraction,
00524                        List *refnames_tlist,
00525                        List **sortClauses, double *pNumGroups)
00526 {
00527     Plan       *lplan,
00528                *rplan,
00529                *plan;
00530     List       *tlist,
00531                *groupList,
00532                *planlist,
00533                *child_sortclauses;
00534     double      dLeftGroups,
00535                 dRightGroups,
00536                 dNumGroups,
00537                 dNumOutputRows;
00538     long        numGroups;
00539     bool        use_hash;
00540     SetOpCmd    cmd;
00541     int         firstFlag;
00542 
00543     /* Recurse on children, ensuring their outputs are marked */
00544     lplan = recurse_set_operations(op->larg, root,
00545                                    0.0 /* all tuples needed */ ,
00546                                    op->colTypes, op->colCollations,
00547                                    false, 0,
00548                                    refnames_tlist,
00549                                    &child_sortclauses, &dLeftGroups);
00550     rplan = recurse_set_operations(op->rarg, root,
00551                                    0.0 /* all tuples needed */ ,
00552                                    op->colTypes, op->colCollations,
00553                                    false, 1,
00554                                    refnames_tlist,
00555                                    &child_sortclauses, &dRightGroups);
00556 
00557     /*
00558      * For EXCEPT, we must put the left input first.  For INTERSECT, either
00559      * order should give the same results, and we prefer to put the smaller
00560      * input first in order to minimize the size of the hash table in the
00561      * hashing case.  "Smaller" means the one with the fewer groups.
00562      */
00563     if (op->op == SETOP_EXCEPT || dLeftGroups <= dRightGroups)
00564     {
00565         planlist = list_make2(lplan, rplan);
00566         firstFlag = 0;
00567     }
00568     else
00569     {
00570         planlist = list_make2(rplan, lplan);
00571         firstFlag = 1;
00572     }
00573 
00574     /*
00575      * Generate tlist for Append plan node.
00576      *
00577      * The tlist for an Append plan isn't important as far as the Append is
00578      * concerned, but we must make it look real anyway for the benefit of the
00579      * next plan level up.  In fact, it has to be real enough that the flag
00580      * column is shown as a variable not a constant, else setrefs.c will get
00581      * confused.
00582      */
00583     tlist = generate_append_tlist(op->colTypes, op->colCollations, true,
00584                                   planlist, refnames_tlist);
00585 
00586     /*
00587      * Append the child results together.
00588      */
00589     plan = (Plan *) make_append(planlist, tlist);
00590 
00591     /* Identify the grouping semantics */
00592     groupList = generate_setop_grouplist(op, tlist);
00593 
00594     /* punt if nothing to group on (can this happen?) */
00595     if (groupList == NIL)
00596     {
00597         *sortClauses = NIL;
00598         return plan;
00599     }
00600 
00601     /*
00602      * Estimate number of distinct groups that we'll need hashtable entries
00603      * for; this is the size of the left-hand input for EXCEPT, or the smaller
00604      * input for INTERSECT.  Also estimate the number of eventual output rows.
00605      * In non-ALL cases, we estimate each group produces one output row; in
00606      * ALL cases use the relevant relation size.  These are worst-case
00607      * estimates, of course, but we need to be conservative.
00608      */
00609     if (op->op == SETOP_EXCEPT)
00610     {
00611         dNumGroups = dLeftGroups;
00612         dNumOutputRows = op->all ? lplan->plan_rows : dNumGroups;
00613     }
00614     else
00615     {
00616         dNumGroups = Min(dLeftGroups, dRightGroups);
00617         dNumOutputRows = op->all ? Min(lplan->plan_rows, rplan->plan_rows) : dNumGroups;
00618     }
00619 
00620     /* Also convert to long int --- but 'ware overflow! */
00621     numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
00622 
00623     /*
00624      * Decide whether to hash or sort, and add a sort node if needed.
00625      */
00626     use_hash = choose_hashed_setop(root, groupList, plan,
00627                                    dNumGroups, dNumOutputRows, tuple_fraction,
00628                        (op->op == SETOP_INTERSECT) ? "INTERSECT" : "EXCEPT");
00629 
00630     if (!use_hash)
00631         plan = (Plan *) make_sort_from_sortclauses(root, groupList, plan);
00632 
00633     /*
00634      * Finally, add a SetOp plan node to generate the correct output.
00635      */
00636     switch (op->op)
00637     {
00638         case SETOP_INTERSECT:
00639             cmd = op->all ? SETOPCMD_INTERSECT_ALL : SETOPCMD_INTERSECT;
00640             break;
00641         case SETOP_EXCEPT:
00642             cmd = op->all ? SETOPCMD_EXCEPT_ALL : SETOPCMD_EXCEPT;
00643             break;
00644         default:
00645             elog(ERROR, "unrecognized set op: %d", (int) op->op);
00646             cmd = SETOPCMD_INTERSECT;   /* keep compiler quiet */
00647             break;
00648     }
00649     plan = (Plan *) make_setop(cmd, use_hash ? SETOP_HASHED : SETOP_SORTED,
00650                                plan, groupList,
00651                                list_length(op->colTypes) + 1,
00652                                use_hash ? firstFlag : -1,
00653                                numGroups, dNumOutputRows);
00654 
00655     /* Result is sorted only if we're not hashing */
00656     *sortClauses = use_hash ? NIL : groupList;
00657 
00658     if (pNumGroups)
00659         *pNumGroups = dNumGroups;
00660 
00661     return plan;
00662 }
00663 
00664 /*
00665  * Pull up children of a UNION node that are identically-propertied UNIONs.
00666  *
00667  * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
00668  * output rows will be lost anyway.
00669  *
00670  * NOTE: currently, we ignore collations while determining if a child has
00671  * the same properties.  This is semantically sound only so long as all
00672  * collations have the same notion of equality.  It is valid from an
00673  * implementation standpoint because we don't care about the ordering of
00674  * a UNION child's result: UNION ALL results are always unordered, and
00675  * generate_union_plan will force a fresh sort if the top level is a UNION.
00676  */
00677 static List *
00678 recurse_union_children(Node *setOp, PlannerInfo *root,
00679                        double tuple_fraction,
00680                        SetOperationStmt *top_union,
00681                        List *refnames_tlist)
00682 {
00683     List       *child_sortclauses;
00684 
00685     if (IsA(setOp, SetOperationStmt))
00686     {
00687         SetOperationStmt *op = (SetOperationStmt *) setOp;
00688 
00689         if (op->op == top_union->op &&
00690             (op->all == top_union->all || op->all) &&
00691             equal(op->colTypes, top_union->colTypes))
00692         {
00693             /* Same UNION, so fold children into parent's subplan list */
00694             return list_concat(recurse_union_children(op->larg, root,
00695                                                       tuple_fraction,
00696                                                       top_union,
00697                                                       refnames_tlist),
00698                                recurse_union_children(op->rarg, root,
00699                                                       tuple_fraction,
00700                                                       top_union,
00701                                                       refnames_tlist));
00702         }
00703     }
00704 
00705     /*
00706      * Not same, so plan this child separately.
00707      *
00708      * Note we disallow any resjunk columns in child results.  This is
00709      * necessary since the Append node that implements the union won't do any
00710      * projection, and upper levels will get confused if some of our output
00711      * tuples have junk and some don't.  This case only arises when we have an
00712      * EXCEPT or INTERSECT as child, else there won't be resjunk anyway.
00713      */
00714     return list_make1(recurse_set_operations(setOp, root,
00715                                              tuple_fraction,
00716                                              top_union->colTypes,
00717                                              top_union->colCollations,
00718                                              false, -1,
00719                                              refnames_tlist,
00720                                              &child_sortclauses, NULL));
00721 }
00722 
00723 /*
00724  * Add nodes to the given plan tree to unique-ify the result of a UNION.
00725  */
00726 static Plan *
00727 make_union_unique(SetOperationStmt *op, Plan *plan,
00728                   PlannerInfo *root, double tuple_fraction,
00729                   List **sortClauses)
00730 {
00731     List       *groupList;
00732     double      dNumGroups;
00733     long        numGroups;
00734 
00735     /* Identify the grouping semantics */
00736     groupList = generate_setop_grouplist(op, plan->targetlist);
00737 
00738     /* punt if nothing to group on (can this happen?) */
00739     if (groupList == NIL)
00740     {
00741         *sortClauses = NIL;
00742         return plan;
00743     }
00744 
00745     /*
00746      * XXX for the moment, take the number of distinct groups as equal to the
00747      * total input size, ie, the worst case.  This is too conservative, but we
00748      * don't want to risk having the hashtable overrun memory; also, it's not
00749      * clear how to get a decent estimate of the true size.  One should note
00750      * as well the propensity of novices to write UNION rather than UNION ALL
00751      * even when they don't expect any duplicates...
00752      */
00753     dNumGroups = plan->plan_rows;
00754 
00755     /* Also convert to long int --- but 'ware overflow! */
00756     numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
00757 
00758     /* Decide whether to hash or sort */
00759     if (choose_hashed_setop(root, groupList, plan,
00760                             dNumGroups, dNumGroups, tuple_fraction,
00761                             "UNION"))
00762     {
00763         /* Hashed aggregate plan --- no sort needed */
00764         plan = (Plan *) make_agg(root,
00765                                  plan->targetlist,
00766                                  NIL,
00767                                  AGG_HASHED,
00768                                  NULL,
00769                                  list_length(groupList),
00770                                  extract_grouping_cols(groupList,
00771                                                        plan->targetlist),
00772                                  extract_grouping_ops(groupList),
00773                                  numGroups,
00774                                  plan);
00775         /* Hashed aggregation produces randomly-ordered results */
00776         *sortClauses = NIL;
00777     }
00778     else
00779     {
00780         /* Sort and Unique */
00781         plan = (Plan *) make_sort_from_sortclauses(root, groupList, plan);
00782         plan = (Plan *) make_unique(plan, groupList);
00783         plan->plan_rows = dNumGroups;
00784         /* We know the sort order of the result */
00785         *sortClauses = groupList;
00786     }
00787 
00788     return plan;
00789 }
00790 
00791 /*
00792  * choose_hashed_setop - should we use hashing for a set operation?
00793  */
00794 static bool
00795 choose_hashed_setop(PlannerInfo *root, List *groupClauses,
00796                     Plan *input_plan,
00797                     double dNumGroups, double dNumOutputRows,
00798                     double tuple_fraction,
00799                     const char *construct)
00800 {
00801     int         numGroupCols = list_length(groupClauses);
00802     bool        can_sort;
00803     bool        can_hash;
00804     Size        hashentrysize;
00805     Path        hashed_p;
00806     Path        sorted_p;
00807 
00808     /* Check whether the operators support sorting or hashing */
00809     can_sort = grouping_is_sortable(groupClauses);
00810     can_hash = grouping_is_hashable(groupClauses);
00811     if (can_hash && can_sort)
00812     {
00813         /* we have a meaningful choice to make, continue ... */
00814     }
00815     else if (can_hash)
00816         return true;
00817     else if (can_sort)
00818         return false;
00819     else
00820         ereport(ERROR,
00821                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00822         /* translator: %s is UNION, INTERSECT, or EXCEPT */
00823                  errmsg("could not implement %s", construct),
00824                  errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
00825 
00826     /* Prefer sorting when enable_hashagg is off */
00827     if (!enable_hashagg)
00828         return false;
00829 
00830     /*
00831      * Don't do it if it doesn't look like the hashtable will fit into
00832      * work_mem.
00833      */
00834     hashentrysize = MAXALIGN(input_plan->plan_width) + MAXALIGN(sizeof(MinimalTupleData));
00835 
00836     if (hashentrysize * dNumGroups > work_mem * 1024L)
00837         return false;
00838 
00839     /*
00840      * See if the estimated cost is no more than doing it the other way.
00841      *
00842      * We need to consider input_plan + hashagg versus input_plan + sort +
00843      * group.  Note that the actual result plan might involve a SetOp or
00844      * Unique node, not Agg or Group, but the cost estimates for Agg and Group
00845      * should be close enough for our purposes here.
00846      *
00847      * These path variables are dummies that just hold cost fields; we don't
00848      * make actual Paths for these steps.
00849      */
00850     cost_agg(&hashed_p, root, AGG_HASHED, NULL,
00851              numGroupCols, dNumGroups,
00852              input_plan->startup_cost, input_plan->total_cost,
00853              input_plan->plan_rows);
00854 
00855     /*
00856      * Now for the sorted case.  Note that the input is *always* unsorted,
00857      * since it was made by appending unrelated sub-relations together.
00858      */
00859     sorted_p.startup_cost = input_plan->startup_cost;
00860     sorted_p.total_cost = input_plan->total_cost;
00861     /* XXX cost_sort doesn't actually look at pathkeys, so just pass NIL */
00862     cost_sort(&sorted_p, root, NIL, sorted_p.total_cost,
00863               input_plan->plan_rows, input_plan->plan_width,
00864               0.0, work_mem, -1.0);
00865     cost_group(&sorted_p, root, numGroupCols, dNumGroups,
00866                sorted_p.startup_cost, sorted_p.total_cost,
00867                input_plan->plan_rows);
00868 
00869     /*
00870      * Now make the decision using the top-level tuple fraction.  First we
00871      * have to convert an absolute count (LIMIT) into fractional form.
00872      */
00873     if (tuple_fraction >= 1.0)
00874         tuple_fraction /= dNumOutputRows;
00875 
00876     if (compare_fractional_path_costs(&hashed_p, &sorted_p,
00877                                       tuple_fraction) < 0)
00878     {
00879         /* Hashed is cheaper, so use it */
00880         return true;
00881     }
00882     return false;
00883 }
00884 
00885 /*
00886  * Generate targetlist for a set-operation plan node
00887  *
00888  * colTypes: OID list of set-op's result column datatypes
00889  * colCollations: OID list of set-op's result column collations
00890  * flag: -1 if no flag column needed, 0 or 1 to create a const flag column
00891  * varno: varno to use in generated Vars
00892  * hack_constants: true to copy up constants (see comments in code)
00893  * input_tlist: targetlist of this node's input node
00894  * refnames_tlist: targetlist to take column names from
00895  */
00896 static List *
00897 generate_setop_tlist(List *colTypes, List *colCollations,
00898                      int flag,
00899                      Index varno,
00900                      bool hack_constants,
00901                      List *input_tlist,
00902                      List *refnames_tlist)
00903 {
00904     List       *tlist = NIL;
00905     int         resno = 1;
00906     ListCell   *ctlc,
00907                *cclc,
00908                *itlc,
00909                *rtlc;
00910     TargetEntry *tle;
00911     Node       *expr;
00912 
00913     /* there's no forfour() so we must chase one list manually */
00914     rtlc = list_head(refnames_tlist);
00915     forthree(ctlc, colTypes, cclc, colCollations, itlc, input_tlist)
00916     {
00917         Oid         colType = lfirst_oid(ctlc);
00918         Oid         colColl = lfirst_oid(cclc);
00919         TargetEntry *inputtle = (TargetEntry *) lfirst(itlc);
00920         TargetEntry *reftle = (TargetEntry *) lfirst(rtlc);
00921 
00922         rtlc = lnext(rtlc);
00923 
00924         Assert(inputtle->resno == resno);
00925         Assert(reftle->resno == resno);
00926         Assert(!inputtle->resjunk);
00927         Assert(!reftle->resjunk);
00928 
00929         /*
00930          * Generate columns referencing input columns and having appropriate
00931          * data types and column names.  Insert datatype coercions where
00932          * necessary.
00933          *
00934          * HACK: constants in the input's targetlist are copied up as-is
00935          * rather than being referenced as subquery outputs.  This is mainly
00936          * to ensure that when we try to coerce them to the output column's
00937          * datatype, the right things happen for UNKNOWN constants.  But do
00938          * this only at the first level of subquery-scan plans; we don't want
00939          * phony constants appearing in the output tlists of upper-level
00940          * nodes!
00941          */
00942         if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
00943             expr = (Node *) inputtle->expr;
00944         else
00945             expr = (Node *) makeVar(varno,
00946                                     inputtle->resno,
00947                                     exprType((Node *) inputtle->expr),
00948                                     exprTypmod((Node *) inputtle->expr),
00949                                     exprCollation((Node *) inputtle->expr),
00950                                     0);
00951 
00952         if (exprType(expr) != colType)
00953         {
00954             /*
00955              * Note: it's not really cool to be applying coerce_to_common_type
00956              * here; one notable point is that assign_expr_collations never
00957              * gets run on any generated nodes.  For the moment that's not a
00958              * problem because we force the correct exposed collation below.
00959              * It would likely be best to make the parser generate the correct
00960              * output tlist for every set-op to begin with, though.
00961              */
00962             expr = coerce_to_common_type(NULL,  /* no UNKNOWNs here */
00963                                          expr,
00964                                          colType,
00965                                          "UNION/INTERSECT/EXCEPT");
00966         }
00967 
00968         /*
00969          * Ensure the tlist entry's exposed collation matches the set-op. This
00970          * is necessary because plan_set_operations() reports the result
00971          * ordering as a list of SortGroupClauses, which don't carry collation
00972          * themselves but just refer to tlist entries.  If we don't show the
00973          * right collation then planner.c might do the wrong thing in
00974          * higher-level queries.
00975          *
00976          * Note we use RelabelType, not CollateExpr, since this expression
00977          * will reach the executor without any further processing.
00978          */
00979         if (exprCollation(expr) != colColl)
00980         {
00981             expr = (Node *) makeRelabelType((Expr *) expr,
00982                                             exprType(expr),
00983                                             exprTypmod(expr),
00984                                             colColl,
00985                                             COERCE_IMPLICIT_CAST);
00986         }
00987 
00988         tle = makeTargetEntry((Expr *) expr,
00989                               (AttrNumber) resno++,
00990                               pstrdup(reftle->resname),
00991                               false);
00992         tlist = lappend(tlist, tle);
00993     }
00994 
00995     if (flag >= 0)
00996     {
00997         /* Add a resjunk flag column */
00998         /* flag value is the given constant */
00999         expr = (Node *) makeConst(INT4OID,
01000                                   -1,
01001                                   InvalidOid,
01002                                   sizeof(int32),
01003                                   Int32GetDatum(flag),
01004                                   false,
01005                                   true);
01006         tle = makeTargetEntry((Expr *) expr,
01007                               (AttrNumber) resno++,
01008                               pstrdup("flag"),
01009                               true);
01010         tlist = lappend(tlist, tle);
01011     }
01012 
01013     return tlist;
01014 }
01015 
01016 /*
01017  * Generate targetlist for a set-operation Append node
01018  *
01019  * colTypes: OID list of set-op's result column datatypes
01020  * colCollations: OID list of set-op's result column collations
01021  * flag: true to create a flag column copied up from subplans
01022  * input_plans: list of sub-plans of the Append
01023  * refnames_tlist: targetlist to take column names from
01024  *
01025  * The entries in the Append's targetlist should always be simple Vars;
01026  * we just have to make sure they have the right datatypes/typmods/collations.
01027  * The Vars are always generated with varno 0.
01028  */
01029 static List *
01030 generate_append_tlist(List *colTypes, List *colCollations,
01031                       bool flag,
01032                       List *input_plans,
01033                       List *refnames_tlist)
01034 {
01035     List       *tlist = NIL;
01036     int         resno = 1;
01037     ListCell   *curColType;
01038     ListCell   *curColCollation;
01039     ListCell   *ref_tl_item;
01040     int         colindex;
01041     TargetEntry *tle;
01042     Node       *expr;
01043     ListCell   *planl;
01044     int32      *colTypmods;
01045 
01046     /*
01047      * First extract typmods to use.
01048      *
01049      * If the inputs all agree on type and typmod of a particular column, use
01050      * that typmod; else use -1.
01051      */
01052     colTypmods = (int32 *) palloc(list_length(colTypes) * sizeof(int32));
01053 
01054     foreach(planl, input_plans)
01055     {
01056         Plan       *subplan = (Plan *) lfirst(planl);
01057         ListCell   *subtlist;
01058 
01059         curColType = list_head(colTypes);
01060         colindex = 0;
01061         foreach(subtlist, subplan->targetlist)
01062         {
01063             TargetEntry *subtle = (TargetEntry *) lfirst(subtlist);
01064 
01065             if (subtle->resjunk)
01066                 continue;
01067             Assert(curColType != NULL);
01068             if (exprType((Node *) subtle->expr) == lfirst_oid(curColType))
01069             {
01070                 /* If first subplan, copy the typmod; else compare */
01071                 int32       subtypmod = exprTypmod((Node *) subtle->expr);
01072 
01073                 if (planl == list_head(input_plans))
01074                     colTypmods[colindex] = subtypmod;
01075                 else if (subtypmod != colTypmods[colindex])
01076                     colTypmods[colindex] = -1;
01077             }
01078             else
01079             {
01080                 /* types disagree, so force typmod to -1 */
01081                 colTypmods[colindex] = -1;
01082             }
01083             curColType = lnext(curColType);
01084             colindex++;
01085         }
01086         Assert(curColType == NULL);
01087     }
01088 
01089     /*
01090      * Now we can build the tlist for the Append.
01091      */
01092     colindex = 0;
01093     forthree(curColType, colTypes, curColCollation, colCollations,
01094              ref_tl_item, refnames_tlist)
01095     {
01096         Oid         colType = lfirst_oid(curColType);
01097         int32       colTypmod = colTypmods[colindex++];
01098         Oid         colColl = lfirst_oid(curColCollation);
01099         TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item);
01100 
01101         Assert(reftle->resno == resno);
01102         Assert(!reftle->resjunk);
01103         expr = (Node *) makeVar(0,
01104                                 resno,
01105                                 colType,
01106                                 colTypmod,
01107                                 colColl,
01108                                 0);
01109         tle = makeTargetEntry((Expr *) expr,
01110                               (AttrNumber) resno++,
01111                               pstrdup(reftle->resname),
01112                               false);
01113         tlist = lappend(tlist, tle);
01114     }
01115 
01116     if (flag)
01117     {
01118         /* Add a resjunk flag column */
01119         /* flag value is shown as copied up from subplan */
01120         expr = (Node *) makeVar(0,
01121                                 resno,
01122                                 INT4OID,
01123                                 -1,
01124                                 InvalidOid,
01125                                 0);
01126         tle = makeTargetEntry((Expr *) expr,
01127                               (AttrNumber) resno++,
01128                               pstrdup("flag"),
01129                               true);
01130         tlist = lappend(tlist, tle);
01131     }
01132 
01133     pfree(colTypmods);
01134 
01135     return tlist;
01136 }
01137 
01138 /*
01139  * generate_setop_grouplist
01140  *      Build a SortGroupClause list defining the sort/grouping properties
01141  *      of the setop's output columns.
01142  *
01143  * Parse analysis already determined the properties and built a suitable
01144  * list, except that the entries do not have sortgrouprefs set because
01145  * the parser output representation doesn't include a tlist for each
01146  * setop.  So what we need to do here is copy that list and install
01147  * proper sortgrouprefs into it and into the targetlist.
01148  */
01149 static List *
01150 generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
01151 {
01152     List       *grouplist = (List *) copyObject(op->groupClauses);
01153     ListCell   *lg;
01154     ListCell   *lt;
01155     Index       refno = 1;
01156 
01157     lg = list_head(grouplist);
01158     foreach(lt, targetlist)
01159     {
01160         TargetEntry *tle = (TargetEntry *) lfirst(lt);
01161         SortGroupClause *sgc;
01162 
01163         /* tlist shouldn't have any sortgrouprefs yet */
01164         Assert(tle->ressortgroupref == 0);
01165 
01166         if (tle->resjunk)
01167             continue;           /* ignore resjunk columns */
01168 
01169         /* non-resjunk columns should have grouping clauses */
01170         Assert(lg != NULL);
01171         sgc = (SortGroupClause *) lfirst(lg);
01172         lg = lnext(lg);
01173         Assert(sgc->tleSortGroupRef == 0);
01174 
01175         /* we could use assignSortGroupRef here, but seems a bit silly */
01176         sgc->tleSortGroupRef = tle->ressortgroupref = refno++;
01177     }
01178     Assert(lg == NULL);
01179     return grouplist;
01180 }
01181 
01182 
01183 /*
01184  * expand_inherited_tables
01185  *      Expand each rangetable entry that represents an inheritance set
01186  *      into an "append relation".  At the conclusion of this process,
01187  *      the "inh" flag is set in all and only those RTEs that are append
01188  *      relation parents.
01189  */
01190 void
01191 expand_inherited_tables(PlannerInfo *root)
01192 {
01193     Index       nrtes;
01194     Index       rti;
01195     ListCell   *rl;
01196 
01197     /*
01198      * expand_inherited_rtentry may add RTEs to parse->rtable; there is no
01199      * need to scan them since they can't have inh=true.  So just scan as far
01200      * as the original end of the rtable list.
01201      */
01202     nrtes = list_length(root->parse->rtable);
01203     rl = list_head(root->parse->rtable);
01204     for (rti = 1; rti <= nrtes; rti++)
01205     {
01206         RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);
01207 
01208         expand_inherited_rtentry(root, rte, rti);
01209         rl = lnext(rl);
01210     }
01211 }
01212 
01213 /*
01214  * expand_inherited_rtentry
01215  *      Check whether a rangetable entry represents an inheritance set.
01216  *      If so, add entries for all the child tables to the query's
01217  *      rangetable, and build AppendRelInfo nodes for all the child tables
01218  *      and add them to root->append_rel_list.  If not, clear the entry's
01219  *      "inh" flag to prevent later code from looking for AppendRelInfos.
01220  *
01221  * Note that the original RTE is considered to represent the whole
01222  * inheritance set.  The first of the generated RTEs is an RTE for the same
01223  * table, but with inh = false, to represent the parent table in its role
01224  * as a simple member of the inheritance set.
01225  *
01226  * A childless table is never considered to be an inheritance set; therefore
01227  * a parent RTE must always have at least two associated AppendRelInfos.
01228  */
01229 static void
01230 expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
01231 {
01232     Query      *parse = root->parse;
01233     Oid         parentOID;
01234     PlanRowMark *oldrc;
01235     Relation    oldrelation;
01236     LOCKMODE    lockmode;
01237     List       *inhOIDs;
01238     List       *appinfos;
01239     ListCell   *l;
01240 
01241     /* Does RT entry allow inheritance? */
01242     if (!rte->inh)
01243         return;
01244     /* Ignore any already-expanded UNION ALL nodes */
01245     if (rte->rtekind != RTE_RELATION)
01246     {
01247         Assert(rte->rtekind == RTE_SUBQUERY);
01248         return;
01249     }
01250     /* Fast path for common case of childless table */
01251     parentOID = rte->relid;
01252     if (!has_subclass(parentOID))
01253     {
01254         /* Clear flag before returning */
01255         rte->inh = false;
01256         return;
01257     }
01258 
01259     /*
01260      * The rewriter should already have obtained an appropriate lock on each
01261      * relation named in the query.  However, for each child relation we add
01262      * to the query, we must obtain an appropriate lock, because this will be
01263      * the first use of those relations in the parse/rewrite/plan pipeline.
01264      *
01265      * If the parent relation is the query's result relation, then we need
01266      * RowExclusiveLock.  Otherwise, if it's accessed FOR UPDATE/SHARE, we
01267      * need RowShareLock; otherwise AccessShareLock.  We can't just grab
01268      * AccessShareLock because then the executor would be trying to upgrade
01269      * the lock, leading to possible deadlocks.  (This code should match the
01270      * parser and rewriter.)
01271      */
01272     oldrc = get_plan_rowmark(root->rowMarks, rti);
01273     if (rti == parse->resultRelation)
01274         lockmode = RowExclusiveLock;
01275     else if (oldrc && RowMarkRequiresRowShareLock(oldrc->markType))
01276         lockmode = RowShareLock;
01277     else
01278         lockmode = AccessShareLock;
01279 
01280     /* Scan for all members of inheritance set, acquire needed locks */
01281     inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
01282 
01283     /*
01284      * Check that there's at least one descendant, else treat as no-child
01285      * case.  This could happen despite above has_subclass() check, if table
01286      * once had a child but no longer does.
01287      */
01288     if (list_length(inhOIDs) < 2)
01289     {
01290         /* Clear flag before returning */
01291         rte->inh = false;
01292         return;
01293     }
01294 
01295     /*
01296      * If parent relation is selected FOR UPDATE/SHARE, we need to mark its
01297      * PlanRowMark as isParent = true, and generate a new PlanRowMark for each
01298      * child.
01299      */
01300     if (oldrc)
01301         oldrc->isParent = true;
01302 
01303     /*
01304      * Must open the parent relation to examine its tupdesc.  We need not lock
01305      * it; we assume the rewriter already did.
01306      */
01307     oldrelation = heap_open(parentOID, NoLock);
01308 
01309     /* Scan the inheritance set and expand it */
01310     appinfos = NIL;
01311     foreach(l, inhOIDs)
01312     {
01313         Oid         childOID = lfirst_oid(l);
01314         Relation    newrelation;
01315         RangeTblEntry *childrte;
01316         Index       childRTindex;
01317         AppendRelInfo *appinfo;
01318 
01319         /* Open rel if needed; we already have required locks */
01320         if (childOID != parentOID)
01321             newrelation = heap_open(childOID, NoLock);
01322         else
01323             newrelation = oldrelation;
01324 
01325         /*
01326          * It is possible that the parent table has children that are temp
01327          * tables of other backends.  We cannot safely access such tables
01328          * (because of buffering issues), and the best thing to do seems to be
01329          * to silently ignore them.
01330          */
01331         if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
01332         {
01333             heap_close(newrelation, lockmode);
01334             continue;
01335         }
01336 
01337         /*
01338          * Build an RTE for the child, and attach to query's rangetable list.
01339          * We copy most fields of the parent's RTE, but replace relation OID,
01340          * and set inh = false.  Also, set requiredPerms to zero since all
01341          * required permissions checks are done on the original RTE.
01342          */
01343         childrte = copyObject(rte);
01344         childrte->relid = childOID;
01345         childrte->inh = false;
01346         childrte->requiredPerms = 0;
01347         parse->rtable = lappend(parse->rtable, childrte);
01348         childRTindex = list_length(parse->rtable);
01349 
01350         /*
01351          * Build an AppendRelInfo for this parent and child.
01352          */
01353         appinfo = makeNode(AppendRelInfo);
01354         appinfo->parent_relid = rti;
01355         appinfo->child_relid = childRTindex;
01356         appinfo->parent_reltype = oldrelation->rd_rel->reltype;
01357         appinfo->child_reltype = newrelation->rd_rel->reltype;
01358         make_inh_translation_list(oldrelation, newrelation, childRTindex,
01359                                   &appinfo->translated_vars);
01360         appinfo->parent_reloid = parentOID;
01361         appinfos = lappend(appinfos, appinfo);
01362 
01363         /*
01364          * Translate the column permissions bitmaps to the child's attnums (we
01365          * have to build the translated_vars list before we can do this). But
01366          * if this is the parent table, leave copyObject's result alone.
01367          *
01368          * Note: we need to do this even though the executor won't run any
01369          * permissions checks on the child RTE.  The modifiedCols bitmap may
01370          * be examined for trigger-firing purposes.
01371          */
01372         if (childOID != parentOID)
01373         {
01374             childrte->selectedCols = translate_col_privs(rte->selectedCols,
01375                                                    appinfo->translated_vars);
01376             childrte->modifiedCols = translate_col_privs(rte->modifiedCols,
01377                                                    appinfo->translated_vars);
01378         }
01379 
01380         /*
01381          * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
01382          */
01383         if (oldrc)
01384         {
01385             PlanRowMark *newrc = makeNode(PlanRowMark);
01386 
01387             newrc->rti = childRTindex;
01388             newrc->prti = rti;
01389             newrc->rowmarkId = oldrc->rowmarkId;
01390             newrc->markType = oldrc->markType;
01391             newrc->noWait = oldrc->noWait;
01392             newrc->isParent = false;
01393 
01394             root->rowMarks = lappend(root->rowMarks, newrc);
01395         }
01396 
01397         /* Close child relations, but keep locks */
01398         if (childOID != parentOID)
01399             heap_close(newrelation, NoLock);
01400     }
01401 
01402     heap_close(oldrelation, NoLock);
01403 
01404     /*
01405      * If all the children were temp tables, pretend it's a non-inheritance
01406      * situation.  The duplicate RTE we added for the parent table is
01407      * harmless, so we don't bother to get rid of it.
01408      */
01409     if (list_length(appinfos) < 2)
01410     {
01411         /* Clear flag before returning */
01412         rte->inh = false;
01413         return;
01414     }
01415 
01416     /* Otherwise, OK to add to root->append_rel_list */
01417     root->append_rel_list = list_concat(root->append_rel_list, appinfos);
01418 }
01419 
01420 /*
01421  * make_inh_translation_list
01422  *    Build the list of translations from parent Vars to child Vars for
01423  *    an inheritance child.
01424  *
01425  * For paranoia's sake, we match type/collation as well as attribute name.
01426  */
01427 static void
01428 make_inh_translation_list(Relation oldrelation, Relation newrelation,
01429                           Index newvarno,
01430                           List **translated_vars)
01431 {
01432     List       *vars = NIL;
01433     TupleDesc   old_tupdesc = RelationGetDescr(oldrelation);
01434     TupleDesc   new_tupdesc = RelationGetDescr(newrelation);
01435     int         oldnatts = old_tupdesc->natts;
01436     int         newnatts = new_tupdesc->natts;
01437     int         old_attno;
01438 
01439     for (old_attno = 0; old_attno < oldnatts; old_attno++)
01440     {
01441         Form_pg_attribute att;
01442         char       *attname;
01443         Oid         atttypid;
01444         int32       atttypmod;
01445         Oid         attcollation;
01446         int         new_attno;
01447 
01448         att = old_tupdesc->attrs[old_attno];
01449         if (att->attisdropped)
01450         {
01451             /* Just put NULL into this list entry */
01452             vars = lappend(vars, NULL);
01453             continue;
01454         }
01455         attname = NameStr(att->attname);
01456         atttypid = att->atttypid;
01457         atttypmod = att->atttypmod;
01458         attcollation = att->attcollation;
01459 
01460         /*
01461          * When we are generating the "translation list" for the parent table
01462          * of an inheritance set, no need to search for matches.
01463          */
01464         if (oldrelation == newrelation)
01465         {
01466             vars = lappend(vars, makeVar(newvarno,
01467                                          (AttrNumber) (old_attno + 1),
01468                                          atttypid,
01469                                          atttypmod,
01470                                          attcollation,
01471                                          0));
01472             continue;
01473         }
01474 
01475         /*
01476          * Otherwise we have to search for the matching column by name.
01477          * There's no guarantee it'll have the same column position, because
01478          * of cases like ALTER TABLE ADD COLUMN and multiple inheritance.
01479          * However, in simple cases it will be the same column number, so try
01480          * that before we go groveling through all the columns.
01481          *
01482          * Note: the test for (att = ...) != NULL cannot fail, it's just a
01483          * notational device to include the assignment into the if-clause.
01484          */
01485         if (old_attno < newnatts &&
01486             (att = new_tupdesc->attrs[old_attno]) != NULL &&
01487             !att->attisdropped && att->attinhcount != 0 &&
01488             strcmp(attname, NameStr(att->attname)) == 0)
01489             new_attno = old_attno;
01490         else
01491         {
01492             for (new_attno = 0; new_attno < newnatts; new_attno++)
01493             {
01494                 att = new_tupdesc->attrs[new_attno];
01495                 if (!att->attisdropped && att->attinhcount != 0 &&
01496                     strcmp(attname, NameStr(att->attname)) == 0)
01497                     break;
01498             }
01499             if (new_attno >= newnatts)
01500                 elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
01501                      attname, RelationGetRelationName(newrelation));
01502         }
01503 
01504         /* Found it, check type and collation match */
01505         if (atttypid != att->atttypid || atttypmod != att->atttypmod)
01506             elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type",
01507                  attname, RelationGetRelationName(newrelation));
01508         if (attcollation != att->attcollation)
01509             elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's collation",
01510                  attname, RelationGetRelationName(newrelation));
01511 
01512         vars = lappend(vars, makeVar(newvarno,
01513                                      (AttrNumber) (new_attno + 1),
01514                                      atttypid,
01515                                      atttypmod,
01516                                      attcollation,
01517                                      0));
01518     }
01519 
01520     *translated_vars = vars;
01521 }
01522 
01523 /*
01524  * translate_col_privs
01525  *    Translate a bitmapset representing per-column privileges from the
01526  *    parent rel's attribute numbering to the child's.
01527  *
01528  * The only surprise here is that we don't translate a parent whole-row
01529  * reference into a child whole-row reference.  That would mean requiring
01530  * permissions on all child columns, which is overly strict, since the
01531  * query is really only going to reference the inherited columns.  Instead
01532  * we set the per-column bits for all inherited columns.
01533  */
01534 static Bitmapset *
01535 translate_col_privs(const Bitmapset *parent_privs,
01536                     List *translated_vars)
01537 {
01538     Bitmapset  *child_privs = NULL;
01539     bool        whole_row;
01540     int         attno;
01541     ListCell   *lc;
01542 
01543     /* System attributes have the same numbers in all tables */
01544     for (attno = FirstLowInvalidHeapAttributeNumber + 1; attno < 0; attno++)
01545     {
01546         if (bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
01547                           parent_privs))
01548             child_privs = bms_add_member(child_privs,
01549                                  attno - FirstLowInvalidHeapAttributeNumber);
01550     }
01551 
01552     /* Check if parent has whole-row reference */
01553     whole_row = bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber,
01554                               parent_privs);
01555 
01556     /* And now translate the regular user attributes, using the vars list */
01557     attno = InvalidAttrNumber;
01558     foreach(lc, translated_vars)
01559     {
01560         Var        *var = (Var *) lfirst(lc);
01561 
01562         attno++;
01563         if (var == NULL)        /* ignore dropped columns */
01564             continue;
01565         Assert(IsA(var, Var));
01566         if (whole_row ||
01567             bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
01568                           parent_privs))
01569             child_privs = bms_add_member(child_privs,
01570                          var->varattno - FirstLowInvalidHeapAttributeNumber);
01571     }
01572 
01573     return child_privs;
01574 }
01575 
01576 /*
01577  * adjust_appendrel_attrs
01578  *    Copy the specified query or expression and translate Vars referring
01579  *    to the parent rel of the specified AppendRelInfo to refer to the
01580  *    child rel instead.  We also update rtindexes appearing outside Vars,
01581  *    such as resultRelation and jointree relids.
01582  *
01583  * Note: this is only applied after conversion of sublinks to subplans,
01584  * so we don't need to cope with recursion into sub-queries.
01585  *
01586  * Note: this is not hugely different from what pullup_replace_vars() does;
01587  * maybe we should try to fold the two routines together.
01588  */
01589 Node *
01590 adjust_appendrel_attrs(PlannerInfo *root, Node *node, AppendRelInfo *appinfo)
01591 {
01592     Node       *result;
01593     adjust_appendrel_attrs_context context;
01594 
01595     context.root = root;
01596     context.appinfo = appinfo;
01597 
01598     /*
01599      * Must be prepared to start with a Query or a bare expression tree.
01600      */
01601     if (node && IsA(node, Query))
01602     {
01603         Query      *newnode;
01604 
01605         newnode = query_tree_mutator((Query *) node,
01606                                      adjust_appendrel_attrs_mutator,
01607                                      (void *) &context,
01608                                      QTW_IGNORE_RC_SUBQUERIES);
01609         if (newnode->resultRelation == appinfo->parent_relid)
01610         {
01611             newnode->resultRelation = appinfo->child_relid;
01612             /* Fix tlist resnos too, if it's inherited UPDATE */
01613             if (newnode->commandType == CMD_UPDATE)
01614                 newnode->targetList =
01615                     adjust_inherited_tlist(newnode->targetList,
01616                                            appinfo);
01617         }
01618         result = (Node *) newnode;
01619     }
01620     else
01621         result = adjust_appendrel_attrs_mutator(node, &context);
01622 
01623     return result;
01624 }
01625 
01626 static Node *
01627 adjust_appendrel_attrs_mutator(Node *node,
01628                                adjust_appendrel_attrs_context *context)
01629 {
01630     AppendRelInfo *appinfo = context->appinfo;
01631 
01632     if (node == NULL)
01633         return NULL;
01634     if (IsA(node, Var))
01635     {
01636         Var        *var = (Var *) copyObject(node);
01637 
01638         if (var->varlevelsup == 0 &&
01639             var->varno == appinfo->parent_relid)
01640         {
01641             var->varno = appinfo->child_relid;
01642             var->varnoold = appinfo->child_relid;
01643             if (var->varattno > 0)
01644             {
01645                 Node       *newnode;
01646 
01647                 if (var->varattno > list_length(appinfo->translated_vars))
01648                     elog(ERROR, "attribute %d of relation \"%s\" does not exist",
01649                          var->varattno, get_rel_name(appinfo->parent_reloid));
01650                 newnode = copyObject(list_nth(appinfo->translated_vars,
01651                                               var->varattno - 1));
01652                 if (newnode == NULL)
01653                     elog(ERROR, "attribute %d of relation \"%s\" does not exist",
01654                          var->varattno, get_rel_name(appinfo->parent_reloid));
01655                 return newnode;
01656             }
01657             else if (var->varattno == 0)
01658             {
01659                 /*
01660                  * Whole-row Var: if we are dealing with named rowtypes, we
01661                  * can use a whole-row Var for the child table plus a coercion
01662                  * step to convert the tuple layout to the parent's rowtype.
01663                  * Otherwise we have to generate a RowExpr.
01664                  */
01665                 if (OidIsValid(appinfo->child_reltype))
01666                 {
01667                     Assert(var->vartype == appinfo->parent_reltype);
01668                     if (appinfo->parent_reltype != appinfo->child_reltype)
01669                     {
01670                         ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);
01671 
01672                         r->arg = (Expr *) var;
01673                         r->resulttype = appinfo->parent_reltype;
01674                         r->convertformat = COERCE_IMPLICIT_CAST;
01675                         r->location = -1;
01676                         /* Make sure the Var node has the right type ID, too */
01677                         var->vartype = appinfo->child_reltype;
01678                         return (Node *) r;
01679                     }
01680                 }
01681                 else
01682                 {
01683                     /*
01684                      * Build a RowExpr containing the translated variables.
01685                      *
01686                      * In practice var->vartype will always be RECORDOID here,
01687                      * so we need to come up with some suitable column names.
01688                      * We use the parent RTE's column names.
01689                      *
01690                      * Note: we can't get here for inheritance cases, so there
01691                      * is no need to worry that translated_vars might contain
01692                      * some dummy NULLs.
01693                      */
01694                     RowExpr    *rowexpr;
01695                     List       *fields;
01696                     RangeTblEntry *rte;
01697 
01698                     rte = rt_fetch(appinfo->parent_relid,
01699                                    context->root->parse->rtable);
01700                     fields = (List *) copyObject(appinfo->translated_vars);
01701                     rowexpr = makeNode(RowExpr);
01702                     rowexpr->args = fields;
01703                     rowexpr->row_typeid = var->vartype;
01704                     rowexpr->row_format = COERCE_IMPLICIT_CAST;
01705                     rowexpr->colnames = copyObject(rte->eref->colnames);
01706                     rowexpr->location = -1;
01707 
01708                     return (Node *) rowexpr;
01709                 }
01710             }
01711             /* system attributes don't need any other translation */
01712         }
01713         return (Node *) var;
01714     }
01715     if (IsA(node, CurrentOfExpr))
01716     {
01717         CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
01718 
01719         if (cexpr->cvarno == appinfo->parent_relid)
01720             cexpr->cvarno = appinfo->child_relid;
01721         return (Node *) cexpr;
01722     }
01723     if (IsA(node, RangeTblRef))
01724     {
01725         RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
01726 
01727         if (rtr->rtindex == appinfo->parent_relid)
01728             rtr->rtindex = appinfo->child_relid;
01729         return (Node *) rtr;
01730     }
01731     if (IsA(node, JoinExpr))
01732     {
01733         /* Copy the JoinExpr node with correct mutation of subnodes */
01734         JoinExpr   *j;
01735 
01736         j = (JoinExpr *) expression_tree_mutator(node,
01737                                               adjust_appendrel_attrs_mutator,
01738                                                  (void *) context);
01739         /* now fix JoinExpr's rtindex (probably never happens) */
01740         if (j->rtindex == appinfo->parent_relid)
01741             j->rtindex = appinfo->child_relid;
01742         return (Node *) j;
01743     }
01744     if (IsA(node, PlaceHolderVar))
01745     {
01746         /* Copy the PlaceHolderVar node with correct mutation of subnodes */
01747         PlaceHolderVar *phv;
01748 
01749         phv = (PlaceHolderVar *) expression_tree_mutator(node,
01750                                               adjust_appendrel_attrs_mutator,
01751                                                          (void *) context);
01752         /* now fix PlaceHolderVar's relid sets */
01753         if (phv->phlevelsup == 0)
01754             phv->phrels = adjust_relid_set(phv->phrels,
01755                                            appinfo->parent_relid,
01756                                            appinfo->child_relid);
01757         return (Node *) phv;
01758     }
01759     /* Shouldn't need to handle planner auxiliary nodes here */
01760     Assert(!IsA(node, SpecialJoinInfo));
01761     Assert(!IsA(node, LateralJoinInfo));
01762     Assert(!IsA(node, AppendRelInfo));
01763     Assert(!IsA(node, PlaceHolderInfo));
01764     Assert(!IsA(node, MinMaxAggInfo));
01765 
01766     /*
01767      * We have to process RestrictInfo nodes specially.  (Note: although
01768      * set_append_rel_pathlist will hide RestrictInfos in the parent's
01769      * baserestrictinfo list from us, it doesn't hide those in joininfo.)
01770      */
01771     if (IsA(node, RestrictInfo))
01772     {
01773         RestrictInfo *oldinfo = (RestrictInfo *) node;
01774         RestrictInfo *newinfo = makeNode(RestrictInfo);
01775 
01776         /* Copy all flat-copiable fields */
01777         memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
01778 
01779         /* Recursively fix the clause itself */
01780         newinfo->clause = (Expr *)
01781             adjust_appendrel_attrs_mutator((Node *) oldinfo->clause, context);
01782 
01783         /* and the modified version, if an OR clause */
01784         newinfo->orclause = (Expr *)
01785             adjust_appendrel_attrs_mutator((Node *) oldinfo->orclause, context);
01786 
01787         /* adjust relid sets too */
01788         newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids,
01789                                                   appinfo->parent_relid,
01790                                                   appinfo->child_relid);
01791         newinfo->required_relids = adjust_relid_set(oldinfo->required_relids,
01792                                                     appinfo->parent_relid,
01793                                                     appinfo->child_relid);
01794         newinfo->outer_relids = adjust_relid_set(oldinfo->outer_relids,
01795                                                  appinfo->parent_relid,
01796                                                  appinfo->child_relid);
01797         newinfo->nullable_relids = adjust_relid_set(oldinfo->nullable_relids,
01798                                                     appinfo->parent_relid,
01799                                                     appinfo->child_relid);
01800         newinfo->left_relids = adjust_relid_set(oldinfo->left_relids,
01801                                                 appinfo->parent_relid,
01802                                                 appinfo->child_relid);
01803         newinfo->right_relids = adjust_relid_set(oldinfo->right_relids,
01804                                                  appinfo->parent_relid,
01805                                                  appinfo->child_relid);
01806 
01807         /*
01808          * Reset cached derivative fields, since these might need to have
01809          * different values when considering the child relation.  Note we
01810          * don't reset left_ec/right_ec: each child variable is implicitly
01811          * equivalent to its parent, so still a member of the same EC if any.
01812          */
01813         newinfo->eval_cost.startup = -1;
01814         newinfo->norm_selec = -1;
01815         newinfo->outer_selec = -1;
01816         newinfo->left_em = NULL;
01817         newinfo->right_em = NULL;
01818         newinfo->scansel_cache = NIL;
01819         newinfo->left_bucketsize = -1;
01820         newinfo->right_bucketsize = -1;
01821 
01822         return (Node *) newinfo;
01823     }
01824 
01825     /*
01826      * NOTE: we do not need to recurse into sublinks, because they should
01827      * already have been converted to subplans before we see them.
01828      */
01829     Assert(!IsA(node, SubLink));
01830     Assert(!IsA(node, Query));
01831 
01832     return expression_tree_mutator(node, adjust_appendrel_attrs_mutator,
01833                                    (void *) context);
01834 }
01835 
01836 /*
01837  * Substitute newrelid for oldrelid in a Relid set
01838  */
01839 static Relids
01840 adjust_relid_set(Relids relids, Index oldrelid, Index newrelid)
01841 {
01842     if (bms_is_member(oldrelid, relids))
01843     {
01844         /* Ensure we have a modifiable copy */
01845         relids = bms_copy(relids);
01846         /* Remove old, add new */
01847         relids = bms_del_member(relids, oldrelid);
01848         relids = bms_add_member(relids, newrelid);
01849     }
01850     return relids;
01851 }
01852 
01853 /*
01854  * Adjust the targetlist entries of an inherited UPDATE operation
01855  *
01856  * The expressions have already been fixed, but we have to make sure that
01857  * the target resnos match the child table (they may not, in the case of
01858  * a column that was added after-the-fact by ALTER TABLE).  In some cases
01859  * this can force us to re-order the tlist to preserve resno ordering.
01860  * (We do all this work in special cases so that preptlist.c is fast for
01861  * the typical case.)
01862  *
01863  * The given tlist has already been through expression_tree_mutator;
01864  * therefore the TargetEntry nodes are fresh copies that it's okay to
01865  * scribble on.
01866  *
01867  * Note that this is not needed for INSERT because INSERT isn't inheritable.
01868  */
01869 static List *
01870 adjust_inherited_tlist(List *tlist, AppendRelInfo *context)
01871 {
01872     bool        changed_it = false;
01873     ListCell   *tl;
01874     List       *new_tlist;
01875     bool        more;
01876     int         attrno;
01877 
01878     /* This should only happen for an inheritance case, not UNION ALL */
01879     Assert(OidIsValid(context->parent_reloid));
01880 
01881     /* Scan tlist and update resnos to match attnums of child rel */
01882     foreach(tl, tlist)
01883     {
01884         TargetEntry *tle = (TargetEntry *) lfirst(tl);
01885         Var        *childvar;
01886 
01887         if (tle->resjunk)
01888             continue;           /* ignore junk items */
01889 
01890         /* Look up the translation of this column: it must be a Var */
01891         if (tle->resno <= 0 ||
01892             tle->resno > list_length(context->translated_vars))
01893             elog(ERROR, "attribute %d of relation \"%s\" does not exist",
01894                  tle->resno, get_rel_name(context->parent_reloid));
01895         childvar = (Var *) list_nth(context->translated_vars, tle->resno - 1);
01896         if (childvar == NULL || !IsA(childvar, Var))
01897             elog(ERROR, "attribute %d of relation \"%s\" does not exist",
01898                  tle->resno, get_rel_name(context->parent_reloid));
01899 
01900         if (tle->resno != childvar->varattno)
01901         {
01902             tle->resno = childvar->varattno;
01903             changed_it = true;
01904         }
01905     }
01906 
01907     /*
01908      * If we changed anything, re-sort the tlist by resno, and make sure
01909      * resjunk entries have resnos above the last real resno.  The sort
01910      * algorithm is a bit stupid, but for such a seldom-taken path, small is
01911      * probably better than fast.
01912      */
01913     if (!changed_it)
01914         return tlist;
01915 
01916     new_tlist = NIL;
01917     more = true;
01918     for (attrno = 1; more; attrno++)
01919     {
01920         more = false;
01921         foreach(tl, tlist)
01922         {
01923             TargetEntry *tle = (TargetEntry *) lfirst(tl);
01924 
01925             if (tle->resjunk)
01926                 continue;       /* ignore junk items */
01927 
01928             if (tle->resno == attrno)
01929                 new_tlist = lappend(new_tlist, tle);
01930             else if (tle->resno > attrno)
01931                 more = true;
01932         }
01933     }
01934 
01935     foreach(tl, tlist)
01936     {
01937         TargetEntry *tle = (TargetEntry *) lfirst(tl);
01938 
01939         if (!tle->resjunk)
01940             continue;           /* here, ignore non-junk items */
01941 
01942         tle->resno = attrno;
01943         new_tlist = lappend(new_tlist, tle);
01944         attrno++;
01945     }
01946 
01947     return new_tlist;
01948 }