Header And Logo

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

setrefs.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * setrefs.c
00004  *    Post-processing of a completed plan tree: fix references to subplan
00005  *    vars, compute regproc values for operators, etc
00006  *
00007  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00008  * Portions Copyright (c) 1994, Regents of the University of California
00009  *
00010  *
00011  * IDENTIFICATION
00012  *    src/backend/optimizer/plan/setrefs.c
00013  *
00014  *-------------------------------------------------------------------------
00015  */
00016 #include "postgres.h"
00017 
00018 #include "access/transam.h"
00019 #include "catalog/pg_type.h"
00020 #include "nodes/makefuncs.h"
00021 #include "nodes/nodeFuncs.h"
00022 #include "optimizer/pathnode.h"
00023 #include "optimizer/planmain.h"
00024 #include "optimizer/tlist.h"
00025 #include "tcop/utility.h"
00026 #include "utils/lsyscache.h"
00027 #include "utils/syscache.h"
00028 
00029 
00030 typedef struct
00031 {
00032     Index       varno;          /* RT index of Var */
00033     AttrNumber  varattno;       /* attr number of Var */
00034     AttrNumber  resno;          /* TLE position of Var */
00035 } tlist_vinfo;
00036 
00037 typedef struct
00038 {
00039     List       *tlist;          /* underlying target list */
00040     int         num_vars;       /* number of plain Var tlist entries */
00041     bool        has_ph_vars;    /* are there PlaceHolderVar entries? */
00042     bool        has_non_vars;   /* are there other entries? */
00043     /* array of num_vars entries: */
00044     tlist_vinfo vars[1];        /* VARIABLE LENGTH ARRAY */
00045 } indexed_tlist;                /* VARIABLE LENGTH STRUCT */
00046 
00047 typedef struct
00048 {
00049     PlannerInfo *root;
00050     int         rtoffset;
00051 } fix_scan_expr_context;
00052 
00053 typedef struct
00054 {
00055     PlannerInfo *root;
00056     indexed_tlist *outer_itlist;
00057     indexed_tlist *inner_itlist;
00058     Index       acceptable_rel;
00059     int         rtoffset;
00060 } fix_join_expr_context;
00061 
00062 typedef struct
00063 {
00064     PlannerInfo *root;
00065     indexed_tlist *subplan_itlist;
00066     Index       newvarno;
00067     int         rtoffset;
00068 } fix_upper_expr_context;
00069 
00070 /*
00071  * Check if a Const node is a regclass value.  We accept plain OID too,
00072  * since a regclass Const will get folded to that type if it's an argument
00073  * to oideq or similar operators.  (This might result in some extraneous
00074  * values in a plan's list of relation dependencies, but the worst result
00075  * would be occasional useless replans.)
00076  */
00077 #define ISREGCLASSCONST(con) \
00078     (((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \
00079      !(con)->constisnull)
00080 
00081 #define fix_scan_list(root, lst, rtoffset) \
00082     ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset))
00083 
00084 static Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset);
00085 static Plan *set_indexonlyscan_references(PlannerInfo *root,
00086                              IndexOnlyScan *plan,
00087                              int rtoffset);
00088 static Plan *set_subqueryscan_references(PlannerInfo *root,
00089                             SubqueryScan *plan,
00090                             int rtoffset);
00091 static bool trivial_subqueryscan(SubqueryScan *plan);
00092 static Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset);
00093 static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
00094 static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);
00095 static void set_join_references(PlannerInfo *root, Join *join, int rtoffset);
00096 static void set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset);
00097 static void set_dummy_tlist_references(Plan *plan, int rtoffset);
00098 static indexed_tlist *build_tlist_index(List *tlist);
00099 static Var *search_indexed_tlist_for_var(Var *var,
00100                              indexed_tlist *itlist,
00101                              Index newvarno,
00102                              int rtoffset);
00103 static Var *search_indexed_tlist_for_non_var(Node *node,
00104                                  indexed_tlist *itlist,
00105                                  Index newvarno);
00106 static Var *search_indexed_tlist_for_sortgroupref(Node *node,
00107                                       Index sortgroupref,
00108                                       indexed_tlist *itlist,
00109                                       Index newvarno);
00110 static List *fix_join_expr(PlannerInfo *root,
00111               List *clauses,
00112               indexed_tlist *outer_itlist,
00113               indexed_tlist *inner_itlist,
00114               Index acceptable_rel, int rtoffset);
00115 static Node *fix_join_expr_mutator(Node *node,
00116                       fix_join_expr_context *context);
00117 static Node *fix_upper_expr(PlannerInfo *root,
00118                Node *node,
00119                indexed_tlist *subplan_itlist,
00120                Index newvarno,
00121                int rtoffset);
00122 static Node *fix_upper_expr_mutator(Node *node,
00123                        fix_upper_expr_context *context);
00124 static List *set_returning_clause_references(PlannerInfo *root,
00125                                 List *rlist,
00126                                 Plan *topplan,
00127                                 Index resultRelation,
00128                                 int rtoffset);
00129 static bool fix_opfuncids_walker(Node *node, void *context);
00130 static bool extract_query_dependencies_walker(Node *node,
00131                                   PlannerInfo *context);
00132 
00133 
00134 /*****************************************************************************
00135  *
00136  *      SUBPLAN REFERENCES
00137  *
00138  *****************************************************************************/
00139 
00140 /*
00141  * set_plan_references
00142  *
00143  * This is the final processing pass of the planner/optimizer.  The plan
00144  * tree is complete; we just have to adjust some representational details
00145  * for the convenience of the executor:
00146  *
00147  * 1. We flatten the various subquery rangetables into a single list, and
00148  * zero out RangeTblEntry fields that are not useful to the executor.
00149  *
00150  * 2. We adjust Vars in scan nodes to be consistent with the flat rangetable.
00151  *
00152  * 3. We adjust Vars in upper plan nodes to refer to the outputs of their
00153  * subplans.
00154  *
00155  * 4. We compute regproc OIDs for operators (ie, we look up the function
00156  * that implements each op).
00157  *
00158  * 5. We create lists of specific objects that the plan depends on.
00159  * This will be used by plancache.c to drive invalidation of cached plans.
00160  * Relation dependencies are represented by OIDs, and everything else by
00161  * PlanInvalItems (this distinction is motivated by the shared-inval APIs).
00162  * Currently, relations and user-defined functions are the only types of
00163  * objects that are explicitly tracked this way.
00164  *
00165  * We also perform one final optimization step, which is to delete
00166  * SubqueryScan plan nodes that aren't doing anything useful (ie, have
00167  * no qual and a no-op targetlist).  The reason for doing this last is that
00168  * it can't readily be done before set_plan_references, because it would
00169  * break set_upper_references: the Vars in the subquery's top tlist
00170  * wouldn't match up with the Vars in the outer plan tree.  The SubqueryScan
00171  * serves a necessary function as a buffer between outer query and subquery
00172  * variable numbering ... but after we've flattened the rangetable this is
00173  * no longer a problem, since then there's only one rtindex namespace.
00174  *
00175  * set_plan_references recursively traverses the whole plan tree.
00176  *
00177  * The return value is normally the same Plan node passed in, but can be
00178  * different when the passed-in Plan is a SubqueryScan we decide isn't needed.
00179  *
00180  * The flattened rangetable entries are appended to root->glob->finalrtable.
00181  * Also, rowmarks entries are appended to root->glob->finalrowmarks, and the
00182  * RT indexes of ModifyTable result relations to root->glob->resultRelations.
00183  * Plan dependencies are appended to root->glob->relationOids (for relations)
00184  * and root->glob->invalItems (for everything else).
00185  *
00186  * Notice that we modify Plan nodes in-place, but use expression_tree_mutator
00187  * to process targetlist and qual expressions.  We can assume that the Plan
00188  * nodes were just built by the planner and are not multiply referenced, but
00189  * it's not so safe to assume that for expression tree nodes.
00190  */
00191 Plan *
00192 set_plan_references(PlannerInfo *root, Plan *plan)
00193 {
00194     PlannerGlobal *glob = root->glob;
00195     int         rtoffset = list_length(glob->finalrtable);
00196     ListCell   *lc;
00197 
00198     /*
00199      * In the flat rangetable, we zero out substructure pointers that are not
00200      * needed by the executor; this reduces the storage space and copying cost
00201      * for cached plans.  We keep only the alias and eref Alias fields, which
00202      * are needed by EXPLAIN, and the selectedCols and modifiedCols bitmaps,
00203      * which are needed for executor-startup permissions checking and for
00204      * trigger event checking.
00205      */
00206     foreach(lc, root->parse->rtable)
00207     {
00208         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
00209         RangeTblEntry *newrte;
00210 
00211         /* flat copy to duplicate all the scalar fields */
00212         newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
00213         memcpy(newrte, rte, sizeof(RangeTblEntry));
00214 
00215         /* zap unneeded sub-structure */
00216         newrte->subquery = NULL;
00217         newrte->joinaliasvars = NIL;
00218         newrte->funcexpr = NULL;
00219         newrte->funccoltypes = NIL;
00220         newrte->funccoltypmods = NIL;
00221         newrte->funccolcollations = NIL;
00222         newrte->values_lists = NIL;
00223         newrte->values_collations = NIL;
00224         newrte->ctecoltypes = NIL;
00225         newrte->ctecoltypmods = NIL;
00226         newrte->ctecolcollations = NIL;
00227 
00228         glob->finalrtable = lappend(glob->finalrtable, newrte);
00229 
00230         /*
00231          * If it's a plain relation RTE, add the table to relationOids.
00232          *
00233          * We do this even though the RTE might be unreferenced in the plan
00234          * tree; this would correspond to cases such as views that were
00235          * expanded, child tables that were eliminated by constraint
00236          * exclusion, etc.  Schema invalidation on such a rel must still force
00237          * rebuilding of the plan.
00238          *
00239          * Note we don't bother to avoid duplicate list entries.  We could,
00240          * but it would probably cost more cycles than it would save.
00241          */
00242         if (newrte->rtekind == RTE_RELATION)
00243             glob->relationOids = lappend_oid(glob->relationOids,
00244                                              newrte->relid);
00245     }
00246 
00247     /*
00248      * Check for RT index overflow; it's very unlikely, but if it did happen,
00249      * the executor would get confused by varnos that match the special varno
00250      * values.
00251      */
00252     if (IS_SPECIAL_VARNO(list_length(glob->finalrtable)))
00253         ereport(ERROR,
00254                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
00255                  errmsg("too many range table entries")));
00256 
00257     /*
00258      * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
00259      */
00260     foreach(lc, root->rowMarks)
00261     {
00262         PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
00263         PlanRowMark *newrc;
00264 
00265         Assert(IsA(rc, PlanRowMark));
00266 
00267         /* flat copy is enough since all fields are scalars */
00268         newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
00269         memcpy(newrc, rc, sizeof(PlanRowMark));
00270 
00271         /* adjust indexes ... but *not* the rowmarkId */
00272         newrc->rti += rtoffset;
00273         newrc->prti += rtoffset;
00274 
00275         glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
00276     }
00277 
00278     /* Now fix the Plan tree */
00279     return set_plan_refs(root, plan, rtoffset);
00280 }
00281 
00282 /*
00283  * set_plan_refs: recurse through the Plan nodes of a single subquery level
00284  */
00285 static Plan *
00286 set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
00287 {
00288     ListCell   *l;
00289 
00290     if (plan == NULL)
00291         return NULL;
00292 
00293     /*
00294      * Plan-type-specific fixes
00295      */
00296     switch (nodeTag(plan))
00297     {
00298         case T_SeqScan:
00299             {
00300                 SeqScan    *splan = (SeqScan *) plan;
00301 
00302                 splan->scanrelid += rtoffset;
00303                 splan->plan.targetlist =
00304                     fix_scan_list(root, splan->plan.targetlist, rtoffset);
00305                 splan->plan.qual =
00306                     fix_scan_list(root, splan->plan.qual, rtoffset);
00307             }
00308             break;
00309         case T_IndexScan:
00310             {
00311                 IndexScan  *splan = (IndexScan *) plan;
00312 
00313                 splan->scan.scanrelid += rtoffset;
00314                 splan->scan.plan.targetlist =
00315                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
00316                 splan->scan.plan.qual =
00317                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
00318                 splan->indexqual =
00319                     fix_scan_list(root, splan->indexqual, rtoffset);
00320                 splan->indexqualorig =
00321                     fix_scan_list(root, splan->indexqualorig, rtoffset);
00322                 splan->indexorderby =
00323                     fix_scan_list(root, splan->indexorderby, rtoffset);
00324                 splan->indexorderbyorig =
00325                     fix_scan_list(root, splan->indexorderbyorig, rtoffset);
00326             }
00327             break;
00328         case T_IndexOnlyScan:
00329             {
00330                 IndexOnlyScan *splan = (IndexOnlyScan *) plan;
00331 
00332                 return set_indexonlyscan_references(root, splan, rtoffset);
00333             }
00334             break;
00335         case T_BitmapIndexScan:
00336             {
00337                 BitmapIndexScan *splan = (BitmapIndexScan *) plan;
00338 
00339                 splan->scan.scanrelid += rtoffset;
00340                 /* no need to fix targetlist and qual */
00341                 Assert(splan->scan.plan.targetlist == NIL);
00342                 Assert(splan->scan.plan.qual == NIL);
00343                 splan->indexqual =
00344                     fix_scan_list(root, splan->indexqual, rtoffset);
00345                 splan->indexqualorig =
00346                     fix_scan_list(root, splan->indexqualorig, rtoffset);
00347             }
00348             break;
00349         case T_BitmapHeapScan:
00350             {
00351                 BitmapHeapScan *splan = (BitmapHeapScan *) plan;
00352 
00353                 splan->scan.scanrelid += rtoffset;
00354                 splan->scan.plan.targetlist =
00355                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
00356                 splan->scan.plan.qual =
00357                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
00358                 splan->bitmapqualorig =
00359                     fix_scan_list(root, splan->bitmapqualorig, rtoffset);
00360             }
00361             break;
00362         case T_TidScan:
00363             {
00364                 TidScan    *splan = (TidScan *) plan;
00365 
00366                 splan->scan.scanrelid += rtoffset;
00367                 splan->scan.plan.targetlist =
00368                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
00369                 splan->scan.plan.qual =
00370                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
00371                 splan->tidquals =
00372                     fix_scan_list(root, splan->tidquals, rtoffset);
00373             }
00374             break;
00375         case T_SubqueryScan:
00376             /* Needs special treatment, see comments below */
00377             return set_subqueryscan_references(root,
00378                                                (SubqueryScan *) plan,
00379                                                rtoffset);
00380         case T_FunctionScan:
00381             {
00382                 FunctionScan *splan = (FunctionScan *) plan;
00383 
00384                 splan->scan.scanrelid += rtoffset;
00385                 splan->scan.plan.targetlist =
00386                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
00387                 splan->scan.plan.qual =
00388                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
00389                 splan->funcexpr =
00390                     fix_scan_expr(root, splan->funcexpr, rtoffset);
00391             }
00392             break;
00393         case T_ValuesScan:
00394             {
00395                 ValuesScan *splan = (ValuesScan *) plan;
00396 
00397                 splan->scan.scanrelid += rtoffset;
00398                 splan->scan.plan.targetlist =
00399                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
00400                 splan->scan.plan.qual =
00401                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
00402                 splan->values_lists =
00403                     fix_scan_list(root, splan->values_lists, rtoffset);
00404             }
00405             break;
00406         case T_CteScan:
00407             {
00408                 CteScan    *splan = (CteScan *) plan;
00409 
00410                 splan->scan.scanrelid += rtoffset;
00411                 splan->scan.plan.targetlist =
00412                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
00413                 splan->scan.plan.qual =
00414                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
00415             }
00416             break;
00417         case T_WorkTableScan:
00418             {
00419                 WorkTableScan *splan = (WorkTableScan *) plan;
00420 
00421                 splan->scan.scanrelid += rtoffset;
00422                 splan->scan.plan.targetlist =
00423                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
00424                 splan->scan.plan.qual =
00425                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
00426             }
00427             break;
00428         case T_ForeignScan:
00429             {
00430                 ForeignScan *splan = (ForeignScan *) plan;
00431 
00432                 splan->scan.scanrelid += rtoffset;
00433                 splan->scan.plan.targetlist =
00434                     fix_scan_list(root, splan->scan.plan.targetlist, rtoffset);
00435                 splan->scan.plan.qual =
00436                     fix_scan_list(root, splan->scan.plan.qual, rtoffset);
00437                 splan->fdw_exprs =
00438                     fix_scan_list(root, splan->fdw_exprs, rtoffset);
00439             }
00440             break;
00441 
00442         case T_NestLoop:
00443         case T_MergeJoin:
00444         case T_HashJoin:
00445             set_join_references(root, (Join *) plan, rtoffset);
00446             break;
00447 
00448         case T_Hash:
00449         case T_Material:
00450         case T_Sort:
00451         case T_Unique:
00452         case T_SetOp:
00453 
00454             /*
00455              * These plan types don't actually bother to evaluate their
00456              * targetlists, because they just return their unmodified input
00457              * tuples.  Even though the targetlist won't be used by the
00458              * executor, we fix it up for possible use by EXPLAIN (not to
00459              * mention ease of debugging --- wrong varnos are very confusing).
00460              */
00461             set_dummy_tlist_references(plan, rtoffset);
00462 
00463             /*
00464              * Since these plan types don't check quals either, we should not
00465              * find any qual expression attached to them.
00466              */
00467             Assert(plan->qual == NIL);
00468             break;
00469         case T_LockRows:
00470             {
00471                 LockRows   *splan = (LockRows *) plan;
00472 
00473                 /*
00474                  * Like the plan types above, LockRows doesn't evaluate its
00475                  * tlist or quals.  But we have to fix up the RT indexes in
00476                  * its rowmarks.
00477                  */
00478                 set_dummy_tlist_references(plan, rtoffset);
00479                 Assert(splan->plan.qual == NIL);
00480 
00481                 foreach(l, splan->rowMarks)
00482                 {
00483                     PlanRowMark *rc = (PlanRowMark *) lfirst(l);
00484 
00485                     rc->rti += rtoffset;
00486                     rc->prti += rtoffset;
00487                 }
00488             }
00489             break;
00490         case T_Limit:
00491             {
00492                 Limit      *splan = (Limit *) plan;
00493 
00494                 /*
00495                  * Like the plan types above, Limit doesn't evaluate its tlist
00496                  * or quals.  It does have live expressions for limit/offset,
00497                  * however; and those cannot contain subplan variable refs, so
00498                  * fix_scan_expr works for them.
00499                  */
00500                 set_dummy_tlist_references(plan, rtoffset);
00501                 Assert(splan->plan.qual == NIL);
00502 
00503                 splan->limitOffset =
00504                     fix_scan_expr(root, splan->limitOffset, rtoffset);
00505                 splan->limitCount =
00506                     fix_scan_expr(root, splan->limitCount, rtoffset);
00507             }
00508             break;
00509         case T_Agg:
00510         case T_Group:
00511             set_upper_references(root, plan, rtoffset);
00512             break;
00513         case T_WindowAgg:
00514             {
00515                 WindowAgg  *wplan = (WindowAgg *) plan;
00516 
00517                 set_upper_references(root, plan, rtoffset);
00518 
00519                 /*
00520                  * Like Limit node limit/offset expressions, WindowAgg has
00521                  * frame offset expressions, which cannot contain subplan
00522                  * variable refs, so fix_scan_expr works for them.
00523                  */
00524                 wplan->startOffset =
00525                     fix_scan_expr(root, wplan->startOffset, rtoffset);
00526                 wplan->endOffset =
00527                     fix_scan_expr(root, wplan->endOffset, rtoffset);
00528             }
00529             break;
00530         case T_Result:
00531             {
00532                 Result     *splan = (Result *) plan;
00533 
00534                 /*
00535                  * Result may or may not have a subplan; if not, it's more
00536                  * like a scan node than an upper node.
00537                  */
00538                 if (splan->plan.lefttree != NULL)
00539                     set_upper_references(root, plan, rtoffset);
00540                 else
00541                 {
00542                     splan->plan.targetlist =
00543                         fix_scan_list(root, splan->plan.targetlist, rtoffset);
00544                     splan->plan.qual =
00545                         fix_scan_list(root, splan->plan.qual, rtoffset);
00546                 }
00547                 /* resconstantqual can't contain any subplan variable refs */
00548                 splan->resconstantqual =
00549                     fix_scan_expr(root, splan->resconstantqual, rtoffset);
00550             }
00551             break;
00552         case T_ModifyTable:
00553             {
00554                 ModifyTable *splan = (ModifyTable *) plan;
00555 
00556                 Assert(splan->plan.targetlist == NIL);
00557                 Assert(splan->plan.qual == NIL);
00558 
00559                 if (splan->returningLists)
00560                 {
00561                     List       *newRL = NIL;
00562                     ListCell   *lcrl,
00563                                *lcrr,
00564                                *lcp;
00565 
00566                     /*
00567                      * Pass each per-subplan returningList through
00568                      * set_returning_clause_references().
00569                      */
00570                     Assert(list_length(splan->returningLists) == list_length(splan->resultRelations));
00571                     Assert(list_length(splan->returningLists) == list_length(splan->plans));
00572                     forthree(lcrl, splan->returningLists,
00573                              lcrr, splan->resultRelations,
00574                              lcp, splan->plans)
00575                     {
00576                         List       *rlist = (List *) lfirst(lcrl);
00577                         Index       resultrel = lfirst_int(lcrr);
00578                         Plan       *subplan = (Plan *) lfirst(lcp);
00579 
00580                         rlist = set_returning_clause_references(root,
00581                                                                 rlist,
00582                                                                 subplan,
00583                                                                 resultrel,
00584                                                                 rtoffset);
00585                         newRL = lappend(newRL, rlist);
00586                     }
00587                     splan->returningLists = newRL;
00588 
00589                     /*
00590                      * Set up the visible plan targetlist as being the same as
00591                      * the first RETURNING list. This is for the use of
00592                      * EXPLAIN; the executor won't pay any attention to the
00593                      * targetlist.  We postpone this step until here so that
00594                      * we don't have to do set_returning_clause_references()
00595                      * twice on identical targetlists.
00596                      */
00597                     splan->plan.targetlist = copyObject(linitial(newRL));
00598                 }
00599 
00600                 foreach(l, splan->resultRelations)
00601                 {
00602                     lfirst_int(l) += rtoffset;
00603                 }
00604                 foreach(l, splan->rowMarks)
00605                 {
00606                     PlanRowMark *rc = (PlanRowMark *) lfirst(l);
00607 
00608                     rc->rti += rtoffset;
00609                     rc->prti += rtoffset;
00610                 }
00611                 foreach(l, splan->plans)
00612                 {
00613                     lfirst(l) = set_plan_refs(root,
00614                                               (Plan *) lfirst(l),
00615                                               rtoffset);
00616                 }
00617 
00618                 /*
00619                  * Append this ModifyTable node's final result relation RT
00620                  * index(es) to the global list for the plan, and set its
00621                  * resultRelIndex to reflect their starting position in the
00622                  * global list.
00623                  */
00624                 splan->resultRelIndex = list_length(root->glob->resultRelations);
00625                 root->glob->resultRelations =
00626                     list_concat(root->glob->resultRelations,
00627                                 list_copy(splan->resultRelations));
00628             }
00629             break;
00630         case T_Append:
00631             {
00632                 Append     *splan = (Append *) plan;
00633 
00634                 /*
00635                  * Append, like Sort et al, doesn't actually evaluate its
00636                  * targetlist or check quals.
00637                  */
00638                 set_dummy_tlist_references(plan, rtoffset);
00639                 Assert(splan->plan.qual == NIL);
00640                 foreach(l, splan->appendplans)
00641                 {
00642                     lfirst(l) = set_plan_refs(root,
00643                                               (Plan *) lfirst(l),
00644                                               rtoffset);
00645                 }
00646             }
00647             break;
00648         case T_MergeAppend:
00649             {
00650                 MergeAppend *splan = (MergeAppend *) plan;
00651 
00652                 /*
00653                  * MergeAppend, like Sort et al, doesn't actually evaluate its
00654                  * targetlist or check quals.
00655                  */
00656                 set_dummy_tlist_references(plan, rtoffset);
00657                 Assert(splan->plan.qual == NIL);
00658                 foreach(l, splan->mergeplans)
00659                 {
00660                     lfirst(l) = set_plan_refs(root,
00661                                               (Plan *) lfirst(l),
00662                                               rtoffset);
00663                 }
00664             }
00665             break;
00666         case T_RecursiveUnion:
00667             /* This doesn't evaluate targetlist or check quals either */
00668             set_dummy_tlist_references(plan, rtoffset);
00669             Assert(plan->qual == NIL);
00670             break;
00671         case T_BitmapAnd:
00672             {
00673                 BitmapAnd  *splan = (BitmapAnd *) plan;
00674 
00675                 /* BitmapAnd works like Append, but has no tlist */
00676                 Assert(splan->plan.targetlist == NIL);
00677                 Assert(splan->plan.qual == NIL);
00678                 foreach(l, splan->bitmapplans)
00679                 {
00680                     lfirst(l) = set_plan_refs(root,
00681                                               (Plan *) lfirst(l),
00682                                               rtoffset);
00683                 }
00684             }
00685             break;
00686         case T_BitmapOr:
00687             {
00688                 BitmapOr   *splan = (BitmapOr *) plan;
00689 
00690                 /* BitmapOr works like Append, but has no tlist */
00691                 Assert(splan->plan.targetlist == NIL);
00692                 Assert(splan->plan.qual == NIL);
00693                 foreach(l, splan->bitmapplans)
00694                 {
00695                     lfirst(l) = set_plan_refs(root,
00696                                               (Plan *) lfirst(l),
00697                                               rtoffset);
00698                 }
00699             }
00700             break;
00701         default:
00702             elog(ERROR, "unrecognized node type: %d",
00703                  (int) nodeTag(plan));
00704             break;
00705     }
00706 
00707     /*
00708      * Now recurse into child plans, if any
00709      *
00710      * NOTE: it is essential that we recurse into child plans AFTER we set
00711      * subplan references in this plan's tlist and quals.  If we did the
00712      * reference-adjustments bottom-up, then we would fail to match this
00713      * plan's var nodes against the already-modified nodes of the children.
00714      */
00715     plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset);
00716     plan->righttree = set_plan_refs(root, plan->righttree, rtoffset);
00717 
00718     return plan;
00719 }
00720 
00721 /*
00722  * set_indexonlyscan_references
00723  *      Do set_plan_references processing on an IndexOnlyScan
00724  *
00725  * This is unlike the handling of a plain IndexScan because we have to
00726  * convert Vars referencing the heap into Vars referencing the index.
00727  * We can use the fix_upper_expr machinery for that, by working from a
00728  * targetlist describing the index columns.
00729  */
00730 static Plan *
00731 set_indexonlyscan_references(PlannerInfo *root,
00732                              IndexOnlyScan *plan,
00733                              int rtoffset)
00734 {
00735     indexed_tlist *index_itlist;
00736 
00737     index_itlist = build_tlist_index(plan->indextlist);
00738 
00739     plan->scan.scanrelid += rtoffset;
00740     plan->scan.plan.targetlist = (List *)
00741         fix_upper_expr(root,
00742                        (Node *) plan->scan.plan.targetlist,
00743                        index_itlist,
00744                        INDEX_VAR,
00745                        rtoffset);
00746     plan->scan.plan.qual = (List *)
00747         fix_upper_expr(root,
00748                        (Node *) plan->scan.plan.qual,
00749                        index_itlist,
00750                        INDEX_VAR,
00751                        rtoffset);
00752     /* indexqual is already transformed to reference index columns */
00753     plan->indexqual = fix_scan_list(root, plan->indexqual, rtoffset);
00754     /* indexorderby is already transformed to reference index columns */
00755     plan->indexorderby = fix_scan_list(root, plan->indexorderby, rtoffset);
00756     /* indextlist must NOT be transformed to reference index columns */
00757     plan->indextlist = fix_scan_list(root, plan->indextlist, rtoffset);
00758 
00759     pfree(index_itlist);
00760 
00761     return (Plan *) plan;
00762 }
00763 
00764 /*
00765  * set_subqueryscan_references
00766  *      Do set_plan_references processing on a SubqueryScan
00767  *
00768  * We try to strip out the SubqueryScan entirely; if we can't, we have
00769  * to do the normal processing on it.
00770  */
00771 static Plan *
00772 set_subqueryscan_references(PlannerInfo *root,
00773                             SubqueryScan *plan,
00774                             int rtoffset)
00775 {
00776     RelOptInfo *rel;
00777     Plan       *result;
00778 
00779     /* Need to look up the subquery's RelOptInfo, since we need its subroot */
00780     rel = find_base_rel(root, plan->scan.scanrelid);
00781     Assert(rel->subplan == plan->subplan);
00782 
00783     /* Recursively process the subplan */
00784     plan->subplan = set_plan_references(rel->subroot, plan->subplan);
00785 
00786     if (trivial_subqueryscan(plan))
00787     {
00788         /*
00789          * We can omit the SubqueryScan node and just pull up the subplan.
00790          */
00791         ListCell   *lp,
00792                    *lc;
00793 
00794         result = plan->subplan;
00795 
00796         /* We have to be sure we don't lose any initplans */
00797         result->initPlan = list_concat(plan->scan.plan.initPlan,
00798                                        result->initPlan);
00799 
00800         /*
00801          * We also have to transfer the SubqueryScan's result-column names
00802          * into the subplan, else columns sent to client will be improperly
00803          * labeled if this is the topmost plan level.  Copy the "source
00804          * column" information too.
00805          */
00806         forboth(lp, plan->scan.plan.targetlist, lc, result->targetlist)
00807         {
00808             TargetEntry *ptle = (TargetEntry *) lfirst(lp);
00809             TargetEntry *ctle = (TargetEntry *) lfirst(lc);
00810 
00811             ctle->resname = ptle->resname;
00812             ctle->resorigtbl = ptle->resorigtbl;
00813             ctle->resorigcol = ptle->resorigcol;
00814         }
00815     }
00816     else
00817     {
00818         /*
00819          * Keep the SubqueryScan node.  We have to do the processing that
00820          * set_plan_references would otherwise have done on it.  Notice we do
00821          * not do set_upper_references() here, because a SubqueryScan will
00822          * always have been created with correct references to its subplan's
00823          * outputs to begin with.
00824          */
00825         plan->scan.scanrelid += rtoffset;
00826         plan->scan.plan.targetlist =
00827             fix_scan_list(root, plan->scan.plan.targetlist, rtoffset);
00828         plan->scan.plan.qual =
00829             fix_scan_list(root, plan->scan.plan.qual, rtoffset);
00830 
00831         result = (Plan *) plan;
00832     }
00833 
00834     return result;
00835 }
00836 
00837 /*
00838  * trivial_subqueryscan
00839  *      Detect whether a SubqueryScan can be deleted from the plan tree.
00840  *
00841  * We can delete it if it has no qual to check and the targetlist just
00842  * regurgitates the output of the child plan.
00843  */
00844 static bool
00845 trivial_subqueryscan(SubqueryScan *plan)
00846 {
00847     int         attrno;
00848     ListCell   *lp,
00849                *lc;
00850 
00851     if (plan->scan.plan.qual != NIL)
00852         return false;
00853 
00854     if (list_length(plan->scan.plan.targetlist) !=
00855         list_length(plan->subplan->targetlist))
00856         return false;           /* tlists not same length */
00857 
00858     attrno = 1;
00859     forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
00860     {
00861         TargetEntry *ptle = (TargetEntry *) lfirst(lp);
00862         TargetEntry *ctle = (TargetEntry *) lfirst(lc);
00863 
00864         if (ptle->resjunk != ctle->resjunk)
00865             return false;       /* tlist doesn't match junk status */
00866 
00867         /*
00868          * We accept either a Var referencing the corresponding element of the
00869          * subplan tlist, or a Const equaling the subplan element. See
00870          * generate_setop_tlist() for motivation.
00871          */
00872         if (ptle->expr && IsA(ptle->expr, Var))
00873         {
00874             Var        *var = (Var *) ptle->expr;
00875 
00876             Assert(var->varno == plan->scan.scanrelid);
00877             Assert(var->varlevelsup == 0);
00878             if (var->varattno != attrno)
00879                 return false;   /* out of order */
00880         }
00881         else if (ptle->expr && IsA(ptle->expr, Const))
00882         {
00883             if (!equal(ptle->expr, ctle->expr))
00884                 return false;
00885         }
00886         else
00887             return false;
00888 
00889         attrno++;
00890     }
00891 
00892     return true;
00893 }
00894 
00895 /*
00896  * copyVar
00897  *      Copy a Var node.
00898  *
00899  * fix_scan_expr and friends do this enough times that it's worth having
00900  * a bespoke routine instead of using the generic copyObject() function.
00901  */
00902 static inline Var *
00903 copyVar(Var *var)
00904 {
00905     Var        *newvar = (Var *) palloc(sizeof(Var));
00906 
00907     *newvar = *var;
00908     return newvar;
00909 }
00910 
00911 /*
00912  * fix_expr_common
00913  *      Do generic set_plan_references processing on an expression node
00914  *
00915  * This is code that is common to all variants of expression-fixing.
00916  * We must look up operator opcode info for OpExpr and related nodes,
00917  * add OIDs from regclass Const nodes into root->glob->relationOids, and
00918  * add catalog TIDs for user-defined functions into root->glob->invalItems.
00919  *
00920  * We assume it's okay to update opcode info in-place.  So this could possibly
00921  * scribble on the planner's input data structures, but it's OK.
00922  */
00923 static void
00924 fix_expr_common(PlannerInfo *root, Node *node)
00925 {
00926     /* We assume callers won't call us on a NULL pointer */
00927     if (IsA(node, Aggref))
00928     {
00929         record_plan_function_dependency(root,
00930                                         ((Aggref *) node)->aggfnoid);
00931     }
00932     else if (IsA(node, WindowFunc))
00933     {
00934         record_plan_function_dependency(root,
00935                                         ((WindowFunc *) node)->winfnoid);
00936     }
00937     else if (IsA(node, FuncExpr))
00938     {
00939         record_plan_function_dependency(root,
00940                                         ((FuncExpr *) node)->funcid);
00941     }
00942     else if (IsA(node, OpExpr))
00943     {
00944         set_opfuncid((OpExpr *) node);
00945         record_plan_function_dependency(root,
00946                                         ((OpExpr *) node)->opfuncid);
00947     }
00948     else if (IsA(node, DistinctExpr))
00949     {
00950         set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
00951         record_plan_function_dependency(root,
00952                                         ((DistinctExpr *) node)->opfuncid);
00953     }
00954     else if (IsA(node, NullIfExpr))
00955     {
00956         set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
00957         record_plan_function_dependency(root,
00958                                         ((NullIfExpr *) node)->opfuncid);
00959     }
00960     else if (IsA(node, ScalarArrayOpExpr))
00961     {
00962         set_sa_opfuncid((ScalarArrayOpExpr *) node);
00963         record_plan_function_dependency(root,
00964                                      ((ScalarArrayOpExpr *) node)->opfuncid);
00965     }
00966     else if (IsA(node, ArrayCoerceExpr))
00967     {
00968         if (OidIsValid(((ArrayCoerceExpr *) node)->elemfuncid))
00969             record_plan_function_dependency(root,
00970                                      ((ArrayCoerceExpr *) node)->elemfuncid);
00971     }
00972     else if (IsA(node, Const))
00973     {
00974         Const      *con = (Const *) node;
00975 
00976         /* Check for regclass reference */
00977         if (ISREGCLASSCONST(con))
00978             root->glob->relationOids =
00979                 lappend_oid(root->glob->relationOids,
00980                             DatumGetObjectId(con->constvalue));
00981     }
00982 }
00983 
00984 /*
00985  * fix_scan_expr
00986  *      Do set_plan_references processing on a scan-level expression
00987  *
00988  * This consists of incrementing all Vars' varnos by rtoffset,
00989  * looking up operator opcode info for OpExpr and related nodes,
00990  * and adding OIDs from regclass Const nodes into root->glob->relationOids.
00991  */
00992 static Node *
00993 fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset)
00994 {
00995     fix_scan_expr_context context;
00996 
00997     context.root = root;
00998     context.rtoffset = rtoffset;
00999 
01000     if (rtoffset != 0 || root->glob->lastPHId != 0)
01001     {
01002         return fix_scan_expr_mutator(node, &context);
01003     }
01004     else
01005     {
01006         /*
01007          * If rtoffset == 0, we don't need to change any Vars, and if there
01008          * are no placeholders anywhere we won't need to remove them.  Then
01009          * it's OK to just scribble on the input node tree instead of copying
01010          * (since the only change, filling in any unset opfuncid fields, is
01011          * harmless).  This saves just enough cycles to be noticeable on
01012          * trivial queries.
01013          */
01014         (void) fix_scan_expr_walker(node, &context);
01015         return node;
01016     }
01017 }
01018 
01019 static Node *
01020 fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
01021 {
01022     if (node == NULL)
01023         return NULL;
01024     if (IsA(node, Var))
01025     {
01026         Var        *var = copyVar((Var *) node);
01027 
01028         Assert(var->varlevelsup == 0);
01029 
01030         /*
01031          * We should not see any Vars marked INNER_VAR or OUTER_VAR.  But an
01032          * indexqual expression could contain INDEX_VAR Vars.
01033          */
01034         Assert(var->varno != INNER_VAR);
01035         Assert(var->varno != OUTER_VAR);
01036         if (!IS_SPECIAL_VARNO(var->varno))
01037             var->varno += context->rtoffset;
01038         if (var->varnoold > 0)
01039             var->varnoold += context->rtoffset;
01040         return (Node *) var;
01041     }
01042     if (IsA(node, CurrentOfExpr))
01043     {
01044         CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
01045 
01046         Assert(cexpr->cvarno != INNER_VAR);
01047         Assert(cexpr->cvarno != OUTER_VAR);
01048         if (!IS_SPECIAL_VARNO(cexpr->cvarno))
01049             cexpr->cvarno += context->rtoffset;
01050         return (Node *) cexpr;
01051     }
01052     if (IsA(node, PlaceHolderVar))
01053     {
01054         /* At scan level, we should always just evaluate the contained expr */
01055         PlaceHolderVar *phv = (PlaceHolderVar *) node;
01056 
01057         return fix_scan_expr_mutator((Node *) phv->phexpr, context);
01058     }
01059     fix_expr_common(context->root, node);
01060     return expression_tree_mutator(node, fix_scan_expr_mutator,
01061                                    (void *) context);
01062 }
01063 
01064 static bool
01065 fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
01066 {
01067     if (node == NULL)
01068         return false;
01069     Assert(!IsA(node, PlaceHolderVar));
01070     fix_expr_common(context->root, node);
01071     return expression_tree_walker(node, fix_scan_expr_walker,
01072                                   (void *) context);
01073 }
01074 
01075 /*
01076  * set_join_references
01077  *    Modify the target list and quals of a join node to reference its
01078  *    subplans, by setting the varnos to OUTER_VAR or INNER_VAR and setting
01079  *    attno values to the result domain number of either the corresponding
01080  *    outer or inner join tuple item.  Also perform opcode lookup for these
01081  *    expressions. and add regclass OIDs to root->glob->relationOids.
01082  */
01083 static void
01084 set_join_references(PlannerInfo *root, Join *join, int rtoffset)
01085 {
01086     Plan       *outer_plan = join->plan.lefttree;
01087     Plan       *inner_plan = join->plan.righttree;
01088     indexed_tlist *outer_itlist;
01089     indexed_tlist *inner_itlist;
01090 
01091     outer_itlist = build_tlist_index(outer_plan->targetlist);
01092     inner_itlist = build_tlist_index(inner_plan->targetlist);
01093 
01094     /* All join plans have tlist, qual, and joinqual */
01095     join->plan.targetlist = fix_join_expr(root,
01096                                           join->plan.targetlist,
01097                                           outer_itlist,
01098                                           inner_itlist,
01099                                           (Index) 0,
01100                                           rtoffset);
01101     join->plan.qual = fix_join_expr(root,
01102                                     join->plan.qual,
01103                                     outer_itlist,
01104                                     inner_itlist,
01105                                     (Index) 0,
01106                                     rtoffset);
01107     join->joinqual = fix_join_expr(root,
01108                                    join->joinqual,
01109                                    outer_itlist,
01110                                    inner_itlist,
01111                                    (Index) 0,
01112                                    rtoffset);
01113 
01114     /* Now do join-type-specific stuff */
01115     if (IsA(join, NestLoop))
01116     {
01117         NestLoop   *nl = (NestLoop *) join;
01118         ListCell   *lc;
01119 
01120         foreach(lc, nl->nestParams)
01121         {
01122             NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
01123 
01124             nlp->paramval = (Var *) fix_upper_expr(root,
01125                                                    (Node *) nlp->paramval,
01126                                                    outer_itlist,
01127                                                    OUTER_VAR,
01128                                                    rtoffset);
01129             /* Check we replaced any PlaceHolderVar with simple Var */
01130             if (!(IsA(nlp->paramval, Var) &&
01131                   nlp->paramval->varno == OUTER_VAR))
01132                 elog(ERROR, "NestLoopParam was not reduced to a simple Var");
01133         }
01134     }
01135     else if (IsA(join, MergeJoin))
01136     {
01137         MergeJoin  *mj = (MergeJoin *) join;
01138 
01139         mj->mergeclauses = fix_join_expr(root,
01140                                          mj->mergeclauses,
01141                                          outer_itlist,
01142                                          inner_itlist,
01143                                          (Index) 0,
01144                                          rtoffset);
01145     }
01146     else if (IsA(join, HashJoin))
01147     {
01148         HashJoin   *hj = (HashJoin *) join;
01149 
01150         hj->hashclauses = fix_join_expr(root,
01151                                         hj->hashclauses,
01152                                         outer_itlist,
01153                                         inner_itlist,
01154                                         (Index) 0,
01155                                         rtoffset);
01156     }
01157 
01158     pfree(outer_itlist);
01159     pfree(inner_itlist);
01160 }
01161 
01162 /*
01163  * set_upper_references
01164  *    Update the targetlist and quals of an upper-level plan node
01165  *    to refer to the tuples returned by its lefttree subplan.
01166  *    Also perform opcode lookup for these expressions, and
01167  *    add regclass OIDs to root->glob->relationOids.
01168  *
01169  * This is used for single-input plan types like Agg, Group, Result.
01170  *
01171  * In most cases, we have to match up individual Vars in the tlist and
01172  * qual expressions with elements of the subplan's tlist (which was
01173  * generated by flatten_tlist() from these selfsame expressions, so it
01174  * should have all the required variables).  There is an important exception,
01175  * however: GROUP BY and ORDER BY expressions will have been pushed into the
01176  * subplan tlist unflattened.  If these values are also needed in the output
01177  * then we want to reference the subplan tlist element rather than recomputing
01178  * the expression.
01179  */
01180 static void
01181 set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
01182 {
01183     Plan       *subplan = plan->lefttree;
01184     indexed_tlist *subplan_itlist;
01185     List       *output_targetlist;
01186     ListCell   *l;
01187 
01188     subplan_itlist = build_tlist_index(subplan->targetlist);
01189 
01190     output_targetlist = NIL;
01191     foreach(l, plan->targetlist)
01192     {
01193         TargetEntry *tle = (TargetEntry *) lfirst(l);
01194         Node       *newexpr;
01195 
01196         /* If it's a non-Var sort/group item, first try to match by sortref */
01197         if (tle->ressortgroupref != 0 && !IsA(tle->expr, Var))
01198         {
01199             newexpr = (Node *)
01200                 search_indexed_tlist_for_sortgroupref((Node *) tle->expr,
01201                                                       tle->ressortgroupref,
01202                                                       subplan_itlist,
01203                                                       OUTER_VAR);
01204             if (!newexpr)
01205                 newexpr = fix_upper_expr(root,
01206                                          (Node *) tle->expr,
01207                                          subplan_itlist,
01208                                          OUTER_VAR,
01209                                          rtoffset);
01210         }
01211         else
01212             newexpr = fix_upper_expr(root,
01213                                      (Node *) tle->expr,
01214                                      subplan_itlist,
01215                                      OUTER_VAR,
01216                                      rtoffset);
01217         tle = flatCopyTargetEntry(tle);
01218         tle->expr = (Expr *) newexpr;
01219         output_targetlist = lappend(output_targetlist, tle);
01220     }
01221     plan->targetlist = output_targetlist;
01222 
01223     plan->qual = (List *)
01224         fix_upper_expr(root,
01225                        (Node *) plan->qual,
01226                        subplan_itlist,
01227                        OUTER_VAR,
01228                        rtoffset);
01229 
01230     pfree(subplan_itlist);
01231 }
01232 
01233 /*
01234  * set_dummy_tlist_references
01235  *    Replace the targetlist of an upper-level plan node with a simple
01236  *    list of OUTER_VAR references to its child.
01237  *
01238  * This is used for plan types like Sort and Append that don't evaluate
01239  * their targetlists.  Although the executor doesn't care at all what's in
01240  * the tlist, EXPLAIN needs it to be realistic.
01241  *
01242  * Note: we could almost use set_upper_references() here, but it fails for
01243  * Append for lack of a lefttree subplan.  Single-purpose code is faster
01244  * anyway.
01245  */
01246 static void
01247 set_dummy_tlist_references(Plan *plan, int rtoffset)
01248 {
01249     List       *output_targetlist;
01250     ListCell   *l;
01251 
01252     output_targetlist = NIL;
01253     foreach(l, plan->targetlist)
01254     {
01255         TargetEntry *tle = (TargetEntry *) lfirst(l);
01256         Var        *oldvar = (Var *) tle->expr;
01257         Var        *newvar;
01258 
01259         newvar = makeVar(OUTER_VAR,
01260                          tle->resno,
01261                          exprType((Node *) oldvar),
01262                          exprTypmod((Node *) oldvar),
01263                          exprCollation((Node *) oldvar),
01264                          0);
01265         if (IsA(oldvar, Var))
01266         {
01267             newvar->varnoold = oldvar->varno + rtoffset;
01268             newvar->varoattno = oldvar->varattno;
01269         }
01270         else
01271         {
01272             newvar->varnoold = 0;       /* wasn't ever a plain Var */
01273             newvar->varoattno = 0;
01274         }
01275 
01276         tle = flatCopyTargetEntry(tle);
01277         tle->expr = (Expr *) newvar;
01278         output_targetlist = lappend(output_targetlist, tle);
01279     }
01280     plan->targetlist = output_targetlist;
01281 
01282     /* We don't touch plan->qual here */
01283 }
01284 
01285 
01286 /*
01287  * build_tlist_index --- build an index data structure for a child tlist
01288  *
01289  * In most cases, subplan tlists will be "flat" tlists with only Vars,
01290  * so we try to optimize that case by extracting information about Vars
01291  * in advance.  Matching a parent tlist to a child is still an O(N^2)
01292  * operation, but at least with a much smaller constant factor than plain
01293  * tlist_member() searches.
01294  *
01295  * The result of this function is an indexed_tlist struct to pass to
01296  * search_indexed_tlist_for_var() or search_indexed_tlist_for_non_var().
01297  * When done, the indexed_tlist may be freed with a single pfree().
01298  */
01299 static indexed_tlist *
01300 build_tlist_index(List *tlist)
01301 {
01302     indexed_tlist *itlist;
01303     tlist_vinfo *vinfo;
01304     ListCell   *l;
01305 
01306     /* Create data structure with enough slots for all tlist entries */
01307     itlist = (indexed_tlist *)
01308         palloc(offsetof(indexed_tlist, vars) +
01309                list_length(tlist) * sizeof(tlist_vinfo));
01310 
01311     itlist->tlist = tlist;
01312     itlist->has_ph_vars = false;
01313     itlist->has_non_vars = false;
01314 
01315     /* Find the Vars and fill in the index array */
01316     vinfo = itlist->vars;
01317     foreach(l, tlist)
01318     {
01319         TargetEntry *tle = (TargetEntry *) lfirst(l);
01320 
01321         if (tle->expr && IsA(tle->expr, Var))
01322         {
01323             Var        *var = (Var *) tle->expr;
01324 
01325             vinfo->varno = var->varno;
01326             vinfo->varattno = var->varattno;
01327             vinfo->resno = tle->resno;
01328             vinfo++;
01329         }
01330         else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
01331             itlist->has_ph_vars = true;
01332         else
01333             itlist->has_non_vars = true;
01334     }
01335 
01336     itlist->num_vars = (vinfo - itlist->vars);
01337 
01338     return itlist;
01339 }
01340 
01341 /*
01342  * build_tlist_index_other_vars --- build a restricted tlist index
01343  *
01344  * This is like build_tlist_index, but we only index tlist entries that
01345  * are Vars belonging to some rel other than the one specified.  We will set
01346  * has_ph_vars (allowing PlaceHolderVars to be matched), but not has_non_vars
01347  * (so nothing other than Vars and PlaceHolderVars can be matched).
01348  */
01349 static indexed_tlist *
01350 build_tlist_index_other_vars(List *tlist, Index ignore_rel)
01351 {
01352     indexed_tlist *itlist;
01353     tlist_vinfo *vinfo;
01354     ListCell   *l;
01355 
01356     /* Create data structure with enough slots for all tlist entries */
01357     itlist = (indexed_tlist *)
01358         palloc(offsetof(indexed_tlist, vars) +
01359                list_length(tlist) * sizeof(tlist_vinfo));
01360 
01361     itlist->tlist = tlist;
01362     itlist->has_ph_vars = false;
01363     itlist->has_non_vars = false;
01364 
01365     /* Find the desired Vars and fill in the index array */
01366     vinfo = itlist->vars;
01367     foreach(l, tlist)
01368     {
01369         TargetEntry *tle = (TargetEntry *) lfirst(l);
01370 
01371         if (tle->expr && IsA(tle->expr, Var))
01372         {
01373             Var        *var = (Var *) tle->expr;
01374 
01375             if (var->varno != ignore_rel)
01376             {
01377                 vinfo->varno = var->varno;
01378                 vinfo->varattno = var->varattno;
01379                 vinfo->resno = tle->resno;
01380                 vinfo++;
01381             }
01382         }
01383         else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
01384             itlist->has_ph_vars = true;
01385     }
01386 
01387     itlist->num_vars = (vinfo - itlist->vars);
01388 
01389     return itlist;
01390 }
01391 
01392 /*
01393  * search_indexed_tlist_for_var --- find a Var in an indexed tlist
01394  *
01395  * If a match is found, return a copy of the given Var with suitably
01396  * modified varno/varattno (to wit, newvarno and the resno of the TLE entry).
01397  * Also ensure that varnoold is incremented by rtoffset.
01398  * If no match, return NULL.
01399  */
01400 static Var *
01401 search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist,
01402                              Index newvarno, int rtoffset)
01403 {
01404     Index       varno = var->varno;
01405     AttrNumber  varattno = var->varattno;
01406     tlist_vinfo *vinfo;
01407     int         i;
01408 
01409     vinfo = itlist->vars;
01410     i = itlist->num_vars;
01411     while (i-- > 0)
01412     {
01413         if (vinfo->varno == varno && vinfo->varattno == varattno)
01414         {
01415             /* Found a match */
01416             Var        *newvar = copyVar(var);
01417 
01418             newvar->varno = newvarno;
01419             newvar->varattno = vinfo->resno;
01420             if (newvar->varnoold > 0)
01421                 newvar->varnoold += rtoffset;
01422             return newvar;
01423         }
01424         vinfo++;
01425     }
01426     return NULL;                /* no match */
01427 }
01428 
01429 /*
01430  * search_indexed_tlist_for_non_var --- find a non-Var in an indexed tlist
01431  *
01432  * If a match is found, return a Var constructed to reference the tlist item.
01433  * If no match, return NULL.
01434  *
01435  * NOTE: it is a waste of time to call this unless itlist->has_ph_vars or
01436  * itlist->has_non_vars
01437  */
01438 static Var *
01439 search_indexed_tlist_for_non_var(Node *node,
01440                                  indexed_tlist *itlist, Index newvarno)
01441 {
01442     TargetEntry *tle;
01443 
01444     tle = tlist_member(node, itlist->tlist);
01445     if (tle)
01446     {
01447         /* Found a matching subplan output expression */
01448         Var        *newvar;
01449 
01450         newvar = makeVarFromTargetEntry(newvarno, tle);
01451         newvar->varnoold = 0;   /* wasn't ever a plain Var */
01452         newvar->varoattno = 0;
01453         return newvar;
01454     }
01455     return NULL;                /* no match */
01456 }
01457 
01458 /*
01459  * search_indexed_tlist_for_sortgroupref --- find a sort/group expression
01460  *      (which is assumed not to be just a Var)
01461  *
01462  * If a match is found, return a Var constructed to reference the tlist item.
01463  * If no match, return NULL.
01464  *
01465  * This is needed to ensure that we select the right subplan TLE in cases
01466  * where there are multiple textually-equal()-but-volatile sort expressions.
01467  * And it's also faster than search_indexed_tlist_for_non_var.
01468  */
01469 static Var *
01470 search_indexed_tlist_for_sortgroupref(Node *node,
01471                                       Index sortgroupref,
01472                                       indexed_tlist *itlist,
01473                                       Index newvarno)
01474 {
01475     ListCell   *lc;
01476 
01477     foreach(lc, itlist->tlist)
01478     {
01479         TargetEntry *tle = (TargetEntry *) lfirst(lc);
01480 
01481         /* The equal() check should be redundant, but let's be paranoid */
01482         if (tle->ressortgroupref == sortgroupref &&
01483             equal(node, tle->expr))
01484         {
01485             /* Found a matching subplan output expression */
01486             Var        *newvar;
01487 
01488             newvar = makeVarFromTargetEntry(newvarno, tle);
01489             newvar->varnoold = 0;       /* wasn't ever a plain Var */
01490             newvar->varoattno = 0;
01491             return newvar;
01492         }
01493     }
01494     return NULL;                /* no match */
01495 }
01496 
01497 /*
01498  * fix_join_expr
01499  *     Create a new set of targetlist entries or join qual clauses by
01500  *     changing the varno/varattno values of variables in the clauses
01501  *     to reference target list values from the outer and inner join
01502  *     relation target lists.  Also perform opcode lookup and add
01503  *     regclass OIDs to root->glob->relationOids.
01504  *
01505  * This is used in two different scenarios: a normal join clause, where all
01506  * the Vars in the clause *must* be replaced by OUTER_VAR or INNER_VAR
01507  * references; and a RETURNING clause, which may contain both Vars of the
01508  * target relation and Vars of other relations.  In the latter case we want
01509  * to replace the other-relation Vars by OUTER_VAR references, while leaving
01510  * target Vars alone.
01511  *
01512  * For a normal join, acceptable_rel should be zero so that any failure to
01513  * match a Var will be reported as an error.  For the RETURNING case, pass
01514  * inner_itlist = NULL and acceptable_rel = the ID of the target relation.
01515  *
01516  * 'clauses' is the targetlist or list of join clauses
01517  * 'outer_itlist' is the indexed target list of the outer join relation
01518  * 'inner_itlist' is the indexed target list of the inner join relation,
01519  *      or NULL
01520  * 'acceptable_rel' is either zero or the rangetable index of a relation
01521  *      whose Vars may appear in the clause without provoking an error
01522  * 'rtoffset': how much to increment varnoold by
01523  *
01524  * Returns the new expression tree.  The original clause structure is
01525  * not modified.
01526  */
01527 static List *
01528 fix_join_expr(PlannerInfo *root,
01529               List *clauses,
01530               indexed_tlist *outer_itlist,
01531               indexed_tlist *inner_itlist,
01532               Index acceptable_rel,
01533               int rtoffset)
01534 {
01535     fix_join_expr_context context;
01536 
01537     context.root = root;
01538     context.outer_itlist = outer_itlist;
01539     context.inner_itlist = inner_itlist;
01540     context.acceptable_rel = acceptable_rel;
01541     context.rtoffset = rtoffset;
01542     return (List *) fix_join_expr_mutator((Node *) clauses, &context);
01543 }
01544 
01545 static Node *
01546 fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
01547 {
01548     Var        *newvar;
01549 
01550     if (node == NULL)
01551         return NULL;
01552     if (IsA(node, Var))
01553     {
01554         Var        *var = (Var *) node;
01555 
01556         /* First look for the var in the input tlists */
01557         newvar = search_indexed_tlist_for_var(var,
01558                                               context->outer_itlist,
01559                                               OUTER_VAR,
01560                                               context->rtoffset);
01561         if (newvar)
01562             return (Node *) newvar;
01563         if (context->inner_itlist)
01564         {
01565             newvar = search_indexed_tlist_for_var(var,
01566                                                   context->inner_itlist,
01567                                                   INNER_VAR,
01568                                                   context->rtoffset);
01569             if (newvar)
01570                 return (Node *) newvar;
01571         }
01572 
01573         /* If it's for acceptable_rel, adjust and return it */
01574         if (var->varno == context->acceptable_rel)
01575         {
01576             var = copyVar(var);
01577             var->varno += context->rtoffset;
01578             if (var->varnoold > 0)
01579                 var->varnoold += context->rtoffset;
01580             return (Node *) var;
01581         }
01582 
01583         /* No referent found for Var */
01584         elog(ERROR, "variable not found in subplan target lists");
01585     }
01586     if (IsA(node, PlaceHolderVar))
01587     {
01588         PlaceHolderVar *phv = (PlaceHolderVar *) node;
01589 
01590         /* See if the PlaceHolderVar has bubbled up from a lower plan node */
01591         if (context->outer_itlist->has_ph_vars)
01592         {
01593             newvar = search_indexed_tlist_for_non_var((Node *) phv,
01594                                                       context->outer_itlist,
01595                                                       OUTER_VAR);
01596             if (newvar)
01597                 return (Node *) newvar;
01598         }
01599         if (context->inner_itlist && context->inner_itlist->has_ph_vars)
01600         {
01601             newvar = search_indexed_tlist_for_non_var((Node *) phv,
01602                                                       context->inner_itlist,
01603                                                       INNER_VAR);
01604             if (newvar)
01605                 return (Node *) newvar;
01606         }
01607 
01608         /* If not supplied by input plans, evaluate the contained expr */
01609         return fix_join_expr_mutator((Node *) phv->phexpr, context);
01610     }
01611     /* Try matching more complex expressions too, if tlists have any */
01612     if (context->outer_itlist->has_non_vars)
01613     {
01614         newvar = search_indexed_tlist_for_non_var(node,
01615                                                   context->outer_itlist,
01616                                                   OUTER_VAR);
01617         if (newvar)
01618             return (Node *) newvar;
01619     }
01620     if (context->inner_itlist && context->inner_itlist->has_non_vars)
01621     {
01622         newvar = search_indexed_tlist_for_non_var(node,
01623                                                   context->inner_itlist,
01624                                                   INNER_VAR);
01625         if (newvar)
01626             return (Node *) newvar;
01627     }
01628     fix_expr_common(context->root, node);
01629     return expression_tree_mutator(node,
01630                                    fix_join_expr_mutator,
01631                                    (void *) context);
01632 }
01633 
01634 /*
01635  * fix_upper_expr
01636  *      Modifies an expression tree so that all Var nodes reference outputs
01637  *      of a subplan.  Also performs opcode lookup, and adds regclass OIDs to
01638  *      root->glob->relationOids.
01639  *
01640  * This is used to fix up target and qual expressions of non-join upper-level
01641  * plan nodes, as well as index-only scan nodes.
01642  *
01643  * An error is raised if no matching var can be found in the subplan tlist
01644  * --- so this routine should only be applied to nodes whose subplans'
01645  * targetlists were generated via flatten_tlist() or some such method.
01646  *
01647  * If itlist->has_non_vars is true, then we try to match whole subexpressions
01648  * against elements of the subplan tlist, so that we can avoid recomputing
01649  * expressions that were already computed by the subplan.  (This is relatively
01650  * expensive, so we don't want to try it in the common case where the
01651  * subplan tlist is just a flattened list of Vars.)
01652  *
01653  * 'node': the tree to be fixed (a target item or qual)
01654  * 'subplan_itlist': indexed target list for subplan (or index)
01655  * 'newvarno': varno to use for Vars referencing tlist elements
01656  * 'rtoffset': how much to increment varnoold by
01657  *
01658  * The resulting tree is a copy of the original in which all Var nodes have
01659  * varno = newvarno, varattno = resno of corresponding targetlist element.
01660  * The original tree is not modified.
01661  */
01662 static Node *
01663 fix_upper_expr(PlannerInfo *root,
01664                Node *node,
01665                indexed_tlist *subplan_itlist,
01666                Index newvarno,
01667                int rtoffset)
01668 {
01669     fix_upper_expr_context context;
01670 
01671     context.root = root;
01672     context.subplan_itlist = subplan_itlist;
01673     context.newvarno = newvarno;
01674     context.rtoffset = rtoffset;
01675     return fix_upper_expr_mutator(node, &context);
01676 }
01677 
01678 static Node *
01679 fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
01680 {
01681     Var        *newvar;
01682 
01683     if (node == NULL)
01684         return NULL;
01685     if (IsA(node, Var))
01686     {
01687         Var        *var = (Var *) node;
01688 
01689         newvar = search_indexed_tlist_for_var(var,
01690                                               context->subplan_itlist,
01691                                               context->newvarno,
01692                                               context->rtoffset);
01693         if (!newvar)
01694             elog(ERROR, "variable not found in subplan target list");
01695         return (Node *) newvar;
01696     }
01697     if (IsA(node, PlaceHolderVar))
01698     {
01699         PlaceHolderVar *phv = (PlaceHolderVar *) node;
01700 
01701         /* See if the PlaceHolderVar has bubbled up from a lower plan node */
01702         if (context->subplan_itlist->has_ph_vars)
01703         {
01704             newvar = search_indexed_tlist_for_non_var((Node *) phv,
01705                                                       context->subplan_itlist,
01706                                                       context->newvarno);
01707             if (newvar)
01708                 return (Node *) newvar;
01709         }
01710         /* If not supplied by input plan, evaluate the contained expr */
01711         return fix_upper_expr_mutator((Node *) phv->phexpr, context);
01712     }
01713     /* Try matching more complex expressions too, if tlist has any */
01714     if (context->subplan_itlist->has_non_vars)
01715     {
01716         newvar = search_indexed_tlist_for_non_var(node,
01717                                                   context->subplan_itlist,
01718                                                   context->newvarno);
01719         if (newvar)
01720             return (Node *) newvar;
01721     }
01722     fix_expr_common(context->root, node);
01723     return expression_tree_mutator(node,
01724                                    fix_upper_expr_mutator,
01725                                    (void *) context);
01726 }
01727 
01728 /*
01729  * set_returning_clause_references
01730  *      Perform setrefs.c's work on a RETURNING targetlist
01731  *
01732  * If the query involves more than just the result table, we have to
01733  * adjust any Vars that refer to other tables to reference junk tlist
01734  * entries in the top subplan's targetlist.  Vars referencing the result
01735  * table should be left alone, however (the executor will evaluate them
01736  * using the actual heap tuple, after firing triggers if any).  In the
01737  * adjusted RETURNING list, result-table Vars will have their original
01738  * varno (plus rtoffset), but Vars for other rels will have varno OUTER_VAR.
01739  *
01740  * We also must perform opcode lookup and add regclass OIDs to
01741  * root->glob->relationOids.
01742  *
01743  * 'rlist': the RETURNING targetlist to be fixed
01744  * 'topplan': the top subplan node that will be just below the ModifyTable
01745  *      node (note it's not yet passed through set_plan_refs)
01746  * 'resultRelation': RT index of the associated result relation
01747  * 'rtoffset': how much to increment varnos by
01748  *
01749  * Note: the given 'root' is for the parent query level, not the 'topplan'.
01750  * This does not matter currently since we only access the dependency-item
01751  * lists in root->glob, but it would need some hacking if we wanted a root
01752  * that actually matches the subplan.
01753  *
01754  * Note: resultRelation is not yet adjusted by rtoffset.
01755  */
01756 static List *
01757 set_returning_clause_references(PlannerInfo *root,
01758                                 List *rlist,
01759                                 Plan *topplan,
01760                                 Index resultRelation,
01761                                 int rtoffset)
01762 {
01763     indexed_tlist *itlist;
01764 
01765     /*
01766      * We can perform the desired Var fixup by abusing the fix_join_expr
01767      * machinery that formerly handled inner indexscan fixup.  We search the
01768      * top plan's targetlist for Vars of non-result relations, and use
01769      * fix_join_expr to convert RETURNING Vars into references to those tlist
01770      * entries, while leaving result-rel Vars as-is.
01771      *
01772      * PlaceHolderVars will also be sought in the targetlist, but no
01773      * more-complex expressions will be.  Note that it is not possible for a
01774      * PlaceHolderVar to refer to the result relation, since the result is
01775      * never below an outer join.  If that case could happen, we'd have to be
01776      * prepared to pick apart the PlaceHolderVar and evaluate its contained
01777      * expression instead.
01778      */
01779     itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
01780 
01781     rlist = fix_join_expr(root,
01782                           rlist,
01783                           itlist,
01784                           NULL,
01785                           resultRelation,
01786                           rtoffset);
01787 
01788     pfree(itlist);
01789 
01790     return rlist;
01791 }
01792 
01793 /*****************************************************************************
01794  *                  OPERATOR REGPROC LOOKUP
01795  *****************************************************************************/
01796 
01797 /*
01798  * fix_opfuncids
01799  *    Calculate opfuncid field from opno for each OpExpr node in given tree.
01800  *    The given tree can be anything expression_tree_walker handles.
01801  *
01802  * The argument is modified in-place.  (This is OK since we'd want the
01803  * same change for any node, even if it gets visited more than once due to
01804  * shared structure.)
01805  */
01806 void
01807 fix_opfuncids(Node *node)
01808 {
01809     /* This tree walk requires no special setup, so away we go... */
01810     fix_opfuncids_walker(node, NULL);
01811 }
01812 
01813 static bool
01814 fix_opfuncids_walker(Node *node, void *context)
01815 {
01816     if (node == NULL)
01817         return false;
01818     if (IsA(node, OpExpr))
01819         set_opfuncid((OpExpr *) node);
01820     else if (IsA(node, DistinctExpr))
01821         set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
01822     else if (IsA(node, NullIfExpr))
01823         set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
01824     else if (IsA(node, ScalarArrayOpExpr))
01825         set_sa_opfuncid((ScalarArrayOpExpr *) node);
01826     return expression_tree_walker(node, fix_opfuncids_walker, context);
01827 }
01828 
01829 /*
01830  * set_opfuncid
01831  *      Set the opfuncid (procedure OID) in an OpExpr node,
01832  *      if it hasn't been set already.
01833  *
01834  * Because of struct equivalence, this can also be used for
01835  * DistinctExpr and NullIfExpr nodes.
01836  */
01837 void
01838 set_opfuncid(OpExpr *opexpr)
01839 {
01840     if (opexpr->opfuncid == InvalidOid)
01841         opexpr->opfuncid = get_opcode(opexpr->opno);
01842 }
01843 
01844 /*
01845  * set_sa_opfuncid
01846  *      As above, for ScalarArrayOpExpr nodes.
01847  */
01848 void
01849 set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
01850 {
01851     if (opexpr->opfuncid == InvalidOid)
01852         opexpr->opfuncid = get_opcode(opexpr->opno);
01853 }
01854 
01855 /*****************************************************************************
01856  *                  QUERY DEPENDENCY MANAGEMENT
01857  *****************************************************************************/
01858 
01859 /*
01860  * record_plan_function_dependency
01861  *      Mark the current plan as depending on a particular function.
01862  *
01863  * This is exported so that the function-inlining code can record a
01864  * dependency on a function that it's removed from the plan tree.
01865  */
01866 void
01867 record_plan_function_dependency(PlannerInfo *root, Oid funcid)
01868 {
01869     /*
01870      * For performance reasons, we don't bother to track built-in functions;
01871      * we just assume they'll never change (or at least not in ways that'd
01872      * invalidate plans using them).  For this purpose we can consider a
01873      * built-in function to be one with OID less than FirstBootstrapObjectId.
01874      * Note that the OID generator guarantees never to generate such an OID
01875      * after startup, even at OID wraparound.
01876      */
01877     if (funcid >= (Oid) FirstBootstrapObjectId)
01878     {
01879         PlanInvalItem *inval_item = makeNode(PlanInvalItem);
01880 
01881         /*
01882          * It would work to use any syscache on pg_proc, but the easiest is
01883          * PROCOID since we already have the function's OID at hand.  Note
01884          * that plancache.c knows we use PROCOID.
01885          */
01886         inval_item->cacheId = PROCOID;
01887         inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
01888                                                    ObjectIdGetDatum(funcid));
01889 
01890         root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
01891     }
01892 }
01893 
01894 /*
01895  * extract_query_dependencies
01896  *      Given a not-yet-planned query or queries (i.e. a Query node or list
01897  *      of Query nodes), extract dependencies just as set_plan_references
01898  *      would do.
01899  *
01900  * This is needed by plancache.c to handle invalidation of cached unplanned
01901  * queries.
01902  */
01903 void
01904 extract_query_dependencies(Node *query,
01905                            List **relationOids,
01906                            List **invalItems)
01907 {
01908     PlannerGlobal glob;
01909     PlannerInfo root;
01910 
01911     /* Make up dummy planner state so we can use this module's machinery */
01912     MemSet(&glob, 0, sizeof(glob));
01913     glob.type = T_PlannerGlobal;
01914     glob.relationOids = NIL;
01915     glob.invalItems = NIL;
01916 
01917     MemSet(&root, 0, sizeof(root));
01918     root.type = T_PlannerInfo;
01919     root.glob = &glob;
01920 
01921     (void) extract_query_dependencies_walker(query, &root);
01922 
01923     *relationOids = glob.relationOids;
01924     *invalItems = glob.invalItems;
01925 }
01926 
01927 static bool
01928 extract_query_dependencies_walker(Node *node, PlannerInfo *context)
01929 {
01930     if (node == NULL)
01931         return false;
01932     Assert(!IsA(node, PlaceHolderVar));
01933     /* Extract function dependencies and check for regclass Consts */
01934     fix_expr_common(context, node);
01935     if (IsA(node, Query))
01936     {
01937         Query      *query = (Query *) node;
01938         ListCell   *lc;
01939 
01940         if (query->commandType == CMD_UTILITY)
01941         {
01942             /*
01943              * Ignore utility statements, except those (such as EXPLAIN) that
01944              * contain a parsed-but-not-planned query.
01945              */
01946             query = UtilityContainsQuery(query->utilityStmt);
01947             if (query == NULL)
01948                 return false;
01949         }
01950 
01951         /* Collect relation OIDs in this Query's rtable */
01952         foreach(lc, query->rtable)
01953         {
01954             RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
01955 
01956             if (rte->rtekind == RTE_RELATION)
01957                 context->glob->relationOids =
01958                     lappend_oid(context->glob->relationOids, rte->relid);
01959         }
01960 
01961         /* And recurse into the query's subexpressions */
01962         return query_tree_walker(query, extract_query_dependencies_walker,
01963                                  (void *) context, 0);
01964     }
01965     return expression_tree_walker(node, extract_query_dependencies_walker,
01966                                   (void *) context);
01967 }