LCOV - differential code coverage report
Current view: top level - src/backend/optimizer/util - var.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 87.0 % 460 400 60 400
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 26 26 26
Baseline: lcov-20250906-005545-baseline Branches: 68.6 % 354 243 111 243
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 85.0 % 20 17 3 17
(360..) days: 87.0 % 440 383 57 383
Function coverage date bins:
(30,360] days: 100.0 % 2 2 2
(360..) days: 100.0 % 24 24 24
Branch coverage date bins:
(30,360] days: 66.7 % 12 8 4 8
(360..) days: 68.7 % 342 235 107 235

 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-2025, 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
 1689 tgl@sss.pgh.pa.us         114                 :CBC     1583388 : pull_varnos(PlannerInfo *root, Node *node)
                                115                 :                : {
                                116                 :                :     pull_varnos_context context;
                                117                 :                : 
 8246                           118                 :        1583388 :     context.varnos = NULL;
 1689                           119                 :        1583388 :     context.root = root;
 9125                           120                 :        1583388 :     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                 :                :      */
 8268                           126                 :        1583388 :     query_or_expression_tree_walker(node,
                                127                 :                :                                     pull_varnos_walker,
                                128                 :                :                                     &context,
                                129                 :                :                                     0);
                                130                 :                : 
 8246                           131                 :        1583388 :     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
 1689                           140                 :           4694 : pull_varnos_of_level(PlannerInfo *root, Node *node, int levelsup)
                                141                 :                : {
                                142                 :                :     pull_varnos_context context;
                                143                 :                : 
 4778                           144                 :           4694 :     context.varnos = NULL;
 1689                           145                 :           4694 :     context.root = root;
 4778                           146                 :           4694 :     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                 :           4694 :     query_or_expression_tree_walker(node,
                                153                 :                :                                     pull_varnos_walker,
                                154                 :                :                                     &context,
                                155                 :                :                                     0);
                                156                 :                : 
                                157                 :           4694 :     return context.varnos;
                                158                 :                : }
                                159                 :                : 
                                160                 :                : static bool
 9125                           161                 :        2773392 : pull_varnos_walker(Node *node, pull_varnos_context *context)
                                162                 :                : {
 9576                           163         [ +  + ]:        2773392 :     if (node == NULL)
                                164                 :         109161 :         return false;
                                165         [ +  + ]:        2664231 :     if (IsA(node, Var))
                                166                 :                :     {
 9278 bruce@momjian.us          167                 :        1296154 :         Var        *var = (Var *) node;
                                168                 :                : 
 8246 tgl@sss.pgh.pa.us         169         [ +  + ]:        1296154 :         if (var->varlevelsup == context->sublevels_up)
                                170                 :                :         {
                                171                 :        1289908 :             context->varnos = bms_add_member(context->varnos, var->varno);
  950                           172                 :        1289908 :             context->varnos = bms_add_members(context->varnos,
                                173                 :        1289908 :                                               var->varnullingrels);
                                174                 :                :         }
 9576                           175                 :        1296154 :         return false;
                                176                 :                :     }
 6662                           177         [ +  + ]:        1368077 :     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                 :                :     }
 6164                           185         [ +  + ]:        1367677 :     if (IsA(node, PlaceHolderVar))
                                186                 :                :     {
                                187                 :           4547 :         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                 :                :          */
 1336                           197         [ +  - ]:           4547 :         if (phv->phlevelsup == context->sublevels_up &&
                                198         [ +  - ]:           4547 :             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                 :                :              */
 1689                           217                 :           4547 :             PlaceHolderInfo *phinfo = NULL;
                                218                 :                : 
                                219         [ +  + ]:           4547 :             if (phv->phlevelsup == 0)
                                220                 :                :             {
 1116                           221         [ +  + ]:           4499 :                 if (phv->phid < context->root->placeholder_array_size)
                                222                 :           3744 :                     phinfo = context->root->placeholder_array[phv->phid];
                                223                 :                :             }
 1450                           224         [ +  + ]:           4547 :             if (phinfo == NULL)
                                225                 :                :             {
                                226                 :                :                 /* No PlaceHolderInfo yet, use phrels */
                                227                 :            809 :                 context->varnos = bms_add_members(context->varnos,
                                228                 :            809 :                                                   phv->phrels);
                                229                 :                :             }
                                230         [ +  + ]:           3738 :             else if (bms_equal(phv->phrels, phinfo->ph_var->phrels))
                                231                 :                :             {
                                232                 :                :                 /* Normal case: use ph_eval_at */
 1689                           233                 :           3244 :                 context->varnos = bms_add_members(context->varnos,
                                234                 :           3244 :                                                   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 ... */
 1450                           243                 :            494 :                 delta = bms_difference(phinfo->ph_var->phrels, phv->phrels);
                                244                 :            494 :                 newevalat = bms_difference(phinfo->ph_eval_at, delta);
                                245                 :                :                 /* ... then if that was in fact part of ph_eval_at ... */
                                246         [ +  + ]:            494 :                 if (!bms_equal(newevalat, phinfo->ph_eval_at))
                                247                 :                :                 {
                                248                 :                :                     /* ... add what was added */
                                249                 :            300 :                     delta = bms_difference(phv->phrels, phinfo->ph_var->phrels);
                                250                 :            300 :                     newevalat = bms_join(newevalat, delta);
                                251                 :                :                 }
                                252                 :            494 :                 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                 :                :              */
  950                           261                 :           9094 :             context->varnos = bms_add_members(context->varnos,
                                262                 :           4547 :                                               phv->phnullingrels);
 1689                           263                 :           4547 :             return false;       /* don't recurse into expression */
                                264                 :                :         }
                                265                 :                :     }
                                266         [ +  + ]:        1363130 :     else if (IsA(node, Query))
                                267                 :                :     {
                                268                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                                269                 :                :         bool        result;
                                270                 :                : 
 9125                           271                 :           3604 :         context->sublevels_up++;
                                272                 :           3604 :         result = query_tree_walker((Query *) node, pull_varnos_walker,
                                273                 :                :                                    context, 0);
                                274                 :           3604 :         context->sublevels_up--;
                                275                 :           3604 :         return result;
                                276                 :                :     }
  282 peter@eisentraut.org      277                 :        1359526 :     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
 5083 tgl@sss.pgh.pa.us         296                 :         908159 : pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
                                297                 :                : {
                                298                 :                :     pull_varattnos_context context;
                                299                 :                : 
                                300                 :         908159 :     context.varattnos = *varattnos;
                                301                 :         908159 :     context.varno = varno;
                                302                 :                : 
                                303                 :         908159 :     (void) pull_varattnos_walker(node, &context);
                                304                 :                : 
                                305                 :         908159 :     *varattnos = context.varattnos;
 6561                           306                 :         908159 : }
                                307                 :                : 
                                308                 :                : static bool
 5083                           309                 :        3092312 : pull_varattnos_walker(Node *node, pull_varattnos_context *context)
                                310                 :                : {
 6561                           311         [ +  + ]:        3092312 :     if (node == NULL)
                                312                 :          38866 :         return false;
                                313         [ +  + ]:        3053446 :     if (IsA(node, Var))
                                314                 :                :     {
                                315                 :        1770252 :         Var        *var = (Var *) node;
                                316                 :                : 
 5083                           317   [ +  +  +  - ]:        1770252 :         if (var->varno == context->varno && var->varlevelsup == 0)
                                318                 :        1770025 :             context->varattnos =
                                319                 :        1770025 :                 bms_add_member(context->varattnos,
 2999                           320                 :        1770025 :                                var->varattno - FirstLowInvalidHeapAttributeNumber);
 6561                           321                 :        1770252 :         return false;
                                322                 :                :     }
                                323                 :                : 
                                324                 :                :     /* Should not find an unplanned subquery */
                                325         [ -  + ]:        1283194 :     Assert(!IsA(node, Query));
                                326                 :                : 
  282 peter@eisentraut.org      327                 :        1283194 :     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 *
 4778 tgl@sss.pgh.pa.us         339                 :           4707 : pull_vars_of_level(Node *node, int levelsup)
                                340                 :                : {
                                341                 :                :     pull_vars_context context;
                                342                 :                : 
                                343                 :           4707 :     context.vars = NIL;
                                344                 :           4707 :     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                 :           4707 :     query_or_expression_tree_walker(node,
                                351                 :                :                                     pull_vars_walker,
                                352                 :                :                                     &context,
                                353                 :                :                                     0);
                                354                 :                : 
                                355                 :           4707 :     return context.vars;
                                356                 :                : }
                                357                 :                : 
                                358                 :                : static bool
                                359                 :          57070 : pull_vars_walker(Node *node, pull_vars_context *context)
                                360                 :                : {
                                361         [ +  + ]:          57070 :     if (node == NULL)
                                362                 :           8128 :         return false;
                                363         [ +  + ]:          48942 :     if (IsA(node, Var))
                                364                 :                :     {
                                365                 :           6954 :         Var        *var = (Var *) node;
                                366                 :                : 
                                367         [ +  + ]:           6954 :         if (var->varlevelsup == context->sublevels_up)
                                368                 :           5051 :             context->vars = lappend(context->vars, var);
                                369                 :           6954 :         return false;
                                370                 :                :     }
 4767                           371         [ +  + ]:          41988 :     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                 :                :     }
 4778                           380         [ +  + ]:          41919 :     if (IsA(node, Query))
                                381                 :                :     {
                                382                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                                383                 :                :         bool        result;
                                384                 :                : 
                                385                 :            174 :         context->sublevels_up++;
                                386                 :            174 :         result = query_tree_walker((Query *) node, pull_vars_walker,
                                387                 :                :                                    context, 0);
                                388                 :            174 :         context->sublevels_up--;
                                389                 :            174 :         return result;
                                390                 :                :     }
  282 peter@eisentraut.org      391                 :          41745 :     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
 8907 tgl@sss.pgh.pa.us         406                 :          20106 : contain_var_clause(Node *node)
                                407                 :                : {
                                408                 :          20106 :     return contain_var_clause_walker(node, NULL);
                                409                 :                : }
                                410                 :                : 
                                411                 :                : static bool
 9576                           412                 :          24187 : contain_var_clause_walker(Node *node, void *context)
                                413                 :                : {
                                414         [ +  + ]:          24187 :     if (node == NULL)
                                415                 :             62 :         return false;
                                416         [ +  + ]:          24125 :     if (IsA(node, Var))
                                417                 :                :     {
 9508                           418         [ +  - ]:           1324 :         if (((Var *) node)->varlevelsup == 0)
 7266 bruce@momjian.us          419                 :           1324 :             return true;        /* abort the tree traversal and return true */
 9508 tgl@sss.pgh.pa.us         420                 :UBC           0 :         return false;
                                421                 :                :     }
 6662 tgl@sss.pgh.pa.us         422         [ -  + ]:CBC       22801 :     if (IsA(node, CurrentOfExpr))
 6662 tgl@sss.pgh.pa.us         423                 :UBC           0 :         return true;
 6164 tgl@sss.pgh.pa.us         424         [ +  + ]:CBC       22801 :     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                 :                :     }
 9576                           430                 :          22795 :     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
 8265                           444                 :          84073 : contain_vars_of_level(Node *node, int levelsup)
                                445                 :                : {
 8069 bruce@momjian.us          446                 :          84073 :     int         sublevels_up = levelsup;
                                447                 :                : 
 8265 tgl@sss.pgh.pa.us         448                 :          84073 :     return query_or_expression_tree_walker(node,
                                449                 :                :                                            contain_vars_of_level_walker,
                                450                 :                :                                            &sublevels_up,
                                451                 :                :                                            0);
                                452                 :                : }
                                453                 :                : 
                                454                 :                : static bool
                                455                 :         283549 : contain_vars_of_level_walker(Node *node, int *sublevels_up)
                                456                 :                : {
                                457         [ +  + ]:         283549 :     if (node == NULL)
                                458                 :          48051 :         return false;
                                459         [ +  + ]:         235498 :     if (IsA(node, Var))
                                460                 :                :     {
                                461         [ +  + ]:          34734 :         if (((Var *) node)->varlevelsup == *sublevels_up)
                                462                 :          21636 :             return true;        /* abort tree traversal and return true */
 6662                           463                 :          13098 :         return false;
                                464                 :                :     }
                                465         [ +  + ]:         200764 :     if (IsA(node, CurrentOfExpr))
                                466                 :                :     {
                                467         [ +  - ]:             92 :         if (*sublevels_up == 0)
                                468                 :             92 :             return true;
 6662 tgl@sss.pgh.pa.us         469                 :UBC           0 :         return false;
                                470                 :                :     }
 6164 tgl@sss.pgh.pa.us         471         [ +  + ]:CBC      200672 :     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                 :                :     }
 8265                           477         [ +  + ]:         200633 :     if (IsA(node, Query))
                                478                 :                :     {
                                479                 :                :         /* Recurse into subselects */
                                480                 :                :         bool        result;
                                481                 :                : 
                                482                 :            406 :         (*sublevels_up)++;
                                483                 :            406 :         result = query_tree_walker((Query *) node,
                                484                 :                :                                    contain_vars_of_level_walker,
                                485                 :                :                                    sublevels_up,
                                486                 :                :                                    0);
                                487                 :            406 :         (*sublevels_up)--;
                                488                 :            406 :         return result;
                                489                 :                :     }
                                490                 :         200227 :     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
  233 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                 :                :     {
  233 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                 :                :     }
  233 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
 6214 tgl@sss.pgh.pa.us         555                 :              6 : locate_var_of_level(Node *node, int levelsup)
                                556                 :                : {
                                557                 :                :     locate_var_of_level_context context;
                                558                 :                : 
 5931 bruce@momjian.us          559                 :              6 :     context.var_location = -1;  /* in case we find nothing */
 6214 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                 :                : {
 8265                           574         [ -  + ]:             15 :     if (node == NULL)
 8265 tgl@sss.pgh.pa.us         575                 :UBC           0 :         return false;
 8265 tgl@sss.pgh.pa.us         576         [ +  + ]:CBC          15 :     if (IsA(node, Var))
                                577                 :                :     {
 5931 bruce@momjian.us          578                 :              6 :         Var        *var = (Var *) node;
                                579                 :                : 
 6214 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;
 8265                           584                 :              6 :             return true;        /* abort tree traversal and return true */
                                585                 :                :         }
 6214 tgl@sss.pgh.pa.us         586                 :UBC           0 :         return false;
                                587                 :                :     }
 6214 tgl@sss.pgh.pa.us         588         [ -  + ]:CBC           9 :     if (IsA(node, CurrentOfExpr))
                                589                 :                :     {
                                590                 :                :         /* since CurrentOfExpr doesn't carry location, nothing we can do */
 6214 tgl@sss.pgh.pa.us         591                 :UBC           0 :         return false;
                                592                 :                :     }
                                593                 :                :     /* No extra code needed for PlaceHolderVar; just look in contained expr */
 8265 tgl@sss.pgh.pa.us         594         [ -  + ]:CBC           9 :     if (IsA(node, Query))
                                595                 :                :     {
                                596                 :                :         /* Recurse into subselects */
                                597                 :                :         bool        result;
                                598                 :                : 
 6214 tgl@sss.pgh.pa.us         599                 :UBC           0 :         context->sublevels_up++;
 8265                           600                 :              0 :         result = query_tree_walker((Query *) node,
                                601                 :                :                                    locate_var_of_level_walker,
                                602                 :                :                                    context,
                                603                 :                :                                    0);
 6214                           604                 :              0 :         context->sublevels_up--;
 8265                           605                 :              0 :         return result;
                                606                 :                :     }
 8265 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 *
 3467                           653                 :         379616 : 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         [ -  + ]:         379616 :     Assert((flags & (PVC_INCLUDE_AGGREGATES | PVC_RECURSE_AGGREGATES))
                                659                 :                :            != (PVC_INCLUDE_AGGREGATES | PVC_RECURSE_AGGREGATES));
                                660         [ -  + ]:         379616 :     Assert((flags & (PVC_INCLUDE_WINDOWFUNCS | PVC_RECURSE_WINDOWFUNCS))
                                661                 :                :            != (PVC_INCLUDE_WINDOWFUNCS | PVC_RECURSE_WINDOWFUNCS));
                                662         [ -  + ]:         379616 :     Assert((flags & (PVC_INCLUDE_PLACEHOLDERS | PVC_RECURSE_PLACEHOLDERS))
                                663                 :                :            != (PVC_INCLUDE_PLACEHOLDERS | PVC_RECURSE_PLACEHOLDERS));
                                664                 :                : 
 7767                           665                 :         379616 :     context.varlist = NIL;
 3467                           666                 :         379616 :     context.flags = flags;
                                667                 :                : 
 8907                           668                 :         379616 :     pull_var_clause_walker(node, &context);
 7767                           669                 :         379616 :     return context.varlist;
                                670                 :                : }
                                671                 :                : 
                                672                 :                : static bool
 9508                           673                 :        2291512 : pull_var_clause_walker(Node *node, pull_var_clause_context *context)
                                674                 :                : {
 9576                           675         [ +  + ]:        2291512 :     if (node == NULL)
                                676                 :          89828 :         return false;
                                677         [ +  + ]:        2201684 :     if (IsA(node, Var))
                                678                 :                :     {
 5170                           679         [ -  + ]:         863162 :         if (((Var *) node)->varlevelsup != 0)
 5170 tgl@sss.pgh.pa.us         680         [ #  # ]:UBC           0 :             elog(ERROR, "Upper-level Var found where not expected");
 5170 tgl@sss.pgh.pa.us         681                 :CBC      863162 :         context->varlist = lappend(context->varlist, node);
 9576                           682                 :         863162 :         return false;
                                683                 :                :     }
 5170                           684         [ +  + ]:        1338522 :     else if (IsA(node, Aggref))
                                685                 :                :     {
                                686         [ -  + ]:          44196 :         if (((Aggref *) node)->agglevelsup != 0)
 5170 tgl@sss.pgh.pa.us         687         [ #  # ]:UBC           0 :             elog(ERROR, "Upper-level Aggref found where not expected");
 3467 tgl@sss.pgh.pa.us         688         [ +  + ]:CBC       44196 :         if (context->flags & PVC_INCLUDE_AGGREGATES)
                                689                 :                :         {
                                690                 :           2404 :             context->varlist = lappend(context->varlist, node);
                                691                 :                :             /* we do NOT descend into the contained expression */
                                692                 :           2404 :             return false;
                                693                 :                :         }
                                694         [ -  + ]:          41792 :         else if (context->flags & PVC_RECURSE_AGGREGATES)
                                695                 :                :         {
                                696                 :                :             /* fall through to recurse into the aggregate's arguments */
                                697                 :                :         }
                                698                 :                :         else
 3467 tgl@sss.pgh.pa.us         699         [ #  # ]:UBC           0 :             elog(ERROR, "Aggref found where not expected");
                                700                 :                :     }
 3766 andres@anarazel.de        701         [ +  + ]:CBC     1294326 :     else if (IsA(node, GroupingFunc))
                                702                 :                :     {
                                703         [ -  + ]:            323 :         if (((GroupingFunc *) node)->agglevelsup != 0)
 3766 andres@anarazel.de        704         [ #  # ]:UBC           0 :             elog(ERROR, "Upper-level GROUPING found where not expected");
 3467 tgl@sss.pgh.pa.us         705         [ +  + ]:CBC         323 :         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         [ -  + ]:            321 :         else if (context->flags & PVC_RECURSE_AGGREGATES)
                                712                 :                :         {
                                713                 :                :             /* fall through to recurse into the GroupingFunc's arguments */
                                714                 :                :         }
                                715                 :                :         else
 3467 tgl@sss.pgh.pa.us         716         [ #  # ]:UBC           0 :             elog(ERROR, "GROUPING found where not expected");
                                717                 :                :     }
 3467 tgl@sss.pgh.pa.us         718         [ +  + ]:CBC     1294003 :     else if (IsA(node, WindowFunc))
                                719                 :                :     {
                                720                 :                :         /* WindowFuncs have no levelsup field to check ... */
                                721         [ +  + ]:           3338 :         if (context->flags & PVC_INCLUDE_WINDOWFUNCS)
                                722                 :                :         {
                                723                 :              6 :             context->varlist = lappend(context->varlist, node);
                                724                 :                :             /* we do NOT descend into the contained expressions */
                                725                 :              6 :             return false;
                                726                 :                :         }
                                727         [ -  + ]:           3332 :         else if (context->flags & PVC_RECURSE_WINDOWFUNCS)
                                728                 :                :         {
                                729                 :                :             /* fall through to recurse into the windowfunc's arguments */
                                730                 :                :         }
                                731                 :                :         else
 3467 tgl@sss.pgh.pa.us         732         [ #  # ]:UBC           0 :             elog(ERROR, "WindowFunc found where not expected");
                                733                 :                :     }
 5170 tgl@sss.pgh.pa.us         734         [ +  + ]:CBC     1290665 :     else if (IsA(node, PlaceHolderVar))
                                735                 :                :     {
                                736         [ -  + ]:           3240 :         if (((PlaceHolderVar *) node)->phlevelsup != 0)
 5170 tgl@sss.pgh.pa.us         737         [ #  # ]:UBC           0 :             elog(ERROR, "Upper-level PlaceHolderVar found where not expected");
 3467 tgl@sss.pgh.pa.us         738         [ +  + ]:CBC        3240 :         if (context->flags & PVC_INCLUDE_PLACEHOLDERS)
                                739                 :                :         {
                                740                 :           2416 :             context->varlist = lappend(context->varlist, node);
                                741                 :                :             /* we do NOT descend into the contained expression */
                                742                 :           2416 :             return false;
                                743                 :                :         }
                                744         [ -  + ]:            824 :         else if (context->flags & PVC_RECURSE_PLACEHOLDERS)
                                745                 :                :         {
                                746                 :                :             /* fall through to recurse into the placeholder's expression */
                                747                 :                :         }
                                748                 :                :         else
 3467 tgl@sss.pgh.pa.us         749         [ #  # ]:UBC           0 :             elog(ERROR, "PlaceHolderVar found where not expected");
                                750                 :                :     }
  282 peter@eisentraut.org      751                 :CBC     1333694 :     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                 :                :  * NOTE: this is also used by the parser, to expand join alias Vars before
                                781                 :                :  * checking GROUP BY validity.  For that use-case, root will be NULL, which
                                782                 :                :  * is why we have to pass the Query separately.  We need the root itself only
                                783                 :                :  * for making PlaceHolderVars.  We can avoid making PlaceHolderVars in the
                                784                 :                :  * parser's usage because it won't be dealing with arbitrary expressions:
                                785                 :                :  * so long as adjust_standard_join_alias_expression can handle everything
                                786                 :                :  * the parser would make as a join alias expression, we're OK.
                                787                 :                :  */
                                788                 :                : Node *
  950 tgl@sss.pgh.pa.us         789                 :         114609 : flatten_join_alias_vars(PlannerInfo *root, Query *query, Node *node)
                                790                 :                : {
                                791                 :                :     flatten_join_alias_vars_context context;
                                792                 :                : 
                                793                 :                :     /*
                                794                 :                :      * We do not expect this to be applied to the whole Query, only to
                                795                 :                :      * expressions or LATERAL subqueries.  Hence, if the top node is a Query,
                                796                 :                :      * it's okay to immediately increment sublevels_up.
                                797                 :                :      */
                                798         [ -  + ]:         114609 :     Assert(node != (Node *) query);
                                799                 :                : 
                                800                 :         114609 :     context.root = root;
 2412                           801                 :         114609 :     context.query = query;
 8270                           802                 :         114609 :     context.sublevels_up = 0;
                                803                 :                :     /* flag whether join aliases could possibly contain SubLinks */
 2412                           804                 :         114609 :     context.possible_sublink = query->hasSubLinks;
                                805                 :                :     /* if hasSubLinks is already true, no need to work hard */
                                806                 :         114609 :     context.inserted_sublink = query->hasSubLinks;
                                807                 :                : 
 8579                           808                 :         114609 :     return flatten_join_alias_vars_mutator(node, &context);
                                809                 :                : }
                                810                 :                : 
                                811                 :                : static Node *
                                812                 :        1618098 : flatten_join_alias_vars_mutator(Node *node,
                                813                 :                :                                 flatten_join_alias_vars_context *context)
                                814                 :                : {
                                815         [ +  + ]:        1618098 :     if (node == NULL)
                                816                 :         145716 :         return NULL;
                                817         [ +  + ]:        1472382 :     if (IsA(node, Var))
                                818                 :                :     {
 8403 bruce@momjian.us          819                 :         446934 :         Var        *var = (Var *) node;
                                820                 :                :         RangeTblEntry *rte;
                                821                 :                :         Node       *newvar;
                                822                 :                : 
                                823                 :                :         /* No change unless Var belongs to a JOIN of the target level */
 8270 tgl@sss.pgh.pa.us         824         [ +  + ]:         446934 :         if (var->varlevelsup != context->sublevels_up)
 8579                           825                 :          26574 :             return node;        /* no need to copy, really */
 2412                           826                 :         420360 :         rte = rt_fetch(var->varno, context->query->rtable);
 8579                           827         [ +  + ]:         420360 :         if (rte->rtekind != RTE_JOIN)
 8532                           828                 :         420117 :             return node;
 7789                           829         [ +  + ]:            243 :         if (var->varattno == InvalidAttrNumber)
                                830                 :                :         {
                                831                 :                :             /* Must expand whole-row reference */
                                832                 :                :             RowExpr    *rowexpr;
 7678 bruce@momjian.us          833                 :              3 :             List       *fields = NIL;
 4953 tgl@sss.pgh.pa.us         834                 :              3 :             List       *colnames = NIL;
                                835                 :                :             ListCell   *lv;
                                836                 :                :             ListCell   *ln;
                                837                 :                : 
                                838         [ -  + ]:              3 :             Assert(list_length(rte->joinaliasvars) == list_length(rte->eref->colnames));
                                839   [ +  -  +  +  :             24 :             forboth(lv, rte->joinaliasvars, ln, rte->eref->colnames)
                                     +  -  +  +  +  
                                        +  +  -  +  
                                                 + ]
                                840                 :                :             {
                                841                 :             21 :                 newvar = (Node *) lfirst(lv);
                                842                 :                :                 /* Ignore dropped columns */
 4428                           843         [ -  + ]:             21 :                 if (newvar == NULL)
 7688 tgl@sss.pgh.pa.us         844                 :UBC           0 :                     continue;
 5058 tgl@sss.pgh.pa.us         845                 :CBC          21 :                 newvar = copyObject(newvar);
                                846                 :                : 
                                847                 :                :                 /*
                                848                 :                :                  * If we are expanding an alias carried down from an upper
                                849                 :                :                  * query, must adjust its varlevelsup fields.
                                850                 :                :                  */
 7789                           851         [ -  + ]:             21 :                 if (context->sublevels_up != 0)
 7789 tgl@sss.pgh.pa.us         852                 :UBC           0 :                     IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
                                853                 :                :                 /* Preserve original Var's location, if possible */
 5058 tgl@sss.pgh.pa.us         854         [ +  - ]:CBC          21 :                 if (IsA(newvar, Var))
                                855                 :             21 :                     ((Var *) newvar)->location = var->location;
                                856                 :                :                 /* Recurse in case join input is itself a join */
                                857                 :                :                 /* (also takes care of setting inserted_sublink if needed) */
 7789                           858                 :             21 :                 newvar = flatten_join_alias_vars_mutator(newvar, context);
                                859                 :             21 :                 fields = lappend(fields, newvar);
                                860                 :                :                 /* We need the names of non-dropped columns, too */
 4953                           861                 :             21 :                 colnames = lappend(colnames, copyObject((Node *) lfirst(ln)));
                                862                 :                :             }
 7789                           863                 :              3 :             rowexpr = makeNode(RowExpr);
                                864                 :              3 :             rowexpr->args = fields;
                                865                 :              3 :             rowexpr->row_typeid = var->vartype;
                                866                 :              3 :             rowexpr->row_format = COERCE_IMPLICIT_CAST;
                                867                 :                :             /* vartype will always be RECORDOID, so we always need colnames */
 4953                           868                 :              3 :             rowexpr->colnames = colnames;
 5058                           869                 :              3 :             rowexpr->location = var->location;
                                870                 :                : 
                                871                 :                :             /* Lastly, add any varnullingrels to the replacement expression */
  950                           872                 :              3 :             return add_nullingrels_if_needed(context->root, (Node *) rowexpr,
                                873                 :                :                                              var);
                                874                 :                :         }
                                875                 :                : 
                                876                 :                :         /* Expand join alias reference */
 8532                           877         [ -  + ]:            240 :         Assert(var->varattno > 0);
 7769 neilc@samurai.com         878                 :            240 :         newvar = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1);
 4428 tgl@sss.pgh.pa.us         879         [ -  + ]:            240 :         Assert(newvar != NULL);
 5058                           880                 :            240 :         newvar = copyObject(newvar);
                                881                 :                : 
                                882                 :                :         /*
                                883                 :                :          * If we are expanding an alias carried down from an upper query, must
                                884                 :                :          * adjust its varlevelsup fields.
                                885                 :                :          */
 8248                           886         [ -  + ]:            240 :         if (context->sublevels_up != 0)
 8248 tgl@sss.pgh.pa.us         887                 :UBC           0 :             IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
                                888                 :                : 
                                889                 :                :         /* Preserve original Var's location, if possible */
 5058 tgl@sss.pgh.pa.us         890         [ -  + ]:CBC         240 :         if (IsA(newvar, Var))
 5058 tgl@sss.pgh.pa.us         891                 :UBC           0 :             ((Var *) newvar)->location = var->location;
                                892                 :                : 
                                893                 :                :         /* Recurse in case join input is itself a join */
 5539 tgl@sss.pgh.pa.us         894                 :CBC         240 :         newvar = flatten_join_alias_vars_mutator(newvar, context);
                                895                 :                : 
                                896                 :                :         /* Detect if we are adding a sublink to query */
                                897   [ -  +  -  - ]:            240 :         if (context->possible_sublink && !context->inserted_sublink)
 5539 tgl@sss.pgh.pa.us         898                 :UBC           0 :             context->inserted_sublink = checkExprHasSubLink(newvar);
                                899                 :                : 
                                900                 :                :         /* Lastly, add any varnullingrels to the replacement expression */
  950 tgl@sss.pgh.pa.us         901                 :CBC         240 :         return add_nullingrels_if_needed(context->root, newvar, var);
                                902                 :                :     }
 6164                           903         [ +  + ]:        1025448 :     if (IsA(node, PlaceHolderVar))
                                904                 :                :     {
                                905                 :                :         /* Copy the PlaceHolderVar node with correct mutation of subnodes */
                                906                 :                :         PlaceHolderVar *phv;
                                907                 :                : 
                                908                 :           1066 :         phv = (PlaceHolderVar *) expression_tree_mutator(node,
                                909                 :                :                                                          flatten_join_alias_vars_mutator,
                                910                 :                :                                                          context);
                                911                 :                :         /* now fix PlaceHolderVar's relid sets */
                                912         [ +  + ]:           1066 :         if (phv->phlevelsup == context->sublevels_up)
                                913                 :                :         {
 2412                           914                 :           1018 :             phv->phrels = alias_relid_set(context->query,
                                915                 :                :                                           phv->phrels);
                                916                 :                :             /* we *don't* change phnullingrels */
                                917                 :                :         }
 6164                           918                 :           1066 :         return (Node *) phv;
                                919                 :                :     }
                                920                 :                : 
 8270                           921         [ +  + ]:        1024382 :     if (IsA(node, Query))
                                922                 :                :     {
                                923                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                                924                 :                :         Query      *newnode;
                                925                 :                :         bool        save_inserted_sublink;
                                926                 :                : 
                                927                 :           8002 :         context->sublevels_up++;
 5539                           928                 :           8002 :         save_inserted_sublink = context->inserted_sublink;
                                929                 :           8002 :         context->inserted_sublink = ((Query *) node)->hasSubLinks;
 8268                           930                 :           8002 :         newnode = query_tree_mutator((Query *) node,
                                931                 :                :                                      flatten_join_alias_vars_mutator,
                                932                 :                :                                      context,
                                933                 :                :                                      QTW_IGNORE_JOINALIASES);
 5539                           934                 :           8002 :         newnode->hasSubLinks |= context->inserted_sublink;
                                935                 :           8002 :         context->inserted_sublink = save_inserted_sublink;
 8270                           936                 :           8002 :         context->sublevels_up--;
                                937                 :           8002 :         return (Node *) newnode;
                                938                 :                :     }
                                939                 :                :     /* Already-planned tree not supported */
 6224                           940         [ -  + ]:        1016380 :     Assert(!IsA(node, SubPlan));
  361 rguo@postgresql.org       941         [ -  + ]:        1016380 :     Assert(!IsA(node, AlternativeSubPlan));
                                942                 :                :     /* Shouldn't need to handle these planner auxiliary nodes here */
 6163 tgl@sss.pgh.pa.us         943         [ -  + ]:        1016380 :     Assert(!IsA(node, SpecialJoinInfo));
                                944         [ -  + ]:        1016380 :     Assert(!IsA(node, PlaceHolderInfo));
 5420                           945         [ -  + ]:        1016380 :     Assert(!IsA(node, MinMaxAggInfo));
                                946                 :                : 
  282 peter@eisentraut.org      947                 :        1016380 :     return expression_tree_mutator(node, flatten_join_alias_vars_mutator, context);
                                948                 :                : }
                                949                 :                : 
                                950                 :                : /*
                                951                 :                :  * flatten_group_exprs
                                952                 :                :  *    Replace Vars that reference GROUP outputs with the underlying grouping
                                953                 :                :  *    expressions.
                                954                 :                :  *
                                955                 :                :  * We have to preserve any varnullingrels info attached to the group Vars we're
                                956                 :                :  * replacing.  If the replacement expression is a Var or PlaceHolderVar or
                                957                 :                :  * constructed from those, we can just add the varnullingrels bits to the
                                958                 :                :  * existing nullingrels field(s); otherwise we have to add a PlaceHolderVar
                                959                 :                :  * wrapper.
                                960                 :                :  *
                                961                 :                :  * NOTE: this is also used by ruleutils.c, to deparse one query parsetree back
                                962                 :                :  * to source text.  For that use-case, root will be NULL, which is why we have
                                963                 :                :  * to pass the Query separately.  We need the root itself only for preserving
                                964                 :                :  * varnullingrels.  We can avoid preserving varnullingrels in the ruleutils.c's
                                965                 :                :  * usage because it does not make any difference to the deparsed source text.
                                966                 :                :  */
                                967                 :                : Node *
  361 rguo@postgresql.org       968                 :           4700 : flatten_group_exprs(PlannerInfo *root, Query *query, Node *node)
                                969                 :                : {
                                970                 :                :     flatten_join_alias_vars_context context;
                                971                 :                : 
                                972                 :                :     /*
                                973                 :                :      * We do not expect this to be applied to the whole Query, only to
                                974                 :                :      * expressions or LATERAL subqueries.  Hence, if the top node is a Query,
                                975                 :                :      * it's okay to immediately increment sublevels_up.
                                976                 :                :      */
                                977         [ -  + ]:           4700 :     Assert(node != (Node *) query);
                                978                 :                : 
                                979                 :           4700 :     context.root = root;
                                980                 :           4700 :     context.query = query;
                                981                 :           4700 :     context.sublevels_up = 0;
                                982                 :                :     /* flag whether grouping expressions could possibly contain SubLinks */
                                983                 :           4700 :     context.possible_sublink = query->hasSubLinks;
                                984                 :                :     /* if hasSubLinks is already true, no need to work hard */
                                985                 :           4700 :     context.inserted_sublink = query->hasSubLinks;
                                986                 :                : 
                                987                 :           4700 :     return flatten_group_exprs_mutator(node, &context);
                                988                 :                : }
                                989                 :                : 
                                990                 :                : static Node *
                                991                 :          31120 : flatten_group_exprs_mutator(Node *node,
                                992                 :                :                             flatten_join_alias_vars_context *context)
                                993                 :                : {
                                994         [ +  + ]:          31120 :     if (node == NULL)
                                995                 :           5293 :         return NULL;
                                996         [ +  + ]:          25827 :     if (IsA(node, Var))
                                997                 :                :     {
                                998                 :           4910 :         Var        *var = (Var *) node;
                                999                 :                :         RangeTblEntry *rte;
                               1000                 :                :         Node       *newvar;
                               1001                 :                : 
                               1002                 :                :         /* No change unless Var belongs to the GROUP of the target level */
                               1003         [ -  + ]:           4910 :         if (var->varlevelsup != context->sublevels_up)
  361 rguo@postgresql.org      1004                 :UBC           0 :             return node;        /* no need to copy, really */
  361 rguo@postgresql.org      1005                 :CBC        4910 :         rte = rt_fetch(var->varno, context->query->rtable);
                               1006         [ +  + ]:           4910 :         if (rte->rtekind != RTE_GROUP)
                               1007                 :            159 :             return node;
                               1008                 :                : 
                               1009                 :                :         /* Expand group exprs reference */
                               1010         [ -  + ]:           4751 :         Assert(var->varattno > 0);
                               1011                 :           4751 :         newvar = (Node *) list_nth(rte->groupexprs, var->varattno - 1);
                               1012         [ -  + ]:           4751 :         Assert(newvar != NULL);
                               1013                 :           4751 :         newvar = copyObject(newvar);
                               1014                 :                : 
                               1015                 :                :         /*
                               1016                 :                :          * If we are expanding an expr carried down from an upper query, must
                               1017                 :                :          * adjust its varlevelsup fields.
                               1018                 :                :          */
                               1019         [ -  + ]:           4751 :         if (context->sublevels_up != 0)
  361 rguo@postgresql.org      1020                 :UBC           0 :             IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
                               1021                 :                : 
                               1022                 :                :         /* Preserve original Var's location, if possible */
  361 rguo@postgresql.org      1023         [ +  + ]:CBC        4751 :         if (IsA(newvar, Var))
                               1024                 :           3613 :             ((Var *) newvar)->location = var->location;
                               1025                 :                : 
                               1026                 :                :         /* Detect if we are adding a sublink to query */
                               1027   [ +  +  -  + ]:           4751 :         if (context->possible_sublink && !context->inserted_sublink)
  361 rguo@postgresql.org      1028                 :UBC           0 :             context->inserted_sublink = checkExprHasSubLink(newvar);
                               1029                 :                : 
                               1030                 :                :         /* Lastly, add any varnullingrels to the replacement expression */
  361 rguo@postgresql.org      1031                 :CBC        4751 :         return mark_nullable_by_grouping(context->root, newvar, var);
                               1032                 :                :     }
                               1033                 :                : 
                               1034         [ +  + ]:          20917 :     if (IsA(node, Aggref))
                               1035                 :                :     {
                               1036                 :           3064 :         Aggref     *agg = (Aggref *) node;
                               1037                 :                : 
                               1038         [ +  - ]:           3064 :         if ((int) agg->agglevelsup == context->sublevels_up)
                               1039                 :                :         {
                               1040                 :                :             /*
                               1041                 :                :              * If we find an aggregate call of the original level, do not
                               1042                 :                :              * recurse into its normal arguments, ORDER BY arguments, or
                               1043                 :                :              * filter; there are no grouped vars there.  But we should check
                               1044                 :                :              * direct arguments as though they weren't in an aggregate.
                               1045                 :                :              */
                               1046                 :           3064 :             agg = copyObject(agg);
                               1047                 :           3064 :             agg->aggdirectargs = (List *)
                               1048                 :           3064 :                 flatten_group_exprs_mutator((Node *) agg->aggdirectargs, context);
                               1049                 :                : 
                               1050                 :           3064 :             return (Node *) agg;
                               1051                 :                :         }
                               1052                 :                : 
                               1053                 :                :         /*
                               1054                 :                :          * We can skip recursing into aggregates of higher levels altogether,
                               1055                 :                :          * since they could not possibly contain Vars of concern to us (see
                               1056                 :                :          * transformAggregateCall).  We do need to look at aggregates of lower
                               1057                 :                :          * levels, however.
                               1058                 :                :          */
  361 rguo@postgresql.org      1059         [ #  # ]:UBC           0 :         if ((int) agg->agglevelsup > context->sublevels_up)
                               1060                 :              0 :             return node;
                               1061                 :                :     }
                               1062                 :                : 
  361 rguo@postgresql.org      1063         [ +  + ]:CBC       17853 :     if (IsA(node, GroupingFunc))
                               1064                 :                :     {
                               1065                 :            178 :         GroupingFunc *grp = (GroupingFunc *) node;
                               1066                 :                : 
                               1067                 :                :         /*
                               1068                 :                :          * If we find a GroupingFunc node of the original or higher level, do
                               1069                 :                :          * not recurse into its arguments; there are no grouped vars there.
                               1070                 :                :          */
                               1071         [ +  - ]:            178 :         if ((int) grp->agglevelsup >= context->sublevels_up)
                               1072                 :            178 :             return node;
                               1073                 :                :     }
                               1074                 :                : 
                               1075         [ -  + ]:          17675 :     if (IsA(node, Query))
                               1076                 :                :     {
                               1077                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                               1078                 :                :         Query      *newnode;
                               1079                 :                :         bool        save_inserted_sublink;
                               1080                 :                : 
  361 rguo@postgresql.org      1081                 :UBC           0 :         context->sublevels_up++;
                               1082                 :              0 :         save_inserted_sublink = context->inserted_sublink;
                               1083                 :              0 :         context->inserted_sublink = ((Query *) node)->hasSubLinks;
                               1084                 :              0 :         newnode = query_tree_mutator((Query *) node,
                               1085                 :                :                                      flatten_group_exprs_mutator,
                               1086                 :                :                                      context,
                               1087                 :                :                                      QTW_IGNORE_GROUPEXPRS);
                               1088                 :              0 :         newnode->hasSubLinks |= context->inserted_sublink;
                               1089                 :              0 :         context->inserted_sublink = save_inserted_sublink;
                               1090                 :              0 :         context->sublevels_up--;
                               1091                 :              0 :         return (Node *) newnode;
                               1092                 :                :     }
                               1093                 :                : 
  361 rguo@postgresql.org      1094                 :CBC       17675 :     return expression_tree_mutator(node, flatten_group_exprs_mutator,
                               1095                 :                :                                    context);
                               1096                 :                : }
                               1097                 :                : 
                               1098                 :                : /*
                               1099                 :                :  * Add oldvar's varnullingrels, if any, to a flattened grouping expression.
                               1100                 :                :  * The newnode has been copied, so we can modify it freely.
                               1101                 :                :  */
                               1102                 :                : static Node *
                               1103                 :           4751 : mark_nullable_by_grouping(PlannerInfo *root, Node *newnode, Var *oldvar)
                               1104                 :                : {
                               1105                 :                :     Relids      relids;
                               1106                 :                : 
                               1107         [ +  + ]:           4751 :     if (root == NULL)
                               1108                 :            355 :         return newnode;
                               1109         [ +  + ]:           4396 :     if (oldvar->varnullingrels == NULL)
                               1110                 :           3493 :         return newnode;         /* nothing to do */
                               1111                 :                : 
                               1112         [ -  + ]:            903 :     Assert(bms_equal(oldvar->varnullingrels,
                               1113                 :                :                      bms_make_singleton(root->group_rtindex)));
                               1114                 :                : 
                               1115                 :            903 :     relids = pull_varnos_of_level(root, newnode, oldvar->varlevelsup);
                               1116                 :                : 
                               1117         [ +  + ]:            903 :     if (!bms_is_empty(relids))
                               1118                 :                :     {
                               1119                 :                :         /*
                               1120                 :                :          * If the newnode is not variable-free, we set the nullingrels of Vars
                               1121                 :                :          * or PHVs that are contained in the expression.  This is not really
                               1122                 :                :          * 'correct' in theory, because it is the whole expression that can be
                               1123                 :                :          * nullable by grouping sets, not its individual vars.  But it works
                               1124                 :                :          * in practice, because what we need is that the expression can be
                               1125                 :                :          * somehow distinguished from the same expression in ECs, and marking
                               1126                 :                :          * its vars is sufficient for this purpose.
                               1127                 :                :          */
                               1128                 :            882 :         newnode = add_nulling_relids(newnode,
                               1129                 :                :                                      relids,
                               1130                 :            882 :                                      oldvar->varnullingrels);
                               1131                 :                :     }
                               1132                 :                :     else                        /* variable-free? */
                               1133                 :                :     {
                               1134                 :                :         /*
                               1135                 :                :          * If the newnode is variable-free and does not contain volatile
                               1136                 :                :          * functions or set-returning functions, it can be treated as a member
                               1137                 :                :          * of EC that is redundant.  So wrap it in a new PlaceHolderVar to
                               1138                 :                :          * carry the nullingrels.  Otherwise we do not bother to make any
                               1139                 :                :          * changes.
                               1140                 :                :          *
                               1141                 :                :          * Aggregate functions and window functions are not allowed in
                               1142                 :                :          * grouping expressions.
                               1143                 :                :          */
                               1144         [ -  + ]:             21 :         Assert(!contain_agg_clause(newnode));
                               1145         [ -  + ]:             21 :         Assert(!contain_window_function(newnode));
                               1146                 :                : 
                               1147         [ +  - ]:             21 :         if (!contain_volatile_functions(newnode) &&
                               1148         [ +  + ]:             21 :             !expression_returns_set(newnode))
                               1149                 :                :         {
                               1150                 :                :             PlaceHolderVar *newphv;
                               1151                 :                :             Relids      phrels;
                               1152                 :                : 
                               1153                 :             12 :             phrels = get_relids_in_jointree((Node *) root->parse->jointree,
                               1154                 :                :                                             true, false);
                               1155         [ -  + ]:             12 :             Assert(!bms_is_empty(phrels));
                               1156                 :                : 
                               1157                 :             12 :             newphv = make_placeholder_expr(root, (Expr *) newnode, phrels);
                               1158                 :                :             /* newphv has zero phlevelsup and NULL phnullingrels; fix it */
                               1159                 :             12 :             newphv->phlevelsup = oldvar->varlevelsup;
                               1160                 :             12 :             newphv->phnullingrels = bms_copy(oldvar->varnullingrels);
                               1161                 :             12 :             newnode = (Node *) newphv;
                               1162                 :                :         }
                               1163                 :                :     }
                               1164                 :                : 
                               1165                 :            903 :     return newnode;
                               1166                 :                : }
                               1167                 :                : 
                               1168                 :                : /*
                               1169                 :                :  * Add oldvar's varnullingrels, if any, to a flattened join alias expression.
                               1170                 :                :  * The newnode has been copied, so we can modify it freely.
                               1171                 :                :  */
                               1172                 :                : static Node *
  950 tgl@sss.pgh.pa.us        1173                 :            243 : add_nullingrels_if_needed(PlannerInfo *root, Node *newnode, Var *oldvar)
                               1174                 :                : {
                               1175         [ +  + ]:            243 :     if (oldvar->varnullingrels == NULL)
                               1176                 :            171 :         return newnode;         /* nothing to do */
                               1177                 :                :     /* If possible, do it by adding to existing nullingrel fields */
                               1178         [ +  + ]:             72 :     if (is_standard_join_alias_expression(newnode, oldvar))
                               1179                 :             66 :         adjust_standard_join_alias_expression(newnode, oldvar);
                               1180         [ +  - ]:              6 :     else if (root)
                               1181                 :                :     {
                               1182                 :                :         /*
                               1183                 :                :          * We can insert a PlaceHolderVar to carry the nullingrels.  However,
                               1184                 :                :          * deciding where to evaluate the PHV is slightly tricky.  We first
                               1185                 :                :          * try to evaluate it at the natural semantic level of the new
                               1186                 :                :          * expression; but if that expression is variable-free, fall back to
                               1187                 :                :          * evaluating it at the join that the oldvar is an alias Var for.
                               1188                 :                :          */
                               1189                 :                :         PlaceHolderVar *newphv;
                               1190                 :              6 :         Index       levelsup = oldvar->varlevelsup;
                               1191                 :              6 :         Relids      phrels = pull_varnos_of_level(root, newnode, levelsup);
                               1192                 :                : 
                               1193         [ +  - ]:              6 :         if (bms_is_empty(phrels))   /* variable-free? */
                               1194                 :                :         {
                               1195         [ -  + ]:              6 :             if (levelsup != 0)  /* this won't work otherwise */
  950 tgl@sss.pgh.pa.us        1196         [ #  # ]:UBC           0 :                 elog(ERROR, "unsupported join alias expression");
  950 tgl@sss.pgh.pa.us        1197                 :CBC           6 :             phrels = get_relids_for_join(root->parse, oldvar->varno);
                               1198                 :                :             /* If it's an outer join, eval below not above the join */
                               1199                 :              6 :             phrels = bms_del_member(phrels, oldvar->varno);
                               1200         [ -  + ]:              6 :             Assert(!bms_is_empty(phrels));
                               1201                 :                :         }
                               1202                 :              6 :         newphv = make_placeholder_expr(root, (Expr *) newnode, phrels);
                               1203                 :                :         /* newphv has zero phlevelsup and NULL phnullingrels; fix it */
                               1204                 :              6 :         newphv->phlevelsup = levelsup;
                               1205                 :              6 :         newphv->phnullingrels = bms_copy(oldvar->varnullingrels);
                               1206                 :              6 :         newnode = (Node *) newphv;
                               1207                 :                :     }
                               1208                 :                :     else
                               1209                 :                :     {
                               1210                 :                :         /* ooops, we're missing support for something the parser can make */
  950 tgl@sss.pgh.pa.us        1211         [ #  # ]:UBC           0 :         elog(ERROR, "unsupported join alias expression");
                               1212                 :                :     }
  950 tgl@sss.pgh.pa.us        1213                 :CBC          72 :     return newnode;
                               1214                 :                : }
                               1215                 :                : 
                               1216                 :                : /*
                               1217                 :                :  * Check to see if we can insert nullingrels into this join alias expression
                               1218                 :                :  * without use of a separate PlaceHolderVar.
                               1219                 :                :  *
                               1220                 :                :  * This will handle Vars, PlaceHolderVars, and implicit-coercion and COALESCE
                               1221                 :                :  * expressions built from those.  This coverage needs to handle anything
                               1222                 :                :  * that the parser would put into joinaliasvars.
                               1223                 :                :  */
                               1224                 :                : static bool
                               1225                 :            222 : is_standard_join_alias_expression(Node *newnode, Var *oldvar)
                               1226                 :                : {
                               1227         [ -  + ]:            222 :     if (newnode == NULL)
  950 tgl@sss.pgh.pa.us        1228                 :UBC           0 :         return false;
  950 tgl@sss.pgh.pa.us        1229         [ +  + ]:CBC         222 :     if (IsA(newnode, Var) &&
                               1230         [ +  - ]:            132 :         ((Var *) newnode)->varlevelsup == oldvar->varlevelsup)
                               1231                 :            132 :         return true;
                               1232         [ -  + ]:             90 :     else if (IsA(newnode, PlaceHolderVar) &&
  950 tgl@sss.pgh.pa.us        1233         [ #  # ]:UBC           0 :              ((PlaceHolderVar *) newnode)->phlevelsup == oldvar->varlevelsup)
                               1234                 :              0 :         return true;
  950 tgl@sss.pgh.pa.us        1235         [ +  + ]:CBC          90 :     else if (IsA(newnode, FuncExpr))
                               1236                 :                :     {
                               1237                 :             12 :         FuncExpr   *fexpr = (FuncExpr *) newnode;
                               1238                 :                : 
                               1239                 :                :         /*
                               1240                 :                :          * We need to assume that the function wouldn't produce non-NULL from
                               1241                 :                :          * NULL, which is reasonable for implicit coercions but otherwise not
                               1242                 :                :          * so much.  (Looking at its strictness is likely overkill, and anyway
                               1243                 :                :          * it would cause us to fail if someone forgot to mark an implicit
                               1244                 :                :          * coercion as strict.)
                               1245                 :                :          */
                               1246         [ +  - ]:             12 :         if (fexpr->funcformat != COERCE_IMPLICIT_CAST ||
                               1247         [ -  + ]:             12 :             fexpr->args == NIL)
  950 tgl@sss.pgh.pa.us        1248                 :UBC           0 :             return false;
                               1249                 :                : 
                               1250                 :                :         /*
                               1251                 :                :          * Examine only the first argument --- coercions might have additional
                               1252                 :                :          * arguments that are constants.
                               1253                 :                :          */
  950 tgl@sss.pgh.pa.us        1254                 :CBC          12 :         return is_standard_join_alias_expression(linitial(fexpr->args), oldvar);
                               1255                 :                :     }
                               1256         [ +  + ]:             78 :     else if (IsA(newnode, RelabelType))
                               1257                 :                :     {
                               1258                 :              6 :         RelabelType *relabel = (RelabelType *) newnode;
                               1259                 :                : 
                               1260                 :                :         /* This definitely won't produce non-NULL from NULL */
                               1261                 :              6 :         return is_standard_join_alias_expression((Node *) relabel->arg, oldvar);
                               1262                 :                :     }
                               1263         [ -  + ]:             72 :     else if (IsA(newnode, CoerceViaIO))
                               1264                 :                :     {
  950 tgl@sss.pgh.pa.us        1265                 :UBC           0 :         CoerceViaIO *iocoerce = (CoerceViaIO *) newnode;
                               1266                 :                : 
                               1267                 :                :         /* This definitely won't produce non-NULL from NULL */
                               1268                 :              0 :         return is_standard_join_alias_expression((Node *) iocoerce->arg, oldvar);
                               1269                 :                :     }
  950 tgl@sss.pgh.pa.us        1270         [ -  + ]:CBC          72 :     else if (IsA(newnode, ArrayCoerceExpr))
                               1271                 :                :     {
  950 tgl@sss.pgh.pa.us        1272                 :UBC           0 :         ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) newnode;
                               1273                 :                : 
                               1274                 :                :         /* This definitely won't produce non-NULL from NULL (at array level) */
                               1275                 :              0 :         return is_standard_join_alias_expression((Node *) acoerce->arg, oldvar);
                               1276                 :                :     }
  950 tgl@sss.pgh.pa.us        1277         [ +  + ]:CBC          72 :     else if (IsA(newnode, CoalesceExpr))
                               1278                 :                :     {
                               1279                 :             66 :         CoalesceExpr *cexpr = (CoalesceExpr *) newnode;
                               1280                 :                :         ListCell   *lc;
                               1281                 :                : 
                               1282         [ -  + ]:             66 :         Assert(cexpr->args != NIL);
                               1283   [ +  -  +  +  :            198 :         foreach(lc, cexpr->args)
                                              +  + ]
                               1284                 :                :         {
                               1285         [ -  + ]:            132 :             if (!is_standard_join_alias_expression(lfirst(lc), oldvar))
  950 tgl@sss.pgh.pa.us        1286                 :UBC           0 :                 return false;
                               1287                 :                :         }
  950 tgl@sss.pgh.pa.us        1288                 :CBC          66 :         return true;
                               1289                 :                :     }
                               1290                 :                :     else
                               1291                 :              6 :         return false;
                               1292                 :                : }
                               1293                 :                : 
                               1294                 :                : /*
                               1295                 :                :  * Insert nullingrels into an expression accepted by
                               1296                 :                :  * is_standard_join_alias_expression.
                               1297                 :                :  */
                               1298                 :                : static void
                               1299                 :            210 : adjust_standard_join_alias_expression(Node *newnode, Var *oldvar)
                               1300                 :                : {
                               1301         [ +  + ]:            210 :     if (IsA(newnode, Var) &&
                               1302         [ +  - ]:            132 :         ((Var *) newnode)->varlevelsup == oldvar->varlevelsup)
                               1303                 :            132 :     {
                               1304                 :            132 :         Var        *newvar = (Var *) newnode;
                               1305                 :                : 
                               1306                 :            132 :         newvar->varnullingrels = bms_add_members(newvar->varnullingrels,
                               1307                 :            132 :                                                  oldvar->varnullingrels);
                               1308                 :                :     }
                               1309         [ -  + ]:             78 :     else if (IsA(newnode, PlaceHolderVar) &&
  950 tgl@sss.pgh.pa.us        1310         [ #  # ]:UBC           0 :              ((PlaceHolderVar *) newnode)->phlevelsup == oldvar->varlevelsup)
                               1311                 :              0 :     {
                               1312                 :              0 :         PlaceHolderVar *newphv = (PlaceHolderVar *) newnode;
                               1313                 :                : 
                               1314                 :              0 :         newphv->phnullingrels = bms_add_members(newphv->phnullingrels,
                               1315                 :              0 :                                                 oldvar->varnullingrels);
                               1316                 :                :     }
  950 tgl@sss.pgh.pa.us        1317         [ +  + ]:CBC          78 :     else if (IsA(newnode, FuncExpr))
                               1318                 :                :     {
                               1319                 :              6 :         FuncExpr   *fexpr = (FuncExpr *) newnode;
                               1320                 :                : 
                               1321                 :              6 :         adjust_standard_join_alias_expression(linitial(fexpr->args), oldvar);
                               1322                 :                :     }
                               1323         [ +  + ]:             72 :     else if (IsA(newnode, RelabelType))
                               1324                 :                :     {
                               1325                 :              6 :         RelabelType *relabel = (RelabelType *) newnode;
                               1326                 :                : 
                               1327                 :              6 :         adjust_standard_join_alias_expression((Node *) relabel->arg, oldvar);
                               1328                 :                :     }
                               1329         [ -  + ]:             66 :     else if (IsA(newnode, CoerceViaIO))
                               1330                 :                :     {
  950 tgl@sss.pgh.pa.us        1331                 :UBC           0 :         CoerceViaIO *iocoerce = (CoerceViaIO *) newnode;
                               1332                 :                : 
                               1333                 :              0 :         adjust_standard_join_alias_expression((Node *) iocoerce->arg, oldvar);
                               1334                 :                :     }
  950 tgl@sss.pgh.pa.us        1335         [ -  + ]:CBC          66 :     else if (IsA(newnode, ArrayCoerceExpr))
                               1336                 :                :     {
  950 tgl@sss.pgh.pa.us        1337                 :UBC           0 :         ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) newnode;
                               1338                 :                : 
                               1339                 :              0 :         adjust_standard_join_alias_expression((Node *) acoerce->arg, oldvar);
                               1340                 :                :     }
  950 tgl@sss.pgh.pa.us        1341         [ +  - ]:CBC          66 :     else if (IsA(newnode, CoalesceExpr))
                               1342                 :                :     {
                               1343                 :             66 :         CoalesceExpr *cexpr = (CoalesceExpr *) newnode;
                               1344                 :                :         ListCell   *lc;
                               1345                 :                : 
                               1346         [ -  + ]:             66 :         Assert(cexpr->args != NIL);
                               1347   [ +  -  +  +  :            198 :         foreach(lc, cexpr->args)
                                              +  + ]
                               1348                 :                :         {
                               1349                 :            132 :             adjust_standard_join_alias_expression(lfirst(lc), oldvar);
                               1350                 :                :         }
                               1351                 :                :     }
                               1352                 :                :     else
  950 tgl@sss.pgh.pa.us        1353                 :UBC           0 :         Assert(false);
  950 tgl@sss.pgh.pa.us        1354                 :CBC         210 : }
                               1355                 :                : 
                               1356                 :                : /*
                               1357                 :                :  * alias_relid_set: in a set of RT indexes, replace joins by their
                               1358                 :                :  * underlying base+OJ relids
                               1359                 :                :  */
                               1360                 :                : static Relids
 2412                          1361                 :           1018 : alias_relid_set(Query *query, Relids relids)
                               1362                 :                : {
 8246                          1363                 :           1018 :     Relids      result = NULL;
                               1364                 :                :     int         rtindex;
                               1365                 :                : 
 3935                          1366                 :           1018 :     rtindex = -1;
                               1367         [ +  + ]:           2530 :     while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
                               1368                 :                :     {
 2412                          1369                 :           1512 :         RangeTblEntry *rte = rt_fetch(rtindex, query->rtable);
                               1370                 :                : 
 8265                          1371         [ +  + ]:           1512 :         if (rte->rtekind == RTE_JOIN)
 2412                          1372                 :            173 :             result = bms_join(result, get_relids_for_join(query, rtindex));
                               1373                 :                :         else
 8246                          1374                 :           1339 :             result = bms_add_member(result, rtindex);
                               1375                 :                :     }
 8265                          1376                 :           1018 :     return result;
                               1377                 :                : }
        

Generated by: LCOV version 2.4-beta