Header And Logo

PostgreSQL
| The world's most advanced open source database.

rewriteManip.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * rewriteManip.c
00004  *
00005  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00006  * Portions Copyright (c) 1994, Regents of the University of California
00007  *
00008  *
00009  * IDENTIFICATION
00010  *    src/backend/rewrite/rewriteManip.c
00011  *
00012  *-------------------------------------------------------------------------
00013  */
00014 #include "postgres.h"
00015 
00016 #include "catalog/pg_type.h"
00017 #include "nodes/makefuncs.h"
00018 #include "nodes/nodeFuncs.h"
00019 #include "nodes/plannodes.h"
00020 #include "optimizer/clauses.h"
00021 #include "parser/parse_coerce.h"
00022 #include "parser/parse_relation.h"
00023 #include "parser/parsetree.h"
00024 #include "rewrite/rewriteManip.h"
00025 
00026 
00027 typedef struct
00028 {
00029     int         sublevels_up;
00030 } contain_aggs_of_level_context;
00031 
00032 typedef struct
00033 {
00034     int         agg_location;
00035     int         sublevels_up;
00036 } locate_agg_of_level_context;
00037 
00038 typedef struct
00039 {
00040     int         win_location;
00041 } locate_windowfunc_context;
00042 
00043 static bool contain_aggs_of_level_walker(Node *node,
00044                              contain_aggs_of_level_context *context);
00045 static bool locate_agg_of_level_walker(Node *node,
00046                            locate_agg_of_level_context *context);
00047 static bool contain_windowfuncs_walker(Node *node, void *context);
00048 static bool locate_windowfunc_walker(Node *node,
00049                          locate_windowfunc_context *context);
00050 static bool checkExprHasSubLink_walker(Node *node, void *context);
00051 static Relids offset_relid_set(Relids relids, int offset);
00052 static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
00053 
00054 
00055 /*
00056  * contain_aggs_of_level -
00057  *  Check if an expression contains an aggregate function call of a
00058  *  specified query level.
00059  *
00060  * The objective of this routine is to detect whether there are aggregates
00061  * belonging to the given query level.  Aggregates belonging to subqueries
00062  * or outer queries do NOT cause a true result.  We must recurse into
00063  * subqueries to detect outer-reference aggregates that logically belong to
00064  * the specified query level.
00065  */
00066 bool
00067 contain_aggs_of_level(Node *node, int levelsup)
00068 {
00069     contain_aggs_of_level_context context;
00070 
00071     context.sublevels_up = levelsup;
00072 
00073     /*
00074      * Must be prepared to start with a Query or a bare expression tree; if
00075      * it's a Query, we don't want to increment sublevels_up.
00076      */
00077     return query_or_expression_tree_walker(node,
00078                                            contain_aggs_of_level_walker,
00079                                            (void *) &context,
00080                                            0);
00081 }
00082 
00083 static bool
00084 contain_aggs_of_level_walker(Node *node,
00085                              contain_aggs_of_level_context *context)
00086 {
00087     if (node == NULL)
00088         return false;
00089     if (IsA(node, Aggref))
00090     {
00091         if (((Aggref *) node)->agglevelsup == context->sublevels_up)
00092             return true;        /* abort the tree traversal and return true */
00093         /* else fall through to examine argument */
00094     }
00095     if (IsA(node, Query))
00096     {
00097         /* Recurse into subselects */
00098         bool        result;
00099 
00100         context->sublevels_up++;
00101         result = query_tree_walker((Query *) node,
00102                                    contain_aggs_of_level_walker,
00103                                    (void *) context, 0);
00104         context->sublevels_up--;
00105         return result;
00106     }
00107     return expression_tree_walker(node, contain_aggs_of_level_walker,
00108                                   (void *) context);
00109 }
00110 
00111 /*
00112  * locate_agg_of_level -
00113  *    Find the parse location of any aggregate of the specified query level.
00114  *
00115  * Returns -1 if no such agg is in the querytree, or if they all have
00116  * unknown parse location.  (The former case is probably caller error,
00117  * but we don't bother to distinguish it from the latter case.)
00118  *
00119  * Note: it might seem appropriate to merge this functionality into
00120  * contain_aggs_of_level, but that would complicate that function's API.
00121  * Currently, the only uses of this function are for error reporting,
00122  * and so shaving cycles probably isn't very important.
00123  */
00124 int
00125 locate_agg_of_level(Node *node, int levelsup)
00126 {
00127     locate_agg_of_level_context context;
00128 
00129     context.agg_location = -1;  /* in case we find nothing */
00130     context.sublevels_up = levelsup;
00131 
00132     /*
00133      * Must be prepared to start with a Query or a bare expression tree; if
00134      * it's a Query, we don't want to increment sublevels_up.
00135      */
00136     (void) query_or_expression_tree_walker(node,
00137                                            locate_agg_of_level_walker,
00138                                            (void *) &context,
00139                                            0);
00140 
00141     return context.agg_location;
00142 }
00143 
00144 static bool
00145 locate_agg_of_level_walker(Node *node,
00146                            locate_agg_of_level_context *context)
00147 {
00148     if (node == NULL)
00149         return false;
00150     if (IsA(node, Aggref))
00151     {
00152         if (((Aggref *) node)->agglevelsup == context->sublevels_up &&
00153             ((Aggref *) node)->location >= 0)
00154         {
00155             context->agg_location = ((Aggref *) node)->location;
00156             return true;        /* abort the tree traversal and return true */
00157         }
00158         /* else fall through to examine argument */
00159     }
00160     if (IsA(node, Query))
00161     {
00162         /* Recurse into subselects */
00163         bool        result;
00164 
00165         context->sublevels_up++;
00166         result = query_tree_walker((Query *) node,
00167                                    locate_agg_of_level_walker,
00168                                    (void *) context, 0);
00169         context->sublevels_up--;
00170         return result;
00171     }
00172     return expression_tree_walker(node, locate_agg_of_level_walker,
00173                                   (void *) context);
00174 }
00175 
00176 /*
00177  * contain_windowfuncs -
00178  *  Check if an expression contains a window function call of the
00179  *  current query level.
00180  */
00181 bool
00182 contain_windowfuncs(Node *node)
00183 {
00184     /*
00185      * Must be prepared to start with a Query or a bare expression tree; if
00186      * it's a Query, we don't want to increment sublevels_up.
00187      */
00188     return query_or_expression_tree_walker(node,
00189                                            contain_windowfuncs_walker,
00190                                            NULL,
00191                                            0);
00192 }
00193 
00194 static bool
00195 contain_windowfuncs_walker(Node *node, void *context)
00196 {
00197     if (node == NULL)
00198         return false;
00199     if (IsA(node, WindowFunc))
00200         return true;            /* abort the tree traversal and return true */
00201     /* Mustn't recurse into subselects */
00202     return expression_tree_walker(node, contain_windowfuncs_walker,
00203                                   (void *) context);
00204 }
00205 
00206 /*
00207  * locate_windowfunc -
00208  *    Find the parse location of any windowfunc of the current query level.
00209  *
00210  * Returns -1 if no such windowfunc is in the querytree, or if they all have
00211  * unknown parse location.  (The former case is probably caller error,
00212  * but we don't bother to distinguish it from the latter case.)
00213  *
00214  * Note: it might seem appropriate to merge this functionality into
00215  * contain_windowfuncs, but that would complicate that function's API.
00216  * Currently, the only uses of this function are for error reporting,
00217  * and so shaving cycles probably isn't very important.
00218  */
00219 int
00220 locate_windowfunc(Node *node)
00221 {
00222     locate_windowfunc_context context;
00223 
00224     context.win_location = -1;  /* in case we find nothing */
00225 
00226     /*
00227      * Must be prepared to start with a Query or a bare expression tree; if
00228      * it's a Query, we don't want to increment sublevels_up.
00229      */
00230     (void) query_or_expression_tree_walker(node,
00231                                            locate_windowfunc_walker,
00232                                            (void *) &context,
00233                                            0);
00234 
00235     return context.win_location;
00236 }
00237 
00238 static bool
00239 locate_windowfunc_walker(Node *node, locate_windowfunc_context *context)
00240 {
00241     if (node == NULL)
00242         return false;
00243     if (IsA(node, WindowFunc))
00244     {
00245         if (((WindowFunc *) node)->location >= 0)
00246         {
00247             context->win_location = ((WindowFunc *) node)->location;
00248             return true;        /* abort the tree traversal and return true */
00249         }
00250         /* else fall through to examine argument */
00251     }
00252     /* Mustn't recurse into subselects */
00253     return expression_tree_walker(node, locate_windowfunc_walker,
00254                                   (void *) context);
00255 }
00256 
00257 /*
00258  * checkExprHasSubLink -
00259  *  Check if an expression contains a SubLink.
00260  */
00261 bool
00262 checkExprHasSubLink(Node *node)
00263 {
00264     /*
00265      * If a Query is passed, examine it --- but we should not recurse into
00266      * sub-Queries that are in its rangetable or CTE list.
00267      */
00268     return query_or_expression_tree_walker(node,
00269                                            checkExprHasSubLink_walker,
00270                                            NULL,
00271                                            QTW_IGNORE_RC_SUBQUERIES);
00272 }
00273 
00274 static bool
00275 checkExprHasSubLink_walker(Node *node, void *context)
00276 {
00277     if (node == NULL)
00278         return false;
00279     if (IsA(node, SubLink))
00280         return true;            /* abort the tree traversal and return true */
00281     return expression_tree_walker(node, checkExprHasSubLink_walker, context);
00282 }
00283 
00284 
00285 /*
00286  * OffsetVarNodes - adjust Vars when appending one query's RT to another
00287  *
00288  * Find all Var nodes in the given tree with varlevelsup == sublevels_up,
00289  * and increment their varno fields (rangetable indexes) by 'offset'.
00290  * The varnoold fields are adjusted similarly.  Also, adjust other nodes
00291  * that contain rangetable indexes, such as RangeTblRef and JoinExpr.
00292  *
00293  * NOTE: although this has the form of a walker, we cheat and modify the
00294  * nodes in-place.  The given expression tree should have been copied
00295  * earlier to ensure that no unwanted side-effects occur!
00296  */
00297 
00298 typedef struct
00299 {
00300     int         offset;
00301     int         sublevels_up;
00302 } OffsetVarNodes_context;
00303 
00304 static bool
00305 OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
00306 {
00307     if (node == NULL)
00308         return false;
00309     if (IsA(node, Var))
00310     {
00311         Var        *var = (Var *) node;
00312 
00313         if (var->varlevelsup == context->sublevels_up)
00314         {
00315             var->varno += context->offset;
00316             var->varnoold += context->offset;
00317         }
00318         return false;
00319     }
00320     if (IsA(node, CurrentOfExpr))
00321     {
00322         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
00323 
00324         if (context->sublevels_up == 0)
00325             cexpr->cvarno += context->offset;
00326         return false;
00327     }
00328     if (IsA(node, RangeTblRef))
00329     {
00330         RangeTblRef *rtr = (RangeTblRef *) node;
00331 
00332         if (context->sublevels_up == 0)
00333             rtr->rtindex += context->offset;
00334         /* the subquery itself is visited separately */
00335         return false;
00336     }
00337     if (IsA(node, JoinExpr))
00338     {
00339         JoinExpr   *j = (JoinExpr *) node;
00340 
00341         if (j->rtindex && context->sublevels_up == 0)
00342             j->rtindex += context->offset;
00343         /* fall through to examine children */
00344     }
00345     if (IsA(node, PlaceHolderVar))
00346     {
00347         PlaceHolderVar *phv = (PlaceHolderVar *) node;
00348 
00349         if (phv->phlevelsup == context->sublevels_up)
00350         {
00351             phv->phrels = offset_relid_set(phv->phrels,
00352                                            context->offset);
00353         }
00354         /* fall through to examine children */
00355     }
00356     if (IsA(node, AppendRelInfo))
00357     {
00358         AppendRelInfo *appinfo = (AppendRelInfo *) node;
00359 
00360         if (context->sublevels_up == 0)
00361         {
00362             appinfo->parent_relid += context->offset;
00363             appinfo->child_relid += context->offset;
00364         }
00365         /* fall through to examine children */
00366     }
00367     /* Shouldn't need to handle other planner auxiliary nodes here */
00368     Assert(!IsA(node, PlanRowMark));
00369     Assert(!IsA(node, SpecialJoinInfo));
00370     Assert(!IsA(node, LateralJoinInfo));
00371     Assert(!IsA(node, PlaceHolderInfo));
00372     Assert(!IsA(node, MinMaxAggInfo));
00373 
00374     if (IsA(node, Query))
00375     {
00376         /* Recurse into subselects */
00377         bool        result;
00378 
00379         context->sublevels_up++;
00380         result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
00381                                    (void *) context, 0);
00382         context->sublevels_up--;
00383         return result;
00384     }
00385     return expression_tree_walker(node, OffsetVarNodes_walker,
00386                                   (void *) context);
00387 }
00388 
00389 void
00390 OffsetVarNodes(Node *node, int offset, int sublevels_up)
00391 {
00392     OffsetVarNodes_context context;
00393 
00394     context.offset = offset;
00395     context.sublevels_up = sublevels_up;
00396 
00397     /*
00398      * Must be prepared to start with a Query or a bare expression tree; if
00399      * it's a Query, go straight to query_tree_walker to make sure that
00400      * sublevels_up doesn't get incremented prematurely.
00401      */
00402     if (node && IsA(node, Query))
00403     {
00404         Query      *qry = (Query *) node;
00405 
00406         /*
00407          * If we are starting at a Query, and sublevels_up is zero, then we
00408          * must also fix rangetable indexes in the Query itself --- namely
00409          * resultRelation and rowMarks entries.  sublevels_up cannot be zero
00410          * when recursing into a subquery, so there's no need to have the same
00411          * logic inside OffsetVarNodes_walker.
00412          */
00413         if (sublevels_up == 0)
00414         {
00415             ListCell   *l;
00416 
00417             if (qry->resultRelation)
00418                 qry->resultRelation += offset;
00419             foreach(l, qry->rowMarks)
00420             {
00421                 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
00422 
00423                 rc->rti += offset;
00424             }
00425         }
00426         query_tree_walker(qry, OffsetVarNodes_walker,
00427                           (void *) &context, 0);
00428     }
00429     else
00430         OffsetVarNodes_walker(node, &context);
00431 }
00432 
00433 static Relids
00434 offset_relid_set(Relids relids, int offset)
00435 {
00436     Relids      result = NULL;
00437     Relids      tmprelids;
00438     int         rtindex;
00439 
00440     tmprelids = bms_copy(relids);
00441     while ((rtindex = bms_first_member(tmprelids)) >= 0)
00442         result = bms_add_member(result, rtindex + offset);
00443     bms_free(tmprelids);
00444     return result;
00445 }
00446 
00447 /*
00448  * ChangeVarNodes - adjust Var nodes for a specific change of RT index
00449  *
00450  * Find all Var nodes in the given tree belonging to a specific relation
00451  * (identified by sublevels_up and rt_index), and change their varno fields
00452  * to 'new_index'.  The varnoold fields are changed too.  Also, adjust other
00453  * nodes that contain rangetable indexes, such as RangeTblRef and JoinExpr.
00454  *
00455  * NOTE: although this has the form of a walker, we cheat and modify the
00456  * nodes in-place.  The given expression tree should have been copied
00457  * earlier to ensure that no unwanted side-effects occur!
00458  */
00459 
00460 typedef struct
00461 {
00462     int         rt_index;
00463     int         new_index;
00464     int         sublevels_up;
00465 } ChangeVarNodes_context;
00466 
00467 static bool
00468 ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
00469 {
00470     if (node == NULL)
00471         return false;
00472     if (IsA(node, Var))
00473     {
00474         Var        *var = (Var *) node;
00475 
00476         if (var->varlevelsup == context->sublevels_up &&
00477             var->varno == context->rt_index)
00478         {
00479             var->varno = context->new_index;
00480             var->varnoold = context->new_index;
00481         }
00482         return false;
00483     }
00484     if (IsA(node, CurrentOfExpr))
00485     {
00486         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
00487 
00488         if (context->sublevels_up == 0 &&
00489             cexpr->cvarno == context->rt_index)
00490             cexpr->cvarno = context->new_index;
00491         return false;
00492     }
00493     if (IsA(node, RangeTblRef))
00494     {
00495         RangeTblRef *rtr = (RangeTblRef *) node;
00496 
00497         if (context->sublevels_up == 0 &&
00498             rtr->rtindex == context->rt_index)
00499             rtr->rtindex = context->new_index;
00500         /* the subquery itself is visited separately */
00501         return false;
00502     }
00503     if (IsA(node, JoinExpr))
00504     {
00505         JoinExpr   *j = (JoinExpr *) node;
00506 
00507         if (context->sublevels_up == 0 &&
00508             j->rtindex == context->rt_index)
00509             j->rtindex = context->new_index;
00510         /* fall through to examine children */
00511     }
00512     if (IsA(node, PlaceHolderVar))
00513     {
00514         PlaceHolderVar *phv = (PlaceHolderVar *) node;
00515 
00516         if (phv->phlevelsup == context->sublevels_up)
00517         {
00518             phv->phrels = adjust_relid_set(phv->phrels,
00519                                            context->rt_index,
00520                                            context->new_index);
00521         }
00522         /* fall through to examine children */
00523     }
00524     if (IsA(node, PlanRowMark))
00525     {
00526         PlanRowMark *rowmark = (PlanRowMark *) node;
00527 
00528         if (context->sublevels_up == 0)
00529         {
00530             if (rowmark->rti == context->rt_index)
00531                 rowmark->rti = context->new_index;
00532             if (rowmark->prti == context->rt_index)
00533                 rowmark->prti = context->new_index;
00534         }
00535         return false;
00536     }
00537     if (IsA(node, AppendRelInfo))
00538     {
00539         AppendRelInfo *appinfo = (AppendRelInfo *) node;
00540 
00541         if (context->sublevels_up == 0)
00542         {
00543             if (appinfo->parent_relid == context->rt_index)
00544                 appinfo->parent_relid = context->new_index;
00545             if (appinfo->child_relid == context->rt_index)
00546                 appinfo->child_relid = context->new_index;
00547         }
00548         /* fall through to examine children */
00549     }
00550     /* Shouldn't need to handle other planner auxiliary nodes here */
00551     Assert(!IsA(node, SpecialJoinInfo));
00552     Assert(!IsA(node, LateralJoinInfo));
00553     Assert(!IsA(node, PlaceHolderInfo));
00554     Assert(!IsA(node, MinMaxAggInfo));
00555 
00556     if (IsA(node, Query))
00557     {
00558         /* Recurse into subselects */
00559         bool        result;
00560 
00561         context->sublevels_up++;
00562         result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
00563                                    (void *) context, 0);
00564         context->sublevels_up--;
00565         return result;
00566     }
00567     return expression_tree_walker(node, ChangeVarNodes_walker,
00568                                   (void *) context);
00569 }
00570 
00571 void
00572 ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
00573 {
00574     ChangeVarNodes_context context;
00575 
00576     context.rt_index = rt_index;
00577     context.new_index = new_index;
00578     context.sublevels_up = sublevels_up;
00579 
00580     /*
00581      * Must be prepared to start with a Query or a bare expression tree; if
00582      * it's a Query, go straight to query_tree_walker to make sure that
00583      * sublevels_up doesn't get incremented prematurely.
00584      */
00585     if (node && IsA(node, Query))
00586     {
00587         Query      *qry = (Query *) node;
00588 
00589         /*
00590          * If we are starting at a Query, and sublevels_up is zero, then we
00591          * must also fix rangetable indexes in the Query itself --- namely
00592          * resultRelation and rowMarks entries.  sublevels_up cannot be zero
00593          * when recursing into a subquery, so there's no need to have the same
00594          * logic inside ChangeVarNodes_walker.
00595          */
00596         if (sublevels_up == 0)
00597         {
00598             ListCell   *l;
00599 
00600             if (qry->resultRelation == rt_index)
00601                 qry->resultRelation = new_index;
00602             foreach(l, qry->rowMarks)
00603             {
00604                 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
00605 
00606                 if (rc->rti == rt_index)
00607                     rc->rti = new_index;
00608             }
00609         }
00610         query_tree_walker(qry, ChangeVarNodes_walker,
00611                           (void *) &context, 0);
00612     }
00613     else
00614         ChangeVarNodes_walker(node, &context);
00615 }
00616 
00617 /*
00618  * Substitute newrelid for oldrelid in a Relid set
00619  */
00620 static Relids
00621 adjust_relid_set(Relids relids, int oldrelid, int newrelid)
00622 {
00623     if (bms_is_member(oldrelid, relids))
00624     {
00625         /* Ensure we have a modifiable copy */
00626         relids = bms_copy(relids);
00627         /* Remove old, add new */
00628         relids = bms_del_member(relids, oldrelid);
00629         relids = bms_add_member(relids, newrelid);
00630     }
00631     return relids;
00632 }
00633 
00634 /*
00635  * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
00636  *
00637  * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
00638  * and add delta_sublevels_up to their varlevelsup value.  This is needed when
00639  * an expression that's correct for some nesting level is inserted into a
00640  * subquery.  Ordinarily the initial call has min_sublevels_up == 0 so that
00641  * all Vars are affected.  The point of min_sublevels_up is that we can
00642  * increment it when we recurse into a sublink, so that local variables in
00643  * that sublink are not affected, only outer references to vars that belong
00644  * to the expression's original query level or parents thereof.
00645  *
00646  * Likewise for other nodes containing levelsup fields, such as Aggref.
00647  *
00648  * NOTE: although this has the form of a walker, we cheat and modify the
00649  * Var nodes in-place.  The given expression tree should have been copied
00650  * earlier to ensure that no unwanted side-effects occur!
00651  */
00652 
00653 typedef struct
00654 {
00655     int         delta_sublevels_up;
00656     int         min_sublevels_up;
00657 } IncrementVarSublevelsUp_context;
00658 
00659 static bool
00660 IncrementVarSublevelsUp_walker(Node *node,
00661                                IncrementVarSublevelsUp_context *context)
00662 {
00663     if (node == NULL)
00664         return false;
00665     if (IsA(node, Var))
00666     {
00667         Var        *var = (Var *) node;
00668 
00669         if (var->varlevelsup >= context->min_sublevels_up)
00670             var->varlevelsup += context->delta_sublevels_up;
00671         return false;           /* done here */
00672     }
00673     if (IsA(node, CurrentOfExpr))
00674     {
00675         /* this should not happen */
00676         if (context->min_sublevels_up == 0)
00677             elog(ERROR, "cannot push down CurrentOfExpr");
00678         return false;
00679     }
00680     if (IsA(node, Aggref))
00681     {
00682         Aggref     *agg = (Aggref *) node;
00683 
00684         if (agg->agglevelsup >= context->min_sublevels_up)
00685             agg->agglevelsup += context->delta_sublevels_up;
00686         /* fall through to recurse into argument */
00687     }
00688     if (IsA(node, PlaceHolderVar))
00689     {
00690         PlaceHolderVar *phv = (PlaceHolderVar *) node;
00691 
00692         if (phv->phlevelsup >= context->min_sublevels_up)
00693             phv->phlevelsup += context->delta_sublevels_up;
00694         /* fall through to recurse into argument */
00695     }
00696     if (IsA(node, RangeTblEntry))
00697     {
00698         RangeTblEntry *rte = (RangeTblEntry *) node;
00699 
00700         if (rte->rtekind == RTE_CTE)
00701         {
00702             if (rte->ctelevelsup >= context->min_sublevels_up)
00703                 rte->ctelevelsup += context->delta_sublevels_up;
00704         }
00705         return false;           /* allow range_table_walker to continue */
00706     }
00707     if (IsA(node, Query))
00708     {
00709         /* Recurse into subselects */
00710         bool        result;
00711 
00712         context->min_sublevels_up++;
00713         result = query_tree_walker((Query *) node,
00714                                    IncrementVarSublevelsUp_walker,
00715                                    (void *) context,
00716                                    QTW_EXAMINE_RTES);
00717         context->min_sublevels_up--;
00718         return result;
00719     }
00720     return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
00721                                   (void *) context);
00722 }
00723 
00724 void
00725 IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
00726                         int min_sublevels_up)
00727 {
00728     IncrementVarSublevelsUp_context context;
00729 
00730     context.delta_sublevels_up = delta_sublevels_up;
00731     context.min_sublevels_up = min_sublevels_up;
00732 
00733     /*
00734      * Must be prepared to start with a Query or a bare expression tree; if
00735      * it's a Query, we don't want to increment sublevels_up.
00736      */
00737     query_or_expression_tree_walker(node,
00738                                     IncrementVarSublevelsUp_walker,
00739                                     (void *) &context,
00740                                     QTW_EXAMINE_RTES);
00741 }
00742 
00743 /*
00744  * IncrementVarSublevelsUp_rtable -
00745  *  Same as IncrementVarSublevelsUp, but to be invoked on a range table.
00746  */
00747 void
00748 IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up,
00749                                int min_sublevels_up)
00750 {
00751     IncrementVarSublevelsUp_context context;
00752 
00753     context.delta_sublevels_up = delta_sublevels_up;
00754     context.min_sublevels_up = min_sublevels_up;
00755 
00756     range_table_walker(rtable,
00757                        IncrementVarSublevelsUp_walker,
00758                        (void *) &context,
00759                        QTW_EXAMINE_RTES);
00760 }
00761 
00762 
00763 /*
00764  * rangeTableEntry_used - detect whether an RTE is referenced somewhere
00765  *  in var nodes or join or setOp trees of a query or expression.
00766  */
00767 
00768 typedef struct
00769 {
00770     int         rt_index;
00771     int         sublevels_up;
00772 } rangeTableEntry_used_context;
00773 
00774 static bool
00775 rangeTableEntry_used_walker(Node *node,
00776                             rangeTableEntry_used_context *context)
00777 {
00778     if (node == NULL)
00779         return false;
00780     if (IsA(node, Var))
00781     {
00782         Var        *var = (Var *) node;
00783 
00784         if (var->varlevelsup == context->sublevels_up &&
00785             var->varno == context->rt_index)
00786             return true;
00787         return false;
00788     }
00789     if (IsA(node, CurrentOfExpr))
00790     {
00791         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
00792 
00793         if (context->sublevels_up == 0 &&
00794             cexpr->cvarno == context->rt_index)
00795             return true;
00796         return false;
00797     }
00798     if (IsA(node, RangeTblRef))
00799     {
00800         RangeTblRef *rtr = (RangeTblRef *) node;
00801 
00802         if (rtr->rtindex == context->rt_index &&
00803             context->sublevels_up == 0)
00804             return true;
00805         /* the subquery itself is visited separately */
00806         return false;
00807     }
00808     if (IsA(node, JoinExpr))
00809     {
00810         JoinExpr   *j = (JoinExpr *) node;
00811 
00812         if (j->rtindex == context->rt_index &&
00813             context->sublevels_up == 0)
00814             return true;
00815         /* fall through to examine children */
00816     }
00817     /* Shouldn't need to handle planner auxiliary nodes here */
00818     Assert(!IsA(node, PlaceHolderVar));
00819     Assert(!IsA(node, PlanRowMark));
00820     Assert(!IsA(node, SpecialJoinInfo));
00821     Assert(!IsA(node, LateralJoinInfo));
00822     Assert(!IsA(node, AppendRelInfo));
00823     Assert(!IsA(node, PlaceHolderInfo));
00824     Assert(!IsA(node, MinMaxAggInfo));
00825 
00826     if (IsA(node, Query))
00827     {
00828         /* Recurse into subselects */
00829         bool        result;
00830 
00831         context->sublevels_up++;
00832         result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
00833                                    (void *) context, 0);
00834         context->sublevels_up--;
00835         return result;
00836     }
00837     return expression_tree_walker(node, rangeTableEntry_used_walker,
00838                                   (void *) context);
00839 }
00840 
00841 bool
00842 rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
00843 {
00844     rangeTableEntry_used_context context;
00845 
00846     context.rt_index = rt_index;
00847     context.sublevels_up = sublevels_up;
00848 
00849     /*
00850      * Must be prepared to start with a Query or a bare expression tree; if
00851      * it's a Query, we don't want to increment sublevels_up.
00852      */
00853     return query_or_expression_tree_walker(node,
00854                                            rangeTableEntry_used_walker,
00855                                            (void *) &context,
00856                                            0);
00857 }
00858 
00859 
00860 /*
00861  * attribute_used -
00862  *  Check if a specific attribute number of a RTE is used
00863  *  somewhere in the query or expression.
00864  */
00865 
00866 typedef struct
00867 {
00868     int         rt_index;
00869     int         attno;
00870     int         sublevels_up;
00871 } attribute_used_context;
00872 
00873 static bool
00874 attribute_used_walker(Node *node,
00875                       attribute_used_context *context)
00876 {
00877     if (node == NULL)
00878         return false;
00879     if (IsA(node, Var))
00880     {
00881         Var        *var = (Var *) node;
00882 
00883         if (var->varlevelsup == context->sublevels_up &&
00884             var->varno == context->rt_index &&
00885             var->varattno == context->attno)
00886             return true;
00887         return false;
00888     }
00889     if (IsA(node, Query))
00890     {
00891         /* Recurse into subselects */
00892         bool        result;
00893 
00894         context->sublevels_up++;
00895         result = query_tree_walker((Query *) node, attribute_used_walker,
00896                                    (void *) context, 0);
00897         context->sublevels_up--;
00898         return result;
00899     }
00900     return expression_tree_walker(node, attribute_used_walker,
00901                                   (void *) context);
00902 }
00903 
00904 bool
00905 attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
00906 {
00907     attribute_used_context context;
00908 
00909     context.rt_index = rt_index;
00910     context.attno = attno;
00911     context.sublevels_up = sublevels_up;
00912 
00913     /*
00914      * Must be prepared to start with a Query or a bare expression tree; if
00915      * it's a Query, we don't want to increment sublevels_up.
00916      */
00917     return query_or_expression_tree_walker(node,
00918                                            attribute_used_walker,
00919                                            (void *) &context,
00920                                            0);
00921 }
00922 
00923 
00924 /*
00925  * If the given Query is an INSERT ... SELECT construct, extract and
00926  * return the sub-Query node that represents the SELECT part.  Otherwise
00927  * return the given Query.
00928  *
00929  * If subquery_ptr is not NULL, then *subquery_ptr is set to the location
00930  * of the link to the SELECT subquery inside parsetree, or NULL if not an
00931  * INSERT ... SELECT.
00932  *
00933  * This is a hack needed because transformations on INSERT ... SELECTs that
00934  * appear in rule actions should be applied to the source SELECT, not to the
00935  * INSERT part.  Perhaps this can be cleaned up with redesigned querytrees.
00936  */
00937 Query *
00938 getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
00939 {
00940     Query      *selectquery;
00941     RangeTblEntry *selectrte;
00942     RangeTblRef *rtr;
00943 
00944     if (subquery_ptr)
00945         *subquery_ptr = NULL;
00946 
00947     if (parsetree == NULL)
00948         return parsetree;
00949     if (parsetree->commandType != CMD_INSERT)
00950         return parsetree;
00951 
00952     /*
00953      * Currently, this is ONLY applied to rule-action queries, and so we
00954      * expect to find the OLD and NEW placeholder entries in the given query.
00955      * If they're not there, it must be an INSERT/SELECT in which they've been
00956      * pushed down to the SELECT.
00957      */
00958     if (list_length(parsetree->rtable) >= 2 &&
00959         strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
00960                "old") == 0 &&
00961         strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
00962                "new") == 0)
00963         return parsetree;
00964     Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
00965     if (list_length(parsetree->jointree->fromlist) != 1)
00966         elog(ERROR, "expected to find SELECT subquery");
00967     rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
00968     Assert(IsA(rtr, RangeTblRef));
00969     selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
00970     selectquery = selectrte->subquery;
00971     if (!(selectquery && IsA(selectquery, Query) &&
00972           selectquery->commandType == CMD_SELECT))
00973         elog(ERROR, "expected to find SELECT subquery");
00974     if (list_length(selectquery->rtable) >= 2 &&
00975         strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
00976                "old") == 0 &&
00977         strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
00978                "new") == 0)
00979     {
00980         if (subquery_ptr)
00981             *subquery_ptr = &(selectrte->subquery);
00982         return selectquery;
00983     }
00984     elog(ERROR, "could not find rule placeholders");
00985     return NULL;                /* not reached */
00986 }
00987 
00988 
00989 /*
00990  * Add the given qualifier condition to the query's WHERE clause
00991  */
00992 void
00993 AddQual(Query *parsetree, Node *qual)
00994 {
00995     Node       *copy;
00996 
00997     if (qual == NULL)
00998         return;
00999 
01000     if (parsetree->commandType == CMD_UTILITY)
01001     {
01002         /*
01003          * There's noplace to put the qual on a utility statement.
01004          *
01005          * If it's a NOTIFY, silently ignore the qual; this means that the
01006          * NOTIFY will execute, whether or not there are any qualifying rows.
01007          * While clearly wrong, this is much more useful than refusing to
01008          * execute the rule at all, and extra NOTIFY events are harmless for
01009          * typical uses of NOTIFY.
01010          *
01011          * If it isn't a NOTIFY, error out, since unconditional execution of
01012          * other utility stmts is unlikely to be wanted.  (This case is not
01013          * currently allowed anyway, but keep the test for safety.)
01014          */
01015         if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
01016             return;
01017         else
01018             ereport(ERROR,
01019                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01020               errmsg("conditional utility statements are not implemented")));
01021     }
01022 
01023     if (parsetree->setOperations != NULL)
01024     {
01025         /*
01026          * There's noplace to put the qual on a setop statement, either. (This
01027          * could be fixed, but right now the planner simply ignores any qual
01028          * condition on a setop query.)
01029          */
01030         ereport(ERROR,
01031                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01032                  errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
01033     }
01034 
01035     /* INTERSECT want's the original, but we need to copy - Jan */
01036     copy = copyObject(qual);
01037 
01038     parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
01039                                                copy);
01040 
01041     /*
01042      * We had better not have stuck an aggregate into the WHERE clause.
01043      */
01044     Assert(!contain_aggs_of_level(copy, 0));
01045 
01046     /*
01047      * Make sure query is marked correctly if added qual has sublinks. Need
01048      * not search qual when query is already marked.
01049      */
01050     if (!parsetree->hasSubLinks)
01051         parsetree->hasSubLinks = checkExprHasSubLink(copy);
01052 }
01053 
01054 
01055 /*
01056  * Invert the given clause and add it to the WHERE qualifications of the
01057  * given querytree.  Inversion means "x IS NOT TRUE", not just "NOT x",
01058  * else we will do the wrong thing when x evaluates to NULL.
01059  */
01060 void
01061 AddInvertedQual(Query *parsetree, Node *qual)
01062 {
01063     BooleanTest *invqual;
01064 
01065     if (qual == NULL)
01066         return;
01067 
01068     /* Need not copy input qual, because AddQual will... */
01069     invqual = makeNode(BooleanTest);
01070     invqual->arg = (Expr *) qual;
01071     invqual->booltesttype = IS_NOT_TRUE;
01072 
01073     AddQual(parsetree, (Node *) invqual);
01074 }
01075 
01076 
01077 /*
01078  * replace_rte_variables() finds all Vars in an expression tree
01079  * that reference a particular RTE, and replaces them with substitute
01080  * expressions obtained from a caller-supplied callback function.
01081  *
01082  * When invoking replace_rte_variables on a portion of a Query, pass the
01083  * address of the containing Query's hasSubLinks field as outer_hasSubLinks.
01084  * Otherwise, pass NULL, but inserting a SubLink into a non-Query expression
01085  * will then cause an error.
01086  *
01087  * Note: the business with inserted_sublink is needed to update hasSubLinks
01088  * in subqueries when the replacement adds a subquery inside a subquery.
01089  * Messy, isn't it?  We do not need to do similar pushups for hasAggs,
01090  * because it isn't possible for this transformation to insert a level-zero
01091  * aggregate reference into a subquery --- it could only insert outer aggs.
01092  * Likewise for hasWindowFuncs.
01093  *
01094  * Note: usually, we'd not expose the mutator function or context struct
01095  * for a function like this.  We do so because callbacks often find it
01096  * convenient to recurse directly to the mutator on sub-expressions of
01097  * what they will return.
01098  */
01099 Node *
01100 replace_rte_variables(Node *node, int target_varno, int sublevels_up,
01101                       replace_rte_variables_callback callback,
01102                       void *callback_arg,
01103                       bool *outer_hasSubLinks)
01104 {
01105     Node       *result;
01106     replace_rte_variables_context context;
01107 
01108     context.callback = callback;
01109     context.callback_arg = callback_arg;
01110     context.target_varno = target_varno;
01111     context.sublevels_up = sublevels_up;
01112 
01113     /*
01114      * We try to initialize inserted_sublink to true if there is no need to
01115      * detect new sublinks because the query already has some.
01116      */
01117     if (node && IsA(node, Query))
01118         context.inserted_sublink = ((Query *) node)->hasSubLinks;
01119     else if (outer_hasSubLinks)
01120         context.inserted_sublink = *outer_hasSubLinks;
01121     else
01122         context.inserted_sublink = false;
01123 
01124     /*
01125      * Must be prepared to start with a Query or a bare expression tree; if
01126      * it's a Query, we don't want to increment sublevels_up.
01127      */
01128     result = query_or_expression_tree_mutator(node,
01129                                               replace_rte_variables_mutator,
01130                                               (void *) &context,
01131                                               0);
01132 
01133     if (context.inserted_sublink)
01134     {
01135         if (result && IsA(result, Query))
01136             ((Query *) result)->hasSubLinks = true;
01137         else if (outer_hasSubLinks)
01138             *outer_hasSubLinks = true;
01139         else
01140             elog(ERROR, "replace_rte_variables inserted a SubLink, but has noplace to record it");
01141     }
01142 
01143     return result;
01144 }
01145 
01146 Node *
01147 replace_rte_variables_mutator(Node *node,
01148                               replace_rte_variables_context *context)
01149 {
01150     if (node == NULL)
01151         return NULL;
01152     if (IsA(node, Var))
01153     {
01154         Var        *var = (Var *) node;
01155 
01156         if (var->varno == context->target_varno &&
01157             var->varlevelsup == context->sublevels_up)
01158         {
01159             /* Found a matching variable, make the substitution */
01160             Node       *newnode;
01161 
01162             newnode = (*context->callback) (var, context);
01163             /* Detect if we are adding a sublink to query */
01164             if (!context->inserted_sublink)
01165                 context->inserted_sublink = checkExprHasSubLink(newnode);
01166             return newnode;
01167         }
01168         /* otherwise fall through to copy the var normally */
01169     }
01170     else if (IsA(node, CurrentOfExpr))
01171     {
01172         CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
01173 
01174         if (cexpr->cvarno == context->target_varno &&
01175             context->sublevels_up == 0)
01176         {
01177             /*
01178              * We get here if a WHERE CURRENT OF expression turns out to apply
01179              * to a view.  Someday we might be able to translate the
01180              * expression to apply to an underlying table of the view, but
01181              * right now it's not implemented.
01182              */
01183             ereport(ERROR,
01184                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01185                    errmsg("WHERE CURRENT OF on a view is not implemented")));
01186         }
01187         /* otherwise fall through to copy the expr normally */
01188     }
01189     else if (IsA(node, Query))
01190     {
01191         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
01192         Query      *newnode;
01193         bool        save_inserted_sublink;
01194 
01195         context->sublevels_up++;
01196         save_inserted_sublink = context->inserted_sublink;
01197         context->inserted_sublink = ((Query *) node)->hasSubLinks;
01198         newnode = query_tree_mutator((Query *) node,
01199                                      replace_rte_variables_mutator,
01200                                      (void *) context,
01201                                      0);
01202         newnode->hasSubLinks |= context->inserted_sublink;
01203         context->inserted_sublink = save_inserted_sublink;
01204         context->sublevels_up--;
01205         return (Node *) newnode;
01206     }
01207     return expression_tree_mutator(node, replace_rte_variables_mutator,
01208                                    (void *) context);
01209 }
01210 
01211 
01212 /*
01213  * map_variable_attnos() finds all user-column Vars in an expression tree
01214  * that reference a particular RTE, and adjusts their varattnos according
01215  * to the given mapping array (varattno n is replaced by attno_map[n-1]).
01216  * Vars for system columns are not modified.
01217  *
01218  * A zero in the mapping array represents a dropped column, which should not
01219  * appear in the expression.
01220  *
01221  * If the expression tree contains a whole-row Var for the target RTE,
01222  * the Var is not changed but *found_whole_row is returned as TRUE.
01223  * For most callers this is an error condition, but we leave it to the caller
01224  * to report the error so that useful context can be provided.  (In some
01225  * usages it would be appropriate to modify the Var's vartype and insert a
01226  * ConvertRowtypeExpr node to map back to the original vartype.  We might
01227  * someday extend this function's API to support that.  For now, the only
01228  * concession to that future need is that this function is a tree mutator
01229  * not just a walker.)
01230  *
01231  * This could be built using replace_rte_variables and a callback function,
01232  * but since we don't ever need to insert sublinks, replace_rte_variables is
01233  * overly complicated.
01234  */
01235 
01236 typedef struct
01237 {
01238     int         target_varno;       /* RTE index to search for */
01239     int         sublevels_up;       /* (current) nesting depth */
01240     const AttrNumber *attno_map;    /* map array for user attnos */
01241     int         map_length;         /* number of entries in attno_map[] */
01242     bool       *found_whole_row;    /* output flag */
01243 } map_variable_attnos_context;
01244 
01245 static Node *
01246 map_variable_attnos_mutator(Node *node,
01247                             map_variable_attnos_context *context)
01248 {
01249     if (node == NULL)
01250         return NULL;
01251     if (IsA(node, Var))
01252     {
01253         Var        *var = (Var *) node;
01254 
01255         if (var->varno == context->target_varno &&
01256             var->varlevelsup == context->sublevels_up)
01257         {
01258             /* Found a matching variable, make the substitution */
01259             Var    *newvar = (Var *) palloc(sizeof(Var));
01260             int     attno = var->varattno;
01261 
01262             *newvar = *var;
01263             if (attno > 0)
01264             {
01265                 /* user-defined column, replace attno */
01266                 if (attno > context->map_length ||
01267                     context->attno_map[attno - 1] == 0)
01268                     elog(ERROR, "unexpected varattno %d in expression to be mapped",
01269                          attno);
01270                 newvar->varattno = newvar->varoattno = context->attno_map[attno - 1];
01271             }
01272             else if (attno == 0)
01273             {
01274                 /* whole-row variable, warn caller */
01275                 *(context->found_whole_row) = true;
01276             }
01277             return (Node *) newvar;
01278         }
01279         /* otherwise fall through to copy the var normally */
01280     }
01281     else if (IsA(node, Query))
01282     {
01283         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
01284         Query      *newnode;
01285 
01286         context->sublevels_up++;
01287         newnode = query_tree_mutator((Query *) node,
01288                                      map_variable_attnos_mutator,
01289                                      (void *) context,
01290                                      0);
01291         context->sublevels_up--;
01292         return (Node *) newnode;
01293     }
01294     return expression_tree_mutator(node, map_variable_attnos_mutator,
01295                                    (void *) context);
01296 }
01297 
01298 Node *
01299 map_variable_attnos(Node *node,
01300                     int target_varno, int sublevels_up,
01301                     const AttrNumber *attno_map, int map_length,
01302                     bool *found_whole_row)
01303 {
01304     map_variable_attnos_context context;
01305 
01306     context.target_varno = target_varno;
01307     context.sublevels_up = sublevels_up;
01308     context.attno_map = attno_map;
01309     context.map_length = map_length;
01310     context.found_whole_row = found_whole_row;
01311 
01312     *found_whole_row = false;
01313 
01314     /*
01315      * Must be prepared to start with a Query or a bare expression tree; if
01316      * it's a Query, we don't want to increment sublevels_up.
01317      */
01318     return query_or_expression_tree_mutator(node,
01319                                             map_variable_attnos_mutator,
01320                                             (void *) &context,
01321                                             0);
01322 }
01323 
01324 
01325 /*
01326  * ReplaceVarsFromTargetList - replace Vars with items from a targetlist
01327  *
01328  * Vars matching target_varno and sublevels_up are replaced by the
01329  * entry with matching resno from targetlist, if there is one.
01330  *
01331  * If there is no matching resno for such a Var, the action depends on the
01332  * nomatch_option:
01333  *  REPLACEVARS_REPORT_ERROR: throw an error
01334  *  REPLACEVARS_CHANGE_VARNO: change Var's varno to nomatch_varno
01335  *  REPLACEVARS_SUBSTITUTE_NULL: replace Var with a NULL Const of same type
01336  *
01337  * The caller must also provide target_rte, the RTE describing the target
01338  * relation.  This is needed to handle whole-row Vars referencing the target.
01339  * We expand such Vars into RowExpr constructs.
01340  *
01341  * outer_hasSubLinks works the same as for replace_rte_variables().
01342  */
01343 
01344 typedef struct
01345 {
01346     RangeTblEntry *target_rte;
01347     List       *targetlist;
01348     ReplaceVarsNoMatchOption nomatch_option;
01349     int         nomatch_varno;
01350 } ReplaceVarsFromTargetList_context;
01351 
01352 static Node *
01353 ReplaceVarsFromTargetList_callback(Var *var,
01354                                    replace_rte_variables_context *context)
01355 {
01356     ReplaceVarsFromTargetList_context *rcon = (ReplaceVarsFromTargetList_context *) context->callback_arg;
01357     TargetEntry *tle;
01358 
01359     if (var->varattno == InvalidAttrNumber)
01360     {
01361         /* Must expand whole-tuple reference into RowExpr */
01362         RowExpr    *rowexpr;
01363         List       *colnames;
01364         List       *fields;
01365 
01366         /*
01367          * If generating an expansion for a var of a named rowtype (ie, this
01368          * is a plain relation RTE), then we must include dummy items for
01369          * dropped columns.  If the var is RECORD (ie, this is a JOIN), then
01370          * omit dropped columns.  Either way, attach column names to the
01371          * RowExpr for use of ruleutils.c.
01372          */
01373         expandRTE(rcon->target_rte,
01374                   var->varno, var->varlevelsup, var->location,
01375                   (var->vartype != RECORDOID),
01376                   &colnames, &fields);
01377         /* Adjust the generated per-field Vars... */
01378         fields = (List *) replace_rte_variables_mutator((Node *) fields,
01379                                                         context);
01380         rowexpr = makeNode(RowExpr);
01381         rowexpr->args = fields;
01382         rowexpr->row_typeid = var->vartype;
01383         rowexpr->row_format = COERCE_IMPLICIT_CAST;
01384         rowexpr->colnames = colnames;
01385         rowexpr->location = var->location;
01386 
01387         return (Node *) rowexpr;
01388     }
01389 
01390     /* Normal case referencing one targetlist element */
01391     tle = get_tle_by_resno(rcon->targetlist, var->varattno);
01392 
01393     if (tle == NULL || tle->resjunk)
01394     {
01395         /* Failed to find column in targetlist */
01396         switch (rcon->nomatch_option)
01397         {
01398             case REPLACEVARS_REPORT_ERROR:
01399                 /* fall through, throw error below */
01400                 break;
01401 
01402             case REPLACEVARS_CHANGE_VARNO:
01403                 var = (Var *) copyObject(var);
01404                 var->varno = rcon->nomatch_varno;
01405                 var->varnoold = rcon->nomatch_varno;
01406                 return (Node *) var;
01407 
01408             case REPLACEVARS_SUBSTITUTE_NULL:
01409                 /*
01410                  * If Var is of domain type, we should add a CoerceToDomain
01411                  * node, in case there is a NOT NULL domain constraint.
01412                  */
01413                 return coerce_to_domain((Node *) makeNullConst(var->vartype,
01414                                                                var->vartypmod,
01415                                                                var->varcollid),
01416                                         InvalidOid, -1,
01417                                         var->vartype,
01418                                         COERCE_IMPLICIT_CAST,
01419                                         -1,
01420                                         false,
01421                                         false);
01422         }
01423         elog(ERROR, "could not find replacement targetlist entry for attno %d",
01424              var->varattno);
01425         return NULL;            /* keep compiler quiet */
01426     }
01427     else
01428     {
01429         /* Make a copy of the tlist item to return */
01430         Node       *newnode = copyObject(tle->expr);
01431 
01432         /* Must adjust varlevelsup if tlist item is from higher query */
01433         if (var->varlevelsup > 0)
01434             IncrementVarSublevelsUp(newnode, var->varlevelsup, 0);
01435 
01436         return newnode;
01437     }
01438 }
01439 
01440 Node *
01441 ReplaceVarsFromTargetList(Node *node,
01442                           int target_varno, int sublevels_up,
01443                           RangeTblEntry *target_rte,
01444                           List *targetlist,
01445                           ReplaceVarsNoMatchOption nomatch_option,
01446                           int nomatch_varno,
01447                           bool *outer_hasSubLinks)
01448 {
01449     ReplaceVarsFromTargetList_context context;
01450 
01451     context.target_rte = target_rte;
01452     context.targetlist = targetlist;
01453     context.nomatch_option = nomatch_option;
01454     context.nomatch_varno = nomatch_varno;
01455 
01456     return replace_rte_variables(node, target_varno, sublevels_up,
01457                                  ReplaceVarsFromTargetList_callback,
01458                                  (void *) &context,
01459                                  outer_hasSubLinks);
01460 }