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