Header And Logo

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

prepjointree.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * prepjointree.c
00004  *    Planner preprocessing for subqueries and join tree manipulation.
00005  *
00006  * NOTE: the intended sequence for invoking these operations is
00007  *      pull_up_sublinks
00008  *      inline_set_returning_functions
00009  *      pull_up_subqueries
00010  *      flatten_simple_union_all
00011  *      do expression preprocessing (including flattening JOIN alias vars)
00012  *      reduce_outer_joins
00013  *
00014  *
00015  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00016  * Portions Copyright (c) 1994, Regents of the University of California
00017  *
00018  *
00019  * IDENTIFICATION
00020  *    src/backend/optimizer/prep/prepjointree.c
00021  *
00022  *-------------------------------------------------------------------------
00023  */
00024 #include "postgres.h"
00025 
00026 #include "catalog/pg_type.h"
00027 #include "nodes/makefuncs.h"
00028 #include "nodes/nodeFuncs.h"
00029 #include "optimizer/clauses.h"
00030 #include "optimizer/placeholder.h"
00031 #include "optimizer/prep.h"
00032 #include "optimizer/subselect.h"
00033 #include "optimizer/tlist.h"
00034 #include "parser/parse_relation.h"
00035 #include "parser/parsetree.h"
00036 #include "rewrite/rewriteManip.h"
00037 
00038 
00039 typedef struct pullup_replace_vars_context
00040 {
00041     PlannerInfo *root;
00042     List       *targetlist;     /* tlist of subquery being pulled up */
00043     RangeTblEntry *target_rte;  /* RTE of subquery */
00044     bool       *outer_hasSubLinks;      /* -> outer query's hasSubLinks */
00045     int         varno;          /* varno of subquery */
00046     bool        need_phvs;      /* do we need PlaceHolderVars? */
00047     bool        wrap_non_vars;  /* do we need 'em on *all* non-Vars? */
00048     Node      **rv_cache;       /* cache for results with PHVs */
00049 } pullup_replace_vars_context;
00050 
00051 typedef struct reduce_outer_joins_state
00052 {
00053     Relids      relids;         /* base relids within this subtree */
00054     bool        contains_outer; /* does subtree contain outer join(s)? */
00055     List       *sub_states;     /* List of states for subtree components */
00056 } reduce_outer_joins_state;
00057 
00058 static Node *pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode,
00059                                   Relids *relids);
00060 static Node *pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
00061                               Node **jtlink1, Relids available_rels1,
00062                               Node **jtlink2, Relids available_rels2);
00063 static Node *pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode,
00064                            JoinExpr *lowest_outer_join,
00065                            JoinExpr *lowest_nulling_outer_join,
00066                            AppendRelInfo *containing_appendrel);
00067 static Node *pull_up_simple_subquery(PlannerInfo *root, Node *jtnode,
00068                         RangeTblEntry *rte,
00069                         JoinExpr *lowest_outer_join,
00070                         JoinExpr *lowest_nulling_outer_join,
00071                         AppendRelInfo *containing_appendrel);
00072 static Node *pull_up_simple_union_all(PlannerInfo *root, Node *jtnode,
00073                          RangeTblEntry *rte);
00074 static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root,
00075                            int parentRTindex, Query *setOpQuery,
00076                            int childRToffset);
00077 static void make_setop_translation_list(Query *query, Index newvarno,
00078                             List **translated_vars);
00079 static bool is_simple_subquery(Query *subquery, RangeTblEntry *rte,
00080                    JoinExpr *lowest_outer_join);
00081 static bool is_simple_union_all(Query *subquery);
00082 static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery,
00083                             List *colTypes);
00084 static bool is_safe_append_member(Query *subquery);
00085 static void replace_vars_in_jointree(Node *jtnode,
00086                          pullup_replace_vars_context *context,
00087                          JoinExpr *lowest_nulling_outer_join);
00088 static Node *pullup_replace_vars(Node *expr,
00089                     pullup_replace_vars_context *context);
00090 static Node *pullup_replace_vars_callback(Var *var,
00091                              replace_rte_variables_context *context);
00092 static Query *pullup_replace_vars_subquery(Query *query,
00093                              pullup_replace_vars_context *context);
00094 static reduce_outer_joins_state *reduce_outer_joins_pass1(Node *jtnode);
00095 static void reduce_outer_joins_pass2(Node *jtnode,
00096                          reduce_outer_joins_state *state,
00097                          PlannerInfo *root,
00098                          Relids nonnullable_rels,
00099                          List *nonnullable_vars,
00100                          List *forced_null_vars);
00101 static void substitute_multiple_relids(Node *node,
00102                            int varno, Relids subrelids);
00103 static void fix_append_rel_relids(List *append_rel_list, int varno,
00104                       Relids subrelids);
00105 static Node *find_jointree_node_for_rel(Node *jtnode, int relid);
00106 
00107 
00108 /*
00109  * pull_up_sublinks
00110  *      Attempt to pull up ANY and EXISTS SubLinks to be treated as
00111  *      semijoins or anti-semijoins.
00112  *
00113  * A clause "foo op ANY (sub-SELECT)" can be processed by pulling the
00114  * sub-SELECT up to become a rangetable entry and treating the implied
00115  * comparisons as quals of a semijoin.  However, this optimization *only*
00116  * works at the top level of WHERE or a JOIN/ON clause, because we cannot
00117  * distinguish whether the ANY ought to return FALSE or NULL in cases
00118  * involving NULL inputs.  Also, in an outer join's ON clause we can only
00119  * do this if the sublink is degenerate (ie, references only the nullable
00120  * side of the join).  In that case it is legal to push the semijoin
00121  * down into the nullable side of the join.  If the sublink references any
00122  * nonnullable-side variables then it would have to be evaluated as part
00123  * of the outer join, which makes things way too complicated.
00124  *
00125  * Under similar conditions, EXISTS and NOT EXISTS clauses can be handled
00126  * by pulling up the sub-SELECT and creating a semijoin or anti-semijoin.
00127  *
00128  * This routine searches for such clauses and does the necessary parsetree
00129  * transformations if any are found.
00130  *
00131  * This routine has to run before preprocess_expression(), so the quals
00132  * clauses are not yet reduced to implicit-AND format.  That means we need
00133  * to recursively search through explicit AND clauses, which are
00134  * probably only binary ANDs.  We stop as soon as we hit a non-AND item.
00135  */
00136 void
00137 pull_up_sublinks(PlannerInfo *root)
00138 {
00139     Node       *jtnode;
00140     Relids      relids;
00141 
00142     /* Begin recursion through the jointree */
00143     jtnode = pull_up_sublinks_jointree_recurse(root,
00144                                                (Node *) root->parse->jointree,
00145                                                &relids);
00146 
00147     /*
00148      * root->parse->jointree must always be a FromExpr, so insert a dummy one
00149      * if we got a bare RangeTblRef or JoinExpr out of the recursion.
00150      */
00151     if (IsA(jtnode, FromExpr))
00152         root->parse->jointree = (FromExpr *) jtnode;
00153     else
00154         root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
00155 }
00156 
00157 /*
00158  * Recurse through jointree nodes for pull_up_sublinks()
00159  *
00160  * In addition to returning the possibly-modified jointree node, we return
00161  * a relids set of the contained rels into *relids.
00162  */
00163 static Node *
00164 pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode,
00165                                   Relids *relids)
00166 {
00167     if (jtnode == NULL)
00168     {
00169         *relids = NULL;
00170     }
00171     else if (IsA(jtnode, RangeTblRef))
00172     {
00173         int         varno = ((RangeTblRef *) jtnode)->rtindex;
00174 
00175         *relids = bms_make_singleton(varno);
00176         /* jtnode is returned unmodified */
00177     }
00178     else if (IsA(jtnode, FromExpr))
00179     {
00180         FromExpr   *f = (FromExpr *) jtnode;
00181         List       *newfromlist = NIL;
00182         Relids      frelids = NULL;
00183         FromExpr   *newf;
00184         Node       *jtlink;
00185         ListCell   *l;
00186 
00187         /* First, recurse to process children and collect their relids */
00188         foreach(l, f->fromlist)
00189         {
00190             Node       *newchild;
00191             Relids      childrelids;
00192 
00193             newchild = pull_up_sublinks_jointree_recurse(root,
00194                                                          lfirst(l),
00195                                                          &childrelids);
00196             newfromlist = lappend(newfromlist, newchild);
00197             frelids = bms_join(frelids, childrelids);
00198         }
00199         /* Build the replacement FromExpr; no quals yet */
00200         newf = makeFromExpr(newfromlist, NULL);
00201         /* Set up a link representing the rebuilt jointree */
00202         jtlink = (Node *) newf;
00203         /* Now process qual --- all children are available for use */
00204         newf->quals = pull_up_sublinks_qual_recurse(root, f->quals,
00205                                                     &jtlink, frelids,
00206                                                     NULL, NULL);
00207 
00208         /*
00209          * Note that the result will be either newf, or a stack of JoinExprs
00210          * with newf at the base.  We rely on subsequent optimization steps to
00211          * flatten this and rearrange the joins as needed.
00212          *
00213          * Although we could include the pulled-up subqueries in the returned
00214          * relids, there's no need since upper quals couldn't refer to their
00215          * outputs anyway.
00216          */
00217         *relids = frelids;
00218         jtnode = jtlink;
00219     }
00220     else if (IsA(jtnode, JoinExpr))
00221     {
00222         JoinExpr   *j;
00223         Relids      leftrelids;
00224         Relids      rightrelids;
00225         Node       *jtlink;
00226 
00227         /*
00228          * Make a modifiable copy of join node, but don't bother copying its
00229          * subnodes (yet).
00230          */
00231         j = (JoinExpr *) palloc(sizeof(JoinExpr));
00232         memcpy(j, jtnode, sizeof(JoinExpr));
00233         jtlink = (Node *) j;
00234 
00235         /* Recurse to process children and collect their relids */
00236         j->larg = pull_up_sublinks_jointree_recurse(root, j->larg,
00237                                                     &leftrelids);
00238         j->rarg = pull_up_sublinks_jointree_recurse(root, j->rarg,
00239                                                     &rightrelids);
00240 
00241         /*
00242          * Now process qual, showing appropriate child relids as available,
00243          * and attach any pulled-up jointree items at the right place. In the
00244          * inner-join case we put new JoinExprs above the existing one (much
00245          * as for a FromExpr-style join).  In outer-join cases the new
00246          * JoinExprs must go into the nullable side of the outer join. The
00247          * point of the available_rels machinations is to ensure that we only
00248          * pull up quals for which that's okay.
00249          *
00250          * We don't expect to see any pre-existing JOIN_SEMI or JOIN_ANTI
00251          * nodes here.
00252          */
00253         switch (j->jointype)
00254         {
00255             case JOIN_INNER:
00256                 j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
00257                                                          &jtlink,
00258                                                          bms_union(leftrelids,
00259                                                                 rightrelids),
00260                                                          NULL, NULL);
00261                 break;
00262             case JOIN_LEFT:
00263                 j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
00264                                                          &j->rarg,
00265                                                          rightrelids,
00266                                                          NULL, NULL);
00267                 break;
00268             case JOIN_FULL:
00269                 /* can't do anything with full-join quals */
00270                 break;
00271             case JOIN_RIGHT:
00272                 j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
00273                                                          &j->larg,
00274                                                          leftrelids,
00275                                                          NULL, NULL);
00276                 break;
00277             default:
00278                 elog(ERROR, "unrecognized join type: %d",
00279                      (int) j->jointype);
00280                 break;
00281         }
00282 
00283         /*
00284          * Although we could include the pulled-up subqueries in the returned
00285          * relids, there's no need since upper quals couldn't refer to their
00286          * outputs anyway.  But we *do* need to include the join's own rtindex
00287          * because we haven't yet collapsed join alias variables, so upper
00288          * levels would mistakenly think they couldn't use references to this
00289          * join.
00290          */
00291         *relids = bms_join(leftrelids, rightrelids);
00292         if (j->rtindex)
00293             *relids = bms_add_member(*relids, j->rtindex);
00294         jtnode = jtlink;
00295     }
00296     else
00297         elog(ERROR, "unrecognized node type: %d",
00298              (int) nodeTag(jtnode));
00299     return jtnode;
00300 }
00301 
00302 /*
00303  * Recurse through top-level qual nodes for pull_up_sublinks()
00304  *
00305  * jtlink1 points to the link in the jointree where any new JoinExprs should
00306  * be inserted if they reference available_rels1 (i.e., available_rels1
00307  * denotes the relations present underneath jtlink1).  Optionally, jtlink2 can
00308  * point to a second link where new JoinExprs should be inserted if they
00309  * reference available_rels2 (pass NULL for both those arguments if not used).
00310  * Note that SubLinks referencing both sets of variables cannot be optimized.
00311  * If we find multiple pull-up-able SubLinks, they'll get stacked onto jtlink1
00312  * and/or jtlink2 in the order we encounter them.  We rely on subsequent
00313  * optimization to rearrange the stack if appropriate.
00314  *
00315  * Returns the replacement qual node, or NULL if the qual should be removed.
00316  */
00317 static Node *
00318 pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
00319                               Node **jtlink1, Relids available_rels1,
00320                               Node **jtlink2, Relids available_rels2)
00321 {
00322     if (node == NULL)
00323         return NULL;
00324     if (IsA(node, SubLink))
00325     {
00326         SubLink    *sublink = (SubLink *) node;
00327         JoinExpr   *j;
00328         Relids      child_rels;
00329 
00330         /* Is it a convertible ANY or EXISTS clause? */
00331         if (sublink->subLinkType == ANY_SUBLINK)
00332         {
00333             if ((j = convert_ANY_sublink_to_join(root, sublink,
00334                                                  available_rels1)) != NULL)
00335             {
00336                 /* Yes; insert the new join node into the join tree */
00337                 j->larg = *jtlink1;
00338                 *jtlink1 = (Node *) j;
00339                 /* Recursively process pulled-up jointree nodes */
00340                 j->rarg = pull_up_sublinks_jointree_recurse(root,
00341                                                             j->rarg,
00342                                                             &child_rels);
00343 
00344                 /*
00345                  * Now recursively process the pulled-up quals.  Any inserted
00346                  * joins can get stacked onto either j->larg or j->rarg,
00347                  * depending on which rels they reference.
00348                  */
00349                 j->quals = pull_up_sublinks_qual_recurse(root,
00350                                                          j->quals,
00351                                                          &j->larg,
00352                                                          available_rels1,
00353                                                          &j->rarg,
00354                                                          child_rels);
00355                 /* Return NULL representing constant TRUE */
00356                 return NULL;
00357             }
00358             if (available_rels2 != NULL &&
00359                 (j = convert_ANY_sublink_to_join(root, sublink,
00360                                                  available_rels2)) != NULL)
00361             {
00362                 /* Yes; insert the new join node into the join tree */
00363                 j->larg = *jtlink2;
00364                 *jtlink2 = (Node *) j;
00365                 /* Recursively process pulled-up jointree nodes */
00366                 j->rarg = pull_up_sublinks_jointree_recurse(root,
00367                                                             j->rarg,
00368                                                             &child_rels);
00369 
00370                 /*
00371                  * Now recursively process the pulled-up quals.  Any inserted
00372                  * joins can get stacked onto either j->larg or j->rarg,
00373                  * depending on which rels they reference.
00374                  */
00375                 j->quals = pull_up_sublinks_qual_recurse(root,
00376                                                          j->quals,
00377                                                          &j->larg,
00378                                                          available_rels2,
00379                                                          &j->rarg,
00380                                                          child_rels);
00381                 /* Return NULL representing constant TRUE */
00382                 return NULL;
00383             }
00384         }
00385         else if (sublink->subLinkType == EXISTS_SUBLINK)
00386         {
00387             if ((j = convert_EXISTS_sublink_to_join(root, sublink, false,
00388                                                     available_rels1)) != NULL)
00389             {
00390                 /* Yes; insert the new join node into the join tree */
00391                 j->larg = *jtlink1;
00392                 *jtlink1 = (Node *) j;
00393                 /* Recursively process pulled-up jointree nodes */
00394                 j->rarg = pull_up_sublinks_jointree_recurse(root,
00395                                                             j->rarg,
00396                                                             &child_rels);
00397 
00398                 /*
00399                  * Now recursively process the pulled-up quals.  Any inserted
00400                  * joins can get stacked onto either j->larg or j->rarg,
00401                  * depending on which rels they reference.
00402                  */
00403                 j->quals = pull_up_sublinks_qual_recurse(root,
00404                                                          j->quals,
00405                                                          &j->larg,
00406                                                          available_rels1,
00407                                                          &j->rarg,
00408                                                          child_rels);
00409                 /* Return NULL representing constant TRUE */
00410                 return NULL;
00411             }
00412             if (available_rels2 != NULL &&
00413                 (j = convert_EXISTS_sublink_to_join(root, sublink, false,
00414                                                     available_rels2)) != NULL)
00415             {
00416                 /* Yes; insert the new join node into the join tree */
00417                 j->larg = *jtlink2;
00418                 *jtlink2 = (Node *) j;
00419                 /* Recursively process pulled-up jointree nodes */
00420                 j->rarg = pull_up_sublinks_jointree_recurse(root,
00421                                                             j->rarg,
00422                                                             &child_rels);
00423 
00424                 /*
00425                  * Now recursively process the pulled-up quals.  Any inserted
00426                  * joins can get stacked onto either j->larg or j->rarg,
00427                  * depending on which rels they reference.
00428                  */
00429                 j->quals = pull_up_sublinks_qual_recurse(root,
00430                                                          j->quals,
00431                                                          &j->larg,
00432                                                          available_rels2,
00433                                                          &j->rarg,
00434                                                          child_rels);
00435                 /* Return NULL representing constant TRUE */
00436                 return NULL;
00437             }
00438         }
00439         /* Else return it unmodified */
00440         return node;
00441     }
00442     if (not_clause(node))
00443     {
00444         /* If the immediate argument of NOT is EXISTS, try to convert */
00445         SubLink    *sublink = (SubLink *) get_notclausearg((Expr *) node);
00446         JoinExpr   *j;
00447         Relids      child_rels;
00448 
00449         if (sublink && IsA(sublink, SubLink))
00450         {
00451             if (sublink->subLinkType == EXISTS_SUBLINK)
00452             {
00453                 if ((j = convert_EXISTS_sublink_to_join(root, sublink, true,
00454                                                    available_rels1)) != NULL)
00455                 {
00456                     /* Yes; insert the new join node into the join tree */
00457                     j->larg = *jtlink1;
00458                     *jtlink1 = (Node *) j;
00459                     /* Recursively process pulled-up jointree nodes */
00460                     j->rarg = pull_up_sublinks_jointree_recurse(root,
00461                                                                 j->rarg,
00462                                                                 &child_rels);
00463 
00464                     /*
00465                      * Now recursively process the pulled-up quals.  Because
00466                      * we are underneath a NOT, we can't pull up sublinks that
00467                      * reference the left-hand stuff, but it's still okay to
00468                      * pull up sublinks referencing j->rarg.
00469                      */
00470                     j->quals = pull_up_sublinks_qual_recurse(root,
00471                                                              j->quals,
00472                                                              &j->rarg,
00473                                                              child_rels,
00474                                                              NULL, NULL);
00475                     /* Return NULL representing constant TRUE */
00476                     return NULL;
00477                 }
00478                 if (available_rels2 != NULL &&
00479                     (j = convert_EXISTS_sublink_to_join(root, sublink, true,
00480                                                    available_rels2)) != NULL)
00481                 {
00482                     /* Yes; insert the new join node into the join tree */
00483                     j->larg = *jtlink2;
00484                     *jtlink2 = (Node *) j;
00485                     /* Recursively process pulled-up jointree nodes */
00486                     j->rarg = pull_up_sublinks_jointree_recurse(root,
00487                                                                 j->rarg,
00488                                                                 &child_rels);
00489 
00490                     /*
00491                      * Now recursively process the pulled-up quals.  Because
00492                      * we are underneath a NOT, we can't pull up sublinks that
00493                      * reference the left-hand stuff, but it's still okay to
00494                      * pull up sublinks referencing j->rarg.
00495                      */
00496                     j->quals = pull_up_sublinks_qual_recurse(root,
00497                                                              j->quals,
00498                                                              &j->rarg,
00499                                                              child_rels,
00500                                                              NULL, NULL);
00501                     /* Return NULL representing constant TRUE */
00502                     return NULL;
00503                 }
00504             }
00505         }
00506         /* Else return it unmodified */
00507         return node;
00508     }
00509     if (and_clause(node))
00510     {
00511         /* Recurse into AND clause */
00512         List       *newclauses = NIL;
00513         ListCell   *l;
00514 
00515         foreach(l, ((BoolExpr *) node)->args)
00516         {
00517             Node       *oldclause = (Node *) lfirst(l);
00518             Node       *newclause;
00519 
00520             newclause = pull_up_sublinks_qual_recurse(root,
00521                                                       oldclause,
00522                                                       jtlink1,
00523                                                       available_rels1,
00524                                                       jtlink2,
00525                                                       available_rels2);
00526             if (newclause)
00527                 newclauses = lappend(newclauses, newclause);
00528         }
00529         /* We might have got back fewer clauses than we started with */
00530         if (newclauses == NIL)
00531             return NULL;
00532         else if (list_length(newclauses) == 1)
00533             return (Node *) linitial(newclauses);
00534         else
00535             return (Node *) make_andclause(newclauses);
00536     }
00537     /* Stop if not an AND */
00538     return node;
00539 }
00540 
00541 /*
00542  * inline_set_returning_functions
00543  *      Attempt to "inline" set-returning functions in the FROM clause.
00544  *
00545  * If an RTE_FUNCTION rtable entry invokes a set-returning function that
00546  * contains just a simple SELECT, we can convert the rtable entry to an
00547  * RTE_SUBQUERY entry exposing the SELECT directly.  This is especially
00548  * useful if the subquery can then be "pulled up" for further optimization,
00549  * but we do it even if not, to reduce executor overhead.
00550  *
00551  * This has to be done before we have started to do any optimization of
00552  * subqueries, else any such steps wouldn't get applied to subqueries
00553  * obtained via inlining.  However, we do it after pull_up_sublinks
00554  * so that we can inline any functions used in SubLink subselects.
00555  *
00556  * Like most of the planner, this feels free to scribble on its input data
00557  * structure.
00558  */
00559 void
00560 inline_set_returning_functions(PlannerInfo *root)
00561 {
00562     ListCell   *rt;
00563 
00564     foreach(rt, root->parse->rtable)
00565     {
00566         RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
00567 
00568         if (rte->rtekind == RTE_FUNCTION)
00569         {
00570             Query      *funcquery;
00571 
00572             /* Check safety of expansion, and expand if possible */
00573             funcquery = inline_set_returning_function(root, rte);
00574             if (funcquery)
00575             {
00576                 /* Successful expansion, replace the rtable entry */
00577                 rte->rtekind = RTE_SUBQUERY;
00578                 rte->subquery = funcquery;
00579                 rte->funcexpr = NULL;
00580                 rte->funccoltypes = NIL;
00581                 rte->funccoltypmods = NIL;
00582                 rte->funccolcollations = NIL;
00583             }
00584         }
00585     }
00586 }
00587 
00588 /*
00589  * pull_up_subqueries
00590  *      Look for subqueries in the rangetable that can be pulled up into
00591  *      the parent query.  If the subquery has no special features like
00592  *      grouping/aggregation then we can merge it into the parent's jointree.
00593  *      Also, subqueries that are simple UNION ALL structures can be
00594  *      converted into "append relations".
00595  *
00596  * This recursively processes the jointree and returns a modified jointree.
00597  */
00598 Node *
00599 pull_up_subqueries(PlannerInfo *root, Node *jtnode)
00600 {
00601     /* Start off with no containing join nor appendrel */
00602     return pull_up_subqueries_recurse(root, jtnode, NULL, NULL, NULL);
00603 }
00604 
00605 /*
00606  * pull_up_subqueries_recurse
00607  *      Recursive guts of pull_up_subqueries.
00608  *
00609  * If this jointree node is within either side of an outer join, then
00610  * lowest_outer_join references the lowest such JoinExpr node; otherwise
00611  * it is NULL.  We use this to constrain the effects of LATERAL subqueries.
00612  *
00613  * If this jointree node is within the nullable side of an outer join, then
00614  * lowest_nulling_outer_join references the lowest such JoinExpr node;
00615  * otherwise it is NULL.  This forces use of the PlaceHolderVar mechanism for
00616  * references to non-nullable targetlist items, but only for references above
00617  * that join.
00618  *
00619  * If we are looking at a member subquery of an append relation,
00620  * containing_appendrel describes that relation; else it is NULL.
00621  * This forces use of the PlaceHolderVar mechanism for all non-Var targetlist
00622  * items, and puts some additional restrictions on what can be pulled up.
00623  *
00624  * A tricky aspect of this code is that if we pull up a subquery we have
00625  * to replace Vars that reference the subquery's outputs throughout the
00626  * parent query, including quals attached to jointree nodes above the one
00627  * we are currently processing!  We handle this by being careful not to
00628  * change the jointree structure while recursing: no nodes other than
00629  * subquery RangeTblRef entries will be replaced.  Also, we can't turn
00630  * pullup_replace_vars loose on the whole jointree, because it'll return a
00631  * mutated copy of the tree; we have to invoke it just on the quals, instead.
00632  * This behavior is what makes it reasonable to pass lowest_outer_join and
00633  * lowest_nulling_outer_join as pointers rather than some more-indirect way
00634  * of identifying the lowest OJs.  Likewise, we don't replace append_rel_list
00635  * members but only their substructure, so the containing_appendrel reference
00636  * is safe to use.
00637  */
00638 static Node *
00639 pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode,
00640                            JoinExpr *lowest_outer_join,
00641                            JoinExpr *lowest_nulling_outer_join,
00642                            AppendRelInfo *containing_appendrel)
00643 {
00644     if (jtnode == NULL)
00645         return NULL;
00646     if (IsA(jtnode, RangeTblRef))
00647     {
00648         int         varno = ((RangeTblRef *) jtnode)->rtindex;
00649         RangeTblEntry *rte = rt_fetch(varno, root->parse->rtable);
00650 
00651         /*
00652          * Is this a subquery RTE, and if so, is the subquery simple enough to
00653          * pull up?
00654          *
00655          * If we are looking at an append-relation member, we can't pull it up
00656          * unless is_safe_append_member says so.
00657          */
00658         if (rte->rtekind == RTE_SUBQUERY &&
00659             is_simple_subquery(rte->subquery, rte, lowest_outer_join) &&
00660             (containing_appendrel == NULL ||
00661              is_safe_append_member(rte->subquery)))
00662             return pull_up_simple_subquery(root, jtnode, rte,
00663                                            lowest_outer_join,
00664                                            lowest_nulling_outer_join,
00665                                            containing_appendrel);
00666 
00667         /*
00668          * Alternatively, is it a simple UNION ALL subquery?  If so, flatten
00669          * into an "append relation".
00670          *
00671          * It's safe to do this regardless of whether this query is itself an
00672          * appendrel member.  (If you're thinking we should try to flatten the
00673          * two levels of appendrel together, you're right; but we handle that
00674          * in set_append_rel_pathlist, not here.)
00675          */
00676         if (rte->rtekind == RTE_SUBQUERY &&
00677             is_simple_union_all(rte->subquery))
00678             return pull_up_simple_union_all(root, jtnode, rte);
00679 
00680         /* Otherwise, do nothing at this node. */
00681     }
00682     else if (IsA(jtnode, FromExpr))
00683     {
00684         FromExpr   *f = (FromExpr *) jtnode;
00685         ListCell   *l;
00686 
00687         Assert(containing_appendrel == NULL);
00688         foreach(l, f->fromlist)
00689             lfirst(l) = pull_up_subqueries_recurse(root, lfirst(l),
00690                                                    lowest_outer_join,
00691                                                    lowest_nulling_outer_join,
00692                                                    NULL);
00693     }
00694     else if (IsA(jtnode, JoinExpr))
00695     {
00696         JoinExpr   *j = (JoinExpr *) jtnode;
00697 
00698         Assert(containing_appendrel == NULL);
00699         /* Recurse, being careful to tell myself when inside outer join */
00700         switch (j->jointype)
00701         {
00702             case JOIN_INNER:
00703                 j->larg = pull_up_subqueries_recurse(root, j->larg,
00704                                                      lowest_outer_join,
00705                                                      lowest_nulling_outer_join,
00706                                                      NULL);
00707                 j->rarg = pull_up_subqueries_recurse(root, j->rarg,
00708                                                      lowest_outer_join,
00709                                                      lowest_nulling_outer_join,
00710                                                      NULL);
00711                 break;
00712             case JOIN_LEFT:
00713             case JOIN_SEMI:
00714             case JOIN_ANTI:
00715                 j->larg = pull_up_subqueries_recurse(root, j->larg,
00716                                                      j,
00717                                                      lowest_nulling_outer_join,
00718                                                      NULL);
00719                 j->rarg = pull_up_subqueries_recurse(root, j->rarg,
00720                                                      j,
00721                                                      j,
00722                                                      NULL);
00723                 break;
00724             case JOIN_FULL:
00725                 j->larg = pull_up_subqueries_recurse(root, j->larg,
00726                                                      j,
00727                                                      j,
00728                                                      NULL);
00729                 j->rarg = pull_up_subqueries_recurse(root, j->rarg,
00730                                                      j,
00731                                                      j,
00732                                                      NULL);
00733                 break;
00734             case JOIN_RIGHT:
00735                 j->larg = pull_up_subqueries_recurse(root, j->larg,
00736                                                      j,
00737                                                      j,
00738                                                      NULL);
00739                 j->rarg = pull_up_subqueries_recurse(root, j->rarg,
00740                                                      j,
00741                                                      lowest_nulling_outer_join,
00742                                                      NULL);
00743                 break;
00744             default:
00745                 elog(ERROR, "unrecognized join type: %d",
00746                      (int) j->jointype);
00747                 break;
00748         }
00749     }
00750     else
00751         elog(ERROR, "unrecognized node type: %d",
00752              (int) nodeTag(jtnode));
00753     return jtnode;
00754 }
00755 
00756 /*
00757  * pull_up_simple_subquery
00758  *      Attempt to pull up a single simple subquery.
00759  *
00760  * jtnode is a RangeTblRef that has been tentatively identified as a simple
00761  * subquery by pull_up_subqueries.  We return the replacement jointree node,
00762  * or jtnode itself if we determine that the subquery can't be pulled up after
00763  * all.
00764  *
00765  * rte is the RangeTblEntry referenced by jtnode.  Remaining parameters are
00766  * as for pull_up_subqueries_recurse.
00767  */
00768 static Node *
00769 pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
00770                         JoinExpr *lowest_outer_join,
00771                         JoinExpr *lowest_nulling_outer_join,
00772                         AppendRelInfo *containing_appendrel)
00773 {
00774     Query      *parse = root->parse;
00775     int         varno = ((RangeTblRef *) jtnode)->rtindex;
00776     Query      *subquery;
00777     PlannerInfo *subroot;
00778     int         rtoffset;
00779     pullup_replace_vars_context rvcontext;
00780     ListCell   *lc;
00781 
00782     /*
00783      * Need a modifiable copy of the subquery to hack on.  Even if we didn't
00784      * sometimes choose not to pull up below, we must do this to avoid
00785      * problems if the same subquery is referenced from multiple jointree
00786      * items (which can't happen normally, but might after rule rewriting).
00787      */
00788     subquery = copyObject(rte->subquery);
00789 
00790     /*
00791      * Create a PlannerInfo data structure for this subquery.
00792      *
00793      * NOTE: the next few steps should match the first processing in
00794      * subquery_planner().  Can we refactor to avoid code duplication, or
00795      * would that just make things uglier?
00796      */
00797     subroot = makeNode(PlannerInfo);
00798     subroot->parse = subquery;
00799     subroot->glob = root->glob;
00800     subroot->query_level = root->query_level;
00801     subroot->parent_root = root->parent_root;
00802     subroot->plan_params = NIL;
00803     subroot->planner_cxt = CurrentMemoryContext;
00804     subroot->init_plans = NIL;
00805     subroot->cte_plan_ids = NIL;
00806     subroot->eq_classes = NIL;
00807     subroot->append_rel_list = NIL;
00808     subroot->rowMarks = NIL;
00809     subroot->hasRecursion = false;
00810     subroot->wt_param_id = -1;
00811     subroot->non_recursive_plan = NULL;
00812 
00813     /* No CTEs to worry about */
00814     Assert(subquery->cteList == NIL);
00815 
00816     /*
00817      * Pull up any SubLinks within the subquery's quals, so that we don't
00818      * leave unoptimized SubLinks behind.
00819      */
00820     if (subquery->hasSubLinks)
00821         pull_up_sublinks(subroot);
00822 
00823     /*
00824      * Similarly, inline any set-returning functions in its rangetable.
00825      */
00826     inline_set_returning_functions(subroot);
00827 
00828     /*
00829      * Recursively pull up the subquery's subqueries, so that
00830      * pull_up_subqueries' processing is complete for its jointree and
00831      * rangetable.
00832      *
00833      * Note: we should pass NULL for containing-join info even if we are
00834      * within an outer join in the upper query; the lower query starts with a
00835      * clean slate for outer-join semantics.  Likewise, we say we aren't
00836      * handling an appendrel member.
00837      */
00838     subquery->jointree = (FromExpr *)
00839         pull_up_subqueries_recurse(subroot, (Node *) subquery->jointree,
00840                                    NULL, NULL, NULL);
00841 
00842     /*
00843      * Now we must recheck whether the subquery is still simple enough to pull
00844      * up.  If not, abandon processing it.
00845      *
00846      * We don't really need to recheck all the conditions involved, but it's
00847      * easier just to keep this "if" looking the same as the one in
00848      * pull_up_subqueries_recurse.
00849      */
00850     if (is_simple_subquery(subquery, rte, lowest_outer_join) &&
00851         (containing_appendrel == NULL || is_safe_append_member(subquery)))
00852     {
00853         /* good to go */
00854     }
00855     else
00856     {
00857         /*
00858          * Give up, return unmodified RangeTblRef.
00859          *
00860          * Note: The work we just did will be redone when the subquery gets
00861          * planned on its own.  Perhaps we could avoid that by storing the
00862          * modified subquery back into the rangetable, but I'm not gonna risk
00863          * it now.
00864          */
00865         return jtnode;
00866     }
00867 
00868     /*
00869      * Adjust level-0 varnos in subquery so that we can append its rangetable
00870      * to upper query's.  We have to fix the subquery's append_rel_list as
00871      * well.
00872      */
00873     rtoffset = list_length(parse->rtable);
00874     OffsetVarNodes((Node *) subquery, rtoffset, 0);
00875     OffsetVarNodes((Node *) subroot->append_rel_list, rtoffset, 0);
00876 
00877     /*
00878      * Upper-level vars in subquery are now one level closer to their parent
00879      * than before.
00880      */
00881     IncrementVarSublevelsUp((Node *) subquery, -1, 1);
00882     IncrementVarSublevelsUp((Node *) subroot->append_rel_list, -1, 1);
00883 
00884     /*
00885      * The subquery's targetlist items are now in the appropriate form to
00886      * insert into the top query, but if we are under an outer join then
00887      * non-nullable items may have to be turned into PlaceHolderVars.  If we
00888      * are dealing with an appendrel member then anything that's not a simple
00889      * Var has to be turned into a PlaceHolderVar.  Set up appropriate context
00890      * data for pullup_replace_vars.
00891      */
00892     rvcontext.root = root;
00893     rvcontext.targetlist = subquery->targetList;
00894     rvcontext.target_rte = rte;
00895     rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
00896     rvcontext.varno = varno;
00897     rvcontext.need_phvs = (lowest_nulling_outer_join != NULL ||
00898                            containing_appendrel != NULL);
00899     rvcontext.wrap_non_vars = (containing_appendrel != NULL);
00900     /* initialize cache array with indexes 0 .. length(tlist) */
00901     rvcontext.rv_cache = palloc0((list_length(subquery->targetList) + 1) *
00902                                  sizeof(Node *));
00903 
00904     /*
00905      * Replace all of the top query's references to the subquery's outputs
00906      * with copies of the adjusted subtlist items, being careful not to
00907      * replace any of the jointree structure. (This'd be a lot cleaner if we
00908      * could use query_tree_mutator.)  We have to use PHVs in the targetList,
00909      * returningList, and havingQual, since those are certainly above any
00910      * outer join.  replace_vars_in_jointree tracks its location in the
00911      * jointree and uses PHVs or not appropriately.
00912      */
00913     parse->targetList = (List *)
00914         pullup_replace_vars((Node *) parse->targetList, &rvcontext);
00915     parse->returningList = (List *)
00916         pullup_replace_vars((Node *) parse->returningList, &rvcontext);
00917     replace_vars_in_jointree((Node *) parse->jointree, &rvcontext,
00918                              lowest_nulling_outer_join);
00919     Assert(parse->setOperations == NULL);
00920     parse->havingQual = pullup_replace_vars(parse->havingQual, &rvcontext);
00921 
00922     /*
00923      * Replace references in the translated_vars lists of appendrels. When
00924      * pulling up an appendrel member, we do not need PHVs in the list of the
00925      * parent appendrel --- there isn't any outer join between. Elsewhere, use
00926      * PHVs for safety.  (This analysis could be made tighter but it seems
00927      * unlikely to be worth much trouble.)
00928      */
00929     foreach(lc, root->append_rel_list)
00930     {
00931         AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
00932         bool        save_need_phvs = rvcontext.need_phvs;
00933 
00934         if (appinfo == containing_appendrel)
00935             rvcontext.need_phvs = false;
00936         appinfo->translated_vars = (List *)
00937             pullup_replace_vars((Node *) appinfo->translated_vars, &rvcontext);
00938         rvcontext.need_phvs = save_need_phvs;
00939     }
00940 
00941     /*
00942      * Replace references in the joinaliasvars lists of join RTEs.
00943      *
00944      * You might think that we could avoid using PHVs for alias vars of joins
00945      * below lowest_nulling_outer_join, but that doesn't work because the
00946      * alias vars could be referenced above that join; we need the PHVs to be
00947      * present in such references after the alias vars get flattened.  (It
00948      * might be worth trying to be smarter here, someday.)
00949      */
00950     foreach(lc, parse->rtable)
00951     {
00952         RangeTblEntry *otherrte = (RangeTblEntry *) lfirst(lc);
00953 
00954         if (otherrte->rtekind == RTE_JOIN)
00955             otherrte->joinaliasvars = (List *)
00956                 pullup_replace_vars((Node *) otherrte->joinaliasvars,
00957                                     &rvcontext);
00958     }
00959 
00960     /*
00961      * If the subquery had a LATERAL marker, propagate that to any of its
00962      * child RTEs that could possibly now contain lateral cross-references.
00963      * The children might or might not contain any actual lateral
00964      * cross-references, but we have to mark the pulled-up child RTEs so that
00965      * later planner stages will check for such.
00966      */
00967     if (rte->lateral)
00968     {
00969         foreach(lc, subquery->rtable)
00970         {
00971             RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(lc);
00972 
00973             switch (child_rte->rtekind)
00974             {
00975                 case RTE_SUBQUERY:
00976                 case RTE_FUNCTION:
00977                 case RTE_VALUES:
00978                     child_rte->lateral = true;
00979                     break;
00980                 case RTE_RELATION:
00981                 case RTE_JOIN:
00982                 case RTE_CTE:
00983                     /* these can't contain any lateral references */
00984                     break;
00985             }
00986         }
00987     }
00988 
00989     /*
00990      * Now append the adjusted rtable entries to upper query. (We hold off
00991      * until after fixing the upper rtable entries; no point in running that
00992      * code on the subquery ones too.)
00993      */
00994     parse->rtable = list_concat(parse->rtable, subquery->rtable);
00995 
00996     /*
00997      * Pull up any FOR UPDATE/SHARE markers, too.  (OffsetVarNodes already
00998      * adjusted the marker rtindexes, so just concat the lists.)
00999      */
01000     parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks);
01001 
01002     /*
01003      * We also have to fix the relid sets of any PlaceHolderVar nodes in the
01004      * parent query.  (This could perhaps be done by pullup_replace_vars(),
01005      * but it seems cleaner to use two passes.)  Note in particular that any
01006      * PlaceHolderVar nodes just created by pullup_replace_vars() will be
01007      * adjusted, so having created them with the subquery's varno is correct.
01008      *
01009      * Likewise, relids appearing in AppendRelInfo nodes have to be fixed. We
01010      * already checked that this won't require introducing multiple subrelids
01011      * into the single-slot AppendRelInfo structs.
01012      */
01013     if (parse->hasSubLinks || root->glob->lastPHId != 0 ||
01014         root->append_rel_list)
01015     {
01016         Relids      subrelids;
01017 
01018         subrelids = get_relids_in_jointree((Node *) subquery->jointree, false);
01019         substitute_multiple_relids((Node *) parse, varno, subrelids);
01020         fix_append_rel_relids(root->append_rel_list, varno, subrelids);
01021     }
01022 
01023     /*
01024      * And now add subquery's AppendRelInfos to our list.
01025      */
01026     root->append_rel_list = list_concat(root->append_rel_list,
01027                                         subroot->append_rel_list);
01028 
01029     /*
01030      * We don't have to do the equivalent bookkeeping for outer-join or
01031      * LATERAL info, because that hasn't been set up yet.  placeholder_list
01032      * likewise.
01033      */
01034     Assert(root->join_info_list == NIL);
01035     Assert(subroot->join_info_list == NIL);
01036     Assert(root->lateral_info_list == NIL);
01037     Assert(subroot->lateral_info_list == NIL);
01038     Assert(root->placeholder_list == NIL);
01039     Assert(subroot->placeholder_list == NIL);
01040 
01041     /*
01042      * Miscellaneous housekeeping.
01043      *
01044      * Although replace_rte_variables() faithfully updated parse->hasSubLinks
01045      * if it copied any SubLinks out of the subquery's targetlist, we still
01046      * could have SubLinks added to the query in the expressions of FUNCTION
01047      * and VALUES RTEs copied up from the subquery.  So it's necessary to copy
01048      * subquery->hasSubLinks anyway.  Perhaps this can be improved someday.
01049      */
01050     parse->hasSubLinks |= subquery->hasSubLinks;
01051 
01052     /*
01053      * subquery won't be pulled up if it hasAggs or hasWindowFuncs, so no work
01054      * needed on those flags
01055      */
01056 
01057     /*
01058      * Return the adjusted subquery jointree to replace the RangeTblRef entry
01059      * in parent's jointree.
01060      */
01061     return (Node *) subquery->jointree;
01062 }
01063 
01064 /*
01065  * pull_up_simple_union_all
01066  *      Pull up a single simple UNION ALL subquery.
01067  *
01068  * jtnode is a RangeTblRef that has been identified as a simple UNION ALL
01069  * subquery by pull_up_subqueries.  We pull up the leaf subqueries and
01070  * build an "append relation" for the union set.  The result value is just
01071  * jtnode, since we don't actually need to change the query jointree.
01072  */
01073 static Node *
01074 pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
01075 {
01076     int         varno = ((RangeTblRef *) jtnode)->rtindex;
01077     Query      *subquery = rte->subquery;
01078     int         rtoffset = list_length(root->parse->rtable);
01079     List       *rtable;
01080 
01081     /*
01082      * Make a modifiable copy of the subquery's rtable, so we can adjust
01083      * upper-level Vars in it.  There are no such Vars in the setOperations
01084      * tree proper, so fixing the rtable should be sufficient.
01085      */
01086     rtable = copyObject(subquery->rtable);
01087 
01088     /*
01089      * Upper-level vars in subquery are now one level closer to their parent
01090      * than before.  We don't have to worry about offsetting varnos, though,
01091      * because the UNION leaf queries can't cross-reference each other.
01092      */
01093     IncrementVarSublevelsUp_rtable(rtable, -1, 1);
01094 
01095     /*
01096      * If the UNION ALL subquery had a LATERAL marker, propagate that to all
01097      * its children.  The individual children might or might not contain any
01098      * actual lateral cross-references, but we have to mark the pulled-up
01099      * child RTEs so that later planner stages will check for such.
01100      */
01101     if (rte->lateral)
01102     {
01103         ListCell   *rt;
01104 
01105         foreach(rt, rtable)
01106         {
01107             RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(rt);
01108 
01109             Assert(child_rte->rtekind == RTE_SUBQUERY);
01110             child_rte->lateral = true;
01111         }
01112     }
01113 
01114     /*
01115      * Append child RTEs to parent rtable.
01116      */
01117     root->parse->rtable = list_concat(root->parse->rtable, rtable);
01118 
01119     /*
01120      * Recursively scan the subquery's setOperations tree and add
01121      * AppendRelInfo nodes for leaf subqueries to the parent's
01122      * append_rel_list.  Also apply pull_up_subqueries to the leaf subqueries.
01123      */
01124     Assert(subquery->setOperations);
01125     pull_up_union_leaf_queries(subquery->setOperations, root, varno, subquery,
01126                                rtoffset);
01127 
01128     /*
01129      * Mark the parent as an append relation.
01130      */
01131     rte->inh = true;
01132 
01133     return jtnode;
01134 }
01135 
01136 /*
01137  * pull_up_union_leaf_queries -- recursive guts of pull_up_simple_union_all
01138  *
01139  * Build an AppendRelInfo for each leaf query in the setop tree, and then
01140  * apply pull_up_subqueries to the leaf query.
01141  *
01142  * Note that setOpQuery is the Query containing the setOp node, whose tlist
01143  * contains references to all the setop output columns.  When called from
01144  * pull_up_simple_union_all, this is *not* the same as root->parse, which is
01145  * the parent Query we are pulling up into.
01146  *
01147  * parentRTindex is the appendrel parent's index in root->parse->rtable.
01148  *
01149  * The child RTEs have already been copied to the parent.  childRToffset
01150  * tells us where in the parent's range table they were copied.  When called
01151  * from flatten_simple_union_all, childRToffset is 0 since the child RTEs
01152  * were already in root->parse->rtable and no RT index adjustment is needed.
01153  */
01154 static void
01155 pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex,
01156                            Query *setOpQuery, int childRToffset)
01157 {
01158     if (IsA(setOp, RangeTblRef))
01159     {
01160         RangeTblRef *rtr = (RangeTblRef *) setOp;
01161         int         childRTindex;
01162         AppendRelInfo *appinfo;
01163 
01164         /*
01165          * Calculate the index in the parent's range table
01166          */
01167         childRTindex = childRToffset + rtr->rtindex;
01168 
01169         /*
01170          * Build a suitable AppendRelInfo, and attach to parent's list.
01171          */
01172         appinfo = makeNode(AppendRelInfo);
01173         appinfo->parent_relid = parentRTindex;
01174         appinfo->child_relid = childRTindex;
01175         appinfo->parent_reltype = InvalidOid;
01176         appinfo->child_reltype = InvalidOid;
01177         make_setop_translation_list(setOpQuery, childRTindex,
01178                                     &appinfo->translated_vars);
01179         appinfo->parent_reloid = InvalidOid;
01180         root->append_rel_list = lappend(root->append_rel_list, appinfo);
01181 
01182         /*
01183          * Recursively apply pull_up_subqueries to the new child RTE.  (We
01184          * must build the AppendRelInfo first, because this will modify it.)
01185          * Note that we can pass NULL for containing-join info even if we're
01186          * actually under an outer join, because the child's expressions
01187          * aren't going to propagate up to the join.
01188          */
01189         rtr = makeNode(RangeTblRef);
01190         rtr->rtindex = childRTindex;
01191         (void) pull_up_subqueries_recurse(root, (Node *) rtr,
01192                                           NULL, NULL, appinfo);
01193     }
01194     else if (IsA(setOp, SetOperationStmt))
01195     {
01196         SetOperationStmt *op = (SetOperationStmt *) setOp;
01197 
01198         /* Recurse to reach leaf queries */
01199         pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery,
01200                                    childRToffset);
01201         pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery,
01202                                    childRToffset);
01203     }
01204     else
01205     {
01206         elog(ERROR, "unrecognized node type: %d",
01207              (int) nodeTag(setOp));
01208     }
01209 }
01210 
01211 /*
01212  * make_setop_translation_list
01213  *    Build the list of translations from parent Vars to child Vars for
01214  *    a UNION ALL member.  (At this point it's just a simple list of
01215  *    referencing Vars, but if we succeed in pulling up the member
01216  *    subquery, the Vars will get replaced by pulled-up expressions.)
01217  */
01218 static void
01219 make_setop_translation_list(Query *query, Index newvarno,
01220                             List **translated_vars)
01221 {
01222     List       *vars = NIL;
01223     ListCell   *l;
01224 
01225     foreach(l, query->targetList)
01226     {
01227         TargetEntry *tle = (TargetEntry *) lfirst(l);
01228 
01229         if (tle->resjunk)
01230             continue;
01231 
01232         vars = lappend(vars, makeVarFromTargetEntry(newvarno, tle));
01233     }
01234 
01235     *translated_vars = vars;
01236 }
01237 
01238 /*
01239  * is_simple_subquery
01240  *    Check a subquery in the range table to see if it's simple enough
01241  *    to pull up into the parent query.
01242  *
01243  * rte is the RTE_SUBQUERY RangeTblEntry that contained the subquery.
01244  * (Note subquery is not necessarily equal to rte->subquery; it could be a
01245  * processed copy of that.)
01246  * lowest_outer_join is the lowest outer join above the subquery, or NULL.
01247  */
01248 static bool
01249 is_simple_subquery(Query *subquery, RangeTblEntry *rte,
01250                    JoinExpr *lowest_outer_join)
01251 {
01252     /*
01253      * Let's just make sure it's a valid subselect ...
01254      */
01255     if (!IsA(subquery, Query) ||
01256         subquery->commandType != CMD_SELECT ||
01257         subquery->utilityStmt != NULL)
01258         elog(ERROR, "subquery is bogus");
01259 
01260     /*
01261      * Can't currently pull up a query with setops (unless it's simple UNION
01262      * ALL, which is handled by a different code path). Maybe after querytree
01263      * redesign...
01264      */
01265     if (subquery->setOperations)
01266         return false;
01267 
01268     /*
01269      * Can't pull up a subquery involving grouping, aggregation, sorting,
01270      * limiting, or WITH.  (XXX WITH could possibly be allowed later)
01271      *
01272      * We also don't pull up a subquery that has explicit FOR UPDATE/SHARE
01273      * clauses, because pullup would cause the locking to occur semantically
01274      * higher than it should.  Implicit FOR UPDATE/SHARE is okay because in
01275      * that case the locking was originally declared in the upper query
01276      * anyway.
01277      */
01278     if (subquery->hasAggs ||
01279         subquery->hasWindowFuncs ||
01280         subquery->groupClause ||
01281         subquery->havingQual ||
01282         subquery->sortClause ||
01283         subquery->distinctClause ||
01284         subquery->limitOffset ||
01285         subquery->limitCount ||
01286         subquery->hasForUpdate ||
01287         subquery->cteList)
01288         return false;
01289 
01290     /*
01291      * Don't pull up if the RTE represents a security-barrier view; we couldn't
01292      * prevent information leakage once the RTE's Vars are scattered about in
01293      * the upper query.
01294      */
01295     if (rte->security_barrier)
01296         return false;
01297 
01298     /*
01299      * If the subquery is LATERAL, and we're below any outer join, and the
01300      * subquery contains lateral references to rels outside the outer join,
01301      * don't pull up.  Doing so would risk creating outer-join quals that
01302      * contain references to rels outside the outer join, which is a semantic
01303      * mess that doesn't seem worth addressing at the moment.
01304      */
01305     if (rte->lateral && lowest_outer_join != NULL)
01306     {
01307         Relids  lvarnos = pull_varnos_of_level((Node *) subquery, 1);
01308         Relids  jvarnos = get_relids_in_jointree((Node *) lowest_outer_join,
01309                                                  true);
01310 
01311         if (!bms_is_subset(lvarnos, jvarnos))
01312             return false;
01313     }
01314 
01315     /*
01316      * Don't pull up a subquery that has any set-returning functions in its
01317      * targetlist.  Otherwise we might well wind up inserting set-returning
01318      * functions into places where they mustn't go, such as quals of higher
01319      * queries.
01320      */
01321     if (expression_returns_set((Node *) subquery->targetList))
01322         return false;
01323 
01324     /*
01325      * Don't pull up a subquery that has any volatile functions in its
01326      * targetlist.  Otherwise we might introduce multiple evaluations of these
01327      * functions, if they get copied to multiple places in the upper query,
01328      * leading to surprising results.  (Note: the PlaceHolderVar mechanism
01329      * doesn't quite guarantee single evaluation; else we could pull up anyway
01330      * and just wrap such items in PlaceHolderVars ...)
01331      */
01332     if (contain_volatile_functions((Node *) subquery->targetList))
01333         return false;
01334 
01335     /*
01336      * Hack: don't try to pull up a subquery with an empty jointree.
01337      * query_planner() will correctly generate a Result plan for a jointree
01338      * that's totally empty, but I don't think the right things happen if an
01339      * empty FromExpr appears lower down in a jointree.  It would pose a
01340      * problem for the PlaceHolderVar mechanism too, since we'd have no way to
01341      * identify where to evaluate a PHV coming out of the subquery. Not worth
01342      * working hard on this, just to collapse SubqueryScan/Result into Result;
01343      * especially since the SubqueryScan can often be optimized away by
01344      * setrefs.c anyway.
01345      */
01346     if (subquery->jointree->fromlist == NIL)
01347         return false;
01348 
01349     return true;
01350 }
01351 
01352 /*
01353  * is_simple_union_all
01354  *    Check a subquery to see if it's a simple UNION ALL.
01355  *
01356  * We require all the setops to be UNION ALL (no mixing) and there can't be
01357  * any datatype coercions involved, ie, all the leaf queries must emit the
01358  * same datatypes.
01359  */
01360 static bool
01361 is_simple_union_all(Query *subquery)
01362 {
01363     SetOperationStmt *topop;
01364 
01365     /* Let's just make sure it's a valid subselect ... */
01366     if (!IsA(subquery, Query) ||
01367         subquery->commandType != CMD_SELECT ||
01368         subquery->utilityStmt != NULL)
01369         elog(ERROR, "subquery is bogus");
01370 
01371     /* Is it a set-operation query at all? */
01372     topop = (SetOperationStmt *) subquery->setOperations;
01373     if (!topop)
01374         return false;
01375     Assert(IsA(topop, SetOperationStmt));
01376 
01377     /* Can't handle ORDER BY, LIMIT/OFFSET, locking, or WITH */
01378     if (subquery->sortClause ||
01379         subquery->limitOffset ||
01380         subquery->limitCount ||
01381         subquery->rowMarks ||
01382         subquery->cteList)
01383         return false;
01384 
01385     /* Recursively check the tree of set operations */
01386     return is_simple_union_all_recurse((Node *) topop, subquery,
01387                                        topop->colTypes);
01388 }
01389 
01390 static bool
01391 is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
01392 {
01393     if (IsA(setOp, RangeTblRef))
01394     {
01395         RangeTblRef *rtr = (RangeTblRef *) setOp;
01396         RangeTblEntry *rte = rt_fetch(rtr->rtindex, setOpQuery->rtable);
01397         Query      *subquery = rte->subquery;
01398 
01399         Assert(subquery != NULL);
01400 
01401         /* Leaf nodes are OK if they match the toplevel column types */
01402         /* We don't have to compare typmods or collations here */
01403         return tlist_same_datatypes(subquery->targetList, colTypes, true);
01404     }
01405     else if (IsA(setOp, SetOperationStmt))
01406     {
01407         SetOperationStmt *op = (SetOperationStmt *) setOp;
01408 
01409         /* Must be UNION ALL */
01410         if (op->op != SETOP_UNION || !op->all)
01411             return false;
01412 
01413         /* Recurse to check inputs */
01414         return is_simple_union_all_recurse(op->larg, setOpQuery, colTypes) &&
01415             is_simple_union_all_recurse(op->rarg, setOpQuery, colTypes);
01416     }
01417     else
01418     {
01419         elog(ERROR, "unrecognized node type: %d",
01420              (int) nodeTag(setOp));
01421         return false;           /* keep compiler quiet */
01422     }
01423 }
01424 
01425 /*
01426  * is_safe_append_member
01427  *    Check a subquery that is a leaf of a UNION ALL appendrel to see if it's
01428  *    safe to pull up.
01429  */
01430 static bool
01431 is_safe_append_member(Query *subquery)
01432 {
01433     FromExpr   *jtnode;
01434 
01435     /*
01436      * It's only safe to pull up the child if its jointree contains exactly
01437      * one RTE, else the AppendRelInfo data structure breaks. The one base RTE
01438      * could be buried in several levels of FromExpr, however.
01439      *
01440      * Also, the child can't have any WHERE quals because there's no place to
01441      * put them in an appendrel.  (This is a bit annoying...) If we didn't
01442      * need to check this, we'd just test whether get_relids_in_jointree()
01443      * yields a singleton set, to be more consistent with the coding of
01444      * fix_append_rel_relids().
01445      */
01446     jtnode = subquery->jointree;
01447     while (IsA(jtnode, FromExpr))
01448     {
01449         if (jtnode->quals != NULL)
01450             return false;
01451         if (list_length(jtnode->fromlist) != 1)
01452             return false;
01453         jtnode = linitial(jtnode->fromlist);
01454     }
01455     if (!IsA(jtnode, RangeTblRef))
01456         return false;
01457 
01458     return true;
01459 }
01460 
01461 /*
01462  * Helper routine for pull_up_subqueries: do pullup_replace_vars on every
01463  * expression in the jointree, without changing the jointree structure itself.
01464  * Ugly, but there's no other way...
01465  *
01466  * If we are at or below lowest_nulling_outer_join, we can suppress use of
01467  * PlaceHolderVars wrapped around the replacement expressions.
01468  */
01469 static void
01470 replace_vars_in_jointree(Node *jtnode,
01471                          pullup_replace_vars_context *context,
01472                          JoinExpr *lowest_nulling_outer_join)
01473 {
01474     if (jtnode == NULL)
01475         return;
01476     if (IsA(jtnode, RangeTblRef))
01477     {
01478         /*
01479          * If the RangeTblRef refers to a LATERAL subquery (that isn't the
01480          * same subquery we're pulling up), it might contain references to the
01481          * target subquery, which we must replace.  We drive this from the
01482          * jointree scan, rather than a scan of the rtable, for a couple of
01483          * reasons: we can avoid processing no-longer-referenced RTEs, and we
01484          * can use the appropriate setting of need_phvs depending on whether
01485          * the RTE is above possibly-nulling outer joins or not.
01486          */
01487         int         varno = ((RangeTblRef *) jtnode)->rtindex;
01488 
01489         if (varno != context->varno)    /* ignore target subquery itself */
01490         {
01491             RangeTblEntry *rte = rt_fetch(varno, context->root->parse->rtable);
01492 
01493             Assert(rte != context->target_rte);
01494             if (rte->lateral)
01495             {
01496                 switch (rte->rtekind)
01497                 {
01498                     case RTE_SUBQUERY:
01499                         rte->subquery =
01500                             pullup_replace_vars_subquery(rte->subquery,
01501                                                          context);
01502                         break;
01503                     case RTE_FUNCTION:
01504                         rte->funcexpr =
01505                             pullup_replace_vars(rte->funcexpr,
01506                                                 context);
01507                         break;
01508                     case RTE_VALUES:
01509                         rte->values_lists = (List *)
01510                             pullup_replace_vars((Node *) rte->values_lists,
01511                                                 context);
01512                         break;
01513                     case RTE_RELATION:
01514                     case RTE_JOIN:
01515                     case RTE_CTE:
01516                         /* these shouldn't be marked LATERAL */
01517                         Assert(false);
01518                         break;
01519                 }
01520             }
01521         }
01522     }
01523     else if (IsA(jtnode, FromExpr))
01524     {
01525         FromExpr   *f = (FromExpr *) jtnode;
01526         ListCell   *l;
01527 
01528         foreach(l, f->fromlist)
01529             replace_vars_in_jointree(lfirst(l), context,
01530                                      lowest_nulling_outer_join);
01531         f->quals = pullup_replace_vars(f->quals, context);
01532     }
01533     else if (IsA(jtnode, JoinExpr))
01534     {
01535         JoinExpr   *j = (JoinExpr *) jtnode;
01536         bool        save_need_phvs = context->need_phvs;
01537 
01538         if (j == lowest_nulling_outer_join)
01539         {
01540             /* no more PHVs in or below this join */
01541             context->need_phvs = false;
01542             lowest_nulling_outer_join = NULL;
01543         }
01544         replace_vars_in_jointree(j->larg, context, lowest_nulling_outer_join);
01545         replace_vars_in_jointree(j->rarg, context, lowest_nulling_outer_join);
01546         j->quals = pullup_replace_vars(j->quals, context);
01547 
01548         /*
01549          * We don't bother to update the colvars list, since it won't be used
01550          * again ...
01551          */
01552         context->need_phvs = save_need_phvs;
01553     }
01554     else
01555         elog(ERROR, "unrecognized node type: %d",
01556              (int) nodeTag(jtnode));
01557 }
01558 
01559 /*
01560  * Apply pullup variable replacement throughout an expression tree
01561  *
01562  * Returns a modified copy of the tree, so this can't be used where we
01563  * need to do in-place replacement.
01564  */
01565 static Node *
01566 pullup_replace_vars(Node *expr, pullup_replace_vars_context *context)
01567 {
01568     return replace_rte_variables(expr,
01569                                  context->varno, 0,
01570                                  pullup_replace_vars_callback,
01571                                  (void *) context,
01572                                  context->outer_hasSubLinks);
01573 }
01574 
01575 static Node *
01576 pullup_replace_vars_callback(Var *var,
01577                              replace_rte_variables_context *context)
01578 {
01579     pullup_replace_vars_context *rcon = (pullup_replace_vars_context *) context->callback_arg;
01580     int         varattno = var->varattno;
01581     Node       *newnode;
01582 
01583     /*
01584      * If PlaceHolderVars are needed, we cache the modified expressions in
01585      * rcon->rv_cache[].  This is not in hopes of any material speed gain
01586      * within this function, but to avoid generating identical PHVs with
01587      * different IDs.  That would result in duplicate evaluations at runtime,
01588      * and possibly prevent optimizations that rely on recognizing different
01589      * references to the same subquery output as being equal().  So it's worth
01590      * a bit of extra effort to avoid it.
01591      */
01592     if (rcon->need_phvs &&
01593         varattno >= InvalidAttrNumber &&
01594         varattno <= list_length(rcon->targetlist) &&
01595         rcon->rv_cache[varattno] != NULL)
01596     {
01597         /* Just copy the entry and fall through to adjust its varlevelsup */
01598         newnode = copyObject(rcon->rv_cache[varattno]);
01599     }
01600     else if (varattno == InvalidAttrNumber)
01601     {
01602         /* Must expand whole-tuple reference into RowExpr */
01603         RowExpr    *rowexpr;
01604         List       *colnames;
01605         List       *fields;
01606         bool        save_need_phvs = rcon->need_phvs;
01607         int         save_sublevelsup = context->sublevels_up;
01608 
01609         /*
01610          * If generating an expansion for a var of a named rowtype (ie, this
01611          * is a plain relation RTE), then we must include dummy items for
01612          * dropped columns.  If the var is RECORD (ie, this is a JOIN), then
01613          * omit dropped columns. Either way, attach column names to the
01614          * RowExpr for use of ruleutils.c.
01615          *
01616          * In order to be able to cache the results, we always generate the
01617          * expansion with varlevelsup = 0, and then adjust if needed.
01618          */
01619         expandRTE(rcon->target_rte,
01620                   var->varno, 0 /* not varlevelsup */ , var->location,
01621                   (var->vartype != RECORDOID),
01622                   &colnames, &fields);
01623         /* Adjust the generated per-field Vars, but don't insert PHVs */
01624         rcon->need_phvs = false;
01625         context->sublevels_up = 0;      /* to match the expandRTE output */
01626         fields = (List *) replace_rte_variables_mutator((Node *) fields,
01627                                                         context);
01628         rcon->need_phvs = save_need_phvs;
01629         context->sublevels_up = save_sublevelsup;
01630 
01631         rowexpr = makeNode(RowExpr);
01632         rowexpr->args = fields;
01633         rowexpr->row_typeid = var->vartype;
01634         rowexpr->row_format = COERCE_IMPLICIT_CAST;
01635         rowexpr->colnames = colnames;
01636         rowexpr->location = var->location;
01637         newnode = (Node *) rowexpr;
01638 
01639         /*
01640          * Insert PlaceHolderVar if needed.  Notice that we are wrapping one
01641          * PlaceHolderVar around the whole RowExpr, rather than putting one
01642          * around each element of the row.  This is because we need the
01643          * expression to yield NULL, not ROW(NULL,NULL,...) when it is forced
01644          * to null by an outer join.
01645          */
01646         if (rcon->need_phvs)
01647         {
01648             /* RowExpr is certainly not strict, so always need PHV */
01649             newnode = (Node *)
01650                 make_placeholder_expr(rcon->root,
01651                                       (Expr *) newnode,
01652                                       bms_make_singleton(rcon->varno));
01653             /* cache it with the PHV, and with varlevelsup still zero */
01654             rcon->rv_cache[InvalidAttrNumber] = copyObject(newnode);
01655         }
01656     }
01657     else
01658     {
01659         /* Normal case referencing one targetlist element */
01660         TargetEntry *tle = get_tle_by_resno(rcon->targetlist, varattno);
01661 
01662         if (tle == NULL)        /* shouldn't happen */
01663             elog(ERROR, "could not find attribute %d in subquery targetlist",
01664                  varattno);
01665 
01666         /* Make a copy of the tlist item to return */
01667         newnode = copyObject(tle->expr);
01668 
01669         /* Insert PlaceHolderVar if needed */
01670         if (rcon->need_phvs)
01671         {
01672             bool        wrap;
01673 
01674             if (newnode && IsA(newnode, Var) &&
01675                 ((Var *) newnode)->varlevelsup == 0)
01676             {
01677                 /* Simple Vars always escape being wrapped */
01678                 wrap = false;
01679             }
01680             else if (newnode && IsA(newnode, PlaceHolderVar) &&
01681                      ((PlaceHolderVar *) newnode)->phlevelsup == 0)
01682             {
01683                 /* No need to wrap a PlaceHolderVar with another one, either */
01684                 wrap = false;
01685             }
01686             else if (rcon->wrap_non_vars)
01687             {
01688                 /* Wrap all non-Vars in a PlaceHolderVar */
01689                 wrap = true;
01690             }
01691             else
01692             {
01693                 /*
01694                  * If it contains a Var of current level, and does not contain
01695                  * any non-strict constructs, then it's certainly nullable so
01696                  * we don't need to insert a PlaceHolderVar.
01697                  *
01698                  * This analysis could be tighter: in particular, a non-strict
01699                  * construct hidden within a lower-level PlaceHolderVar is not
01700                  * reason to add another PHV.  But for now it doesn't seem
01701                  * worth the code to be more exact.
01702                  *
01703                  * Note: in future maybe we should insert a PlaceHolderVar
01704                  * anyway, if the tlist item is expensive to evaluate?
01705                  */
01706                 if (contain_vars_of_level((Node *) newnode, 0) &&
01707                     !contain_nonstrict_functions((Node *) newnode))
01708                 {
01709                     /* No wrap needed */
01710                     wrap = false;
01711                 }
01712                 else
01713                 {
01714                     /* Else wrap it in a PlaceHolderVar */
01715                     wrap = true;
01716                 }
01717             }
01718 
01719             if (wrap)
01720                 newnode = (Node *)
01721                     make_placeholder_expr(rcon->root,
01722                                           (Expr *) newnode,
01723                                           bms_make_singleton(rcon->varno));
01724 
01725             /*
01726              * Cache it if possible (ie, if the attno is in range, which it
01727              * probably always should be).  We can cache the value even if we
01728              * decided we didn't need a PHV, since this result will be
01729              * suitable for any request that has need_phvs.
01730              */
01731             if (varattno > InvalidAttrNumber &&
01732                 varattno <= list_length(rcon->targetlist))
01733                 rcon->rv_cache[varattno] = copyObject(newnode);
01734         }
01735     }
01736 
01737     /* Must adjust varlevelsup if tlist item is from higher query */
01738     if (var->varlevelsup > 0)
01739         IncrementVarSublevelsUp(newnode, var->varlevelsup, 0);
01740 
01741     return newnode;
01742 }
01743 
01744 /*
01745  * Apply pullup variable replacement to a subquery
01746  *
01747  * This needs to be different from pullup_replace_vars() because
01748  * replace_rte_variables will think that it shouldn't increment sublevels_up
01749  * before entering the Query; so we need to call it with sublevels_up == 1.
01750  */
01751 static Query *
01752 pullup_replace_vars_subquery(Query *query,
01753                              pullup_replace_vars_context *context)
01754 {
01755     Assert(IsA(query, Query));
01756     return (Query *) replace_rte_variables((Node *) query,
01757                                            context->varno, 1,
01758                                            pullup_replace_vars_callback,
01759                                            (void *) context,
01760                                            NULL);
01761 }
01762 
01763 
01764 /*
01765  * flatten_simple_union_all
01766  *      Try to optimize top-level UNION ALL structure into an appendrel
01767  *
01768  * If a query's setOperations tree consists entirely of simple UNION ALL
01769  * operations, flatten it into an append relation, which we can process more
01770  * intelligently than the general setops case.  Otherwise, do nothing.
01771  *
01772  * In most cases, this can succeed only for a top-level query, because for a
01773  * subquery in FROM, the parent query's invocation of pull_up_subqueries would
01774  * already have flattened the UNION via pull_up_simple_union_all.  But there
01775  * are a few cases we can support here but not in that code path, for example
01776  * when the subquery also contains ORDER BY.
01777  */
01778 void
01779 flatten_simple_union_all(PlannerInfo *root)
01780 {
01781     Query      *parse = root->parse;
01782     SetOperationStmt *topop;
01783     Node       *leftmostjtnode;
01784     int         leftmostRTI;
01785     RangeTblEntry *leftmostRTE;
01786     int         childRTI;
01787     RangeTblEntry *childRTE;
01788     RangeTblRef *rtr;
01789 
01790     /* Shouldn't be called unless query has setops */
01791     topop = (SetOperationStmt *) parse->setOperations;
01792     Assert(topop && IsA(topop, SetOperationStmt));
01793 
01794     /* Can't optimize away a recursive UNION */
01795     if (root->hasRecursion)
01796         return;
01797 
01798     /*
01799      * Recursively check the tree of set operations.  If not all UNION ALL
01800      * with identical column types, punt.
01801      */
01802     if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
01803         return;
01804 
01805     /*
01806      * Locate the leftmost leaf query in the setops tree.  The upper query's
01807      * Vars all refer to this RTE (see transformSetOperationStmt).
01808      */
01809     leftmostjtnode = topop->larg;
01810     while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
01811         leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;
01812     Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
01813     leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
01814     leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
01815     Assert(leftmostRTE->rtekind == RTE_SUBQUERY);
01816 
01817     /*
01818      * Make a copy of the leftmost RTE and add it to the rtable.  This copy
01819      * will represent the leftmost leaf query in its capacity as a member of
01820      * the appendrel.  The original will represent the appendrel as a whole.
01821      * (We must do things this way because the upper query's Vars have to be
01822      * seen as referring to the whole appendrel.)
01823      */
01824     childRTE = copyObject(leftmostRTE);
01825     parse->rtable = lappend(parse->rtable, childRTE);
01826     childRTI = list_length(parse->rtable);
01827 
01828     /* Modify the setops tree to reference the child copy */
01829     ((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;
01830 
01831     /* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
01832     leftmostRTE->inh = true;
01833 
01834     /*
01835      * Form a RangeTblRef for the appendrel, and insert it into FROM.  The top
01836      * Query of a setops tree should have had an empty FromClause initially.
01837      */
01838     rtr = makeNode(RangeTblRef);
01839     rtr->rtindex = leftmostRTI;
01840     Assert(parse->jointree->fromlist == NIL);
01841     parse->jointree->fromlist = list_make1(rtr);
01842 
01843     /*
01844      * Now pretend the query has no setops.  We must do this before trying to
01845      * do subquery pullup, because of Assert in pull_up_simple_subquery.
01846      */
01847     parse->setOperations = NULL;
01848 
01849     /*
01850      * Build AppendRelInfo information, and apply pull_up_subqueries to the
01851      * leaf queries of the UNION ALL.  (We must do that now because they
01852      * weren't previously referenced by the jointree, and so were missed by
01853      * the main invocation of pull_up_subqueries.)
01854      */
01855     pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
01856 }
01857 
01858 
01859 /*
01860  * reduce_outer_joins
01861  *      Attempt to reduce outer joins to plain inner joins.
01862  *
01863  * The idea here is that given a query like
01864  *      SELECT ... FROM a LEFT JOIN b ON (...) WHERE b.y = 42;
01865  * we can reduce the LEFT JOIN to a plain JOIN if the "=" operator in WHERE
01866  * is strict.  The strict operator will always return NULL, causing the outer
01867  * WHERE to fail, on any row where the LEFT JOIN filled in NULLs for b's
01868  * columns.  Therefore, there's no need for the join to produce null-extended
01869  * rows in the first place --- which makes it a plain join not an outer join.
01870  * (This scenario may not be very likely in a query written out by hand, but
01871  * it's reasonably likely when pushing quals down into complex views.)
01872  *
01873  * More generally, an outer join can be reduced in strength if there is a
01874  * strict qual above it in the qual tree that constrains a Var from the
01875  * nullable side of the join to be non-null.  (For FULL joins this applies
01876  * to each side separately.)
01877  *
01878  * Another transformation we apply here is to recognize cases like
01879  *      SELECT ... FROM a LEFT JOIN b ON (a.x = b.y) WHERE b.y IS NULL;
01880  * If the join clause is strict for b.y, then only null-extended rows could
01881  * pass the upper WHERE, and we can conclude that what the query is really
01882  * specifying is an anti-semijoin.  We change the join type from JOIN_LEFT
01883  * to JOIN_ANTI.  The IS NULL clause then becomes redundant, and must be
01884  * removed to prevent bogus selectivity calculations, but we leave it to
01885  * distribute_qual_to_rels to get rid of such clauses.
01886  *
01887  * Also, we get rid of JOIN_RIGHT cases by flipping them around to become
01888  * JOIN_LEFT.  This saves some code here and in some later planner routines,
01889  * but the main reason to do it is to not need to invent a JOIN_REVERSE_ANTI
01890  * join type.
01891  *
01892  * To ease recognition of strict qual clauses, we require this routine to be
01893  * run after expression preprocessing (i.e., qual canonicalization and JOIN
01894  * alias-var expansion).
01895  */
01896 void
01897 reduce_outer_joins(PlannerInfo *root)
01898 {
01899     reduce_outer_joins_state *state;
01900 
01901     /*
01902      * To avoid doing strictness checks on more quals than necessary, we want
01903      * to stop descending the jointree as soon as there are no outer joins
01904      * below our current point.  This consideration forces a two-pass process.
01905      * The first pass gathers information about which base rels appear below
01906      * each side of each join clause, and about whether there are outer
01907      * join(s) below each side of each join clause. The second pass examines
01908      * qual clauses and changes join types as it descends the tree.
01909      */
01910     state = reduce_outer_joins_pass1((Node *) root->parse->jointree);
01911 
01912     /* planner.c shouldn't have called me if no outer joins */
01913     if (state == NULL || !state->contains_outer)
01914         elog(ERROR, "so where are the outer joins?");
01915 
01916     reduce_outer_joins_pass2((Node *) root->parse->jointree,
01917                              state, root, NULL, NIL, NIL);
01918 }
01919 
01920 /*
01921  * reduce_outer_joins_pass1 - phase 1 data collection
01922  *
01923  * Returns a state node describing the given jointree node.
01924  */
01925 static reduce_outer_joins_state *
01926 reduce_outer_joins_pass1(Node *jtnode)
01927 {
01928     reduce_outer_joins_state *result;
01929 
01930     result = (reduce_outer_joins_state *)
01931         palloc(sizeof(reduce_outer_joins_state));
01932     result->relids = NULL;
01933     result->contains_outer = false;
01934     result->sub_states = NIL;
01935 
01936     if (jtnode == NULL)
01937         return result;
01938     if (IsA(jtnode, RangeTblRef))
01939     {
01940         int         varno = ((RangeTblRef *) jtnode)->rtindex;
01941 
01942         result->relids = bms_make_singleton(varno);
01943     }
01944     else if (IsA(jtnode, FromExpr))
01945     {
01946         FromExpr   *f = (FromExpr *) jtnode;
01947         ListCell   *l;
01948 
01949         foreach(l, f->fromlist)
01950         {
01951             reduce_outer_joins_state *sub_state;
01952 
01953             sub_state = reduce_outer_joins_pass1(lfirst(l));
01954             result->relids = bms_add_members(result->relids,
01955                                              sub_state->relids);
01956             result->contains_outer |= sub_state->contains_outer;
01957             result->sub_states = lappend(result->sub_states, sub_state);
01958         }
01959     }
01960     else if (IsA(jtnode, JoinExpr))
01961     {
01962         JoinExpr   *j = (JoinExpr *) jtnode;
01963         reduce_outer_joins_state *sub_state;
01964 
01965         /* join's own RT index is not wanted in result->relids */
01966         if (IS_OUTER_JOIN(j->jointype))
01967             result->contains_outer = true;
01968 
01969         sub_state = reduce_outer_joins_pass1(j->larg);
01970         result->relids = bms_add_members(result->relids,
01971                                          sub_state->relids);
01972         result->contains_outer |= sub_state->contains_outer;
01973         result->sub_states = lappend(result->sub_states, sub_state);
01974 
01975         sub_state = reduce_outer_joins_pass1(j->rarg);
01976         result->relids = bms_add_members(result->relids,
01977                                          sub_state->relids);
01978         result->contains_outer |= sub_state->contains_outer;
01979         result->sub_states = lappend(result->sub_states, sub_state);
01980     }
01981     else
01982         elog(ERROR, "unrecognized node type: %d",
01983              (int) nodeTag(jtnode));
01984     return result;
01985 }
01986 
01987 /*
01988  * reduce_outer_joins_pass2 - phase 2 processing
01989  *
01990  *  jtnode: current jointree node
01991  *  state: state data collected by phase 1 for this node
01992  *  root: toplevel planner state
01993  *  nonnullable_rels: set of base relids forced non-null by upper quals
01994  *  nonnullable_vars: list of Vars forced non-null by upper quals
01995  *  forced_null_vars: list of Vars forced null by upper quals
01996  */
01997 static void
01998 reduce_outer_joins_pass2(Node *jtnode,
01999                          reduce_outer_joins_state *state,
02000                          PlannerInfo *root,
02001                          Relids nonnullable_rels,
02002                          List *nonnullable_vars,
02003                          List *forced_null_vars)
02004 {
02005     /*
02006      * pass 2 should never descend as far as an empty subnode or base rel,
02007      * because it's only called on subtrees marked as contains_outer.
02008      */
02009     if (jtnode == NULL)
02010         elog(ERROR, "reached empty jointree");
02011     if (IsA(jtnode, RangeTblRef))
02012         elog(ERROR, "reached base rel");
02013     else if (IsA(jtnode, FromExpr))
02014     {
02015         FromExpr   *f = (FromExpr *) jtnode;
02016         ListCell   *l;
02017         ListCell   *s;
02018         Relids      pass_nonnullable_rels;
02019         List       *pass_nonnullable_vars;
02020         List       *pass_forced_null_vars;
02021 
02022         /* Scan quals to see if we can add any constraints */
02023         pass_nonnullable_rels = find_nonnullable_rels(f->quals);
02024         pass_nonnullable_rels = bms_add_members(pass_nonnullable_rels,
02025                                                 nonnullable_rels);
02026         /* NB: we rely on list_concat to not damage its second argument */
02027         pass_nonnullable_vars = find_nonnullable_vars(f->quals);
02028         pass_nonnullable_vars = list_concat(pass_nonnullable_vars,
02029                                             nonnullable_vars);
02030         pass_forced_null_vars = find_forced_null_vars(f->quals);
02031         pass_forced_null_vars = list_concat(pass_forced_null_vars,
02032                                             forced_null_vars);
02033         /* And recurse --- but only into interesting subtrees */
02034         Assert(list_length(f->fromlist) == list_length(state->sub_states));
02035         forboth(l, f->fromlist, s, state->sub_states)
02036         {
02037             reduce_outer_joins_state *sub_state = lfirst(s);
02038 
02039             if (sub_state->contains_outer)
02040                 reduce_outer_joins_pass2(lfirst(l), sub_state, root,
02041                                          pass_nonnullable_rels,
02042                                          pass_nonnullable_vars,
02043                                          pass_forced_null_vars);
02044         }
02045         bms_free(pass_nonnullable_rels);
02046         /* can't so easily clean up var lists, unfortunately */
02047     }
02048     else if (IsA(jtnode, JoinExpr))
02049     {
02050         JoinExpr   *j = (JoinExpr *) jtnode;
02051         int         rtindex = j->rtindex;
02052         JoinType    jointype = j->jointype;
02053         reduce_outer_joins_state *left_state = linitial(state->sub_states);
02054         reduce_outer_joins_state *right_state = lsecond(state->sub_states);
02055         List       *local_nonnullable_vars = NIL;
02056         bool        computed_local_nonnullable_vars = false;
02057 
02058         /* Can we simplify this join? */
02059         switch (jointype)
02060         {
02061             case JOIN_INNER:
02062                 break;
02063             case JOIN_LEFT:
02064                 if (bms_overlap(nonnullable_rels, right_state->relids))
02065                     jointype = JOIN_INNER;
02066                 break;
02067             case JOIN_RIGHT:
02068                 if (bms_overlap(nonnullable_rels, left_state->relids))
02069                     jointype = JOIN_INNER;
02070                 break;
02071             case JOIN_FULL:
02072                 if (bms_overlap(nonnullable_rels, left_state->relids))
02073                 {
02074                     if (bms_overlap(nonnullable_rels, right_state->relids))
02075                         jointype = JOIN_INNER;
02076                     else
02077                         jointype = JOIN_LEFT;
02078                 }
02079                 else
02080                 {
02081                     if (bms_overlap(nonnullable_rels, right_state->relids))
02082                         jointype = JOIN_RIGHT;
02083                 }
02084                 break;
02085             case JOIN_SEMI:
02086             case JOIN_ANTI:
02087 
02088                 /*
02089                  * These could only have been introduced by pull_up_sublinks,
02090                  * so there's no way that upper quals could refer to their
02091                  * righthand sides, and no point in checking.
02092                  */
02093                 break;
02094             default:
02095                 elog(ERROR, "unrecognized join type: %d",
02096                      (int) jointype);
02097                 break;
02098         }
02099 
02100         /*
02101          * Convert JOIN_RIGHT to JOIN_LEFT.  Note that in the case where we
02102          * reduced JOIN_FULL to JOIN_RIGHT, this will mean the JoinExpr no
02103          * longer matches the internal ordering of any CoalesceExpr's built to
02104          * represent merged join variables.  We don't care about that at
02105          * present, but be wary of it ...
02106          */
02107         if (jointype == JOIN_RIGHT)
02108         {
02109             Node       *tmparg;
02110 
02111             tmparg = j->larg;
02112             j->larg = j->rarg;
02113             j->rarg = tmparg;
02114             jointype = JOIN_LEFT;
02115             right_state = linitial(state->sub_states);
02116             left_state = lsecond(state->sub_states);
02117         }
02118 
02119         /*
02120          * See if we can reduce JOIN_LEFT to JOIN_ANTI.  This is the case if
02121          * the join's own quals are strict for any var that was forced null by
02122          * higher qual levels.  NOTE: there are other ways that we could
02123          * detect an anti-join, in particular if we were to check whether Vars
02124          * coming from the RHS must be non-null because of table constraints.
02125          * That seems complicated and expensive though (in particular, one
02126          * would have to be wary of lower outer joins). For the moment this
02127          * seems sufficient.
02128          */
02129         if (jointype == JOIN_LEFT)
02130         {
02131             List       *overlap;
02132 
02133             local_nonnullable_vars = find_nonnullable_vars(j->quals);
02134             computed_local_nonnullable_vars = true;
02135 
02136             /*
02137              * It's not sufficient to check whether local_nonnullable_vars and
02138              * forced_null_vars overlap: we need to know if the overlap
02139              * includes any RHS variables.
02140              */
02141             overlap = list_intersection(local_nonnullable_vars,
02142                                         forced_null_vars);
02143             if (overlap != NIL &&
02144                 bms_overlap(pull_varnos((Node *) overlap),
02145                             right_state->relids))
02146                 jointype = JOIN_ANTI;
02147         }
02148 
02149         /* Apply the jointype change, if any, to both jointree node and RTE */
02150         if (rtindex && jointype != j->jointype)
02151         {
02152             RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable);
02153 
02154             Assert(rte->rtekind == RTE_JOIN);
02155             Assert(rte->jointype == j->jointype);
02156             rte->jointype = jointype;
02157         }
02158         j->jointype = jointype;
02159 
02160         /* Only recurse if there's more to do below here */
02161         if (left_state->contains_outer || right_state->contains_outer)
02162         {
02163             Relids      local_nonnullable_rels;
02164             List       *local_forced_null_vars;
02165             Relids      pass_nonnullable_rels;
02166             List       *pass_nonnullable_vars;
02167             List       *pass_forced_null_vars;
02168 
02169             /*
02170              * If this join is (now) inner, we can add any constraints its
02171              * quals provide to those we got from above.  But if it is outer,
02172              * we can pass down the local constraints only into the nullable
02173              * side, because an outer join never eliminates any rows from its
02174              * non-nullable side.  Also, there is no point in passing upper
02175              * constraints into the nullable side, since if there were any
02176              * we'd have been able to reduce the join.  (In the case of upper
02177              * forced-null constraints, we *must not* pass them into the
02178              * nullable side --- they either applied here, or not.) The upshot
02179              * is that we pass either the local or the upper constraints,
02180              * never both, to the children of an outer join.
02181              *
02182              * Note that a SEMI join works like an inner join here: it's okay
02183              * to pass down both local and upper constraints.  (There can't be
02184              * any upper constraints affecting its inner side, but it's not
02185              * worth having a separate code path to avoid passing them.)
02186              *
02187              * At a FULL join we just punt and pass nothing down --- is it
02188              * possible to be smarter?
02189              */
02190             if (jointype != JOIN_FULL)
02191             {
02192                 local_nonnullable_rels = find_nonnullable_rels(j->quals);
02193                 if (!computed_local_nonnullable_vars)
02194                     local_nonnullable_vars = find_nonnullable_vars(j->quals);
02195                 local_forced_null_vars = find_forced_null_vars(j->quals);
02196                 if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
02197                 {
02198                     /* OK to merge upper and local constraints */
02199                     local_nonnullable_rels = bms_add_members(local_nonnullable_rels,
02200                                                            nonnullable_rels);
02201                     local_nonnullable_vars = list_concat(local_nonnullable_vars,
02202                                                          nonnullable_vars);
02203                     local_forced_null_vars = list_concat(local_forced_null_vars,
02204                                                          forced_null_vars);
02205                 }
02206             }
02207             else
02208             {
02209                 /* no use in calculating these */
02210                 local_nonnullable_rels = NULL;
02211                 local_forced_null_vars = NIL;
02212             }
02213 
02214             if (left_state->contains_outer)
02215             {
02216                 if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
02217                 {
02218                     /* pass union of local and upper constraints */
02219                     pass_nonnullable_rels = local_nonnullable_rels;
02220                     pass_nonnullable_vars = local_nonnullable_vars;
02221                     pass_forced_null_vars = local_forced_null_vars;
02222                 }
02223                 else if (jointype != JOIN_FULL) /* ie, LEFT or ANTI */
02224                 {
02225                     /* can't pass local constraints to non-nullable side */
02226                     pass_nonnullable_rels = nonnullable_rels;
02227                     pass_nonnullable_vars = nonnullable_vars;
02228                     pass_forced_null_vars = forced_null_vars;
02229                 }
02230                 else
02231                 {
02232                     /* no constraints pass through JOIN_FULL */
02233                     pass_nonnullable_rels = NULL;
02234                     pass_nonnullable_vars = NIL;
02235                     pass_forced_null_vars = NIL;
02236                 }
02237                 reduce_outer_joins_pass2(j->larg, left_state, root,
02238                                          pass_nonnullable_rels,
02239                                          pass_nonnullable_vars,
02240                                          pass_forced_null_vars);
02241             }
02242 
02243             if (right_state->contains_outer)
02244             {
02245                 if (jointype != JOIN_FULL)      /* ie, INNER/LEFT/SEMI/ANTI */
02246                 {
02247                     /* pass appropriate constraints, per comment above */
02248                     pass_nonnullable_rels = local_nonnullable_rels;
02249                     pass_nonnullable_vars = local_nonnullable_vars;
02250                     pass_forced_null_vars = local_forced_null_vars;
02251                 }
02252                 else
02253                 {
02254                     /* no constraints pass through JOIN_FULL */
02255                     pass_nonnullable_rels = NULL;
02256                     pass_nonnullable_vars = NIL;
02257                     pass_forced_null_vars = NIL;
02258                 }
02259                 reduce_outer_joins_pass2(j->rarg, right_state, root,
02260                                          pass_nonnullable_rels,
02261                                          pass_nonnullable_vars,
02262                                          pass_forced_null_vars);
02263             }
02264             bms_free(local_nonnullable_rels);
02265         }
02266     }
02267     else
02268         elog(ERROR, "unrecognized node type: %d",
02269              (int) nodeTag(jtnode));
02270 }
02271 
02272 /*
02273  * substitute_multiple_relids - adjust node relid sets after pulling up
02274  * a subquery
02275  *
02276  * Find any PlaceHolderVar nodes in the given tree that reference the
02277  * pulled-up relid, and change them to reference the replacement relid(s).
02278  *
02279  * NOTE: although this has the form of a walker, we cheat and modify the
02280  * nodes in-place.  This should be OK since the tree was copied by
02281  * pullup_replace_vars earlier.  Avoid scribbling on the original values of
02282  * the bitmapsets, though, because expression_tree_mutator doesn't copy those.
02283  */
02284 
02285 typedef struct
02286 {
02287     int         varno;
02288     int         sublevels_up;
02289     Relids      subrelids;
02290 } substitute_multiple_relids_context;
02291 
02292 static bool
02293 substitute_multiple_relids_walker(Node *node,
02294                                   substitute_multiple_relids_context *context)
02295 {
02296     if (node == NULL)
02297         return false;
02298     if (IsA(node, PlaceHolderVar))
02299     {
02300         PlaceHolderVar *phv = (PlaceHolderVar *) node;
02301 
02302         if (phv->phlevelsup == context->sublevels_up &&
02303             bms_is_member(context->varno, phv->phrels))
02304         {
02305             phv->phrels = bms_union(phv->phrels,
02306                                     context->subrelids);
02307             phv->phrels = bms_del_member(phv->phrels,
02308                                          context->varno);
02309         }
02310         /* fall through to examine children */
02311     }
02312     if (IsA(node, Query))
02313     {
02314         /* Recurse into subselects */
02315         bool        result;
02316 
02317         context->sublevels_up++;
02318         result = query_tree_walker((Query *) node,
02319                                    substitute_multiple_relids_walker,
02320                                    (void *) context, 0);
02321         context->sublevels_up--;
02322         return result;
02323     }
02324     /* Shouldn't need to handle planner auxiliary nodes here */
02325     Assert(!IsA(node, SpecialJoinInfo));
02326     Assert(!IsA(node, LateralJoinInfo));
02327     Assert(!IsA(node, AppendRelInfo));
02328     Assert(!IsA(node, PlaceHolderInfo));
02329     Assert(!IsA(node, MinMaxAggInfo));
02330 
02331     return expression_tree_walker(node, substitute_multiple_relids_walker,
02332                                   (void *) context);
02333 }
02334 
02335 static void
02336 substitute_multiple_relids(Node *node, int varno, Relids subrelids)
02337 {
02338     substitute_multiple_relids_context context;
02339 
02340     context.varno = varno;
02341     context.sublevels_up = 0;
02342     context.subrelids = subrelids;
02343 
02344     /*
02345      * Must be prepared to start with a Query or a bare expression tree.
02346      */
02347     query_or_expression_tree_walker(node,
02348                                     substitute_multiple_relids_walker,
02349                                     (void *) &context,
02350                                     0);
02351 }
02352 
02353 /*
02354  * fix_append_rel_relids: update RT-index fields of AppendRelInfo nodes
02355  *
02356  * When we pull up a subquery, any AppendRelInfo references to the subquery's
02357  * RT index have to be replaced by the substituted relid (and there had better
02358  * be only one).  We also need to apply substitute_multiple_relids to their
02359  * translated_vars lists, since those might contain PlaceHolderVars.
02360  *
02361  * We assume we may modify the AppendRelInfo nodes in-place.
02362  */
02363 static void
02364 fix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids)
02365 {
02366     ListCell   *l;
02367     int         subvarno = -1;
02368 
02369     /*
02370      * We only want to extract the member relid once, but we mustn't fail
02371      * immediately if there are multiple members; it could be that none of the
02372      * AppendRelInfo nodes refer to it.  So compute it on first use. Note that
02373      * bms_singleton_member will complain if set is not singleton.
02374      */
02375     foreach(l, append_rel_list)
02376     {
02377         AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
02378 
02379         /* The parent_relid shouldn't ever be a pullup target */
02380         Assert(appinfo->parent_relid != varno);
02381 
02382         if (appinfo->child_relid == varno)
02383         {
02384             if (subvarno < 0)
02385                 subvarno = bms_singleton_member(subrelids);
02386             appinfo->child_relid = subvarno;
02387         }
02388 
02389         /* Also finish fixups for its translated vars */
02390         substitute_multiple_relids((Node *) appinfo->translated_vars,
02391                                    varno, subrelids);
02392     }
02393 }
02394 
02395 /*
02396  * get_relids_in_jointree: get set of RT indexes present in a jointree
02397  *
02398  * If include_joins is true, join RT indexes are included; if false,
02399  * only base rels are included.
02400  */
02401 Relids
02402 get_relids_in_jointree(Node *jtnode, bool include_joins)
02403 {
02404     Relids      result = NULL;
02405 
02406     if (jtnode == NULL)
02407         return result;
02408     if (IsA(jtnode, RangeTblRef))
02409     {
02410         int         varno = ((RangeTblRef *) jtnode)->rtindex;
02411 
02412         result = bms_make_singleton(varno);
02413     }
02414     else if (IsA(jtnode, FromExpr))
02415     {
02416         FromExpr   *f = (FromExpr *) jtnode;
02417         ListCell   *l;
02418 
02419         foreach(l, f->fromlist)
02420         {
02421             result = bms_join(result,
02422                               get_relids_in_jointree(lfirst(l),
02423                                                      include_joins));
02424         }
02425     }
02426     else if (IsA(jtnode, JoinExpr))
02427     {
02428         JoinExpr   *j = (JoinExpr *) jtnode;
02429 
02430         result = get_relids_in_jointree(j->larg, include_joins);
02431         result = bms_join(result,
02432                           get_relids_in_jointree(j->rarg, include_joins));
02433         if (include_joins && j->rtindex)
02434             result = bms_add_member(result, j->rtindex);
02435     }
02436     else
02437         elog(ERROR, "unrecognized node type: %d",
02438              (int) nodeTag(jtnode));
02439     return result;
02440 }
02441 
02442 /*
02443  * get_relids_for_join: get set of base RT indexes making up a join
02444  */
02445 Relids
02446 get_relids_for_join(PlannerInfo *root, int joinrelid)
02447 {
02448     Node       *jtnode;
02449 
02450     jtnode = find_jointree_node_for_rel((Node *) root->parse->jointree,
02451                                         joinrelid);
02452     if (!jtnode)
02453         elog(ERROR, "could not find join node %d", joinrelid);
02454     return get_relids_in_jointree(jtnode, false);
02455 }
02456 
02457 /*
02458  * find_jointree_node_for_rel: locate jointree node for a base or join RT index
02459  *
02460  * Returns NULL if not found
02461  */
02462 static Node *
02463 find_jointree_node_for_rel(Node *jtnode, int relid)
02464 {
02465     if (jtnode == NULL)
02466         return NULL;
02467     if (IsA(jtnode, RangeTblRef))
02468     {
02469         int         varno = ((RangeTblRef *) jtnode)->rtindex;
02470 
02471         if (relid == varno)
02472             return jtnode;
02473     }
02474     else if (IsA(jtnode, FromExpr))
02475     {
02476         FromExpr   *f = (FromExpr *) jtnode;
02477         ListCell   *l;
02478 
02479         foreach(l, f->fromlist)
02480         {
02481             jtnode = find_jointree_node_for_rel(lfirst(l), relid);
02482             if (jtnode)
02483                 return jtnode;
02484         }
02485     }
02486     else if (IsA(jtnode, JoinExpr))
02487     {
02488         JoinExpr   *j = (JoinExpr *) jtnode;
02489 
02490         if (relid == j->rtindex)
02491             return jtnode;
02492         jtnode = find_jointree_node_for_rel(j->larg, relid);
02493         if (jtnode)
02494             return jtnode;
02495         jtnode = find_jointree_node_for_rel(j->rarg, relid);
02496         if (jtnode)
02497             return jtnode;
02498     }
02499     else
02500         elog(ERROR, "unrecognized node type: %d",
02501              (int) nodeTag(jtnode));
02502     return NULL;
02503 }