LCOV - code coverage report
Current view: top level - src/backend/rewrite - rewriteManip.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 498 577 86.3 %
Date: 2024-11-21 09:14:53 Functions: 36 36 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * rewriteManip.c
       4             :  *
       5             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       6             :  * Portions Copyright (c) 1994, Regents of the University of California
       7             :  *
       8             :  *
       9             :  * IDENTIFICATION
      10             :  *    src/backend/rewrite/rewriteManip.c
      11             :  *
      12             :  *-------------------------------------------------------------------------
      13             :  */
      14             : #include "postgres.h"
      15             : 
      16             : #include "catalog/pg_type.h"
      17             : #include "nodes/makefuncs.h"
      18             : #include "nodes/nodeFuncs.h"
      19             : #include "nodes/pathnodes.h"
      20             : #include "nodes/plannodes.h"
      21             : #include "parser/parse_coerce.h"
      22             : #include "parser/parse_relation.h"
      23             : #include "parser/parsetree.h"
      24             : #include "rewrite/rewriteManip.h"
      25             : 
      26             : 
      27             : typedef struct
      28             : {
      29             :     int         sublevels_up;
      30             : } contain_aggs_of_level_context;
      31             : 
      32             : typedef struct
      33             : {
      34             :     int         agg_location;
      35             :     int         sublevels_up;
      36             : } locate_agg_of_level_context;
      37             : 
      38             : typedef struct
      39             : {
      40             :     int         win_location;
      41             : } locate_windowfunc_context;
      42             : 
      43             : typedef struct
      44             : {
      45             :     const Bitmapset *target_relids;
      46             :     const Bitmapset *added_relids;
      47             :     int         sublevels_up;
      48             : } add_nulling_relids_context;
      49             : 
      50             : typedef struct
      51             : {
      52             :     const Bitmapset *removable_relids;
      53             :     const Bitmapset *except_relids;
      54             :     int         sublevels_up;
      55             : } remove_nulling_relids_context;
      56             : 
      57             : static bool contain_aggs_of_level_walker(Node *node,
      58             :                                          contain_aggs_of_level_context *context);
      59             : static bool locate_agg_of_level_walker(Node *node,
      60             :                                        locate_agg_of_level_context *context);
      61             : static bool contain_windowfuncs_walker(Node *node, void *context);
      62             : static bool locate_windowfunc_walker(Node *node,
      63             :                                      locate_windowfunc_context *context);
      64             : static bool checkExprHasSubLink_walker(Node *node, void *context);
      65             : static Relids offset_relid_set(Relids relids, int offset);
      66             : static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
      67             : static Node *add_nulling_relids_mutator(Node *node,
      68             :                                         add_nulling_relids_context *context);
      69             : static Node *remove_nulling_relids_mutator(Node *node,
      70             :                                            remove_nulling_relids_context *context);
      71             : 
      72             : 
      73             : /*
      74             :  * contain_aggs_of_level -
      75             :  *  Check if an expression contains an aggregate function call of a
      76             :  *  specified query level.
      77             :  *
      78             :  * The objective of this routine is to detect whether there are aggregates
      79             :  * belonging to the given query level.  Aggregates belonging to subqueries
      80             :  * or outer queries do NOT cause a true result.  We must recurse into
      81             :  * subqueries to detect outer-reference aggregates that logically belong to
      82             :  * the specified query level.
      83             :  */
      84             : bool
      85         744 : contain_aggs_of_level(Node *node, int levelsup)
      86             : {
      87             :     contain_aggs_of_level_context context;
      88             : 
      89         744 :     context.sublevels_up = levelsup;
      90             : 
      91             :     /*
      92             :      * Must be prepared to start with a Query or a bare expression tree; if
      93             :      * it's a Query, we don't want to increment sublevels_up.
      94             :      */
      95         744 :     return query_or_expression_tree_walker(node,
      96             :                                            contain_aggs_of_level_walker,
      97             :                                            (void *) &context,
      98             :                                            0);
      99             : }
     100             : 
     101             : static bool
     102        1748 : contain_aggs_of_level_walker(Node *node,
     103             :                              contain_aggs_of_level_context *context)
     104             : {
     105        1748 :     if (node == NULL)
     106         450 :         return false;
     107        1298 :     if (IsA(node, Aggref))
     108             :     {
     109           0 :         if (((Aggref *) node)->agglevelsup == context->sublevels_up)
     110           0 :             return true;        /* abort the tree traversal and return true */
     111             :         /* else fall through to examine argument */
     112             :     }
     113        1298 :     if (IsA(node, GroupingFunc))
     114             :     {
     115           0 :         if (((GroupingFunc *) node)->agglevelsup == context->sublevels_up)
     116           0 :             return true;
     117             :         /* else fall through to examine argument */
     118             :     }
     119        1298 :     if (IsA(node, Query))
     120             :     {
     121             :         /* Recurse into subselects */
     122             :         bool        result;
     123             : 
     124          28 :         context->sublevels_up++;
     125          28 :         result = query_tree_walker((Query *) node,
     126             :                                    contain_aggs_of_level_walker,
     127             :                                    (void *) context, 0);
     128          28 :         context->sublevels_up--;
     129          28 :         return result;
     130             :     }
     131        1270 :     return expression_tree_walker(node, contain_aggs_of_level_walker,
     132             :                                   (void *) context);
     133             : }
     134             : 
     135             : /*
     136             :  * locate_agg_of_level -
     137             :  *    Find the parse location of any aggregate of the specified query level.
     138             :  *
     139             :  * Returns -1 if no such agg is in the querytree, or if they all have
     140             :  * unknown parse location.  (The former case is probably caller error,
     141             :  * but we don't bother to distinguish it from the latter case.)
     142             :  *
     143             :  * Note: it might seem appropriate to merge this functionality into
     144             :  * contain_aggs_of_level, but that would complicate that function's API.
     145             :  * Currently, the only uses of this function are for error reporting,
     146             :  * and so shaving cycles probably isn't very important.
     147             :  */
     148             : int
     149          60 : locate_agg_of_level(Node *node, int levelsup)
     150             : {
     151             :     locate_agg_of_level_context context;
     152             : 
     153          60 :     context.agg_location = -1;  /* in case we find nothing */
     154          60 :     context.sublevels_up = levelsup;
     155             : 
     156             :     /*
     157             :      * Must be prepared to start with a Query or a bare expression tree; if
     158             :      * it's a Query, we don't want to increment sublevels_up.
     159             :      */
     160          60 :     (void) query_or_expression_tree_walker(node,
     161             :                                            locate_agg_of_level_walker,
     162             :                                            (void *) &context,
     163             :                                            0);
     164             : 
     165          60 :     return context.agg_location;
     166             : }
     167             : 
     168             : static bool
     169         240 : locate_agg_of_level_walker(Node *node,
     170             :                            locate_agg_of_level_context *context)
     171             : {
     172         240 :     if (node == NULL)
     173          12 :         return false;
     174         228 :     if (IsA(node, Aggref))
     175             :     {
     176          54 :         if (((Aggref *) node)->agglevelsup == context->sublevels_up &&
     177          48 :             ((Aggref *) node)->location >= 0)
     178             :         {
     179          48 :             context->agg_location = ((Aggref *) node)->location;
     180          48 :             return true;        /* abort the tree traversal and return true */
     181             :         }
     182             :         /* else fall through to examine argument */
     183             :     }
     184         180 :     if (IsA(node, GroupingFunc))
     185             :     {
     186           0 :         if (((GroupingFunc *) node)->agglevelsup == context->sublevels_up &&
     187           0 :             ((GroupingFunc *) node)->location >= 0)
     188             :         {
     189           0 :             context->agg_location = ((GroupingFunc *) node)->location;
     190           0 :             return true;        /* abort the tree traversal and return true */
     191             :         }
     192             :     }
     193         180 :     if (IsA(node, Query))
     194             :     {
     195             :         /* Recurse into subselects */
     196             :         bool        result;
     197             : 
     198          12 :         context->sublevels_up++;
     199          12 :         result = query_tree_walker((Query *) node,
     200             :                                    locate_agg_of_level_walker,
     201             :                                    (void *) context, 0);
     202          12 :         context->sublevels_up--;
     203          12 :         return result;
     204             :     }
     205         168 :     return expression_tree_walker(node, locate_agg_of_level_walker,
     206             :                                   (void *) context);
     207             : }
     208             : 
     209             : /*
     210             :  * contain_windowfuncs -
     211             :  *  Check if an expression contains a window function call of the
     212             :  *  current query level.
     213             :  */
     214             : bool
     215        9506 : contain_windowfuncs(Node *node)
     216             : {
     217             :     /*
     218             :      * Must be prepared to start with a Query or a bare expression tree; if
     219             :      * it's a Query, we don't want to increment sublevels_up.
     220             :      */
     221        9506 :     return query_or_expression_tree_walker(node,
     222             :                                            contain_windowfuncs_walker,
     223             :                                            NULL,
     224             :                                            0);
     225             : }
     226             : 
     227             : static bool
     228       10376 : contain_windowfuncs_walker(Node *node, void *context)
     229             : {
     230       10376 :     if (node == NULL)
     231         168 :         return false;
     232       10208 :     if (IsA(node, WindowFunc))
     233          12 :         return true;            /* abort the tree traversal and return true */
     234             :     /* Mustn't recurse into subselects */
     235       10196 :     return expression_tree_walker(node, contain_windowfuncs_walker,
     236             :                                   (void *) context);
     237             : }
     238             : 
     239             : /*
     240             :  * locate_windowfunc -
     241             :  *    Find the parse location of any windowfunc of the current query level.
     242             :  *
     243             :  * Returns -1 if no such windowfunc is in the querytree, or if they all have
     244             :  * unknown parse location.  (The former case is probably caller error,
     245             :  * but we don't bother to distinguish it from the latter case.)
     246             :  *
     247             :  * Note: it might seem appropriate to merge this functionality into
     248             :  * contain_windowfuncs, but that would complicate that function's API.
     249             :  * Currently, the only uses of this function are for error reporting,
     250             :  * and so shaving cycles probably isn't very important.
     251             :  */
     252             : int
     253           6 : locate_windowfunc(Node *node)
     254             : {
     255             :     locate_windowfunc_context context;
     256             : 
     257           6 :     context.win_location = -1;  /* in case we find nothing */
     258             : 
     259             :     /*
     260             :      * Must be prepared to start with a Query or a bare expression tree; if
     261             :      * it's a Query, we don't want to increment sublevels_up.
     262             :      */
     263           6 :     (void) query_or_expression_tree_walker(node,
     264             :                                            locate_windowfunc_walker,
     265             :                                            (void *) &context,
     266             :                                            0);
     267             : 
     268           6 :     return context.win_location;
     269             : }
     270             : 
     271             : static bool
     272           6 : locate_windowfunc_walker(Node *node, locate_windowfunc_context *context)
     273             : {
     274           6 :     if (node == NULL)
     275           0 :         return false;
     276           6 :     if (IsA(node, WindowFunc))
     277             :     {
     278           6 :         if (((WindowFunc *) node)->location >= 0)
     279             :         {
     280           6 :             context->win_location = ((WindowFunc *) node)->location;
     281           6 :             return true;        /* abort the tree traversal and return true */
     282             :         }
     283             :         /* else fall through to examine argument */
     284             :     }
     285             :     /* Mustn't recurse into subselects */
     286           0 :     return expression_tree_walker(node, locate_windowfunc_walker,
     287             :                                   (void *) context);
     288             : }
     289             : 
     290             : /*
     291             :  * checkExprHasSubLink -
     292             :  *  Check if an expression contains a SubLink.
     293             :  */
     294             : bool
     295      108594 : checkExprHasSubLink(Node *node)
     296             : {
     297             :     /*
     298             :      * If a Query is passed, examine it --- but we should not recurse into
     299             :      * sub-Queries that are in its rangetable or CTE list.
     300             :      */
     301      108594 :     return query_or_expression_tree_walker(node,
     302             :                                            checkExprHasSubLink_walker,
     303             :                                            NULL,
     304             :                                            QTW_IGNORE_RC_SUBQUERIES);
     305             : }
     306             : 
     307             : static bool
     308      180978 : checkExprHasSubLink_walker(Node *node, void *context)
     309             : {
     310      180978 :     if (node == NULL)
     311        3588 :         return false;
     312      177390 :     if (IsA(node, SubLink))
     313        1690 :         return true;            /* abort the tree traversal and return true */
     314      175700 :     return expression_tree_walker(node, checkExprHasSubLink_walker, context);
     315             : }
     316             : 
     317             : /*
     318             :  * Check for MULTIEXPR Param within expression tree
     319             :  *
     320             :  * We intentionally don't descend into SubLinks: only Params at the current
     321             :  * query level are of interest.
     322             :  */
     323             : static bool
     324       10640 : contains_multiexpr_param(Node *node, void *context)
     325             : {
     326       10640 :     if (node == NULL)
     327          18 :         return false;
     328       10622 :     if (IsA(node, Param))
     329             :     {
     330           0 :         if (((Param *) node)->paramkind == PARAM_MULTIEXPR)
     331           0 :             return true;        /* abort the tree traversal and return true */
     332           0 :         return false;
     333             :     }
     334       10622 :     return expression_tree_walker(node, contains_multiexpr_param, context);
     335             : }
     336             : 
     337             : /*
     338             :  * CombineRangeTables
     339             :  *      Adds the RTEs of 'src_rtable' into 'dst_rtable'
     340             :  *
     341             :  * This also adds the RTEPermissionInfos of 'src_perminfos' (belonging to the
     342             :  * RTEs in 'src_rtable') into *dst_perminfos and also updates perminfoindex of
     343             :  * the RTEs in 'src_rtable' to now point to the perminfos' indexes in
     344             :  * *dst_perminfos.
     345             :  *
     346             :  * Note that this changes both 'dst_rtable' and 'dst_perminfos' destructively,
     347             :  * so the caller should have better passed safe-to-modify copies.
     348             :  */
     349             : void
     350       36408 : CombineRangeTables(List **dst_rtable, List **dst_perminfos,
     351             :                    List *src_rtable, List *src_perminfos)
     352             : {
     353             :     ListCell   *l;
     354       36408 :     int         offset = list_length(*dst_perminfos);
     355             : 
     356       36408 :     if (offset > 0)
     357             :     {
     358       88798 :         foreach(l, src_rtable)
     359             :         {
     360       59842 :             RangeTblEntry *rte = lfirst_node(RangeTblEntry, l);
     361             : 
     362       59842 :             if (rte->perminfoindex > 0)
     363       31252 :                 rte->perminfoindex += offset;
     364             :         }
     365             :     }
     366             : 
     367       36408 :     *dst_perminfos = list_concat(*dst_perminfos, src_perminfos);
     368       36408 :     *dst_rtable = list_concat(*dst_rtable, src_rtable);
     369       36408 : }
     370             : 
     371             : /*
     372             :  * OffsetVarNodes - adjust Vars when appending one query's RT to another
     373             :  *
     374             :  * Find all Var nodes in the given tree with varlevelsup == sublevels_up,
     375             :  * and increment their varno fields (rangetable indexes) by 'offset'.
     376             :  * The varnosyn fields are adjusted similarly.  Also, adjust other nodes
     377             :  * that contain rangetable indexes, such as RangeTblRef and JoinExpr.
     378             :  *
     379             :  * NOTE: although this has the form of a walker, we cheat and modify the
     380             :  * nodes in-place.  The given expression tree should have been copied
     381             :  * earlier to ensure that no unwanted side-effects occur!
     382             :  */
     383             : 
     384             : typedef struct
     385             : {
     386             :     int         offset;
     387             :     int         sublevels_up;
     388             : } OffsetVarNodes_context;
     389             : 
     390             : static bool
     391     1918374 : OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
     392             : {
     393     1918374 :     if (node == NULL)
     394      571274 :         return false;
     395     1347100 :     if (IsA(node, Var))
     396             :     {
     397      708310 :         Var        *var = (Var *) node;
     398             : 
     399      708310 :         if (var->varlevelsup == context->sublevels_up)
     400             :         {
     401      686108 :             var->varno += context->offset;
     402      686108 :             var->varnullingrels = offset_relid_set(var->varnullingrels,
     403             :                                                    context->offset);
     404      686108 :             if (var->varnosyn > 0)
     405      686108 :                 var->varnosyn += context->offset;
     406             :         }
     407      708310 :         return false;
     408             :     }
     409      638790 :     if (IsA(node, CurrentOfExpr))
     410             :     {
     411           0 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
     412             : 
     413           0 :         if (context->sublevels_up == 0)
     414           0 :             cexpr->cvarno += context->offset;
     415           0 :         return false;
     416             :     }
     417      638790 :     if (IsA(node, RangeTblRef))
     418             :     {
     419       53498 :         RangeTblRef *rtr = (RangeTblRef *) node;
     420             : 
     421       53498 :         if (context->sublevels_up == 0)
     422       48952 :             rtr->rtindex += context->offset;
     423             :         /* the subquery itself is visited separately */
     424       53498 :         return false;
     425             :     }
     426      585292 :     if (IsA(node, JoinExpr))
     427             :     {
     428       13164 :         JoinExpr   *j = (JoinExpr *) node;
     429             : 
     430       13164 :         if (j->rtindex && context->sublevels_up == 0)
     431       12478 :             j->rtindex += context->offset;
     432             :         /* fall through to examine children */
     433             :     }
     434      585292 :     if (IsA(node, PlaceHolderVar))
     435             :     {
     436         416 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
     437             : 
     438         416 :         if (phv->phlevelsup == context->sublevels_up)
     439             :         {
     440         332 :             phv->phrels = offset_relid_set(phv->phrels,
     441             :                                            context->offset);
     442         332 :             phv->phnullingrels = offset_relid_set(phv->phnullingrels,
     443             :                                                   context->offset);
     444             :         }
     445             :         /* fall through to examine children */
     446             :     }
     447      585292 :     if (IsA(node, AppendRelInfo))
     448             :     {
     449         584 :         AppendRelInfo *appinfo = (AppendRelInfo *) node;
     450             : 
     451         584 :         if (context->sublevels_up == 0)
     452             :         {
     453         584 :             appinfo->parent_relid += context->offset;
     454         584 :             appinfo->child_relid += context->offset;
     455             :         }
     456             :         /* fall through to examine children */
     457             :     }
     458             :     /* Shouldn't need to handle other planner auxiliary nodes here */
     459             :     Assert(!IsA(node, PlanRowMark));
     460             :     Assert(!IsA(node, SpecialJoinInfo));
     461             :     Assert(!IsA(node, PlaceHolderInfo));
     462             :     Assert(!IsA(node, MinMaxAggInfo));
     463             : 
     464      585292 :     if (IsA(node, Query))
     465             :     {
     466             :         /* Recurse into subselects */
     467             :         bool        result;
     468             : 
     469        4022 :         context->sublevels_up++;
     470        4022 :         result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
     471             :                                    (void *) context, 0);
     472        4022 :         context->sublevels_up--;
     473        4022 :         return result;
     474             :     }
     475      581270 :     return expression_tree_walker(node, OffsetVarNodes_walker,
     476             :                                   (void *) context);
     477             : }
     478             : 
     479             : void
     480       69832 : OffsetVarNodes(Node *node, int offset, int sublevels_up)
     481             : {
     482             :     OffsetVarNodes_context context;
     483             : 
     484       69832 :     context.offset = offset;
     485       69832 :     context.sublevels_up = sublevels_up;
     486             : 
     487             :     /*
     488             :      * Must be prepared to start with a Query or a bare expression tree; if
     489             :      * it's a Query, go straight to query_tree_walker to make sure that
     490             :      * sublevels_up doesn't get incremented prematurely.
     491             :      */
     492       69832 :     if (node && IsA(node, Query))
     493       34916 :     {
     494       34916 :         Query      *qry = (Query *) node;
     495             : 
     496             :         /*
     497             :          * If we are starting at a Query, and sublevels_up is zero, then we
     498             :          * must also fix rangetable indexes in the Query itself --- namely
     499             :          * resultRelation, mergeTargetRelation, exclRelIndex and rowMarks
     500             :          * entries.  sublevels_up cannot be zero when recursing into a
     501             :          * subquery, so there's no need to have the same logic inside
     502             :          * OffsetVarNodes_walker.
     503             :          */
     504       34916 :         if (sublevels_up == 0)
     505             :         {
     506             :             ListCell   *l;
     507             : 
     508       34916 :             if (qry->resultRelation)
     509        1230 :                 qry->resultRelation += offset;
     510             : 
     511       34916 :             if (qry->mergeTargetRelation)
     512           0 :                 qry->mergeTargetRelation += offset;
     513             : 
     514       34916 :             if (qry->onConflict && qry->onConflict->exclRelIndex)
     515          36 :                 qry->onConflict->exclRelIndex += offset;
     516             : 
     517       35064 :             foreach(l, qry->rowMarks)
     518             :             {
     519         148 :                 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
     520             : 
     521         148 :                 rc->rti += offset;
     522             :             }
     523             :         }
     524       34916 :         query_tree_walker(qry, OffsetVarNodes_walker,
     525             :                           (void *) &context, 0);
     526             :     }
     527             :     else
     528       34916 :         OffsetVarNodes_walker(node, &context);
     529       69832 : }
     530             : 
     531             : static Relids
     532      686772 : offset_relid_set(Relids relids, int offset)
     533             : {
     534      686772 :     Relids      result = NULL;
     535             :     int         rtindex;
     536             : 
     537      686772 :     rtindex = -1;
     538      788898 :     while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
     539      102126 :         result = bms_add_member(result, rtindex + offset);
     540      686772 :     return result;
     541             : }
     542             : 
     543             : /*
     544             :  * ChangeVarNodes - adjust Var nodes for a specific change of RT index
     545             :  *
     546             :  * Find all Var nodes in the given tree belonging to a specific relation
     547             :  * (identified by sublevels_up and rt_index), and change their varno fields
     548             :  * to 'new_index'.  The varnosyn fields are changed too.  Also, adjust other
     549             :  * nodes that contain rangetable indexes, such as RangeTblRef and JoinExpr.
     550             :  *
     551             :  * NOTE: although this has the form of a walker, we cheat and modify the
     552             :  * nodes in-place.  The given expression tree should have been copied
     553             :  * earlier to ensure that no unwanted side-effects occur!
     554             :  */
     555             : 
     556             : typedef struct
     557             : {
     558             :     int         rt_index;
     559             :     int         new_index;
     560             :     int         sublevels_up;
     561             : } ChangeVarNodes_context;
     562             : 
     563             : static bool
     564      265354 : ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
     565             : {
     566      265354 :     if (node == NULL)
     567       98810 :         return false;
     568      166544 :     if (IsA(node, Var))
     569             :     {
     570       45364 :         Var        *var = (Var *) node;
     571             : 
     572       45364 :         if (var->varlevelsup == context->sublevels_up)
     573             :         {
     574       42286 :             if (var->varno == context->rt_index)
     575       30972 :                 var->varno = context->new_index;
     576       42286 :             var->varnullingrels = adjust_relid_set(var->varnullingrels,
     577             :                                                    context->rt_index,
     578             :                                                    context->new_index);
     579       42286 :             if (var->varnosyn == context->rt_index)
     580       30972 :                 var->varnosyn = context->new_index;
     581             :         }
     582       45364 :         return false;
     583             :     }
     584      121180 :     if (IsA(node, CurrentOfExpr))
     585             :     {
     586           0 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
     587             : 
     588           0 :         if (context->sublevels_up == 0 &&
     589           0 :             cexpr->cvarno == context->rt_index)
     590           0 :             cexpr->cvarno = context->new_index;
     591           0 :         return false;
     592             :     }
     593      121180 :     if (IsA(node, RangeTblRef))
     594             :     {
     595        5098 :         RangeTblRef *rtr = (RangeTblRef *) node;
     596             : 
     597        5098 :         if (context->sublevels_up == 0 &&
     598        3028 :             rtr->rtindex == context->rt_index)
     599        1652 :             rtr->rtindex = context->new_index;
     600             :         /* the subquery itself is visited separately */
     601        5098 :         return false;
     602             :     }
     603      116082 :     if (IsA(node, JoinExpr))
     604             :     {
     605           0 :         JoinExpr   *j = (JoinExpr *) node;
     606             : 
     607           0 :         if (context->sublevels_up == 0 &&
     608           0 :             j->rtindex == context->rt_index)
     609           0 :             j->rtindex = context->new_index;
     610             :         /* fall through to examine children */
     611             :     }
     612      116082 :     if (IsA(node, PlaceHolderVar))
     613             :     {
     614           0 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
     615             : 
     616           0 :         if (phv->phlevelsup == context->sublevels_up)
     617             :         {
     618           0 :             phv->phrels = adjust_relid_set(phv->phrels,
     619             :                                            context->rt_index,
     620             :                                            context->new_index);
     621           0 :             phv->phnullingrels = adjust_relid_set(phv->phnullingrels,
     622             :                                                   context->rt_index,
     623             :                                                   context->new_index);
     624             :         }
     625             :         /* fall through to examine children */
     626             :     }
     627      116082 :     if (IsA(node, PlanRowMark))
     628             :     {
     629           0 :         PlanRowMark *rowmark = (PlanRowMark *) node;
     630             : 
     631           0 :         if (context->sublevels_up == 0)
     632             :         {
     633           0 :             if (rowmark->rti == context->rt_index)
     634           0 :                 rowmark->rti = context->new_index;
     635           0 :             if (rowmark->prti == context->rt_index)
     636           0 :                 rowmark->prti = context->new_index;
     637             :         }
     638           0 :         return false;
     639             :     }
     640      116082 :     if (IsA(node, AppendRelInfo))
     641             :     {
     642           0 :         AppendRelInfo *appinfo = (AppendRelInfo *) node;
     643             : 
     644           0 :         if (context->sublevels_up == 0)
     645             :         {
     646           0 :             if (appinfo->parent_relid == context->rt_index)
     647           0 :                 appinfo->parent_relid = context->new_index;
     648           0 :             if (appinfo->child_relid == context->rt_index)
     649           0 :                 appinfo->child_relid = context->new_index;
     650             :         }
     651             :         /* fall through to examine children */
     652             :     }
     653             :     /* Shouldn't need to handle other planner auxiliary nodes here */
     654             :     Assert(!IsA(node, SpecialJoinInfo));
     655             :     Assert(!IsA(node, PlaceHolderInfo));
     656             :     Assert(!IsA(node, MinMaxAggInfo));
     657             : 
     658      116082 :     if (IsA(node, Query))
     659             :     {
     660             :         /* Recurse into subselects */
     661             :         bool        result;
     662             : 
     663        2076 :         context->sublevels_up++;
     664        2076 :         result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
     665             :                                    (void *) context, 0);
     666        2076 :         context->sublevels_up--;
     667        2076 :         return result;
     668             :     }
     669      114006 :     return expression_tree_walker(node, ChangeVarNodes_walker,
     670             :                                   (void *) context);
     671             : }
     672             : 
     673             : void
     674       22660 : ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
     675             : {
     676             :     ChangeVarNodes_context context;
     677             : 
     678       22660 :     context.rt_index = rt_index;
     679       22660 :     context.new_index = new_index;
     680       22660 :     context.sublevels_up = sublevels_up;
     681             : 
     682             :     /*
     683             :      * Must be prepared to start with a Query or a bare expression tree; if
     684             :      * it's a Query, go straight to query_tree_walker to make sure that
     685             :      * sublevels_up doesn't get incremented prematurely.
     686             :      */
     687       22660 :     if (node && IsA(node, Query))
     688        4442 :     {
     689        4442 :         Query      *qry = (Query *) node;
     690             : 
     691             :         /*
     692             :          * If we are starting at a Query, and sublevels_up is zero, then we
     693             :          * must also fix rangetable indexes in the Query itself --- namely
     694             :          * resultRelation, mergeTargetRelation, exclRelIndex  and rowMarks
     695             :          * entries.  sublevels_up cannot be zero when recursing into a
     696             :          * subquery, so there's no need to have the same logic inside
     697             :          * ChangeVarNodes_walker.
     698             :          */
     699        4442 :         if (sublevels_up == 0)
     700             :         {
     701             :             ListCell   *l;
     702             : 
     703        4442 :             if (qry->resultRelation == rt_index)
     704        3098 :                 qry->resultRelation = new_index;
     705             : 
     706        4442 :             if (qry->mergeTargetRelation == rt_index)
     707         804 :                 qry->mergeTargetRelation = new_index;
     708             : 
     709             :             /* this is unlikely to ever be used, but ... */
     710        4442 :             if (qry->onConflict && qry->onConflict->exclRelIndex == rt_index)
     711           0 :                 qry->onConflict->exclRelIndex = new_index;
     712             : 
     713        4454 :             foreach(l, qry->rowMarks)
     714             :             {
     715          12 :                 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
     716             : 
     717          12 :                 if (rc->rti == rt_index)
     718           0 :                     rc->rti = new_index;
     719             :             }
     720             :         }
     721        4442 :         query_tree_walker(qry, ChangeVarNodes_walker,
     722             :                           (void *) &context, 0);
     723             :     }
     724             :     else
     725       18218 :         ChangeVarNodes_walker(node, &context);
     726       22660 : }
     727             : 
     728             : /*
     729             :  * Substitute newrelid for oldrelid in a Relid set
     730             :  *
     731             :  * Note: some extensions may pass a special varno such as INDEX_VAR for
     732             :  * oldrelid.  bms_is_member won't like that, but we should tolerate it.
     733             :  * (Perhaps newrelid could also be a special varno, but there had better
     734             :  * not be a reason to inject that into a nullingrels or phrels set.)
     735             :  */
     736             : static Relids
     737       42286 : adjust_relid_set(Relids relids, int oldrelid, int newrelid)
     738             : {
     739       42286 :     if (!IS_SPECIAL_VARNO(oldrelid) && bms_is_member(oldrelid, relids))
     740             :     {
     741             :         /* Ensure we have a modifiable copy */
     742           0 :         relids = bms_copy(relids);
     743             :         /* Remove old, add new */
     744           0 :         relids = bms_del_member(relids, oldrelid);
     745           0 :         relids = bms_add_member(relids, newrelid);
     746             :     }
     747       42286 :     return relids;
     748             : }
     749             : 
     750             : /*
     751             :  * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
     752             :  *
     753             :  * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
     754             :  * and add delta_sublevels_up to their varlevelsup value.  This is needed when
     755             :  * an expression that's correct for some nesting level is inserted into a
     756             :  * subquery.  Ordinarily the initial call has min_sublevels_up == 0 so that
     757             :  * all Vars are affected.  The point of min_sublevels_up is that we can
     758             :  * increment it when we recurse into a sublink, so that local variables in
     759             :  * that sublink are not affected, only outer references to vars that belong
     760             :  * to the expression's original query level or parents thereof.
     761             :  *
     762             :  * Likewise for other nodes containing levelsup fields, such as Aggref.
     763             :  *
     764             :  * NOTE: although this has the form of a walker, we cheat and modify the
     765             :  * Var nodes in-place.  The given expression tree should have been copied
     766             :  * earlier to ensure that no unwanted side-effects occur!
     767             :  */
     768             : 
     769             : typedef struct
     770             : {
     771             :     int         delta_sublevels_up;
     772             :     int         min_sublevels_up;
     773             : } IncrementVarSublevelsUp_context;
     774             : 
     775             : static bool
     776     2204928 : IncrementVarSublevelsUp_walker(Node *node,
     777             :                                IncrementVarSublevelsUp_context *context)
     778             : {
     779     2204928 :     if (node == NULL)
     780      647498 :         return false;
     781     1557430 :     if (IsA(node, Var))
     782             :     {
     783      763846 :         Var        *var = (Var *) node;
     784             : 
     785      763846 :         if (var->varlevelsup >= context->min_sublevels_up)
     786        8948 :             var->varlevelsup += context->delta_sublevels_up;
     787      763846 :         return false;           /* done here */
     788             :     }
     789      793584 :     if (IsA(node, CurrentOfExpr))
     790             :     {
     791             :         /* this should not happen */
     792           0 :         if (context->min_sublevels_up == 0)
     793           0 :             elog(ERROR, "cannot push down CurrentOfExpr");
     794           0 :         return false;
     795             :     }
     796      793584 :     if (IsA(node, Aggref))
     797             :     {
     798        2394 :         Aggref     *agg = (Aggref *) node;
     799             : 
     800        2394 :         if (agg->agglevelsup >= context->min_sublevels_up)
     801          70 :             agg->agglevelsup += context->delta_sublevels_up;
     802             :         /* fall through to recurse into argument */
     803             :     }
     804      793584 :     if (IsA(node, GroupingFunc))
     805             :     {
     806          64 :         GroupingFunc *grp = (GroupingFunc *) node;
     807             : 
     808          64 :         if (grp->agglevelsup >= context->min_sublevels_up)
     809          64 :             grp->agglevelsup += context->delta_sublevels_up;
     810             :         /* fall through to recurse into argument */
     811             :     }
     812      793584 :     if (IsA(node, PlaceHolderVar))
     813             :     {
     814         772 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
     815             : 
     816         772 :         if (phv->phlevelsup >= context->min_sublevels_up)
     817         440 :             phv->phlevelsup += context->delta_sublevels_up;
     818             :         /* fall through to recurse into argument */
     819             :     }
     820      793584 :     if (IsA(node, RangeTblEntry))
     821             :     {
     822       80040 :         RangeTblEntry *rte = (RangeTblEntry *) node;
     823             : 
     824       80040 :         if (rte->rtekind == RTE_CTE)
     825             :         {
     826        3534 :             if (rte->ctelevelsup >= context->min_sublevels_up)
     827        3504 :                 rte->ctelevelsup += context->delta_sublevels_up;
     828             :         }
     829       80040 :         return false;           /* allow range_table_walker to continue */
     830             :     }
     831      713544 :     if (IsA(node, Query))
     832             :     {
     833             :         /* Recurse into subselects */
     834             :         bool        result;
     835             : 
     836        9194 :         context->min_sublevels_up++;
     837        9194 :         result = query_tree_walker((Query *) node,
     838             :                                    IncrementVarSublevelsUp_walker,
     839             :                                    (void *) context,
     840             :                                    QTW_EXAMINE_RTES_BEFORE);
     841        9194 :         context->min_sublevels_up--;
     842        9194 :         return result;
     843             :     }
     844      704350 :     return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
     845             :                                   (void *) context);
     846             : }
     847             : 
     848             : void
     849       73390 : IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
     850             :                         int min_sublevels_up)
     851             : {
     852             :     IncrementVarSublevelsUp_context context;
     853             : 
     854       73390 :     context.delta_sublevels_up = delta_sublevels_up;
     855       73390 :     context.min_sublevels_up = min_sublevels_up;
     856             : 
     857             :     /*
     858             :      * Must be prepared to start with a Query or a bare expression tree; if
     859             :      * it's a Query, we don't want to increment sublevels_up.
     860             :      */
     861       73390 :     query_or_expression_tree_walker(node,
     862             :                                     IncrementVarSublevelsUp_walker,
     863             :                                     (void *) &context,
     864             :                                     QTW_EXAMINE_RTES_BEFORE);
     865       73390 : }
     866             : 
     867             : /*
     868             :  * IncrementVarSublevelsUp_rtable -
     869             :  *  Same as IncrementVarSublevelsUp, but to be invoked on a range table.
     870             :  */
     871             : void
     872        1530 : IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up,
     873             :                                int min_sublevels_up)
     874             : {
     875             :     IncrementVarSublevelsUp_context context;
     876             : 
     877        1530 :     context.delta_sublevels_up = delta_sublevels_up;
     878        1530 :     context.min_sublevels_up = min_sublevels_up;
     879             : 
     880        1530 :     range_table_walker(rtable,
     881             :                        IncrementVarSublevelsUp_walker,
     882             :                        (void *) &context,
     883             :                        QTW_EXAMINE_RTES_BEFORE);
     884        1530 : }
     885             : 
     886             : 
     887             : /*
     888             :  * rangeTableEntry_used - detect whether an RTE is referenced somewhere
     889             :  *  in var nodes or join or setOp trees of a query or expression.
     890             :  */
     891             : 
     892             : typedef struct
     893             : {
     894             :     int         rt_index;
     895             :     int         sublevels_up;
     896             : } rangeTableEntry_used_context;
     897             : 
     898             : static bool
     899     3489530 : rangeTableEntry_used_walker(Node *node,
     900             :                             rangeTableEntry_used_context *context)
     901             : {
     902     3489530 :     if (node == NULL)
     903      661294 :         return false;
     904     2828236 :     if (IsA(node, Var))
     905             :     {
     906      811682 :         Var        *var = (Var *) node;
     907             : 
     908      811682 :         if (var->varlevelsup == context->sublevels_up &&
     909     1288204 :             (var->varno == context->rt_index ||
     910      507758 :              bms_is_member(context->rt_index, var->varnullingrels)))
     911      272688 :             return true;
     912      538994 :         return false;
     913             :     }
     914     2016554 :     if (IsA(node, CurrentOfExpr))
     915             :     {
     916          12 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
     917             : 
     918          12 :         if (context->sublevels_up == 0 &&
     919          12 :             cexpr->cvarno == context->rt_index)
     920           0 :             return true;
     921          12 :         return false;
     922             :     }
     923     2016542 :     if (IsA(node, RangeTblRef))
     924             :     {
     925      122924 :         RangeTblRef *rtr = (RangeTblRef *) node;
     926             : 
     927      122924 :         if (rtr->rtindex == context->rt_index &&
     928       65732 :             context->sublevels_up == 0)
     929       62906 :             return true;
     930             :         /* the subquery itself is visited separately */
     931       60018 :         return false;
     932             :     }
     933     1893618 :     if (IsA(node, JoinExpr))
     934             :     {
     935       42166 :         JoinExpr   *j = (JoinExpr *) node;
     936             : 
     937       42166 :         if (j->rtindex == context->rt_index &&
     938          66 :             context->sublevels_up == 0)
     939           0 :             return true;
     940             :         /* fall through to examine children */
     941             :     }
     942             :     /* Shouldn't need to handle planner auxiliary nodes here */
     943             :     Assert(!IsA(node, PlaceHolderVar));
     944             :     Assert(!IsA(node, PlanRowMark));
     945             :     Assert(!IsA(node, SpecialJoinInfo));
     946             :     Assert(!IsA(node, AppendRelInfo));
     947             :     Assert(!IsA(node, PlaceHolderInfo));
     948             :     Assert(!IsA(node, MinMaxAggInfo));
     949             : 
     950     1893618 :     if (IsA(node, Query))
     951             :     {
     952             :         /* Recurse into subselects */
     953             :         bool        result;
     954             : 
     955       13264 :         context->sublevels_up++;
     956       13264 :         result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
     957             :                                    (void *) context, 0);
     958       13264 :         context->sublevels_up--;
     959       13264 :         return result;
     960             :     }
     961     1880354 :     return expression_tree_walker(node, rangeTableEntry_used_walker,
     962             :                                   (void *) context);
     963             : }
     964             : 
     965             : bool
     966      350806 : rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
     967             : {
     968             :     rangeTableEntry_used_context context;
     969             : 
     970      350806 :     context.rt_index = rt_index;
     971      350806 :     context.sublevels_up = sublevels_up;
     972             : 
     973             :     /*
     974             :      * Must be prepared to start with a Query or a bare expression tree; if
     975             :      * it's a Query, we don't want to increment sublevels_up.
     976             :      */
     977      350806 :     return query_or_expression_tree_walker(node,
     978             :                                            rangeTableEntry_used_walker,
     979             :                                            (void *) &context,
     980             :                                            0);
     981             : }
     982             : 
     983             : 
     984             : /*
     985             :  * If the given Query is an INSERT ... SELECT construct, extract and
     986             :  * return the sub-Query node that represents the SELECT part.  Otherwise
     987             :  * return the given Query.
     988             :  *
     989             :  * If subquery_ptr is not NULL, then *subquery_ptr is set to the location
     990             :  * of the link to the SELECT subquery inside parsetree, or NULL if not an
     991             :  * INSERT ... SELECT.
     992             :  *
     993             :  * This is a hack needed because transformations on INSERT ... SELECTs that
     994             :  * appear in rule actions should be applied to the source SELECT, not to the
     995             :  * INSERT part.  Perhaps this can be cleaned up with redesigned querytrees.
     996             :  */
     997             : Query *
     998        3422 : getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
     999             : {
    1000             :     Query      *selectquery;
    1001             :     RangeTblEntry *selectrte;
    1002             :     RangeTblRef *rtr;
    1003             : 
    1004        3422 :     if (subquery_ptr)
    1005        1344 :         *subquery_ptr = NULL;
    1006             : 
    1007        3422 :     if (parsetree == NULL)
    1008           0 :         return parsetree;
    1009        3422 :     if (parsetree->commandType != CMD_INSERT)
    1010        1458 :         return parsetree;
    1011             : 
    1012             :     /*
    1013             :      * Currently, this is ONLY applied to rule-action queries, and so we
    1014             :      * expect to find the OLD and NEW placeholder entries in the given query.
    1015             :      * If they're not there, it must be an INSERT/SELECT in which they've been
    1016             :      * pushed down to the SELECT.
    1017             :      */
    1018        1964 :     if (list_length(parsetree->rtable) >= 2 &&
    1019        1964 :         strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
    1020        1788 :                "old") == 0 &&
    1021        1788 :         strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
    1022             :                "new") == 0)
    1023        1788 :         return parsetree;
    1024             :     Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
    1025         176 :     if (list_length(parsetree->jointree->fromlist) != 1)
    1026           0 :         elog(ERROR, "expected to find SELECT subquery");
    1027         176 :     rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
    1028         176 :     if (!IsA(rtr, RangeTblRef))
    1029           0 :         elog(ERROR, "expected to find SELECT subquery");
    1030         176 :     selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
    1031         176 :     if (!(selectrte->rtekind == RTE_SUBQUERY &&
    1032         176 :           selectrte->subquery &&
    1033         176 :           IsA(selectrte->subquery, Query) &&
    1034         176 :           selectrte->subquery->commandType == CMD_SELECT))
    1035           0 :         elog(ERROR, "expected to find SELECT subquery");
    1036         176 :     selectquery = selectrte->subquery;
    1037         176 :     if (list_length(selectquery->rtable) >= 2 &&
    1038         176 :         strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
    1039         176 :                "old") == 0 &&
    1040         176 :         strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
    1041             :                "new") == 0)
    1042             :     {
    1043         176 :         if (subquery_ptr)
    1044          60 :             *subquery_ptr = &(selectrte->subquery);
    1045         176 :         return selectquery;
    1046             :     }
    1047           0 :     elog(ERROR, "could not find rule placeholders");
    1048             :     return NULL;                /* not reached */
    1049             : }
    1050             : 
    1051             : 
    1052             : /*
    1053             :  * Add the given qualifier condition to the query's WHERE clause
    1054             :  */
    1055             : void
    1056        3584 : AddQual(Query *parsetree, Node *qual)
    1057             : {
    1058             :     Node       *copy;
    1059             : 
    1060        3584 :     if (qual == NULL)
    1061        1686 :         return;
    1062             : 
    1063        1898 :     if (parsetree->commandType == CMD_UTILITY)
    1064             :     {
    1065             :         /*
    1066             :          * There's noplace to put the qual on a utility statement.
    1067             :          *
    1068             :          * If it's a NOTIFY, silently ignore the qual; this means that the
    1069             :          * NOTIFY will execute, whether or not there are any qualifying rows.
    1070             :          * While clearly wrong, this is much more useful than refusing to
    1071             :          * execute the rule at all, and extra NOTIFY events are harmless for
    1072             :          * typical uses of NOTIFY.
    1073             :          *
    1074             :          * If it isn't a NOTIFY, error out, since unconditional execution of
    1075             :          * other utility stmts is unlikely to be wanted.  (This case is not
    1076             :          * currently allowed anyway, but keep the test for safety.)
    1077             :          */
    1078           0 :         if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
    1079           0 :             return;
    1080             :         else
    1081           0 :             ereport(ERROR,
    1082             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1083             :                      errmsg("conditional utility statements are not implemented")));
    1084             :     }
    1085             : 
    1086        1898 :     if (parsetree->setOperations != NULL)
    1087             :     {
    1088             :         /*
    1089             :          * There's noplace to put the qual on a setop statement, either. (This
    1090             :          * could be fixed, but right now the planner simply ignores any qual
    1091             :          * condition on a setop query.)
    1092             :          */
    1093           0 :         ereport(ERROR,
    1094             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1095             :                  errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
    1096             :     }
    1097             : 
    1098             :     /* INTERSECT wants the original, but we need to copy - Jan */
    1099        1898 :     copy = copyObject(qual);
    1100             : 
    1101        1898 :     parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
    1102             :                                                copy);
    1103             : 
    1104             :     /*
    1105             :      * We had better not have stuck an aggregate into the WHERE clause.
    1106             :      */
    1107             :     Assert(!contain_aggs_of_level(copy, 0));
    1108             : 
    1109             :     /*
    1110             :      * Make sure query is marked correctly if added qual has sublinks. Need
    1111             :      * not search qual when query is already marked.
    1112             :      */
    1113        1898 :     if (!parsetree->hasSubLinks)
    1114        1892 :         parsetree->hasSubLinks = checkExprHasSubLink(copy);
    1115             : }
    1116             : 
    1117             : 
    1118             : /*
    1119             :  * Invert the given clause and add it to the WHERE qualifications of the
    1120             :  * given querytree.  Inversion means "x IS NOT TRUE", not just "NOT x",
    1121             :  * else we will do the wrong thing when x evaluates to NULL.
    1122             :  */
    1123             : void
    1124         444 : AddInvertedQual(Query *parsetree, Node *qual)
    1125             : {
    1126             :     BooleanTest *invqual;
    1127             : 
    1128         444 :     if (qual == NULL)
    1129           0 :         return;
    1130             : 
    1131             :     /* Need not copy input qual, because AddQual will... */
    1132         444 :     invqual = makeNode(BooleanTest);
    1133         444 :     invqual->arg = (Expr *) qual;
    1134         444 :     invqual->booltesttype = IS_NOT_TRUE;
    1135         444 :     invqual->location = -1;
    1136             : 
    1137         444 :     AddQual(parsetree, (Node *) invqual);
    1138             : }
    1139             : 
    1140             : 
    1141             : /*
    1142             :  * add_nulling_relids() finds Vars and PlaceHolderVars that belong to any
    1143             :  * of the target_relids, and adds added_relids to their varnullingrels
    1144             :  * and phnullingrels fields.  If target_relids is NULL, all level-zero
    1145             :  * Vars and PHVs are modified.
    1146             :  */
    1147             : Node *
    1148        7224 : add_nulling_relids(Node *node,
    1149             :                    const Bitmapset *target_relids,
    1150             :                    const Bitmapset *added_relids)
    1151             : {
    1152             :     add_nulling_relids_context context;
    1153             : 
    1154        7224 :     context.target_relids = target_relids;
    1155        7224 :     context.added_relids = added_relids;
    1156        7224 :     context.sublevels_up = 0;
    1157        7224 :     return query_or_expression_tree_mutator(node,
    1158             :                                             add_nulling_relids_mutator,
    1159             :                                             &context,
    1160             :                                             0);
    1161             : }
    1162             : 
    1163             : static Node *
    1164       29334 : add_nulling_relids_mutator(Node *node,
    1165             :                            add_nulling_relids_context *context)
    1166             : {
    1167       29334 :     if (node == NULL)
    1168         474 :         return NULL;
    1169       28860 :     if (IsA(node, Var))
    1170             :     {
    1171       11566 :         Var        *var = (Var *) node;
    1172             : 
    1173       11566 :         if (var->varlevelsup == context->sublevels_up &&
    1174       23024 :             (context->target_relids == NULL ||
    1175       11458 :              bms_is_member(var->varno, context->target_relids)))
    1176             :         {
    1177        6688 :             Relids      newnullingrels = bms_union(var->varnullingrels,
    1178             :                                                    context->added_relids);
    1179             : 
    1180             :             /* Copy the Var ... */
    1181        6688 :             var = copyObject(var);
    1182             :             /* ... and replace the copy's varnullingrels field */
    1183        6688 :             var->varnullingrels = newnullingrels;
    1184        6688 :             return (Node *) var;
    1185             :         }
    1186             :         /* Otherwise fall through to copy the Var normally */
    1187             :     }
    1188       17294 :     else if (IsA(node, PlaceHolderVar))
    1189             :     {
    1190         248 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
    1191             : 
    1192         248 :         if (phv->phlevelsup == context->sublevels_up &&
    1193         496 :             (context->target_relids == NULL ||
    1194         248 :              bms_overlap(phv->phrels, context->target_relids)))
    1195             :         {
    1196         248 :             Relids      newnullingrels = bms_union(phv->phnullingrels,
    1197             :                                                    context->added_relids);
    1198             : 
    1199             :             /*
    1200             :              * We don't modify the contents of the PHV's expression, only add
    1201             :              * to phnullingrels.  This corresponds to assuming that the PHV
    1202             :              * will be evaluated at the same level as before, then perhaps be
    1203             :              * nulled as it bubbles up.  Hence, just flat-copy the node ...
    1204             :              */
    1205         248 :             phv = makeNode(PlaceHolderVar);
    1206         248 :             memcpy(phv, node, sizeof(PlaceHolderVar));
    1207             :             /* ... and replace the copy's phnullingrels field */
    1208         248 :             phv->phnullingrels = newnullingrels;
    1209         248 :             return (Node *) phv;
    1210             :         }
    1211             :         /* Otherwise fall through to copy the PlaceHolderVar normally */
    1212             :     }
    1213       17046 :     else if (IsA(node, Query))
    1214             :     {
    1215             :         /* Recurse into RTE or sublink subquery */
    1216             :         Query      *newnode;
    1217             : 
    1218           0 :         context->sublevels_up++;
    1219           0 :         newnode = query_tree_mutator((Query *) node,
    1220             :                                      add_nulling_relids_mutator,
    1221             :                                      (void *) context,
    1222             :                                      0);
    1223           0 :         context->sublevels_up--;
    1224           0 :         return (Node *) newnode;
    1225             :     }
    1226       21924 :     return expression_tree_mutator(node, add_nulling_relids_mutator,
    1227             :                                    (void *) context);
    1228             : }
    1229             : 
    1230             : /*
    1231             :  * remove_nulling_relids() removes mentions of the specified RT index(es)
    1232             :  * in Var.varnullingrels and PlaceHolderVar.phnullingrels fields within
    1233             :  * the given expression, except in nodes belonging to rels listed in
    1234             :  * except_relids.
    1235             :  */
    1236             : Node *
    1237       13640 : remove_nulling_relids(Node *node,
    1238             :                       const Bitmapset *removable_relids,
    1239             :                       const Bitmapset *except_relids)
    1240             : {
    1241             :     remove_nulling_relids_context context;
    1242             : 
    1243       13640 :     context.removable_relids = removable_relids;
    1244       13640 :     context.except_relids = except_relids;
    1245       13640 :     context.sublevels_up = 0;
    1246       13640 :     return query_or_expression_tree_mutator(node,
    1247             :                                             remove_nulling_relids_mutator,
    1248             :                                             &context,
    1249             :                                             0);
    1250             : }
    1251             : 
    1252             : static Node *
    1253      250930 : remove_nulling_relids_mutator(Node *node,
    1254             :                               remove_nulling_relids_context *context)
    1255             : {
    1256      250930 :     if (node == NULL)
    1257       53574 :         return NULL;
    1258      197356 :     if (IsA(node, Var))
    1259             :     {
    1260       55160 :         Var        *var = (Var *) node;
    1261             : 
    1262       55160 :         if (var->varlevelsup == context->sublevels_up &&
    1263      103958 :             !bms_is_member(var->varno, context->except_relids) &&
    1264       51932 :             bms_overlap(var->varnullingrels, context->removable_relids))
    1265             :         {
    1266             :             /* Copy the Var ... */
    1267       12588 :             var = copyObject(var);
    1268             :             /* ... and replace the copy's varnullingrels field */
    1269       12588 :             var->varnullingrels = bms_difference(var->varnullingrels,
    1270             :                                                  context->removable_relids);
    1271       12588 :             return (Node *) var;
    1272             :         }
    1273             :         /* Otherwise fall through to copy the Var normally */
    1274             :     }
    1275      142196 :     else if (IsA(node, PlaceHolderVar))
    1276             :     {
    1277        1232 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
    1278             : 
    1279        1232 :         if (phv->phlevelsup == context->sublevels_up &&
    1280        1232 :             !bms_overlap(phv->phrels, context->except_relids))
    1281             :         {
    1282             :             /*
    1283             :              * Note: it might seem desirable to remove the PHV altogether if
    1284             :              * phnullingrels goes to empty.  Currently we dare not do that
    1285             :              * because we use PHVs in some cases to enforce separate identity
    1286             :              * of subexpressions; see wrap_non_vars usages in prepjointree.c.
    1287             :              */
    1288             :             /* Copy the PlaceHolderVar and mutate what's below ... */
    1289             :             phv = (PlaceHolderVar *)
    1290        1232 :                 expression_tree_mutator(node,
    1291             :                                         remove_nulling_relids_mutator,
    1292             :                                         (void *) context);
    1293             :             /* ... and replace the copy's phnullingrels field */
    1294        1232 :             phv->phnullingrels = bms_difference(phv->phnullingrels,
    1295             :                                                 context->removable_relids);
    1296             :             /* We must also update phrels, if it contains a removable RTI */
    1297        1232 :             phv->phrels = bms_difference(phv->phrels,
    1298             :                                          context->removable_relids);
    1299             :             Assert(!bms_is_empty(phv->phrels));
    1300        1232 :             return (Node *) phv;
    1301             :         }
    1302             :         /* Otherwise fall through to copy the PlaceHolderVar normally */
    1303             :     }
    1304      140964 :     else if (IsA(node, Query))
    1305             :     {
    1306             :         /* Recurse into RTE or sublink subquery */
    1307             :         Query      *newnode;
    1308             : 
    1309         166 :         context->sublevels_up++;
    1310         166 :         newnode = query_tree_mutator((Query *) node,
    1311             :                                      remove_nulling_relids_mutator,
    1312             :                                      (void *) context,
    1313             :                                      0);
    1314         166 :         context->sublevels_up--;
    1315         166 :         return (Node *) newnode;
    1316             :     }
    1317      183370 :     return expression_tree_mutator(node, remove_nulling_relids_mutator,
    1318             :                                    (void *) context);
    1319             : }
    1320             : 
    1321             : 
    1322             : /*
    1323             :  * replace_rte_variables() finds all Vars in an expression tree
    1324             :  * that reference a particular RTE, and replaces them with substitute
    1325             :  * expressions obtained from a caller-supplied callback function.
    1326             :  *
    1327             :  * When invoking replace_rte_variables on a portion of a Query, pass the
    1328             :  * address of the containing Query's hasSubLinks field as outer_hasSubLinks.
    1329             :  * Otherwise, pass NULL, but inserting a SubLink into a non-Query expression
    1330             :  * will then cause an error.
    1331             :  *
    1332             :  * Note: the business with inserted_sublink is needed to update hasSubLinks
    1333             :  * in subqueries when the replacement adds a subquery inside a subquery.
    1334             :  * Messy, isn't it?  We do not need to do similar pushups for hasAggs,
    1335             :  * because it isn't possible for this transformation to insert a level-zero
    1336             :  * aggregate reference into a subquery --- it could only insert outer aggs.
    1337             :  * Likewise for hasWindowFuncs.
    1338             :  *
    1339             :  * Note: usually, we'd not expose the mutator function or context struct
    1340             :  * for a function like this.  We do so because callbacks often find it
    1341             :  * convenient to recurse directly to the mutator on sub-expressions of
    1342             :  * what they will return.
    1343             :  */
    1344             : Node *
    1345      177140 : replace_rte_variables(Node *node, int target_varno, int sublevels_up,
    1346             :                       replace_rte_variables_callback callback,
    1347             :                       void *callback_arg,
    1348             :                       bool *outer_hasSubLinks)
    1349             : {
    1350             :     Node       *result;
    1351             :     replace_rte_variables_context context;
    1352             : 
    1353      177140 :     context.callback = callback;
    1354      177140 :     context.callback_arg = callback_arg;
    1355      177140 :     context.target_varno = target_varno;
    1356      177140 :     context.sublevels_up = sublevels_up;
    1357             : 
    1358             :     /*
    1359             :      * We try to initialize inserted_sublink to true if there is no need to
    1360             :      * detect new sublinks because the query already has some.
    1361             :      */
    1362      177140 :     if (node && IsA(node, Query))
    1363        4628 :         context.inserted_sublink = ((Query *) node)->hasSubLinks;
    1364      172512 :     else if (outer_hasSubLinks)
    1365      172512 :         context.inserted_sublink = *outer_hasSubLinks;
    1366             :     else
    1367           0 :         context.inserted_sublink = false;
    1368             : 
    1369             :     /*
    1370             :      * Must be prepared to start with a Query or a bare expression tree; if
    1371             :      * it's a Query, we don't want to increment sublevels_up.
    1372             :      */
    1373      177140 :     result = query_or_expression_tree_mutator(node,
    1374             :                                               replace_rte_variables_mutator,
    1375             :                                               (void *) &context,
    1376             :                                               0);
    1377             : 
    1378      177134 :     if (context.inserted_sublink)
    1379             :     {
    1380       17950 :         if (result && IsA(result, Query))
    1381          96 :             ((Query *) result)->hasSubLinks = true;
    1382       17854 :         else if (outer_hasSubLinks)
    1383       17854 :             *outer_hasSubLinks = true;
    1384             :         else
    1385           0 :             elog(ERROR, "replace_rte_variables inserted a SubLink, but has noplace to record it");
    1386             :     }
    1387             : 
    1388      177134 :     return result;
    1389             : }
    1390             : 
    1391             : Node *
    1392      779870 : replace_rte_variables_mutator(Node *node,
    1393             :                               replace_rte_variables_context *context)
    1394             : {
    1395      779870 :     if (node == NULL)
    1396      238428 :         return NULL;
    1397      541442 :     if (IsA(node, Var))
    1398             :     {
    1399      198014 :         Var        *var = (Var *) node;
    1400             : 
    1401      198014 :         if (var->varno == context->target_varno &&
    1402      116664 :             var->varlevelsup == context->sublevels_up)
    1403             :         {
    1404             :             /* Found a matching variable, make the substitution */
    1405             :             Node       *newnode;
    1406             : 
    1407      109178 :             newnode = context->callback(var, context);
    1408             :             /* Detect if we are adding a sublink to query */
    1409      109178 :             if (!context->inserted_sublink)
    1410      100664 :                 context->inserted_sublink = checkExprHasSubLink(newnode);
    1411      109178 :             return newnode;
    1412             :         }
    1413             :         /* otherwise fall through to copy the var normally */
    1414             :     }
    1415      343428 :     else if (IsA(node, CurrentOfExpr))
    1416             :     {
    1417           6 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
    1418             : 
    1419           6 :         if (cexpr->cvarno == context->target_varno &&
    1420           6 :             context->sublevels_up == 0)
    1421             :         {
    1422             :             /*
    1423             :              * We get here if a WHERE CURRENT OF expression turns out to apply
    1424             :              * to a view.  Someday we might be able to translate the
    1425             :              * expression to apply to an underlying table of the view, but
    1426             :              * right now it's not implemented.
    1427             :              */
    1428           6 :             ereport(ERROR,
    1429             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1430             :                      errmsg("WHERE CURRENT OF on a view is not implemented")));
    1431             :         }
    1432             :         /* otherwise fall through to copy the expr normally */
    1433             :     }
    1434      343422 :     else if (IsA(node, Query))
    1435             :     {
    1436             :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
    1437             :         Query      *newnode;
    1438             :         bool        save_inserted_sublink;
    1439             : 
    1440        2458 :         context->sublevels_up++;
    1441        2458 :         save_inserted_sublink = context->inserted_sublink;
    1442        2458 :         context->inserted_sublink = ((Query *) node)->hasSubLinks;
    1443        2458 :         newnode = query_tree_mutator((Query *) node,
    1444             :                                      replace_rte_variables_mutator,
    1445             :                                      (void *) context,
    1446             :                                      0);
    1447        2458 :         newnode->hasSubLinks |= context->inserted_sublink;
    1448        2458 :         context->inserted_sublink = save_inserted_sublink;
    1449        2458 :         context->sublevels_up--;
    1450        2458 :         return (Node *) newnode;
    1451             :     }
    1452      429800 :     return expression_tree_mutator(node, replace_rte_variables_mutator,
    1453             :                                    (void *) context);
    1454             : }
    1455             : 
    1456             : 
    1457             : /*
    1458             :  * map_variable_attnos() finds all user-column Vars in an expression tree
    1459             :  * that reference a particular RTE, and adjusts their varattnos according
    1460             :  * to the given mapping array (varattno n is replaced by attno_map[n-1]).
    1461             :  * Vars for system columns are not modified.
    1462             :  *
    1463             :  * A zero in the mapping array represents a dropped column, which should not
    1464             :  * appear in the expression.
    1465             :  *
    1466             :  * If the expression tree contains a whole-row Var for the target RTE,
    1467             :  * *found_whole_row is set to true.  In addition, if to_rowtype is
    1468             :  * not InvalidOid, we replace the Var with a Var of that vartype, inserting
    1469             :  * a ConvertRowtypeExpr to map back to the rowtype expected by the expression.
    1470             :  * (Therefore, to_rowtype had better be a child rowtype of the rowtype of the
    1471             :  * RTE we're changing references to.)  Callers that don't provide to_rowtype
    1472             :  * should report an error if *found_whole_row is true; we don't do that here
    1473             :  * because we don't know exactly what wording for the error message would
    1474             :  * be most appropriate.  The caller will be aware of the context.
    1475             :  *
    1476             :  * This could be built using replace_rte_variables and a callback function,
    1477             :  * but since we don't ever need to insert sublinks, replace_rte_variables is
    1478             :  * overly complicated.
    1479             :  */
    1480             : 
    1481             : typedef struct
    1482             : {
    1483             :     int         target_varno;   /* RTE index to search for */
    1484             :     int         sublevels_up;   /* (current) nesting depth */
    1485             :     const AttrMap *attno_map;   /* map array for user attnos */
    1486             :     Oid         to_rowtype;     /* change whole-row Vars to this type */
    1487             :     bool       *found_whole_row;    /* output flag */
    1488             : } map_variable_attnos_context;
    1489             : 
    1490             : static Node *
    1491      101804 : map_variable_attnos_mutator(Node *node,
    1492             :                             map_variable_attnos_context *context)
    1493             : {
    1494      101804 :     if (node == NULL)
    1495         154 :         return NULL;
    1496      101650 :     if (IsA(node, Var))
    1497             :     {
    1498       23728 :         Var        *var = (Var *) node;
    1499             : 
    1500       23728 :         if (var->varno == context->target_varno &&
    1501       23512 :             var->varlevelsup == context->sublevels_up)
    1502             :         {
    1503             :             /* Found a matching variable, make the substitution */
    1504       23512 :             Var        *newvar = (Var *) palloc(sizeof(Var));
    1505       23512 :             int         attno = var->varattno;
    1506             : 
    1507       23512 :             *newvar = *var;     /* initially copy all fields of the Var */
    1508             : 
    1509       23512 :             if (attno > 0)
    1510             :             {
    1511             :                 /* user-defined column, replace attno */
    1512       23386 :                 if (attno > context->attno_map->maplen ||
    1513       23386 :                     context->attno_map->attnums[attno - 1] == 0)
    1514           0 :                     elog(ERROR, "unexpected varattno %d in expression to be mapped",
    1515             :                          attno);
    1516       23386 :                 newvar->varattno = context->attno_map->attnums[attno - 1];
    1517             :                 /* If the syntactic referent is same RTE, fix it too */
    1518       23386 :                 if (newvar->varnosyn == context->target_varno)
    1519       23308 :                     newvar->varattnosyn = newvar->varattno;
    1520             :             }
    1521         126 :             else if (attno == 0)
    1522             :             {
    1523             :                 /* whole-row variable, warn caller */
    1524          54 :                 *(context->found_whole_row) = true;
    1525             : 
    1526             :                 /* If the caller expects us to convert the Var, do so. */
    1527          54 :                 if (OidIsValid(context->to_rowtype) &&
    1528          48 :                     context->to_rowtype != var->vartype)
    1529             :                 {
    1530             :                     ConvertRowtypeExpr *r;
    1531             : 
    1532             :                     /* This certainly won't work for a RECORD variable. */
    1533             :                     Assert(var->vartype != RECORDOID);
    1534             : 
    1535             :                     /* Var itself is changed to the requested type. */
    1536          48 :                     newvar->vartype = context->to_rowtype;
    1537             : 
    1538             :                     /*
    1539             :                      * Add a conversion node on top to convert back to the
    1540             :                      * original type expected by the expression.
    1541             :                      */
    1542          48 :                     r = makeNode(ConvertRowtypeExpr);
    1543          48 :                     r->arg = (Expr *) newvar;
    1544          48 :                     r->resulttype = var->vartype;
    1545          48 :                     r->convertformat = COERCE_IMPLICIT_CAST;
    1546          48 :                     r->location = -1;
    1547             : 
    1548          48 :                     return (Node *) r;
    1549             :                 }
    1550             :             }
    1551       23464 :             return (Node *) newvar;
    1552             :         }
    1553             :         /* otherwise fall through to copy the var normally */
    1554             :     }
    1555       77922 :     else if (IsA(node, ConvertRowtypeExpr))
    1556             :     {
    1557          36 :         ConvertRowtypeExpr *r = (ConvertRowtypeExpr *) node;
    1558          36 :         Var        *var = (Var *) r->arg;
    1559             : 
    1560             :         /*
    1561             :          * If this is coercing a whole-row Var that we need to convert, then
    1562             :          * just convert the Var without adding an extra ConvertRowtypeExpr.
    1563             :          * Effectively we're simplifying var::parenttype::grandparenttype into
    1564             :          * just var::grandparenttype.  This avoids building stacks of CREs if
    1565             :          * this function is applied repeatedly.
    1566             :          */
    1567          36 :         if (IsA(var, Var) &&
    1568          24 :             var->varno == context->target_varno &&
    1569          18 :             var->varlevelsup == context->sublevels_up &&
    1570          18 :             var->varattno == 0 &&
    1571          18 :             OidIsValid(context->to_rowtype) &&
    1572          18 :             context->to_rowtype != var->vartype)
    1573             :         {
    1574             :             ConvertRowtypeExpr *newnode;
    1575          18 :             Var        *newvar = (Var *) palloc(sizeof(Var));
    1576             : 
    1577             :             /* whole-row variable, warn caller */
    1578          18 :             *(context->found_whole_row) = true;
    1579             : 
    1580          18 :             *newvar = *var;     /* initially copy all fields of the Var */
    1581             : 
    1582             :             /* This certainly won't work for a RECORD variable. */
    1583             :             Assert(var->vartype != RECORDOID);
    1584             : 
    1585             :             /* Var itself is changed to the requested type. */
    1586          18 :             newvar->vartype = context->to_rowtype;
    1587             : 
    1588          18 :             newnode = (ConvertRowtypeExpr *) palloc(sizeof(ConvertRowtypeExpr));
    1589          18 :             *newnode = *r;      /* initially copy all fields of the CRE */
    1590          18 :             newnode->arg = (Expr *) newvar;
    1591             : 
    1592          18 :             return (Node *) newnode;
    1593             :         }
    1594             :         /* otherwise fall through to process the expression normally */
    1595             :     }
    1596       77886 :     else if (IsA(node, Query))
    1597             :     {
    1598             :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
    1599             :         Query      *newnode;
    1600             : 
    1601           0 :         context->sublevels_up++;
    1602           0 :         newnode = query_tree_mutator((Query *) node,
    1603             :                                      map_variable_attnos_mutator,
    1604             :                                      (void *) context,
    1605             :                                      0);
    1606           0 :         context->sublevels_up--;
    1607           0 :         return (Node *) newnode;
    1608             :     }
    1609       78120 :     return expression_tree_mutator(node, map_variable_attnos_mutator,
    1610             :                                    (void *) context);
    1611             : }
    1612             : 
    1613             : Node *
    1614        8218 : map_variable_attnos(Node *node,
    1615             :                     int target_varno, int sublevels_up,
    1616             :                     const AttrMap *attno_map,
    1617             :                     Oid to_rowtype, bool *found_whole_row)
    1618             : {
    1619             :     map_variable_attnos_context context;
    1620             : 
    1621        8218 :     context.target_varno = target_varno;
    1622        8218 :     context.sublevels_up = sublevels_up;
    1623        8218 :     context.attno_map = attno_map;
    1624        8218 :     context.to_rowtype = to_rowtype;
    1625        8218 :     context.found_whole_row = found_whole_row;
    1626             : 
    1627        8218 :     *found_whole_row = false;
    1628             : 
    1629             :     /*
    1630             :      * Must be prepared to start with a Query or a bare expression tree; if
    1631             :      * it's a Query, we don't want to increment sublevels_up.
    1632             :      */
    1633        8218 :     return query_or_expression_tree_mutator(node,
    1634             :                                             map_variable_attnos_mutator,
    1635             :                                             (void *) &context,
    1636             :                                             0);
    1637             : }
    1638             : 
    1639             : 
    1640             : /*
    1641             :  * ReplaceVarsFromTargetList - replace Vars with items from a targetlist
    1642             :  *
    1643             :  * Vars matching target_varno and sublevels_up are replaced by the
    1644             :  * entry with matching resno from targetlist, if there is one.
    1645             :  *
    1646             :  * If there is no matching resno for such a Var, the action depends on the
    1647             :  * nomatch_option:
    1648             :  *  REPLACEVARS_REPORT_ERROR: throw an error
    1649             :  *  REPLACEVARS_CHANGE_VARNO: change Var's varno to nomatch_varno
    1650             :  *  REPLACEVARS_SUBSTITUTE_NULL: replace Var with a NULL Const of same type
    1651             :  *
    1652             :  * The caller must also provide target_rte, the RTE describing the target
    1653             :  * relation.  This is needed to handle whole-row Vars referencing the target.
    1654             :  * We expand such Vars into RowExpr constructs.
    1655             :  *
    1656             :  * outer_hasSubLinks works the same as for replace_rte_variables().
    1657             :  */
    1658             : 
    1659             : typedef struct
    1660             : {
    1661             :     RangeTblEntry *target_rte;
    1662             :     List       *targetlist;
    1663             :     ReplaceVarsNoMatchOption nomatch_option;
    1664             :     int         nomatch_varno;
    1665             : } ReplaceVarsFromTargetList_context;
    1666             : 
    1667             : static Node *
    1668        9552 : ReplaceVarsFromTargetList_callback(Var *var,
    1669             :                                    replace_rte_variables_context *context)
    1670             : {
    1671        9552 :     ReplaceVarsFromTargetList_context *rcon = (ReplaceVarsFromTargetList_context *) context->callback_arg;
    1672             :     TargetEntry *tle;
    1673             : 
    1674        9552 :     if (var->varattno == InvalidAttrNumber)
    1675             :     {
    1676             :         /* Must expand whole-tuple reference into RowExpr */
    1677             :         RowExpr    *rowexpr;
    1678             :         List       *colnames;
    1679             :         List       *fields;
    1680             : 
    1681             :         /*
    1682             :          * If generating an expansion for a var of a named rowtype (ie, this
    1683             :          * is a plain relation RTE), then we must include dummy items for
    1684             :          * dropped columns.  If the var is RECORD (ie, this is a JOIN), then
    1685             :          * omit dropped columns.  In the latter case, attach column names to
    1686             :          * the RowExpr for use of the executor and ruleutils.c.
    1687             :          */
    1688          54 :         expandRTE(rcon->target_rte,
    1689          54 :                   var->varno, var->varlevelsup, var->location,
    1690          54 :                   (var->vartype != RECORDOID),
    1691             :                   &colnames, &fields);
    1692             :         /* Adjust the generated per-field Vars... */
    1693          54 :         fields = (List *) replace_rte_variables_mutator((Node *) fields,
    1694             :                                                         context);
    1695          54 :         rowexpr = makeNode(RowExpr);
    1696          54 :         rowexpr->args = fields;
    1697          54 :         rowexpr->row_typeid = var->vartype;
    1698          54 :         rowexpr->row_format = COERCE_IMPLICIT_CAST;
    1699          54 :         rowexpr->colnames = (var->vartype == RECORDOID) ? colnames : NIL;
    1700          54 :         rowexpr->location = var->location;
    1701             : 
    1702          54 :         return (Node *) rowexpr;
    1703             :     }
    1704             : 
    1705             :     /* Normal case referencing one targetlist element */
    1706        9498 :     tle = get_tle_by_resno(rcon->targetlist, var->varattno);
    1707             : 
    1708        9498 :     if (tle == NULL || tle->resjunk)
    1709             :     {
    1710             :         /* Failed to find column in targetlist */
    1711         390 :         switch (rcon->nomatch_option)
    1712             :         {
    1713           0 :             case REPLACEVARS_REPORT_ERROR:
    1714             :                 /* fall through, throw error below */
    1715           0 :                 break;
    1716             : 
    1717         240 :             case REPLACEVARS_CHANGE_VARNO:
    1718         240 :                 var = copyObject(var);
    1719         240 :                 var->varno = rcon->nomatch_varno;
    1720             :                 /* we leave the syntactic referent alone */
    1721         240 :                 return (Node *) var;
    1722             : 
    1723         150 :             case REPLACEVARS_SUBSTITUTE_NULL:
    1724             : 
    1725             :                 /*
    1726             :                  * If Var is of domain type, we should add a CoerceToDomain
    1727             :                  * node, in case there is a NOT NULL domain constraint.
    1728             :                  */
    1729         150 :                 return coerce_to_domain((Node *) makeNullConst(var->vartype,
    1730             :                                                                var->vartypmod,
    1731             :                                                                var->varcollid),
    1732             :                                         InvalidOid, -1,
    1733             :                                         var->vartype,
    1734             :                                         COERCION_IMPLICIT,
    1735             :                                         COERCE_IMPLICIT_CAST,
    1736             :                                         -1,
    1737             :                                         false);
    1738             :         }
    1739           0 :         elog(ERROR, "could not find replacement targetlist entry for attno %d",
    1740             :              var->varattno);
    1741             :         return NULL;            /* keep compiler quiet */
    1742             :     }
    1743             :     else
    1744             :     {
    1745             :         /* Make a copy of the tlist item to return */
    1746        9108 :         Expr       *newnode = copyObject(tle->expr);
    1747             : 
    1748             :         /* Must adjust varlevelsup if tlist item is from higher query */
    1749        9108 :         if (var->varlevelsup > 0)
    1750         162 :             IncrementVarSublevelsUp((Node *) newnode, var->varlevelsup, 0);
    1751             : 
    1752             :         /*
    1753             :          * Check to see if the tlist item contains a PARAM_MULTIEXPR Param,
    1754             :          * and throw error if so.  This case could only happen when expanding
    1755             :          * an ON UPDATE rule's NEW variable and the referenced tlist item in
    1756             :          * the original UPDATE command is part of a multiple assignment. There
    1757             :          * seems no practical way to handle such cases without multiple
    1758             :          * evaluation of the multiple assignment's sub-select, which would
    1759             :          * create semantic oddities that users of rules would probably prefer
    1760             :          * not to cope with.  So treat it as an unimplemented feature.
    1761             :          */
    1762        9108 :         if (contains_multiexpr_param((Node *) newnode, NULL))
    1763           0 :             ereport(ERROR,
    1764             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1765             :                      errmsg("NEW variables in ON UPDATE rules cannot reference columns that are part of a multiple assignment in the subject UPDATE command")));
    1766             : 
    1767        9108 :         return (Node *) newnode;
    1768             :     }
    1769             : }
    1770             : 
    1771             : Node *
    1772        6640 : ReplaceVarsFromTargetList(Node *node,
    1773             :                           int target_varno, int sublevels_up,
    1774             :                           RangeTblEntry *target_rte,
    1775             :                           List *targetlist,
    1776             :                           ReplaceVarsNoMatchOption nomatch_option,
    1777             :                           int nomatch_varno,
    1778             :                           bool *outer_hasSubLinks)
    1779             : {
    1780             :     ReplaceVarsFromTargetList_context context;
    1781             : 
    1782        6640 :     context.target_rte = target_rte;
    1783        6640 :     context.targetlist = targetlist;
    1784        6640 :     context.nomatch_option = nomatch_option;
    1785        6640 :     context.nomatch_varno = nomatch_varno;
    1786             : 
    1787        6640 :     return replace_rte_variables(node, target_varno, sublevels_up,
    1788             :                                  ReplaceVarsFromTargetList_callback,
    1789             :                                  (void *) &context,
    1790             :                                  outer_hasSubLinks);
    1791             : }

Generated by: LCOV version 1.14