LCOV - differential code coverage report
Current view: top level - src/backend/optimizer/util - var.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 88.1 % 371 327 44 327
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 21 21 21
Baseline: 16@8cea358b128 Branches: 68.8 % 288 198 90 198
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 88.1 % 371 327 44 327
Function coverage date bins:
(240..) days: 100.0 % 21 21 21
Branch coverage date bins:
(240..) days: 68.8 % 288 198 90 198

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * var.c
                                  4                 :                :  *    Var node manipulation routines
                                  5                 :                :  *
                                  6                 :                :  * Note: for most purposes, PlaceHolderVar is considered a Var too,
                                  7                 :                :  * even if its contained expression is variable-free.  Also, CurrentOfExpr
                                  8                 :                :  * is treated as a Var for purposes of determining whether an expression
                                  9                 :                :  * contains variables.
                                 10                 :                :  *
                                 11                 :                :  *
                                 12                 :                :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
                                 13                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                 14                 :                :  *
                                 15                 :                :  *
                                 16                 :                :  * IDENTIFICATION
                                 17                 :                :  *    src/backend/optimizer/util/var.c
                                 18                 :                :  *
                                 19                 :                :  *-------------------------------------------------------------------------
                                 20                 :                :  */
                                 21                 :                : #include "postgres.h"
                                 22                 :                : 
                                 23                 :                : #include "access/sysattr.h"
                                 24                 :                : #include "nodes/nodeFuncs.h"
                                 25                 :                : #include "optimizer/optimizer.h"
                                 26                 :                : #include "optimizer/placeholder.h"
                                 27                 :                : #include "optimizer/prep.h"
                                 28                 :                : #include "parser/parsetree.h"
                                 29                 :                : #include "rewrite/rewriteManip.h"
                                 30                 :                : 
                                 31                 :                : 
                                 32                 :                : typedef struct
                                 33                 :                : {
                                 34                 :                :     Relids      varnos;
                                 35                 :                :     PlannerInfo *root;
                                 36                 :                :     int         sublevels_up;
                                 37                 :                : } pull_varnos_context;
                                 38                 :                : 
                                 39                 :                : typedef struct
                                 40                 :                : {
                                 41                 :                :     Bitmapset  *varattnos;
                                 42                 :                :     Index       varno;
                                 43                 :                : } pull_varattnos_context;
                                 44                 :                : 
                                 45                 :                : typedef struct
                                 46                 :                : {
                                 47                 :                :     List       *vars;
                                 48                 :                :     int         sublevels_up;
                                 49                 :                : } pull_vars_context;
                                 50                 :                : 
                                 51                 :                : typedef struct
                                 52                 :                : {
                                 53                 :                :     int         var_location;
                                 54                 :                :     int         sublevels_up;
                                 55                 :                : } locate_var_of_level_context;
                                 56                 :                : 
                                 57                 :                : typedef struct
                                 58                 :                : {
                                 59                 :                :     List       *varlist;
                                 60                 :                :     int         flags;
                                 61                 :                : } pull_var_clause_context;
                                 62                 :                : 
                                 63                 :                : typedef struct
                                 64                 :                : {
                                 65                 :                :     PlannerInfo *root;          /* could be NULL! */
                                 66                 :                :     Query      *query;          /* outer Query */
                                 67                 :                :     int         sublevels_up;
                                 68                 :                :     bool        possible_sublink;   /* could aliases include a SubLink? */
                                 69                 :                :     bool        inserted_sublink;   /* have we inserted a SubLink? */
                                 70                 :                : } flatten_join_alias_vars_context;
                                 71                 :                : 
                                 72                 :                : static bool pull_varnos_walker(Node *node,
                                 73                 :                :                                pull_varnos_context *context);
                                 74                 :                : static bool pull_varattnos_walker(Node *node, pull_varattnos_context *context);
                                 75                 :                : static bool pull_vars_walker(Node *node, pull_vars_context *context);
                                 76                 :                : static bool contain_var_clause_walker(Node *node, void *context);
                                 77                 :                : static bool contain_vars_of_level_walker(Node *node, int *sublevels_up);
                                 78                 :                : static bool locate_var_of_level_walker(Node *node,
                                 79                 :                :                                        locate_var_of_level_context *context);
                                 80                 :                : static bool pull_var_clause_walker(Node *node,
                                 81                 :                :                                    pull_var_clause_context *context);
                                 82                 :                : static Node *flatten_join_alias_vars_mutator(Node *node,
                                 83                 :                :                                              flatten_join_alias_vars_context *context);
                                 84                 :                : static Node *add_nullingrels_if_needed(PlannerInfo *root, Node *newnode,
                                 85                 :                :                                        Var *oldvar);
                                 86                 :                : static bool is_standard_join_alias_expression(Node *newnode, Var *oldvar);
                                 87                 :                : static void adjust_standard_join_alias_expression(Node *newnode, Var *oldvar);
                                 88                 :                : static Relids alias_relid_set(Query *query, Relids relids);
                                 89                 :                : 
                                 90                 :                : 
                                 91                 :                : /*
                                 92                 :                :  * pull_varnos
                                 93                 :                :  *      Create a set of all the distinct varnos present in a parsetree.
                                 94                 :                :  *      Only varnos that reference level-zero rtable entries are considered.
                                 95                 :                :  *
                                 96                 :                :  * The result includes outer-join relids mentioned in Var.varnullingrels and
                                 97                 :                :  * PlaceHolderVar.phnullingrels fields in the parsetree.
                                 98                 :                :  *
                                 99                 :                :  * "root" can be passed as NULL if it is not necessary to process
                                100                 :                :  * PlaceHolderVars.
                                101                 :                :  *
                                102                 :                :  * NOTE: this is used on not-yet-planned expressions.  It may therefore find
                                103                 :                :  * bare SubLinks, and if so it needs to recurse into them to look for uplevel
                                104                 :                :  * references to the desired rtable level!  But when we find a completed
                                105                 :                :  * SubPlan, we only need to look at the parameters passed to the subplan.
                                106                 :                :  */
                                107                 :                : Relids
 1179 tgl@sss.pgh.pa.us         108                 :CBC     1345757 : pull_varnos(PlannerInfo *root, Node *node)
                                109                 :                : {
                                110                 :                :     pull_varnos_context context;
                                111                 :                : 
 7736                           112                 :        1345757 :     context.varnos = NULL;
 1179                           113                 :        1345757 :     context.root = root;
 8615                           114                 :        1345757 :     context.sublevels_up = 0;
                                115                 :                : 
                                116                 :                :     /*
                                117                 :                :      * Must be prepared to start with a Query or a bare expression tree; if
                                118                 :                :      * it's a Query, we don't want to increment sublevels_up.
                                119                 :                :      */
 7758                           120                 :        1345757 :     query_or_expression_tree_walker(node,
                                121                 :                :                                     pull_varnos_walker,
                                122                 :                :                                     (void *) &context,
                                123                 :                :                                     0);
                                124                 :                : 
 7736                           125                 :        1345757 :     return context.varnos;
                                126                 :                : }
                                127                 :                : 
                                128                 :                : /*
                                129                 :                :  * pull_varnos_of_level
                                130                 :                :  *      Create a set of all the distinct varnos present in a parsetree.
                                131                 :                :  *      Only Vars of the specified level are considered.
                                132                 :                :  */
                                133                 :                : Relids
 1179                           134                 :           1600 : pull_varnos_of_level(PlannerInfo *root, Node *node, int levelsup)
                                135                 :                : {
                                136                 :                :     pull_varnos_context context;
                                137                 :                : 
 4268                           138                 :           1600 :     context.varnos = NULL;
 1179                           139                 :           1600 :     context.root = root;
 4268                           140                 :           1600 :     context.sublevels_up = levelsup;
                                141                 :                : 
                                142                 :                :     /*
                                143                 :                :      * Must be prepared to start with a Query or a bare expression tree; if
                                144                 :                :      * it's a Query, we don't want to increment sublevels_up.
                                145                 :                :      */
                                146                 :           1600 :     query_or_expression_tree_walker(node,
                                147                 :                :                                     pull_varnos_walker,
                                148                 :                :                                     (void *) &context,
                                149                 :                :                                     0);
                                150                 :                : 
                                151                 :           1600 :     return context.varnos;
                                152                 :                : }
                                153                 :                : 
                                154                 :                : static bool
 8615                           155                 :        2297595 : pull_varnos_walker(Node *node, pull_varnos_context *context)
                                156                 :                : {
 9066                           157         [ +  + ]:        2297595 :     if (node == NULL)
                                158                 :          53875 :         return false;
                                159         [ +  + ]:        2243720 :     if (IsA(node, Var))
                                160                 :                :     {
 8768 bruce@momjian.us          161                 :        1103826 :         Var        *var = (Var *) node;
                                162                 :                : 
 7736 tgl@sss.pgh.pa.us         163         [ +  + ]:        1103826 :         if (var->varlevelsup == context->sublevels_up)
                                164                 :                :         {
                                165                 :        1100789 :             context->varnos = bms_add_member(context->varnos, var->varno);
  440                           166                 :        1100789 :             context->varnos = bms_add_members(context->varnos,
                                167                 :        1100789 :                                               var->varnullingrels);
                                168                 :                :         }
 9066                           169                 :        1103826 :         return false;
                                170                 :                :     }
 6152                           171         [ +  + ]:        1139894 :     if (IsA(node, CurrentOfExpr))
                                172                 :                :     {
                                173                 :            388 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
                                174                 :                : 
                                175         [ +  - ]:            388 :         if (context->sublevels_up == 0)
                                176                 :            388 :             context->varnos = bms_add_member(context->varnos, cexpr->cvarno);
                                177                 :            388 :         return false;
                                178                 :                :     }
 5654                           179         [ +  + ]:        1139506 :     if (IsA(node, PlaceHolderVar))
                                180                 :                :     {
                                181                 :           2243 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
                                182                 :                : 
                                183                 :                :         /*
                                184                 :                :          * If a PlaceHolderVar is not of the target query level, ignore it,
                                185                 :                :          * instead recursing into its expression to see if it contains any
                                186                 :                :          * vars that are of the target level.  We'll also do that when the
                                187                 :                :          * caller doesn't pass a "root" pointer.  (We probably shouldn't see
                                188                 :                :          * PlaceHolderVars at all in such cases, but if we do, this is a
                                189                 :                :          * reasonable behavior.)
                                190                 :                :          */
  826                           191         [ +  - ]:           2243 :         if (phv->phlevelsup == context->sublevels_up &&
                                192         [ +  - ]:           2243 :             context->root != NULL)
                                193                 :                :         {
                                194                 :                :             /*
                                195                 :                :              * Ideally, the PHV's contribution to context->varnos is its
                                196                 :                :              * ph_eval_at set.  However, this code can be invoked before
                                197                 :                :              * that's been computed.  If we cannot find a PlaceHolderInfo,
                                198                 :                :              * fall back to the conservative assumption that the PHV will be
                                199                 :                :              * evaluated at its syntactic level (phv->phrels).
                                200                 :                :              *
                                201                 :                :              * Another problem is that a PlaceHolderVar can appear in quals or
                                202                 :                :              * tlists that have been translated for use in a child appendrel.
                                203                 :                :              * Typically such a PHV is a parameter expression sourced by some
                                204                 :                :              * other relation, so that the translation from parent appendrel
                                205                 :                :              * to child doesn't change its phrels, and we should still take
                                206                 :                :              * ph_eval_at at face value.  But in corner cases, the PHV's
                                207                 :                :              * original phrels can include the parent appendrel itself, in
                                208                 :                :              * which case the translated PHV will have the child appendrel in
                                209                 :                :              * phrels, and we must translate ph_eval_at to match.
                                210                 :                :              */
 1179                           211                 :           2243 :             PlaceHolderInfo *phinfo = NULL;
                                212                 :                : 
                                213         [ +  + ]:           2243 :             if (phv->phlevelsup == 0)
                                214                 :                :             {
  606                           215         [ +  + ]:           2219 :                 if (phv->phid < context->root->placeholder_array_size)
                                216                 :           2092 :                     phinfo = context->root->placeholder_array[phv->phid];
                                217                 :                :             }
  940                           218         [ +  + ]:           2243 :             if (phinfo == NULL)
                                219                 :                :             {
                                220                 :                :                 /* No PlaceHolderInfo yet, use phrels */
                                221                 :            160 :                 context->varnos = bms_add_members(context->varnos,
                                222                 :            160 :                                                   phv->phrels);
                                223                 :                :             }
                                224         [ +  + ]:           2083 :             else if (bms_equal(phv->phrels, phinfo->ph_var->phrels))
                                225                 :                :             {
                                226                 :                :                 /* Normal case: use ph_eval_at */
 1179                           227                 :           1603 :                 context->varnos = bms_add_members(context->varnos,
                                228                 :           1603 :                                                   phinfo->ph_eval_at);
                                229                 :                :             }
                                230                 :                :             else
                                231                 :                :             {
                                232                 :                :                 /* Translated PlaceHolderVar: translate ph_eval_at to match */
                                233                 :                :                 Relids      newevalat,
                                234                 :                :                             delta;
                                235                 :                : 
                                236                 :                :                 /* remove what was removed from phv->phrels ... */
  940                           237                 :            480 :                 delta = bms_difference(phinfo->ph_var->phrels, phv->phrels);
                                238                 :            480 :                 newevalat = bms_difference(phinfo->ph_eval_at, delta);
                                239                 :                :                 /* ... then if that was in fact part of ph_eval_at ... */
                                240         [ +  + ]:            480 :                 if (!bms_equal(newevalat, phinfo->ph_eval_at))
                                241                 :                :                 {
                                242                 :                :                     /* ... add what was added */
                                243                 :            300 :                     delta = bms_difference(phv->phrels, phinfo->ph_var->phrels);
                                244                 :            300 :                     newevalat = bms_join(newevalat, delta);
                                245                 :                :                 }
                                246                 :            480 :                 context->varnos = bms_join(context->varnos,
                                247                 :                :                                            newevalat);
                                248                 :                :             }
                                249                 :                : 
                                250                 :                :             /*
                                251                 :                :              * In all three cases, include phnullingrels in the result.  We
                                252                 :                :              * don't worry about possibly needing to translate it, because
                                253                 :                :              * appendrels only translate varnos of baserels, not outer joins.
                                254                 :                :              */
  440                           255                 :           4486 :             context->varnos = bms_add_members(context->varnos,
                                256                 :           2243 :                                               phv->phnullingrels);
 1179                           257                 :           2243 :             return false;       /* don't recurse into expression */
                                258                 :                :         }
                                259                 :                :     }
                                260         [ +  + ]:        1137263 :     else if (IsA(node, Query))
                                261                 :                :     {
                                262                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                                263                 :                :         bool        result;
                                264                 :                : 
 8615                           265                 :            825 :         context->sublevels_up++;
                                266                 :            825 :         result = query_tree_walker((Query *) node, pull_varnos_walker,
                                267                 :                :                                    (void *) context, 0);
                                268                 :            825 :         context->sublevels_up--;
                                269                 :            825 :         return result;
                                270                 :                :     }
                                271                 :        1136438 :     return expression_tree_walker(node, pull_varnos_walker,
                                272                 :                :                                   (void *) context);
                                273                 :                : }
                                274                 :                : 
                                275                 :                : 
                                276                 :                : /*
                                277                 :                :  * pull_varattnos
                                278                 :                :  *      Find all the distinct attribute numbers present in an expression tree,
                                279                 :                :  *      and add them to the initial contents of *varattnos.
                                280                 :                :  *      Only Vars of the given varno and rtable level zero are considered.
                                281                 :                :  *
                                282                 :                :  * Attribute numbers are offset by FirstLowInvalidHeapAttributeNumber so that
                                283                 :                :  * we can include system attributes (e.g., OID) in the bitmap representation.
                                284                 :                :  *
                                285                 :                :  * Currently, this does not support unplanned subqueries; that is not needed
                                286                 :                :  * for current uses.  It will handle already-planned SubPlan nodes, though,
                                287                 :                :  * looking into only the "testexpr" and the "args" list.  (The subplan cannot
                                288                 :                :  * contain any other references to Vars of the current level.)
                                289                 :                :  */
                                290                 :                : void
 4573                           291                 :         755926 : pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
                                292                 :                : {
                                293                 :                :     pull_varattnos_context context;
                                294                 :                : 
                                295                 :         755926 :     context.varattnos = *varattnos;
                                296                 :         755926 :     context.varno = varno;
                                297                 :                : 
                                298                 :         755926 :     (void) pull_varattnos_walker(node, &context);
                                299                 :                : 
                                300                 :         755926 :     *varattnos = context.varattnos;
 6051                           301                 :         755926 : }
                                302                 :                : 
                                303                 :                : static bool
 4573                           304                 :        2474371 : pull_varattnos_walker(Node *node, pull_varattnos_context *context)
                                305                 :                : {
 6051                           306         [ +  + ]:        2474371 :     if (node == NULL)
                                307                 :          37031 :         return false;
                                308         [ +  + ]:        2437340 :     if (IsA(node, Var))
                                309                 :                :     {
                                310                 :        1400713 :         Var        *var = (Var *) node;
                                311                 :                : 
 4573                           312   [ +  +  +  - ]:        1400713 :         if (var->varno == context->varno && var->varlevelsup == 0)
                                313                 :        1400542 :             context->varattnos =
                                314                 :        1400542 :                 bms_add_member(context->varattnos,
 2489                           315                 :        1400542 :                                var->varattno - FirstLowInvalidHeapAttributeNumber);
 6051                           316                 :        1400713 :         return false;
                                317                 :                :     }
                                318                 :                : 
                                319                 :                :     /* Should not find an unplanned subquery */
                                320         [ -  + ]:        1036627 :     Assert(!IsA(node, Query));
                                321                 :                : 
                                322                 :        1036627 :     return expression_tree_walker(node, pull_varattnos_walker,
                                323                 :                :                                   (void *) context);
                                324                 :                : }
                                325                 :                : 
                                326                 :                : 
                                327                 :                : /*
                                328                 :                :  * pull_vars_of_level
                                329                 :                :  *      Create a list of all Vars (and PlaceHolderVars) referencing the
                                330                 :                :  *      specified query level in the given parsetree.
                                331                 :                :  *
                                332                 :                :  * Caution: the Vars are not copied, only linked into the list.
                                333                 :                :  */
                                334                 :                : List *
 4268                           335                 :           4328 : pull_vars_of_level(Node *node, int levelsup)
                                336                 :                : {
                                337                 :                :     pull_vars_context context;
                                338                 :                : 
                                339                 :           4328 :     context.vars = NIL;
                                340                 :           4328 :     context.sublevels_up = levelsup;
                                341                 :                : 
                                342                 :                :     /*
                                343                 :                :      * Must be prepared to start with a Query or a bare expression tree; if
                                344                 :                :      * it's a Query, we don't want to increment sublevels_up.
                                345                 :                :      */
                                346                 :           4328 :     query_or_expression_tree_walker(node,
                                347                 :                :                                     pull_vars_walker,
                                348                 :                :                                     (void *) &context,
                                349                 :                :                                     0);
                                350                 :                : 
                                351                 :           4328 :     return context.vars;
                                352                 :                : }
                                353                 :                : 
                                354                 :                : static bool
                                355                 :          50979 : pull_vars_walker(Node *node, pull_vars_context *context)
                                356                 :                : {
                                357         [ +  + ]:          50979 :     if (node == NULL)
                                358                 :           6506 :         return false;
                                359         [ +  + ]:          44473 :     if (IsA(node, Var))
                                360                 :                :     {
                                361                 :           5794 :         Var        *var = (Var *) node;
                                362                 :                : 
                                363         [ +  + ]:           5794 :         if (var->varlevelsup == context->sublevels_up)
                                364                 :           4631 :             context->vars = lappend(context->vars, var);
                                365                 :           5794 :         return false;
                                366                 :                :     }
 4257                           367         [ +  + ]:          38679 :     if (IsA(node, PlaceHolderVar))
                                368                 :                :     {
                                369                 :             36 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
                                370                 :                : 
                                371         [ +  - ]:             36 :         if (phv->phlevelsup == context->sublevels_up)
                                372                 :             36 :             context->vars = lappend(context->vars, phv);
                                373                 :                :         /* we don't want to look into the contained expression */
                                374                 :             36 :         return false;
                                375                 :                :     }
 4268                           376         [ +  + ]:          38643 :     if (IsA(node, Query))
                                377                 :                :     {
                                378                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                                379                 :                :         bool        result;
                                380                 :                : 
                                381                 :            156 :         context->sublevels_up++;
                                382                 :            156 :         result = query_tree_walker((Query *) node, pull_vars_walker,
                                383                 :                :                                    (void *) context, 0);
                                384                 :            156 :         context->sublevels_up--;
                                385                 :            156 :         return result;
                                386                 :                :     }
                                387                 :          38487 :     return expression_tree_walker(node, pull_vars_walker,
                                388                 :                :                                   (void *) context);
                                389                 :                : }
                                390                 :                : 
                                391                 :                : 
                                392                 :                : /*
                                393                 :                :  * contain_var_clause
                                394                 :                :  *    Recursively scan a clause to discover whether it contains any Var nodes
                                395                 :                :  *    (of the current query level).
                                396                 :                :  *
                                397                 :                :  *    Returns true if any varnode found.
                                398                 :                :  *
                                399                 :                :  * Does not examine subqueries, therefore must only be used after reduction
                                400                 :                :  * of sublinks to subplans!
                                401                 :                :  */
                                402                 :                : bool
 8397                           403                 :          18986 : contain_var_clause(Node *node)
                                404                 :                : {
                                405                 :          18986 :     return contain_var_clause_walker(node, NULL);
                                406                 :                : }
                                407                 :                : 
                                408                 :                : static bool
 9066                           409                 :          22436 : contain_var_clause_walker(Node *node, void *context)
                                410                 :                : {
                                411         [ +  + ]:          22436 :     if (node == NULL)
                                412                 :             62 :         return false;
                                413         [ +  + ]:          22374 :     if (IsA(node, Var))
                                414                 :                :     {
 8998                           415         [ +  - ]:           1093 :         if (((Var *) node)->varlevelsup == 0)
 6756 bruce@momjian.us          416                 :           1093 :             return true;        /* abort the tree traversal and return true */
 8998 tgl@sss.pgh.pa.us         417                 :UBC           0 :         return false;
                                418                 :                :     }
 6152 tgl@sss.pgh.pa.us         419         [ -  + ]:CBC       21281 :     if (IsA(node, CurrentOfExpr))
 6152 tgl@sss.pgh.pa.us         420                 :UBC           0 :         return true;
 5654 tgl@sss.pgh.pa.us         421         [ +  + ]:CBC       21281 :     if (IsA(node, PlaceHolderVar))
                                422                 :                :     {
                                423         [ +  - ]:              6 :         if (((PlaceHolderVar *) node)->phlevelsup == 0)
                                424                 :              6 :             return true;        /* abort the tree traversal and return true */
                                425                 :                :         /* else fall through to check the contained expr */
                                426                 :                :     }
 9066                           427                 :          21275 :     return expression_tree_walker(node, contain_var_clause_walker, context);
                                428                 :                : }
                                429                 :                : 
                                430                 :                : 
                                431                 :                : /*
                                432                 :                :  * contain_vars_of_level
                                433                 :                :  *    Recursively scan a clause to discover whether it contains any Var nodes
                                434                 :                :  *    of the specified query level.
                                435                 :                :  *
                                436                 :                :  *    Returns true if any such Var found.
                                437                 :                :  *
                                438                 :                :  * Will recurse into sublinks.  Also, may be invoked directly on a Query.
                                439                 :                :  */
                                440                 :                : bool
 7755                           441                 :          70216 : contain_vars_of_level(Node *node, int levelsup)
                                442                 :                : {
 7559 bruce@momjian.us          443                 :          70216 :     int         sublevels_up = levelsup;
                                444                 :                : 
 7755 tgl@sss.pgh.pa.us         445                 :          70216 :     return query_or_expression_tree_walker(node,
                                446                 :                :                                            contain_vars_of_level_walker,
                                447                 :                :                                            (void *) &sublevels_up,
                                448                 :                :                                            0);
                                449                 :                : }
                                450                 :                : 
                                451                 :                : static bool
                                452                 :         221467 : contain_vars_of_level_walker(Node *node, int *sublevels_up)
                                453                 :                : {
                                454         [ +  + ]:         221467 :     if (node == NULL)
                                455                 :          40784 :         return false;
                                456         [ +  + ]:         180683 :     if (IsA(node, Var))
                                457                 :                :     {
                                458         [ +  + ]:          30438 :         if (((Var *) node)->varlevelsup == *sublevels_up)
                                459                 :          19731 :             return true;        /* abort tree traversal and return true */
 6152                           460                 :          10707 :         return false;
                                461                 :                :     }
                                462         [ +  + ]:         150245 :     if (IsA(node, CurrentOfExpr))
                                463                 :                :     {
                                464         [ +  - ]:             92 :         if (*sublevels_up == 0)
                                465                 :             92 :             return true;
 6152 tgl@sss.pgh.pa.us         466                 :UBC           0 :         return false;
                                467                 :                :     }
 5654 tgl@sss.pgh.pa.us         468         [ +  + ]:CBC      150153 :     if (IsA(node, PlaceHolderVar))
                                469                 :                :     {
                                470         [ +  + ]:             27 :         if (((PlaceHolderVar *) node)->phlevelsup == *sublevels_up)
                                471                 :             24 :             return true;        /* abort the tree traversal and return true */
                                472                 :                :         /* else fall through to check the contained expr */
                                473                 :                :     }
 7755                           474         [ +  + ]:         150129 :     if (IsA(node, Query))
                                475                 :                :     {
                                476                 :                :         /* Recurse into subselects */
                                477                 :                :         bool        result;
                                478                 :                : 
                                479                 :            293 :         (*sublevels_up)++;
                                480                 :            293 :         result = query_tree_walker((Query *) node,
                                481                 :                :                                    contain_vars_of_level_walker,
                                482                 :                :                                    (void *) sublevels_up,
                                483                 :                :                                    0);
                                484                 :            293 :         (*sublevels_up)--;
                                485                 :            293 :         return result;
                                486                 :                :     }
                                487                 :         149836 :     return expression_tree_walker(node,
                                488                 :                :                                   contain_vars_of_level_walker,
                                489                 :                :                                   (void *) sublevels_up);
                                490                 :                : }
                                491                 :                : 
                                492                 :                : 
                                493                 :                : /*
                                494                 :                :  * locate_var_of_level
                                495                 :                :  *    Find the parse location of any Var of the specified query level.
                                496                 :                :  *
                                497                 :                :  * Returns -1 if no such Var is in the querytree, or if they all have
                                498                 :                :  * unknown parse location.  (The former case is probably caller error,
                                499                 :                :  * but we don't bother to distinguish it from the latter case.)
                                500                 :                :  *
                                501                 :                :  * Will recurse into sublinks.  Also, may be invoked directly on a Query.
                                502                 :                :  *
                                503                 :                :  * Note: it might seem appropriate to merge this functionality into
                                504                 :                :  * contain_vars_of_level, but that would complicate that function's API.
                                505                 :                :  * Currently, the only uses of this function are for error reporting,
                                506                 :                :  * and so shaving cycles probably isn't very important.
                                507                 :                :  */
                                508                 :                : int
 5704                           509                 :              6 : locate_var_of_level(Node *node, int levelsup)
                                510                 :                : {
                                511                 :                :     locate_var_of_level_context context;
                                512                 :                : 
 5421 bruce@momjian.us          513                 :              6 :     context.var_location = -1;  /* in case we find nothing */
 5704 tgl@sss.pgh.pa.us         514                 :              6 :     context.sublevels_up = levelsup;
                                515                 :                : 
                                516                 :              6 :     (void) query_or_expression_tree_walker(node,
                                517                 :                :                                            locate_var_of_level_walker,
                                518                 :                :                                            (void *) &context,
                                519                 :                :                                            0);
                                520                 :                : 
                                521                 :              6 :     return context.var_location;
                                522                 :                : }
                                523                 :                : 
                                524                 :                : static bool
                                525                 :             15 : locate_var_of_level_walker(Node *node,
                                526                 :                :                            locate_var_of_level_context *context)
                                527                 :                : {
 7755                           528         [ -  + ]:             15 :     if (node == NULL)
 7755 tgl@sss.pgh.pa.us         529                 :UBC           0 :         return false;
 7755 tgl@sss.pgh.pa.us         530         [ +  + ]:CBC          15 :     if (IsA(node, Var))
                                531                 :                :     {
 5421 bruce@momjian.us          532                 :              6 :         Var        *var = (Var *) node;
                                533                 :                : 
 5704 tgl@sss.pgh.pa.us         534         [ +  - ]:              6 :         if (var->varlevelsup == context->sublevels_up &&
                                535         [ +  - ]:              6 :             var->location >= 0)
                                536                 :                :         {
                                537                 :              6 :             context->var_location = var->location;
 7755                           538                 :              6 :             return true;        /* abort tree traversal and return true */
                                539                 :                :         }
 5704 tgl@sss.pgh.pa.us         540                 :UBC           0 :         return false;
                                541                 :                :     }
 5704 tgl@sss.pgh.pa.us         542         [ -  + ]:CBC           9 :     if (IsA(node, CurrentOfExpr))
                                543                 :                :     {
                                544                 :                :         /* since CurrentOfExpr doesn't carry location, nothing we can do */
 5704 tgl@sss.pgh.pa.us         545                 :UBC           0 :         return false;
                                546                 :                :     }
                                547                 :                :     /* No extra code needed for PlaceHolderVar; just look in contained expr */
 7755 tgl@sss.pgh.pa.us         548         [ -  + ]:CBC           9 :     if (IsA(node, Query))
                                549                 :                :     {
                                550                 :                :         /* Recurse into subselects */
                                551                 :                :         bool        result;
                                552                 :                : 
 5704 tgl@sss.pgh.pa.us         553                 :UBC           0 :         context->sublevels_up++;
 7755                           554                 :              0 :         result = query_tree_walker((Query *) node,
                                555                 :                :                                    locate_var_of_level_walker,
                                556                 :                :                                    (void *) context,
                                557                 :                :                                    0);
 5704                           558                 :              0 :         context->sublevels_up--;
 7755                           559                 :              0 :         return result;
                                560                 :                :     }
 7755 tgl@sss.pgh.pa.us         561                 :CBC           9 :     return expression_tree_walker(node,
                                562                 :                :                                   locate_var_of_level_walker,
                                563                 :                :                                   (void *) context);
                                564                 :                : }
                                565                 :                : 
                                566                 :                : 
                                567                 :                : /*
                                568                 :                :  * pull_var_clause
                                569                 :                :  *    Recursively pulls all Var nodes from an expression clause.
                                570                 :                :  *
                                571                 :                :  *    Aggrefs are handled according to these bits in 'flags':
                                572                 :                :  *      PVC_INCLUDE_AGGREGATES      include Aggrefs in output list
                                573                 :                :  *      PVC_RECURSE_AGGREGATES      recurse into Aggref arguments
                                574                 :                :  *      neither flag                throw error if Aggref found
                                575                 :                :  *    Vars within an Aggref's expression are included in the result only
                                576                 :                :  *    when PVC_RECURSE_AGGREGATES is specified.
                                577                 :                :  *
                                578                 :                :  *    WindowFuncs are handled according to these bits in 'flags':
                                579                 :                :  *      PVC_INCLUDE_WINDOWFUNCS     include WindowFuncs in output list
                                580                 :                :  *      PVC_RECURSE_WINDOWFUNCS     recurse into WindowFunc arguments
                                581                 :                :  *      neither flag                throw error if WindowFunc found
                                582                 :                :  *    Vars within a WindowFunc's expression are included in the result only
                                583                 :                :  *    when PVC_RECURSE_WINDOWFUNCS is specified.
                                584                 :                :  *
                                585                 :                :  *    PlaceHolderVars are handled according to these bits in 'flags':
                                586                 :                :  *      PVC_INCLUDE_PLACEHOLDERS    include PlaceHolderVars in output list
                                587                 :                :  *      PVC_RECURSE_PLACEHOLDERS    recurse into PlaceHolderVar arguments
                                588                 :                :  *      neither flag                throw error if PlaceHolderVar found
                                589                 :                :  *    Vars within a PHV's expression are included in the result only
                                590                 :                :  *    when PVC_RECURSE_PLACEHOLDERS is specified.
                                591                 :                :  *
                                592                 :                :  *    GroupingFuncs are treated exactly like Aggrefs, and so do not need
                                593                 :                :  *    their own flag bits.
                                594                 :                :  *
                                595                 :                :  *    CurrentOfExpr nodes are ignored in all cases.
                                596                 :                :  *
                                597                 :                :  *    Upper-level vars (with varlevelsup > 0) should not be seen here,
                                598                 :                :  *    likewise for upper-level Aggrefs and PlaceHolderVars.
                                599                 :                :  *
                                600                 :                :  *    Returns list of nodes found.  Note the nodes themselves are not
                                601                 :                :  *    copied, only referenced.
                                602                 :                :  *
                                603                 :                :  * Does not examine subqueries, therefore must only be used after reduction
                                604                 :                :  * of sublinks to subplans!
                                605                 :                :  */
                                606                 :                : List *
 2957                           607                 :         307998 : pull_var_clause(Node *node, int flags)
                                608                 :                : {
                                609                 :                :     pull_var_clause_context context;
                                610                 :                : 
                                611                 :                :     /* Assert that caller has not specified inconsistent flags */
                                612         [ -  + ]:         307998 :     Assert((flags & (PVC_INCLUDE_AGGREGATES | PVC_RECURSE_AGGREGATES))
                                613                 :                :            != (PVC_INCLUDE_AGGREGATES | PVC_RECURSE_AGGREGATES));
                                614         [ -  + ]:         307998 :     Assert((flags & (PVC_INCLUDE_WINDOWFUNCS | PVC_RECURSE_WINDOWFUNCS))
                                615                 :                :            != (PVC_INCLUDE_WINDOWFUNCS | PVC_RECURSE_WINDOWFUNCS));
                                616         [ -  + ]:         307998 :     Assert((flags & (PVC_INCLUDE_PLACEHOLDERS | PVC_RECURSE_PLACEHOLDERS))
                                617                 :                :            != (PVC_INCLUDE_PLACEHOLDERS | PVC_RECURSE_PLACEHOLDERS));
                                618                 :                : 
 7257                           619                 :         307998 :     context.varlist = NIL;
 2957                           620                 :         307998 :     context.flags = flags;
                                621                 :                : 
 8397                           622                 :         307998 :     pull_var_clause_walker(node, &context);
 7257                           623                 :         307998 :     return context.varlist;
                                624                 :                : }
                                625                 :                : 
                                626                 :                : static bool
 8998                           627                 :        1868192 : pull_var_clause_walker(Node *node, pull_var_clause_context *context)
                                628                 :                : {
 9066                           629         [ +  + ]:        1868192 :     if (node == NULL)
                                630                 :          75309 :         return false;
                                631         [ +  + ]:        1792883 :     if (IsA(node, Var))
                                632                 :                :     {
 4660                           633         [ -  + ]:         686360 :         if (((Var *) node)->varlevelsup != 0)
 4660 tgl@sss.pgh.pa.us         634         [ #  # ]:UBC           0 :             elog(ERROR, "Upper-level Var found where not expected");
 4660 tgl@sss.pgh.pa.us         635                 :CBC      686360 :         context->varlist = lappend(context->varlist, node);
 9066                           636                 :         686360 :         return false;
                                637                 :                :     }
 4660                           638         [ +  + ]:        1106523 :     else if (IsA(node, Aggref))
                                639                 :                :     {
                                640         [ -  + ]:          42990 :         if (((Aggref *) node)->agglevelsup != 0)
 4660 tgl@sss.pgh.pa.us         641         [ #  # ]:UBC           0 :             elog(ERROR, "Upper-level Aggref found where not expected");
 2957 tgl@sss.pgh.pa.us         642         [ +  + ]:CBC       42990 :         if (context->flags & PVC_INCLUDE_AGGREGATES)
                                643                 :                :         {
                                644                 :           2345 :             context->varlist = lappend(context->varlist, node);
                                645                 :                :             /* we do NOT descend into the contained expression */
                                646                 :           2345 :             return false;
                                647                 :                :         }
                                648         [ -  + ]:          40645 :         else if (context->flags & PVC_RECURSE_AGGREGATES)
                                649                 :                :         {
                                650                 :                :             /* fall through to recurse into the aggregate's arguments */
                                651                 :                :         }
                                652                 :                :         else
 2957 tgl@sss.pgh.pa.us         653         [ #  # ]:UBC           0 :             elog(ERROR, "Aggref found where not expected");
                                654                 :                :     }
 3256 andres@anarazel.de        655         [ +  + ]:CBC     1063533 :     else if (IsA(node, GroupingFunc))
                                656                 :                :     {
                                657         [ -  + ]:            275 :         if (((GroupingFunc *) node)->agglevelsup != 0)
 3256 andres@anarazel.de        658         [ #  # ]:UBC           0 :             elog(ERROR, "Upper-level GROUPING found where not expected");
 2957 tgl@sss.pgh.pa.us         659         [ +  + ]:CBC         275 :         if (context->flags & PVC_INCLUDE_AGGREGATES)
                                660                 :                :         {
                                661                 :              2 :             context->varlist = lappend(context->varlist, node);
                                662                 :                :             /* we do NOT descend into the contained expression */
                                663                 :              2 :             return false;
                                664                 :                :         }
                                665         [ -  + ]:            273 :         else if (context->flags & PVC_RECURSE_AGGREGATES)
                                666                 :                :         {
                                667                 :                :             /* fall through to recurse into the GroupingFunc's arguments */
                                668                 :                :         }
                                669                 :                :         else
 2957 tgl@sss.pgh.pa.us         670         [ #  # ]:UBC           0 :             elog(ERROR, "GROUPING found where not expected");
                                671                 :                :     }
 2957 tgl@sss.pgh.pa.us         672         [ +  + ]:CBC     1063258 :     else if (IsA(node, WindowFunc))
                                673                 :                :     {
                                674                 :                :         /* WindowFuncs have no levelsup field to check ... */
                                675         [ +  + ]:           3197 :         if (context->flags & PVC_INCLUDE_WINDOWFUNCS)
                                676                 :                :         {
                                677                 :              6 :             context->varlist = lappend(context->varlist, node);
                                678                 :                :             /* we do NOT descend into the contained expressions */
                                679                 :              6 :             return false;
                                680                 :                :         }
                                681         [ -  + ]:           3191 :         else if (context->flags & PVC_RECURSE_WINDOWFUNCS)
                                682                 :                :         {
                                683                 :                :             /* fall through to recurse into the windowfunc's arguments */
                                684                 :                :         }
                                685                 :                :         else
 2957 tgl@sss.pgh.pa.us         686         [ #  # ]:UBC           0 :             elog(ERROR, "WindowFunc found where not expected");
                                687                 :                :     }
 4660 tgl@sss.pgh.pa.us         688         [ +  + ]:CBC     1060061 :     else if (IsA(node, PlaceHolderVar))
                                689                 :                :     {
                                690         [ -  + ]:           1300 :         if (((PlaceHolderVar *) node)->phlevelsup != 0)
 4660 tgl@sss.pgh.pa.us         691         [ #  # ]:UBC           0 :             elog(ERROR, "Upper-level PlaceHolderVar found where not expected");
 2957 tgl@sss.pgh.pa.us         692         [ +  + ]:CBC        1300 :         if (context->flags & PVC_INCLUDE_PLACEHOLDERS)
                                693                 :                :         {
                                694                 :           1110 :             context->varlist = lappend(context->varlist, node);
                                695                 :                :             /* we do NOT descend into the contained expression */
                                696                 :           1110 :             return false;
                                697                 :                :         }
                                698         [ -  + ]:            190 :         else if (context->flags & PVC_RECURSE_PLACEHOLDERS)
                                699                 :                :         {
                                700                 :                :             /* fall through to recurse into the placeholder's expression */
                                701                 :                :         }
                                702                 :                :         else
 2957 tgl@sss.pgh.pa.us         703         [ #  # ]:UBC           0 :             elog(ERROR, "PlaceHolderVar found where not expected");
                                704                 :                :     }
 9066 tgl@sss.pgh.pa.us         705                 :CBC     1103060 :     return expression_tree_walker(node, pull_var_clause_walker,
                                706                 :                :                                   (void *) context);
                                707                 :                : }
                                708                 :                : 
                                709                 :                : 
                                710                 :                : /*
                                711                 :                :  * flatten_join_alias_vars
                                712                 :                :  *    Replace Vars that reference JOIN outputs with references to the original
                                713                 :                :  *    relation variables instead.  This allows quals involving such vars to be
                                714                 :                :  *    pushed down.  Whole-row Vars that reference JOIN relations are expanded
                                715                 :                :  *    into RowExpr constructs that name the individual output Vars.  This
                                716                 :                :  *    is necessary since we will not scan the JOIN as a base relation, which
                                717                 :                :  *    is the only way that the executor can directly handle whole-row Vars.
                                718                 :                :  *
                                719                 :                :  * This also adjusts relid sets found in some expression node types to
                                720                 :                :  * substitute the contained base+OJ rels for any join relid.
                                721                 :                :  *
                                722                 :                :  * If a JOIN contains sub-selects that have been flattened, its join alias
                                723                 :                :  * entries might now be arbitrary expressions, not just Vars.  This affects
                                724                 :                :  * this function in two important ways.  First, we might find ourselves
                                725                 :                :  * inserting SubLink expressions into subqueries, and we must make sure that
                                726                 :                :  * their Query.hasSubLinks fields get set to true if so.  If there are any
                                727                 :                :  * SubLinks in the join alias lists, the outer Query should already have
                                728                 :                :  * hasSubLinks = true, so this is only relevant to un-flattened subqueries.
                                729                 :                :  * Second, we have to preserve any varnullingrels info attached to the
                                730                 :                :  * alias Vars we're replacing.  If the replacement expression is a Var or
                                731                 :                :  * PlaceHolderVar or constructed from those, we can just add the
                                732                 :                :  * varnullingrels bits to the existing nullingrels field(s); otherwise
                                733                 :                :  * we have to add a PlaceHolderVar wrapper.
                                734                 :                :  *
                                735                 :                :  * NOTE: this is also used by the parser, to expand join alias Vars before
                                736                 :                :  * checking GROUP BY validity.  For that use-case, root will be NULL, which
                                737                 :                :  * is why we have to pass the Query separately.  We need the root itself only
                                738                 :                :  * for making PlaceHolderVars.  We can avoid making PlaceHolderVars in the
                                739                 :                :  * parser's usage because it won't be dealing with arbitrary expressions:
                                740                 :                :  * so long as adjust_standard_join_alias_expression can handle everything
                                741                 :                :  * the parser would make as a join alias expression, we're OK.
                                742                 :                :  */
                                743                 :                : Node *
  440                           744                 :          99929 : flatten_join_alias_vars(PlannerInfo *root, Query *query, Node *node)
                                745                 :                : {
                                746                 :                :     flatten_join_alias_vars_context context;
                                747                 :                : 
                                748                 :                :     /*
                                749                 :                :      * We do not expect this to be applied to the whole Query, only to
                                750                 :                :      * expressions or LATERAL subqueries.  Hence, if the top node is a Query,
                                751                 :                :      * it's okay to immediately increment sublevels_up.
                                752                 :                :      */
                                753         [ -  + ]:          99929 :     Assert(node != (Node *) query);
                                754                 :                : 
                                755                 :          99929 :     context.root = root;
 1902                           756                 :          99929 :     context.query = query;
 7760                           757                 :          99929 :     context.sublevels_up = 0;
                                758                 :                :     /* flag whether join aliases could possibly contain SubLinks */
 1902                           759                 :          99929 :     context.possible_sublink = query->hasSubLinks;
                                760                 :                :     /* if hasSubLinks is already true, no need to work hard */
                                761                 :          99929 :     context.inserted_sublink = query->hasSubLinks;
                                762                 :                : 
 8069                           763                 :          99929 :     return flatten_join_alias_vars_mutator(node, &context);
                                764                 :                : }
                                765                 :                : 
                                766                 :                : static Node *
                                767                 :        1294367 : flatten_join_alias_vars_mutator(Node *node,
                                768                 :                :                                 flatten_join_alias_vars_context *context)
                                769                 :                : {
                                770         [ +  + ]:        1294367 :     if (node == NULL)
                                771                 :         109865 :         return NULL;
                                772         [ +  + ]:        1184502 :     if (IsA(node, Var))
                                773                 :                :     {
 7893 bruce@momjian.us          774                 :         363617 :         Var        *var = (Var *) node;
                                775                 :                :         RangeTblEntry *rte;
                                776                 :                :         Node       *newvar;
                                777                 :                : 
                                778                 :                :         /* No change unless Var belongs to a JOIN of the target level */
 7760 tgl@sss.pgh.pa.us         779         [ +  + ]:         363617 :         if (var->varlevelsup != context->sublevels_up)
 8069                           780                 :          20806 :             return node;        /* no need to copy, really */
 1902                           781                 :         342811 :         rte = rt_fetch(var->varno, context->query->rtable);
 8069                           782         [ +  + ]:         342811 :         if (rte->rtekind != RTE_JOIN)
 8022                           783                 :         342544 :             return node;
 7279                           784         [ +  + ]:            267 :         if (var->varattno == InvalidAttrNumber)
                                785                 :                :         {
                                786                 :                :             /* Must expand whole-row reference */
                                787                 :                :             RowExpr    *rowexpr;
 7168 bruce@momjian.us          788                 :              3 :             List       *fields = NIL;
 4443 tgl@sss.pgh.pa.us         789                 :              3 :             List       *colnames = NIL;
                                790                 :                :             ListCell   *lv;
                                791                 :                :             ListCell   *ln;
                                792                 :                : 
                                793         [ -  + ]:              3 :             Assert(list_length(rte->joinaliasvars) == list_length(rte->eref->colnames));
                                794   [ +  -  +  +  :             24 :             forboth(lv, rte->joinaliasvars, ln, rte->eref->colnames)
                                     +  -  +  +  +  
                                        +  +  -  +  
                                                 + ]
                                795                 :                :             {
                                796                 :             21 :                 newvar = (Node *) lfirst(lv);
                                797                 :                :                 /* Ignore dropped columns */
 3918                           798         [ -  + ]:             21 :                 if (newvar == NULL)
 7178 tgl@sss.pgh.pa.us         799                 :UBC           0 :                     continue;
 4548 tgl@sss.pgh.pa.us         800                 :CBC          21 :                 newvar = copyObject(newvar);
                                801                 :                : 
                                802                 :                :                 /*
                                803                 :                :                  * If we are expanding an alias carried down from an upper
                                804                 :                :                  * query, must adjust its varlevelsup fields.
                                805                 :                :                  */
 7279                           806         [ -  + ]:             21 :                 if (context->sublevels_up != 0)
 7279 tgl@sss.pgh.pa.us         807                 :UBC           0 :                     IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
                                808                 :                :                 /* Preserve original Var's location, if possible */
 4548 tgl@sss.pgh.pa.us         809         [ +  - ]:CBC          21 :                 if (IsA(newvar, Var))
                                810                 :             21 :                     ((Var *) newvar)->location = var->location;
                                811                 :                :                 /* Recurse in case join input is itself a join */
                                812                 :                :                 /* (also takes care of setting inserted_sublink if needed) */
 7279                           813                 :             21 :                 newvar = flatten_join_alias_vars_mutator(newvar, context);
                                814                 :             21 :                 fields = lappend(fields, newvar);
                                815                 :                :                 /* We need the names of non-dropped columns, too */
 4443                           816                 :             21 :                 colnames = lappend(colnames, copyObject((Node *) lfirst(ln)));
                                817                 :                :             }
 7279                           818                 :              3 :             rowexpr = makeNode(RowExpr);
                                819                 :              3 :             rowexpr->args = fields;
                                820                 :              3 :             rowexpr->row_typeid = var->vartype;
                                821                 :              3 :             rowexpr->row_format = COERCE_IMPLICIT_CAST;
                                822                 :                :             /* vartype will always be RECORDOID, so we always need colnames */
 4443                           823                 :              3 :             rowexpr->colnames = colnames;
 4548                           824                 :              3 :             rowexpr->location = var->location;
                                825                 :                : 
                                826                 :                :             /* Lastly, add any varnullingrels to the replacement expression */
  440                           827                 :              3 :             return add_nullingrels_if_needed(context->root, (Node *) rowexpr,
                                828                 :                :                                              var);
                                829                 :                :         }
                                830                 :                : 
                                831                 :                :         /* Expand join alias reference */
 8022                           832         [ -  + ]:            264 :         Assert(var->varattno > 0);
 7259 neilc@samurai.com         833                 :            264 :         newvar = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1);
 3918 tgl@sss.pgh.pa.us         834         [ -  + ]:            264 :         Assert(newvar != NULL);
 4548                           835                 :            264 :         newvar = copyObject(newvar);
                                836                 :                : 
                                837                 :                :         /*
                                838                 :                :          * If we are expanding an alias carried down from an upper query, must
                                839                 :                :          * adjust its varlevelsup fields.
                                840                 :                :          */
 7738                           841         [ -  + ]:            264 :         if (context->sublevels_up != 0)
 7738 tgl@sss.pgh.pa.us         842                 :UBC           0 :             IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
                                843                 :                : 
                                844                 :                :         /* Preserve original Var's location, if possible */
 4548 tgl@sss.pgh.pa.us         845         [ -  + ]:CBC         264 :         if (IsA(newvar, Var))
 4548 tgl@sss.pgh.pa.us         846                 :UBC           0 :             ((Var *) newvar)->location = var->location;
                                847                 :                : 
                                848                 :                :         /* Recurse in case join input is itself a join */
 5029 tgl@sss.pgh.pa.us         849                 :CBC         264 :         newvar = flatten_join_alias_vars_mutator(newvar, context);
                                850                 :                : 
                                851                 :                :         /* Detect if we are adding a sublink to query */
                                852   [ -  +  -  - ]:            264 :         if (context->possible_sublink && !context->inserted_sublink)
 5029 tgl@sss.pgh.pa.us         853                 :UBC           0 :             context->inserted_sublink = checkExprHasSubLink(newvar);
                                854                 :                : 
                                855                 :                :         /* Lastly, add any varnullingrels to the replacement expression */
  440 tgl@sss.pgh.pa.us         856                 :CBC         264 :         return add_nullingrels_if_needed(context->root, newvar, var);
                                857                 :                :     }
 5654                           858         [ +  + ]:         820885 :     if (IsA(node, PlaceHolderVar))
                                859                 :                :     {
                                860                 :                :         /* Copy the PlaceHolderVar node with correct mutation of subnodes */
                                861                 :                :         PlaceHolderVar *phv;
                                862                 :                : 
                                863                 :            839 :         phv = (PlaceHolderVar *) expression_tree_mutator(node,
                                864                 :                :                                                          flatten_join_alias_vars_mutator,
                                865                 :                :                                                          (void *) context);
                                866                 :                :         /* now fix PlaceHolderVar's relid sets */
                                867         [ +  + ]:            839 :         if (phv->phlevelsup == context->sublevels_up)
                                868                 :                :         {
 1902                           869                 :            803 :             phv->phrels = alias_relid_set(context->query,
                                870                 :                :                                           phv->phrels);
                                871                 :                :             /* we *don't* change phnullingrels */
                                872                 :                :         }
 5654                           873                 :            839 :         return (Node *) phv;
                                874                 :                :     }
                                875                 :                : 
 7760                           876         [ +  + ]:         820046 :     if (IsA(node, Query))
                                877                 :                :     {
                                878                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                                879                 :                :         Query      *newnode;
                                880                 :                :         bool        save_inserted_sublink;
                                881                 :                : 
                                882                 :           6147 :         context->sublevels_up++;
 5029                           883                 :           6147 :         save_inserted_sublink = context->inserted_sublink;
                                884                 :           6147 :         context->inserted_sublink = ((Query *) node)->hasSubLinks;
 7758                           885                 :           6147 :         newnode = query_tree_mutator((Query *) node,
                                886                 :                :                                      flatten_join_alias_vars_mutator,
                                887                 :                :                                      (void *) context,
                                888                 :                :                                      QTW_IGNORE_JOINALIASES);
 5029                           889                 :           6147 :         newnode->hasSubLinks |= context->inserted_sublink;
                                890                 :           6147 :         context->inserted_sublink = save_inserted_sublink;
 7760                           891                 :           6147 :         context->sublevels_up--;
                                892                 :           6147 :         return (Node *) newnode;
                                893                 :                :     }
                                894                 :                :     /* Already-planned tree not supported */
 5714                           895         [ -  + ]:         813899 :     Assert(!IsA(node, SubPlan));
                                896                 :                :     /* Shouldn't need to handle these planner auxiliary nodes here */
 5653                           897         [ -  + ]:         813899 :     Assert(!IsA(node, SpecialJoinInfo));
                                898         [ -  + ]:         813899 :     Assert(!IsA(node, PlaceHolderInfo));
 4910                           899         [ -  + ]:         813899 :     Assert(!IsA(node, MinMaxAggInfo));
                                900                 :                : 
 8022                           901                 :         813899 :     return expression_tree_mutator(node, flatten_join_alias_vars_mutator,
                                902                 :                :                                    (void *) context);
                                903                 :                : }
                                904                 :                : 
                                905                 :                : /*
                                906                 :                :  * Add oldvar's varnullingrels, if any, to a flattened join alias expression.
                                907                 :                :  * The newnode has been copied, so we can modify it freely.
                                908                 :                :  */
                                909                 :                : static Node *
  440                           910                 :            267 : add_nullingrels_if_needed(PlannerInfo *root, Node *newnode, Var *oldvar)
                                911                 :                : {
                                912         [ +  + ]:            267 :     if (oldvar->varnullingrels == NULL)
                                913                 :            189 :         return newnode;         /* nothing to do */
                                914                 :                :     /* If possible, do it by adding to existing nullingrel fields */
                                915         [ +  + ]:             78 :     if (is_standard_join_alias_expression(newnode, oldvar))
                                916                 :             72 :         adjust_standard_join_alias_expression(newnode, oldvar);
                                917         [ +  - ]:              6 :     else if (root)
                                918                 :                :     {
                                919                 :                :         /*
                                920                 :                :          * We can insert a PlaceHolderVar to carry the nullingrels.  However,
                                921                 :                :          * deciding where to evaluate the PHV is slightly tricky.  We first
                                922                 :                :          * try to evaluate it at the natural semantic level of the new
                                923                 :                :          * expression; but if that expression is variable-free, fall back to
                                924                 :                :          * evaluating it at the join that the oldvar is an alias Var for.
                                925                 :                :          */
                                926                 :                :         PlaceHolderVar *newphv;
                                927                 :              6 :         Index       levelsup = oldvar->varlevelsup;
                                928                 :              6 :         Relids      phrels = pull_varnos_of_level(root, newnode, levelsup);
                                929                 :                : 
                                930         [ +  - ]:              6 :         if (bms_is_empty(phrels))   /* variable-free? */
                                931                 :                :         {
                                932         [ -  + ]:              6 :             if (levelsup != 0)  /* this won't work otherwise */
  440 tgl@sss.pgh.pa.us         933         [ #  # ]:UBC           0 :                 elog(ERROR, "unsupported join alias expression");
  440 tgl@sss.pgh.pa.us         934                 :CBC           6 :             phrels = get_relids_for_join(root->parse, oldvar->varno);
                                935                 :                :             /* If it's an outer join, eval below not above the join */
                                936                 :              6 :             phrels = bms_del_member(phrels, oldvar->varno);
                                937         [ -  + ]:              6 :             Assert(!bms_is_empty(phrels));
                                938                 :                :         }
                                939                 :              6 :         newphv = make_placeholder_expr(root, (Expr *) newnode, phrels);
                                940                 :                :         /* newphv has zero phlevelsup and NULL phnullingrels; fix it */
                                941                 :              6 :         newphv->phlevelsup = levelsup;
                                942                 :              6 :         newphv->phnullingrels = bms_copy(oldvar->varnullingrels);
                                943                 :              6 :         newnode = (Node *) newphv;
                                944                 :                :     }
                                945                 :                :     else
                                946                 :                :     {
                                947                 :                :         /* ooops, we're missing support for something the parser can make */
  440 tgl@sss.pgh.pa.us         948         [ #  # ]:UBC           0 :         elog(ERROR, "unsupported join alias expression");
                                949                 :                :     }
  440 tgl@sss.pgh.pa.us         950                 :CBC          78 :     return newnode;
                                951                 :                : }
                                952                 :                : 
                                953                 :                : /*
                                954                 :                :  * Check to see if we can insert nullingrels into this join alias expression
                                955                 :                :  * without use of a separate PlaceHolderVar.
                                956                 :                :  *
                                957                 :                :  * This will handle Vars, PlaceHolderVars, and implicit-coercion and COALESCE
                                958                 :                :  * expressions built from those.  This coverage needs to handle anything
                                959                 :                :  * that the parser would put into joinaliasvars.
                                960                 :                :  */
                                961                 :                : static bool
                                962                 :            234 : is_standard_join_alias_expression(Node *newnode, Var *oldvar)
                                963                 :                : {
                                964         [ -  + ]:            234 :     if (newnode == NULL)
  440 tgl@sss.pgh.pa.us         965                 :UBC           0 :         return false;
  440 tgl@sss.pgh.pa.us         966         [ +  + ]:CBC         234 :     if (IsA(newnode, Var) &&
                                967         [ +  - ]:            138 :         ((Var *) newnode)->varlevelsup == oldvar->varlevelsup)
                                968                 :            138 :         return true;
                                969         [ -  + ]:             96 :     else if (IsA(newnode, PlaceHolderVar) &&
  440 tgl@sss.pgh.pa.us         970         [ #  # ]:UBC           0 :              ((PlaceHolderVar *) newnode)->phlevelsup == oldvar->varlevelsup)
                                971                 :              0 :         return true;
  440 tgl@sss.pgh.pa.us         972         [ +  + ]:CBC          96 :     else if (IsA(newnode, FuncExpr))
                                973                 :                :     {
                                974                 :             15 :         FuncExpr   *fexpr = (FuncExpr *) newnode;
                                975                 :                : 
                                976                 :                :         /*
                                977                 :                :          * We need to assume that the function wouldn't produce non-NULL from
                                978                 :                :          * NULL, which is reasonable for implicit coercions but otherwise not
                                979                 :                :          * so much.  (Looking at its strictness is likely overkill, and anyway
                                980                 :                :          * it would cause us to fail if someone forgot to mark an implicit
                                981                 :                :          * coercion as strict.)
                                982                 :                :          */
                                983         [ +  - ]:             15 :         if (fexpr->funcformat != COERCE_IMPLICIT_CAST ||
                                984         [ -  + ]:             15 :             fexpr->args == NIL)
  440 tgl@sss.pgh.pa.us         985                 :UBC           0 :             return false;
                                986                 :                : 
                                987                 :                :         /*
                                988                 :                :          * Examine only the first argument --- coercions might have additional
                                989                 :                :          * arguments that are constants.
                                990                 :                :          */
  440 tgl@sss.pgh.pa.us         991                 :CBC          15 :         return is_standard_join_alias_expression(linitial(fexpr->args), oldvar);
                                992                 :                :     }
                                993         [ +  + ]:             81 :     else if (IsA(newnode, RelabelType))
                                994                 :                :     {
                                995                 :              9 :         RelabelType *relabel = (RelabelType *) newnode;
                                996                 :                : 
                                997                 :                :         /* This definitely won't produce non-NULL from NULL */
                                998                 :              9 :         return is_standard_join_alias_expression((Node *) relabel->arg, oldvar);
                                999                 :                :     }
                               1000         [ -  + ]:             72 :     else if (IsA(newnode, CoerceViaIO))
                               1001                 :                :     {
  440 tgl@sss.pgh.pa.us        1002                 :UBC           0 :         CoerceViaIO *iocoerce = (CoerceViaIO *) newnode;
                               1003                 :                : 
                               1004                 :                :         /* This definitely won't produce non-NULL from NULL */
                               1005                 :              0 :         return is_standard_join_alias_expression((Node *) iocoerce->arg, oldvar);
                               1006                 :                :     }
  440 tgl@sss.pgh.pa.us        1007         [ -  + ]:CBC          72 :     else if (IsA(newnode, ArrayCoerceExpr))
                               1008                 :                :     {
  440 tgl@sss.pgh.pa.us        1009                 :UBC           0 :         ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) newnode;
                               1010                 :                : 
                               1011                 :                :         /* This definitely won't produce non-NULL from NULL (at array level) */
                               1012                 :              0 :         return is_standard_join_alias_expression((Node *) acoerce->arg, oldvar);
                               1013                 :                :     }
  440 tgl@sss.pgh.pa.us        1014         [ +  + ]:CBC          72 :     else if (IsA(newnode, CoalesceExpr))
                               1015                 :                :     {
                               1016                 :             66 :         CoalesceExpr *cexpr = (CoalesceExpr *) newnode;
                               1017                 :                :         ListCell   *lc;
                               1018                 :                : 
                               1019         [ -  + ]:             66 :         Assert(cexpr->args != NIL);
                               1020   [ +  -  +  +  :            198 :         foreach(lc, cexpr->args)
                                              +  + ]
                               1021                 :                :         {
                               1022         [ -  + ]:            132 :             if (!is_standard_join_alias_expression(lfirst(lc), oldvar))
  440 tgl@sss.pgh.pa.us        1023                 :UBC           0 :                 return false;
                               1024                 :                :         }
  440 tgl@sss.pgh.pa.us        1025                 :CBC          66 :         return true;
                               1026                 :                :     }
                               1027                 :                :     else
                               1028                 :              6 :         return false;
                               1029                 :                : }
                               1030                 :                : 
                               1031                 :                : /*
                               1032                 :                :  * Insert nullingrels into an expression accepted by
                               1033                 :                :  * is_standard_join_alias_expression.
                               1034                 :                :  */
                               1035                 :                : static void
                               1036                 :            222 : adjust_standard_join_alias_expression(Node *newnode, Var *oldvar)
                               1037                 :                : {
                               1038         [ +  + ]:            222 :     if (IsA(newnode, Var) &&
                               1039         [ +  - ]:            138 :         ((Var *) newnode)->varlevelsup == oldvar->varlevelsup)
                               1040                 :            138 :     {
                               1041                 :            138 :         Var        *newvar = (Var *) newnode;
                               1042                 :                : 
                               1043                 :            138 :         newvar->varnullingrels = bms_add_members(newvar->varnullingrels,
                               1044                 :            138 :                                                  oldvar->varnullingrels);
                               1045                 :                :     }
                               1046         [ -  + ]:             84 :     else if (IsA(newnode, PlaceHolderVar) &&
  440 tgl@sss.pgh.pa.us        1047         [ #  # ]:UBC           0 :              ((PlaceHolderVar *) newnode)->phlevelsup == oldvar->varlevelsup)
                               1048                 :              0 :     {
                               1049                 :              0 :         PlaceHolderVar *newphv = (PlaceHolderVar *) newnode;
                               1050                 :                : 
                               1051                 :              0 :         newphv->phnullingrels = bms_add_members(newphv->phnullingrels,
                               1052                 :              0 :                                                 oldvar->varnullingrels);
                               1053                 :                :     }
  440 tgl@sss.pgh.pa.us        1054         [ +  + ]:CBC          84 :     else if (IsA(newnode, FuncExpr))
                               1055                 :                :     {
                               1056                 :              9 :         FuncExpr   *fexpr = (FuncExpr *) newnode;
                               1057                 :                : 
                               1058                 :              9 :         adjust_standard_join_alias_expression(linitial(fexpr->args), oldvar);
                               1059                 :                :     }
                               1060         [ +  + ]:             75 :     else if (IsA(newnode, RelabelType))
                               1061                 :                :     {
                               1062                 :              9 :         RelabelType *relabel = (RelabelType *) newnode;
                               1063                 :                : 
                               1064                 :              9 :         adjust_standard_join_alias_expression((Node *) relabel->arg, oldvar);
                               1065                 :                :     }
                               1066         [ -  + ]:             66 :     else if (IsA(newnode, CoerceViaIO))
                               1067                 :                :     {
  440 tgl@sss.pgh.pa.us        1068                 :UBC           0 :         CoerceViaIO *iocoerce = (CoerceViaIO *) newnode;
                               1069                 :                : 
                               1070                 :              0 :         adjust_standard_join_alias_expression((Node *) iocoerce->arg, oldvar);
                               1071                 :                :     }
  440 tgl@sss.pgh.pa.us        1072         [ -  + ]:CBC          66 :     else if (IsA(newnode, ArrayCoerceExpr))
                               1073                 :                :     {
  440 tgl@sss.pgh.pa.us        1074                 :UBC           0 :         ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) newnode;
                               1075                 :                : 
                               1076                 :              0 :         adjust_standard_join_alias_expression((Node *) acoerce->arg, oldvar);
                               1077                 :                :     }
  440 tgl@sss.pgh.pa.us        1078         [ +  - ]:CBC          66 :     else if (IsA(newnode, CoalesceExpr))
                               1079                 :                :     {
                               1080                 :             66 :         CoalesceExpr *cexpr = (CoalesceExpr *) newnode;
                               1081                 :                :         ListCell   *lc;
                               1082                 :                : 
                               1083         [ -  + ]:             66 :         Assert(cexpr->args != NIL);
                               1084   [ +  -  +  +  :            198 :         foreach(lc, cexpr->args)
                                              +  + ]
                               1085                 :                :         {
                               1086                 :            132 :             adjust_standard_join_alias_expression(lfirst(lc), oldvar);
                               1087                 :                :         }
                               1088                 :                :     }
                               1089                 :                :     else
  440 tgl@sss.pgh.pa.us        1090                 :UBC           0 :         Assert(false);
  440 tgl@sss.pgh.pa.us        1091                 :CBC         222 : }
                               1092                 :                : 
                               1093                 :                : /*
                               1094                 :                :  * alias_relid_set: in a set of RT indexes, replace joins by their
                               1095                 :                :  * underlying base+OJ relids
                               1096                 :                :  */
                               1097                 :                : static Relids
 1902                          1098                 :            803 : alias_relid_set(Query *query, Relids relids)
                               1099                 :                : {
 7736                          1100                 :            803 :     Relids      result = NULL;
                               1101                 :                :     int         rtindex;
                               1102                 :                : 
 3425                          1103                 :            803 :     rtindex = -1;
                               1104         [ +  + ]:           2070 :     while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
                               1105                 :                :     {
 1902                          1106                 :           1267 :         RangeTblEntry *rte = rt_fetch(rtindex, query->rtable);
                               1107                 :                : 
 7755                          1108         [ +  + ]:           1267 :         if (rte->rtekind == RTE_JOIN)
 1902                          1109                 :            167 :             result = bms_join(result, get_relids_for_join(query, rtindex));
                               1110                 :                :         else
 7736                          1111                 :           1100 :             result = bms_add_member(result, rtindex);
                               1112                 :                :     }
 7755                          1113                 :            803 :     return result;
                               1114                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622