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