LCOV - code coverage report
Current view: top level - src/backend/rewrite - rewriteManip.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 495 575 86.1 %
Date: 2024-05-09 13:11:02 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         660 : contain_aggs_of_level(Node *node, int levelsup)
      86             : {
      87             :     contain_aggs_of_level_context context;
      88             : 
      89         660 :     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         660 :     return query_or_expression_tree_walker(node,
      96             :                                            contain_aggs_of_level_walker,
      97             :                                            (void *) &context,
      98             :                                            0);
      99             : }
     100             : 
     101             : static bool
     102        1136 : contain_aggs_of_level_walker(Node *node,
     103             :                              contain_aggs_of_level_context *context)
     104             : {
     105        1136 :     if (node == NULL)
     106         138 :         return false;
     107         998 :     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         998 :     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         998 :     if (IsA(node, Query))
     120             :     {
     121             :         /* Recurse into subselects */
     122             :         bool        result;
     123             : 
     124           4 :         context->sublevels_up++;
     125           4 :         result = query_tree_walker((Query *) node,
     126             :                                    contain_aggs_of_level_walker,
     127             :                                    (void *) context, 0);
     128           4 :         context->sublevels_up--;
     129           4 :         return result;
     130             :     }
     131         994 :     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        9320 : 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        9320 :     return query_or_expression_tree_walker(node,
     222             :                                            contain_windowfuncs_walker,
     223             :                                            NULL,
     224             :                                            0);
     225             : }
     226             : 
     227             : static bool
     228       10190 : contain_windowfuncs_walker(Node *node, void *context)
     229             : {
     230       10190 :     if (node == NULL)
     231         168 :         return false;
     232       10022 :     if (IsA(node, WindowFunc))
     233          12 :         return true;            /* abort the tree traversal and return true */
     234             :     /* Mustn't recurse into subselects */
     235       10010 :     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      103132 : 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      103132 :     return query_or_expression_tree_walker(node,
     302             :                                            checkExprHasSubLink_walker,
     303             :                                            NULL,
     304             :                                            QTW_IGNORE_RC_SUBQUERIES);
     305             : }
     306             : 
     307             : static bool
     308      174186 : checkExprHasSubLink_walker(Node *node, void *context)
     309             : {
     310      174186 :     if (node == NULL)
     311        3576 :         return false;
     312      170610 :     if (IsA(node, SubLink))
     313        1582 :         return true;            /* abort the tree traversal and return true */
     314      169028 :     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        9782 : contains_multiexpr_param(Node *node, void *context)
     325             : {
     326        9782 :     if (node == NULL)
     327          18 :         return false;
     328        9764 :     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        9764 :     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       35070 : CombineRangeTables(List **dst_rtable, List **dst_perminfos,
     351             :                    List *src_rtable, List *src_perminfos)
     352             : {
     353             :     ListCell   *l;
     354       35070 :     int         offset = list_length(*dst_perminfos);
     355             : 
     356       35070 :     if (offset > 0)
     357             :     {
     358       85770 :         foreach(l, src_rtable)
     359             :         {
     360       57966 :             RangeTblEntry *rte = lfirst_node(RangeTblEntry, l);
     361             : 
     362       57966 :             if (rte->perminfoindex > 0)
     363       30682 :                 rte->perminfoindex += offset;
     364             :         }
     365             :     }
     366             : 
     367       35070 :     *dst_perminfos = list_concat(*dst_perminfos, src_perminfos);
     368       35070 :     *dst_rtable = list_concat(*dst_rtable, src_rtable);
     369       35070 : }
     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     1830058 : OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
     392             : {
     393     1830058 :     if (node == NULL)
     394      550808 :         return false;
     395     1279250 :     if (IsA(node, Var))
     396             :     {
     397      675166 :         Var        *var = (Var *) node;
     398             : 
     399      675166 :         if (var->varlevelsup == context->sublevels_up)
     400             :         {
     401      658618 :             var->varno += context->offset;
     402      658618 :             var->varnullingrels = offset_relid_set(var->varnullingrels,
     403             :                                                    context->offset);
     404      658618 :             if (var->varnosyn > 0)
     405      658618 :                 var->varnosyn += context->offset;
     406             :         }
     407      675166 :         return false;
     408             :     }
     409      604084 :     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      604084 :     if (IsA(node, RangeTblRef))
     418             :     {
     419       51624 :         RangeTblRef *rtr = (RangeTblRef *) node;
     420             : 
     421       51624 :         if (context->sublevels_up == 0)
     422       47252 :             rtr->rtindex += context->offset;
     423             :         /* the subquery itself is visited separately */
     424       51624 :         return false;
     425             :     }
     426      552460 :     if (IsA(node, JoinExpr))
     427             :     {
     428       12764 :         JoinExpr   *j = (JoinExpr *) node;
     429             : 
     430       12764 :         if (j->rtindex && context->sublevels_up == 0)
     431       12146 :             j->rtindex += context->offset;
     432             :         /* fall through to examine children */
     433             :     }
     434      552460 :     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      552460 :     if (IsA(node, AppendRelInfo))
     448             :     {
     449         632 :         AppendRelInfo *appinfo = (AppendRelInfo *) node;
     450             : 
     451         632 :         if (context->sublevels_up == 0)
     452             :         {
     453         632 :             appinfo->parent_relid += context->offset;
     454         632 :             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      552460 :     if (IsA(node, Query))
     465             :     {
     466             :         /* Recurse into subselects */
     467             :         bool        result;
     468             : 
     469        3896 :         context->sublevels_up++;
     470        3896 :         result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
     471             :                                    (void *) context, 0);
     472        3896 :         context->sublevels_up--;
     473        3896 :         return result;
     474             :     }
     475      548564 :     return expression_tree_walker(node, OffsetVarNodes_walker,
     476             :                                   (void *) context);
     477             : }
     478             : 
     479             : void
     480       67124 : OffsetVarNodes(Node *node, int offset, int sublevels_up)
     481             : {
     482             :     OffsetVarNodes_context context;
     483             : 
     484       67124 :     context.offset = offset;
     485       67124 :     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       67124 :     if (node && IsA(node, Query))
     493       33562 :     {
     494       33562 :         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       33562 :         if (sublevels_up == 0)
     505             :         {
     506             :             ListCell   *l;
     507             : 
     508       33562 :             if (qry->resultRelation)
     509        1230 :                 qry->resultRelation += offset;
     510             : 
     511       33562 :             if (qry->mergeTargetRelation)
     512           0 :                 qry->mergeTargetRelation += offset;
     513             : 
     514       33562 :             if (qry->onConflict && qry->onConflict->exclRelIndex)
     515          36 :                 qry->onConflict->exclRelIndex += offset;
     516             : 
     517       33710 :             foreach(l, qry->rowMarks)
     518             :             {
     519         148 :                 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
     520             : 
     521         148 :                 rc->rti += offset;
     522             :             }
     523             :         }
     524       33562 :         query_tree_walker(qry, OffsetVarNodes_walker,
     525             :                           (void *) &context, 0);
     526             :     }
     527             :     else
     528       33562 :         OffsetVarNodes_walker(node, &context);
     529       67124 : }
     530             : 
     531             : static Relids
     532      659282 : offset_relid_set(Relids relids, int offset)
     533             : {
     534      659282 :     Relids      result = NULL;
     535             :     int         rtindex;
     536             : 
     537      659282 :     rtindex = -1;
     538      757236 :     while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
     539       97954 :         result = bms_add_member(result, rtindex + offset);
     540      659282 :     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      263092 : ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
     565             : {
     566      263092 :     if (node == NULL)
     567       98228 :         return false;
     568      164864 :     if (IsA(node, Var))
     569             :     {
     570       44818 :         Var        *var = (Var *) node;
     571             : 
     572       44818 :         if (var->varlevelsup == context->sublevels_up)
     573             :         {
     574       41740 :             if (var->varno == context->rt_index)
     575       30540 :                 var->varno = context->new_index;
     576       41740 :             var->varnullingrels = adjust_relid_set(var->varnullingrels,
     577             :                                                    context->rt_index,
     578             :                                                    context->new_index);
     579       41740 :             if (var->varnosyn == context->rt_index)
     580       30540 :                 var->varnosyn = context->new_index;
     581             :         }
     582       44818 :         return false;
     583             :     }
     584      120046 :     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      120046 :     if (IsA(node, RangeTblRef))
     594             :     {
     595        5080 :         RangeTblRef *rtr = (RangeTblRef *) node;
     596             : 
     597        5080 :         if (context->sublevels_up == 0 &&
     598        3016 :             rtr->rtindex == context->rt_index)
     599        1652 :             rtr->rtindex = context->new_index;
     600             :         /* the subquery itself is visited separately */
     601        5080 :         return false;
     602             :     }
     603      114966 :     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      114966 :     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      114966 :     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      114966 :     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      114966 :     if (IsA(node, Query))
     659             :     {
     660             :         /* Recurse into subselects */
     661             :         bool        result;
     662             : 
     663        2070 :         context->sublevels_up++;
     664        2070 :         result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
     665             :                                    (void *) context, 0);
     666        2070 :         context->sublevels_up--;
     667        2070 :         return result;
     668             :     }
     669      112896 :     return expression_tree_walker(node, ChangeVarNodes_walker,
     670             :                                   (void *) context);
     671             : }
     672             : 
     673             : void
     674       22420 : ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
     675             : {
     676             :     ChangeVarNodes_context context;
     677             : 
     678       22420 :     context.rt_index = rt_index;
     679       22420 :     context.new_index = new_index;
     680       22420 :     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       22420 :     if (node && IsA(node, Query))
     688        4412 :     {
     689        4412 :         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        4412 :         if (sublevels_up == 0)
     700             :         {
     701             :             ListCell   *l;
     702             : 
     703        4412 :             if (qry->resultRelation == rt_index)
     704        3074 :                 qry->resultRelation = new_index;
     705             : 
     706        4412 :             if (qry->mergeTargetRelation == rt_index)
     707         792 :                 qry->mergeTargetRelation = new_index;
     708             : 
     709             :             /* this is unlikely to ever be used, but ... */
     710        4412 :             if (qry->onConflict && qry->onConflict->exclRelIndex == rt_index)
     711           0 :                 qry->onConflict->exclRelIndex = new_index;
     712             : 
     713        4424 :             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        4412 :         query_tree_walker(qry, ChangeVarNodes_walker,
     722             :                           (void *) &context, 0);
     723             :     }
     724             :     else
     725       18008 :         ChangeVarNodes_walker(node, &context);
     726       22420 : }
     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       41740 : adjust_relid_set(Relids relids, int oldrelid, int newrelid)
     738             : {
     739       41740 :     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       41740 :     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     2115348 : IncrementVarSublevelsUp_walker(Node *node,
     777             :                                IncrementVarSublevelsUp_context *context)
     778             : {
     779     2115348 :     if (node == NULL)
     780      627492 :         return false;
     781     1487856 :     if (IsA(node, Var))
     782             :     {
     783      731174 :         Var        *var = (Var *) node;
     784             : 
     785      731174 :         if (var->varlevelsup >= context->min_sublevels_up)
     786        8890 :             var->varlevelsup += context->delta_sublevels_up;
     787      731174 :         return false;           /* done here */
     788             :     }
     789      756682 :     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      756682 :     if (IsA(node, Aggref))
     797             :     {
     798        2202 :         Aggref     *agg = (Aggref *) node;
     799             : 
     800        2202 :         if (agg->agglevelsup >= context->min_sublevels_up)
     801          70 :             agg->agglevelsup += context->delta_sublevels_up;
     802             :         /* fall through to recurse into argument */
     803             :     }
     804      756682 :     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      756682 :     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      756682 :     if (IsA(node, RangeTblEntry))
     821             :     {
     822       77840 :         RangeTblEntry *rte = (RangeTblEntry *) node;
     823             : 
     824       77840 :         if (rte->rtekind == RTE_CTE)
     825             :         {
     826        3826 :             if (rte->ctelevelsup >= context->min_sublevels_up)
     827        3796 :                 rte->ctelevelsup += context->delta_sublevels_up;
     828             :         }
     829       77840 :         return false;           /* allow range_table_walker to continue */
     830             :     }
     831      678842 :     if (IsA(node, Query))
     832             :     {
     833             :         /* Recurse into subselects */
     834             :         bool        result;
     835             : 
     836        9184 :         context->min_sublevels_up++;
     837        9184 :         result = query_tree_walker((Query *) node,
     838             :                                    IncrementVarSublevelsUp_walker,
     839             :                                    (void *) context,
     840             :                                    QTW_EXAMINE_RTES_BEFORE);
     841        9184 :         context->min_sublevels_up--;
     842        9184 :         return result;
     843             :     }
     844      669658 :     return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
     845             :                                   (void *) context);
     846             : }
     847             : 
     848             : void
     849       70564 : IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
     850             :                         int min_sublevels_up)
     851             : {
     852             :     IncrementVarSublevelsUp_context context;
     853             : 
     854       70564 :     context.delta_sublevels_up = delta_sublevels_up;
     855       70564 :     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       70564 :     query_or_expression_tree_walker(node,
     862             :                                     IncrementVarSublevelsUp_walker,
     863             :                                     (void *) &context,
     864             :                                     QTW_EXAMINE_RTES_BEFORE);
     865       70564 : }
     866             : 
     867             : /*
     868             :  * IncrementVarSublevelsUp_rtable -
     869             :  *  Same as IncrementVarSublevelsUp, but to be invoked on a range table.
     870             :  */
     871             : void
     872        1546 : IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up,
     873             :                                int min_sublevels_up)
     874             : {
     875             :     IncrementVarSublevelsUp_context context;
     876             : 
     877        1546 :     context.delta_sublevels_up = delta_sublevels_up;
     878        1546 :     context.min_sublevels_up = min_sublevels_up;
     879             : 
     880        1546 :     range_table_walker(rtable,
     881             :                        IncrementVarSublevelsUp_walker,
     882             :                        (void *) &context,
     883             :                        QTW_EXAMINE_RTES_BEFORE);
     884        1546 : }
     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     3388860 : rangeTableEntry_used_walker(Node *node,
     900             :                             rangeTableEntry_used_context *context)
     901             : {
     902     3388860 :     if (node == NULL)
     903      637158 :         return false;
     904     2751702 :     if (IsA(node, Var))
     905             :     {
     906      797146 :         Var        *var = (Var *) node;
     907             : 
     908      797146 :         if (var->varlevelsup == context->sublevels_up &&
     909     1265518 :             (var->varno == context->rt_index ||
     910      498734 :              bms_is_member(context->rt_index, var->varnullingrels)))
     911      268050 :             return true;
     912      529096 :         return false;
     913             :     }
     914     1954556 :     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     1954544 :     if (IsA(node, RangeTblRef))
     924             :     {
     925      115716 :         RangeTblRef *rtr = (RangeTblRef *) node;
     926             : 
     927      115716 :         if (rtr->rtindex == context->rt_index &&
     928       61248 :             context->sublevels_up == 0)
     929       59130 :             return true;
     930             :         /* the subquery itself is visited separately */
     931       56586 :         return false;
     932             :     }
     933     1838828 :     if (IsA(node, JoinExpr))
     934             :     {
     935       37002 :         JoinExpr   *j = (JoinExpr *) node;
     936             : 
     937       37002 :         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     1838828 :     if (IsA(node, Query))
     951             :     {
     952             :         /* Recurse into subselects */
     953             :         bool        result;
     954             : 
     955       12592 :         context->sublevels_up++;
     956       12592 :         result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
     957             :                                    (void *) context, 0);
     958       12592 :         context->sublevels_up--;
     959       12592 :         return result;
     960             :     }
     961     1826236 :     return expression_tree_walker(node, rangeTableEntry_used_walker,
     962             :                                   (void *) context);
     963             : }
     964             : 
     965             : bool
     966      342274 : rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
     967             : {
     968             :     rangeTableEntry_used_context context;
     969             : 
     970      342274 :     context.rt_index = rt_index;
     971      342274 :     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      342274 :     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        3386 : getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
     999             : {
    1000             :     Query      *selectquery;
    1001             :     RangeTblEntry *selectrte;
    1002             :     RangeTblRef *rtr;
    1003             : 
    1004        3386 :     if (subquery_ptr)
    1005        1338 :         *subquery_ptr = NULL;
    1006             : 
    1007        3386 :     if (parsetree == NULL)
    1008           0 :         return parsetree;
    1009        3386 :     if (parsetree->commandType != CMD_INSERT)
    1010        1422 :         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        3566 : AddQual(Query *parsetree, Node *qual)
    1057             : {
    1058             :     Node       *copy;
    1059             : 
    1060        3566 :     if (qual == NULL)
    1061        1674 :         return;
    1062             : 
    1063        1892 :     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        1892 :     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        1892 :     copy = copyObject(qual);
    1100             : 
    1101        1892 :     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        1892 :     if (!parsetree->hasSubLinks)
    1114        1886 :         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.
    1145             :  */
    1146             : Node *
    1147        4682 : add_nulling_relids(Node *node,
    1148             :                    const Bitmapset *target_relids,
    1149             :                    const Bitmapset *added_relids)
    1150             : {
    1151             :     add_nulling_relids_context context;
    1152             : 
    1153        4682 :     context.target_relids = target_relids;
    1154        4682 :     context.added_relids = added_relids;
    1155        4682 :     context.sublevels_up = 0;
    1156        4682 :     return query_or_expression_tree_mutator(node,
    1157             :                                             add_nulling_relids_mutator,
    1158             :                                             &context,
    1159             :                                             0);
    1160             : }
    1161             : 
    1162             : static Node *
    1163       23518 : add_nulling_relids_mutator(Node *node,
    1164             :                            add_nulling_relids_context *context)
    1165             : {
    1166       23518 :     if (node == NULL)
    1167           0 :         return NULL;
    1168       23518 :     if (IsA(node, Var))
    1169             :     {
    1170        9268 :         Var        *var = (Var *) node;
    1171             : 
    1172       18536 :         if (var->varlevelsup == context->sublevels_up &&
    1173        9268 :             bms_is_member(var->varno, context->target_relids))
    1174             :         {
    1175        4736 :             Relids      newnullingrels = bms_union(var->varnullingrels,
    1176             :                                                    context->added_relids);
    1177             : 
    1178             :             /* Copy the Var ... */
    1179        4736 :             var = copyObject(var);
    1180             :             /* ... and replace the copy's varnullingrels field */
    1181        4736 :             var->varnullingrels = newnullingrels;
    1182        4736 :             return (Node *) var;
    1183             :         }
    1184             :         /* Otherwise fall through to copy the Var normally */
    1185             :     }
    1186       14250 :     else if (IsA(node, PlaceHolderVar))
    1187             :     {
    1188           6 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
    1189             : 
    1190          12 :         if (phv->phlevelsup == context->sublevels_up &&
    1191           6 :             bms_overlap(phv->phrels, context->target_relids))
    1192             :         {
    1193           6 :             Relids      newnullingrels = bms_union(phv->phnullingrels,
    1194             :                                                    context->added_relids);
    1195             : 
    1196             :             /*
    1197             :              * We don't modify the contents of the PHV's expression, only add
    1198             :              * to phnullingrels.  This corresponds to assuming that the PHV
    1199             :              * will be evaluated at the same level as before, then perhaps be
    1200             :              * nulled as it bubbles up.  Hence, just flat-copy the node ...
    1201             :              */
    1202           6 :             phv = makeNode(PlaceHolderVar);
    1203           6 :             memcpy(phv, node, sizeof(PlaceHolderVar));
    1204             :             /* ... and replace the copy's phnullingrels field */
    1205           6 :             phv->phnullingrels = newnullingrels;
    1206           6 :             return (Node *) phv;
    1207             :         }
    1208             :         /* Otherwise fall through to copy the PlaceHolderVar normally */
    1209             :     }
    1210       14244 :     else if (IsA(node, Query))
    1211             :     {
    1212             :         /* Recurse into RTE or sublink subquery */
    1213             :         Query      *newnode;
    1214             : 
    1215           0 :         context->sublevels_up++;
    1216           0 :         newnode = query_tree_mutator((Query *) node,
    1217             :                                      add_nulling_relids_mutator,
    1218             :                                      (void *) context,
    1219             :                                      0);
    1220           0 :         context->sublevels_up--;
    1221           0 :         return (Node *) newnode;
    1222             :     }
    1223       18776 :     return expression_tree_mutator(node, add_nulling_relids_mutator,
    1224             :                                    (void *) context);
    1225             : }
    1226             : 
    1227             : /*
    1228             :  * remove_nulling_relids() removes mentions of the specified RT index(es)
    1229             :  * in Var.varnullingrels and PlaceHolderVar.phnullingrels fields within
    1230             :  * the given expression, except in nodes belonging to rels listed in
    1231             :  * except_relids.
    1232             :  */
    1233             : Node *
    1234        7912 : remove_nulling_relids(Node *node,
    1235             :                       const Bitmapset *removable_relids,
    1236             :                       const Bitmapset *except_relids)
    1237             : {
    1238             :     remove_nulling_relids_context context;
    1239             : 
    1240        7912 :     context.removable_relids = removable_relids;
    1241        7912 :     context.except_relids = except_relids;
    1242        7912 :     context.sublevels_up = 0;
    1243        7912 :     return query_or_expression_tree_mutator(node,
    1244             :                                             remove_nulling_relids_mutator,
    1245             :                                             &context,
    1246             :                                             0);
    1247             : }
    1248             : 
    1249             : static Node *
    1250      145066 : remove_nulling_relids_mutator(Node *node,
    1251             :                               remove_nulling_relids_context *context)
    1252             : {
    1253      145066 :     if (node == NULL)
    1254       38690 :         return NULL;
    1255      106376 :     if (IsA(node, Var))
    1256             :     {
    1257       28642 :         Var        *var = (Var *) node;
    1258             : 
    1259       28642 :         if (var->varlevelsup == context->sublevels_up &&
    1260       51150 :             !bms_is_member(var->varno, context->except_relids) &&
    1261       25528 :             bms_overlap(var->varnullingrels, context->removable_relids))
    1262             :         {
    1263             :             /* Copy the Var ... */
    1264        8222 :             var = copyObject(var);
    1265             :             /* ... and replace the copy's varnullingrels field */
    1266        8222 :             var->varnullingrels = bms_difference(var->varnullingrels,
    1267             :                                                  context->removable_relids);
    1268        8222 :             return (Node *) var;
    1269             :         }
    1270             :         /* Otherwise fall through to copy the Var normally */
    1271             :     }
    1272       77734 :     else if (IsA(node, PlaceHolderVar))
    1273             :     {
    1274         438 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
    1275             : 
    1276         438 :         if (phv->phlevelsup == context->sublevels_up &&
    1277         438 :             !bms_overlap(phv->phrels, context->except_relids))
    1278             :         {
    1279             :             /*
    1280             :              * Note: it might seem desirable to remove the PHV altogether if
    1281             :              * phnullingrels goes to empty.  Currently we dare not do that
    1282             :              * because we use PHVs in some cases to enforce separate identity
    1283             :              * of subexpressions; see wrap_non_vars usages in prepjointree.c.
    1284             :              */
    1285             :             /* Copy the PlaceHolderVar and mutate what's below ... */
    1286             :             phv = (PlaceHolderVar *)
    1287         438 :                 expression_tree_mutator(node,
    1288             :                                         remove_nulling_relids_mutator,
    1289             :                                         (void *) context);
    1290             :             /* ... and replace the copy's phnullingrels field */
    1291         438 :             phv->phnullingrels = bms_difference(phv->phnullingrels,
    1292             :                                                 context->removable_relids);
    1293             :             /* We must also update phrels, if it contains a removable RTI */
    1294         438 :             phv->phrels = bms_difference(phv->phrels,
    1295             :                                          context->removable_relids);
    1296             :             Assert(!bms_is_empty(phv->phrels));
    1297         438 :             return (Node *) phv;
    1298             :         }
    1299             :         /* Otherwise fall through to copy the PlaceHolderVar normally */
    1300             :     }
    1301       77296 :     else if (IsA(node, Query))
    1302             :     {
    1303             :         /* Recurse into RTE or sublink subquery */
    1304             :         Query      *newnode;
    1305             : 
    1306         160 :         context->sublevels_up++;
    1307         160 :         newnode = query_tree_mutator((Query *) node,
    1308             :                                      remove_nulling_relids_mutator,
    1309             :                                      (void *) context,
    1310             :                                      0);
    1311         160 :         context->sublevels_up--;
    1312         160 :         return (Node *) newnode;
    1313             :     }
    1314       97556 :     return expression_tree_mutator(node, remove_nulling_relids_mutator,
    1315             :                                    (void *) context);
    1316             : }
    1317             : 
    1318             : 
    1319             : /*
    1320             :  * replace_rte_variables() finds all Vars in an expression tree
    1321             :  * that reference a particular RTE, and replaces them with substitute
    1322             :  * expressions obtained from a caller-supplied callback function.
    1323             :  *
    1324             :  * When invoking replace_rte_variables on a portion of a Query, pass the
    1325             :  * address of the containing Query's hasSubLinks field as outer_hasSubLinks.
    1326             :  * Otherwise, pass NULL, but inserting a SubLink into a non-Query expression
    1327             :  * will then cause an error.
    1328             :  *
    1329             :  * Note: the business with inserted_sublink is needed to update hasSubLinks
    1330             :  * in subqueries when the replacement adds a subquery inside a subquery.
    1331             :  * Messy, isn't it?  We do not need to do similar pushups for hasAggs,
    1332             :  * because it isn't possible for this transformation to insert a level-zero
    1333             :  * aggregate reference into a subquery --- it could only insert outer aggs.
    1334             :  * Likewise for hasWindowFuncs.
    1335             :  *
    1336             :  * Note: usually, we'd not expose the mutator function or context struct
    1337             :  * for a function like this.  We do so because callbacks often find it
    1338             :  * convenient to recurse directly to the mutator on sub-expressions of
    1339             :  * what they will return.
    1340             :  */
    1341             : Node *
    1342      168184 : replace_rte_variables(Node *node, int target_varno, int sublevels_up,
    1343             :                       replace_rte_variables_callback callback,
    1344             :                       void *callback_arg,
    1345             :                       bool *outer_hasSubLinks)
    1346             : {
    1347             :     Node       *result;
    1348             :     replace_rte_variables_context context;
    1349             : 
    1350      168184 :     context.callback = callback;
    1351      168184 :     context.callback_arg = callback_arg;
    1352      168184 :     context.target_varno = target_varno;
    1353      168184 :     context.sublevels_up = sublevels_up;
    1354             : 
    1355             :     /*
    1356             :      * We try to initialize inserted_sublink to true if there is no need to
    1357             :      * detect new sublinks because the query already has some.
    1358             :      */
    1359      168184 :     if (node && IsA(node, Query))
    1360        4604 :         context.inserted_sublink = ((Query *) node)->hasSubLinks;
    1361      163580 :     else if (outer_hasSubLinks)
    1362      163580 :         context.inserted_sublink = *outer_hasSubLinks;
    1363             :     else
    1364           0 :         context.inserted_sublink = false;
    1365             : 
    1366             :     /*
    1367             :      * Must be prepared to start with a Query or a bare expression tree; if
    1368             :      * it's a Query, we don't want to increment sublevels_up.
    1369             :      */
    1370      168184 :     result = query_or_expression_tree_mutator(node,
    1371             :                                               replace_rte_variables_mutator,
    1372             :                                               (void *) &context,
    1373             :                                               0);
    1374             : 
    1375      168178 :     if (context.inserted_sublink)
    1376             :     {
    1377       17236 :         if (result && IsA(result, Query))
    1378          96 :             ((Query *) result)->hasSubLinks = true;
    1379       17140 :         else if (outer_hasSubLinks)
    1380       17140 :             *outer_hasSubLinks = true;
    1381             :         else
    1382           0 :             elog(ERROR, "replace_rte_variables inserted a SubLink, but has noplace to record it");
    1383             :     }
    1384             : 
    1385      168178 :     return result;
    1386             : }
    1387             : 
    1388             : Node *
    1389      749842 : replace_rte_variables_mutator(Node *node,
    1390             :                               replace_rte_variables_context *context)
    1391             : {
    1392      749842 :     if (node == NULL)
    1393      232906 :         return NULL;
    1394      516936 :     if (IsA(node, Var))
    1395             :     {
    1396      189466 :         Var        *var = (Var *) node;
    1397             : 
    1398      189466 :         if (var->varno == context->target_varno &&
    1399      111108 :             var->varlevelsup == context->sublevels_up)
    1400             :         {
    1401             :             /* Found a matching variable, make the substitution */
    1402             :             Node       *newnode;
    1403             : 
    1404      103692 :             newnode = context->callback(var, context);
    1405             :             /* Detect if we are adding a sublink to query */
    1406      103692 :             if (!context->inserted_sublink)
    1407       95244 :                 context->inserted_sublink = checkExprHasSubLink(newnode);
    1408      103692 :             return newnode;
    1409             :         }
    1410             :         /* otherwise fall through to copy the var normally */
    1411             :     }
    1412      327470 :     else if (IsA(node, CurrentOfExpr))
    1413             :     {
    1414           6 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
    1415             : 
    1416           6 :         if (cexpr->cvarno == context->target_varno &&
    1417           6 :             context->sublevels_up == 0)
    1418             :         {
    1419             :             /*
    1420             :              * We get here if a WHERE CURRENT OF expression turns out to apply
    1421             :              * to a view.  Someday we might be able to translate the
    1422             :              * expression to apply to an underlying table of the view, but
    1423             :              * right now it's not implemented.
    1424             :              */
    1425           6 :             ereport(ERROR,
    1426             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1427             :                      errmsg("WHERE CURRENT OF on a view is not implemented")));
    1428             :         }
    1429             :         /* otherwise fall through to copy the expr normally */
    1430             :     }
    1431      327464 :     else if (IsA(node, Query))
    1432             :     {
    1433             :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
    1434             :         Query      *newnode;
    1435             :         bool        save_inserted_sublink;
    1436             : 
    1437        2470 :         context->sublevels_up++;
    1438        2470 :         save_inserted_sublink = context->inserted_sublink;
    1439        2470 :         context->inserted_sublink = ((Query *) node)->hasSubLinks;
    1440        2470 :         newnode = query_tree_mutator((Query *) node,
    1441             :                                      replace_rte_variables_mutator,
    1442             :                                      (void *) context,
    1443             :                                      0);
    1444        2470 :         newnode->hasSubLinks |= context->inserted_sublink;
    1445        2470 :         context->inserted_sublink = save_inserted_sublink;
    1446        2470 :         context->sublevels_up--;
    1447        2470 :         return (Node *) newnode;
    1448             :     }
    1449      410768 :     return expression_tree_mutator(node, replace_rte_variables_mutator,
    1450             :                                    (void *) context);
    1451             : }
    1452             : 
    1453             : 
    1454             : /*
    1455             :  * map_variable_attnos() finds all user-column Vars in an expression tree
    1456             :  * that reference a particular RTE, and adjusts their varattnos according
    1457             :  * to the given mapping array (varattno n is replaced by attno_map[n-1]).
    1458             :  * Vars for system columns are not modified.
    1459             :  *
    1460             :  * A zero in the mapping array represents a dropped column, which should not
    1461             :  * appear in the expression.
    1462             :  *
    1463             :  * If the expression tree contains a whole-row Var for the target RTE,
    1464             :  * *found_whole_row is set to true.  In addition, if to_rowtype is
    1465             :  * not InvalidOid, we replace the Var with a Var of that vartype, inserting
    1466             :  * a ConvertRowtypeExpr to map back to the rowtype expected by the expression.
    1467             :  * (Therefore, to_rowtype had better be a child rowtype of the rowtype of the
    1468             :  * RTE we're changing references to.)  Callers that don't provide to_rowtype
    1469             :  * should report an error if *found_whole_row is true; we don't do that here
    1470             :  * because we don't know exactly what wording for the error message would
    1471             :  * be most appropriate.  The caller will be aware of the context.
    1472             :  *
    1473             :  * This could be built using replace_rte_variables and a callback function,
    1474             :  * but since we don't ever need to insert sublinks, replace_rte_variables is
    1475             :  * overly complicated.
    1476             :  */
    1477             : 
    1478             : typedef struct
    1479             : {
    1480             :     int         target_varno;   /* RTE index to search for */
    1481             :     int         sublevels_up;   /* (current) nesting depth */
    1482             :     const AttrMap *attno_map;   /* map array for user attnos */
    1483             :     Oid         to_rowtype;     /* change whole-row Vars to this type */
    1484             :     bool       *found_whole_row;    /* output flag */
    1485             : } map_variable_attnos_context;
    1486             : 
    1487             : static Node *
    1488      114446 : map_variable_attnos_mutator(Node *node,
    1489             :                             map_variable_attnos_context *context)
    1490             : {
    1491      114446 :     if (node == NULL)
    1492        1104 :         return NULL;
    1493      113342 :     if (IsA(node, Var))
    1494             :     {
    1495       25924 :         Var        *var = (Var *) node;
    1496             : 
    1497       25924 :         if (var->varno == context->target_varno &&
    1498       25708 :             var->varlevelsup == context->sublevels_up)
    1499             :         {
    1500             :             /* Found a matching variable, make the substitution */
    1501       25708 :             Var        *newvar = (Var *) palloc(sizeof(Var));
    1502       25708 :             int         attno = var->varattno;
    1503             : 
    1504       25708 :             *newvar = *var;     /* initially copy all fields of the Var */
    1505             : 
    1506       25708 :             if (attno > 0)
    1507             :             {
    1508             :                 /* user-defined column, replace attno */
    1509       25582 :                 if (attno > context->attno_map->maplen ||
    1510       25582 :                     context->attno_map->attnums[attno - 1] == 0)
    1511           0 :                     elog(ERROR, "unexpected varattno %d in expression to be mapped",
    1512             :                          attno);
    1513       25582 :                 newvar->varattno = context->attno_map->attnums[attno - 1];
    1514             :                 /* If the syntactic referent is same RTE, fix it too */
    1515       25582 :                 if (newvar->varnosyn == context->target_varno)
    1516       25504 :                     newvar->varattnosyn = newvar->varattno;
    1517             :             }
    1518         126 :             else if (attno == 0)
    1519             :             {
    1520             :                 /* whole-row variable, warn caller */
    1521          54 :                 *(context->found_whole_row) = true;
    1522             : 
    1523             :                 /* If the caller expects us to convert the Var, do so. */
    1524          54 :                 if (OidIsValid(context->to_rowtype) &&
    1525          48 :                     context->to_rowtype != var->vartype)
    1526             :                 {
    1527             :                     ConvertRowtypeExpr *r;
    1528             : 
    1529             :                     /* This certainly won't work for a RECORD variable. */
    1530             :                     Assert(var->vartype != RECORDOID);
    1531             : 
    1532             :                     /* Var itself is changed to the requested type. */
    1533          48 :                     newvar->vartype = context->to_rowtype;
    1534             : 
    1535             :                     /*
    1536             :                      * Add a conversion node on top to convert back to the
    1537             :                      * original type expected by the expression.
    1538             :                      */
    1539          48 :                     r = makeNode(ConvertRowtypeExpr);
    1540          48 :                     r->arg = (Expr *) newvar;
    1541          48 :                     r->resulttype = var->vartype;
    1542          48 :                     r->convertformat = COERCE_IMPLICIT_CAST;
    1543          48 :                     r->location = -1;
    1544             : 
    1545          48 :                     return (Node *) r;
    1546             :                 }
    1547             :             }
    1548       25660 :             return (Node *) newvar;
    1549             :         }
    1550             :         /* otherwise fall through to copy the var normally */
    1551             :     }
    1552       87418 :     else if (IsA(node, ConvertRowtypeExpr))
    1553             :     {
    1554          36 :         ConvertRowtypeExpr *r = (ConvertRowtypeExpr *) node;
    1555          36 :         Var        *var = (Var *) r->arg;
    1556             : 
    1557             :         /*
    1558             :          * If this is coercing a whole-row Var that we need to convert, then
    1559             :          * just convert the Var without adding an extra ConvertRowtypeExpr.
    1560             :          * Effectively we're simplifying var::parenttype::grandparenttype into
    1561             :          * just var::grandparenttype.  This avoids building stacks of CREs if
    1562             :          * this function is applied repeatedly.
    1563             :          */
    1564          36 :         if (IsA(var, Var) &&
    1565          24 :             var->varno == context->target_varno &&
    1566          18 :             var->varlevelsup == context->sublevels_up &&
    1567          18 :             var->varattno == 0 &&
    1568          18 :             OidIsValid(context->to_rowtype) &&
    1569          18 :             context->to_rowtype != var->vartype)
    1570             :         {
    1571             :             ConvertRowtypeExpr *newnode;
    1572          18 :             Var        *newvar = (Var *) palloc(sizeof(Var));
    1573             : 
    1574             :             /* whole-row variable, warn caller */
    1575          18 :             *(context->found_whole_row) = true;
    1576             : 
    1577          18 :             *newvar = *var;     /* initially copy all fields of the Var */
    1578             : 
    1579             :             /* This certainly won't work for a RECORD variable. */
    1580             :             Assert(var->vartype != RECORDOID);
    1581             : 
    1582             :             /* Var itself is changed to the requested type. */
    1583          18 :             newvar->vartype = context->to_rowtype;
    1584             : 
    1585          18 :             newnode = (ConvertRowtypeExpr *) palloc(sizeof(ConvertRowtypeExpr));
    1586          18 :             *newnode = *r;      /* initially copy all fields of the CRE */
    1587          18 :             newnode->arg = (Expr *) newvar;
    1588             : 
    1589          18 :             return (Node *) newnode;
    1590             :         }
    1591             :         /* otherwise fall through to process the expression normally */
    1592             :     }
    1593       87382 :     else if (IsA(node, Query))
    1594             :     {
    1595             :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
    1596             :         Query      *newnode;
    1597             : 
    1598           0 :         context->sublevels_up++;
    1599           0 :         newnode = query_tree_mutator((Query *) node,
    1600             :                                      map_variable_attnos_mutator,
    1601             :                                      (void *) context,
    1602             :                                      0);
    1603           0 :         context->sublevels_up--;
    1604           0 :         return (Node *) newnode;
    1605             :     }
    1606       87616 :     return expression_tree_mutator(node, map_variable_attnos_mutator,
    1607             :                                    (void *) context);
    1608             : }
    1609             : 
    1610             : Node *
    1611        9812 : map_variable_attnos(Node *node,
    1612             :                     int target_varno, int sublevels_up,
    1613             :                     const AttrMap *attno_map,
    1614             :                     Oid to_rowtype, bool *found_whole_row)
    1615             : {
    1616             :     map_variable_attnos_context context;
    1617             : 
    1618        9812 :     context.target_varno = target_varno;
    1619        9812 :     context.sublevels_up = sublevels_up;
    1620        9812 :     context.attno_map = attno_map;
    1621        9812 :     context.to_rowtype = to_rowtype;
    1622        9812 :     context.found_whole_row = found_whole_row;
    1623             : 
    1624        9812 :     *found_whole_row = false;
    1625             : 
    1626             :     /*
    1627             :      * Must be prepared to start with a Query or a bare expression tree; if
    1628             :      * it's a Query, we don't want to increment sublevels_up.
    1629             :      */
    1630        9812 :     return query_or_expression_tree_mutator(node,
    1631             :                                             map_variable_attnos_mutator,
    1632             :                                             (void *) &context,
    1633             :                                             0);
    1634             : }
    1635             : 
    1636             : 
    1637             : /*
    1638             :  * ReplaceVarsFromTargetList - replace Vars with items from a targetlist
    1639             :  *
    1640             :  * Vars matching target_varno and sublevels_up are replaced by the
    1641             :  * entry with matching resno from targetlist, if there is one.
    1642             :  *
    1643             :  * If there is no matching resno for such a Var, the action depends on the
    1644             :  * nomatch_option:
    1645             :  *  REPLACEVARS_REPORT_ERROR: throw an error
    1646             :  *  REPLACEVARS_CHANGE_VARNO: change Var's varno to nomatch_varno
    1647             :  *  REPLACEVARS_SUBSTITUTE_NULL: replace Var with a NULL Const of same type
    1648             :  *
    1649             :  * The caller must also provide target_rte, the RTE describing the target
    1650             :  * relation.  This is needed to handle whole-row Vars referencing the target.
    1651             :  * We expand such Vars into RowExpr constructs.
    1652             :  *
    1653             :  * outer_hasSubLinks works the same as for replace_rte_variables().
    1654             :  */
    1655             : 
    1656             : typedef struct
    1657             : {
    1658             :     RangeTblEntry *target_rte;
    1659             :     List       *targetlist;
    1660             :     ReplaceVarsNoMatchOption nomatch_option;
    1661             :     int         nomatch_varno;
    1662             : } ReplaceVarsFromTargetList_context;
    1663             : 
    1664             : static Node *
    1665        8700 : ReplaceVarsFromTargetList_callback(Var *var,
    1666             :                                    replace_rte_variables_context *context)
    1667             : {
    1668        8700 :     ReplaceVarsFromTargetList_context *rcon = (ReplaceVarsFromTargetList_context *) context->callback_arg;
    1669             :     TargetEntry *tle;
    1670             : 
    1671        8700 :     if (var->varattno == InvalidAttrNumber)
    1672             :     {
    1673             :         /* Must expand whole-tuple reference into RowExpr */
    1674             :         RowExpr    *rowexpr;
    1675             :         List       *colnames;
    1676             :         List       *fields;
    1677             : 
    1678             :         /*
    1679             :          * If generating an expansion for a var of a named rowtype (ie, this
    1680             :          * is a plain relation RTE), then we must include dummy items for
    1681             :          * dropped columns.  If the var is RECORD (ie, this is a JOIN), then
    1682             :          * omit dropped columns.  In the latter case, attach column names to
    1683             :          * the RowExpr for use of the executor and ruleutils.c.
    1684             :          */
    1685          54 :         expandRTE(rcon->target_rte,
    1686          54 :                   var->varno, var->varlevelsup, var->location,
    1687          54 :                   (var->vartype != RECORDOID),
    1688             :                   &colnames, &fields);
    1689             :         /* Adjust the generated per-field Vars... */
    1690          54 :         fields = (List *) replace_rte_variables_mutator((Node *) fields,
    1691             :                                                         context);
    1692          54 :         rowexpr = makeNode(RowExpr);
    1693          54 :         rowexpr->args = fields;
    1694          54 :         rowexpr->row_typeid = var->vartype;
    1695          54 :         rowexpr->row_format = COERCE_IMPLICIT_CAST;
    1696          54 :         rowexpr->colnames = (var->vartype == RECORDOID) ? colnames : NIL;
    1697          54 :         rowexpr->location = var->location;
    1698             : 
    1699          54 :         return (Node *) rowexpr;
    1700             :     }
    1701             : 
    1702             :     /* Normal case referencing one targetlist element */
    1703        8646 :     tle = get_tle_by_resno(rcon->targetlist, var->varattno);
    1704             : 
    1705        8646 :     if (tle == NULL || tle->resjunk)
    1706             :     {
    1707             :         /* Failed to find column in targetlist */
    1708         390 :         switch (rcon->nomatch_option)
    1709             :         {
    1710           0 :             case REPLACEVARS_REPORT_ERROR:
    1711             :                 /* fall through, throw error below */
    1712           0 :                 break;
    1713             : 
    1714         240 :             case REPLACEVARS_CHANGE_VARNO:
    1715         240 :                 var = (Var *) copyObject(var);
    1716         240 :                 var->varno = rcon->nomatch_varno;
    1717             :                 /* we leave the syntactic referent alone */
    1718         240 :                 return (Node *) var;
    1719             : 
    1720         150 :             case REPLACEVARS_SUBSTITUTE_NULL:
    1721             : 
    1722             :                 /*
    1723             :                  * If Var is of domain type, we should add a CoerceToDomain
    1724             :                  * node, in case there is a NOT NULL domain constraint.
    1725             :                  */
    1726         150 :                 return coerce_to_domain((Node *) makeNullConst(var->vartype,
    1727             :                                                                var->vartypmod,
    1728             :                                                                var->varcollid),
    1729             :                                         InvalidOid, -1,
    1730             :                                         var->vartype,
    1731             :                                         COERCION_IMPLICIT,
    1732             :                                         COERCE_IMPLICIT_CAST,
    1733             :                                         -1,
    1734             :                                         false);
    1735             :         }
    1736           0 :         elog(ERROR, "could not find replacement targetlist entry for attno %d",
    1737             :              var->varattno);
    1738             :         return NULL;            /* keep compiler quiet */
    1739             :     }
    1740             :     else
    1741             :     {
    1742             :         /* Make a copy of the tlist item to return */
    1743        8256 :         Expr       *newnode = copyObject(tle->expr);
    1744             : 
    1745             :         /* Must adjust varlevelsup if tlist item is from higher query */
    1746        8256 :         if (var->varlevelsup > 0)
    1747         162 :             IncrementVarSublevelsUp((Node *) newnode, var->varlevelsup, 0);
    1748             : 
    1749             :         /*
    1750             :          * Check to see if the tlist item contains a PARAM_MULTIEXPR Param,
    1751             :          * and throw error if so.  This case could only happen when expanding
    1752             :          * an ON UPDATE rule's NEW variable and the referenced tlist item in
    1753             :          * the original UPDATE command is part of a multiple assignment. There
    1754             :          * seems no practical way to handle such cases without multiple
    1755             :          * evaluation of the multiple assignment's sub-select, which would
    1756             :          * create semantic oddities that users of rules would probably prefer
    1757             :          * not to cope with.  So treat it as an unimplemented feature.
    1758             :          */
    1759        8256 :         if (contains_multiexpr_param((Node *) newnode, NULL))
    1760           0 :             ereport(ERROR,
    1761             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1762             :                      errmsg("NEW variables in ON UPDATE rules cannot reference columns that are part of a multiple assignment in the subject UPDATE command")));
    1763             : 
    1764        8256 :         return (Node *) newnode;
    1765             :     }
    1766             : }
    1767             : 
    1768             : Node *
    1769        5854 : ReplaceVarsFromTargetList(Node *node,
    1770             :                           int target_varno, int sublevels_up,
    1771             :                           RangeTblEntry *target_rte,
    1772             :                           List *targetlist,
    1773             :                           ReplaceVarsNoMatchOption nomatch_option,
    1774             :                           int nomatch_varno,
    1775             :                           bool *outer_hasSubLinks)
    1776             : {
    1777             :     ReplaceVarsFromTargetList_context context;
    1778             : 
    1779        5854 :     context.target_rte = target_rte;
    1780        5854 :     context.targetlist = targetlist;
    1781        5854 :     context.nomatch_option = nomatch_option;
    1782        5854 :     context.nomatch_varno = nomatch_varno;
    1783             : 
    1784        5854 :     return replace_rte_variables(node, target_varno, sublevels_up,
    1785             :                                  ReplaceVarsFromTargetList_callback,
    1786             :                                  (void *) &context,
    1787             :                                  outer_hasSubLinks);
    1788             : }

Generated by: LCOV version 1.14