LCOV - code coverage report
Current view: top level - src/backend/rewrite - rewriteManip.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 420 486 86.4 %
Date: 2019-09-19 02:07:14 Functions: 30 31 96.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * rewriteManip.c
       4             :  *
       5             :  * Portions Copyright (c) 1996-2019, 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             : static bool contain_aggs_of_level_walker(Node *node,
      44             :                                          contain_aggs_of_level_context *context);
      45             : static bool locate_agg_of_level_walker(Node *node,
      46             :                                        locate_agg_of_level_context *context);
      47             : static bool contain_windowfuncs_walker(Node *node, void *context);
      48             : static bool locate_windowfunc_walker(Node *node,
      49             :                                      locate_windowfunc_context *context);
      50             : static bool checkExprHasSubLink_walker(Node *node, void *context);
      51             : static Relids offset_relid_set(Relids relids, int offset);
      52             : static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
      53             : 
      54             : 
      55             : /*
      56             :  * contain_aggs_of_level -
      57             :  *  Check if an expression contains an aggregate function call of a
      58             :  *  specified query level.
      59             :  *
      60             :  * The objective of this routine is to detect whether there are aggregates
      61             :  * belonging to the given query level.  Aggregates belonging to subqueries
      62             :  * or outer queries do NOT cause a true result.  We must recurse into
      63             :  * subqueries to detect outer-reference aggregates that logically belong to
      64             :  * the specified query level.
      65             :  */
      66             : bool
      67         420 : contain_aggs_of_level(Node *node, int levelsup)
      68             : {
      69             :     contain_aggs_of_level_context context;
      70             : 
      71         420 :     context.sublevels_up = levelsup;
      72             : 
      73             :     /*
      74             :      * Must be prepared to start with a Query or a bare expression tree; if
      75             :      * it's a Query, we don't want to increment sublevels_up.
      76             :      */
      77         420 :     return query_or_expression_tree_walker(node,
      78             :                                            contain_aggs_of_level_walker,
      79             :                                            (void *) &context,
      80             :                                            0);
      81             : }
      82             : 
      83             : static bool
      84         780 : contain_aggs_of_level_walker(Node *node,
      85             :                              contain_aggs_of_level_context *context)
      86             : {
      87         780 :     if (node == NULL)
      88          92 :         return false;
      89         688 :     if (IsA(node, Aggref))
      90             :     {
      91           0 :         if (((Aggref *) node)->agglevelsup == context->sublevels_up)
      92           0 :             return true;        /* abort the tree traversal and return true */
      93             :         /* else fall through to examine argument */
      94             :     }
      95         688 :     if (IsA(node, GroupingFunc))
      96             :     {
      97           0 :         if (((GroupingFunc *) node)->agglevelsup == context->sublevels_up)
      98           0 :             return true;
      99             :         /* else fall through to examine argument */
     100             :     }
     101         688 :     if (IsA(node, Query))
     102             :     {
     103             :         /* Recurse into subselects */
     104             :         bool        result;
     105             : 
     106           4 :         context->sublevels_up++;
     107           4 :         result = query_tree_walker((Query *) node,
     108             :                                    contain_aggs_of_level_walker,
     109             :                                    (void *) context, 0);
     110           4 :         context->sublevels_up--;
     111           4 :         return result;
     112             :     }
     113         684 :     return expression_tree_walker(node, contain_aggs_of_level_walker,
     114             :                                   (void *) context);
     115             : }
     116             : 
     117             : /*
     118             :  * locate_agg_of_level -
     119             :  *    Find the parse location of any aggregate of the specified query level.
     120             :  *
     121             :  * Returns -1 if no such agg is in the querytree, or if they all have
     122             :  * unknown parse location.  (The former case is probably caller error,
     123             :  * but we don't bother to distinguish it from the latter case.)
     124             :  *
     125             :  * Note: it might seem appropriate to merge this functionality into
     126             :  * contain_aggs_of_level, but that would complicate that function's API.
     127             :  * Currently, the only uses of this function are for error reporting,
     128             :  * and so shaving cycles probably isn't very important.
     129             :  */
     130             : int
     131          20 : locate_agg_of_level(Node *node, int levelsup)
     132             : {
     133             :     locate_agg_of_level_context context;
     134             : 
     135          20 :     context.agg_location = -1;  /* in case we find nothing */
     136          20 :     context.sublevels_up = levelsup;
     137             : 
     138             :     /*
     139             :      * Must be prepared to start with a Query or a bare expression tree; if
     140             :      * it's a Query, we don't want to increment sublevels_up.
     141             :      */
     142          20 :     (void) query_or_expression_tree_walker(node,
     143             :                                            locate_agg_of_level_walker,
     144             :                                            (void *) &context,
     145             :                                            0);
     146             : 
     147          20 :     return context.agg_location;
     148             : }
     149             : 
     150             : static bool
     151          56 : locate_agg_of_level_walker(Node *node,
     152             :                            locate_agg_of_level_context *context)
     153             : {
     154          56 :     if (node == NULL)
     155           0 :         return false;
     156          56 :     if (IsA(node, Aggref))
     157             :     {
     158          40 :         if (((Aggref *) node)->agglevelsup == context->sublevels_up &&
     159          20 :             ((Aggref *) node)->location >= 0)
     160             :         {
     161          20 :             context->agg_location = ((Aggref *) node)->location;
     162          20 :             return true;        /* abort the tree traversal and return true */
     163             :         }
     164             :         /* else fall through to examine argument */
     165             :     }
     166          36 :     if (IsA(node, GroupingFunc))
     167             :     {
     168           0 :         if (((GroupingFunc *) node)->agglevelsup == context->sublevels_up &&
     169           0 :             ((GroupingFunc *) node)->location >= 0)
     170             :         {
     171           0 :             context->agg_location = ((GroupingFunc *) node)->location;
     172           0 :             return true;        /* abort the tree traversal and return true */
     173             :         }
     174             :     }
     175          36 :     if (IsA(node, Query))
     176             :     {
     177             :         /* Recurse into subselects */
     178             :         bool        result;
     179             : 
     180           0 :         context->sublevels_up++;
     181           0 :         result = query_tree_walker((Query *) node,
     182             :                                    locate_agg_of_level_walker,
     183             :                                    (void *) context, 0);
     184           0 :         context->sublevels_up--;
     185           0 :         return result;
     186             :     }
     187          36 :     return expression_tree_walker(node, locate_agg_of_level_walker,
     188             :                                   (void *) context);
     189             : }
     190             : 
     191             : /*
     192             :  * contain_windowfuncs -
     193             :  *  Check if an expression contains a window function call of the
     194             :  *  current query level.
     195             :  */
     196             : bool
     197         892 : contain_windowfuncs(Node *node)
     198             : {
     199             :     /*
     200             :      * Must be prepared to start with a Query or a bare expression tree; if
     201             :      * it's a Query, we don't want to increment sublevels_up.
     202             :      */
     203         892 :     return query_or_expression_tree_walker(node,
     204             :                                            contain_windowfuncs_walker,
     205             :                                            NULL,
     206             :                                            0);
     207             : }
     208             : 
     209             : static bool
     210        1300 : contain_windowfuncs_walker(Node *node, void *context)
     211             : {
     212        1300 :     if (node == NULL)
     213          32 :         return false;
     214        1268 :     if (IsA(node, WindowFunc))
     215           8 :         return true;            /* abort the tree traversal and return true */
     216             :     /* Mustn't recurse into subselects */
     217        1260 :     return expression_tree_walker(node, contain_windowfuncs_walker,
     218             :                                   (void *) context);
     219             : }
     220             : 
     221             : /*
     222             :  * locate_windowfunc -
     223             :  *    Find the parse location of any windowfunc of the current query level.
     224             :  *
     225             :  * Returns -1 if no such windowfunc is in the querytree, or if they all have
     226             :  * unknown parse location.  (The former case is probably caller error,
     227             :  * but we don't bother to distinguish it from the latter case.)
     228             :  *
     229             :  * Note: it might seem appropriate to merge this functionality into
     230             :  * contain_windowfuncs, but that would complicate that function's API.
     231             :  * Currently, the only uses of this function are for error reporting,
     232             :  * and so shaving cycles probably isn't very important.
     233             :  */
     234             : int
     235           4 : locate_windowfunc(Node *node)
     236             : {
     237             :     locate_windowfunc_context context;
     238             : 
     239           4 :     context.win_location = -1;  /* in case we find nothing */
     240             : 
     241             :     /*
     242             :      * Must be prepared to start with a Query or a bare expression tree; if
     243             :      * it's a Query, we don't want to increment sublevels_up.
     244             :      */
     245           4 :     (void) query_or_expression_tree_walker(node,
     246             :                                            locate_windowfunc_walker,
     247             :                                            (void *) &context,
     248             :                                            0);
     249             : 
     250           4 :     return context.win_location;
     251             : }
     252             : 
     253             : static bool
     254           4 : locate_windowfunc_walker(Node *node, locate_windowfunc_context *context)
     255             : {
     256           4 :     if (node == NULL)
     257           0 :         return false;
     258           4 :     if (IsA(node, WindowFunc))
     259             :     {
     260           4 :         if (((WindowFunc *) node)->location >= 0)
     261             :         {
     262           4 :             context->win_location = ((WindowFunc *) node)->location;
     263           4 :             return true;        /* abort the tree traversal and return true */
     264             :         }
     265             :         /* else fall through to examine argument */
     266             :     }
     267             :     /* Mustn't recurse into subselects */
     268           0 :     return expression_tree_walker(node, locate_windowfunc_walker,
     269             :                                   (void *) context);
     270             : }
     271             : 
     272             : /*
     273             :  * checkExprHasSubLink -
     274             :  *  Check if an expression contains a SubLink.
     275             :  */
     276             : bool
     277      130012 : checkExprHasSubLink(Node *node)
     278             : {
     279             :     /*
     280             :      * If a Query is passed, examine it --- but we should not recurse into
     281             :      * sub-Queries that are in its rangetable or CTE list.
     282             :      */
     283      130012 :     return query_or_expression_tree_walker(node,
     284             :                                            checkExprHasSubLink_walker,
     285             :                                            NULL,
     286             :                                            QTW_IGNORE_RC_SUBQUERIES);
     287             : }
     288             : 
     289             : static bool
     290      167002 : checkExprHasSubLink_walker(Node *node, void *context)
     291             : {
     292      167002 :     if (node == NULL)
     293        2036 :         return false;
     294      164966 :     if (IsA(node, SubLink))
     295        3330 :         return true;            /* abort the tree traversal and return true */
     296      161636 :     return expression_tree_walker(node, checkExprHasSubLink_walker, context);
     297             : }
     298             : 
     299             : /*
     300             :  * Check for MULTIEXPR Param within expression tree
     301             :  *
     302             :  * We intentionally don't descend into SubLinks: only Params at the current
     303             :  * query level are of interest.
     304             :  */
     305             : static bool
     306        5060 : contains_multiexpr_param(Node *node, void *context)
     307             : {
     308        5060 :     if (node == NULL)
     309          12 :         return false;
     310        5048 :     if (IsA(node, Param))
     311             :     {
     312           0 :         if (((Param *) node)->paramkind == PARAM_MULTIEXPR)
     313           0 :             return true;        /* abort the tree traversal and return true */
     314           0 :         return false;
     315             :     }
     316        5048 :     return expression_tree_walker(node, contains_multiexpr_param, context);
     317             : }
     318             : 
     319             : 
     320             : /*
     321             :  * OffsetVarNodes - adjust Vars when appending one query's RT to another
     322             :  *
     323             :  * Find all Var nodes in the given tree with varlevelsup == sublevels_up,
     324             :  * and increment their varno fields (rangetable indexes) by 'offset'.
     325             :  * The varnoold fields are adjusted similarly.  Also, adjust other nodes
     326             :  * that contain rangetable indexes, such as RangeTblRef and JoinExpr.
     327             :  *
     328             :  * NOTE: although this has the form of a walker, we cheat and modify the
     329             :  * nodes in-place.  The given expression tree should have been copied
     330             :  * earlier to ensure that no unwanted side-effects occur!
     331             :  */
     332             : 
     333             : typedef struct
     334             : {
     335             :     int         offset;
     336             :     int         sublevels_up;
     337             : } OffsetVarNodes_context;
     338             : 
     339             : static bool
     340     8940448 : OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
     341             : {
     342     8940448 :     if (node == NULL)
     343     1919144 :         return false;
     344     7021304 :     if (IsA(node, Var))
     345             :     {
     346     3700318 :         Var        *var = (Var *) node;
     347             : 
     348     3700318 :         if (var->varlevelsup == context->sublevels_up)
     349             :         {
     350     2930260 :             var->varno += context->offset;
     351     2930260 :             var->varnoold += context->offset;
     352             :         }
     353     3700318 :         return false;
     354             :     }
     355     3320986 :     if (IsA(node, CurrentOfExpr))
     356             :     {
     357           0 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
     358             : 
     359           0 :         if (context->sublevels_up == 0)
     360           0 :             cexpr->cvarno += context->offset;
     361           0 :         return false;
     362             :     }
     363     3320986 :     if (IsA(node, RangeTblRef))
     364             :     {
     365      243428 :         RangeTblRef *rtr = (RangeTblRef *) node;
     366             : 
     367      243428 :         if (context->sublevels_up == 0)
     368      176866 :             rtr->rtindex += context->offset;
     369             :         /* the subquery itself is visited separately */
     370      243428 :         return false;
     371             :     }
     372     3077558 :     if (IsA(node, JoinExpr))
     373             :     {
     374       65498 :         JoinExpr   *j = (JoinExpr *) node;
     375             : 
     376       65498 :         if (j->rtindex && context->sublevels_up == 0)
     377       47312 :             j->rtindex += context->offset;
     378             :         /* fall through to examine children */
     379             :     }
     380     3077558 :     if (IsA(node, PlaceHolderVar))
     381             :     {
     382         224 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
     383             : 
     384         224 :         if (phv->phlevelsup == context->sublevels_up)
     385             :         {
     386         184 :             phv->phrels = offset_relid_set(phv->phrels,
     387             :                                            context->offset);
     388             :         }
     389             :         /* fall through to examine children */
     390             :     }
     391     3077558 :     if (IsA(node, AppendRelInfo))
     392             :     {
     393         240 :         AppendRelInfo *appinfo = (AppendRelInfo *) node;
     394             : 
     395         240 :         if (context->sublevels_up == 0)
     396             :         {
     397         240 :             appinfo->parent_relid += context->offset;
     398         240 :             appinfo->child_relid += context->offset;
     399             :         }
     400             :         /* fall through to examine children */
     401             :     }
     402             :     /* Shouldn't need to handle other planner auxiliary nodes here */
     403             :     Assert(!IsA(node, PlanRowMark));
     404             :     Assert(!IsA(node, SpecialJoinInfo));
     405             :     Assert(!IsA(node, PlaceHolderInfo));
     406             :     Assert(!IsA(node, MinMaxAggInfo));
     407             : 
     408     3077558 :     if (IsA(node, Query))
     409             :     {
     410             :         /* Recurse into subselects */
     411             :         bool        result;
     412             : 
     413       40676 :         context->sublevels_up++;
     414       40676 :         result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
     415             :                                    (void *) context, 0);
     416       40676 :         context->sublevels_up--;
     417       40676 :         return result;
     418             :     }
     419     3036882 :     return expression_tree_walker(node, OffsetVarNodes_walker,
     420             :                                   (void *) context);
     421             : }
     422             : 
     423             : void
     424      133658 : OffsetVarNodes(Node *node, int offset, int sublevels_up)
     425             : {
     426             :     OffsetVarNodes_context context;
     427             : 
     428      133658 :     context.offset = offset;
     429      133658 :     context.sublevels_up = sublevels_up;
     430             : 
     431             :     /*
     432             :      * Must be prepared to start with a Query or a bare expression tree; if
     433             :      * it's a Query, go straight to query_tree_walker to make sure that
     434             :      * sublevels_up doesn't get incremented prematurely.
     435             :      */
     436      133658 :     if (node && IsA(node, Query))
     437       87484 :     {
     438       87484 :         Query      *qry = (Query *) node;
     439             : 
     440             :         /*
     441             :          * If we are starting at a Query, and sublevels_up is zero, then we
     442             :          * must also fix rangetable indexes in the Query itself --- namely
     443             :          * resultRelation, exclRelIndex and rowMarks entries.  sublevels_up
     444             :          * cannot be zero when recursing into a subquery, so there's no need
     445             :          * to have the same logic inside OffsetVarNodes_walker.
     446             :          */
     447       87484 :         if (sublevels_up == 0)
     448             :         {
     449             :             ListCell   *l;
     450             : 
     451       87484 :             if (qry->resultRelation)
     452         776 :                 qry->resultRelation += offset;
     453             : 
     454       87484 :             if (qry->onConflict && qry->onConflict->exclRelIndex)
     455          24 :                 qry->onConflict->exclRelIndex += offset;
     456             : 
     457       87576 :             foreach(l, qry->rowMarks)
     458             :             {
     459          92 :                 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
     460             : 
     461          92 :                 rc->rti += offset;
     462             :             }
     463             :         }
     464       87484 :         query_tree_walker(qry, OffsetVarNodes_walker,
     465             :                           (void *) &context, 0);
     466             :     }
     467             :     else
     468       46174 :         OffsetVarNodes_walker(node, &context);
     469      133658 : }
     470             : 
     471             : static Relids
     472         184 : offset_relid_set(Relids relids, int offset)
     473             : {
     474         184 :     Relids      result = NULL;
     475             :     int         rtindex;
     476             : 
     477         184 :     rtindex = -1;
     478         584 :     while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
     479         216 :         result = bms_add_member(result, rtindex + offset);
     480         184 :     return result;
     481             : }
     482             : 
     483             : /*
     484             :  * ChangeVarNodes - adjust Var nodes for a specific change of RT index
     485             :  *
     486             :  * Find all Var nodes in the given tree belonging to a specific relation
     487             :  * (identified by sublevels_up and rt_index), and change their varno fields
     488             :  * to 'new_index'.  The varnoold fields are changed too.  Also, adjust other
     489             :  * nodes that contain rangetable indexes, such as RangeTblRef and JoinExpr.
     490             :  *
     491             :  * NOTE: although this has the form of a walker, we cheat and modify the
     492             :  * nodes in-place.  The given expression tree should have been copied
     493             :  * earlier to ensure that no unwanted side-effects occur!
     494             :  */
     495             : 
     496             : typedef struct
     497             : {
     498             :     int         rt_index;
     499             :     int         new_index;
     500             :     int         sublevels_up;
     501             : } ChangeVarNodes_context;
     502             : 
     503             : static bool
     504      167034 : ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
     505             : {
     506      167034 :     if (node == NULL)
     507       65612 :         return false;
     508      101422 :     if (IsA(node, Var))
     509             :     {
     510       25076 :         Var        *var = (Var *) node;
     511             : 
     512       47240 :         if (var->varlevelsup == context->sublevels_up &&
     513       22164 :             var->varno == context->rt_index)
     514             :         {
     515       16516 :             var->varno = context->new_index;
     516       16516 :             var->varnoold = context->new_index;
     517             :         }
     518       25076 :         return false;
     519             :     }
     520       76346 :     if (IsA(node, CurrentOfExpr))
     521             :     {
     522           0 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
     523             : 
     524           0 :         if (context->sublevels_up == 0 &&
     525           0 :             cexpr->cvarno == context->rt_index)
     526           0 :             cexpr->cvarno = context->new_index;
     527           0 :         return false;
     528             :     }
     529       76346 :     if (IsA(node, RangeTblRef))
     530             :     {
     531        4628 :         RangeTblRef *rtr = (RangeTblRef *) node;
     532             : 
     533        6132 :         if (context->sublevels_up == 0 &&
     534        1504 :             rtr->rtindex == context->rt_index)
     535         896 :             rtr->rtindex = context->new_index;
     536             :         /* the subquery itself is visited separately */
     537        4628 :         return false;
     538             :     }
     539       71718 :     if (IsA(node, JoinExpr))
     540             :     {
     541          32 :         JoinExpr   *j = (JoinExpr *) node;
     542             : 
     543          64 :         if (context->sublevels_up == 0 &&
     544          32 :             j->rtindex == context->rt_index)
     545           0 :             j->rtindex = context->new_index;
     546             :         /* fall through to examine children */
     547             :     }
     548       71718 :     if (IsA(node, PlaceHolderVar))
     549             :     {
     550           0 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
     551             : 
     552           0 :         if (phv->phlevelsup == context->sublevels_up)
     553             :         {
     554           0 :             phv->phrels = adjust_relid_set(phv->phrels,
     555             :                                            context->rt_index,
     556             :                                            context->new_index);
     557             :         }
     558             :         /* fall through to examine children */
     559             :     }
     560       71718 :     if (IsA(node, PlanRowMark))
     561             :     {
     562         208 :         PlanRowMark *rowmark = (PlanRowMark *) node;
     563             : 
     564         208 :         if (context->sublevels_up == 0)
     565             :         {
     566         208 :             if (rowmark->rti == context->rt_index)
     567          96 :                 rowmark->rti = context->new_index;
     568         208 :             if (rowmark->prti == context->rt_index)
     569          96 :                 rowmark->prti = context->new_index;
     570             :         }
     571         208 :         return false;
     572             :     }
     573       71510 :     if (IsA(node, AppendRelInfo))
     574             :     {
     575         248 :         AppendRelInfo *appinfo = (AppendRelInfo *) node;
     576             : 
     577         248 :         if (context->sublevels_up == 0)
     578             :         {
     579         248 :             if (appinfo->parent_relid == context->rt_index)
     580          72 :                 appinfo->parent_relid = context->new_index;
     581         248 :             if (appinfo->child_relid == context->rt_index)
     582          16 :                 appinfo->child_relid = context->new_index;
     583             :         }
     584             :         /* fall through to examine children */
     585             :     }
     586             :     /* Shouldn't need to handle other planner auxiliary nodes here */
     587             :     Assert(!IsA(node, SpecialJoinInfo));
     588             :     Assert(!IsA(node, PlaceHolderInfo));
     589             :     Assert(!IsA(node, MinMaxAggInfo));
     590             : 
     591       71510 :     if (IsA(node, Query))
     592             :     {
     593             :         /* Recurse into subselects */
     594             :         bool        result;
     595             : 
     596        2752 :         context->sublevels_up++;
     597        2752 :         result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
     598             :                                    (void *) context, 0);
     599        2752 :         context->sublevels_up--;
     600        2752 :         return result;
     601             :     }
     602       68758 :     return expression_tree_walker(node, ChangeVarNodes_walker,
     603             :                                   (void *) context);
     604             : }
     605             : 
     606             : void
     607       12358 : ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
     608             : {
     609             :     ChangeVarNodes_context context;
     610             : 
     611       12358 :     context.rt_index = rt_index;
     612       12358 :     context.new_index = new_index;
     613       12358 :     context.sublevels_up = sublevels_up;
     614             : 
     615             :     /*
     616             :      * Must be prepared to start with a Query or a bare expression tree; if
     617             :      * it's a Query, go straight to query_tree_walker to make sure that
     618             :      * sublevels_up doesn't get incremented prematurely.
     619             :      */
     620       12358 :     if (node && IsA(node, Query))
     621        2168 :     {
     622        2168 :         Query      *qry = (Query *) node;
     623             : 
     624             :         /*
     625             :          * If we are starting at a Query, and sublevels_up is zero, then we
     626             :          * must also fix rangetable indexes in the Query itself --- namely
     627             :          * resultRelation and rowMarks entries.  sublevels_up cannot be zero
     628             :          * when recursing into a subquery, so there's no need to have the same
     629             :          * logic inside ChangeVarNodes_walker.
     630             :          */
     631        2168 :         if (sublevels_up == 0)
     632             :         {
     633             :             ListCell   *l;
     634             : 
     635        2168 :             if (qry->resultRelation == rt_index)
     636        1168 :                 qry->resultRelation = new_index;
     637             : 
     638             :             /* this is unlikely to ever be used, but ... */
     639        2168 :             if (qry->onConflict && qry->onConflict->exclRelIndex == rt_index)
     640           0 :                 qry->onConflict->exclRelIndex = new_index;
     641             : 
     642        2168 :             foreach(l, qry->rowMarks)
     643             :             {
     644           0 :                 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
     645             : 
     646           0 :                 if (rc->rti == rt_index)
     647           0 :                     rc->rti = new_index;
     648             :             }
     649             :         }
     650        2168 :         query_tree_walker(qry, ChangeVarNodes_walker,
     651             :                           (void *) &context, 0);
     652             :     }
     653             :     else
     654       10190 :         ChangeVarNodes_walker(node, &context);
     655       12358 : }
     656             : 
     657             : /*
     658             :  * Substitute newrelid for oldrelid in a Relid set
     659             :  */
     660             : static Relids
     661           0 : adjust_relid_set(Relids relids, int oldrelid, int newrelid)
     662             : {
     663           0 :     if (bms_is_member(oldrelid, relids))
     664             :     {
     665             :         /* Ensure we have a modifiable copy */
     666           0 :         relids = bms_copy(relids);
     667             :         /* Remove old, add new */
     668           0 :         relids = bms_del_member(relids, oldrelid);
     669           0 :         relids = bms_add_member(relids, newrelid);
     670             :     }
     671           0 :     return relids;
     672             : }
     673             : 
     674             : /*
     675             :  * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
     676             :  *
     677             :  * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
     678             :  * and add delta_sublevels_up to their varlevelsup value.  This is needed when
     679             :  * an expression that's correct for some nesting level is inserted into a
     680             :  * subquery.  Ordinarily the initial call has min_sublevels_up == 0 so that
     681             :  * all Vars are affected.  The point of min_sublevels_up is that we can
     682             :  * increment it when we recurse into a sublink, so that local variables in
     683             :  * that sublink are not affected, only outer references to vars that belong
     684             :  * to the expression's original query level or parents thereof.
     685             :  *
     686             :  * Likewise for other nodes containing levelsup fields, such as Aggref.
     687             :  *
     688             :  * NOTE: although this has the form of a walker, we cheat and modify the
     689             :  * Var nodes in-place.  The given expression tree should have been copied
     690             :  * earlier to ensure that no unwanted side-effects occur!
     691             :  */
     692             : 
     693             : typedef struct
     694             : {
     695             :     int         delta_sublevels_up;
     696             :     int         min_sublevels_up;
     697             : } IncrementVarSublevelsUp_context;
     698             : 
     699             : static bool
     700     2547756 : IncrementVarSublevelsUp_walker(Node *node,
     701             :                                IncrementVarSublevelsUp_context *context)
     702             : {
     703     2547756 :     if (node == NULL)
     704      746204 :         return false;
     705     1801552 :     if (IsA(node, Var))
     706             :     {
     707      714294 :         Var        *var = (Var *) node;
     708             : 
     709      714294 :         if (var->varlevelsup >= context->min_sublevels_up)
     710       55194 :             var->varlevelsup += context->delta_sublevels_up;
     711      714294 :         return false;           /* done here */
     712             :     }
     713     1087258 :     if (IsA(node, CurrentOfExpr))
     714             :     {
     715             :         /* this should not happen */
     716           0 :         if (context->min_sublevels_up == 0)
     717           0 :             elog(ERROR, "cannot push down CurrentOfExpr");
     718           0 :         return false;
     719             :     }
     720     1087258 :     if (IsA(node, Aggref))
     721             :     {
     722        1446 :         Aggref     *agg = (Aggref *) node;
     723             : 
     724        1446 :         if (agg->agglevelsup >= context->min_sublevels_up)
     725          44 :             agg->agglevelsup += context->delta_sublevels_up;
     726             :         /* fall through to recurse into argument */
     727             :     }
     728     1087258 :     if (IsA(node, GroupingFunc))
     729             :     {
     730          16 :         GroupingFunc *grp = (GroupingFunc *) node;
     731             : 
     732          16 :         if (grp->agglevelsup >= context->min_sublevels_up)
     733          16 :             grp->agglevelsup += context->delta_sublevels_up;
     734             :         /* fall through to recurse into argument */
     735             :     }
     736     1087258 :     if (IsA(node, PlaceHolderVar))
     737             :     {
     738         368 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
     739             : 
     740         368 :         if (phv->phlevelsup >= context->min_sublevels_up)
     741         184 :             phv->phlevelsup += context->delta_sublevels_up;
     742             :         /* fall through to recurse into argument */
     743             :     }
     744     1087258 :     if (IsA(node, RangeTblEntry))
     745             :     {
     746      123064 :         RangeTblEntry *rte = (RangeTblEntry *) node;
     747             : 
     748      123064 :         if (rte->rtekind == RTE_CTE)
     749             :         {
     750        1004 :             if (rte->ctelevelsup >= context->min_sublevels_up)
     751        1004 :                 rte->ctelevelsup += context->delta_sublevels_up;
     752             :         }
     753      123064 :         return false;           /* allow range_table_walker to continue */
     754             :     }
     755      964194 :     if (IsA(node, Query))
     756             :     {
     757             :         /* Recurse into subselects */
     758             :         bool        result;
     759             : 
     760        7940 :         context->min_sublevels_up++;
     761        7940 :         result = query_tree_walker((Query *) node,
     762             :                                    IncrementVarSublevelsUp_walker,
     763             :                                    (void *) context,
     764             :                                    QTW_EXAMINE_RTES_BEFORE);
     765        7940 :         context->min_sublevels_up--;
     766        7940 :         return result;
     767             :     }
     768      956254 :     return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
     769             :                                   (void *) context);
     770             : }
     771             : 
     772             : void
     773      102334 : IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
     774             :                         int min_sublevels_up)
     775             : {
     776             :     IncrementVarSublevelsUp_context context;
     777             : 
     778      102334 :     context.delta_sublevels_up = delta_sublevels_up;
     779      102334 :     context.min_sublevels_up = min_sublevels_up;
     780             : 
     781             :     /*
     782             :      * Must be prepared to start with a Query or a bare expression tree; if
     783             :      * it's a Query, we don't want to increment sublevels_up.
     784             :      */
     785      102334 :     query_or_expression_tree_walker(node,
     786             :                                     IncrementVarSublevelsUp_walker,
     787             :                                     (void *) &context,
     788             :                                     QTW_EXAMINE_RTES_BEFORE);
     789      102334 : }
     790             : 
     791             : /*
     792             :  * IncrementVarSublevelsUp_rtable -
     793             :  *  Same as IncrementVarSublevelsUp, but to be invoked on a range table.
     794             :  */
     795             : void
     796         674 : IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up,
     797             :                                int min_sublevels_up)
     798             : {
     799             :     IncrementVarSublevelsUp_context context;
     800             : 
     801         674 :     context.delta_sublevels_up = delta_sublevels_up;
     802         674 :     context.min_sublevels_up = min_sublevels_up;
     803             : 
     804         674 :     range_table_walker(rtable,
     805             :                        IncrementVarSublevelsUp_walker,
     806             :                        (void *) &context,
     807             :                        QTW_EXAMINE_RTES_BEFORE);
     808         674 : }
     809             : 
     810             : 
     811             : /*
     812             :  * rangeTableEntry_used - detect whether an RTE is referenced somewhere
     813             :  *  in var nodes or join or setOp trees of a query or expression.
     814             :  */
     815             : 
     816             : typedef struct
     817             : {
     818             :     int         rt_index;
     819             :     int         sublevels_up;
     820             : } rangeTableEntry_used_context;
     821             : 
     822             : static bool
     823     5240858 : rangeTableEntry_used_walker(Node *node,
     824             :                             rangeTableEntry_used_context *context)
     825             : {
     826     5240858 :     if (node == NULL)
     827      941932 :         return false;
     828     4298926 :     if (IsA(node, Var))
     829             :     {
     830     1781076 :         Var        *var = (Var *) node;
     831             : 
     832     3496904 :         if (var->varlevelsup == context->sublevels_up &&
     833     1715828 :             var->varno == context->rt_index)
     834      181524 :             return true;
     835     1599552 :         return false;
     836             :     }
     837     2517850 :     if (IsA(node, CurrentOfExpr))
     838             :     {
     839           8 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
     840             : 
     841          16 :         if (context->sublevels_up == 0 &&
     842           8 :             cexpr->cvarno == context->rt_index)
     843           0 :             return true;
     844           8 :         return false;
     845             :     }
     846     2517842 :     if (IsA(node, RangeTblRef))
     847             :     {
     848      147550 :         RangeTblRef *rtr = (RangeTblRef *) node;
     849             : 
     850      187242 :         if (rtr->rtindex == context->rt_index &&
     851       39692 :             context->sublevels_up == 0)
     852       37364 :             return true;
     853             :         /* the subquery itself is visited separately */
     854      110186 :         return false;
     855             :     }
     856     2370292 :     if (IsA(node, JoinExpr))
     857             :     {
     858       62770 :         JoinExpr   *j = (JoinExpr *) node;
     859             : 
     860       62770 :         if (j->rtindex == context->rt_index &&
     861           0 :             context->sublevels_up == 0)
     862           0 :             return true;
     863             :         /* fall through to examine children */
     864             :     }
     865             :     /* Shouldn't need to handle planner auxiliary nodes here */
     866             :     Assert(!IsA(node, PlaceHolderVar));
     867             :     Assert(!IsA(node, PlanRowMark));
     868             :     Assert(!IsA(node, SpecialJoinInfo));
     869             :     Assert(!IsA(node, AppendRelInfo));
     870             :     Assert(!IsA(node, PlaceHolderInfo));
     871             :     Assert(!IsA(node, MinMaxAggInfo));
     872             : 
     873     2370292 :     if (IsA(node, Query))
     874             :     {
     875             :         /* Recurse into subselects */
     876             :         bool        result;
     877             : 
     878       23726 :         context->sublevels_up++;
     879       23726 :         result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
     880             :                                    (void *) context, 0);
     881       23726 :         context->sublevels_up--;
     882       23726 :         return result;
     883             :     }
     884     2346566 :     return expression_tree_walker(node, rangeTableEntry_used_walker,
     885             :                                   (void *) context);
     886             : }
     887             : 
     888             : bool
     889      255998 : rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
     890             : {
     891             :     rangeTableEntry_used_context context;
     892             : 
     893      255998 :     context.rt_index = rt_index;
     894      255998 :     context.sublevels_up = sublevels_up;
     895             : 
     896             :     /*
     897             :      * Must be prepared to start with a Query or a bare expression tree; if
     898             :      * it's a Query, we don't want to increment sublevels_up.
     899             :      */
     900      255998 :     return query_or_expression_tree_walker(node,
     901             :                                            rangeTableEntry_used_walker,
     902             :                                            (void *) &context,
     903             :                                            0);
     904             : }
     905             : 
     906             : 
     907             : /*
     908             :  * If the given Query is an INSERT ... SELECT construct, extract and
     909             :  * return the sub-Query node that represents the SELECT part.  Otherwise
     910             :  * return the given Query.
     911             :  *
     912             :  * If subquery_ptr is not NULL, then *subquery_ptr is set to the location
     913             :  * of the link to the SELECT subquery inside parsetree, or NULL if not an
     914             :  * INSERT ... SELECT.
     915             :  *
     916             :  * This is a hack needed because transformations on INSERT ... SELECTs that
     917             :  * appear in rule actions should be applied to the source SELECT, not to the
     918             :  * INSERT part.  Perhaps this can be cleaned up with redesigned querytrees.
     919             :  */
     920             : Query *
     921        2576 : getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
     922             : {
     923             :     Query      *selectquery;
     924             :     RangeTblEntry *selectrte;
     925             :     RangeTblRef *rtr;
     926             : 
     927        2576 :     if (subquery_ptr)
     928         808 :         *subquery_ptr = NULL;
     929             : 
     930        2576 :     if (parsetree == NULL)
     931           0 :         return parsetree;
     932        2576 :     if (parsetree->commandType != CMD_INSERT)
     933        1384 :         return parsetree;
     934             : 
     935             :     /*
     936             :      * Currently, this is ONLY applied to rule-action queries, and so we
     937             :      * expect to find the OLD and NEW placeholder entries in the given query.
     938             :      * If they're not there, it must be an INSERT/SELECT in which they've been
     939             :      * pushed down to the SELECT.
     940             :      */
     941        2384 :     if (list_length(parsetree->rtable) >= 2 &&
     942        1192 :         strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
     943        1120 :                "old") == 0 &&
     944        1120 :         strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
     945             :                "new") == 0)
     946        1120 :         return parsetree;
     947             :     Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
     948          72 :     if (list_length(parsetree->jointree->fromlist) != 1)
     949           0 :         elog(ERROR, "expected to find SELECT subquery");
     950          72 :     rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
     951             :     Assert(IsA(rtr, RangeTblRef));
     952          72 :     selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
     953          72 :     selectquery = selectrte->subquery;
     954         144 :     if (!(selectquery && IsA(selectquery, Query) &&
     955          72 :           selectquery->commandType == CMD_SELECT))
     956           0 :         elog(ERROR, "expected to find SELECT subquery");
     957         144 :     if (list_length(selectquery->rtable) >= 2 &&
     958          72 :         strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
     959          72 :                "old") == 0 &&
     960          72 :         strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
     961             :                "new") == 0)
     962             :     {
     963          72 :         if (subquery_ptr)
     964          28 :             *subquery_ptr = &(selectrte->subquery);
     965          72 :         return selectquery;
     966             :     }
     967           0 :     elog(ERROR, "could not find rule placeholders");
     968             :     return NULL;                /* not reached */
     969             : }
     970             : 
     971             : 
     972             : /*
     973             :  * Add the given qualifier condition to the query's WHERE clause
     974             :  */
     975             : void
     976        2104 : AddQual(Query *parsetree, Node *qual)
     977             : {
     978             :     Node       *copy;
     979             : 
     980        2104 :     if (qual == NULL)
     981         984 :         return;
     982             : 
     983        1120 :     if (parsetree->commandType == CMD_UTILITY)
     984             :     {
     985             :         /*
     986             :          * There's noplace to put the qual on a utility statement.
     987             :          *
     988             :          * If it's a NOTIFY, silently ignore the qual; this means that the
     989             :          * NOTIFY will execute, whether or not there are any qualifying rows.
     990             :          * While clearly wrong, this is much more useful than refusing to
     991             :          * execute the rule at all, and extra NOTIFY events are harmless for
     992             :          * typical uses of NOTIFY.
     993             :          *
     994             :          * If it isn't a NOTIFY, error out, since unconditional execution of
     995             :          * other utility stmts is unlikely to be wanted.  (This case is not
     996             :          * currently allowed anyway, but keep the test for safety.)
     997             :          */
     998           0 :         if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
     999           0 :             return;
    1000             :         else
    1001           0 :             ereport(ERROR,
    1002             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1003             :                      errmsg("conditional utility statements are not implemented")));
    1004             :     }
    1005             : 
    1006        1120 :     if (parsetree->setOperations != NULL)
    1007             :     {
    1008             :         /*
    1009             :          * There's noplace to put the qual on a setop statement, either. (This
    1010             :          * could be fixed, but right now the planner simply ignores any qual
    1011             :          * condition on a setop query.)
    1012             :          */
    1013           0 :         ereport(ERROR,
    1014             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1015             :                  errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
    1016             :     }
    1017             : 
    1018             :     /* INTERSECT wants the original, but we need to copy - Jan */
    1019        1120 :     copy = copyObject(qual);
    1020             : 
    1021        1120 :     parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
    1022             :                                                copy);
    1023             : 
    1024             :     /*
    1025             :      * We had better not have stuck an aggregate into the WHERE clause.
    1026             :      */
    1027             :     Assert(!contain_aggs_of_level(copy, 0));
    1028             : 
    1029             :     /*
    1030             :      * Make sure query is marked correctly if added qual has sublinks. Need
    1031             :      * not search qual when query is already marked.
    1032             :      */
    1033        1120 :     if (!parsetree->hasSubLinks)
    1034        1116 :         parsetree->hasSubLinks = checkExprHasSubLink(copy);
    1035             : }
    1036             : 
    1037             : 
    1038             : /*
    1039             :  * Invert the given clause and add it to the WHERE qualifications of the
    1040             :  * given querytree.  Inversion means "x IS NOT TRUE", not just "NOT x",
    1041             :  * else we will do the wrong thing when x evaluates to NULL.
    1042             :  */
    1043             : void
    1044         284 : AddInvertedQual(Query *parsetree, Node *qual)
    1045             : {
    1046             :     BooleanTest *invqual;
    1047             : 
    1048         284 :     if (qual == NULL)
    1049           0 :         return;
    1050             : 
    1051             :     /* Need not copy input qual, because AddQual will... */
    1052         284 :     invqual = makeNode(BooleanTest);
    1053         284 :     invqual->arg = (Expr *) qual;
    1054         284 :     invqual->booltesttype = IS_NOT_TRUE;
    1055         284 :     invqual->location = -1;
    1056             : 
    1057         284 :     AddQual(parsetree, (Node *) invqual);
    1058             : }
    1059             : 
    1060             : 
    1061             : /*
    1062             :  * replace_rte_variables() finds all Vars in an expression tree
    1063             :  * that reference a particular RTE, and replaces them with substitute
    1064             :  * expressions obtained from a caller-supplied callback function.
    1065             :  *
    1066             :  * When invoking replace_rte_variables on a portion of a Query, pass the
    1067             :  * address of the containing Query's hasSubLinks field as outer_hasSubLinks.
    1068             :  * Otherwise, pass NULL, but inserting a SubLink into a non-Query expression
    1069             :  * will then cause an error.
    1070             :  *
    1071             :  * Note: the business with inserted_sublink is needed to update hasSubLinks
    1072             :  * in subqueries when the replacement adds a subquery inside a subquery.
    1073             :  * Messy, isn't it?  We do not need to do similar pushups for hasAggs,
    1074             :  * because it isn't possible for this transformation to insert a level-zero
    1075             :  * aggregate reference into a subquery --- it could only insert outer aggs.
    1076             :  * Likewise for hasWindowFuncs.
    1077             :  *
    1078             :  * Note: usually, we'd not expose the mutator function or context struct
    1079             :  * for a function like this.  We do so because callbacks often find it
    1080             :  * convenient to recurse directly to the mutator on sub-expressions of
    1081             :  * what they will return.
    1082             :  */
    1083             : Node *
    1084      166218 : replace_rte_variables(Node *node, int target_varno, int sublevels_up,
    1085             :                       replace_rte_variables_callback callback,
    1086             :                       void *callback_arg,
    1087             :                       bool *outer_hasSubLinks)
    1088             : {
    1089             :     Node       *result;
    1090             :     replace_rte_variables_context context;
    1091             : 
    1092      166218 :     context.callback = callback;
    1093      166218 :     context.callback_arg = callback_arg;
    1094      166218 :     context.target_varno = target_varno;
    1095      166218 :     context.sublevels_up = sublevels_up;
    1096             : 
    1097             :     /*
    1098             :      * We try to initialize inserted_sublink to true if there is no need to
    1099             :      * detect new sublinks because the query already has some.
    1100             :      */
    1101      166218 :     if (node && IsA(node, Query))
    1102        2080 :         context.inserted_sublink = ((Query *) node)->hasSubLinks;
    1103      164138 :     else if (outer_hasSubLinks)
    1104      164138 :         context.inserted_sublink = *outer_hasSubLinks;
    1105             :     else
    1106           0 :         context.inserted_sublink = false;
    1107             : 
    1108             :     /*
    1109             :      * Must be prepared to start with a Query or a bare expression tree; if
    1110             :      * it's a Query, we don't want to increment sublevels_up.
    1111             :      */
    1112      166218 :     result = query_or_expression_tree_mutator(node,
    1113             :                                               replace_rte_variables_mutator,
    1114             :                                               (void *) &context,
    1115             :                                               0);
    1116             : 
    1117      166214 :     if (context.inserted_sublink)
    1118             :     {
    1119       20436 :         if (result && IsA(result, Query))
    1120          60 :             ((Query *) result)->hasSubLinks = true;
    1121       20376 :         else if (outer_hasSubLinks)
    1122       20376 :             *outer_hasSubLinks = true;
    1123             :         else
    1124           0 :             elog(ERROR, "replace_rte_variables inserted a SubLink, but has noplace to record it");
    1125             :     }
    1126             : 
    1127      166214 :     return result;
    1128             : }
    1129             : 
    1130             : Node *
    1131      730860 : replace_rte_variables_mutator(Node *node,
    1132             :                               replace_rte_variables_context *context)
    1133             : {
    1134      730860 :     if (node == NULL)
    1135      170510 :         return NULL;
    1136      560350 :     if (IsA(node, Var))
    1137             :     {
    1138      191142 :         Var        *var = (Var *) node;
    1139             : 
    1140      331248 :         if (var->varno == context->target_varno &&
    1141      140106 :             var->varlevelsup == context->sublevels_up)
    1142             :         {
    1143             :             /* Found a matching variable, make the substitution */
    1144             :             Node       *newnode;
    1145             : 
    1146      128416 :             newnode = context->callback(var, context);
    1147             :             /* Detect if we are adding a sublink to query */
    1148      128416 :             if (!context->inserted_sublink)
    1149      118552 :                 context->inserted_sublink = checkExprHasSubLink(newnode);
    1150      128416 :             return newnode;
    1151             :         }
    1152             :         /* otherwise fall through to copy the var normally */
    1153             :     }
    1154      369208 :     else if (IsA(node, CurrentOfExpr))
    1155             :     {
    1156           4 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
    1157             : 
    1158           8 :         if (cexpr->cvarno == context->target_varno &&
    1159           4 :             context->sublevels_up == 0)
    1160             :         {
    1161             :             /*
    1162             :              * We get here if a WHERE CURRENT OF expression turns out to apply
    1163             :              * to a view.  Someday we might be able to translate the
    1164             :              * expression to apply to an underlying table of the view, but
    1165             :              * right now it's not implemented.
    1166             :              */
    1167           4 :             ereport(ERROR,
    1168             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1169             :                      errmsg("WHERE CURRENT OF on a view is not implemented")));
    1170             :         }
    1171             :         /* otherwise fall through to copy the expr normally */
    1172             :     }
    1173      369204 :     else if (IsA(node, Query))
    1174             :     {
    1175             :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
    1176             :         Query      *newnode;
    1177             :         bool        save_inserted_sublink;
    1178             : 
    1179        1060 :         context->sublevels_up++;
    1180        1060 :         save_inserted_sublink = context->inserted_sublink;
    1181        1060 :         context->inserted_sublink = ((Query *) node)->hasSubLinks;
    1182        1060 :         newnode = query_tree_mutator((Query *) node,
    1183             :                                      replace_rte_variables_mutator,
    1184             :                                      (void *) context,
    1185             :                                      0);
    1186        1060 :         newnode->hasSubLinks |= context->inserted_sublink;
    1187        1060 :         context->inserted_sublink = save_inserted_sublink;
    1188        1060 :         context->sublevels_up--;
    1189        1060 :         return (Node *) newnode;
    1190             :     }
    1191      430870 :     return expression_tree_mutator(node, replace_rte_variables_mutator,
    1192             :                                    (void *) context);
    1193             : }
    1194             : 
    1195             : 
    1196             : /*
    1197             :  * map_variable_attnos() finds all user-column Vars in an expression tree
    1198             :  * that reference a particular RTE, and adjusts their varattnos according
    1199             :  * to the given mapping array (varattno n is replaced by attno_map[n-1]).
    1200             :  * Vars for system columns are not modified.
    1201             :  *
    1202             :  * A zero in the mapping array represents a dropped column, which should not
    1203             :  * appear in the expression.
    1204             :  *
    1205             :  * If the expression tree contains a whole-row Var for the target RTE,
    1206             :  * *found_whole_row is set to true.  In addition, if to_rowtype is
    1207             :  * not InvalidOid, we replace the Var with a Var of that vartype, inserting
    1208             :  * a ConvertRowtypeExpr to map back to the rowtype expected by the expression.
    1209             :  * (Therefore, to_rowtype had better be a child rowtype of the rowtype of the
    1210             :  * RTE we're changing references to.)  Callers that don't provide to_rowtype
    1211             :  * should report an error if *found_whole_row is true; we don't do that here
    1212             :  * because we don't know exactly what wording for the error message would
    1213             :  * be most appropriate.  The caller will be aware of the context.
    1214             :  *
    1215             :  * This could be built using replace_rte_variables and a callback function,
    1216             :  * but since we don't ever need to insert sublinks, replace_rte_variables is
    1217             :  * overly complicated.
    1218             :  */
    1219             : 
    1220             : typedef struct
    1221             : {
    1222             :     int         target_varno;   /* RTE index to search for */
    1223             :     int         sublevels_up;   /* (current) nesting depth */
    1224             :     const AttrNumber *attno_map;    /* map array for user attnos */
    1225             :     int         map_length;     /* number of entries in attno_map[] */
    1226             :     Oid         to_rowtype;     /* change whole-row Vars to this type */
    1227             :     bool       *found_whole_row;    /* output flag */
    1228             : } map_variable_attnos_context;
    1229             : 
    1230             : static Node *
    1231       87368 : map_variable_attnos_mutator(Node *node,
    1232             :                             map_variable_attnos_context *context)
    1233             : {
    1234       87368 :     if (node == NULL)
    1235         306 :         return NULL;
    1236       87062 :     if (IsA(node, Var))
    1237             :     {
    1238       21116 :         Var        *var = (Var *) node;
    1239             : 
    1240       42064 :         if (var->varno == context->target_varno &&
    1241       20948 :             var->varlevelsup == context->sublevels_up)
    1242             :         {
    1243             :             /* Found a matching variable, make the substitution */
    1244       20948 :             Var        *newvar = (Var *) palloc(sizeof(Var));
    1245       20948 :             int         attno = var->varattno;
    1246             : 
    1247       20948 :             *newvar = *var;     /* initially copy all fields of the Var */
    1248             : 
    1249       20948 :             if (attno > 0)
    1250             :             {
    1251             :                 /* user-defined column, replace attno */
    1252       41784 :                 if (attno > context->map_length ||
    1253       20892 :                     context->attno_map[attno - 1] == 0)
    1254           0 :                     elog(ERROR, "unexpected varattno %d in expression to be mapped",
    1255             :                          attno);
    1256       20892 :                 newvar->varattno = newvar->varoattno = context->attno_map[attno - 1];
    1257             :             }
    1258          56 :             else if (attno == 0)
    1259             :             {
    1260             :                 /* whole-row variable, warn caller */
    1261          28 :                 *(context->found_whole_row) = true;
    1262             : 
    1263             :                 /* If the caller expects us to convert the Var, do so. */
    1264          52 :                 if (OidIsValid(context->to_rowtype) &&
    1265          24 :                     context->to_rowtype != var->vartype)
    1266             :                 {
    1267             :                     ConvertRowtypeExpr *r;
    1268             : 
    1269             :                     /* This certainly won't work for a RECORD variable. */
    1270             :                     Assert(var->vartype != RECORDOID);
    1271             : 
    1272             :                     /* Var itself is changed to the requested type. */
    1273          24 :                     newvar->vartype = context->to_rowtype;
    1274             : 
    1275             :                     /*
    1276             :                      * Add a conversion node on top to convert back to the
    1277             :                      * original type expected by the expression.
    1278             :                      */
    1279          24 :                     r = makeNode(ConvertRowtypeExpr);
    1280          24 :                     r->arg = (Expr *) newvar;
    1281          24 :                     r->resulttype = var->vartype;
    1282          24 :                     r->convertformat = COERCE_IMPLICIT_CAST;
    1283          24 :                     r->location = -1;
    1284             : 
    1285          24 :                     return (Node *) r;
    1286             :                 }
    1287             :             }
    1288       20924 :             return (Node *) newvar;
    1289             :         }
    1290             :         /* otherwise fall through to copy the var normally */
    1291             :     }
    1292       65946 :     else if (IsA(node, ConvertRowtypeExpr))
    1293             :     {
    1294          24 :         ConvertRowtypeExpr *r = (ConvertRowtypeExpr *) node;
    1295          24 :         Var        *var = (Var *) r->arg;
    1296             : 
    1297             :         /*
    1298             :          * If this is coercing a whole-row Var that we need to convert, then
    1299             :          * just convert the Var without adding an extra ConvertRowtypeExpr.
    1300             :          * Effectively we're simplifying var::parenttype::grandparenttype into
    1301             :          * just var::grandparenttype.  This avoids building stacks of CREs if
    1302             :          * this function is applied repeatedly.
    1303             :          */
    1304          40 :         if (IsA(var, Var) &&
    1305          28 :             var->varno == context->target_varno &&
    1306          24 :             var->varlevelsup == context->sublevels_up &&
    1307          24 :             var->varattno == 0 &&
    1308          24 :             OidIsValid(context->to_rowtype) &&
    1309          12 :             context->to_rowtype != var->vartype)
    1310             :         {
    1311             :             ConvertRowtypeExpr *newnode;
    1312          12 :             Var        *newvar = (Var *) palloc(sizeof(Var));
    1313             : 
    1314             :             /* whole-row variable, warn caller */
    1315          12 :             *(context->found_whole_row) = true;
    1316             : 
    1317          12 :             *newvar = *var;     /* initially copy all fields of the Var */
    1318             : 
    1319             :             /* This certainly won't work for a RECORD variable. */
    1320             :             Assert(var->vartype != RECORDOID);
    1321             : 
    1322             :             /* Var itself is changed to the requested type. */
    1323          12 :             newvar->vartype = context->to_rowtype;
    1324             : 
    1325          12 :             newnode = (ConvertRowtypeExpr *) palloc(sizeof(ConvertRowtypeExpr));
    1326          12 :             *newnode = *r;      /* initially copy all fields of the CRE */
    1327          12 :             newnode->arg = (Expr *) newvar;
    1328             : 
    1329          12 :             return (Node *) newnode;
    1330             :         }
    1331             :         /* otherwise fall through to process the expression normally */
    1332             :     }
    1333       65922 :     else if (IsA(node, Query))
    1334             :     {
    1335             :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
    1336             :         Query      *newnode;
    1337             : 
    1338           0 :         context->sublevels_up++;
    1339           0 :         newnode = query_tree_mutator((Query *) node,
    1340             :                                      map_variable_attnos_mutator,
    1341             :                                      (void *) context,
    1342             :                                      0);
    1343           0 :         context->sublevels_up--;
    1344           0 :         return (Node *) newnode;
    1345             :     }
    1346       66102 :     return expression_tree_mutator(node, map_variable_attnos_mutator,
    1347             :                                    (void *) context);
    1348             : }
    1349             : 
    1350             : Node *
    1351        5820 : map_variable_attnos(Node *node,
    1352             :                     int target_varno, int sublevels_up,
    1353             :                     const AttrNumber *attno_map, int map_length,
    1354             :                     Oid to_rowtype, bool *found_whole_row)
    1355             : {
    1356             :     map_variable_attnos_context context;
    1357             : 
    1358        5820 :     context.target_varno = target_varno;
    1359        5820 :     context.sublevels_up = sublevels_up;
    1360        5820 :     context.attno_map = attno_map;
    1361        5820 :     context.map_length = map_length;
    1362        5820 :     context.to_rowtype = to_rowtype;
    1363        5820 :     context.found_whole_row = found_whole_row;
    1364             : 
    1365        5820 :     *found_whole_row = false;
    1366             : 
    1367             :     /*
    1368             :      * Must be prepared to start with a Query or a bare expression tree; if
    1369             :      * it's a Query, we don't want to increment sublevels_up.
    1370             :      */
    1371        5820 :     return query_or_expression_tree_mutator(node,
    1372             :                                             map_variable_attnos_mutator,
    1373             :                                             (void *) &context,
    1374             :                                             0);
    1375             : }
    1376             : 
    1377             : 
    1378             : /*
    1379             :  * ReplaceVarsFromTargetList - replace Vars with items from a targetlist
    1380             :  *
    1381             :  * Vars matching target_varno and sublevels_up are replaced by the
    1382             :  * entry with matching resno from targetlist, if there is one.
    1383             :  *
    1384             :  * If there is no matching resno for such a Var, the action depends on the
    1385             :  * nomatch_option:
    1386             :  *  REPLACEVARS_REPORT_ERROR: throw an error
    1387             :  *  REPLACEVARS_CHANGE_VARNO: change Var's varno to nomatch_varno
    1388             :  *  REPLACEVARS_SUBSTITUTE_NULL: replace Var with a NULL Const of same type
    1389             :  *
    1390             :  * The caller must also provide target_rte, the RTE describing the target
    1391             :  * relation.  This is needed to handle whole-row Vars referencing the target.
    1392             :  * We expand such Vars into RowExpr constructs.
    1393             :  *
    1394             :  * outer_hasSubLinks works the same as for replace_rte_variables().
    1395             :  */
    1396             : 
    1397             : typedef struct
    1398             : {
    1399             :     RangeTblEntry *target_rte;
    1400             :     List       *targetlist;
    1401             :     ReplaceVarsNoMatchOption nomatch_option;
    1402             :     int         nomatch_varno;
    1403             : } ReplaceVarsFromTargetList_context;
    1404             : 
    1405             : static Node *
    1406        4380 : ReplaceVarsFromTargetList_callback(Var *var,
    1407             :                                    replace_rte_variables_context *context)
    1408             : {
    1409        4380 :     ReplaceVarsFromTargetList_context *rcon = (ReplaceVarsFromTargetList_context *) context->callback_arg;
    1410             :     TargetEntry *tle;
    1411             : 
    1412        4380 :     if (var->varattno == InvalidAttrNumber)
    1413             :     {
    1414             :         /* Must expand whole-tuple reference into RowExpr */
    1415             :         RowExpr    *rowexpr;
    1416             :         List       *colnames;
    1417             :         List       *fields;
    1418             : 
    1419             :         /*
    1420             :          * If generating an expansion for a var of a named rowtype (ie, this
    1421             :          * is a plain relation RTE), then we must include dummy items for
    1422             :          * dropped columns.  If the var is RECORD (ie, this is a JOIN), then
    1423             :          * omit dropped columns.  Either way, attach column names to the
    1424             :          * RowExpr for use of ruleutils.c.
    1425             :          */
    1426         108 :         expandRTE(rcon->target_rte,
    1427          72 :                   var->varno, var->varlevelsup, var->location,
    1428          36 :                   (var->vartype != RECORDOID),
    1429             :                   &colnames, &fields);
    1430             :         /* Adjust the generated per-field Vars... */
    1431          36 :         fields = (List *) replace_rte_variables_mutator((Node *) fields,
    1432             :                                                         context);
    1433          36 :         rowexpr = makeNode(RowExpr);
    1434          36 :         rowexpr->args = fields;
    1435          36 :         rowexpr->row_typeid = var->vartype;
    1436          36 :         rowexpr->row_format = COERCE_IMPLICIT_CAST;
    1437          36 :         rowexpr->colnames = colnames;
    1438          36 :         rowexpr->location = var->location;
    1439             : 
    1440          36 :         return (Node *) rowexpr;
    1441             :     }
    1442             : 
    1443             :     /* Normal case referencing one targetlist element */
    1444        4344 :     tle = get_tle_by_resno(rcon->targetlist, var->varattno);
    1445             : 
    1446        4344 :     if (tle == NULL || tle->resjunk)
    1447             :     {
    1448             :         /* Failed to find column in targetlist */
    1449         208 :         switch (rcon->nomatch_option)
    1450             :         {
    1451             :             case REPLACEVARS_REPORT_ERROR:
    1452             :                 /* fall through, throw error below */
    1453           0 :                 break;
    1454             : 
    1455             :             case REPLACEVARS_CHANGE_VARNO:
    1456         108 :                 var = (Var *) copyObject(var);
    1457         108 :                 var->varno = rcon->nomatch_varno;
    1458         108 :                 var->varnoold = rcon->nomatch_varno;
    1459         108 :                 return (Node *) var;
    1460             : 
    1461             :             case REPLACEVARS_SUBSTITUTE_NULL:
    1462             : 
    1463             :                 /*
    1464             :                  * If Var is of domain type, we should add a CoerceToDomain
    1465             :                  * node, in case there is a NOT NULL domain constraint.
    1466             :                  */
    1467         100 :                 return coerce_to_domain((Node *) makeNullConst(var->vartype,
    1468             :                                                                var->vartypmod,
    1469             :                                                                var->varcollid),
    1470             :                                         InvalidOid, -1,
    1471             :                                         var->vartype,
    1472             :                                         COERCION_IMPLICIT,
    1473             :                                         COERCE_IMPLICIT_CAST,
    1474             :                                         -1,
    1475             :                                         false);
    1476             :         }
    1477           0 :         elog(ERROR, "could not find replacement targetlist entry for attno %d",
    1478             :              var->varattno);
    1479             :         return NULL;            /* keep compiler quiet */
    1480             :     }
    1481             :     else
    1482             :     {
    1483             :         /* Make a copy of the tlist item to return */
    1484        4136 :         Expr       *newnode = copyObject(tle->expr);
    1485             : 
    1486             :         /* Must adjust varlevelsup if tlist item is from higher query */
    1487        4136 :         if (var->varlevelsup > 0)
    1488         104 :             IncrementVarSublevelsUp((Node *) newnode, var->varlevelsup, 0);
    1489             : 
    1490             :         /*
    1491             :          * Check to see if the tlist item contains a PARAM_MULTIEXPR Param,
    1492             :          * and throw error if so.  This case could only happen when expanding
    1493             :          * an ON UPDATE rule's NEW variable and the referenced tlist item in
    1494             :          * the original UPDATE command is part of a multiple assignment. There
    1495             :          * seems no practical way to handle such cases without multiple
    1496             :          * evaluation of the multiple assignment's sub-select, which would
    1497             :          * create semantic oddities that users of rules would probably prefer
    1498             :          * not to cope with.  So treat it as an unimplemented feature.
    1499             :          */
    1500        4136 :         if (contains_multiexpr_param((Node *) newnode, NULL))
    1501           0 :             ereport(ERROR,
    1502             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1503             :                      errmsg("NEW variables in ON UPDATE rules cannot reference columns that are part of a multiple assignment in the subject UPDATE command")));
    1504             : 
    1505        4136 :         return (Node *) newnode;
    1506             :     }
    1507             : }
    1508             : 
    1509             : Node *
    1510        2880 : ReplaceVarsFromTargetList(Node *node,
    1511             :                           int target_varno, int sublevels_up,
    1512             :                           RangeTblEntry *target_rte,
    1513             :                           List *targetlist,
    1514             :                           ReplaceVarsNoMatchOption nomatch_option,
    1515             :                           int nomatch_varno,
    1516             :                           bool *outer_hasSubLinks)
    1517             : {
    1518             :     ReplaceVarsFromTargetList_context context;
    1519             : 
    1520        2880 :     context.target_rte = target_rte;
    1521        2880 :     context.targetlist = targetlist;
    1522        2880 :     context.nomatch_option = nomatch_option;
    1523        2880 :     context.nomatch_varno = nomatch_varno;
    1524             : 
    1525        2880 :     return replace_rte_variables(node, target_varno, sublevels_up,
    1526             :                                  ReplaceVarsFromTargetList_callback,
    1527             :                                  (void *) &context,
    1528             :                                  outer_hasSubLinks);
    1529             : }

Generated by: LCOV version 1.13