LCOV - differential code coverage report
Current view: top level - src/backend/rewrite - rewriteManip.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 86.6 % 589 510 6 29 39 5 19 296 75 120 55 358 3
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 36 36 31 5 35 1
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a