LCOV - differential code coverage report
Current view: top level - src/backend/optimizer/util - var.c (source / functions) Coverage Total Hit UNC UBC GBC GNC CBC
Current: 0e5ff9b9b45a657aea12440478dc002e9b01f138 vs 0123ce131fca454009439dfa3b2266d1d40737d7 Lines: 87.6 % 468 410 58 2 8 400
Current Date: 2026-03-14 14:10:32 -0400 Functions: 100.0 % 27 27 1 26
Baseline: lcov-20260315-024220-baseline Branches: 69.7 % 356 248 1 107 4 1 243
Baseline Date: 2026-03-14 15:27:56 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 100.0 % 8 8 5 3
(360..) days: 87.4 % 460 402 58 2 3 397
Function coverage date bins:
(7,30] days: 100.0 % 1 1 1
(360..) days: 100.0 % 26 26 26
Branch coverage date bins:
(7,30] days: 50.0 % 2 1 1 1
(360..) days: 69.8 % 354 247 107 4 243

 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-2026, 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/clauses.h"
                                 26                 :                : #include "optimizer/optimizer.h"
                                 27                 :                : #include "optimizer/placeholder.h"
                                 28                 :                : #include "optimizer/prep.h"
                                 29                 :                : #include "parser/parsetree.h"
                                 30                 :                : #include "rewrite/rewriteManip.h"
                                 31                 :                : 
                                 32                 :                : 
                                 33                 :                : typedef struct
                                 34                 :                : {
                                 35                 :                :     Relids      varnos;
                                 36                 :                :     PlannerInfo *root;
                                 37                 :                :     int         sublevels_up;
                                 38                 :                : } pull_varnos_context;
                                 39                 :                : 
                                 40                 :                : typedef struct
                                 41                 :                : {
                                 42                 :                :     Bitmapset  *varattnos;
                                 43                 :                :     Index       varno;
                                 44                 :                : } pull_varattnos_context;
                                 45                 :                : 
                                 46                 :                : typedef struct
                                 47                 :                : {
                                 48                 :                :     List       *vars;
                                 49                 :                :     int         sublevels_up;
                                 50                 :                : } pull_vars_context;
                                 51                 :                : 
                                 52                 :                : typedef struct
                                 53                 :                : {
                                 54                 :                :     int         var_location;
                                 55                 :                :     int         sublevels_up;
                                 56                 :                : } locate_var_of_level_context;
                                 57                 :                : 
                                 58                 :                : typedef struct
                                 59                 :                : {
                                 60                 :                :     List       *varlist;
                                 61                 :                :     int         flags;
                                 62                 :                : } pull_var_clause_context;
                                 63                 :                : 
                                 64                 :                : typedef struct
                                 65                 :                : {
                                 66                 :                :     PlannerInfo *root;          /* could be NULL! */
                                 67                 :                :     Query      *query;          /* outer Query */
                                 68                 :                :     int         sublevels_up;
                                 69                 :                :     bool        possible_sublink;   /* could aliases include a SubLink? */
                                 70                 :                :     bool        inserted_sublink;   /* have we inserted a SubLink? */
                                 71                 :                : } flatten_join_alias_vars_context;
                                 72                 :                : 
                                 73                 :                : static bool pull_varnos_walker(Node *node,
                                 74                 :                :                                pull_varnos_context *context);
                                 75                 :                : static bool pull_varattnos_walker(Node *node, pull_varattnos_context *context);
                                 76                 :                : static bool pull_vars_walker(Node *node, pull_vars_context *context);
                                 77                 :                : static bool contain_var_clause_walker(Node *node, void *context);
                                 78                 :                : static bool contain_vars_of_level_walker(Node *node, int *sublevels_up);
                                 79                 :                : static bool contain_vars_returning_old_or_new_walker(Node *node, void *context);
                                 80                 :                : static bool locate_var_of_level_walker(Node *node,
                                 81                 :                :                                        locate_var_of_level_context *context);
                                 82                 :                : static bool pull_var_clause_walker(Node *node,
                                 83                 :                :                                    pull_var_clause_context *context);
                                 84                 :                : static Node *flatten_join_alias_vars_mutator(Node *node,
                                 85                 :                :                                              flatten_join_alias_vars_context *context);
                                 86                 :                : static Node *flatten_group_exprs_mutator(Node *node,
                                 87                 :                :                                          flatten_join_alias_vars_context *context);
                                 88                 :                : static Node *mark_nullable_by_grouping(PlannerInfo *root, Node *newnode,
                                 89                 :                :                                        Var *oldvar);
                                 90                 :                : static Node *add_nullingrels_if_needed(PlannerInfo *root, Node *newnode,
                                 91                 :                :                                        Var *oldvar);
                                 92                 :                : static bool is_standard_join_alias_expression(Node *newnode, Var *oldvar);
                                 93                 :                : static void adjust_standard_join_alias_expression(Node *newnode, Var *oldvar);
                                 94                 :                : static Relids alias_relid_set(Query *query, Relids relids);
                                 95                 :                : 
                                 96                 :                : 
                                 97                 :                : /*
                                 98                 :                :  * pull_varnos
                                 99                 :                :  *      Create a set of all the distinct varnos present in a parsetree.
                                100                 :                :  *      Only varnos that reference level-zero rtable entries are considered.
                                101                 :                :  *
                                102                 :                :  * The result includes outer-join relids mentioned in Var.varnullingrels and
                                103                 :                :  * PlaceHolderVar.phnullingrels fields in the parsetree.
                                104                 :                :  *
                                105                 :                :  * "root" can be passed as NULL if it is not necessary to process
                                106                 :                :  * PlaceHolderVars.
                                107                 :                :  *
                                108                 :                :  * NOTE: this is used on not-yet-planned expressions.  It may therefore find
                                109                 :                :  * bare SubLinks, and if so it needs to recurse into them to look for uplevel
                                110                 :                :  * references to the desired rtable level!  But when we find a completed
                                111                 :                :  * SubPlan, we only need to look at the parameters passed to the subplan.
                                112                 :                :  */
                                113                 :                : Relids
 1879 tgl@sss.pgh.pa.us         114                 :CBC     1910047 : pull_varnos(PlannerInfo *root, Node *node)
                                115                 :                : {
                                116                 :                :     pull_varnos_context context;
                                117                 :                : 
 8436                           118                 :        1910047 :     context.varnos = NULL;
 1879                           119                 :        1910047 :     context.root = root;
 9315                           120                 :        1910047 :     context.sublevels_up = 0;
                                121                 :                : 
                                122                 :                :     /*
                                123                 :                :      * Must be prepared to start with a Query or a bare expression tree; if
                                124                 :                :      * it's a Query, we don't want to increment sublevels_up.
                                125                 :                :      */
 8458                           126                 :        1910047 :     query_or_expression_tree_walker(node,
                                127                 :                :                                     pull_varnos_walker,
                                128                 :                :                                     &context,
                                129                 :                :                                     0);
                                130                 :                : 
 8436                           131                 :        1910047 :     return context.varnos;
                                132                 :                : }
                                133                 :                : 
                                134                 :                : /*
                                135                 :                :  * pull_varnos_of_level
                                136                 :                :  *      Create a set of all the distinct varnos present in a parsetree.
                                137                 :                :  *      Only Vars of the specified level are considered.
                                138                 :                :  */
                                139                 :                : Relids
 1879                           140                 :           5016 : pull_varnos_of_level(PlannerInfo *root, Node *node, int levelsup)
                                141                 :                : {
                                142                 :                :     pull_varnos_context context;
                                143                 :                : 
 4968                           144                 :           5016 :     context.varnos = NULL;
 1879                           145                 :           5016 :     context.root = root;
 4968                           146                 :           5016 :     context.sublevels_up = levelsup;
                                147                 :                : 
                                148                 :                :     /*
                                149                 :                :      * Must be prepared to start with a Query or a bare expression tree; if
                                150                 :                :      * it's a Query, we don't want to increment sublevels_up.
                                151                 :                :      */
                                152                 :           5016 :     query_or_expression_tree_walker(node,
                                153                 :                :                                     pull_varnos_walker,
                                154                 :                :                                     &context,
                                155                 :                :                                     0);
                                156                 :                : 
                                157                 :           5016 :     return context.varnos;
                                158                 :                : }
                                159                 :                : 
                                160                 :                : static bool
 9315                           161                 :        3316894 : pull_varnos_walker(Node *node, pull_varnos_context *context)
                                162                 :                : {
 9766                           163         [ +  + ]:        3316894 :     if (node == NULL)
                                164                 :         117277 :         return false;
                                165         [ +  + ]:        3199617 :     if (IsA(node, Var))
                                166                 :                :     {
 9468 bruce@momjian.us          167                 :        1606992 :         Var        *var = (Var *) node;
                                168                 :                : 
 8436 tgl@sss.pgh.pa.us         169         [ +  + ]:        1606992 :         if (var->varlevelsup == context->sublevels_up)
                                170                 :                :         {
                                171                 :        1600214 :             context->varnos = bms_add_member(context->varnos, var->varno);
 1140                           172                 :        1600214 :             context->varnos = bms_add_members(context->varnos,
                                173                 :        1600214 :                                               var->varnullingrels);
                                174                 :                :         }
 9766                           175                 :        1606992 :         return false;
                                176                 :                :     }
 6852                           177         [ +  + ]:        1592625 :     if (IsA(node, CurrentOfExpr))
                                178                 :                :     {
                                179                 :            400 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
                                180                 :                : 
                                181         [ +  - ]:            400 :         if (context->sublevels_up == 0)
                                182                 :            400 :             context->varnos = bms_add_member(context->varnos, cexpr->cvarno);
                                183                 :            400 :         return false;
                                184                 :                :     }
 6354                           185         [ +  + ]:        1592225 :     if (IsA(node, PlaceHolderVar))
                                186                 :                :     {
                                187                 :           2780 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
                                188                 :                : 
                                189                 :                :         /*
                                190                 :                :          * If a PlaceHolderVar is not of the target query level, ignore it,
                                191                 :                :          * instead recursing into its expression to see if it contains any
                                192                 :                :          * vars that are of the target level.  We'll also do that when the
                                193                 :                :          * caller doesn't pass a "root" pointer.  (We probably shouldn't see
                                194                 :                :          * PlaceHolderVars at all in such cases, but if we do, this is a
                                195                 :                :          * reasonable behavior.)
                                196                 :                :          */
 1526                           197         [ +  - ]:           2780 :         if (phv->phlevelsup == context->sublevels_up &&
                                198         [ +  - ]:           2780 :             context->root != NULL)
                                199                 :                :         {
                                200                 :                :             /*
                                201                 :                :              * Ideally, the PHV's contribution to context->varnos is its
                                202                 :                :              * ph_eval_at set.  However, this code can be invoked before
                                203                 :                :              * that's been computed.  If we cannot find a PlaceHolderInfo,
                                204                 :                :              * fall back to the conservative assumption that the PHV will be
                                205                 :                :              * evaluated at its syntactic level (phv->phrels).
                                206                 :                :              *
                                207                 :                :              * Another problem is that a PlaceHolderVar can appear in quals or
                                208                 :                :              * tlists that have been translated for use in a child appendrel.
                                209                 :                :              * Typically such a PHV is a parameter expression sourced by some
                                210                 :                :              * other relation, so that the translation from parent appendrel
                                211                 :                :              * to child doesn't change its phrels, and we should still take
                                212                 :                :              * ph_eval_at at face value.  But in corner cases, the PHV's
                                213                 :                :              * original phrels can include the parent appendrel itself, in
                                214                 :                :              * which case the translated PHV will have the child appendrel in
                                215                 :                :              * phrels, and we must translate ph_eval_at to match.
                                216                 :                :              */
 1879                           217                 :           2780 :             PlaceHolderInfo *phinfo = NULL;
                                218                 :                : 
                                219         [ +  + ]:           2780 :             if (phv->phlevelsup == 0)
                                220                 :                :             {
 1306                           221         [ +  + ]:           2732 :                 if (phv->phid < context->root->placeholder_array_size)
                                222                 :           2030 :                     phinfo = context->root->placeholder_array[phv->phid];
                                223                 :                :             }
 1640                           224         [ +  + ]:           2780 :             if (phinfo == NULL)
                                225                 :                :             {
                                226                 :                :                 /* No PlaceHolderInfo yet, use phrels */
                                227                 :            756 :                 context->varnos = bms_add_members(context->varnos,
                                228                 :            756 :                                                   phv->phrels);
                                229                 :                :             }
                                230         [ +  + ]:           2024 :             else if (bms_equal(phv->phrels, phinfo->ph_var->phrels))
                                231                 :                :             {
                                232                 :                :                 /* Normal case: use ph_eval_at */
 1879                           233                 :           1889 :                 context->varnos = bms_add_members(context->varnos,
                                234                 :           1889 :                                                   phinfo->ph_eval_at);
                                235                 :                :             }
                                236                 :                :             else
                                237                 :                :             {
                                238                 :                :                 /* Translated PlaceHolderVar: translate ph_eval_at to match */
                                239                 :                :                 Relids      newevalat,
                                240                 :                :                             delta;
                                241                 :                : 
                                242                 :                :                 /* remove what was removed from phv->phrels ... */
 1640                           243                 :            135 :                 delta = bms_difference(phinfo->ph_var->phrels, phv->phrels);
                                244                 :            135 :                 newevalat = bms_difference(phinfo->ph_eval_at, delta);
                                245                 :                :                 /* ... then if that was in fact part of ph_eval_at ... */
                                246         [ +  + ]:            135 :                 if (!bms_equal(newevalat, phinfo->ph_eval_at))
                                247                 :                :                 {
                                248                 :                :                     /* ... add what was added */
                                249                 :             84 :                     delta = bms_difference(phv->phrels, phinfo->ph_var->phrels);
                                250                 :             84 :                     newevalat = bms_join(newevalat, delta);
                                251                 :                :                 }
                                252                 :            135 :                 context->varnos = bms_join(context->varnos,
                                253                 :                :                                            newevalat);
                                254                 :                :             }
                                255                 :                : 
                                256                 :                :             /*
                                257                 :                :              * In all three cases, include phnullingrels in the result.  We
                                258                 :                :              * don't worry about possibly needing to translate it, because
                                259                 :                :              * appendrels only translate varnos of baserels, not outer joins.
                                260                 :                :              */
 1140                           261                 :           5560 :             context->varnos = bms_add_members(context->varnos,
                                262                 :           2780 :                                               phv->phnullingrels);
 1879                           263                 :           2780 :             return false;       /* don't recurse into expression */
                                264                 :                :         }
                                265                 :                :     }
                                266         [ +  + ]:        1589445 :     else if (IsA(node, Query))
                                267                 :                :     {
                                268                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                                269                 :                :         bool        result;
                                270                 :                : 
 9315                           271                 :           3794 :         context->sublevels_up++;
                                272                 :           3794 :         result = query_tree_walker((Query *) node, pull_varnos_walker,
                                273                 :                :                                    context, 0);
                                274                 :           3794 :         context->sublevels_up--;
                                275                 :           3794 :         return result;
                                276                 :                :     }
  472 peter@eisentraut.org      277                 :        1585651 :     return expression_tree_walker(node, pull_varnos_walker, context);
                                278                 :                : }
                                279                 :                : 
                                280                 :                : 
                                281                 :                : /*
                                282                 :                :  * pull_varattnos
                                283                 :                :  *      Find all the distinct attribute numbers present in an expression tree,
                                284                 :                :  *      and add them to the initial contents of *varattnos.
                                285                 :                :  *      Only Vars of the given varno and rtable level zero are considered.
                                286                 :                :  *
                                287                 :                :  * Attribute numbers are offset by FirstLowInvalidHeapAttributeNumber so that
                                288                 :                :  * we can include system attributes (e.g., OID) in the bitmap representation.
                                289                 :                :  *
                                290                 :                :  * Currently, this does not support unplanned subqueries; that is not needed
                                291                 :                :  * for current uses.  It will handle already-planned SubPlan nodes, though,
                                292                 :                :  * looking into only the "testexpr" and the "args" list.  (The subplan cannot
                                293                 :                :  * contain any other references to Vars of the current level.)
                                294                 :                :  */
                                295                 :                : void
 5273 tgl@sss.pgh.pa.us         296                 :        1080910 : pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
                                297                 :                : {
                                298                 :                :     pull_varattnos_context context;
                                299                 :                : 
                                300                 :        1080910 :     context.varattnos = *varattnos;
                                301                 :        1080910 :     context.varno = varno;
                                302                 :                : 
                                303                 :        1080910 :     (void) pull_varattnos_walker(node, &context);
                                304                 :                : 
                                305                 :        1080910 :     *varattnos = context.varattnos;
 6751                           306                 :        1080910 : }
                                307                 :                : 
                                308                 :                : static bool
 5273                           309                 :        3672724 : pull_varattnos_walker(Node *node, pull_varattnos_context *context)
                                310                 :                : {
 6751                           311         [ +  + ]:        3672724 :     if (node == NULL)
                                312                 :          44426 :         return false;
                                313         [ +  + ]:        3628298 :     if (IsA(node, Var))
                                314                 :                :     {
                                315                 :        2117688 :         Var        *var = (Var *) node;
                                316                 :                : 
 5273                           317   [ +  +  +  - ]:        2117688 :         if (var->varno == context->varno && var->varlevelsup == 0)
                                318                 :        2117461 :             context->varattnos =
                                319                 :        2117461 :                 bms_add_member(context->varattnos,
 3189                           320                 :        2117461 :                                var->varattno - FirstLowInvalidHeapAttributeNumber);
 6751                           321                 :        2117688 :         return false;
                                322                 :                :     }
                                323                 :                : 
                                324                 :                :     /* Should not find an unplanned subquery */
                                325         [ -  + ]:        1510610 :     Assert(!IsA(node, Query));
                                326                 :                : 
  472 peter@eisentraut.org      327                 :        1510610 :     return expression_tree_walker(node, pull_varattnos_walker, context);
                                328                 :                : }
                                329                 :                : 
                                330                 :                : 
                                331                 :                : /*
                                332                 :                :  * pull_vars_of_level
                                333                 :                :  *      Create a list of all Vars (and PlaceHolderVars) referencing the
                                334                 :                :  *      specified query level in the given parsetree.
                                335                 :                :  *
                                336                 :                :  * Caution: the Vars are not copied, only linked into the list.
                                337                 :                :  */
                                338                 :                : List *
 4968 tgl@sss.pgh.pa.us         339                 :           5518 : pull_vars_of_level(Node *node, int levelsup)
                                340                 :                : {
                                341                 :                :     pull_vars_context context;
                                342                 :                : 
                                343                 :           5518 :     context.vars = NIL;
                                344                 :           5518 :     context.sublevels_up = levelsup;
                                345                 :                : 
                                346                 :                :     /*
                                347                 :                :      * Must be prepared to start with a Query or a bare expression tree; if
                                348                 :                :      * it's a Query, we don't want to increment sublevels_up.
                                349                 :                :      */
                                350                 :           5518 :     query_or_expression_tree_walker(node,
                                351                 :                :                                     pull_vars_walker,
                                352                 :                :                                     &context,
                                353                 :                :                                     0);
                                354                 :                : 
                                355                 :           5518 :     return context.vars;
                                356                 :                : }
                                357                 :                : 
                                358                 :                : static bool
                                359                 :          80780 : pull_vars_walker(Node *node, pull_vars_context *context)
                                360                 :                : {
                                361         [ +  + ]:          80780 :     if (node == NULL)
                                362                 :          13889 :         return false;
                                363         [ +  + ]:          66891 :     if (IsA(node, Var))
                                364                 :                :     {
                                365                 :          12730 :         Var        *var = (Var *) node;
                                366                 :                : 
                                367         [ +  + ]:          12730 :         if (var->varlevelsup == context->sublevels_up)
                                368                 :           7657 :             context->vars = lappend(context->vars, var);
                                369                 :          12730 :         return false;
                                370                 :                :     }
 4957                           371         [ +  + ]:          54161 :     if (IsA(node, PlaceHolderVar))
                                372                 :                :     {
                                373                 :             69 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
                                374                 :                : 
                                375         [ +  - ]:             69 :         if (phv->phlevelsup == context->sublevels_up)
                                376                 :             69 :             context->vars = lappend(context->vars, phv);
                                377                 :                :         /* we don't want to look into the contained expression */
                                378                 :             69 :         return false;
                                379                 :                :     }
 4968                           380         [ +  + ]:          54092 :     if (IsA(node, Query))
                                381                 :                :     {
                                382                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                                383                 :                :         bool        result;
                                384                 :                : 
                                385                 :            198 :         context->sublevels_up++;
                                386                 :            198 :         result = query_tree_walker((Query *) node, pull_vars_walker,
                                387                 :                :                                    context, 0);
                                388                 :            198 :         context->sublevels_up--;
                                389                 :            198 :         return result;
                                390                 :                :     }
  472 peter@eisentraut.org      391                 :          53894 :     return expression_tree_walker(node, pull_vars_walker, context);
                                392                 :                : }
                                393                 :                : 
                                394                 :                : 
                                395                 :                : /*
                                396                 :                :  * contain_var_clause
                                397                 :                :  *    Recursively scan a clause to discover whether it contains any Var nodes
                                398                 :                :  *    (of the current query level).
                                399                 :                :  *
                                400                 :                :  *    Returns true if any varnode found.
                                401                 :                :  *
                                402                 :                :  * Does not examine subqueries, therefore must only be used after reduction
                                403                 :                :  * of sublinks to subplans!
                                404                 :                :  */
                                405                 :                : bool
 9097 tgl@sss.pgh.pa.us         406                 :          20048 : contain_var_clause(Node *node)
                                407                 :                : {
                                408                 :          20048 :     return contain_var_clause_walker(node, NULL);
                                409                 :                : }
                                410                 :                : 
                                411                 :                : static bool
 9766                           412                 :          24138 : contain_var_clause_walker(Node *node, void *context)
                                413                 :                : {
                                414         [ +  + ]:          24138 :     if (node == NULL)
                                415                 :             62 :         return false;
                                416         [ +  + ]:          24076 :     if (IsA(node, Var))
                                417                 :                :     {
 9698                           418         [ +  - ]:           1348 :         if (((Var *) node)->varlevelsup == 0)
 7456 bruce@momjian.us          419                 :           1348 :             return true;        /* abort the tree traversal and return true */
 9698 tgl@sss.pgh.pa.us         420                 :UBC           0 :         return false;
                                421                 :                :     }
 6852 tgl@sss.pgh.pa.us         422         [ -  + ]:CBC       22728 :     if (IsA(node, CurrentOfExpr))
 6852 tgl@sss.pgh.pa.us         423                 :UBC           0 :         return true;
 6354 tgl@sss.pgh.pa.us         424         [ +  + ]:CBC       22728 :     if (IsA(node, PlaceHolderVar))
                                425                 :                :     {
                                426         [ +  - ]:              6 :         if (((PlaceHolderVar *) node)->phlevelsup == 0)
                                427                 :              6 :             return true;        /* abort the tree traversal and return true */
                                428                 :                :         /* else fall through to check the contained expr */
                                429                 :                :     }
 9766                           430                 :          22722 :     return expression_tree_walker(node, contain_var_clause_walker, context);
                                431                 :                : }
                                432                 :                : 
                                433                 :                : 
                                434                 :                : /*
                                435                 :                :  * contain_vars_of_level
                                436                 :                :  *    Recursively scan a clause to discover whether it contains any Var nodes
                                437                 :                :  *    of the specified query level.
                                438                 :                :  *
                                439                 :                :  *    Returns true if any such Var found.
                                440                 :                :  *
                                441                 :                :  * Will recurse into sublinks.  Also, may be invoked directly on a Query.
                                442                 :                :  */
                                443                 :                : bool
 8455                           444                 :          93376 : contain_vars_of_level(Node *node, int levelsup)
                                445                 :                : {
 8259 bruce@momjian.us          446                 :          93376 :     int         sublevels_up = levelsup;
                                447                 :                : 
 8455 tgl@sss.pgh.pa.us         448                 :          93376 :     return query_or_expression_tree_walker(node,
                                449                 :                :                                            contain_vars_of_level_walker,
                                450                 :                :                                            &sublevels_up,
                                451                 :                :                                            0);
                                452                 :                : }
                                453                 :                : 
                                454                 :                : static bool
                                455                 :         333265 : contain_vars_of_level_walker(Node *node, int *sublevels_up)
                                456                 :                : {
                                457         [ +  + ]:         333265 :     if (node == NULL)
                                458                 :          74804 :         return false;
                                459         [ +  + ]:         258461 :     if (IsA(node, Var))
                                460                 :                :     {
                                461         [ +  + ]:          39552 :         if (((Var *) node)->varlevelsup == *sublevels_up)
                                462                 :          23880 :             return true;        /* abort tree traversal and return true */
 6852                           463                 :          15672 :         return false;
                                464                 :                :     }
                                465         [ +  + ]:         218909 :     if (IsA(node, CurrentOfExpr))
                                466                 :                :     {
                                467         [ +  - ]:             92 :         if (*sublevels_up == 0)
                                468                 :             92 :             return true;
 6852 tgl@sss.pgh.pa.us         469                 :UBC           0 :         return false;
                                470                 :                :     }
 6354 tgl@sss.pgh.pa.us         471         [ +  + ]:CBC      218817 :     if (IsA(node, PlaceHolderVar))
                                472                 :                :     {
                                473         [ +  + ]:             42 :         if (((PlaceHolderVar *) node)->phlevelsup == *sublevels_up)
                                474                 :             39 :             return true;        /* abort the tree traversal and return true */
                                475                 :                :         /* else fall through to check the contained expr */
                                476                 :                :     }
 8455                           477         [ +  + ]:         218778 :     if (IsA(node, Query))
                                478                 :                :     {
                                479                 :                :         /* Recurse into subselects */
                                480                 :                :         bool        result;
                                481                 :                : 
                                482                 :            414 :         (*sublevels_up)++;
                                483                 :            414 :         result = query_tree_walker((Query *) node,
                                484                 :                :                                    contain_vars_of_level_walker,
                                485                 :                :                                    sublevels_up,
                                486                 :                :                                    0);
                                487                 :            414 :         (*sublevels_up)--;
                                488                 :            414 :         return result;
                                489                 :                :     }
                                490                 :         218364 :     return expression_tree_walker(node,
                                491                 :                :                                   contain_vars_of_level_walker,
                                492                 :                :                                   sublevels_up);
                                493                 :                : }
                                494                 :                : 
                                495                 :                : 
                                496                 :                : /*
                                497                 :                :  * contain_vars_returning_old_or_new
                                498                 :                :  *    Recursively scan a clause to discover whether it contains any Var nodes
                                499                 :                :  *    (of the current query level) whose varreturningtype is VAR_RETURNING_OLD
                                500                 :                :  *    or VAR_RETURNING_NEW.
                                501                 :                :  *
                                502                 :                :  *    Returns true if any found.
                                503                 :                :  *
                                504                 :                :  * Any ReturningExprs are also detected --- if an OLD/NEW Var was rewritten,
                                505                 :                :  * we still regard this as a clause that returns OLD/NEW values.
                                506                 :                :  *
                                507                 :                :  * Does not examine subqueries, therefore must only be used after reduction
                                508                 :                :  * of sublinks to subplans!
                                509                 :                :  */
                                510                 :                : bool
  423 dean.a.rasheed@gmail      511                 :            202 : contain_vars_returning_old_or_new(Node *node)
                                512                 :                : {
                                513                 :            202 :     return contain_vars_returning_old_or_new_walker(node, NULL);
                                514                 :                : }
                                515                 :                : 
                                516                 :                : static bool
                                517                 :            614 : contain_vars_returning_old_or_new_walker(Node *node, void *context)
                                518                 :                : {
                                519         [ +  + ]:            614 :     if (node == NULL)
                                520                 :            144 :         return false;
                                521         [ +  + ]:            470 :     if (IsA(node, Var))
                                522                 :                :     {
                                523         [ +  - ]:            201 :         if (((Var *) node)->varlevelsup == 0 &&
                                524         [ +  + ]:            201 :             ((Var *) node)->varreturningtype != VAR_RETURNING_DEFAULT)
                                525                 :              7 :             return true;        /* abort the tree traversal and return true */
                                526                 :            194 :         return false;
                                527                 :                :     }
                                528         [ -  + ]:            269 :     if (IsA(node, ReturningExpr))
                                529                 :                :     {
  423 dean.a.rasheed@gmail      530         [ #  # ]:UBC           0 :         if (((ReturningExpr *) node)->retlevelsup == 0)
                                531                 :              0 :             return true;        /* abort the tree traversal and return true */
                                532                 :              0 :         return false;
                                533                 :                :     }
  423 dean.a.rasheed@gmail      534                 :CBC         269 :     return expression_tree_walker(node, contain_vars_returning_old_or_new_walker,
                                535                 :                :                                   context);
                                536                 :                : }
                                537                 :                : 
                                538                 :                : 
                                539                 :                : /*
                                540                 :                :  * locate_var_of_level
                                541                 :                :  *    Find the parse location of any Var of the specified query level.
                                542                 :                :  *
                                543                 :                :  * Returns -1 if no such Var is in the querytree, or if they all have
                                544                 :                :  * unknown parse location.  (The former case is probably caller error,
                                545                 :                :  * but we don't bother to distinguish it from the latter case.)
                                546                 :                :  *
                                547                 :                :  * Will recurse into sublinks.  Also, may be invoked directly on a Query.
                                548                 :                :  *
                                549                 :                :  * Note: it might seem appropriate to merge this functionality into
                                550                 :                :  * contain_vars_of_level, but that would complicate that function's API.
                                551                 :                :  * Currently, the only uses of this function are for error reporting,
                                552                 :                :  * and so shaving cycles probably isn't very important.
                                553                 :                :  */
                                554                 :                : int
 6404 tgl@sss.pgh.pa.us         555                 :              6 : locate_var_of_level(Node *node, int levelsup)
                                556                 :                : {
                                557                 :                :     locate_var_of_level_context context;
                                558                 :                : 
 6121 bruce@momjian.us          559                 :              6 :     context.var_location = -1;  /* in case we find nothing */
 6404 tgl@sss.pgh.pa.us         560                 :              6 :     context.sublevels_up = levelsup;
                                561                 :                : 
                                562                 :              6 :     (void) query_or_expression_tree_walker(node,
                                563                 :                :                                            locate_var_of_level_walker,
                                564                 :                :                                            &context,
                                565                 :                :                                            0);
                                566                 :                : 
                                567                 :              6 :     return context.var_location;
                                568                 :                : }
                                569                 :                : 
                                570                 :                : static bool
                                571                 :             15 : locate_var_of_level_walker(Node *node,
                                572                 :                :                            locate_var_of_level_context *context)
                                573                 :                : {
 8455                           574         [ -  + ]:             15 :     if (node == NULL)
 8455 tgl@sss.pgh.pa.us         575                 :UBC           0 :         return false;
 8455 tgl@sss.pgh.pa.us         576         [ +  + ]:CBC          15 :     if (IsA(node, Var))
                                577                 :                :     {
 6121 bruce@momjian.us          578                 :              6 :         Var        *var = (Var *) node;
                                579                 :                : 
 6404 tgl@sss.pgh.pa.us         580         [ +  - ]:              6 :         if (var->varlevelsup == context->sublevels_up &&
                                581         [ +  - ]:              6 :             var->location >= 0)
                                582                 :                :         {
                                583                 :              6 :             context->var_location = var->location;
 8455                           584                 :              6 :             return true;        /* abort tree traversal and return true */
                                585                 :                :         }
 6404 tgl@sss.pgh.pa.us         586                 :UBC           0 :         return false;
                                587                 :                :     }
 6404 tgl@sss.pgh.pa.us         588         [ -  + ]:CBC           9 :     if (IsA(node, CurrentOfExpr))
                                589                 :                :     {
                                590                 :                :         /* since CurrentOfExpr doesn't carry location, nothing we can do */
 6404 tgl@sss.pgh.pa.us         591                 :UBC           0 :         return false;
                                592                 :                :     }
                                593                 :                :     /* No extra code needed for PlaceHolderVar; just look in contained expr */
 8455 tgl@sss.pgh.pa.us         594         [ -  + ]:CBC           9 :     if (IsA(node, Query))
                                595                 :                :     {
                                596                 :                :         /* Recurse into subselects */
                                597                 :                :         bool        result;
                                598                 :                : 
 6404 tgl@sss.pgh.pa.us         599                 :UBC           0 :         context->sublevels_up++;
 8455                           600                 :              0 :         result = query_tree_walker((Query *) node,
                                601                 :                :                                    locate_var_of_level_walker,
                                602                 :                :                                    context,
                                603                 :                :                                    0);
 6404                           604                 :              0 :         context->sublevels_up--;
 8455                           605                 :              0 :         return result;
                                606                 :                :     }
 8455 tgl@sss.pgh.pa.us         607                 :CBC           9 :     return expression_tree_walker(node,
                                608                 :                :                                   locate_var_of_level_walker,
                                609                 :                :                                   context);
                                610                 :                : }
                                611                 :                : 
                                612                 :                : 
                                613                 :                : /*
                                614                 :                :  * pull_var_clause
                                615                 :                :  *    Recursively pulls all Var nodes from an expression clause.
                                616                 :                :  *
                                617                 :                :  *    Aggrefs are handled according to these bits in 'flags':
                                618                 :                :  *      PVC_INCLUDE_AGGREGATES      include Aggrefs in output list
                                619                 :                :  *      PVC_RECURSE_AGGREGATES      recurse into Aggref arguments
                                620                 :                :  *      neither flag                throw error if Aggref found
                                621                 :                :  *    Vars within an Aggref's expression are included in the result only
                                622                 :                :  *    when PVC_RECURSE_AGGREGATES is specified.
                                623                 :                :  *
                                624                 :                :  *    WindowFuncs are handled according to these bits in 'flags':
                                625                 :                :  *      PVC_INCLUDE_WINDOWFUNCS     include WindowFuncs in output list
                                626                 :                :  *      PVC_RECURSE_WINDOWFUNCS     recurse into WindowFunc arguments
                                627                 :                :  *      neither flag                throw error if WindowFunc found
                                628                 :                :  *    Vars within a WindowFunc's expression are included in the result only
                                629                 :                :  *    when PVC_RECURSE_WINDOWFUNCS is specified.
                                630                 :                :  *
                                631                 :                :  *    PlaceHolderVars are handled according to these bits in 'flags':
                                632                 :                :  *      PVC_INCLUDE_PLACEHOLDERS    include PlaceHolderVars in output list
                                633                 :                :  *      PVC_RECURSE_PLACEHOLDERS    recurse into PlaceHolderVar arguments
                                634                 :                :  *      neither flag                throw error if PlaceHolderVar found
                                635                 :                :  *    Vars within a PHV's expression are included in the result only
                                636                 :                :  *    when PVC_RECURSE_PLACEHOLDERS is specified.
                                637                 :                :  *
                                638                 :                :  *    GroupingFuncs are treated exactly like Aggrefs, and so do not need
                                639                 :                :  *    their own flag bits.
                                640                 :                :  *
                                641                 :                :  *    CurrentOfExpr nodes are ignored in all cases.
                                642                 :                :  *
                                643                 :                :  *    Upper-level vars (with varlevelsup > 0) should not be seen here,
                                644                 :                :  *    likewise for upper-level Aggrefs and PlaceHolderVars.
                                645                 :                :  *
                                646                 :                :  *    Returns list of nodes found.  Note the nodes themselves are not
                                647                 :                :  *    copied, only referenced.
                                648                 :                :  *
                                649                 :                :  * Does not examine subqueries, therefore must only be used after reduction
                                650                 :                :  * of sublinks to subplans!
                                651                 :                :  */
                                652                 :                : List *
 3657                           653                 :         474319 : pull_var_clause(Node *node, int flags)
                                654                 :                : {
                                655                 :                :     pull_var_clause_context context;
                                656                 :                : 
                                657                 :                :     /* Assert that caller has not specified inconsistent flags */
                                658         [ -  + ]:         474319 :     Assert((flags & (PVC_INCLUDE_AGGREGATES | PVC_RECURSE_AGGREGATES))
                                659                 :                :            != (PVC_INCLUDE_AGGREGATES | PVC_RECURSE_AGGREGATES));
                                660         [ -  + ]:         474319 :     Assert((flags & (PVC_INCLUDE_WINDOWFUNCS | PVC_RECURSE_WINDOWFUNCS))
                                661                 :                :            != (PVC_INCLUDE_WINDOWFUNCS | PVC_RECURSE_WINDOWFUNCS));
                                662         [ -  + ]:         474319 :     Assert((flags & (PVC_INCLUDE_PLACEHOLDERS | PVC_RECURSE_PLACEHOLDERS))
                                663                 :                :            != (PVC_INCLUDE_PLACEHOLDERS | PVC_RECURSE_PLACEHOLDERS));
                                664                 :                : 
 7957                           665                 :         474319 :     context.varlist = NIL;
 3657                           666                 :         474319 :     context.flags = flags;
                                667                 :                : 
 9097                           668                 :         474319 :     pull_var_clause_walker(node, &context);
 7957                           669                 :         474319 :     return context.varlist;
                                670                 :                : }
                                671                 :                : 
                                672                 :                : static bool
 9698                           673                 :        2786761 : pull_var_clause_walker(Node *node, pull_var_clause_context *context)
                                674                 :                : {
 9766                           675         [ +  + ]:        2786761 :     if (node == NULL)
                                676                 :         111038 :         return false;
                                677         [ +  + ]:        2675723 :     if (IsA(node, Var))
                                678                 :                :     {
 5360                           679         [ -  + ]:        1045958 :         if (((Var *) node)->varlevelsup != 0)
 5360 tgl@sss.pgh.pa.us         680         [ #  # ]:UBC           0 :             elog(ERROR, "Upper-level Var found where not expected");
 5360 tgl@sss.pgh.pa.us         681                 :CBC     1045958 :         context->varlist = lappend(context->varlist, node);
 9766                           682                 :        1045958 :         return false;
                                683                 :                :     }
 5360                           684         [ +  + ]:        1629765 :     else if (IsA(node, Aggref))
                                685                 :                :     {
                                686         [ -  + ]:          58989 :         if (((Aggref *) node)->agglevelsup != 0)
 5360 tgl@sss.pgh.pa.us         687         [ #  # ]:UBC           0 :             elog(ERROR, "Upper-level Aggref found where not expected");
 3657 tgl@sss.pgh.pa.us         688         [ +  + ]:CBC       58989 :         if (context->flags & PVC_INCLUDE_AGGREGATES)
                                689                 :                :         {
                                690                 :           4070 :             context->varlist = lappend(context->varlist, node);
                                691                 :                :             /* we do NOT descend into the contained expression */
                                692                 :           4070 :             return false;
                                693                 :                :         }
                                694         [ -  + ]:          54919 :         else if (context->flags & PVC_RECURSE_AGGREGATES)
                                695                 :                :         {
                                696                 :                :             /* fall through to recurse into the aggregate's arguments */
                                697                 :                :         }
                                698                 :                :         else
 3657 tgl@sss.pgh.pa.us         699         [ #  # ]:UBC           0 :             elog(ERROR, "Aggref found where not expected");
                                700                 :                :     }
 3956 andres@anarazel.de        701         [ +  + ]:CBC     1570776 :     else if (IsA(node, GroupingFunc))
                                702                 :                :     {
                                703         [ -  + ]:            339 :         if (((GroupingFunc *) node)->agglevelsup != 0)
 3956 andres@anarazel.de        704         [ #  # ]:UBC           0 :             elog(ERROR, "Upper-level GROUPING found where not expected");
 3657 tgl@sss.pgh.pa.us         705         [ +  + ]:CBC         339 :         if (context->flags & PVC_INCLUDE_AGGREGATES)
                                706                 :                :         {
                                707                 :              2 :             context->varlist = lappend(context->varlist, node);
                                708                 :                :             /* we do NOT descend into the contained expression */
                                709                 :              2 :             return false;
                                710                 :                :         }
                                711         [ -  + ]:            337 :         else if (context->flags & PVC_RECURSE_AGGREGATES)
                                712                 :                :         {
                                713                 :                :             /* fall through to recurse into the GroupingFunc's arguments */
                                714                 :                :         }
                                715                 :                :         else
 3657 tgl@sss.pgh.pa.us         716         [ #  # ]:UBC           0 :             elog(ERROR, "GROUPING found where not expected");
                                717                 :                :     }
 3657 tgl@sss.pgh.pa.us         718         [ +  + ]:CBC     1570437 :     else if (IsA(node, WindowFunc))
                                719                 :                :     {
                                720                 :                :         /* WindowFuncs have no levelsup field to check ... */
                                721         [ +  + ]:           3839 :         if (context->flags & PVC_INCLUDE_WINDOWFUNCS)
                                722                 :                :         {
                                723                 :             56 :             context->varlist = lappend(context->varlist, node);
                                724                 :                :             /* we do NOT descend into the contained expressions */
                                725                 :             56 :             return false;
                                726                 :                :         }
                                727         [ -  + ]:           3783 :         else if (context->flags & PVC_RECURSE_WINDOWFUNCS)
                                728                 :                :         {
                                729                 :                :             /* fall through to recurse into the windowfunc's arguments */
                                730                 :                :         }
                                731                 :                :         else
 3657 tgl@sss.pgh.pa.us         732         [ #  # ]:UBC           0 :             elog(ERROR, "WindowFunc found where not expected");
                                733                 :                :     }
 5360 tgl@sss.pgh.pa.us         734         [ +  + ]:CBC     1566598 :     else if (IsA(node, PlaceHolderVar))
                                735                 :                :     {
                                736         [ -  + ]:           3509 :         if (((PlaceHolderVar *) node)->phlevelsup != 0)
 5360 tgl@sss.pgh.pa.us         737         [ #  # ]:UBC           0 :             elog(ERROR, "Upper-level PlaceHolderVar found where not expected");
 3657 tgl@sss.pgh.pa.us         738         [ +  + ]:CBC        3509 :         if (context->flags & PVC_INCLUDE_PLACEHOLDERS)
                                739                 :                :         {
                                740                 :           2665 :             context->varlist = lappend(context->varlist, node);
                                741                 :                :             /* we do NOT descend into the contained expression */
                                742                 :           2665 :             return false;
                                743                 :                :         }
                                744         [ -  + ]:            844 :         else if (context->flags & PVC_RECURSE_PLACEHOLDERS)
                                745                 :                :         {
                                746                 :                :             /* fall through to recurse into the placeholder's expression */
                                747                 :                :         }
                                748                 :                :         else
 3657 tgl@sss.pgh.pa.us         749         [ #  # ]:UBC           0 :             elog(ERROR, "PlaceHolderVar found where not expected");
                                750                 :                :     }
  472 peter@eisentraut.org      751                 :CBC     1622972 :     return expression_tree_walker(node, pull_var_clause_walker, context);
                                752                 :                : }
                                753                 :                : 
                                754                 :                : 
                                755                 :                : /*
                                756                 :                :  * flatten_join_alias_vars
                                757                 :                :  *    Replace Vars that reference JOIN outputs with references to the original
                                758                 :                :  *    relation variables instead.  This allows quals involving such vars to be
                                759                 :                :  *    pushed down.  Whole-row Vars that reference JOIN relations are expanded
                                760                 :                :  *    into RowExpr constructs that name the individual output Vars.  This
                                761                 :                :  *    is necessary since we will not scan the JOIN as a base relation, which
                                762                 :                :  *    is the only way that the executor can directly handle whole-row Vars.
                                763                 :                :  *
                                764                 :                :  * This also adjusts relid sets found in some expression node types to
                                765                 :                :  * substitute the contained base+OJ rels for any join relid.
                                766                 :                :  *
                                767                 :                :  * If a JOIN contains sub-selects that have been flattened, its join alias
                                768                 :                :  * entries might now be arbitrary expressions, not just Vars.  This affects
                                769                 :                :  * this function in two important ways.  First, we might find ourselves
                                770                 :                :  * inserting SubLink expressions into subqueries, and we must make sure that
                                771                 :                :  * their Query.hasSubLinks fields get set to true if so.  If there are any
                                772                 :                :  * SubLinks in the join alias lists, the outer Query should already have
                                773                 :                :  * hasSubLinks = true, so this is only relevant to un-flattened subqueries.
                                774                 :                :  * Second, we have to preserve any varnullingrels info attached to the
                                775                 :                :  * alias Vars we're replacing.  If the replacement expression is a Var or
                                776                 :                :  * PlaceHolderVar or constructed from those, we can just add the
                                777                 :                :  * varnullingrels bits to the existing nullingrels field(s); otherwise
                                778                 :                :  * we have to add a PlaceHolderVar wrapper.
                                779                 :                :  */
                                780                 :                : Node *
 1140 tgl@sss.pgh.pa.us         781                 :         143181 : flatten_join_alias_vars(PlannerInfo *root, Query *query, Node *node)
                                782                 :                : {
                                783                 :                :     flatten_join_alias_vars_context context;
                                784                 :                : 
                                785                 :                :     /*
                                786                 :                :      * We do not expect this to be applied to the whole Query, only to
                                787                 :                :      * expressions or LATERAL subqueries.  Hence, if the top node is a Query,
                                788                 :                :      * it's okay to immediately increment sublevels_up.
                                789                 :                :      */
                                790         [ -  + ]:         143181 :     Assert(node != (Node *) query);
                                791                 :                : 
                                792                 :         143181 :     context.root = root;
 2602                           793                 :         143181 :     context.query = query;
 8460                           794                 :         143181 :     context.sublevels_up = 0;
                                795                 :                :     /* flag whether join aliases could possibly contain SubLinks */
    9                           796                 :         143181 :     context.possible_sublink = query->hasSubLinks;
                                797                 :                :     /* if hasSubLinks is already true, no need to work hard */
                                798                 :         143181 :     context.inserted_sublink = query->hasSubLinks;
                                799                 :                : 
                                800                 :         143181 :     return flatten_join_alias_vars_mutator(node, &context);
                                801                 :                : }
                                802                 :                : 
                                803                 :                : /*
                                804                 :                :  * flatten_join_alias_for_parser
                                805                 :                :  *
                                806                 :                :  * This variant of flatten_join_alias_vars is used by the parser, to expand
                                807                 :                :  * join alias Vars before checking GROUP BY validity.  In that case we lack
                                808                 :                :  * a root structure.  Fortunately, we'd only need the root for making
                                809                 :                :  * PlaceHolderVars.  We can avoid making PlaceHolderVars in the parser's
                                810                 :                :  * usage because it won't be dealing with arbitrary expressions: so long as
                                811                 :                :  * adjust_standard_join_alias_expression can handle everything the parser
                                812                 :                :  * would make as a join alias expression, we're OK.
                                813                 :                :  *
                                814                 :                :  * The "node" might be part of a sub-query of the Query whose join alias
                                815                 :                :  * Vars are to be expanded.  "sublevels_up" indicates how far below the
                                816                 :                :  * given query we are starting.
                                817                 :                :  */
                                818                 :                : Node *
    9 tgl@sss.pgh.pa.us         819                 :GNC        2943 : flatten_join_alias_for_parser(Query *query, Node *node, int sublevels_up)
                                820                 :                : {
                                821                 :                :     flatten_join_alias_vars_context context;
                                822                 :                : 
                                823                 :                :     /*
                                824                 :                :      * We do not expect this to be applied to the whole Query, only to
                                825                 :                :      * expressions or LATERAL subqueries.  Hence, if the top node is a Query,
                                826                 :                :      * it's okay to immediately increment sublevels_up.
                                827                 :                :      */
                                828         [ -  + ]:           2943 :     Assert(node != (Node *) query);
                                829                 :                : 
                                830                 :           2943 :     context.root = NULL;
                                831                 :           2943 :     context.query = query;
                                832                 :           2943 :     context.sublevels_up = sublevels_up;
                                833                 :                :     /* flag whether join aliases could possibly contain SubLinks */
 2602                           834                 :           2943 :     context.possible_sublink = query->hasSubLinks;
                                835                 :                :     /* if hasSubLinks is already true, no need to work hard */
                                836                 :           2943 :     context.inserted_sublink = query->hasSubLinks;
                                837                 :                : 
 8769                           838                 :           2943 :     return flatten_join_alias_vars_mutator(node, &context);
                                839                 :                : }
                                840                 :                : 
                                841                 :                : static Node *
 8769 tgl@sss.pgh.pa.us         842                 :CBC     2119951 : flatten_join_alias_vars_mutator(Node *node,
                                843                 :                :                                 flatten_join_alias_vars_context *context)
                                844                 :                : {
                                845         [ +  + ]:        2119951 :     if (node == NULL)
                                846                 :         179785 :         return NULL;
                                847         [ +  + ]:        1940166 :     if (IsA(node, Var))
                                848                 :                :     {
 8593 bruce@momjian.us          849                 :         583389 :         Var        *var = (Var *) node;
                                850                 :                :         RangeTblEntry *rte;
                                851                 :                :         Node       *newvar;
                                852                 :                : 
                                853                 :                :         /* No change unless Var belongs to a JOIN of the target level */
 8460 tgl@sss.pgh.pa.us         854         [ +  + ]:         583389 :         if (var->varlevelsup != context->sublevels_up)
 8769                           855                 :          32341 :             return node;        /* no need to copy, really */
 2602                           856                 :         551048 :         rte = rt_fetch(var->varno, context->query->rtable);
 8769                           857         [ +  + ]:         551048 :         if (rte->rtekind != RTE_JOIN)
 8722                           858                 :         550697 :             return node;
 7979                           859         [ +  + ]:            351 :         if (var->varattno == InvalidAttrNumber)
                                860                 :                :         {
                                861                 :                :             /* Must expand whole-row reference */
                                862                 :                :             RowExpr    *rowexpr;
 7868 bruce@momjian.us          863                 :              3 :             List       *fields = NIL;
 5143 tgl@sss.pgh.pa.us         864                 :              3 :             List       *colnames = NIL;
                                865                 :                :             ListCell   *lv;
                                866                 :                :             ListCell   *ln;
                                867                 :                : 
                                868         [ -  + ]:              3 :             Assert(list_length(rte->joinaliasvars) == list_length(rte->eref->colnames));
                                869   [ +  -  +  +  :             24 :             forboth(lv, rte->joinaliasvars, ln, rte->eref->colnames)
                                     +  -  +  +  +  
                                        +  +  -  +  
                                                 + ]
                                870                 :                :             {
                                871                 :             21 :                 newvar = (Node *) lfirst(lv);
                                872                 :                :                 /* Ignore dropped columns */
 4618                           873         [ -  + ]:             21 :                 if (newvar == NULL)
 7878 tgl@sss.pgh.pa.us         874                 :UBC           0 :                     continue;
 5248 tgl@sss.pgh.pa.us         875                 :CBC          21 :                 newvar = copyObject(newvar);
                                876                 :                : 
                                877                 :                :                 /*
                                878                 :                :                  * If we are expanding an alias carried down from an upper
                                879                 :                :                  * query, must adjust its varlevelsup fields.
                                880                 :                :                  */
 7979                           881         [ -  + ]:             21 :                 if (context->sublevels_up != 0)
 7979 tgl@sss.pgh.pa.us         882                 :UBC           0 :                     IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
                                883                 :                :                 /* Preserve original Var's location, if possible */
 5248 tgl@sss.pgh.pa.us         884         [ +  - ]:CBC          21 :                 if (IsA(newvar, Var))
                                885                 :             21 :                     ((Var *) newvar)->location = var->location;
                                886                 :                :                 /* Recurse in case join input is itself a join */
                                887                 :                :                 /* (also takes care of setting inserted_sublink if needed) */
 7979                           888                 :             21 :                 newvar = flatten_join_alias_vars_mutator(newvar, context);
                                889                 :             21 :                 fields = lappend(fields, newvar);
                                890                 :                :                 /* We need the names of non-dropped columns, too */
 5143                           891                 :             21 :                 colnames = lappend(colnames, copyObject((Node *) lfirst(ln)));
                                892                 :                :             }
 7979                           893                 :              3 :             rowexpr = makeNode(RowExpr);
                                894                 :              3 :             rowexpr->args = fields;
                                895                 :              3 :             rowexpr->row_typeid = var->vartype;
                                896                 :              3 :             rowexpr->row_format = COERCE_IMPLICIT_CAST;
                                897                 :                :             /* vartype will always be RECORDOID, so we always need colnames */
 5143                           898                 :              3 :             rowexpr->colnames = colnames;
 5248                           899                 :              3 :             rowexpr->location = var->location;
                                900                 :                : 
                                901                 :                :             /* Lastly, add any varnullingrels to the replacement expression */
 1140                           902                 :              3 :             return add_nullingrels_if_needed(context->root, (Node *) rowexpr,
                                903                 :                :                                              var);
                                904                 :                :         }
                                905                 :                : 
                                906                 :                :         /* Expand join alias reference */
 8722                           907         [ -  + ]:            348 :         Assert(var->varattno > 0);
 7959 neilc@samurai.com         908                 :            348 :         newvar = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1);
 4618 tgl@sss.pgh.pa.us         909         [ -  + ]:            348 :         Assert(newvar != NULL);
 5248                           910                 :            348 :         newvar = copyObject(newvar);
                                911                 :                : 
                                912                 :                :         /*
                                913                 :                :          * If we are expanding an alias carried down from an upper query, must
                                914                 :                :          * adjust its varlevelsup fields.
                                915                 :                :          */
 8438                           916         [ +  + ]:            348 :         if (context->sublevels_up != 0)
 8438 tgl@sss.pgh.pa.us         917                 :GBC          21 :             IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
                                918                 :                : 
                                919                 :                :         /* Preserve original Var's location, if possible */
 5248 tgl@sss.pgh.pa.us         920         [ -  + ]:CBC         348 :         if (IsA(newvar, Var))
 5248 tgl@sss.pgh.pa.us         921                 :UBC           0 :             ((Var *) newvar)->location = var->location;
                                922                 :                : 
                                923                 :                :         /* Recurse in case join input is itself a join */
 5729 tgl@sss.pgh.pa.us         924                 :CBC         348 :         newvar = flatten_join_alias_vars_mutator(newvar, context);
                                925                 :                : 
                                926                 :                :         /* Detect if we are adding a sublink to query */
                                927   [ +  +  +  + ]:            348 :         if (context->possible_sublink && !context->inserted_sublink)
 5729 tgl@sss.pgh.pa.us         928                 :GBC          15 :             context->inserted_sublink = checkExprHasSubLink(newvar);
                                929                 :                : 
                                930                 :                :         /* Lastly, add any varnullingrels to the replacement expression */
 1140 tgl@sss.pgh.pa.us         931                 :CBC         348 :         return add_nullingrels_if_needed(context->root, newvar, var);
                                932                 :                :     }
 6354                           933         [ +  + ]:        1356777 :     if (IsA(node, PlaceHolderVar))
                                934                 :                :     {
                                935                 :                :         /* Copy the PlaceHolderVar node with correct mutation of subnodes */
                                936                 :                :         PlaceHolderVar *phv;
                                937                 :                : 
                                938                 :           1148 :         phv = (PlaceHolderVar *) expression_tree_mutator(node,
                                939                 :                :                                                          flatten_join_alias_vars_mutator,
                                940                 :                :                                                          context);
                                941                 :                :         /* now fix PlaceHolderVar's relid sets */
                                942         [ +  + ]:           1148 :         if (phv->phlevelsup == context->sublevels_up)
                                943                 :                :         {
 2602                           944                 :           1100 :             phv->phrels = alias_relid_set(context->query,
                                945                 :                :                                           phv->phrels);
                                946                 :                :             /* we *don't* change phnullingrels */
                                947                 :                :         }
 6354                           948                 :           1148 :         return (Node *) phv;
                                949                 :                :     }
                                950                 :                : 
 8460                           951         [ +  + ]:        1355629 :     if (IsA(node, Query))
                                952                 :                :     {
                                953                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                                954                 :                :         Query      *newnode;
                                955                 :                :         bool        save_inserted_sublink;
                                956                 :                : 
                                957                 :           9608 :         context->sublevels_up++;
 5729                           958                 :           9608 :         save_inserted_sublink = context->inserted_sublink;
                                959                 :           9608 :         context->inserted_sublink = ((Query *) node)->hasSubLinks;
 8458                           960                 :           9608 :         newnode = query_tree_mutator((Query *) node,
                                961                 :                :                                      flatten_join_alias_vars_mutator,
                                962                 :                :                                      context,
                                963                 :                :                                      QTW_IGNORE_JOINALIASES);
 5729                           964                 :           9608 :         newnode->hasSubLinks |= context->inserted_sublink;
                                965                 :           9608 :         context->inserted_sublink = save_inserted_sublink;
 8460                           966                 :           9608 :         context->sublevels_up--;
                                967                 :           9608 :         return (Node *) newnode;
                                968                 :                :     }
                                969                 :                :     /* Already-planned tree not supported */
 6414                           970         [ -  + ]:        1346021 :     Assert(!IsA(node, SubPlan));
  551 rguo@postgresql.org       971         [ -  + ]:        1346021 :     Assert(!IsA(node, AlternativeSubPlan));
                                972                 :                :     /* Shouldn't need to handle these planner auxiliary nodes here */
 6353 tgl@sss.pgh.pa.us         973         [ -  + ]:        1346021 :     Assert(!IsA(node, SpecialJoinInfo));
                                974         [ -  + ]:        1346021 :     Assert(!IsA(node, PlaceHolderInfo));
 5610                           975         [ -  + ]:        1346021 :     Assert(!IsA(node, MinMaxAggInfo));
                                976                 :                : 
  472 peter@eisentraut.org      977                 :        1346021 :     return expression_tree_mutator(node, flatten_join_alias_vars_mutator, context);
                                978                 :                : }
                                979                 :                : 
                                980                 :                : /*
                                981                 :                :  * flatten_group_exprs
                                982                 :                :  *    Replace Vars that reference GROUP outputs with the underlying grouping
                                983                 :                :  *    expressions.
                                984                 :                :  *
                                985                 :                :  * We have to preserve any varnullingrels info attached to the group Vars we're
                                986                 :                :  * replacing.  If the replacement expression is a Var or PlaceHolderVar or
                                987                 :                :  * constructed from those, we can just add the varnullingrels bits to the
                                988                 :                :  * existing nullingrels field(s); otherwise we have to add a PlaceHolderVar
                                989                 :                :  * wrapper.
                                990                 :                :  *
                                991                 :                :  * NOTE: root may be passed as NULL, which is why we have to pass the Query
                                992                 :                :  * separately.  We need the root itself only for preserving varnullingrels.
                                993                 :                :  * Callers can safely pass NULL if preserving varnullingrels is unnecessary for
                                994                 :                :  * their specific use case (e.g., deparsing source text, or scanning for
                                995                 :                :  * volatile functions), or if it is already guaranteed that the query cannot
                                996                 :                :  * contain grouping sets.
                                997                 :                :  */
                                998                 :                : Node *
  551 rguo@postgresql.org       999                 :           5506 : flatten_group_exprs(PlannerInfo *root, Query *query, Node *node)
                               1000                 :                : {
                               1001                 :                :     flatten_join_alias_vars_context context;
                               1002                 :                : 
                               1003                 :                :     /*
                               1004                 :                :      * We do not expect this to be applied to the whole Query, only to
                               1005                 :                :      * expressions or LATERAL subqueries.  Hence, if the top node is a Query,
                               1006                 :                :      * it's okay to immediately increment sublevels_up.
                               1007                 :                :      */
                               1008         [ -  + ]:           5506 :     Assert(node != (Node *) query);
                               1009                 :                : 
                               1010                 :           5506 :     context.root = root;
                               1011                 :           5506 :     context.query = query;
                               1012                 :           5506 :     context.sublevels_up = 0;
                               1013                 :                :     /* flag whether grouping expressions could possibly contain SubLinks */
                               1014                 :           5506 :     context.possible_sublink = query->hasSubLinks;
                               1015                 :                :     /* if hasSubLinks is already true, no need to work hard */
                               1016                 :           5506 :     context.inserted_sublink = query->hasSubLinks;
                               1017                 :                : 
                               1018                 :           5506 :     return flatten_group_exprs_mutator(node, &context);
                               1019                 :                : }
                               1020                 :                : 
                               1021                 :                : static Node *
                               1022                 :          51854 : flatten_group_exprs_mutator(Node *node,
                               1023                 :                :                             flatten_join_alias_vars_context *context)
                               1024                 :                : {
                               1025         [ +  + ]:          51854 :     if (node == NULL)
                               1026                 :           6217 :         return NULL;
                               1027         [ +  + ]:          45637 :     if (IsA(node, Var))
                               1028                 :                :     {
                               1029                 :           8932 :         Var        *var = (Var *) node;
                               1030                 :                :         RangeTblEntry *rte;
                               1031                 :                :         Node       *newvar;
                               1032                 :                : 
                               1033                 :                :         /* No change unless Var belongs to the GROUP of the target level */
                               1034         [ -  + ]:           8932 :         if (var->varlevelsup != context->sublevels_up)
  551 rguo@postgresql.org      1035                 :UBC           0 :             return node;        /* no need to copy, really */
  551 rguo@postgresql.org      1036                 :CBC        8932 :         rte = rt_fetch(var->varno, context->query->rtable);
                               1037         [ +  + ]:           8932 :         if (rte->rtekind != RTE_GROUP)
                               1038                 :            147 :             return node;
                               1039                 :                : 
                               1040                 :                :         /* Expand group exprs reference */
                               1041         [ -  + ]:           8785 :         Assert(var->varattno > 0);
                               1042                 :           8785 :         newvar = (Node *) list_nth(rte->groupexprs, var->varattno - 1);
                               1043         [ -  + ]:           8785 :         Assert(newvar != NULL);
                               1044                 :           8785 :         newvar = copyObject(newvar);
                               1045                 :                : 
                               1046                 :                :         /*
                               1047                 :                :          * If we are expanding an expr carried down from an upper query, must
                               1048                 :                :          * adjust its varlevelsup fields.
                               1049                 :                :          */
                               1050         [ -  + ]:           8785 :         if (context->sublevels_up != 0)
  551 rguo@postgresql.org      1051                 :UBC           0 :             IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
                               1052                 :                : 
                               1053                 :                :         /* Preserve original Var's location, if possible */
  551 rguo@postgresql.org      1054         [ +  + ]:CBC        8785 :         if (IsA(newvar, Var))
                               1055                 :           7482 :             ((Var *) newvar)->location = var->location;
                               1056                 :                : 
                               1057                 :                :         /* Detect if we are adding a sublink to query */
                               1058   [ +  +  -  + ]:           8785 :         if (context->possible_sublink && !context->inserted_sublink)
  551 rguo@postgresql.org      1059                 :UBC           0 :             context->inserted_sublink = checkExprHasSubLink(newvar);
                               1060                 :                : 
                               1061                 :                :         /* Lastly, add any varnullingrels to the replacement expression */
  551 rguo@postgresql.org      1062                 :CBC        8785 :         return mark_nullable_by_grouping(context->root, newvar, var);
                               1063                 :                :     }
                               1064                 :                : 
                               1065         [ +  + ]:          36705 :     if (IsA(node, Aggref))
                               1066                 :                :     {
                               1067                 :           3728 :         Aggref     *agg = (Aggref *) node;
                               1068                 :                : 
                               1069         [ +  - ]:           3728 :         if ((int) agg->agglevelsup == context->sublevels_up)
                               1070                 :                :         {
                               1071                 :                :             /*
                               1072                 :                :              * If we find an aggregate call of the original level, do not
                               1073                 :                :              * recurse into its normal arguments, ORDER BY arguments, or
                               1074                 :                :              * filter; there are no grouped vars there.  But we should check
                               1075                 :                :              * direct arguments as though they weren't in an aggregate.
                               1076                 :                :              */
                               1077                 :           3728 :             agg = copyObject(agg);
                               1078                 :           3728 :             agg->aggdirectargs = (List *)
                               1079                 :           3728 :                 flatten_group_exprs_mutator((Node *) agg->aggdirectargs, context);
                               1080                 :                : 
                               1081                 :           3728 :             return (Node *) agg;
                               1082                 :                :         }
                               1083                 :                : 
                               1084                 :                :         /*
                               1085                 :                :          * We can skip recursing into aggregates of higher levels altogether,
                               1086                 :                :          * since they could not possibly contain Vars of concern to us (see
                               1087                 :                :          * transformAggregateCall).  We do need to look at aggregates of lower
                               1088                 :                :          * levels, however.
                               1089                 :                :          */
  551 rguo@postgresql.org      1090         [ #  # ]:UBC           0 :         if ((int) agg->agglevelsup > context->sublevels_up)
                               1091                 :              0 :             return node;
                               1092                 :                :     }
                               1093                 :                : 
  551 rguo@postgresql.org      1094         [ +  + ]:CBC       32977 :     if (IsA(node, GroupingFunc))
                               1095                 :                :     {
                               1096                 :            188 :         GroupingFunc *grp = (GroupingFunc *) node;
                               1097                 :                : 
                               1098                 :                :         /*
                               1099                 :                :          * If we find a GroupingFunc node of the original or higher level, do
                               1100                 :                :          * not recurse into its arguments; there are no grouped vars there.
                               1101                 :                :          */
                               1102         [ +  - ]:            188 :         if ((int) grp->agglevelsup >= context->sublevels_up)
                               1103                 :            188 :             return node;
                               1104                 :                :     }
                               1105                 :                : 
                               1106         [ -  + ]:          32789 :     if (IsA(node, Query))
                               1107                 :                :     {
                               1108                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                               1109                 :                :         Query      *newnode;
                               1110                 :                :         bool        save_inserted_sublink;
                               1111                 :                : 
  551 rguo@postgresql.org      1112                 :UBC           0 :         context->sublevels_up++;
                               1113                 :              0 :         save_inserted_sublink = context->inserted_sublink;
                               1114                 :              0 :         context->inserted_sublink = ((Query *) node)->hasSubLinks;
                               1115                 :              0 :         newnode = query_tree_mutator((Query *) node,
                               1116                 :                :                                      flatten_group_exprs_mutator,
                               1117                 :                :                                      context,
                               1118                 :                :                                      QTW_IGNORE_GROUPEXPRS);
                               1119                 :              0 :         newnode->hasSubLinks |= context->inserted_sublink;
                               1120                 :              0 :         context->inserted_sublink = save_inserted_sublink;
                               1121                 :              0 :         context->sublevels_up--;
                               1122                 :              0 :         return (Node *) newnode;
                               1123                 :                :     }
                               1124                 :                : 
  551 rguo@postgresql.org      1125                 :CBC       32789 :     return expression_tree_mutator(node, flatten_group_exprs_mutator,
                               1126                 :                :                                    context);
                               1127                 :                : }
                               1128                 :                : 
                               1129                 :                : /*
                               1130                 :                :  * Add oldvar's varnullingrels, if any, to a flattened grouping expression.
                               1131                 :                :  * The newnode has been copied, so we can modify it freely.
                               1132                 :                :  */
                               1133                 :                : static Node *
                               1134                 :           8785 : mark_nullable_by_grouping(PlannerInfo *root, Node *newnode, Var *oldvar)
                               1135                 :                : {
                               1136                 :                :     Relids      relids;
                               1137                 :                : 
                               1138         [ +  + ]:           8785 :     if (root == NULL)
                               1139                 :           3663 :         return newnode;
                               1140         [ +  + ]:           5122 :     if (oldvar->varnullingrels == NULL)
                               1141                 :           4100 :         return newnode;         /* nothing to do */
                               1142                 :                : 
                               1143         [ -  + ]:           1022 :     Assert(bms_equal(oldvar->varnullingrels,
                               1144                 :                :                      bms_make_singleton(root->group_rtindex)));
                               1145                 :                : 
                               1146                 :           1022 :     relids = pull_varnos_of_level(root, newnode, oldvar->varlevelsup);
                               1147                 :                : 
                               1148         [ +  + ]:           1022 :     if (!bms_is_empty(relids))
                               1149                 :                :     {
                               1150                 :                :         /*
                               1151                 :                :          * If the newnode is not variable-free, we set the nullingrels of Vars
                               1152                 :                :          * or PHVs that are contained in the expression.  This is not really
                               1153                 :                :          * 'correct' in theory, because it is the whole expression that can be
                               1154                 :                :          * nullable by grouping sets, not its individual vars.  But it works
                               1155                 :                :          * in practice, because what we need is that the expression can be
                               1156                 :                :          * somehow distinguished from the same expression in ECs, and marking
                               1157                 :                :          * its vars is sufficient for this purpose.
                               1158                 :                :          */
                               1159                 :            998 :         newnode = add_nulling_relids(newnode,
                               1160                 :                :                                      relids,
                               1161                 :            998 :                                      oldvar->varnullingrels);
                               1162                 :                :     }
                               1163                 :                :     else                        /* variable-free? */
                               1164                 :                :     {
                               1165                 :                :         /*
                               1166                 :                :          * If the newnode is variable-free and does not contain volatile
                               1167                 :                :          * functions or set-returning functions, it can be treated as a member
                               1168                 :                :          * of EC that is redundant.  So wrap it in a new PlaceHolderVar to
                               1169                 :                :          * carry the nullingrels.  Otherwise we do not bother to make any
                               1170                 :                :          * changes.
                               1171                 :                :          *
                               1172                 :                :          * Aggregate functions and window functions are not allowed in
                               1173                 :                :          * grouping expressions.
                               1174                 :                :          */
                               1175         [ -  + ]:             24 :         Assert(!contain_agg_clause(newnode));
                               1176         [ -  + ]:             24 :         Assert(!contain_window_function(newnode));
                               1177                 :                : 
                               1178         [ +  - ]:             24 :         if (!contain_volatile_functions(newnode) &&
                               1179         [ +  + ]:             24 :             !expression_returns_set(newnode))
                               1180                 :                :         {
                               1181                 :                :             PlaceHolderVar *newphv;
                               1182                 :                :             Relids      phrels;
                               1183                 :                : 
                               1184                 :             15 :             phrels = get_relids_in_jointree((Node *) root->parse->jointree,
                               1185                 :                :                                             true, false);
                               1186         [ -  + ]:             15 :             Assert(!bms_is_empty(phrels));
                               1187                 :                : 
                               1188                 :             15 :             newphv = make_placeholder_expr(root, (Expr *) newnode, phrels);
                               1189                 :                :             /* newphv has zero phlevelsup and NULL phnullingrels; fix it */
                               1190                 :             15 :             newphv->phlevelsup = oldvar->varlevelsup;
                               1191                 :             15 :             newphv->phnullingrels = bms_copy(oldvar->varnullingrels);
                               1192                 :             15 :             newnode = (Node *) newphv;
                               1193                 :                :         }
                               1194                 :                :     }
                               1195                 :                : 
                               1196                 :           1022 :     return newnode;
                               1197                 :                : }
                               1198                 :                : 
                               1199                 :                : /*
                               1200                 :                :  * Add oldvar's varnullingrels, if any, to a flattened join alias expression.
                               1201                 :                :  * The newnode has been copied, so we can modify it freely.
                               1202                 :                :  */
                               1203                 :                : static Node *
 1140 tgl@sss.pgh.pa.us        1204                 :            351 : add_nullingrels_if_needed(PlannerInfo *root, Node *newnode, Var *oldvar)
                               1205                 :                : {
                               1206         [ +  + ]:            351 :     if (oldvar->varnullingrels == NULL)
                               1207                 :            273 :         return newnode;         /* nothing to do */
                               1208                 :                :     /* If possible, do it by adding to existing nullingrel fields */
                               1209         [ +  + ]:             78 :     if (is_standard_join_alias_expression(newnode, oldvar))
                               1210                 :             72 :         adjust_standard_join_alias_expression(newnode, oldvar);
                               1211         [ +  - ]:              6 :     else if (root)
                               1212                 :                :     {
                               1213                 :                :         /*
                               1214                 :                :          * We can insert a PlaceHolderVar to carry the nullingrels.  However,
                               1215                 :                :          * deciding where to evaluate the PHV is slightly tricky.  We first
                               1216                 :                :          * try to evaluate it at the natural semantic level of the new
                               1217                 :                :          * expression; but if that expression is variable-free, fall back to
                               1218                 :                :          * evaluating it at the join that the oldvar is an alias Var for.
                               1219                 :                :          */
                               1220                 :                :         PlaceHolderVar *newphv;
                               1221                 :              6 :         Index       levelsup = oldvar->varlevelsup;
                               1222                 :              6 :         Relids      phrels = pull_varnos_of_level(root, newnode, levelsup);
                               1223                 :                : 
                               1224         [ +  - ]:              6 :         if (bms_is_empty(phrels))   /* variable-free? */
                               1225                 :                :         {
                               1226         [ -  + ]:              6 :             if (levelsup != 0)  /* this won't work otherwise */
 1140 tgl@sss.pgh.pa.us        1227         [ #  # ]:UBC           0 :                 elog(ERROR, "unsupported join alias expression");
 1140 tgl@sss.pgh.pa.us        1228                 :CBC           6 :             phrels = get_relids_for_join(root->parse, oldvar->varno);
                               1229                 :                :             /* If it's an outer join, eval below not above the join */
                               1230                 :              6 :             phrels = bms_del_member(phrels, oldvar->varno);
                               1231         [ -  + ]:              6 :             Assert(!bms_is_empty(phrels));
                               1232                 :                :         }
                               1233                 :              6 :         newphv = make_placeholder_expr(root, (Expr *) newnode, phrels);
                               1234                 :                :         /* newphv has zero phlevelsup and NULL phnullingrels; fix it */
                               1235                 :              6 :         newphv->phlevelsup = levelsup;
                               1236                 :              6 :         newphv->phnullingrels = bms_copy(oldvar->varnullingrels);
                               1237                 :              6 :         newnode = (Node *) newphv;
                               1238                 :                :     }
                               1239                 :                :     else
                               1240                 :                :     {
                               1241                 :                :         /* ooops, we're missing support for something the parser can make */
 1140 tgl@sss.pgh.pa.us        1242         [ #  # ]:UBC           0 :         elog(ERROR, "unsupported join alias expression");
                               1243                 :                :     }
 1140 tgl@sss.pgh.pa.us        1244                 :CBC          78 :     return newnode;
                               1245                 :                : }
                               1246                 :                : 
                               1247                 :                : /*
                               1248                 :                :  * Check to see if we can insert nullingrels into this join alias expression
                               1249                 :                :  * without use of a separate PlaceHolderVar.
                               1250                 :                :  *
                               1251                 :                :  * This will handle Vars, PlaceHolderVars, and implicit-coercion and COALESCE
                               1252                 :                :  * expressions built from those.  This coverage needs to handle anything
                               1253                 :                :  * that the parser would put into joinaliasvars.
                               1254                 :                :  */
                               1255                 :                : static bool
                               1256                 :            234 : is_standard_join_alias_expression(Node *newnode, Var *oldvar)
                               1257                 :                : {
                               1258         [ -  + ]:            234 :     if (newnode == NULL)
 1140 tgl@sss.pgh.pa.us        1259                 :UBC           0 :         return false;
 1140 tgl@sss.pgh.pa.us        1260         [ +  + ]:CBC         234 :     if (IsA(newnode, Var) &&
                               1261         [ +  - ]:            138 :         ((Var *) newnode)->varlevelsup == oldvar->varlevelsup)
                               1262                 :            138 :         return true;
                               1263         [ -  + ]:             96 :     else if (IsA(newnode, PlaceHolderVar) &&
 1140 tgl@sss.pgh.pa.us        1264         [ #  # ]:UBC           0 :              ((PlaceHolderVar *) newnode)->phlevelsup == oldvar->varlevelsup)
                               1265                 :              0 :         return true;
 1140 tgl@sss.pgh.pa.us        1266         [ +  + ]:CBC          96 :     else if (IsA(newnode, FuncExpr))
                               1267                 :                :     {
                               1268                 :             15 :         FuncExpr   *fexpr = (FuncExpr *) newnode;
                               1269                 :                : 
                               1270                 :                :         /*
                               1271                 :                :          * We need to assume that the function wouldn't produce non-NULL from
                               1272                 :                :          * NULL, which is reasonable for implicit coercions but otherwise not
                               1273                 :                :          * so much.  (Looking at its strictness is likely overkill, and anyway
                               1274                 :                :          * it would cause us to fail if someone forgot to mark an implicit
                               1275                 :                :          * coercion as strict.)
                               1276                 :                :          */
                               1277         [ +  - ]:             15 :         if (fexpr->funcformat != COERCE_IMPLICIT_CAST ||
                               1278         [ -  + ]:             15 :             fexpr->args == NIL)
 1140 tgl@sss.pgh.pa.us        1279                 :UBC           0 :             return false;
                               1280                 :                : 
                               1281                 :                :         /*
                               1282                 :                :          * Examine only the first argument --- coercions might have additional
                               1283                 :                :          * arguments that are constants.
                               1284                 :                :          */
 1140 tgl@sss.pgh.pa.us        1285                 :CBC          15 :         return is_standard_join_alias_expression(linitial(fexpr->args), oldvar);
                               1286                 :                :     }
                               1287         [ +  + ]:             81 :     else if (IsA(newnode, RelabelType))
                               1288                 :                :     {
                               1289                 :              9 :         RelabelType *relabel = (RelabelType *) newnode;
                               1290                 :                : 
                               1291                 :                :         /* This definitely won't produce non-NULL from NULL */
                               1292                 :              9 :         return is_standard_join_alias_expression((Node *) relabel->arg, oldvar);
                               1293                 :                :     }
                               1294         [ -  + ]:             72 :     else if (IsA(newnode, CoerceViaIO))
                               1295                 :                :     {
 1140 tgl@sss.pgh.pa.us        1296                 :UBC           0 :         CoerceViaIO *iocoerce = (CoerceViaIO *) newnode;
                               1297                 :                : 
                               1298                 :                :         /* This definitely won't produce non-NULL from NULL */
                               1299                 :              0 :         return is_standard_join_alias_expression((Node *) iocoerce->arg, oldvar);
                               1300                 :                :     }
 1140 tgl@sss.pgh.pa.us        1301         [ -  + ]:CBC          72 :     else if (IsA(newnode, ArrayCoerceExpr))
                               1302                 :                :     {
 1140 tgl@sss.pgh.pa.us        1303                 :UBC           0 :         ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) newnode;
                               1304                 :                : 
                               1305                 :                :         /* This definitely won't produce non-NULL from NULL (at array level) */
                               1306                 :              0 :         return is_standard_join_alias_expression((Node *) acoerce->arg, oldvar);
                               1307                 :                :     }
 1140 tgl@sss.pgh.pa.us        1308         [ +  + ]:CBC          72 :     else if (IsA(newnode, CoalesceExpr))
                               1309                 :                :     {
                               1310                 :             66 :         CoalesceExpr *cexpr = (CoalesceExpr *) newnode;
                               1311                 :                :         ListCell   *lc;
                               1312                 :                : 
                               1313         [ -  + ]:             66 :         Assert(cexpr->args != NIL);
                               1314   [ +  -  +  +  :            198 :         foreach(lc, cexpr->args)
                                              +  + ]
                               1315                 :                :         {
                               1316         [ -  + ]:            132 :             if (!is_standard_join_alias_expression(lfirst(lc), oldvar))
 1140 tgl@sss.pgh.pa.us        1317                 :UBC           0 :                 return false;
                               1318                 :                :         }
 1140 tgl@sss.pgh.pa.us        1319                 :CBC          66 :         return true;
                               1320                 :                :     }
                               1321                 :                :     else
                               1322                 :              6 :         return false;
                               1323                 :                : }
                               1324                 :                : 
                               1325                 :                : /*
                               1326                 :                :  * Insert nullingrels into an expression accepted by
                               1327                 :                :  * is_standard_join_alias_expression.
                               1328                 :                :  */
                               1329                 :                : static void
                               1330                 :            222 : adjust_standard_join_alias_expression(Node *newnode, Var *oldvar)
                               1331                 :                : {
                               1332         [ +  + ]:            222 :     if (IsA(newnode, Var) &&
                               1333         [ +  - ]:            138 :         ((Var *) newnode)->varlevelsup == oldvar->varlevelsup)
                               1334                 :            138 :     {
                               1335                 :            138 :         Var        *newvar = (Var *) newnode;
                               1336                 :                : 
                               1337                 :            138 :         newvar->varnullingrels = bms_add_members(newvar->varnullingrels,
                               1338                 :            138 :                                                  oldvar->varnullingrels);
                               1339                 :                :     }
                               1340         [ -  + ]:             84 :     else if (IsA(newnode, PlaceHolderVar) &&
 1140 tgl@sss.pgh.pa.us        1341         [ #  # ]:UBC           0 :              ((PlaceHolderVar *) newnode)->phlevelsup == oldvar->varlevelsup)
                               1342                 :              0 :     {
                               1343                 :              0 :         PlaceHolderVar *newphv = (PlaceHolderVar *) newnode;
                               1344                 :                : 
                               1345                 :              0 :         newphv->phnullingrels = bms_add_members(newphv->phnullingrels,
                               1346                 :              0 :                                                 oldvar->varnullingrels);
                               1347                 :                :     }
 1140 tgl@sss.pgh.pa.us        1348         [ +  + ]:CBC          84 :     else if (IsA(newnode, FuncExpr))
                               1349                 :                :     {
                               1350                 :              9 :         FuncExpr   *fexpr = (FuncExpr *) newnode;
                               1351                 :                : 
                               1352                 :              9 :         adjust_standard_join_alias_expression(linitial(fexpr->args), oldvar);
                               1353                 :                :     }
                               1354         [ +  + ]:             75 :     else if (IsA(newnode, RelabelType))
                               1355                 :                :     {
                               1356                 :              9 :         RelabelType *relabel = (RelabelType *) newnode;
                               1357                 :                : 
                               1358                 :              9 :         adjust_standard_join_alias_expression((Node *) relabel->arg, oldvar);
                               1359                 :                :     }
                               1360         [ -  + ]:             66 :     else if (IsA(newnode, CoerceViaIO))
                               1361                 :                :     {
 1140 tgl@sss.pgh.pa.us        1362                 :UBC           0 :         CoerceViaIO *iocoerce = (CoerceViaIO *) newnode;
                               1363                 :                : 
                               1364                 :              0 :         adjust_standard_join_alias_expression((Node *) iocoerce->arg, oldvar);
                               1365                 :                :     }
 1140 tgl@sss.pgh.pa.us        1366         [ -  + ]:CBC          66 :     else if (IsA(newnode, ArrayCoerceExpr))
                               1367                 :                :     {
 1140 tgl@sss.pgh.pa.us        1368                 :UBC           0 :         ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) newnode;
                               1369                 :                : 
                               1370                 :              0 :         adjust_standard_join_alias_expression((Node *) acoerce->arg, oldvar);
                               1371                 :                :     }
 1140 tgl@sss.pgh.pa.us        1372         [ +  - ]:CBC          66 :     else if (IsA(newnode, CoalesceExpr))
                               1373                 :                :     {
                               1374                 :             66 :         CoalesceExpr *cexpr = (CoalesceExpr *) newnode;
                               1375                 :                :         ListCell   *lc;
                               1376                 :                : 
                               1377         [ -  + ]:             66 :         Assert(cexpr->args != NIL);
                               1378   [ +  -  +  +  :            198 :         foreach(lc, cexpr->args)
                                              +  + ]
                               1379                 :                :         {
                               1380                 :            132 :             adjust_standard_join_alias_expression(lfirst(lc), oldvar);
                               1381                 :                :         }
                               1382                 :                :     }
                               1383                 :                :     else
 1140 tgl@sss.pgh.pa.us        1384                 :UBC           0 :         Assert(false);
 1140 tgl@sss.pgh.pa.us        1385                 :CBC         222 : }
                               1386                 :                : 
                               1387                 :                : /*
                               1388                 :                :  * alias_relid_set: in a set of RT indexes, replace joins by their
                               1389                 :                :  * underlying base+OJ relids
                               1390                 :                :  */
                               1391                 :                : static Relids
 2602                          1392                 :           1100 : alias_relid_set(Query *query, Relids relids)
                               1393                 :                : {
 8436                          1394                 :           1100 :     Relids      result = NULL;
                               1395                 :                :     int         rtindex;
                               1396                 :                : 
 4125                          1397                 :           1100 :     rtindex = -1;
                               1398         [ +  + ]:           2694 :     while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
                               1399                 :                :     {
 2602                          1400                 :           1594 :         RangeTblEntry *rte = rt_fetch(rtindex, query->rtable);
                               1401                 :                : 
 8455                          1402         [ +  + ]:           1594 :         if (rte->rtekind == RTE_JOIN)
 2602                          1403                 :            173 :             result = bms_join(result, get_relids_for_join(query, rtindex));
                               1404                 :                :         else
 8436                          1405                 :           1421 :             result = bms_add_member(result, rtindex);
                               1406                 :                :     }
 8455                          1407                 :           1100 :     return result;
                               1408                 :                : }
        

Generated by: LCOV version 2.4-beta