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