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