LCOV - code coverage report
Current view: top level - src/backend/rewrite - rewriteManip.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 424 491 86.4 %
Date: 2020-06-03 10:06:28 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-2020, 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         476 : contain_aggs_of_level(Node *node, int levelsup)
      68             : {
      69             :     contain_aggs_of_level_context context;
      70             : 
      71         476 :     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         476 :     return query_or_expression_tree_walker(node,
      78             :                                            contain_aggs_of_level_walker,
      79             :                                            (void *) &context,
      80             :                                            0);
      81             : }
      82             : 
      83             : static bool
      84         836 : contain_aggs_of_level_walker(Node *node,
      85             :                              contain_aggs_of_level_context *context)
      86             : {
      87         836 :     if (node == NULL)
      88          92 :         return false;
      89         744 :     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         744 :     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         744 :     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         740 :     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          20 :         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         900 : 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         900 :     return query_or_expression_tree_walker(node,
     204             :                                            contain_windowfuncs_walker,
     205             :                                            NULL,
     206             :                                            0);
     207             : }
     208             : 
     209             : static bool
     210        1308 : contain_windowfuncs_walker(Node *node, void *context)
     211             : {
     212        1308 :     if (node == NULL)
     213          32 :         return false;
     214        1276 :     if (IsA(node, WindowFunc))
     215           8 :         return true;            /* abort the tree traversal and return true */
     216             :     /* Mustn't recurse into subselects */
     217        1268 :     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      133330 : 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      133330 :     return query_or_expression_tree_walker(node,
     284             :                                            checkExprHasSubLink_walker,
     285             :                                            NULL,
     286             :                                            QTW_IGNORE_RC_SUBQUERIES);
     287             : }
     288             : 
     289             : static bool
     290      173522 : checkExprHasSubLink_walker(Node *node, void *context)
     291             : {
     292      173522 :     if (node == NULL)
     293        2062 :         return false;
     294      171460 :     if (IsA(node, SubLink))
     295        3678 :         return true;            /* abort the tree traversal and return true */
     296      167782 :     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        5108 : contains_multiexpr_param(Node *node, void *context)
     307             : {
     308        5108 :     if (node == NULL)
     309          12 :         return false;
     310        5096 :     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        5096 :     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 varnosyn 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     9955294 : OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
     341             : {
     342     9955294 :     if (node == NULL)
     343     2115860 :         return false;
     344     7839434 :     if (IsA(node, Var))
     345             :     {
     346     4137318 :         Var        *var = (Var *) node;
     347             : 
     348     4137318 :         if (var->varlevelsup == context->sublevels_up)
     349             :         {
     350     3281660 :             var->varno += context->offset;
     351     3281660 :             if (var->varnosyn > 0)
     352     3281660 :                 var->varnosyn += context->offset;
     353             :         }
     354     4137318 :         return false;
     355             :     }
     356     3702116 :     if (IsA(node, CurrentOfExpr))
     357             :     {
     358           0 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
     359             : 
     360           0 :         if (context->sublevels_up == 0)
     361           0 :             cexpr->cvarno += context->offset;
     362           0 :         return false;
     363             :     }
     364     3702116 :     if (IsA(node, RangeTblRef))
     365             :     {
     366      268228 :         RangeTblRef *rtr = (RangeTblRef *) node;
     367             : 
     368      268228 :         if (context->sublevels_up == 0)
     369      194110 :             rtr->rtindex += context->offset;
     370             :         /* the subquery itself is visited separately */
     371      268228 :         return false;
     372             :     }
     373     3433888 :     if (IsA(node, JoinExpr))
     374             :     {
     375       72174 :         JoinExpr   *j = (JoinExpr *) node;
     376             : 
     377       72174 :         if (j->rtindex && context->sublevels_up == 0)
     378       52494 :             j->rtindex += context->offset;
     379             :         /* fall through to examine children */
     380             :     }
     381     3433888 :     if (IsA(node, PlaceHolderVar))
     382             :     {
     383         224 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
     384             : 
     385         224 :         if (phv->phlevelsup == context->sublevels_up)
     386             :         {
     387         184 :             phv->phrels = offset_relid_set(phv->phrels,
     388             :                                            context->offset);
     389             :         }
     390             :         /* fall through to examine children */
     391             :     }
     392     3433888 :     if (IsA(node, AppendRelInfo))
     393             :     {
     394         256 :         AppendRelInfo *appinfo = (AppendRelInfo *) node;
     395             : 
     396         256 :         if (context->sublevels_up == 0)
     397             :         {
     398         256 :             appinfo->parent_relid += context->offset;
     399         256 :             appinfo->child_relid += context->offset;
     400             :         }
     401             :         /* fall through to examine children */
     402             :     }
     403             :     /* Shouldn't need to handle other planner auxiliary nodes here */
     404             :     Assert(!IsA(node, PlanRowMark));
     405             :     Assert(!IsA(node, SpecialJoinInfo));
     406             :     Assert(!IsA(node, PlaceHolderInfo));
     407             :     Assert(!IsA(node, MinMaxAggInfo));
     408             : 
     409     3433888 :     if (IsA(node, Query))
     410             :     {
     411             :         /* Recurse into subselects */
     412             :         bool        result;
     413             : 
     414       45258 :         context->sublevels_up++;
     415       45258 :         result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
     416             :                                    (void *) context, 0);
     417       45258 :         context->sublevels_up--;
     418       45258 :         return result;
     419             :     }
     420     3388630 :     return expression_tree_walker(node, OffsetVarNodes_walker,
     421             :                                   (void *) context);
     422             : }
     423             : 
     424             : void
     425      144344 : OffsetVarNodes(Node *node, int offset, int sublevels_up)
     426             : {
     427             :     OffsetVarNodes_context context;
     428             : 
     429      144344 :     context.offset = offset;
     430      144344 :     context.sublevels_up = sublevels_up;
     431             : 
     432             :     /*
     433             :      * Must be prepared to start with a Query or a bare expression tree; if
     434             :      * it's a Query, go straight to query_tree_walker to make sure that
     435             :      * sublevels_up doesn't get incremented prematurely.
     436             :      */
     437      144344 :     if (node && IsA(node, Query))
     438       95932 :     {
     439       95932 :         Query      *qry = (Query *) node;
     440             : 
     441             :         /*
     442             :          * If we are starting at a Query, and sublevels_up is zero, then we
     443             :          * must also fix rangetable indexes in the Query itself --- namely
     444             :          * resultRelation, exclRelIndex and rowMarks entries.  sublevels_up
     445             :          * cannot be zero when recursing into a subquery, so there's no need
     446             :          * to have the same logic inside OffsetVarNodes_walker.
     447             :          */
     448       95932 :         if (sublevels_up == 0)
     449             :         {
     450             :             ListCell   *l;
     451             : 
     452       95932 :             if (qry->resultRelation)
     453         788 :                 qry->resultRelation += offset;
     454             : 
     455       95932 :             if (qry->onConflict && qry->onConflict->exclRelIndex)
     456          24 :                 qry->onConflict->exclRelIndex += offset;
     457             : 
     458       96024 :             foreach(l, qry->rowMarks)
     459             :             {
     460          92 :                 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
     461             : 
     462          92 :                 rc->rti += offset;
     463             :             }
     464             :         }
     465       95932 :         query_tree_walker(qry, OffsetVarNodes_walker,
     466             :                           (void *) &context, 0);
     467             :     }
     468             :     else
     469       48412 :         OffsetVarNodes_walker(node, &context);
     470      144344 : }
     471             : 
     472             : static Relids
     473         184 : offset_relid_set(Relids relids, int offset)
     474             : {
     475         184 :     Relids      result = NULL;
     476             :     int         rtindex;
     477             : 
     478         184 :     rtindex = -1;
     479         400 :     while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
     480         216 :         result = bms_add_member(result, rtindex + offset);
     481         184 :     return result;
     482             : }
     483             : 
     484             : /*
     485             :  * ChangeVarNodes - adjust Var nodes for a specific change of RT index
     486             :  *
     487             :  * Find all Var nodes in the given tree belonging to a specific relation
     488             :  * (identified by sublevels_up and rt_index), and change their varno fields
     489             :  * to 'new_index'.  The varnosyn fields are changed too.  Also, adjust other
     490             :  * nodes that contain rangetable indexes, such as RangeTblRef and JoinExpr.
     491             :  *
     492             :  * NOTE: although this has the form of a walker, we cheat and modify the
     493             :  * nodes in-place.  The given expression tree should have been copied
     494             :  * earlier to ensure that no unwanted side-effects occur!
     495             :  */
     496             : 
     497             : typedef struct
     498             : {
     499             :     int         rt_index;
     500             :     int         new_index;
     501             :     int         sublevels_up;
     502             : } ChangeVarNodes_context;
     503             : 
     504             : static bool
     505      166962 : ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
     506             : {
     507      166962 :     if (node == NULL)
     508       65792 :         return false;
     509      101170 :     if (IsA(node, Var))
     510             :     {
     511       24964 :         Var        *var = (Var *) node;
     512             : 
     513       24964 :         if (var->varlevelsup == context->sublevels_up &&
     514       22052 :             var->varno == context->rt_index)
     515             :         {
     516       16376 :             var->varno = context->new_index;
     517             :             /* If the syntactic referent is same RTE, fix it too */
     518       16376 :             if (var->varnosyn == context->rt_index)
     519       16376 :                 var->varnosyn = context->new_index;
     520             :         }
     521       24964 :         return false;
     522             :     }
     523       76206 :     if (IsA(node, CurrentOfExpr))
     524             :     {
     525           0 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
     526             : 
     527           0 :         if (context->sublevels_up == 0 &&
     528           0 :             cexpr->cvarno == context->rt_index)
     529           0 :             cexpr->cvarno = context->new_index;
     530           0 :         return false;
     531             :     }
     532       76206 :     if (IsA(node, RangeTblRef))
     533             :     {
     534        4644 :         RangeTblRef *rtr = (RangeTblRef *) node;
     535             : 
     536        4644 :         if (context->sublevels_up == 0 &&
     537        1520 :             rtr->rtindex == context->rt_index)
     538         904 :             rtr->rtindex = context->new_index;
     539             :         /* the subquery itself is visited separately */
     540        4644 :         return false;
     541             :     }
     542       71562 :     if (IsA(node, JoinExpr))
     543             :     {
     544          32 :         JoinExpr   *j = (JoinExpr *) node;
     545             : 
     546          32 :         if (context->sublevels_up == 0 &&
     547          32 :             j->rtindex == context->rt_index)
     548           0 :             j->rtindex = context->new_index;
     549             :         /* fall through to examine children */
     550             :     }
     551       71562 :     if (IsA(node, PlaceHolderVar))
     552             :     {
     553           0 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
     554             : 
     555           0 :         if (phv->phlevelsup == context->sublevels_up)
     556             :         {
     557           0 :             phv->phrels = adjust_relid_set(phv->phrels,
     558             :                                            context->rt_index,
     559             :                                            context->new_index);
     560             :         }
     561             :         /* fall through to examine children */
     562             :     }
     563       71562 :     if (IsA(node, PlanRowMark))
     564             :     {
     565         208 :         PlanRowMark *rowmark = (PlanRowMark *) node;
     566             : 
     567         208 :         if (context->sublevels_up == 0)
     568             :         {
     569         208 :             if (rowmark->rti == context->rt_index)
     570          96 :                 rowmark->rti = context->new_index;
     571         208 :             if (rowmark->prti == context->rt_index)
     572          96 :                 rowmark->prti = context->new_index;
     573             :         }
     574         208 :         return false;
     575             :     }
     576       71354 :     if (IsA(node, AppendRelInfo))
     577             :     {
     578         248 :         AppendRelInfo *appinfo = (AppendRelInfo *) node;
     579             : 
     580         248 :         if (context->sublevels_up == 0)
     581             :         {
     582         248 :             if (appinfo->parent_relid == context->rt_index)
     583          72 :                 appinfo->parent_relid = context->new_index;
     584         248 :             if (appinfo->child_relid == context->rt_index)
     585          16 :                 appinfo->child_relid = context->new_index;
     586             :         }
     587             :         /* fall through to examine children */
     588             :     }
     589             :     /* Shouldn't need to handle other planner auxiliary nodes here */
     590             :     Assert(!IsA(node, SpecialJoinInfo));
     591             :     Assert(!IsA(node, PlaceHolderInfo));
     592             :     Assert(!IsA(node, MinMaxAggInfo));
     593             : 
     594       71354 :     if (IsA(node, Query))
     595             :     {
     596             :         /* Recurse into subselects */
     597             :         bool        result;
     598             : 
     599        2752 :         context->sublevels_up++;
     600        2752 :         result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
     601             :                                    (void *) context, 0);
     602        2752 :         context->sublevels_up--;
     603        2752 :         return result;
     604             :     }
     605       68602 :     return expression_tree_walker(node, ChangeVarNodes_walker,
     606             :                                   (void *) context);
     607             : }
     608             : 
     609             : void
     610       12398 : ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
     611             : {
     612             :     ChangeVarNodes_context context;
     613             : 
     614       12398 :     context.rt_index = rt_index;
     615       12398 :     context.new_index = new_index;
     616       12398 :     context.sublevels_up = sublevels_up;
     617             : 
     618             :     /*
     619             :      * Must be prepared to start with a Query or a bare expression tree; if
     620             :      * it's a Query, go straight to query_tree_walker to make sure that
     621             :      * sublevels_up doesn't get incremented prematurely.
     622             :      */
     623       12398 :     if (node && IsA(node, Query))
     624        2180 :     {
     625        2180 :         Query      *qry = (Query *) node;
     626             : 
     627             :         /*
     628             :          * If we are starting at a Query, and sublevels_up is zero, then we
     629             :          * must also fix rangetable indexes in the Query itself --- namely
     630             :          * resultRelation and rowMarks entries.  sublevels_up cannot be zero
     631             :          * when recursing into a subquery, so there's no need to have the same
     632             :          * logic inside ChangeVarNodes_walker.
     633             :          */
     634        2180 :         if (sublevels_up == 0)
     635             :         {
     636             :             ListCell   *l;
     637             : 
     638        2180 :             if (qry->resultRelation == rt_index)
     639        1168 :                 qry->resultRelation = new_index;
     640             : 
     641             :             /* this is unlikely to ever be used, but ... */
     642        2180 :             if (qry->onConflict && qry->onConflict->exclRelIndex == rt_index)
     643           0 :                 qry->onConflict->exclRelIndex = new_index;
     644             : 
     645        2180 :             foreach(l, qry->rowMarks)
     646             :             {
     647           0 :                 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
     648             : 
     649           0 :                 if (rc->rti == rt_index)
     650           0 :                     rc->rti = new_index;
     651             :             }
     652             :         }
     653        2180 :         query_tree_walker(qry, ChangeVarNodes_walker,
     654             :                           (void *) &context, 0);
     655             :     }
     656             :     else
     657       10218 :         ChangeVarNodes_walker(node, &context);
     658       12398 : }
     659             : 
     660             : /*
     661             :  * Substitute newrelid for oldrelid in a Relid set
     662             :  */
     663             : static Relids
     664           0 : adjust_relid_set(Relids relids, int oldrelid, int newrelid)
     665             : {
     666           0 :     if (bms_is_member(oldrelid, relids))
     667             :     {
     668             :         /* Ensure we have a modifiable copy */
     669           0 :         relids = bms_copy(relids);
     670             :         /* Remove old, add new */
     671           0 :         relids = bms_del_member(relids, oldrelid);
     672           0 :         relids = bms_add_member(relids, newrelid);
     673             :     }
     674           0 :     return relids;
     675             : }
     676             : 
     677             : /*
     678             :  * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
     679             :  *
     680             :  * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
     681             :  * and add delta_sublevels_up to their varlevelsup value.  This is needed when
     682             :  * an expression that's correct for some nesting level is inserted into a
     683             :  * subquery.  Ordinarily the initial call has min_sublevels_up == 0 so that
     684             :  * all Vars are affected.  The point of min_sublevels_up is that we can
     685             :  * increment it when we recurse into a sublink, so that local variables in
     686             :  * that sublink are not affected, only outer references to vars that belong
     687             :  * to the expression's original query level or parents thereof.
     688             :  *
     689             :  * Likewise for other nodes containing levelsup fields, such as Aggref.
     690             :  *
     691             :  * NOTE: although this has the form of a walker, we cheat and modify the
     692             :  * Var nodes in-place.  The given expression tree should have been copied
     693             :  * earlier to ensure that no unwanted side-effects occur!
     694             :  */
     695             : 
     696             : typedef struct
     697             : {
     698             :     int         delta_sublevels_up;
     699             :     int         min_sublevels_up;
     700             : } IncrementVarSublevelsUp_context;
     701             : 
     702             : static bool
     703     2683704 : IncrementVarSublevelsUp_walker(Node *node,
     704             :                                IncrementVarSublevelsUp_context *context)
     705             : {
     706     2683704 :     if (node == NULL)
     707      783920 :         return false;
     708     1899784 :     if (IsA(node, Var))
     709             :     {
     710      753344 :         Var        *var = (Var *) node;
     711             : 
     712      753344 :         if (var->varlevelsup >= context->min_sublevels_up)
     713       48504 :             var->varlevelsup += context->delta_sublevels_up;
     714      753344 :         return false;           /* done here */
     715             :     }
     716     1146440 :     if (IsA(node, CurrentOfExpr))
     717             :     {
     718             :         /* this should not happen */
     719           0 :         if (context->min_sublevels_up == 0)
     720           0 :             elog(ERROR, "cannot push down CurrentOfExpr");
     721           0 :         return false;
     722             :     }
     723     1146440 :     if (IsA(node, Aggref))
     724             :     {
     725        1450 :         Aggref     *agg = (Aggref *) node;
     726             : 
     727        1450 :         if (agg->agglevelsup >= context->min_sublevels_up)
     728          44 :             agg->agglevelsup += context->delta_sublevels_up;
     729             :         /* fall through to recurse into argument */
     730             :     }
     731     1146440 :     if (IsA(node, GroupingFunc))
     732             :     {
     733          16 :         GroupingFunc *grp = (GroupingFunc *) node;
     734             : 
     735          16 :         if (grp->agglevelsup >= context->min_sublevels_up)
     736          16 :             grp->agglevelsup += context->delta_sublevels_up;
     737             :         /* fall through to recurse into argument */
     738             :     }
     739     1146440 :     if (IsA(node, PlaceHolderVar))
     740             :     {
     741         392 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
     742             : 
     743         392 :         if (phv->phlevelsup >= context->min_sublevels_up)
     744         208 :             phv->phlevelsup += context->delta_sublevels_up;
     745             :         /* fall through to recurse into argument */
     746             :     }
     747     1146440 :     if (IsA(node, RangeTblEntry))
     748             :     {
     749      128834 :         RangeTblEntry *rte = (RangeTblEntry *) node;
     750             : 
     751      128834 :         if (rte->rtekind == RTE_CTE)
     752             :         {
     753        1004 :             if (rte->ctelevelsup >= context->min_sublevels_up)
     754        1004 :                 rte->ctelevelsup += context->delta_sublevels_up;
     755             :         }
     756      128834 :         return false;           /* allow range_table_walker to continue */
     757             :     }
     758     1017606 :     if (IsA(node, Query))
     759             :     {
     760             :         /* Recurse into subselects */
     761             :         bool        result;
     762             : 
     763        8504 :         context->min_sublevels_up++;
     764        8504 :         result = query_tree_walker((Query *) node,
     765             :                                    IncrementVarSublevelsUp_walker,
     766             :                                    (void *) context,
     767             :                                    QTW_EXAMINE_RTES_BEFORE);
     768        8504 :         context->min_sublevels_up--;
     769        8504 :         return result;
     770             :     }
     771     1009102 :     return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
     772             :                                   (void *) context);
     773             : }
     774             : 
     775             : void
     776       99170 : IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
     777             :                         int min_sublevels_up)
     778             : {
     779             :     IncrementVarSublevelsUp_context context;
     780             : 
     781       99170 :     context.delta_sublevels_up = delta_sublevels_up;
     782       99170 :     context.min_sublevels_up = min_sublevels_up;
     783             : 
     784             :     /*
     785             :      * Must be prepared to start with a Query or a bare expression tree; if
     786             :      * it's a Query, we don't want to increment sublevels_up.
     787             :      */
     788       99170 :     query_or_expression_tree_walker(node,
     789             :                                     IncrementVarSublevelsUp_walker,
     790             :                                     (void *) &context,
     791             :                                     QTW_EXAMINE_RTES_BEFORE);
     792       99170 : }
     793             : 
     794             : /*
     795             :  * IncrementVarSublevelsUp_rtable -
     796             :  *  Same as IncrementVarSublevelsUp, but to be invoked on a range table.
     797             :  */
     798             : void
     799         730 : IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up,
     800             :                                int min_sublevels_up)
     801             : {
     802             :     IncrementVarSublevelsUp_context context;
     803             : 
     804         730 :     context.delta_sublevels_up = delta_sublevels_up;
     805         730 :     context.min_sublevels_up = min_sublevels_up;
     806             : 
     807         730 :     range_table_walker(rtable,
     808             :                        IncrementVarSublevelsUp_walker,
     809             :                        (void *) &context,
     810             :                        QTW_EXAMINE_RTES_BEFORE);
     811         730 : }
     812             : 
     813             : 
     814             : /*
     815             :  * rangeTableEntry_used - detect whether an RTE is referenced somewhere
     816             :  *  in var nodes or join or setOp trees of a query or expression.
     817             :  */
     818             : 
     819             : typedef struct
     820             : {
     821             :     int         rt_index;
     822             :     int         sublevels_up;
     823             : } rangeTableEntry_used_context;
     824             : 
     825             : static bool
     826     5092168 : rangeTableEntry_used_walker(Node *node,
     827             :                             rangeTableEntry_used_context *context)
     828             : {
     829     5092168 :     if (node == NULL)
     830      931788 :         return false;
     831     4160380 :     if (IsA(node, Var))
     832             :     {
     833     1753478 :         Var        *var = (Var *) node;
     834             : 
     835     1753478 :         if (var->varlevelsup == context->sublevels_up &&
     836     1686246 :             var->varno == context->rt_index)
     837      211252 :             return true;
     838     1542226 :         return false;
     839             :     }
     840     2406902 :     if (IsA(node, CurrentOfExpr))
     841             :     {
     842           8 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
     843             : 
     844           8 :         if (context->sublevels_up == 0 &&
     845           8 :             cexpr->cvarno == context->rt_index)
     846           0 :             return true;
     847           8 :         return false;
     848             :     }
     849     2406894 :     if (IsA(node, RangeTblRef))
     850             :     {
     851      123716 :         RangeTblRef *rtr = (RangeTblRef *) node;
     852             : 
     853      123716 :         if (rtr->rtindex == context->rt_index &&
     854       25732 :             context->sublevels_up == 0)
     855       23518 :             return true;
     856             :         /* the subquery itself is visited separately */
     857      100198 :         return false;
     858             :     }
     859     2283178 :     if (IsA(node, JoinExpr))
     860             :     {
     861       46420 :         JoinExpr   *j = (JoinExpr *) node;
     862             : 
     863       46420 :         if (j->rtindex == context->rt_index &&
     864           0 :             context->sublevels_up == 0)
     865           0 :             return true;
     866             :         /* fall through to examine children */
     867             :     }
     868             :     /* Shouldn't need to handle planner auxiliary nodes here */
     869             :     Assert(!IsA(node, PlaceHolderVar));
     870             :     Assert(!IsA(node, PlanRowMark));
     871             :     Assert(!IsA(node, SpecialJoinInfo));
     872             :     Assert(!IsA(node, AppendRelInfo));
     873             :     Assert(!IsA(node, PlaceHolderInfo));
     874             :     Assert(!IsA(node, MinMaxAggInfo));
     875             : 
     876     2283178 :     if (IsA(node, Query))
     877             :     {
     878             :         /* Recurse into subselects */
     879             :         bool        result;
     880             : 
     881       24206 :         context->sublevels_up++;
     882       24206 :         result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
     883             :                                    (void *) context, 0);
     884       24206 :         context->sublevels_up--;
     885       24206 :         return result;
     886             :     }
     887     2258972 :     return expression_tree_walker(node, rangeTableEntry_used_walker,
     888             :                                   (void *) context);
     889             : }
     890             : 
     891             : bool
     892      273612 : rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
     893             : {
     894             :     rangeTableEntry_used_context context;
     895             : 
     896      273612 :     context.rt_index = rt_index;
     897      273612 :     context.sublevels_up = sublevels_up;
     898             : 
     899             :     /*
     900             :      * Must be prepared to start with a Query or a bare expression tree; if
     901             :      * it's a Query, we don't want to increment sublevels_up.
     902             :      */
     903      273612 :     return query_or_expression_tree_walker(node,
     904             :                                            rangeTableEntry_used_walker,
     905             :                                            (void *) &context,
     906             :                                            0);
     907             : }
     908             : 
     909             : 
     910             : /*
     911             :  * If the given Query is an INSERT ... SELECT construct, extract and
     912             :  * return the sub-Query node that represents the SELECT part.  Otherwise
     913             :  * return the given Query.
     914             :  *
     915             :  * If subquery_ptr is not NULL, then *subquery_ptr is set to the location
     916             :  * of the link to the SELECT subquery inside parsetree, or NULL if not an
     917             :  * INSERT ... SELECT.
     918             :  *
     919             :  * This is a hack needed because transformations on INSERT ... SELECTs that
     920             :  * appear in rule actions should be applied to the source SELECT, not to the
     921             :  * INSERT part.  Perhaps this can be cleaned up with redesigned querytrees.
     922             :  */
     923             : Query *
     924        2708 : getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
     925             : {
     926             :     Query      *selectquery;
     927             :     RangeTblEntry *selectrte;
     928             :     RangeTblRef *rtr;
     929             : 
     930        2708 :     if (subquery_ptr)
     931         820 :         *subquery_ptr = NULL;
     932             : 
     933        2708 :     if (parsetree == NULL)
     934           0 :         return parsetree;
     935        2708 :     if (parsetree->commandType != CMD_INSERT)
     936        1500 :         return parsetree;
     937             : 
     938             :     /*
     939             :      * Currently, this is ONLY applied to rule-action queries, and so we
     940             :      * expect to find the OLD and NEW placeholder entries in the given query.
     941             :      * If they're not there, it must be an INSERT/SELECT in which they've been
     942             :      * pushed down to the SELECT.
     943             :      */
     944        1208 :     if (list_length(parsetree->rtable) >= 2 &&
     945        1208 :         strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
     946        1136 :                "old") == 0 &&
     947        1136 :         strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
     948             :                "new") == 0)
     949        1136 :         return parsetree;
     950             :     Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
     951          72 :     if (list_length(parsetree->jointree->fromlist) != 1)
     952           0 :         elog(ERROR, "expected to find SELECT subquery");
     953          72 :     rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
     954             :     Assert(IsA(rtr, RangeTblRef));
     955          72 :     selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
     956          72 :     selectquery = selectrte->subquery;
     957          72 :     if (!(selectquery && IsA(selectquery, Query) &&
     958          72 :           selectquery->commandType == CMD_SELECT))
     959           0 :         elog(ERROR, "expected to find SELECT subquery");
     960          72 :     if (list_length(selectquery->rtable) >= 2 &&
     961          72 :         strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
     962          72 :                "old") == 0 &&
     963          72 :         strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
     964             :                "new") == 0)
     965             :     {
     966          72 :         if (subquery_ptr)
     967          28 :             *subquery_ptr = &(selectrte->subquery);
     968          72 :         return selectquery;
     969             :     }
     970           0 :     elog(ERROR, "could not find rule placeholders");
     971             :     return NULL;                /* not reached */
     972             : }
     973             : 
     974             : 
     975             : /*
     976             :  * Add the given qualifier condition to the query's WHERE clause
     977             :  */
     978             : void
     979        2140 : AddQual(Query *parsetree, Node *qual)
     980             : {
     981             :     Node       *copy;
     982             : 
     983        2140 :     if (qual == NULL)
     984         988 :         return;
     985             : 
     986        1152 :     if (parsetree->commandType == CMD_UTILITY)
     987             :     {
     988             :         /*
     989             :          * There's noplace to put the qual on a utility statement.
     990             :          *
     991             :          * If it's a NOTIFY, silently ignore the qual; this means that the
     992             :          * NOTIFY will execute, whether or not there are any qualifying rows.
     993             :          * While clearly wrong, this is much more useful than refusing to
     994             :          * execute the rule at all, and extra NOTIFY events are harmless for
     995             :          * typical uses of NOTIFY.
     996             :          *
     997             :          * If it isn't a NOTIFY, error out, since unconditional execution of
     998             :          * other utility stmts is unlikely to be wanted.  (This case is not
     999             :          * currently allowed anyway, but keep the test for safety.)
    1000             :          */
    1001           0 :         if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
    1002           0 :             return;
    1003             :         else
    1004           0 :             ereport(ERROR,
    1005             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1006             :                      errmsg("conditional utility statements are not implemented")));
    1007             :     }
    1008             : 
    1009        1152 :     if (parsetree->setOperations != NULL)
    1010             :     {
    1011             :         /*
    1012             :          * There's noplace to put the qual on a setop statement, either. (This
    1013             :          * could be fixed, but right now the planner simply ignores any qual
    1014             :          * condition on a setop query.)
    1015             :          */
    1016           0 :         ereport(ERROR,
    1017             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1018             :                  errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
    1019             :     }
    1020             : 
    1021             :     /* INTERSECT wants the original, but we need to copy - Jan */
    1022        1152 :     copy = copyObject(qual);
    1023             : 
    1024        1152 :     parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
    1025             :                                                copy);
    1026             : 
    1027             :     /*
    1028             :      * We had better not have stuck an aggregate into the WHERE clause.
    1029             :      */
    1030             :     Assert(!contain_aggs_of_level(copy, 0));
    1031             : 
    1032             :     /*
    1033             :      * Make sure query is marked correctly if added qual has sublinks. Need
    1034             :      * not search qual when query is already marked.
    1035             :      */
    1036        1152 :     if (!parsetree->hasSubLinks)
    1037        1148 :         parsetree->hasSubLinks = checkExprHasSubLink(copy);
    1038             : }
    1039             : 
    1040             : 
    1041             : /*
    1042             :  * Invert the given clause and add it to the WHERE qualifications of the
    1043             :  * given querytree.  Inversion means "x IS NOT TRUE", not just "NOT x",
    1044             :  * else we will do the wrong thing when x evaluates to NULL.
    1045             :  */
    1046             : void
    1047         296 : AddInvertedQual(Query *parsetree, Node *qual)
    1048             : {
    1049             :     BooleanTest *invqual;
    1050             : 
    1051         296 :     if (qual == NULL)
    1052           0 :         return;
    1053             : 
    1054             :     /* Need not copy input qual, because AddQual will... */
    1055         296 :     invqual = makeNode(BooleanTest);
    1056         296 :     invqual->arg = (Expr *) qual;
    1057         296 :     invqual->booltesttype = IS_NOT_TRUE;
    1058         296 :     invqual->location = -1;
    1059             : 
    1060         296 :     AddQual(parsetree, (Node *) invqual);
    1061             : }
    1062             : 
    1063             : 
    1064             : /*
    1065             :  * replace_rte_variables() finds all Vars in an expression tree
    1066             :  * that reference a particular RTE, and replaces them with substitute
    1067             :  * expressions obtained from a caller-supplied callback function.
    1068             :  *
    1069             :  * When invoking replace_rte_variables on a portion of a Query, pass the
    1070             :  * address of the containing Query's hasSubLinks field as outer_hasSubLinks.
    1071             :  * Otherwise, pass NULL, but inserting a SubLink into a non-Query expression
    1072             :  * will then cause an error.
    1073             :  *
    1074             :  * Note: the business with inserted_sublink is needed to update hasSubLinks
    1075             :  * in subqueries when the replacement adds a subquery inside a subquery.
    1076             :  * Messy, isn't it?  We do not need to do similar pushups for hasAggs,
    1077             :  * because it isn't possible for this transformation to insert a level-zero
    1078             :  * aggregate reference into a subquery --- it could only insert outer aggs.
    1079             :  * Likewise for hasWindowFuncs.
    1080             :  *
    1081             :  * Note: usually, we'd not expose the mutator function or context struct
    1082             :  * for a function like this.  We do so because callbacks often find it
    1083             :  * convenient to recurse directly to the mutator on sub-expressions of
    1084             :  * what they will return.
    1085             :  */
    1086             : Node *
    1087      174972 : replace_rte_variables(Node *node, int target_varno, int sublevels_up,
    1088             :                       replace_rte_variables_callback callback,
    1089             :                       void *callback_arg,
    1090             :                       bool *outer_hasSubLinks)
    1091             : {
    1092             :     Node       *result;
    1093             :     replace_rte_variables_context context;
    1094             : 
    1095      174972 :     context.callback = callback;
    1096      174972 :     context.callback_arg = callback_arg;
    1097      174972 :     context.target_varno = target_varno;
    1098      174972 :     context.sublevels_up = sublevels_up;
    1099             : 
    1100             :     /*
    1101             :      * We try to initialize inserted_sublink to true if there is no need to
    1102             :      * detect new sublinks because the query already has some.
    1103             :      */
    1104      174972 :     if (node && IsA(node, Query))
    1105        2112 :         context.inserted_sublink = ((Query *) node)->hasSubLinks;
    1106      172860 :     else if (outer_hasSubLinks)
    1107      172860 :         context.inserted_sublink = *outer_hasSubLinks;
    1108             :     else
    1109           0 :         context.inserted_sublink = false;
    1110             : 
    1111             :     /*
    1112             :      * Must be prepared to start with a Query or a bare expression tree; if
    1113             :      * it's a Query, we don't want to increment sublevels_up.
    1114             :      */
    1115      174972 :     result = query_or_expression_tree_mutator(node,
    1116             :                                               replace_rte_variables_mutator,
    1117             :                                               (void *) &context,
    1118             :                                               0);
    1119             : 
    1120      174968 :     if (context.inserted_sublink)
    1121             :     {
    1122       22434 :         if (result && IsA(result, Query))
    1123          60 :             ((Query *) result)->hasSubLinks = true;
    1124       22374 :         else if (outer_hasSubLinks)
    1125       22374 :             *outer_hasSubLinks = true;
    1126             :         else
    1127           0 :             elog(ERROR, "replace_rte_variables inserted a SubLink, but has noplace to record it");
    1128             :     }
    1129             : 
    1130      174968 :     return result;
    1131             : }
    1132             : 
    1133             : Node *
    1134      774768 : replace_rte_variables_mutator(Node *node,
    1135             :                               replace_rte_variables_context *context)
    1136             : {
    1137      774768 :     if (node == NULL)
    1138      177642 :         return NULL;
    1139      597126 :     if (IsA(node, Var))
    1140             :     {
    1141      203614 :         Var        *var = (Var *) node;
    1142             : 
    1143      203614 :         if (var->varno == context->target_varno &&
    1144      151824 :             var->varlevelsup == context->sublevels_up)
    1145             :         {
    1146             :             /* Found a matching variable, make the substitution */
    1147             :             Node       *newnode;
    1148             : 
    1149      139538 :             newnode = context->callback(var, context);
    1150             :             /* Detect if we are adding a sublink to query */
    1151      139538 :             if (!context->inserted_sublink)
    1152      128534 :                 context->inserted_sublink = checkExprHasSubLink(newnode);
    1153      139538 :             return newnode;
    1154             :         }
    1155             :         /* otherwise fall through to copy the var normally */
    1156             :     }
    1157      393512 :     else if (IsA(node, CurrentOfExpr))
    1158             :     {
    1159           4 :         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
    1160             : 
    1161           4 :         if (cexpr->cvarno == context->target_varno &&
    1162           4 :             context->sublevels_up == 0)
    1163             :         {
    1164             :             /*
    1165             :              * We get here if a WHERE CURRENT OF expression turns out to apply
    1166             :              * to a view.  Someday we might be able to translate the
    1167             :              * expression to apply to an underlying table of the view, but
    1168             :              * right now it's not implemented.
    1169             :              */
    1170           4 :             ereport(ERROR,
    1171             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1172             :                      errmsg("WHERE CURRENT OF on a view is not implemented")));
    1173             :         }
    1174             :         /* otherwise fall through to copy the expr normally */
    1175             :     }
    1176      393508 :     else if (IsA(node, Query))
    1177             :     {
    1178             :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
    1179             :         Query      *newnode;
    1180             :         bool        save_inserted_sublink;
    1181             : 
    1182        1086 :         context->sublevels_up++;
    1183        1086 :         save_inserted_sublink = context->inserted_sublink;
    1184        1086 :         context->inserted_sublink = ((Query *) node)->hasSubLinks;
    1185        1086 :         newnode = query_tree_mutator((Query *) node,
    1186             :                                      replace_rte_variables_mutator,
    1187             :                                      (void *) context,
    1188             :                                      0);
    1189        1086 :         newnode->hasSubLinks |= context->inserted_sublink;
    1190        1086 :         context->inserted_sublink = save_inserted_sublink;
    1191        1086 :         context->sublevels_up--;
    1192        1086 :         return (Node *) newnode;
    1193             :     }
    1194      456498 :     return expression_tree_mutator(node, replace_rte_variables_mutator,
    1195             :                                    (void *) context);
    1196             : }
    1197             : 
    1198             : 
    1199             : /*
    1200             :  * map_variable_attnos() finds all user-column Vars in an expression tree
    1201             :  * that reference a particular RTE, and adjusts their varattnos according
    1202             :  * to the given mapping array (varattno n is replaced by attno_map[n-1]).
    1203             :  * Vars for system columns are not modified.
    1204             :  *
    1205             :  * A zero in the mapping array represents a dropped column, which should not
    1206             :  * appear in the expression.
    1207             :  *
    1208             :  * If the expression tree contains a whole-row Var for the target RTE,
    1209             :  * *found_whole_row is set to true.  In addition, if to_rowtype is
    1210             :  * not InvalidOid, we replace the Var with a Var of that vartype, inserting
    1211             :  * a ConvertRowtypeExpr to map back to the rowtype expected by the expression.
    1212             :  * (Therefore, to_rowtype had better be a child rowtype of the rowtype of the
    1213             :  * RTE we're changing references to.)  Callers that don't provide to_rowtype
    1214             :  * should report an error if *found_whole_row is true; we don't do that here
    1215             :  * because we don't know exactly what wording for the error message would
    1216             :  * be most appropriate.  The caller will be aware of the context.
    1217             :  *
    1218             :  * This could be built using replace_rte_variables and a callback function,
    1219             :  * but since we don't ever need to insert sublinks, replace_rte_variables is
    1220             :  * overly complicated.
    1221             :  */
    1222             : 
    1223             : typedef struct
    1224             : {
    1225             :     int         target_varno;   /* RTE index to search for */
    1226             :     int         sublevels_up;   /* (current) nesting depth */
    1227             :     const AttrMap *attno_map;   /* map array for user attnos */
    1228             :     Oid         to_rowtype;     /* change whole-row Vars to this type */
    1229             :     bool       *found_whole_row;    /* output flag */
    1230             : } map_variable_attnos_context;
    1231             : 
    1232             : static Node *
    1233       98380 : map_variable_attnos_mutator(Node *node,
    1234             :                             map_variable_attnos_context *context)
    1235             : {
    1236       98380 :     if (node == NULL)
    1237         412 :         return NULL;
    1238       97968 :     if (IsA(node, Var))
    1239             :     {
    1240       23764 :         Var        *var = (Var *) node;
    1241             : 
    1242       23764 :         if (var->varno == context->target_varno &&
    1243       23596 :             var->varlevelsup == context->sublevels_up)
    1244             :         {
    1245             :             /* Found a matching variable, make the substitution */
    1246       23596 :             Var        *newvar = (Var *) palloc(sizeof(Var));
    1247       23596 :             int         attno = var->varattno;
    1248             : 
    1249       23596 :             *newvar = *var;     /* initially copy all fields of the Var */
    1250             : 
    1251       23596 :             if (attno > 0)
    1252             :             {
    1253             :                 /* user-defined column, replace attno */
    1254       23532 :                 if (attno > context->attno_map->maplen ||
    1255       23532 :                     context->attno_map->attnums[attno - 1] == 0)
    1256           0 :                     elog(ERROR, "unexpected varattno %d in expression to be mapped",
    1257             :                          attno);
    1258       23532 :                 newvar->varattno = context->attno_map->attnums[attno - 1];
    1259             :                 /* If the syntactic referent is same RTE, fix it too */
    1260       23532 :                 if (newvar->varnosyn == context->target_varno)
    1261       23480 :                     newvar->varattnosyn = newvar->varattno;
    1262             :             }
    1263          64 :             else if (attno == 0)
    1264             :             {
    1265             :                 /* whole-row variable, warn caller */
    1266          36 :                 *(context->found_whole_row) = true;
    1267             : 
    1268             :                 /* If the caller expects us to convert the Var, do so. */
    1269          36 :                 if (OidIsValid(context->to_rowtype) &&
    1270          32 :                     context->to_rowtype != var->vartype)
    1271             :                 {
    1272             :                     ConvertRowtypeExpr *r;
    1273             : 
    1274             :                     /* This certainly won't work for a RECORD variable. */
    1275             :                     Assert(var->vartype != RECORDOID);
    1276             : 
    1277             :                     /* Var itself is changed to the requested type. */
    1278          32 :                     newvar->vartype = context->to_rowtype;
    1279             : 
    1280             :                     /*
    1281             :                      * Add a conversion node on top to convert back to the
    1282             :                      * original type expected by the expression.
    1283             :                      */
    1284          32 :                     r = makeNode(ConvertRowtypeExpr);
    1285          32 :                     r->arg = (Expr *) newvar;
    1286          32 :                     r->resulttype = var->vartype;
    1287          32 :                     r->convertformat = COERCE_IMPLICIT_CAST;
    1288          32 :                     r->location = -1;
    1289             : 
    1290          32 :                     return (Node *) r;
    1291             :                 }
    1292             :             }
    1293       23564 :             return (Node *) newvar;
    1294             :         }
    1295             :         /* otherwise fall through to copy the var normally */
    1296             :     }
    1297       74204 :     else if (IsA(node, ConvertRowtypeExpr))
    1298             :     {
    1299          24 :         ConvertRowtypeExpr *r = (ConvertRowtypeExpr *) node;
    1300          24 :         Var        *var = (Var *) r->arg;
    1301             : 
    1302             :         /*
    1303             :          * If this is coercing a whole-row Var that we need to convert, then
    1304             :          * just convert the Var without adding an extra ConvertRowtypeExpr.
    1305             :          * Effectively we're simplifying var::parenttype::grandparenttype into
    1306             :          * just var::grandparenttype.  This avoids building stacks of CREs if
    1307             :          * this function is applied repeatedly.
    1308             :          */
    1309          24 :         if (IsA(var, Var) &&
    1310          16 :             var->varno == context->target_varno &&
    1311          12 :             var->varlevelsup == context->sublevels_up &&
    1312          12 :             var->varattno == 0 &&
    1313          12 :             OidIsValid(context->to_rowtype) &&
    1314          12 :             context->to_rowtype != var->vartype)
    1315             :         {
    1316             :             ConvertRowtypeExpr *newnode;
    1317          12 :             Var        *newvar = (Var *) palloc(sizeof(Var));
    1318             : 
    1319             :             /* whole-row variable, warn caller */
    1320          12 :             *(context->found_whole_row) = true;
    1321             : 
    1322          12 :             *newvar = *var;     /* initially copy all fields of the Var */
    1323             : 
    1324             :             /* This certainly won't work for a RECORD variable. */
    1325             :             Assert(var->vartype != RECORDOID);
    1326             : 
    1327             :             /* Var itself is changed to the requested type. */
    1328          12 :             newvar->vartype = context->to_rowtype;
    1329             : 
    1330          12 :             newnode = (ConvertRowtypeExpr *) palloc(sizeof(ConvertRowtypeExpr));
    1331          12 :             *newnode = *r;      /* initially copy all fields of the CRE */
    1332          12 :             newnode->arg = (Expr *) newvar;
    1333             : 
    1334          12 :             return (Node *) newnode;
    1335             :         }
    1336             :         /* otherwise fall through to process the expression normally */
    1337             :     }
    1338       74180 :     else if (IsA(node, Query))
    1339             :     {
    1340             :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
    1341             :         Query      *newnode;
    1342             : 
    1343           0 :         context->sublevels_up++;
    1344           0 :         newnode = query_tree_mutator((Query *) node,
    1345             :                                      map_variable_attnos_mutator,
    1346             :                                      (void *) context,
    1347             :                                      0);
    1348           0 :         context->sublevels_up--;
    1349           0 :         return (Node *) newnode;
    1350             :     }
    1351       74360 :     return expression_tree_mutator(node, map_variable_attnos_mutator,
    1352             :                                    (void *) context);
    1353             : }
    1354             : 
    1355             : Node *
    1356        6936 : map_variable_attnos(Node *node,
    1357             :                     int target_varno, int sublevels_up,
    1358             :                     const AttrMap *attno_map,
    1359             :                     Oid to_rowtype, bool *found_whole_row)
    1360             : {
    1361             :     map_variable_attnos_context context;
    1362             : 
    1363        6936 :     context.target_varno = target_varno;
    1364        6936 :     context.sublevels_up = sublevels_up;
    1365        6936 :     context.attno_map = attno_map;
    1366        6936 :     context.to_rowtype = to_rowtype;
    1367        6936 :     context.found_whole_row = found_whole_row;
    1368             : 
    1369        6936 :     *found_whole_row = false;
    1370             : 
    1371             :     /*
    1372             :      * Must be prepared to start with a Query or a bare expression tree; if
    1373             :      * it's a Query, we don't want to increment sublevels_up.
    1374             :      */
    1375        6936 :     return query_or_expression_tree_mutator(node,
    1376             :                                             map_variable_attnos_mutator,
    1377             :                                             (void *) &context,
    1378             :                                             0);
    1379             : }
    1380             : 
    1381             : 
    1382             : /*
    1383             :  * ReplaceVarsFromTargetList - replace Vars with items from a targetlist
    1384             :  *
    1385             :  * Vars matching target_varno and sublevels_up are replaced by the
    1386             :  * entry with matching resno from targetlist, if there is one.
    1387             :  *
    1388             :  * If there is no matching resno for such a Var, the action depends on the
    1389             :  * nomatch_option:
    1390             :  *  REPLACEVARS_REPORT_ERROR: throw an error
    1391             :  *  REPLACEVARS_CHANGE_VARNO: change Var's varno to nomatch_varno
    1392             :  *  REPLACEVARS_SUBSTITUTE_NULL: replace Var with a NULL Const of same type
    1393             :  *
    1394             :  * The caller must also provide target_rte, the RTE describing the target
    1395             :  * relation.  This is needed to handle whole-row Vars referencing the target.
    1396             :  * We expand such Vars into RowExpr constructs.
    1397             :  *
    1398             :  * outer_hasSubLinks works the same as for replace_rte_variables().
    1399             :  */
    1400             : 
    1401             : typedef struct
    1402             : {
    1403             :     RangeTblEntry *target_rte;
    1404             :     List       *targetlist;
    1405             :     ReplaceVarsNoMatchOption nomatch_option;
    1406             :     int         nomatch_varno;
    1407             : } ReplaceVarsFromTargetList_context;
    1408             : 
    1409             : static Node *
    1410        4416 : ReplaceVarsFromTargetList_callback(Var *var,
    1411             :                                    replace_rte_variables_context *context)
    1412             : {
    1413        4416 :     ReplaceVarsFromTargetList_context *rcon = (ReplaceVarsFromTargetList_context *) context->callback_arg;
    1414             :     TargetEntry *tle;
    1415             : 
    1416        4416 :     if (var->varattno == InvalidAttrNumber)
    1417             :     {
    1418             :         /* Must expand whole-tuple reference into RowExpr */
    1419             :         RowExpr    *rowexpr;
    1420             :         List       *colnames;
    1421             :         List       *fields;
    1422             : 
    1423             :         /*
    1424             :          * If generating an expansion for a var of a named rowtype (ie, this
    1425             :          * is a plain relation RTE), then we must include dummy items for
    1426             :          * dropped columns.  If the var is RECORD (ie, this is a JOIN), then
    1427             :          * omit dropped columns.  Either way, attach column names to the
    1428             :          * RowExpr for use of ruleutils.c.
    1429             :          */
    1430         108 :         expandRTE(rcon->target_rte,
    1431          72 :                   var->varno, var->varlevelsup, var->location,
    1432          36 :                   (var->vartype != RECORDOID),
    1433             :                   &colnames, &fields);
    1434             :         /* Adjust the generated per-field Vars... */
    1435          36 :         fields = (List *) replace_rte_variables_mutator((Node *) fields,
    1436             :                                                         context);
    1437          36 :         rowexpr = makeNode(RowExpr);
    1438          36 :         rowexpr->args = fields;
    1439          36 :         rowexpr->row_typeid = var->vartype;
    1440          36 :         rowexpr->row_format = COERCE_IMPLICIT_CAST;
    1441          36 :         rowexpr->colnames = colnames;
    1442          36 :         rowexpr->location = var->location;
    1443             : 
    1444          36 :         return (Node *) rowexpr;
    1445             :     }
    1446             : 
    1447             :     /* Normal case referencing one targetlist element */
    1448        4380 :     tle = get_tle_by_resno(rcon->targetlist, var->varattno);
    1449             : 
    1450        4380 :     if (tle == NULL || tle->resjunk)
    1451             :     {
    1452             :         /* Failed to find column in targetlist */
    1453         208 :         switch (rcon->nomatch_option)
    1454             :         {
    1455           0 :             case REPLACEVARS_REPORT_ERROR:
    1456             :                 /* fall through, throw error below */
    1457           0 :                 break;
    1458             : 
    1459         108 :             case REPLACEVARS_CHANGE_VARNO:
    1460         108 :                 var = (Var *) copyObject(var);
    1461         108 :                 var->varno = rcon->nomatch_varno;
    1462             :                 /* we leave the syntactic referent alone */
    1463         108 :                 return (Node *) var;
    1464             : 
    1465         100 :             case REPLACEVARS_SUBSTITUTE_NULL:
    1466             : 
    1467             :                 /*
    1468             :                  * If Var is of domain type, we should add a CoerceToDomain
    1469             :                  * node, in case there is a NOT NULL domain constraint.
    1470             :                  */
    1471         100 :                 return coerce_to_domain((Node *) makeNullConst(var->vartype,
    1472             :                                                                var->vartypmod,
    1473             :                                                                var->varcollid),
    1474             :                                         InvalidOid, -1,
    1475             :                                         var->vartype,
    1476             :                                         COERCION_IMPLICIT,
    1477             :                                         COERCE_IMPLICIT_CAST,
    1478             :                                         -1,
    1479             :                                         false);
    1480             :         }
    1481           0 :         elog(ERROR, "could not find replacement targetlist entry for attno %d",
    1482             :              var->varattno);
    1483             :         return NULL;            /* keep compiler quiet */
    1484             :     }
    1485             :     else
    1486             :     {
    1487             :         /* Make a copy of the tlist item to return */
    1488        4172 :         Expr       *newnode = copyObject(tle->expr);
    1489             : 
    1490             :         /* Must adjust varlevelsup if tlist item is from higher query */
    1491        4172 :         if (var->varlevelsup > 0)
    1492         104 :             IncrementVarSublevelsUp((Node *) newnode, var->varlevelsup, 0);
    1493             : 
    1494             :         /*
    1495             :          * Check to see if the tlist item contains a PARAM_MULTIEXPR Param,
    1496             :          * and throw error if so.  This case could only happen when expanding
    1497             :          * an ON UPDATE rule's NEW variable and the referenced tlist item in
    1498             :          * the original UPDATE command is part of a multiple assignment. There
    1499             :          * seems no practical way to handle such cases without multiple
    1500             :          * evaluation of the multiple assignment's sub-select, which would
    1501             :          * create semantic oddities that users of rules would probably prefer
    1502             :          * not to cope with.  So treat it as an unimplemented feature.
    1503             :          */
    1504        4172 :         if (contains_multiexpr_param((Node *) newnode, NULL))
    1505           0 :             ereport(ERROR,
    1506             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1507             :                      errmsg("NEW variables in ON UPDATE rules cannot reference columns that are part of a multiple assignment in the subject UPDATE command")));
    1508             : 
    1509        4172 :         return (Node *) newnode;
    1510             :     }
    1511             : }
    1512             : 
    1513             : Node *
    1514        2912 : ReplaceVarsFromTargetList(Node *node,
    1515             :                           int target_varno, int sublevels_up,
    1516             :                           RangeTblEntry *target_rte,
    1517             :                           List *targetlist,
    1518             :                           ReplaceVarsNoMatchOption nomatch_option,
    1519             :                           int nomatch_varno,
    1520             :                           bool *outer_hasSubLinks)
    1521             : {
    1522             :     ReplaceVarsFromTargetList_context context;
    1523             : 
    1524        2912 :     context.target_rte = target_rte;
    1525        2912 :     context.targetlist = targetlist;
    1526        2912 :     context.nomatch_option = nomatch_option;
    1527        2912 :     context.nomatch_varno = nomatch_varno;
    1528             : 
    1529        2912 :     return replace_rte_variables(node, target_varno, sublevels_up,
    1530             :                                  ReplaceVarsFromTargetList_callback,
    1531             :                                  (void *) &context,
    1532             :                                  outer_hasSubLinks);
    1533             : }

Generated by: LCOV version 1.13