Header And Logo

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

var.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * var.c
00004  *    Var node manipulation routines
00005  *
00006  * Note: for most purposes, PlaceHolderVar is considered a Var too,
00007  * even if its contained expression is variable-free.  Also, CurrentOfExpr
00008  * is treated as a Var for purposes of determining whether an expression
00009  * contains variables.
00010  *
00011  *
00012  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00013  * Portions Copyright (c) 1994, Regents of the University of California
00014  *
00015  *
00016  * IDENTIFICATION
00017  *    src/backend/optimizer/util/var.c
00018  *
00019  *-------------------------------------------------------------------------
00020  */
00021 #include "postgres.h"
00022 
00023 #include "access/sysattr.h"
00024 #include "nodes/nodeFuncs.h"
00025 #include "optimizer/prep.h"
00026 #include "optimizer/var.h"
00027 #include "parser/parsetree.h"
00028 #include "rewrite/rewriteManip.h"
00029 
00030 
00031 typedef struct
00032 {
00033     Relids      varnos;
00034     int         sublevels_up;
00035 } pull_varnos_context;
00036 
00037 typedef struct
00038 {
00039     Bitmapset  *varattnos;
00040     Index       varno;
00041 } pull_varattnos_context;
00042 
00043 typedef struct
00044 {
00045     List       *vars;
00046     int         sublevels_up;
00047 } pull_vars_context;
00048 
00049 typedef struct
00050 {
00051     int         var_location;
00052     int         sublevels_up;
00053 } locate_var_of_level_context;
00054 
00055 typedef struct
00056 {
00057     List       *varlist;
00058     PVCAggregateBehavior aggbehavior;
00059     PVCPlaceHolderBehavior phbehavior;
00060 } pull_var_clause_context;
00061 
00062 typedef struct
00063 {
00064     PlannerInfo *root;
00065     int         sublevels_up;
00066     bool        possible_sublink;       /* could aliases include a SubLink? */
00067     bool        inserted_sublink;       /* have we inserted a SubLink? */
00068 } flatten_join_alias_vars_context;
00069 
00070 static bool pull_varnos_walker(Node *node,
00071                    pull_varnos_context *context);
00072 static bool pull_varattnos_walker(Node *node, pull_varattnos_context *context);
00073 static bool pull_vars_walker(Node *node, pull_vars_context *context);
00074 static bool contain_var_clause_walker(Node *node, void *context);
00075 static bool contain_vars_of_level_walker(Node *node, int *sublevels_up);
00076 static bool locate_var_of_level_walker(Node *node,
00077                            locate_var_of_level_context *context);
00078 static bool pull_var_clause_walker(Node *node,
00079                        pull_var_clause_context *context);
00080 static Node *flatten_join_alias_vars_mutator(Node *node,
00081                                 flatten_join_alias_vars_context *context);
00082 static Relids alias_relid_set(PlannerInfo *root, Relids relids);
00083 
00084 
00085 /*
00086  * pull_varnos
00087  *      Create a set of all the distinct varnos present in a parsetree.
00088  *      Only varnos that reference level-zero rtable entries are considered.
00089  *
00090  * NOTE: this is used on not-yet-planned expressions.  It may therefore find
00091  * bare SubLinks, and if so it needs to recurse into them to look for uplevel
00092  * references to the desired rtable level!  But when we find a completed
00093  * SubPlan, we only need to look at the parameters passed to the subplan.
00094  */
00095 Relids
00096 pull_varnos(Node *node)
00097 {
00098     pull_varnos_context context;
00099 
00100     context.varnos = NULL;
00101     context.sublevels_up = 0;
00102 
00103     /*
00104      * Must be prepared to start with a Query or a bare expression tree; if
00105      * it's a Query, we don't want to increment sublevels_up.
00106      */
00107     query_or_expression_tree_walker(node,
00108                                     pull_varnos_walker,
00109                                     (void *) &context,
00110                                     0);
00111 
00112     return context.varnos;
00113 }
00114 
00115 /*
00116  * pull_varnos_of_level
00117  *      Create a set of all the distinct varnos present in a parsetree.
00118  *      Only Vars of the specified level are considered.
00119  */
00120 Relids
00121 pull_varnos_of_level(Node *node, int levelsup)
00122 {
00123     pull_varnos_context context;
00124 
00125     context.varnos = NULL;
00126     context.sublevels_up = levelsup;
00127 
00128     /*
00129      * Must be prepared to start with a Query or a bare expression tree; if
00130      * it's a Query, we don't want to increment sublevels_up.
00131      */
00132     query_or_expression_tree_walker(node,
00133                                     pull_varnos_walker,
00134                                     (void *) &context,
00135                                     0);
00136 
00137     return context.varnos;
00138 }
00139 
00140 static bool
00141 pull_varnos_walker(Node *node, pull_varnos_context *context)
00142 {
00143     if (node == NULL)
00144         return false;
00145     if (IsA(node, Var))
00146     {
00147         Var        *var = (Var *) node;
00148 
00149         if (var->varlevelsup == context->sublevels_up)
00150             context->varnos = bms_add_member(context->varnos, var->varno);
00151         return false;
00152     }
00153     if (IsA(node, CurrentOfExpr))
00154     {
00155         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
00156 
00157         if (context->sublevels_up == 0)
00158             context->varnos = bms_add_member(context->varnos, cexpr->cvarno);
00159         return false;
00160     }
00161     if (IsA(node, PlaceHolderVar))
00162     {
00163         /*
00164          * Normally, we can just take the varnos in the contained expression.
00165          * But if it is variable-free, use the PHV's syntactic relids.
00166          */
00167         PlaceHolderVar *phv = (PlaceHolderVar *) node;
00168         pull_varnos_context subcontext;
00169 
00170         subcontext.varnos = NULL;
00171         subcontext.sublevels_up = context->sublevels_up;
00172         (void) pull_varnos_walker((Node *) phv->phexpr, &subcontext);
00173 
00174         if (bms_is_empty(subcontext.varnos) &&
00175             phv->phlevelsup == context->sublevels_up)
00176             context->varnos = bms_add_members(context->varnos, phv->phrels);
00177         else
00178             context->varnos = bms_join(context->varnos, subcontext.varnos);
00179         return false;
00180     }
00181     if (IsA(node, Query))
00182     {
00183         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
00184         bool        result;
00185 
00186         context->sublevels_up++;
00187         result = query_tree_walker((Query *) node, pull_varnos_walker,
00188                                    (void *) context, 0);
00189         context->sublevels_up--;
00190         return result;
00191     }
00192     return expression_tree_walker(node, pull_varnos_walker,
00193                                   (void *) context);
00194 }
00195 
00196 
00197 /*
00198  * pull_varattnos
00199  *      Find all the distinct attribute numbers present in an expression tree,
00200  *      and add them to the initial contents of *varattnos.
00201  *      Only Vars of the given varno and rtable level zero are considered.
00202  *
00203  * Attribute numbers are offset by FirstLowInvalidHeapAttributeNumber so that
00204  * we can include system attributes (e.g., OID) in the bitmap representation.
00205  *
00206  * Currently, this does not support unplanned subqueries; that is not needed
00207  * for current uses.  It will handle already-planned SubPlan nodes, though,
00208  * looking into only the "testexpr" and the "args" list.  (The subplan cannot
00209  * contain any other references to Vars of the current level.)
00210  */
00211 void
00212 pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
00213 {
00214     pull_varattnos_context context;
00215 
00216     context.varattnos = *varattnos;
00217     context.varno = varno;
00218 
00219     (void) pull_varattnos_walker(node, &context);
00220 
00221     *varattnos = context.varattnos;
00222 }
00223 
00224 static bool
00225 pull_varattnos_walker(Node *node, pull_varattnos_context *context)
00226 {
00227     if (node == NULL)
00228         return false;
00229     if (IsA(node, Var))
00230     {
00231         Var        *var = (Var *) node;
00232 
00233         if (var->varno == context->varno && var->varlevelsup == 0)
00234             context->varattnos =
00235                 bms_add_member(context->varattnos,
00236                          var->varattno - FirstLowInvalidHeapAttributeNumber);
00237         return false;
00238     }
00239 
00240     /* Should not find an unplanned subquery */
00241     Assert(!IsA(node, Query));
00242 
00243     return expression_tree_walker(node, pull_varattnos_walker,
00244                                   (void *) context);
00245 }
00246 
00247 
00248 /*
00249  * pull_vars_of_level
00250  *      Create a list of all Vars (and PlaceHolderVars) referencing the
00251  *      specified query level in the given parsetree.
00252  *
00253  * Caution: the Vars are not copied, only linked into the list.
00254  */
00255 List *
00256 pull_vars_of_level(Node *node, int levelsup)
00257 {
00258     pull_vars_context context;
00259 
00260     context.vars = NIL;
00261     context.sublevels_up = levelsup;
00262 
00263     /*
00264      * Must be prepared to start with a Query or a bare expression tree; if
00265      * it's a Query, we don't want to increment sublevels_up.
00266      */
00267     query_or_expression_tree_walker(node,
00268                                     pull_vars_walker,
00269                                     (void *) &context,
00270                                     0);
00271 
00272     return context.vars;
00273 }
00274 
00275 static bool
00276 pull_vars_walker(Node *node, pull_vars_context *context)
00277 {
00278     if (node == NULL)
00279         return false;
00280     if (IsA(node, Var))
00281     {
00282         Var        *var = (Var *) node;
00283 
00284         if (var->varlevelsup == context->sublevels_up)
00285             context->vars = lappend(context->vars, var);
00286         return false;
00287     }
00288     if (IsA(node, PlaceHolderVar))
00289     {
00290         PlaceHolderVar *phv = (PlaceHolderVar *) node;
00291 
00292         if (phv->phlevelsup == context->sublevels_up)
00293             context->vars = lappend(context->vars, phv);
00294         /* we don't want to look into the contained expression */
00295         return false;
00296     }
00297     if (IsA(node, Query))
00298     {
00299         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
00300         bool        result;
00301 
00302         context->sublevels_up++;
00303         result = query_tree_walker((Query *) node, pull_vars_walker,
00304                                    (void *) context, 0);
00305         context->sublevels_up--;
00306         return result;
00307     }
00308     return expression_tree_walker(node, pull_vars_walker,
00309                                   (void *) context);
00310 }
00311 
00312 
00313 /*
00314  * contain_var_clause
00315  *    Recursively scan a clause to discover whether it contains any Var nodes
00316  *    (of the current query level).
00317  *
00318  *    Returns true if any varnode found.
00319  *
00320  * Does not examine subqueries, therefore must only be used after reduction
00321  * of sublinks to subplans!
00322  */
00323 bool
00324 contain_var_clause(Node *node)
00325 {
00326     return contain_var_clause_walker(node, NULL);
00327 }
00328 
00329 static bool
00330 contain_var_clause_walker(Node *node, void *context)
00331 {
00332     if (node == NULL)
00333         return false;
00334     if (IsA(node, Var))
00335     {
00336         if (((Var *) node)->varlevelsup == 0)
00337             return true;        /* abort the tree traversal and return true */
00338         return false;
00339     }
00340     if (IsA(node, CurrentOfExpr))
00341         return true;
00342     if (IsA(node, PlaceHolderVar))
00343     {
00344         if (((PlaceHolderVar *) node)->phlevelsup == 0)
00345             return true;        /* abort the tree traversal and return true */
00346         /* else fall through to check the contained expr */
00347     }
00348     return expression_tree_walker(node, contain_var_clause_walker, context);
00349 }
00350 
00351 
00352 /*
00353  * contain_vars_of_level
00354  *    Recursively scan a clause to discover whether it contains any Var nodes
00355  *    of the specified query level.
00356  *
00357  *    Returns true if any such Var found.
00358  *
00359  * Will recurse into sublinks.  Also, may be invoked directly on a Query.
00360  */
00361 bool
00362 contain_vars_of_level(Node *node, int levelsup)
00363 {
00364     int         sublevels_up = levelsup;
00365 
00366     return query_or_expression_tree_walker(node,
00367                                            contain_vars_of_level_walker,
00368                                            (void *) &sublevels_up,
00369                                            0);
00370 }
00371 
00372 static bool
00373 contain_vars_of_level_walker(Node *node, int *sublevels_up)
00374 {
00375     if (node == NULL)
00376         return false;
00377     if (IsA(node, Var))
00378     {
00379         if (((Var *) node)->varlevelsup == *sublevels_up)
00380             return true;        /* abort tree traversal and return true */
00381         return false;
00382     }
00383     if (IsA(node, CurrentOfExpr))
00384     {
00385         if (*sublevels_up == 0)
00386             return true;
00387         return false;
00388     }
00389     if (IsA(node, PlaceHolderVar))
00390     {
00391         if (((PlaceHolderVar *) node)->phlevelsup == *sublevels_up)
00392             return true;        /* abort the tree traversal and return true */
00393         /* else fall through to check the contained expr */
00394     }
00395     if (IsA(node, Query))
00396     {
00397         /* Recurse into subselects */
00398         bool        result;
00399 
00400         (*sublevels_up)++;
00401         result = query_tree_walker((Query *) node,
00402                                    contain_vars_of_level_walker,
00403                                    (void *) sublevels_up,
00404                                    0);
00405         (*sublevels_up)--;
00406         return result;
00407     }
00408     return expression_tree_walker(node,
00409                                   contain_vars_of_level_walker,
00410                                   (void *) sublevels_up);
00411 }
00412 
00413 
00414 /*
00415  * locate_var_of_level
00416  *    Find the parse location of any Var of the specified query level.
00417  *
00418  * Returns -1 if no such Var is in the querytree, or if they all have
00419  * unknown parse location.  (The former case is probably caller error,
00420  * but we don't bother to distinguish it from the latter case.)
00421  *
00422  * Will recurse into sublinks.  Also, may be invoked directly on a Query.
00423  *
00424  * Note: it might seem appropriate to merge this functionality into
00425  * contain_vars_of_level, but that would complicate that function's API.
00426  * Currently, the only uses of this function are for error reporting,
00427  * and so shaving cycles probably isn't very important.
00428  */
00429 int
00430 locate_var_of_level(Node *node, int levelsup)
00431 {
00432     locate_var_of_level_context context;
00433 
00434     context.var_location = -1;  /* in case we find nothing */
00435     context.sublevels_up = levelsup;
00436 
00437     (void) query_or_expression_tree_walker(node,
00438                                            locate_var_of_level_walker,
00439                                            (void *) &context,
00440                                            0);
00441 
00442     return context.var_location;
00443 }
00444 
00445 static bool
00446 locate_var_of_level_walker(Node *node,
00447                            locate_var_of_level_context *context)
00448 {
00449     if (node == NULL)
00450         return false;
00451     if (IsA(node, Var))
00452     {
00453         Var        *var = (Var *) node;
00454 
00455         if (var->varlevelsup == context->sublevels_up &&
00456             var->location >= 0)
00457         {
00458             context->var_location = var->location;
00459             return true;        /* abort tree traversal and return true */
00460         }
00461         return false;
00462     }
00463     if (IsA(node, CurrentOfExpr))
00464     {
00465         /* since CurrentOfExpr doesn't carry location, nothing we can do */
00466         return false;
00467     }
00468     /* No extra code needed for PlaceHolderVar; just look in contained expr */
00469     if (IsA(node, Query))
00470     {
00471         /* Recurse into subselects */
00472         bool        result;
00473 
00474         context->sublevels_up++;
00475         result = query_tree_walker((Query *) node,
00476                                    locate_var_of_level_walker,
00477                                    (void *) context,
00478                                    0);
00479         context->sublevels_up--;
00480         return result;
00481     }
00482     return expression_tree_walker(node,
00483                                   locate_var_of_level_walker,
00484                                   (void *) context);
00485 }
00486 
00487 
00488 /*
00489  * pull_var_clause
00490  *    Recursively pulls all Var nodes from an expression clause.
00491  *
00492  *    Aggrefs are handled according to 'aggbehavior':
00493  *      PVC_REJECT_AGGREGATES       throw error if Aggref found
00494  *      PVC_INCLUDE_AGGREGATES      include Aggrefs in output list
00495  *      PVC_RECURSE_AGGREGATES      recurse into Aggref arguments
00496  *    Vars within an Aggref's expression are included only in the last case.
00497  *
00498  *    PlaceHolderVars are handled according to 'phbehavior':
00499  *      PVC_REJECT_PLACEHOLDERS     throw error if PlaceHolderVar found
00500  *      PVC_INCLUDE_PLACEHOLDERS    include PlaceHolderVars in output list
00501  *      PVC_RECURSE_PLACEHOLDERS    recurse into PlaceHolderVar arguments
00502  *    Vars within a PHV's expression are included only in the last case.
00503  *
00504  *    CurrentOfExpr nodes are ignored in all cases.
00505  *
00506  *    Upper-level vars (with varlevelsup > 0) should not be seen here,
00507  *    likewise for upper-level Aggrefs and PlaceHolderVars.
00508  *
00509  *    Returns list of nodes found.  Note the nodes themselves are not
00510  *    copied, only referenced.
00511  *
00512  * Does not examine subqueries, therefore must only be used after reduction
00513  * of sublinks to subplans!
00514  */
00515 List *
00516 pull_var_clause(Node *node, PVCAggregateBehavior aggbehavior,
00517                 PVCPlaceHolderBehavior phbehavior)
00518 {
00519     pull_var_clause_context context;
00520 
00521     context.varlist = NIL;
00522     context.aggbehavior = aggbehavior;
00523     context.phbehavior = phbehavior;
00524 
00525     pull_var_clause_walker(node, &context);
00526     return context.varlist;
00527 }
00528 
00529 static bool
00530 pull_var_clause_walker(Node *node, pull_var_clause_context *context)
00531 {
00532     if (node == NULL)
00533         return false;
00534     if (IsA(node, Var))
00535     {
00536         if (((Var *) node)->varlevelsup != 0)
00537             elog(ERROR, "Upper-level Var found where not expected");
00538         context->varlist = lappend(context->varlist, node);
00539         return false;
00540     }
00541     else if (IsA(node, Aggref))
00542     {
00543         if (((Aggref *) node)->agglevelsup != 0)
00544             elog(ERROR, "Upper-level Aggref found where not expected");
00545         switch (context->aggbehavior)
00546         {
00547             case PVC_REJECT_AGGREGATES:
00548                 elog(ERROR, "Aggref found where not expected");
00549                 break;
00550             case PVC_INCLUDE_AGGREGATES:
00551                 context->varlist = lappend(context->varlist, node);
00552                 /* we do NOT descend into the contained expression */
00553                 return false;
00554             case PVC_RECURSE_AGGREGATES:
00555                 /* ignore the aggregate, look at its argument instead */
00556                 break;
00557         }
00558     }
00559     else if (IsA(node, PlaceHolderVar))
00560     {
00561         if (((PlaceHolderVar *) node)->phlevelsup != 0)
00562             elog(ERROR, "Upper-level PlaceHolderVar found where not expected");
00563         switch (context->phbehavior)
00564         {
00565             case PVC_REJECT_PLACEHOLDERS:
00566                 elog(ERROR, "PlaceHolderVar found where not expected");
00567                 break;
00568             case PVC_INCLUDE_PLACEHOLDERS:
00569                 context->varlist = lappend(context->varlist, node);
00570                 /* we do NOT descend into the contained expression */
00571                 return false;
00572             case PVC_RECURSE_PLACEHOLDERS:
00573                 /* ignore the placeholder, look at its argument instead */
00574                 break;
00575         }
00576     }
00577     return expression_tree_walker(node, pull_var_clause_walker,
00578                                   (void *) context);
00579 }
00580 
00581 
00582 /*
00583  * flatten_join_alias_vars
00584  *    Replace Vars that reference JOIN outputs with references to the original
00585  *    relation variables instead.  This allows quals involving such vars to be
00586  *    pushed down.  Whole-row Vars that reference JOIN relations are expanded
00587  *    into RowExpr constructs that name the individual output Vars.  This
00588  *    is necessary since we will not scan the JOIN as a base relation, which
00589  *    is the only way that the executor can directly handle whole-row Vars.
00590  *
00591  * This also adjusts relid sets found in some expression node types to
00592  * substitute the contained base rels for any join relid.
00593  *
00594  * If a JOIN contains sub-selects that have been flattened, its join alias
00595  * entries might now be arbitrary expressions, not just Vars.  This affects
00596  * this function in one important way: we might find ourselves inserting
00597  * SubLink expressions into subqueries, and we must make sure that their
00598  * Query.hasSubLinks fields get set to TRUE if so.  If there are any
00599  * SubLinks in the join alias lists, the outer Query should already have
00600  * hasSubLinks = TRUE, so this is only relevant to un-flattened subqueries.
00601  *
00602  * NOTE: this is used on not-yet-planned expressions.  We do not expect it
00603  * to be applied directly to the whole Query, so if we see a Query to start
00604  * with, we do want to increment sublevels_up (this occurs for LATERAL
00605  * subqueries).
00606  */
00607 Node *
00608 flatten_join_alias_vars(PlannerInfo *root, Node *node)
00609 {
00610     flatten_join_alias_vars_context context;
00611 
00612     context.root = root;
00613     context.sublevels_up = 0;
00614     /* flag whether join aliases could possibly contain SubLinks */
00615     context.possible_sublink = root->parse->hasSubLinks;
00616     /* if hasSubLinks is already true, no need to work hard */
00617     context.inserted_sublink = root->parse->hasSubLinks;
00618 
00619     return flatten_join_alias_vars_mutator(node, &context);
00620 }
00621 
00622 static Node *
00623 flatten_join_alias_vars_mutator(Node *node,
00624                                 flatten_join_alias_vars_context *context)
00625 {
00626     if (node == NULL)
00627         return NULL;
00628     if (IsA(node, Var))
00629     {
00630         Var        *var = (Var *) node;
00631         RangeTblEntry *rte;
00632         Node       *newvar;
00633 
00634         /* No change unless Var belongs to a JOIN of the target level */
00635         if (var->varlevelsup != context->sublevels_up)
00636             return node;        /* no need to copy, really */
00637         rte = rt_fetch(var->varno, context->root->parse->rtable);
00638         if (rte->rtekind != RTE_JOIN)
00639             return node;
00640         if (var->varattno == InvalidAttrNumber)
00641         {
00642             /* Must expand whole-row reference */
00643             RowExpr    *rowexpr;
00644             List       *fields = NIL;
00645             List       *colnames = NIL;
00646             AttrNumber  attnum;
00647             ListCell   *lv;
00648             ListCell   *ln;
00649 
00650             attnum = 0;
00651             Assert(list_length(rte->joinaliasvars) == list_length(rte->eref->colnames));
00652             forboth(lv, rte->joinaliasvars, ln, rte->eref->colnames)
00653             {
00654                 newvar = (Node *) lfirst(lv);
00655                 attnum++;
00656                 /* Ignore dropped columns */
00657                 if (IsA(newvar, Const))
00658                     continue;
00659                 newvar = copyObject(newvar);
00660 
00661                 /*
00662                  * If we are expanding an alias carried down from an upper
00663                  * query, must adjust its varlevelsup fields.
00664                  */
00665                 if (context->sublevels_up != 0)
00666                     IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
00667                 /* Preserve original Var's location, if possible */
00668                 if (IsA(newvar, Var))
00669                     ((Var *) newvar)->location = var->location;
00670                 /* Recurse in case join input is itself a join */
00671                 /* (also takes care of setting inserted_sublink if needed) */
00672                 newvar = flatten_join_alias_vars_mutator(newvar, context);
00673                 fields = lappend(fields, newvar);
00674                 /* We need the names of non-dropped columns, too */
00675                 colnames = lappend(colnames, copyObject((Node *) lfirst(ln)));
00676             }
00677             rowexpr = makeNode(RowExpr);
00678             rowexpr->args = fields;
00679             rowexpr->row_typeid = var->vartype;
00680             rowexpr->row_format = COERCE_IMPLICIT_CAST;
00681             rowexpr->colnames = colnames;
00682             rowexpr->location = var->location;
00683 
00684             return (Node *) rowexpr;
00685         }
00686 
00687         /* Expand join alias reference */
00688         Assert(var->varattno > 0);
00689         newvar = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1);
00690         newvar = copyObject(newvar);
00691 
00692         /*
00693          * If we are expanding an alias carried down from an upper query, must
00694          * adjust its varlevelsup fields.
00695          */
00696         if (context->sublevels_up != 0)
00697             IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
00698 
00699         /* Preserve original Var's location, if possible */
00700         if (IsA(newvar, Var))
00701             ((Var *) newvar)->location = var->location;
00702 
00703         /* Recurse in case join input is itself a join */
00704         newvar = flatten_join_alias_vars_mutator(newvar, context);
00705 
00706         /* Detect if we are adding a sublink to query */
00707         if (context->possible_sublink && !context->inserted_sublink)
00708             context->inserted_sublink = checkExprHasSubLink(newvar);
00709 
00710         return newvar;
00711     }
00712     if (IsA(node, PlaceHolderVar))
00713     {
00714         /* Copy the PlaceHolderVar node with correct mutation of subnodes */
00715         PlaceHolderVar *phv;
00716 
00717         phv = (PlaceHolderVar *) expression_tree_mutator(node,
00718                                              flatten_join_alias_vars_mutator,
00719                                                          (void *) context);
00720         /* now fix PlaceHolderVar's relid sets */
00721         if (phv->phlevelsup == context->sublevels_up)
00722         {
00723             phv->phrels = alias_relid_set(context->root,
00724                                           phv->phrels);
00725         }
00726         return (Node *) phv;
00727     }
00728 
00729     if (IsA(node, Query))
00730     {
00731         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
00732         Query      *newnode;
00733         bool        save_inserted_sublink;
00734 
00735         context->sublevels_up++;
00736         save_inserted_sublink = context->inserted_sublink;
00737         context->inserted_sublink = ((Query *) node)->hasSubLinks;
00738         newnode = query_tree_mutator((Query *) node,
00739                                      flatten_join_alias_vars_mutator,
00740                                      (void *) context,
00741                                      QTW_IGNORE_JOINALIASES);
00742         newnode->hasSubLinks |= context->inserted_sublink;
00743         context->inserted_sublink = save_inserted_sublink;
00744         context->sublevels_up--;
00745         return (Node *) newnode;
00746     }
00747     /* Already-planned tree not supported */
00748     Assert(!IsA(node, SubPlan));
00749     /* Shouldn't need to handle these planner auxiliary nodes here */
00750     Assert(!IsA(node, SpecialJoinInfo));
00751     Assert(!IsA(node, LateralJoinInfo));
00752     Assert(!IsA(node, PlaceHolderInfo));
00753     Assert(!IsA(node, MinMaxAggInfo));
00754 
00755     return expression_tree_mutator(node, flatten_join_alias_vars_mutator,
00756                                    (void *) context);
00757 }
00758 
00759 /*
00760  * alias_relid_set: in a set of RT indexes, replace joins by their
00761  * underlying base relids
00762  */
00763 static Relids
00764 alias_relid_set(PlannerInfo *root, Relids relids)
00765 {
00766     Relids      result = NULL;
00767     Relids      tmprelids;
00768     int         rtindex;
00769 
00770     tmprelids = bms_copy(relids);
00771     while ((rtindex = bms_first_member(tmprelids)) >= 0)
00772     {
00773         RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable);
00774 
00775         if (rte->rtekind == RTE_JOIN)
00776             result = bms_join(result, get_relids_for_join(root, rtindex));
00777         else
00778             result = bms_add_member(result, rtindex);
00779     }
00780     bms_free(tmprelids);
00781     return result;
00782 }