LCOV - code coverage report
Current view: top level - src/backend/rewrite - rewriteManip.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 418 486 86.0 %
Date: 2017-09-29 13:40:31 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-2017, 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/plannodes.h"
      20             : #include "optimizer/clauses.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         298 : contain_aggs_of_level(Node *node, int levelsup)
      68             : {
      69             :     contain_aggs_of_level_context context;
      70             : 
      71         298 :     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         298 :     return query_or_expression_tree_walker(node,
      78             :                                            contain_aggs_of_level_walker,
      79             :                                            (void *) &context,
      80             :                                            0);
      81             : }
      82             : 
      83             : static bool
      84        1629 : contain_aggs_of_level_walker(Node *node,
      85             :                              contain_aggs_of_level_context *context)
      86             : {
      87        1629 :     if (node == NULL)
      88         136 :         return false;
      89        1493 :     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        1493 :     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        1493 :     if (IsA(node, Query))
     102             :     {
     103             :         /* Recurse into subselects */
     104             :         bool        result;
     105             : 
     106          12 :         context->sublevels_up++;
     107          12 :         result = query_tree_walker((Query *) node,
     108             :                                    contain_aggs_of_level_walker,
     109             :                                    (void *) context, 0);
     110          12 :         context->sublevels_up--;
     111          12 :         return result;
     112             :     }
     113        1481 :     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           5 : locate_agg_of_level(Node *node, int levelsup)
     132             : {
     133             :     locate_agg_of_level_context context;
     134             : 
     135           5 :     context.agg_location = -1;  /* in case we find nothing */
     136           5 :     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           5 :     (void) query_or_expression_tree_walker(node,
     143             :                                            locate_agg_of_level_walker,
     144             :                                            (void *) &context,
     145             :                                            0);
     146             : 
     147           5 :     return context.agg_location;
     148             : }
     149             : 
     150             : static bool
     151          14 : locate_agg_of_level_walker(Node *node,
     152             :                            locate_agg_of_level_context *context)
     153             : {
     154          14 :     if (node == NULL)
     155           0 :         return false;
     156          14 :     if (IsA(node, Aggref))
     157             :     {
     158          10 :         if (((Aggref *) node)->agglevelsup == context->sublevels_up &&
     159           5 :             ((Aggref *) node)->location >= 0)
     160             :         {
     161           5 :             context->agg_location = ((Aggref *) node)->location;
     162           5 :             return true;        /* abort the tree traversal and return true */
     163             :         }
     164             :         /* else fall through to examine argument */
     165             :     }
     166           9 :     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           9 :     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           9 :     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         280 : 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         280 :     return query_or_expression_tree_walker(node,
     204             :                                            contain_windowfuncs_walker,
     205             :                                            NULL,
     206             :                                            0);
     207             : }
     208             : 
     209             : static bool
     210         805 : contain_windowfuncs_walker(Node *node, void *context)
     211             : {
     212         805 :     if (node == NULL)
     213           8 :         return false;
     214         797 :     if (IsA(node, WindowFunc))
     215           2 :         return true;            /* abort the tree traversal and return true */
     216             :     /* Mustn't recurse into subselects */
     217         795 :     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           1 : locate_windowfunc(Node *node)
     236             : {
     237             :     locate_windowfunc_context context;
     238             : 
     239           1 :     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           1 :     (void) query_or_expression_tree_walker(node,
     246             :                                            locate_windowfunc_walker,
     247             :                                            (void *) &context,
     248             :                                            0);
     249             : 
     250           1 :     return context.win_location;
     251             : }
     252             : 
     253             : static bool
     254           1 : locate_windowfunc_walker(Node *node, locate_windowfunc_context *context)
     255             : {
     256           1 :     if (node == NULL)
     257           0 :         return false;
     258           1 :     if (IsA(node, WindowFunc))
     259             :     {
     260           1 :         if (((WindowFunc *) node)->location >= 0)
     261             :         {
     262           1 :             context->win_location = ((WindowFunc *) node)->location;
     263           1 :             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        7014 : 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        7014 :     return query_or_expression_tree_walker(node,
     284             :                                            checkExprHasSubLink_walker,
     285             :                                            NULL,
     286             :                                            QTW_IGNORE_RC_SUBQUERIES);
     287             : }
     288             : 
     289             : static bool
     290       13530 : checkExprHasSubLink_walker(Node *node, void *context)
     291             : {
     292       13530 :     if (node == NULL)
     293         340 :         return false;
     294       13190 :     if (IsA(node, SubLink))
     295         101 :         return true;            /* abort the tree traversal and return true */
     296       13089 :     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        1137 : contains_multiexpr_param(Node *node, void *context)
     307             : {
     308        1137 :     if (node == NULL)
     309           3 :         return false;
     310        1134 :     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        1134 :     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      152099 : OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
     341             : {
     342      152099 :     if (node == NULL)
     343       47096 :         return false;
     344      105003 :     if (IsA(node, Var))
     345             :     {
     346       47660 :         Var        *var = (Var *) node;
     347             : 
     348       47660 :         if (var->varlevelsup == context->sublevels_up)
     349             :         {
     350       41374 :             var->varno += context->offset;
     351       41374 :             var->varnoold += context->offset;
     352             :         }
     353       47660 :         return false;
     354             :     }
     355       57343 :     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       57343 :     if (IsA(node, RangeTblRef))
     364             :     {
     365        4424 :         RangeTblRef *rtr = (RangeTblRef *) node;
     366             : 
     367        4424 :         if (context->sublevels_up == 0)
     368        3519 :             rtr->rtindex += context->offset;
     369             :         /* the subquery itself is visited separately */
     370        4424 :         return false;
     371             :     }
     372       52919 :     if (IsA(node, JoinExpr))
     373             :     {
     374         897 :         JoinExpr   *j = (JoinExpr *) node;
     375             : 
     376         897 :         if (j->rtindex && context->sublevels_up == 0)
     377         778 :             j->rtindex += context->offset;
     378             :         /* fall through to examine children */
     379             :     }
     380       52919 :     if (IsA(node, PlaceHolderVar))
     381             :     {
     382          21 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
     383             : 
     384          21 :         if (phv->phlevelsup == context->sublevels_up)
     385             :         {
     386          12 :             phv->phrels = offset_relid_set(phv->phrels,
     387             :                                            context->offset);
     388             :         }
     389             :         /* fall through to examine children */
     390             :     }
     391       52919 :     if (IsA(node, AppendRelInfo))
     392             :     {
     393          30 :         AppendRelInfo *appinfo = (AppendRelInfo *) node;
     394             : 
     395          30 :         if (context->sublevels_up == 0)
     396             :         {
     397          30 :             appinfo->parent_relid += context->offset;
     398          30 :             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       52919 :     Assert(!IsA(node, PlanRowMark));
     404       52919 :     Assert(!IsA(node, SpecialJoinInfo));
     405       52919 :     Assert(!IsA(node, PlaceHolderInfo));
     406       52919 :     Assert(!IsA(node, MinMaxAggInfo));
     407             : 
     408       52919 :     if (IsA(node, Query))
     409             :     {
     410             :         /* Recurse into subselects */
     411             :         bool        result;
     412             : 
     413         683 :         context->sublevels_up++;
     414         683 :         result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
     415             :                                    (void *) context, 0);
     416         683 :         context->sublevels_up--;
     417         683 :         return result;
     418             :     }
     419       52236 :     return expression_tree_walker(node, OffsetVarNodes_walker,
     420             :                                   (void *) context);
     421             : }
     422             : 
     423             : void
     424        4737 : OffsetVarNodes(Node *node, int offset, int sublevels_up)
     425             : {
     426             :     OffsetVarNodes_context context;
     427             : 
     428        4737 :     context.offset = offset;
     429        4737 :     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        4737 :     if (node && IsA(node, Query))
     437        2583 :     {
     438        2583 :         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        2583 :         if (sublevels_up == 0)
     448             :         {
     449             :             ListCell   *l;
     450             : 
     451        2583 :             if (qry->resultRelation)
     452         182 :                 qry->resultRelation += offset;
     453             : 
     454        2583 :             if (qry->onConflict && qry->onConflict->exclRelIndex)
     455           6 :                 qry->onConflict->exclRelIndex += offset;
     456             : 
     457        2583 :             foreach(l, qry->rowMarks)
     458             :             {
     459           0 :                 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
     460             : 
     461           0 :                 rc->rti += offset;
     462             :             }
     463             :         }
     464        2583 :         query_tree_walker(qry, OffsetVarNodes_walker,
     465             :                           (void *) &context, 0);
     466             :     }
     467             :     else
     468        2154 :         OffsetVarNodes_walker(node, &context);
     469        4737 : }
     470             : 
     471             : static Relids
     472          12 : offset_relid_set(Relids relids, int offset)
     473             : {
     474          12 :     Relids      result = NULL;
     475             :     int         rtindex;
     476             : 
     477          12 :     rtindex = -1;
     478          42 :     while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
     479          18 :         result = bms_add_member(result, rtindex + offset);
     480          12 :     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       26347 : ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
     505             : {
     506       26347 :     if (node == NULL)
     507        9697 :         return false;
     508       16650 :     if (IsA(node, Var))
     509             :     {
     510        4245 :         Var        *var = (Var *) node;
     511             : 
     512        8186 :         if (var->varlevelsup == context->sublevels_up &&
     513        3941 :             var->varno == context->rt_index)
     514             :         {
     515        2889 :             var->varno = context->new_index;
     516        2889 :             var->varnoold = context->new_index;
     517             :         }
     518        4245 :         return false;
     519             :     }
     520       12405 :     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       12405 :     if (IsA(node, RangeTblRef))
     530             :     {
     531         558 :         RangeTblRef *rtr = (RangeTblRef *) node;
     532             : 
     533         847 :         if (context->sublevels_up == 0 &&
     534         289 :             rtr->rtindex == context->rt_index)
     535         186 :             rtr->rtindex = context->new_index;
     536             :         /* the subquery itself is visited separately */
     537         558 :         return false;
     538             :     }
     539       11847 :     if (IsA(node, JoinExpr))
     540             :     {
     541           1 :         JoinExpr   *j = (JoinExpr *) node;
     542             : 
     543           2 :         if (context->sublevels_up == 0 &&
     544           1 :             j->rtindex == context->rt_index)
     545           0 :             j->rtindex = context->new_index;
     546             :         /* fall through to examine children */
     547             :     }
     548       11847 :     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       11847 :     if (IsA(node, PlanRowMark))
     561             :     {
     562          27 :         PlanRowMark *rowmark = (PlanRowMark *) node;
     563             : 
     564          27 :         if (context->sublevels_up == 0)
     565             :         {
     566          27 :             if (rowmark->rti == context->rt_index)
     567          14 :                 rowmark->rti = context->new_index;
     568          27 :             if (rowmark->prti == context->rt_index)
     569          14 :                 rowmark->prti = context->new_index;
     570             :         }
     571          27 :         return false;
     572             :     }
     573       11820 :     if (IsA(node, AppendRelInfo))
     574             :     {
     575          30 :         AppendRelInfo *appinfo = (AppendRelInfo *) node;
     576             : 
     577          30 :         if (context->sublevels_up == 0)
     578             :         {
     579          30 :             if (appinfo->parent_relid == context->rt_index)
     580          10 :                 appinfo->parent_relid = context->new_index;
     581          30 :             if (appinfo->child_relid == context->rt_index)
     582           0 :                 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       11820 :     Assert(!IsA(node, SpecialJoinInfo));
     588       11820 :     Assert(!IsA(node, PlaceHolderInfo));
     589       11820 :     Assert(!IsA(node, MinMaxAggInfo));
     590             : 
     591       11820 :     if (IsA(node, Query))
     592             :     {
     593             :         /* Recurse into subselects */
     594             :         bool        result;
     595             : 
     596         244 :         context->sublevels_up++;
     597         244 :         result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
     598             :                                    (void *) context, 0);
     599         244 :         context->sublevels_up--;
     600         244 :         return result;
     601             :     }
     602       11576 :     return expression_tree_walker(node, ChangeVarNodes_walker,
     603             :                                   (void *) context);
     604             : }
     605             : 
     606             : void
     607        2166 : ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
     608             : {
     609             :     ChangeVarNodes_context context;
     610             : 
     611        2166 :     context.rt_index = rt_index;
     612        2166 :     context.new_index = new_index;
     613        2166 :     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        2166 :     if (node && IsA(node, Query))
     621         440 :     {
     622         440 :         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         440 :         if (sublevels_up == 0)
     632             :         {
     633             :             ListCell   *l;
     634             : 
     635         440 :             if (qry->resultRelation == rt_index)
     636         225 :                 qry->resultRelation = new_index;
     637             : 
     638             :             /* this is unlikely to ever be used, but ... */
     639         440 :             if (qry->onConflict && qry->onConflict->exclRelIndex == rt_index)
     640           0 :                 qry->onConflict->exclRelIndex = new_index;
     641             : 
     642         440 :             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         440 :         query_tree_walker(qry, ChangeVarNodes_walker,
     651             :                           (void *) &context, 0);
     652             :     }
     653             :     else
     654        1726 :         ChangeVarNodes_walker(node, &context);
     655        2166 : }
     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      135656 : IncrementVarSublevelsUp_walker(Node *node,
     701             :                                IncrementVarSublevelsUp_context *context)
     702             : {
     703      135656 :     if (node == NULL)
     704       40183 :         return false;
     705       95473 :     if (IsA(node, Var))
     706             :     {
     707       38600 :         Var        *var = (Var *) node;
     708             : 
     709       38600 :         if (var->varlevelsup >= context->min_sublevels_up)
     710         617 :             var->varlevelsup += context->delta_sublevels_up;
     711       38600 :         return false;           /* done here */
     712             :     }
     713       56873 :     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       56873 :     if (IsA(node, Aggref))
     721             :     {
     722         322 :         Aggref     *agg = (Aggref *) node;
     723             : 
     724         322 :         if (agg->agglevelsup >= context->min_sublevels_up)
     725           9 :             agg->agglevelsup += context->delta_sublevels_up;
     726             :         /* fall through to recurse into argument */
     727             :     }
     728       56873 :     if (IsA(node, GroupingFunc))
     729             :     {
     730           4 :         GroupingFunc *grp = (GroupingFunc *) node;
     731             : 
     732           4 :         if (grp->agglevelsup >= context->min_sublevels_up)
     733           4 :             grp->agglevelsup += context->delta_sublevels_up;
     734             :         /* fall through to recurse into argument */
     735             :     }
     736       56873 :     if (IsA(node, PlaceHolderVar))
     737             :     {
     738          55 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
     739             : 
     740          55 :         if (phv->phlevelsup >= context->min_sublevels_up)
     741          43 :             phv->phlevelsup += context->delta_sublevels_up;
     742             :         /* fall through to recurse into argument */
     743             :     }
     744       56873 :     if (IsA(node, RangeTblEntry))
     745             :     {
     746        6771 :         RangeTblEntry *rte = (RangeTblEntry *) node;
     747             : 
     748        6771 :         if (rte->rtekind == RTE_CTE)
     749             :         {
     750          23 :             if (rte->ctelevelsup >= context->min_sublevels_up)
     751          23 :                 rte->ctelevelsup += context->delta_sublevels_up;
     752             :         }
     753        6771 :         return false;           /* allow range_table_walker to continue */
     754             :     }
     755       50102 :     if (IsA(node, Query))
     756             :     {
     757             :         /* Recurse into subselects */
     758             :         bool        result;
     759             : 
     760         751 :         context->min_sublevels_up++;
     761         751 :         result = query_tree_walker((Query *) node,
     762             :                                    IncrementVarSublevelsUp_walker,
     763             :                                    (void *) context,
     764             :                                    QTW_EXAMINE_RTES);
     765         751 :         context->min_sublevels_up--;
     766         751 :         return result;
     767             :     }
     768       49351 :     return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
     769             :                                   (void *) context);
     770             : }
     771             : 
     772             : void
     773        4495 : IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
     774             :                         int min_sublevels_up)
     775             : {
     776             :     IncrementVarSublevelsUp_context context;
     777             : 
     778        4495 :     context.delta_sublevels_up = delta_sublevels_up;
     779        4495 :     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        4495 :     query_or_expression_tree_walker(node,
     786             :                                     IncrementVarSublevelsUp_walker,
     787             :                                     (void *) &context,
     788             :                                     QTW_EXAMINE_RTES);
     789        4495 : }
     790             : 
     791             : /*
     792             :  * IncrementVarSublevelsUp_rtable -
     793             :  *  Same as IncrementVarSublevelsUp, but to be invoked on a range table.
     794             :  */
     795             : void
     796          69 : IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up,
     797             :                                int min_sublevels_up)
     798             : {
     799             :     IncrementVarSublevelsUp_context context;
     800             : 
     801          69 :     context.delta_sublevels_up = delta_sublevels_up;
     802          69 :     context.min_sublevels_up = min_sublevels_up;
     803             : 
     804          69 :     range_table_walker(rtable,
     805             :                        IncrementVarSublevelsUp_walker,
     806             :                        (void *) &context,
     807             :                        QTW_EXAMINE_RTES);
     808          69 : }
     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      359814 : rangeTableEntry_used_walker(Node *node,
     824             :                             rangeTableEntry_used_context *context)
     825             : {
     826      359814 :     if (node == NULL)
     827       72614 :         return false;
     828      287200 :     if (IsA(node, Var))
     829             :     {
     830      112084 :         Var        *var = (Var *) node;
     831             : 
     832      220797 :         if (var->varlevelsup == context->sublevels_up &&
     833      108713 :             var->varno == context->rt_index)
     834       11640 :             return true;
     835      100444 :         return false;
     836             :     }
     837      175116 :     if (IsA(node, CurrentOfExpr))
     838             :     {
     839           2 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
     840             : 
     841           4 :         if (context->sublevels_up == 0 &&
     842           2 :             cexpr->cvarno == context->rt_index)
     843           0 :             return true;
     844           2 :         return false;
     845             :     }
     846      175114 :     if (IsA(node, RangeTblRef))
     847             :     {
     848       10657 :         RangeTblRef *rtr = (RangeTblRef *) node;
     849             : 
     850       14435 :         if (rtr->rtindex == context->rt_index &&
     851        3778 :             context->sublevels_up == 0)
     852        3343 :             return true;
     853             :         /* the subquery itself is visited separately */
     854        7314 :         return false;
     855             :     }
     856      164457 :     if (IsA(node, JoinExpr))
     857             :     {
     858        3507 :         JoinExpr   *j = (JoinExpr *) node;
     859             : 
     860        3507 :         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      164457 :     Assert(!IsA(node, PlaceHolderVar));
     867      164457 :     Assert(!IsA(node, PlanRowMark));
     868      164457 :     Assert(!IsA(node, SpecialJoinInfo));
     869      164457 :     Assert(!IsA(node, AppendRelInfo));
     870      164457 :     Assert(!IsA(node, PlaceHolderInfo));
     871      164457 :     Assert(!IsA(node, MinMaxAggInfo));
     872             : 
     873      164457 :     if (IsA(node, Query))
     874             :     {
     875             :         /* Recurse into subselects */
     876             :         bool        result;
     877             : 
     878        1136 :         context->sublevels_up++;
     879        1136 :         result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
     880             :                                    (void *) context, 0);
     881        1136 :         context->sublevels_up--;
     882        1136 :         return result;
     883             :     }
     884      163321 :     return expression_tree_walker(node, rangeTableEntry_used_walker,
     885             :                                   (void *) context);
     886             : }
     887             : 
     888             : bool
     889       18522 : rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
     890             : {
     891             :     rangeTableEntry_used_context context;
     892             : 
     893       18522 :     context.rt_index = rt_index;
     894       18522 :     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       18522 :     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         410 : getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
     922             : {
     923             :     Query      *selectquery;
     924             :     RangeTblEntry *selectrte;
     925             :     RangeTblRef *rtr;
     926             : 
     927         410 :     if (subquery_ptr)
     928         190 :         *subquery_ptr = NULL;
     929             : 
     930         410 :     if (parsetree == NULL)
     931           0 :         return parsetree;
     932         410 :     if (parsetree->commandType != CMD_INSERT)
     933         165 :         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         490 :     if (list_length(parsetree->rtable) >= 2 &&
     942         245 :         strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
     943         228 :                "old") == 0 &&
     944         228 :         strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
     945             :                "new") == 0)
     946         228 :         return parsetree;
     947          17 :     Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
     948          17 :     if (list_length(parsetree->jointree->fromlist) != 1)
     949           0 :         elog(ERROR, "expected to find SELECT subquery");
     950          17 :     rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
     951          17 :     Assert(IsA(rtr, RangeTblRef));
     952          17 :     selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
     953          17 :     selectquery = selectrte->subquery;
     954          34 :     if (!(selectquery && IsA(selectquery, Query) &&
     955          17 :           selectquery->commandType == CMD_SELECT))
     956           0 :         elog(ERROR, "expected to find SELECT subquery");
     957          34 :     if (list_length(selectquery->rtable) >= 2 &&
     958          17 :         strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
     959          17 :                "old") == 0 &&
     960          17 :         strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
     961             :                "new") == 0)
     962             :     {
     963          17 :         if (subquery_ptr)
     964           7 :             *subquery_ptr = &(selectrte->subquery);
     965          17 :         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         494 : AddQual(Query *parsetree, Node *qual)
     977             : {
     978             :     Node       *copy;
     979             : 
     980         494 :     if (qual == NULL)
     981         222 :         return;
     982             : 
     983         272 :     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         272 :     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 want's the original, but we need to copy - Jan */
    1019         272 :     copy = copyObject(qual);
    1020             : 
    1021         272 :     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         272 :     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         272 :     if (!parsetree->hasSubLinks)
    1034         271 :         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          71 : AddInvertedQual(Query *parsetree, Node *qual)
    1045             : {
    1046             :     BooleanTest *invqual;
    1047             : 
    1048          71 :     if (qual == NULL)
    1049          71 :         return;
    1050             : 
    1051             :     /* Need not copy input qual, because AddQual will... */
    1052          71 :     invqual = makeNode(BooleanTest);
    1053          71 :     invqual->arg = (Expr *) qual;
    1054          71 :     invqual->booltesttype = IS_NOT_TRUE;
    1055          71 :     invqual->location = -1;
    1056             : 
    1057          71 :     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        9189 : 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        9189 :     context.callback = callback;
    1093        9189 :     context.callback_arg = callback_arg;
    1094        9189 :     context.target_varno = target_varno;
    1095        9189 :     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        9189 :     if (node && IsA(node, Query))
    1102         429 :         context.inserted_sublink = ((Query *) node)->hasSubLinks;
    1103        8760 :     else if (outer_hasSubLinks)
    1104        8760 :         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        9189 :     result = query_or_expression_tree_mutator(node,
    1113             :                                               replace_rte_variables_mutator,
    1114             :                                               (void *) &context,
    1115             :                                               0);
    1116             : 
    1117        9188 :     if (context.inserted_sublink)
    1118             :     {
    1119         787 :         if (result && IsA(result, Query))
    1120          15 :             ((Query *) result)->hasSubLinks = true;
    1121         772 :         else if (outer_hasSubLinks)
    1122         772 :             *outer_hasSubLinks = true;
    1123             :         else
    1124           0 :             elog(ERROR, "replace_rte_variables inserted a SubLink, but has noplace to record it");
    1125             :     }
    1126             : 
    1127        9188 :     return result;
    1128             : }
    1129             : 
    1130             : Node *
    1131       54391 : replace_rte_variables_mutator(Node *node,
    1132             :                               replace_rte_variables_context *context)
    1133             : {
    1134       54391 :     if (node == NULL)
    1135       14810 :         return NULL;
    1136       39581 :     if (IsA(node, Var))
    1137             :     {
    1138       14686 :         Var        *var = (Var *) node;
    1139             : 
    1140       22046 :         if (var->varno == context->target_varno &&
    1141        7360 :             var->varlevelsup == context->sublevels_up)
    1142             :         {
    1143             :             /* Found a matching variable, make the substitution */
    1144             :             Node       *newnode;
    1145             : 
    1146        6733 :             newnode = (*context->callback) (var, context);
    1147             :             /* Detect if we are adding a sublink to query */
    1148        6733 :             if (!context->inserted_sublink)
    1149        6187 :                 context->inserted_sublink = checkExprHasSubLink(newnode);
    1150        6733 :             return newnode;
    1151             :         }
    1152             :         /* otherwise fall through to copy the var normally */
    1153             :     }
    1154       24895 :     else if (IsA(node, CurrentOfExpr))
    1155             :     {
    1156           1 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
    1157             : 
    1158           2 :         if (cexpr->cvarno == context->target_varno &&
    1159           1 :             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           1 :             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       24894 :     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         204 :         context->sublevels_up++;
    1180         204 :         save_inserted_sublink = context->inserted_sublink;
    1181         204 :         context->inserted_sublink = ((Query *) node)->hasSubLinks;
    1182         204 :         newnode = query_tree_mutator((Query *) node,
    1183             :                                      replace_rte_variables_mutator,
    1184             :                                      (void *) context,
    1185             :                                      0);
    1186         204 :         newnode->hasSubLinks |= context->inserted_sublink;
    1187         204 :         context->inserted_sublink = save_inserted_sublink;
    1188         204 :         context->sublevels_up--;
    1189         204 :         return (Node *) newnode;
    1190             :     }
    1191       32643 :     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 returned as TRUE.  In addition, if to_rowtype is
    1207             :  * not InvalidOid, we modify the Var's vartype and insert a ConvertRowTypeExpr
    1208             :  * to map back to the orignal rowtype.  Callers that don't provide to_rowtype
    1209             :  * should report an error if *found_row_type is true; we don't do that here
    1210             :  * because we don't know exactly what wording for the error message would
    1211             :  * be most appropriate.  The caller will be aware of the context.
    1212             :  *
    1213             :  * This could be built using replace_rte_variables and a callback function,
    1214             :  * but since we don't ever need to insert sublinks, replace_rte_variables is
    1215             :  * overly complicated.
    1216             :  */
    1217             : 
    1218             : typedef struct
    1219             : {
    1220             :     int         target_varno;   /* RTE index to search for */
    1221             :     int         sublevels_up;   /* (current) nesting depth */
    1222             :     const AttrNumber *attno_map;    /* map array for user attnos */
    1223             :     int         map_length;     /* number of entries in attno_map[] */
    1224             :     /* Target type when converting whole-row vars */
    1225             :     Oid         to_rowtype;
    1226             :     bool       *found_whole_row;    /* output flag */
    1227             : } map_variable_attnos_context;
    1228             : 
    1229             : static Node *
    1230        3741 : map_variable_attnos_mutator(Node *node,
    1231             :                             map_variable_attnos_context *context)
    1232             : {
    1233        3741 :     if (node == NULL)
    1234           3 :         return NULL;
    1235        3738 :     if (IsA(node, Var))
    1236             :     {
    1237         858 :         Var        *var = (Var *) node;
    1238             : 
    1239        1716 :         if (var->varno == context->target_varno &&
    1240         858 :             var->varlevelsup == context->sublevels_up)
    1241             :         {
    1242             :             /* Found a matching variable, make the substitution */
    1243         858 :             Var        *newvar = (Var *) palloc(sizeof(Var));
    1244         858 :             int         attno = var->varattno;
    1245             : 
    1246         858 :             *newvar = *var;
    1247         858 :             if (attno > 0)
    1248             :             {
    1249             :                 /* user-defined column, replace attno */
    1250        1688 :                 if (attno > context->map_length ||
    1251         844 :                     context->attno_map[attno - 1] == 0)
    1252           0 :                     elog(ERROR, "unexpected varattno %d in expression to be mapped",
    1253             :                          attno);
    1254         844 :                 newvar->varattno = newvar->varoattno = context->attno_map[attno - 1];
    1255             :             }
    1256          14 :             else if (attno == 0)
    1257             :             {
    1258             :                 /* whole-row variable, warn caller */
    1259           7 :                 *(context->found_whole_row) = true;
    1260             : 
    1261             :                 /* If the callers expects us to convert the same, do so. */
    1262           7 :                 if (OidIsValid(context->to_rowtype))
    1263             :                 {
    1264             :                     /* No support for RECORDOID. */
    1265           6 :                     Assert(var->vartype != RECORDOID);
    1266             : 
    1267             :                     /* Don't convert unless necessary. */
    1268           6 :                     if (context->to_rowtype != var->vartype)
    1269             :                     {
    1270             :                         ConvertRowtypeExpr *r;
    1271             : 
    1272             :                         /* Var itself is converted to the requested type. */
    1273           6 :                         newvar->vartype = context->to_rowtype;
    1274             : 
    1275             :                         /*
    1276             :                          * And a conversion node on top to convert back to the
    1277             :                          * original type.
    1278             :                          */
    1279           6 :                         r = makeNode(ConvertRowtypeExpr);
    1280           6 :                         r->arg = (Expr *) newvar;
    1281           6 :                         r->resulttype = var->vartype;
    1282           6 :                         r->convertformat = COERCE_IMPLICIT_CAST;
    1283           6 :                         r->location = -1;
    1284             : 
    1285           6 :                         return (Node *) r;
    1286             :                     }
    1287             :                 }
    1288             :             }
    1289         852 :             return (Node *) newvar;
    1290             :         }
    1291             :         /* otherwise fall through to copy the var normally */
    1292             :     }
    1293        2880 :     else if (IsA(node, Query))
    1294             :     {
    1295             :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
    1296             :         Query      *newnode;
    1297             : 
    1298           0 :         context->sublevels_up++;
    1299           0 :         newnode = query_tree_mutator((Query *) node,
    1300             :                                      map_variable_attnos_mutator,
    1301             :                                      (void *) context,
    1302             :                                      0);
    1303           0 :         context->sublevels_up--;
    1304           0 :         return (Node *) newnode;
    1305             :     }
    1306        2880 :     return expression_tree_mutator(node, map_variable_attnos_mutator,
    1307             :                                    (void *) context);
    1308             : }
    1309             : 
    1310             : Node *
    1311         257 : map_variable_attnos(Node *node,
    1312             :                     int target_varno, int sublevels_up,
    1313             :                     const AttrNumber *attno_map, int map_length,
    1314             :                     Oid to_rowtype, bool *found_whole_row)
    1315             : {
    1316             :     map_variable_attnos_context context;
    1317             : 
    1318         257 :     context.target_varno = target_varno;
    1319         257 :     context.sublevels_up = sublevels_up;
    1320         257 :     context.attno_map = attno_map;
    1321         257 :     context.map_length = map_length;
    1322         257 :     context.to_rowtype = to_rowtype;
    1323         257 :     context.found_whole_row = found_whole_row;
    1324             : 
    1325         257 :     *found_whole_row = false;
    1326             : 
    1327             :     /*
    1328             :      * Must be prepared to start with a Query or a bare expression tree; if
    1329             :      * it's a Query, we don't want to increment sublevels_up.
    1330             :      */
    1331         257 :     return query_or_expression_tree_mutator(node,
    1332             :                                             map_variable_attnos_mutator,
    1333             :                                             (void *) &context,
    1334             :                                             0);
    1335             : }
    1336             : 
    1337             : 
    1338             : /*
    1339             :  * ReplaceVarsFromTargetList - replace Vars with items from a targetlist
    1340             :  *
    1341             :  * Vars matching target_varno and sublevels_up are replaced by the
    1342             :  * entry with matching resno from targetlist, if there is one.
    1343             :  *
    1344             :  * If there is no matching resno for such a Var, the action depends on the
    1345             :  * nomatch_option:
    1346             :  *  REPLACEVARS_REPORT_ERROR: throw an error
    1347             :  *  REPLACEVARS_CHANGE_VARNO: change Var's varno to nomatch_varno
    1348             :  *  REPLACEVARS_SUBSTITUTE_NULL: replace Var with a NULL Const of same type
    1349             :  *
    1350             :  * The caller must also provide target_rte, the RTE describing the target
    1351             :  * relation.  This is needed to handle whole-row Vars referencing the target.
    1352             :  * We expand such Vars into RowExpr constructs.
    1353             :  *
    1354             :  * outer_hasSubLinks works the same as for replace_rte_variables().
    1355             :  */
    1356             : 
    1357             : typedef struct
    1358             : {
    1359             :     RangeTblEntry *target_rte;
    1360             :     List       *targetlist;
    1361             :     ReplaceVarsNoMatchOption nomatch_option;
    1362             :     int         nomatch_varno;
    1363             : } ReplaceVarsFromTargetList_context;
    1364             : 
    1365             : static Node *
    1366         941 : ReplaceVarsFromTargetList_callback(Var *var,
    1367             :                                    replace_rte_variables_context *context)
    1368             : {
    1369         941 :     ReplaceVarsFromTargetList_context *rcon = (ReplaceVarsFromTargetList_context *) context->callback_arg;
    1370             :     TargetEntry *tle;
    1371             : 
    1372         941 :     if (var->varattno == InvalidAttrNumber)
    1373             :     {
    1374             :         /* Must expand whole-tuple reference into RowExpr */
    1375             :         RowExpr    *rowexpr;
    1376             :         List       *colnames;
    1377             :         List       *fields;
    1378             : 
    1379             :         /*
    1380             :          * If generating an expansion for a var of a named rowtype (ie, this
    1381             :          * is a plain relation RTE), then we must include dummy items for
    1382             :          * dropped columns.  If the var is RECORD (ie, this is a JOIN), then
    1383             :          * omit dropped columns.  Either way, attach column names to the
    1384             :          * RowExpr for use of ruleutils.c.
    1385             :          */
    1386          12 :         expandRTE(rcon->target_rte,
    1387           8 :                   var->varno, var->varlevelsup, var->location,
    1388           4 :                   (var->vartype != RECORDOID),
    1389             :                   &colnames, &fields);
    1390             :         /* Adjust the generated per-field Vars... */
    1391           4 :         fields = (List *) replace_rte_variables_mutator((Node *) fields,
    1392             :                                                         context);
    1393           4 :         rowexpr = makeNode(RowExpr);
    1394           4 :         rowexpr->args = fields;
    1395           4 :         rowexpr->row_typeid = var->vartype;
    1396           4 :         rowexpr->row_format = COERCE_IMPLICIT_CAST;
    1397           4 :         rowexpr->colnames = colnames;
    1398           4 :         rowexpr->location = var->location;
    1399             : 
    1400           4 :         return (Node *) rowexpr;
    1401             :     }
    1402             : 
    1403             :     /* Normal case referencing one targetlist element */
    1404         937 :     tle = get_tle_by_resno(rcon->targetlist, var->varattno);
    1405             : 
    1406         937 :     if (tle == NULL || tle->resjunk)
    1407             :     {
    1408             :         /* Failed to find column in targetlist */
    1409          36 :         switch (rcon->nomatch_option)
    1410             :         {
    1411             :             case REPLACEVARS_REPORT_ERROR:
    1412             :                 /* fall through, throw error below */
    1413           0 :                 break;
    1414             : 
    1415             :             case REPLACEVARS_CHANGE_VARNO:
    1416          27 :                 var = (Var *) copyObject(var);
    1417          27 :                 var->varno = rcon->nomatch_varno;
    1418          27 :                 var->varnoold = rcon->nomatch_varno;
    1419          27 :                 return (Node *) var;
    1420             : 
    1421             :             case REPLACEVARS_SUBSTITUTE_NULL:
    1422             : 
    1423             :                 /*
    1424             :                  * If Var is of domain type, we should add a CoerceToDomain
    1425             :                  * node, in case there is a NOT NULL domain constraint.
    1426             :                  */
    1427           9 :                 return coerce_to_domain((Node *) makeNullConst(var->vartype,
    1428             :                                                                var->vartypmod,
    1429             :                                                                var->varcollid),
    1430             :                                         InvalidOid, -1,
    1431             :                                         var->vartype,
    1432             :                                         COERCE_IMPLICIT_CAST,
    1433             :                                         -1,
    1434             :                                         false,
    1435             :                                         false);
    1436             :         }
    1437           0 :         elog(ERROR, "could not find replacement targetlist entry for attno %d",
    1438             :              var->varattno);
    1439             :         return NULL;            /* keep compiler quiet */
    1440             :     }
    1441             :     else
    1442             :     {
    1443             :         /* Make a copy of the tlist item to return */
    1444         901 :         Expr       *newnode = copyObject(tle->expr);
    1445             : 
    1446             :         /* Must adjust varlevelsup if tlist item is from higher query */
    1447         901 :         if (var->varlevelsup > 0)
    1448          26 :             IncrementVarSublevelsUp((Node *) newnode, var->varlevelsup, 0);
    1449             : 
    1450             :         /*
    1451             :          * Check to see if the tlist item contains a PARAM_MULTIEXPR Param,
    1452             :          * and throw error if so.  This case could only happen when expanding
    1453             :          * an ON UPDATE rule's NEW variable and the referenced tlist item in
    1454             :          * the original UPDATE command is part of a multiple assignment. There
    1455             :          * seems no practical way to handle such cases without multiple
    1456             :          * evaluation of the multiple assignment's sub-select, which would
    1457             :          * create semantic oddities that users of rules would probably prefer
    1458             :          * not to cope with.  So treat it as an unimplemented feature.
    1459             :          */
    1460         901 :         if (contains_multiexpr_param((Node *) newnode, NULL))
    1461           0 :             ereport(ERROR,
    1462             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1463             :                      errmsg("NEW variables in ON UPDATE rules cannot reference columns that are part of a multiple assignment in the subject UPDATE command")));
    1464             : 
    1465         901 :         return (Node *) newnode;
    1466             :     }
    1467             : }
    1468             : 
    1469             : Node *
    1470         616 : ReplaceVarsFromTargetList(Node *node,
    1471             :                           int target_varno, int sublevels_up,
    1472             :                           RangeTblEntry *target_rte,
    1473             :                           List *targetlist,
    1474             :                           ReplaceVarsNoMatchOption nomatch_option,
    1475             :                           int nomatch_varno,
    1476             :                           bool *outer_hasSubLinks)
    1477             : {
    1478             :     ReplaceVarsFromTargetList_context context;
    1479             : 
    1480         616 :     context.target_rte = target_rte;
    1481         616 :     context.targetlist = targetlist;
    1482         616 :     context.nomatch_option = nomatch_option;
    1483         616 :     context.nomatch_varno = nomatch_varno;
    1484             : 
    1485         616 :     return replace_rte_variables(node, target_varno, sublevels_up,
    1486             :                                  ReplaceVarsFromTargetList_callback,
    1487             :                                  (void *) &context,
    1488             :                                  outer_hasSubLinks);
    1489             : }

Generated by: LCOV version 1.11