TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * rewriteManip.c
4 : *
5 : * Portions Copyright (c) 1996-2023, 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 : typedef struct
44 : {
45 : const Bitmapset *target_relids;
46 : const Bitmapset *added_relids;
47 : int sublevels_up;
48 : } add_nulling_relids_context;
49 :
50 : typedef struct
51 : {
52 : const Bitmapset *removable_relids;
53 : const Bitmapset *except_relids;
54 : int sublevels_up;
55 : } remove_nulling_relids_context;
56 :
57 : static bool contain_aggs_of_level_walker(Node *node,
58 : contain_aggs_of_level_context *context);
59 : static bool locate_agg_of_level_walker(Node *node,
60 : locate_agg_of_level_context *context);
61 : static bool contain_windowfuncs_walker(Node *node, void *context);
62 : static bool locate_windowfunc_walker(Node *node,
63 : locate_windowfunc_context *context);
64 : static bool checkExprHasSubLink_walker(Node *node, void *context);
65 : static Relids offset_relid_set(Relids relids, int offset);
66 : static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
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 GIC 1192 : contain_aggs_of_level(Node *node, int levelsup)
86 : {
87 : contain_aggs_of_level_context context;
88 :
89 1192 : 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 1192 : return query_or_expression_tree_walker(node,
96 : contain_aggs_of_level_walker,
97 : (void *) &context,
98 : 0);
99 : }
100 :
101 : static bool
102 5678 : contain_aggs_of_level_walker(Node *node,
103 ECB : contain_aggs_of_level_context *context)
104 : {
105 GIC 5678 : if (node == NULL)
106 652 : return false;
107 CBC 5026 : if (IsA(node, Aggref))
108 : {
109 UIC 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 CBC 5026 : if (IsA(node, GroupingFunc))
114 : {
115 UIC 0 : if (((GroupingFunc *) node)->agglevelsup == context->sublevels_up)
116 0 : return true;
117 : /* else fall through to examine argument */
118 : }
119 GIC 5026 : if (IsA(node, Query))
120 ECB : {
121 : /* Recurse into subselects */
122 : bool result;
123 :
124 CBC 50 : context->sublevels_up++;
125 50 : result = query_tree_walker((Query *) node,
126 : contain_aggs_of_level_walker,
127 EUB : (void *) context, 0);
128 GBC 50 : context->sublevels_up--;
129 GIC 50 : return result;
130 : }
131 CBC 4976 : return expression_tree_walker(node, contain_aggs_of_level_walker,
132 : (void *) context);
133 EUB : }
134 :
135 : /*
136 : * locate_agg_of_level -
137 ECB : * 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 CBC 30 : locate_agg_of_level(Node *node, int levelsup)
150 : {
151 : locate_agg_of_level_context context;
152 :
153 GIC 30 : context.agg_location = -1; /* in case we find nothing */
154 30 : 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 30 : (void) query_or_expression_tree_walker(node,
161 : locate_agg_of_level_walker,
162 : (void *) &context,
163 : 0);
164 :
165 30 : return context.agg_location;
166 : }
167 ECB :
168 : static bool
169 GIC 120 : locate_agg_of_level_walker(Node *node,
170 : locate_agg_of_level_context *context)
171 ECB : {
172 CBC 120 : if (node == NULL)
173 GIC 6 : return false;
174 114 : if (IsA(node, Aggref))
175 : {
176 27 : if (((Aggref *) node)->agglevelsup == context->sublevels_up &&
177 24 : ((Aggref *) node)->location >= 0)
178 ECB : {
179 GIC 24 : context->agg_location = ((Aggref *) node)->location;
180 24 : return true; /* abort the tree traversal and return true */
181 : }
182 : /* else fall through to examine argument */
183 ECB : }
184 GIC 90 : if (IsA(node, GroupingFunc))
185 : {
186 UIC 0 : if (((GroupingFunc *) node)->agglevelsup == context->sublevels_up &&
187 LBC 0 : ((GroupingFunc *) node)->location >= 0)
188 : {
189 UIC 0 : context->agg_location = ((GroupingFunc *) node)->location;
190 LBC 0 : return true; /* abort the tree traversal and return true */
191 ECB : }
192 : }
193 GIC 90 : if (IsA(node, Query))
194 ECB : {
195 : /* Recurse into subselects */
196 : bool result;
197 :
198 CBC 6 : context->sublevels_up++;
199 GIC 6 : result = query_tree_walker((Query *) node,
200 : locate_agg_of_level_walker,
201 : (void *) context, 0);
202 CBC 6 : context->sublevels_up--;
203 GIC 6 : return result;
204 EUB : }
205 GBC 84 : return expression_tree_walker(node, locate_agg_of_level_walker,
206 : (void *) context);
207 EUB : }
208 :
209 : /*
210 : * contain_windowfuncs -
211 ECB : * Check if an expression contains a window function call of the
212 : * current query level.
213 : */
214 : bool
215 GIC 837 : contain_windowfuncs(Node *node)
216 ECB : {
217 : /*
218 : * Must be prepared to start with a Query or a bare expression tree; if
219 : * it's a Query, we don't want to increment sublevels_up.
220 : */
221 CBC 837 : return query_or_expression_tree_walker(node,
222 : contain_windowfuncs_walker,
223 ECB : NULL,
224 : 0);
225 : }
226 :
227 : static bool
228 GIC 1188 : contain_windowfuncs_walker(Node *node, void *context)
229 : {
230 1188 : if (node == NULL)
231 84 : return false;
232 1104 : if (IsA(node, WindowFunc))
233 CBC 6 : return true; /* abort the tree traversal and return true */
234 : /* Mustn't recurse into subselects */
235 GIC 1098 : return expression_tree_walker(node, contain_windowfuncs_walker,
236 : (void *) context);
237 : }
238 :
239 ECB : /*
240 : * locate_windowfunc -
241 : * Find the parse location of any windowfunc of the current query level.
242 : *
243 : * Returns -1 if no such windowfunc is in the querytree, or if they all have
244 : * unknown parse location. (The former case is probably caller error,
245 : * but we don't bother to distinguish it from the latter case.)
246 : *
247 : * Note: it might seem appropriate to merge this functionality into
248 : * contain_windowfuncs, but that would complicate that function's API.
249 : * Currently, the only uses of this function are for error reporting,
250 : * and so shaving cycles probably isn't very important.
251 : */
252 : int
253 CBC 3 : locate_windowfunc(Node *node)
254 : {
255 : locate_windowfunc_context context;
256 :
257 GIC 3 : context.win_location = -1; /* in case we find nothing */
258 :
259 : /*
260 : * Must be prepared to start with a Query or a bare expression tree; if
261 : * it's a Query, we don't want to increment sublevels_up.
262 : */
263 3 : (void) query_or_expression_tree_walker(node,
264 : locate_windowfunc_walker,
265 : (void *) &context,
266 : 0);
267 :
268 3 : return context.win_location;
269 : }
270 :
271 ECB : static bool
272 GIC 3 : locate_windowfunc_walker(Node *node, locate_windowfunc_context *context)
273 : {
274 3 : if (node == NULL)
275 LBC 0 : return false;
276 GIC 3 : if (IsA(node, WindowFunc))
277 : {
278 3 : if (((WindowFunc *) node)->location >= 0)
279 : {
280 3 : context->win_location = ((WindowFunc *) node)->location;
281 CBC 3 : return true; /* abort the tree traversal and return true */
282 : }
283 : /* else fall through to examine argument */
284 : }
285 : /* Mustn't recurse into subselects */
286 LBC 0 : return expression_tree_walker(node, locate_windowfunc_walker,
287 : (void *) context);
288 : }
289 :
290 ECB : /*
291 : * checkExprHasSubLink -
292 : * Check if an expression contains a SubLink.
293 EUB : */
294 ECB : bool
295 GIC 51578 : checkExprHasSubLink(Node *node)
296 ECB : {
297 : /*
298 : * If a Query is passed, examine it --- but we should not recurse into
299 : * sub-Queries that are in its rangetable or CTE list.
300 : */
301 GIC 51578 : return query_or_expression_tree_walker(node,
302 : checkExprHasSubLink_walker,
303 : NULL,
304 EUB : QTW_IGNORE_RC_SUBQUERIES);
305 : }
306 :
307 : static bool
308 GIC 86564 : checkExprHasSubLink_walker(Node *node, void *context)
309 : {
310 86564 : if (node == NULL)
311 1743 : return false;
312 84821 : if (IsA(node, SubLink))
313 CBC 3161 : return true; /* abort the tree traversal and return true */
314 GIC 81660 : return expression_tree_walker(node, checkExprHasSubLink_walker, context);
315 : }
316 :
317 : /*
318 : * Check for MULTIEXPR Param within expression tree
319 ECB : *
320 : * We intentionally don't descend into SubLinks: only Params at the current
321 : * query level are of interest.
322 : */
323 : static bool
324 GIC 4102 : contains_multiexpr_param(Node *node, void *context)
325 : {
326 CBC 4102 : if (node == NULL)
327 GIC 9 : return false;
328 CBC 4093 : if (IsA(node, Param))
329 ECB : {
330 LBC 0 : if (((Param *) node)->paramkind == PARAM_MULTIEXPR)
331 0 : return true; /* abort the tree traversal and return true */
332 0 : return false;
333 : }
334 GIC 4093 : return expression_tree_walker(node, contains_multiexpr_param, context);
335 : }
336 :
337 : /*
338 : * CombineRangeTables
339 : * Adds the RTEs of 'src_rtable' into 'dst_rtable'
340 : *
341 : * This also adds the RTEPermissionInfos of 'src_perminfos' (belonging to the
342 : * RTEs in 'src_rtable') into *dst_perminfos and also updates perminfoindex of
343 : * the RTEs in 'src_rtable' to now point to the perminfos' indexes in
344 : * *dst_perminfos.
345 : *
346 : * Note that this changes both 'dst_rtable' and 'dst_perminfo' destructively,
347 : * so the caller should have better passed safe-to-modify copies.
348 : */
349 : void
350 GNC 18811 : CombineRangeTables(List **dst_rtable, List **dst_perminfos,
351 : List *src_rtable, List *src_perminfos)
352 : {
353 : ListCell *l;
354 18811 : int offset = list_length(*dst_perminfos);
355 :
356 18811 : if (offset > 0)
357 : {
358 46089 : foreach(l, src_rtable)
359 : {
360 30915 : RangeTblEntry *rte = lfirst_node(RangeTblEntry, l);
361 :
362 30915 : if (rte->perminfoindex > 0)
363 18337 : rte->perminfoindex += offset;
364 : }
365 : }
366 :
367 18811 : *dst_perminfos = list_concat(*dst_perminfos, src_perminfos);
368 18811 : *dst_rtable = list_concat(*dst_rtable, src_rtable);
369 18811 : }
370 :
371 : /*
372 : * OffsetVarNodes - adjust Vars when appending one query's RT to another
373 : *
374 : * Find all Var nodes in the given tree with varlevelsup == sublevels_up,
375 ECB : * and increment their varno fields (rangetable indexes) by 'offset'.
376 : * The varnosyn fields are adjusted similarly. Also, adjust other nodes
377 : * that contain rangetable indexes, such as RangeTblRef and JoinExpr.
378 : *
379 : * NOTE: although this has the form of a walker, we cheat and modify the
380 : * nodes in-place. The given expression tree should have been copied
381 EUB : * earlier to ensure that no unwanted side-effects occur!
382 : */
383 :
384 : typedef struct
385 ECB : {
386 : int offset;
387 : int sublevels_up;
388 : } OffsetVarNodes_context;
389 :
390 : static bool
391 GIC 994434 : OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
392 : {
393 994434 : if (node == NULL)
394 301540 : return false;
395 692894 : if (IsA(node, Var))
396 : {
397 356047 : Var *var = (Var *) node;
398 :
399 356047 : if (var->varlevelsup == context->sublevels_up)
400 : {
401 CBC 342896 : var->varno += context->offset;
402 GNC 342896 : var->varnullingrels = offset_relid_set(var->varnullingrels,
403 : context->offset);
404 GIC 342896 : if (var->varnosyn > 0)
405 342896 : var->varnosyn += context->offset;
406 : }
407 CBC 356047 : return false;
408 : }
409 336847 : if (IsA(node, CurrentOfExpr))
410 : {
411 LBC 0 : CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
412 :
413 0 : if (context->sublevels_up == 0)
414 UIC 0 : cexpr->cvarno += context->offset;
415 LBC 0 : return false;
416 ECB : }
417 GIC 336847 : if (IsA(node, RangeTblRef))
418 : {
419 29780 : RangeTblRef *rtr = (RangeTblRef *) node;
420 ECB :
421 CBC 29780 : if (context->sublevels_up == 0)
422 25462 : rtr->rtindex += context->offset;
423 : /* the subquery itself is visited separately */
424 GIC 29780 : return false;
425 : }
426 307067 : if (IsA(node, JoinExpr))
427 : {
428 6867 : JoinExpr *j = (JoinExpr *) node;
429 :
430 6867 : if (j->rtindex && context->sublevels_up == 0)
431 6109 : j->rtindex += context->offset;
432 : /* fall through to examine children */
433 : }
434 307067 : if (IsA(node, PlaceHolderVar))
435 : {
436 202 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
437 :
438 202 : if (phv->phlevelsup == context->sublevels_up)
439 : {
440 166 : phv->phrels = offset_relid_set(phv->phrels,
441 : context->offset);
442 GNC 166 : phv->phnullingrels = offset_relid_set(phv->phnullingrels,
443 : context->offset);
444 : }
445 : /* fall through to examine children */
446 ECB : }
447 GIC 307067 : if (IsA(node, AppendRelInfo))
448 ECB : {
449 CBC 196 : AppendRelInfo *appinfo = (AppendRelInfo *) node;
450 ECB :
451 GIC 196 : if (context->sublevels_up == 0)
452 ECB : {
453 GIC 196 : appinfo->parent_relid += context->offset;
454 CBC 196 : appinfo->child_relid += context->offset;
455 : }
456 ECB : /* fall through to examine children */
457 : }
458 : /* Shouldn't need to handle other planner auxiliary nodes here */
459 CBC 307067 : Assert(!IsA(node, PlanRowMark));
460 307067 : Assert(!IsA(node, SpecialJoinInfo));
461 GIC 307067 : Assert(!IsA(node, PlaceHolderInfo));
462 CBC 307067 : Assert(!IsA(node, MinMaxAggInfo));
463 :
464 307067 : if (IsA(node, Query))
465 : {
466 EUB : /* Recurse into subselects */
467 : bool result;
468 :
469 GBC 4134 : context->sublevels_up++;
470 4134 : result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
471 : (void *) context, 0);
472 CBC 4134 : context->sublevels_up--;
473 GIC 4134 : return result;
474 ECB : }
475 GIC 302933 : return expression_tree_walker(node, OffsetVarNodes_walker,
476 ECB : (void *) context);
477 : }
478 :
479 : void
480 GIC 36378 : OffsetVarNodes(Node *node, int offset, int sublevels_up)
481 ECB : {
482 : OffsetVarNodes_context context;
483 :
484 GIC 36378 : context.offset = offset;
485 CBC 36378 : context.sublevels_up = sublevels_up;
486 ECB :
487 : /*
488 : * Must be prepared to start with a Query or a bare expression tree; if
489 : * it's a Query, go straight to query_tree_walker to make sure that
490 : * sublevels_up doesn't get incremented prematurely.
491 : */
492 GIC 36378 : if (node && IsA(node, Query))
493 CBC 18189 : {
494 GIC 18189 : Query *qry = (Query *) node;
495 ECB :
496 : /*
497 : * If we are starting at a Query, and sublevels_up is zero, then we
498 : * must also fix rangetable indexes in the Query itself --- namely
499 : * resultRelation, exclRelIndex and rowMarks entries. sublevels_up
500 : * cannot be zero when recursing into a subquery, so there's no need
501 : * to have the same logic inside OffsetVarNodes_walker.
502 : */
503 GIC 18189 : if (sublevels_up == 0)
504 ECB : {
505 : ListCell *l;
506 :
507 GIC 18189 : if (qry->resultRelation)
508 CBC 612 : qry->resultRelation += offset;
509 ECB :
510 GIC 18189 : if (qry->onConflict && qry->onConflict->exclRelIndex)
511 18 : qry->onConflict->exclRelIndex += offset;
512 :
513 18263 : foreach(l, qry->rowMarks)
514 ECB : {
515 CBC 74 : RowMarkClause *rc = (RowMarkClause *) lfirst(l);
516 ECB :
517 CBC 74 : rc->rti += offset;
518 : }
519 ECB : }
520 GIC 18189 : query_tree_walker(qry, OffsetVarNodes_walker,
521 : (void *) &context, 0);
522 : }
523 : else
524 CBC 18189 : OffsetVarNodes_walker(node, &context);
525 36378 : }
526 :
527 ECB : static Relids
528 CBC 343228 : offset_relid_set(Relids relids, int offset)
529 : {
530 343228 : Relids result = NULL;
531 : int rtindex;
532 :
533 GIC 343228 : rtindex = -1;
534 387454 : while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
535 CBC 44226 : result = bms_add_member(result, rtindex + offset);
536 GIC 343228 : return result;
537 : }
538 :
539 ECB : /*
540 : * ChangeVarNodes - adjust Var nodes for a specific change of RT index
541 : *
542 : * Find all Var nodes in the given tree belonging to a specific relation
543 : * (identified by sublevels_up and rt_index), and change their varno fields
544 : * to 'new_index'. The varnosyn fields are changed too. Also, adjust other
545 : * nodes that contain rangetable indexes, such as RangeTblRef and JoinExpr.
546 : *
547 : * NOTE: although this has the form of a walker, we cheat and modify the
548 : * nodes in-place. The given expression tree should have been copied
549 : * earlier to ensure that no unwanted side-effects occur!
550 : */
551 :
552 : typedef struct
553 : {
554 : int rt_index;
555 : int new_index;
556 : int sublevels_up;
557 : } ChangeVarNodes_context;
558 :
559 : static bool
560 GIC 100723 : ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
561 : {
562 CBC 100723 : if (node == NULL)
563 34161 : return false;
564 GIC 66562 : if (IsA(node, Var))
565 ECB : {
566 CBC 18503 : Var *var = (Var *) node;
567 :
568 GNC 18503 : if (var->varlevelsup == context->sublevels_up)
569 ECB : {
570 GNC 17606 : if (var->varno == context->rt_index)
571 13464 : var->varno = context->new_index;
572 17606 : var->varnullingrels = adjust_relid_set(var->varnullingrels,
573 : context->rt_index,
574 : context->new_index);
575 GIC 17606 : if (var->varnosyn == context->rt_index)
576 13464 : var->varnosyn = context->new_index;
577 ECB : }
578 GIC 18503 : return false;
579 : }
580 48059 : if (IsA(node, CurrentOfExpr))
581 ECB : {
582 LBC 0 : CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
583 :
584 UIC 0 : if (context->sublevels_up == 0 &&
585 LBC 0 : cexpr->cvarno == context->rt_index)
586 UIC 0 : cexpr->cvarno = context->new_index;
587 LBC 0 : return false;
588 : }
589 GIC 48059 : if (IsA(node, RangeTblRef))
590 ECB : {
591 CBC 1661 : RangeTblRef *rtr = (RangeTblRef *) node;
592 ECB :
593 CBC 1661 : if (context->sublevels_up == 0 &&
594 GIC 1103 : rtr->rtindex == context->rt_index)
595 820 : rtr->rtindex = context->new_index;
596 : /* the subquery itself is visited separately */
597 1661 : return false;
598 : }
599 46398 : if (IsA(node, JoinExpr))
600 : {
601 UIC 0 : JoinExpr *j = (JoinExpr *) node;
602 :
603 0 : if (context->sublevels_up == 0 &&
604 0 : j->rtindex == context->rt_index)
605 0 : j->rtindex = context->new_index;
606 : /* fall through to examine children */
607 : }
608 GIC 46398 : if (IsA(node, PlaceHolderVar))
609 : {
610 UIC 0 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
611 :
612 0 : if (phv->phlevelsup == context->sublevels_up)
613 : {
614 0 : phv->phrels = adjust_relid_set(phv->phrels,
615 : context->rt_index,
616 : context->new_index);
617 UNC 0 : phv->phnullingrels = adjust_relid_set(phv->phnullingrels,
618 : context->rt_index,
619 : context->new_index);
620 ECB : }
621 : /* fall through to examine children */
622 : }
623 CBC 46398 : if (IsA(node, PlanRowMark))
624 ECB : {
625 UIC 0 : PlanRowMark *rowmark = (PlanRowMark *) node;
626 ECB :
627 UIC 0 : if (context->sublevels_up == 0)
628 ECB : {
629 UIC 0 : if (rowmark->rti == context->rt_index)
630 LBC 0 : rowmark->rti = context->new_index;
631 0 : if (rowmark->prti == context->rt_index)
632 0 : rowmark->prti = context->new_index;
633 : }
634 UIC 0 : return false;
635 ECB : }
636 CBC 46398 : if (IsA(node, AppendRelInfo))
637 : {
638 LBC 0 : AppendRelInfo *appinfo = (AppendRelInfo *) node;
639 :
640 0 : if (context->sublevels_up == 0)
641 : {
642 UBC 0 : if (appinfo->parent_relid == context->rt_index)
643 UIC 0 : appinfo->parent_relid = context->new_index;
644 UBC 0 : if (appinfo->child_relid == context->rt_index)
645 0 : appinfo->child_relid = context->new_index;
646 EUB : }
647 : /* fall through to examine children */
648 : }
649 ECB : /* Shouldn't need to handle other planner auxiliary nodes here */
650 GIC 46398 : Assert(!IsA(node, SpecialJoinInfo));
651 CBC 46398 : Assert(!IsA(node, PlaceHolderInfo));
652 GIC 46398 : Assert(!IsA(node, MinMaxAggInfo));
653 ECB :
654 CBC 46398 : if (IsA(node, Query))
655 ECB : {
656 : /* Recurse into subselects */
657 : bool result;
658 :
659 CBC 558 : context->sublevels_up++;
660 GIC 558 : result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
661 EUB : (void *) context, 0);
662 GIC 558 : context->sublevels_up--;
663 GBC 558 : return result;
664 EUB : }
665 GBC 45840 : return expression_tree_walker(node, ChangeVarNodes_walker,
666 : (void *) context);
667 : }
668 ECB :
669 : void
670 GBC 9836 : ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
671 : {
672 EUB : ChangeVarNodes_context context;
673 :
674 GBC 9836 : context.rt_index = rt_index;
675 GIC 9836 : context.new_index = new_index;
676 9836 : context.sublevels_up = sublevels_up;
677 EUB :
678 : /*
679 : * Must be prepared to start with a Query or a bare expression tree; if
680 : * it's a Query, go straight to query_tree_walker to make sure that
681 : * sublevels_up doesn't get incremented prematurely.
682 : */
683 CBC 9836 : if (node && IsA(node, Query))
684 GIC 1804 : {
685 GBC 1804 : Query *qry = (Query *) node;
686 :
687 EUB : /*
688 : * If we are starting at a Query, and sublevels_up is zero, then we
689 : * must also fix rangetable indexes in the Query itself --- namely
690 : * resultRelation and rowMarks entries. sublevels_up cannot be zero
691 : * when recursing into a subquery, so there's no need to have the same
692 : * logic inside ChangeVarNodes_walker.
693 : */
694 GBC 1804 : if (sublevels_up == 0)
695 : {
696 ECB : ListCell *l;
697 :
698 GBC 1804 : if (qry->resultRelation == rt_index)
699 GIC 1138 : qry->resultRelation = new_index;
700 EUB :
701 : /* this is unlikely to ever be used, but ... */
702 GBC 1804 : if (qry->onConflict && qry->onConflict->exclRelIndex == rt_index)
703 UBC 0 : qry->onConflict->exclRelIndex = new_index;
704 EUB :
705 GBC 1810 : foreach(l, qry->rowMarks)
706 : {
707 GIC 6 : RowMarkClause *rc = (RowMarkClause *) lfirst(l);
708 :
709 6 : if (rc->rti == rt_index)
710 LBC 0 : rc->rti = new_index;
711 ECB : }
712 : }
713 GIC 1804 : query_tree_walker(qry, ChangeVarNodes_walker,
714 ECB : (void *) &context, 0);
715 : }
716 : else
717 GIC 8032 : ChangeVarNodes_walker(node, &context);
718 9836 : }
719 ECB :
720 : /*
721 : * Substitute newrelid for oldrelid in a Relid set
722 : */
723 : static Relids
724 GIC 17606 : adjust_relid_set(Relids relids, int oldrelid, int newrelid)
725 ECB : {
726 GIC 17606 : if (bms_is_member(oldrelid, relids))
727 : {
728 : /* Ensure we have a modifiable copy */
729 UIC 0 : relids = bms_copy(relids);
730 ECB : /* Remove old, add new */
731 UIC 0 : relids = bms_del_member(relids, oldrelid);
732 0 : relids = bms_add_member(relids, newrelid);
733 : }
734 CBC 17606 : return relids;
735 ECB : }
736 :
737 : /*
738 : * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
739 : *
740 : * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
741 : * and add delta_sublevels_up to their varlevelsup value. This is needed when
742 : * an expression that's correct for some nesting level is inserted into a
743 : * subquery. Ordinarily the initial call has min_sublevels_up == 0 so that
744 : * all Vars are affected. The point of min_sublevels_up is that we can
745 : * increment it when we recurse into a sublink, so that local variables in
746 : * that sublink are not affected, only outer references to vars that belong
747 : * to the expression's original query level or parents thereof.
748 : *
749 : * Likewise for other nodes containing levelsup fields, such as Aggref.
750 : *
751 : * NOTE: although this has the form of a walker, we cheat and modify the
752 : * Var nodes in-place. The given expression tree should have been copied
753 : * earlier to ensure that no unwanted side-effects occur!
754 : */
755 :
756 : typedef struct
757 : {
758 : int delta_sublevels_up;
759 : int min_sublevels_up;
760 : } IncrementVarSublevelsUp_context;
761 :
762 : static bool
763 GBC 1138928 : IncrementVarSublevelsUp_walker(Node *node,
764 : IncrementVarSublevelsUp_context *context)
765 ECB : {
766 GIC 1138928 : if (node == NULL)
767 CBC 333670 : return false;
768 GIC 805258 : if (IsA(node, Var))
769 ECB : {
770 GBC 390681 : Var *var = (Var *) node;
771 :
772 GIC 390681 : if (var->varlevelsup >= context->min_sublevels_up)
773 CBC 4408 : var->varlevelsup += context->delta_sublevels_up;
774 GIC 390681 : return false; /* done here */
775 : }
776 414577 : if (IsA(node, CurrentOfExpr))
777 ECB : {
778 : /* this should not happen */
779 UIC 0 : if (context->min_sublevels_up == 0)
780 0 : elog(ERROR, "cannot push down CurrentOfExpr");
781 0 : return false;
782 : }
783 GIC 414577 : if (IsA(node, Aggref))
784 ECB : {
785 GIC 1123 : Aggref *agg = (Aggref *) node;
786 ECB :
787 GIC 1123 : if (agg->agglevelsup >= context->min_sublevels_up)
788 35 : agg->agglevelsup += context->delta_sublevels_up;
789 EUB : /* fall through to recurse into argument */
790 : }
791 GBC 414577 : if (IsA(node, GroupingFunc))
792 EUB : {
793 GIC 32 : GroupingFunc *grp = (GroupingFunc *) node;
794 ECB :
795 GIC 32 : if (grp->agglevelsup >= context->min_sublevels_up)
796 32 : grp->agglevelsup += context->delta_sublevels_up;
797 : /* fall through to recurse into argument */
798 : }
799 414577 : if (IsA(node, PlaceHolderVar))
800 : {
801 374 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
802 :
803 374 : if (phv->phlevelsup >= context->min_sublevels_up)
804 208 : phv->phlevelsup += context->delta_sublevels_up;
805 : /* fall through to recurse into argument */
806 : }
807 414577 : if (IsA(node, RangeTblEntry))
808 : {
809 42586 : RangeTblEntry *rte = (RangeTblEntry *) node;
810 :
811 42586 : if (rte->rtekind == RTE_CTE)
812 : {
813 1108 : if (rte->ctelevelsup >= context->min_sublevels_up)
814 1093 : rte->ctelevelsup += context->delta_sublevels_up;
815 : }
816 42586 : return false; /* allow range_table_walker to continue */
817 : }
818 371991 : if (IsA(node, Query))
819 : {
820 : /* Recurse into subselects */
821 : bool result;
822 :
823 CBC 6228 : context->min_sublevels_up++;
824 GIC 6228 : result = query_tree_walker((Query *) node,
825 : IncrementVarSublevelsUp_walker,
826 ECB : (void *) context,
827 : QTW_EXAMINE_RTES_BEFORE);
828 CBC 6228 : context->min_sublevels_up--;
829 GIC 6228 : return result;
830 ECB : }
831 GIC 365763 : return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
832 ECB : (void *) context);
833 : }
834 :
835 : void
836 CBC 38205 : IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
837 : int min_sublevels_up)
838 : {
839 EUB : IncrementVarSublevelsUp_context context;
840 :
841 GBC 38205 : context.delta_sublevels_up = delta_sublevels_up;
842 GIC 38205 : context.min_sublevels_up = min_sublevels_up;
843 ECB :
844 : /*
845 : * Must be prepared to start with a Query or a bare expression tree; if
846 : * it's a Query, we don't want to increment sublevels_up.
847 : */
848 CBC 38205 : query_or_expression_tree_walker(node,
849 : IncrementVarSublevelsUp_walker,
850 : (void *) &context,
851 ECB : QTW_EXAMINE_RTES_BEFORE);
852 GIC 38205 : }
853 ECB :
854 : /*
855 : * IncrementVarSublevelsUp_rtable -
856 : * Same as IncrementVarSublevelsUp, but to be invoked on a range table.
857 : */
858 : void
859 CBC 625 : IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up,
860 : int min_sublevels_up)
861 ECB : {
862 : IncrementVarSublevelsUp_context context;
863 :
864 CBC 625 : context.delta_sublevels_up = delta_sublevels_up;
865 GIC 625 : context.min_sublevels_up = min_sublevels_up;
866 :
867 CBC 625 : range_table_walker(rtable,
868 : IncrementVarSublevelsUp_walker,
869 ECB : (void *) &context,
870 : QTW_EXAMINE_RTES_BEFORE);
871 CBC 625 : }
872 :
873 ECB :
874 : /*
875 : * rangeTableEntry_used - detect whether an RTE is referenced somewhere
876 : * in var nodes or join or setOp trees of a query or expression.
877 : */
878 :
879 : typedef struct
880 : {
881 : int rt_index;
882 : int sublevels_up;
883 : } rangeTableEntry_used_context;
884 :
885 : static bool
886 GIC 1455721 : rangeTableEntry_used_walker(Node *node,
887 : rangeTableEntry_used_context *context)
888 ECB : {
889 CBC 1455721 : if (node == NULL)
890 GIC 242072 : return false;
891 CBC 1213649 : if (IsA(node, Var))
892 : {
893 GIC 344292 : Var *var = (Var *) node;
894 :
895 344292 : if (var->varlevelsup == context->sublevels_up &&
896 GNC 537529 : (var->varno == context->rt_index ||
897 206570 : bms_is_member(context->rt_index, var->varnullingrels)))
898 GIC 124389 : return true;
899 219903 : return false;
900 : }
901 869357 : if (IsA(node, CurrentOfExpr))
902 ECB : {
903 CBC 6 : CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
904 :
905 GIC 6 : if (context->sublevels_up == 0 &&
906 6 : cexpr->cvarno == context->rt_index)
907 UIC 0 : return true;
908 GIC 6 : return false;
909 ECB : }
910 GIC 869351 : if (IsA(node, RangeTblRef))
911 : {
912 47999 : RangeTblRef *rtr = (RangeTblRef *) node;
913 ECB :
914 GIC 47999 : if (rtr->rtindex == context->rt_index &&
915 25649 : context->sublevels_up == 0)
916 25032 : return true;
917 : /* the subquery itself is visited separately */
918 22967 : return false;
919 : }
920 CBC 821352 : if (IsA(node, JoinExpr))
921 : {
922 GIC 15618 : JoinExpr *j = (JoinExpr *) node;
923 :
924 15618 : if (j->rtindex == context->rt_index &&
925 CBC 33 : context->sublevels_up == 0)
926 LBC 0 : return true;
927 : /* fall through to examine children */
928 ECB : }
929 : /* Shouldn't need to handle planner auxiliary nodes here */
930 GIC 821352 : Assert(!IsA(node, PlaceHolderVar));
931 821352 : Assert(!IsA(node, PlanRowMark));
932 CBC 821352 : Assert(!IsA(node, SpecialJoinInfo));
933 GIC 821352 : Assert(!IsA(node, AppendRelInfo));
934 821352 : Assert(!IsA(node, PlaceHolderInfo));
935 821352 : Assert(!IsA(node, MinMaxAggInfo));
936 :
937 821352 : if (IsA(node, Query))
938 : {
939 : /* Recurse into subselects */
940 : bool result;
941 :
942 5195 : context->sublevels_up++;
943 5195 : result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
944 : (void *) context, 0);
945 5195 : context->sublevels_up--;
946 5195 : return result;
947 ECB : }
948 GIC 816157 : return expression_tree_walker(node, rangeTableEntry_used_walker,
949 : (void *) context);
950 ECB : }
951 :
952 : bool
953 GIC 157558 : rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
954 ECB : {
955 : rangeTableEntry_used_context context;
956 :
957 CBC 157558 : context.rt_index = rt_index;
958 157558 : context.sublevels_up = sublevels_up;
959 ECB :
960 : /*
961 : * Must be prepared to start with a Query or a bare expression tree; if
962 : * it's a Query, we don't want to increment sublevels_up.
963 : */
964 CBC 157558 : return query_or_expression_tree_walker(node,
965 : rangeTableEntry_used_walker,
966 ECB : (void *) &context,
967 : 0);
968 EUB : }
969 ECB :
970 :
971 : /*
972 : * If the given Query is an INSERT ... SELECT construct, extract and
973 : * return the sub-Query node that represents the SELECT part. Otherwise
974 : * return the given Query.
975 : *
976 : * If subquery_ptr is not NULL, then *subquery_ptr is set to the location
977 : * of the link to the SELECT subquery inside parsetree, or NULL if not an
978 : * INSERT ... SELECT.
979 : *
980 : * This is a hack needed because transformations on INSERT ... SELECTs that
981 : * appear in rule actions should be applied to the source SELECT, not to the
982 : * INSERT part. Perhaps this can be cleaned up with redesigned querytrees.
983 : */
984 : Query *
985 CBC 2194 : getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
986 ECB : {
987 EUB : Query *selectquery;
988 : RangeTblEntry *selectrte;
989 : RangeTblRef *rtr;
990 :
991 CBC 2194 : if (subquery_ptr)
992 666 : *subquery_ptr = NULL;
993 ECB :
994 CBC 2194 : if (parsetree == NULL)
995 LBC 0 : return parsetree;
996 CBC 2194 : if (parsetree->commandType != CMD_INSERT)
997 GIC 1230 : return parsetree;
998 ECB :
999 : /*
1000 : * Currently, this is ONLY applied to rule-action queries, and so we
1001 : * expect to find the OLD and NEW placeholder entries in the given query.
1002 : * If they're not there, it must be an INSERT/SELECT in which they've been
1003 : * pushed down to the SELECT.
1004 : */
1005 GIC 964 : if (list_length(parsetree->rtable) >= 2 &&
1006 CBC 964 : strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
1007 882 : "old") == 0 &&
1008 GIC 882 : strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
1009 ECB : "new") == 0)
1010 GIC 882 : return parsetree;
1011 82 : Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
1012 82 : if (list_length(parsetree->jointree->fromlist) != 1)
1013 UIC 0 : elog(ERROR, "expected to find SELECT subquery");
1014 CBC 82 : rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
1015 GIC 82 : if (!IsA(rtr, RangeTblRef))
1016 UIC 0 : elog(ERROR, "expected to find SELECT subquery");
1017 GIC 82 : selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
1018 CBC 82 : if (!(selectrte->rtekind == RTE_SUBQUERY &&
1019 82 : selectrte->subquery &&
1020 GIC 82 : IsA(selectrte->subquery, Query) &&
1021 82 : selectrte->subquery->commandType == CMD_SELECT))
1022 UIC 0 : elog(ERROR, "expected to find SELECT subquery");
1023 GIC 82 : selectquery = selectrte->subquery;
1024 82 : if (list_length(selectquery->rtable) >= 2 &&
1025 CBC 82 : strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
1026 GIC 82 : "old") == 0 &&
1027 82 : strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
1028 : "new") == 0)
1029 : {
1030 82 : if (subquery_ptr)
1031 30 : *subquery_ptr = &(selectrte->subquery);
1032 82 : return selectquery;
1033 : }
1034 UIC 0 : elog(ERROR, "could not find rule placeholders");
1035 : return NULL; /* not reached */
1036 : }
1037 :
1038 :
1039 : /*
1040 : * Add the given qualifier condition to the query's WHERE clause
1041 : */
1042 : void
1043 GIC 1699 : AddQual(Query *parsetree, Node *qual)
1044 : {
1045 : Node *copy;
1046 ECB :
1047 GIC 1699 : if (qual == NULL)
1048 831 : return;
1049 :
1050 868 : if (parsetree->commandType == CMD_UTILITY)
1051 : {
1052 ECB : /*
1053 : * There's noplace to put the qual on a utility statement.
1054 : *
1055 : * If it's a NOTIFY, silently ignore the qual; this means that the
1056 EUB : * NOTIFY will execute, whether or not there are any qualifying rows.
1057 ECB : * While clearly wrong, this is much more useful than refusing to
1058 : * execute the rule at all, and extra NOTIFY events are harmless for
1059 : * typical uses of NOTIFY.
1060 : *
1061 : * If it isn't a NOTIFY, error out, since unconditional execution of
1062 : * other utility stmts is unlikely to be wanted. (This case is not
1063 : * currently allowed anyway, but keep the test for safety.)
1064 : */
1065 UIC 0 : if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
1066 LBC 0 : return;
1067 ECB : else
1068 LBC 0 : ereport(ERROR,
1069 ECB : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1070 : errmsg("conditional utility statements are not implemented")));
1071 : }
1072 :
1073 CBC 868 : if (parsetree->setOperations != NULL)
1074 EUB : {
1075 ECB : /*
1076 : * There's noplace to put the qual on a setop statement, either. (This
1077 EUB : * could be fixed, but right now the planner simply ignores any qual
1078 ECB : * condition on a setop query.)
1079 : */
1080 LBC 0 : ereport(ERROR,
1081 ECB : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1082 : errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
1083 EUB : }
1084 ECB :
1085 : /* INTERSECT wants the original, but we need to copy - Jan */
1086 CBC 868 : copy = copyObject(qual);
1087 ECB :
1088 CBC 868 : parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
1089 : copy);
1090 :
1091 ECB : /*
1092 : * We had better not have stuck an aggregate into the WHERE clause.
1093 : */
1094 GIC 868 : Assert(!contain_aggs_of_level(copy, 0));
1095 EUB :
1096 : /*
1097 : * Make sure query is marked correctly if added qual has sublinks. Need
1098 : * not search qual when query is already marked.
1099 : */
1100 GIC 868 : if (!parsetree->hasSubLinks)
1101 865 : parsetree->hasSubLinks = checkExprHasSubLink(copy);
1102 : }
1103 :
1104 ECB :
1105 : /*
1106 : * Invert the given clause and add it to the WHERE qualifications of the
1107 : * given querytree. Inversion means "x IS NOT TRUE", not just "NOT x",
1108 : * else we will do the wrong thing when x evaluates to NULL.
1109 : */
1110 : void
1111 CBC 222 : AddInvertedQual(Query *parsetree, Node *qual)
1112 : {
1113 : BooleanTest *invqual;
1114 :
1115 GIC 222 : if (qual == NULL)
1116 UIC 0 : return;
1117 :
1118 : /* Need not copy input qual, because AddQual will... */
1119 GIC 222 : invqual = makeNode(BooleanTest);
1120 222 : invqual->arg = (Expr *) qual;
1121 222 : invqual->booltesttype = IS_NOT_TRUE;
1122 222 : invqual->location = -1;
1123 :
1124 222 : AddQual(parsetree, (Node *) invqual);
1125 : }
1126 EUB :
1127 :
1128 : /*
1129 : * add_nulling_relids() finds Vars and PlaceHolderVars that belong to any
1130 : * of the target_relids, and adds added_relids to their varnullingrels
1131 : * and phnullingrels fields.
1132 : */
1133 : Node *
1134 GNC 1642 : add_nulling_relids(Node *node,
1135 : const Bitmapset *target_relids,
1136 : const Bitmapset *added_relids)
1137 : {
1138 : add_nulling_relids_context context;
1139 :
1140 1642 : context.target_relids = target_relids;
1141 1642 : context.added_relids = added_relids;
1142 1642 : context.sublevels_up = 0;
1143 1642 : return query_or_expression_tree_mutator(node,
1144 : add_nulling_relids_mutator,
1145 : &context,
1146 : 0);
1147 : }
1148 :
1149 : static Node *
1150 8234 : add_nulling_relids_mutator(Node *node,
1151 : add_nulling_relids_context *context)
1152 : {
1153 8234 : if (node == NULL)
1154 UNC 0 : return NULL;
1155 GNC 8234 : if (IsA(node, Var))
1156 : {
1157 3287 : Var *var = (Var *) node;
1158 :
1159 6574 : if (var->varlevelsup == context->sublevels_up &&
1160 3287 : bms_is_member(var->varno, context->target_relids))
1161 : {
1162 1648 : Relids newnullingrels = bms_union(var->varnullingrels,
1163 : context->added_relids);
1164 :
1165 : /* Copy the Var ... */
1166 1648 : var = copyObject(var);
1167 : /* ... and replace the copy's varnullingrels field */
1168 1648 : var->varnullingrels = newnullingrels;
1169 1648 : return (Node *) var;
1170 : }
1171 : /* Otherwise fall through to copy the Var normally */
1172 : }
1173 4947 : else if (IsA(node, PlaceHolderVar))
1174 : {
1175 3 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
1176 :
1177 6 : if (phv->phlevelsup == context->sublevels_up &&
1178 3 : bms_overlap(phv->phrels, context->target_relids))
1179 : {
1180 3 : Relids newnullingrels = bms_union(phv->phnullingrels,
1181 : context->added_relids);
1182 :
1183 : /*
1184 : * We don't modify the contents of the PHV's expression, only add
1185 : * to phnullingrels. This corresponds to assuming that the PHV
1186 : * will be evaluated at the same level as before, then perhaps be
1187 : * nulled as it bubbles up. Hence, just flat-copy the node ...
1188 : */
1189 3 : phv = makeNode(PlaceHolderVar);
1190 3 : memcpy(phv, node, sizeof(PlaceHolderVar));
1191 : /* ... and replace the copy's phnullingrels field */
1192 3 : phv->phnullingrels = newnullingrels;
1193 3 : return (Node *) phv;
1194 : }
1195 : /* Otherwise fall through to copy the PlaceHolderVar normally */
1196 : }
1197 4944 : else if (IsA(node, Query))
1198 : {
1199 : /* Recurse into RTE or sublink subquery */
1200 : Query *newnode;
1201 :
1202 UNC 0 : context->sublevels_up++;
1203 0 : newnode = query_tree_mutator((Query *) node,
1204 : add_nulling_relids_mutator,
1205 : (void *) context,
1206 : 0);
1207 0 : context->sublevels_up--;
1208 0 : return (Node *) newnode;
1209 : }
1210 GNC 6583 : return expression_tree_mutator(node, add_nulling_relids_mutator,
1211 : (void *) context);
1212 : }
1213 :
1214 : /*
1215 : * remove_nulling_relids() removes mentions of the specified RT index(es)
1216 : * in Var.varnullingrels and PlaceHolderVar.phnullingrels fields within
1217 : * the given expression, except in nodes belonging to rels listed in
1218 : * except_relids.
1219 : */
1220 : Node *
1221 3074 : remove_nulling_relids(Node *node,
1222 : const Bitmapset *removable_relids,
1223 : const Bitmapset *except_relids)
1224 : {
1225 : remove_nulling_relids_context context;
1226 :
1227 3074 : context.removable_relids = removable_relids;
1228 3074 : context.except_relids = except_relids;
1229 3074 : context.sublevels_up = 0;
1230 3074 : return query_or_expression_tree_mutator(node,
1231 : remove_nulling_relids_mutator,
1232 : &context,
1233 : 0);
1234 : }
1235 :
1236 : static Node *
1237 60868 : remove_nulling_relids_mutator(Node *node,
1238 : remove_nulling_relids_context *context)
1239 : {
1240 60868 : if (node == NULL)
1241 15667 : return NULL;
1242 45201 : if (IsA(node, Var))
1243 : {
1244 11968 : Var *var = (Var *) node;
1245 :
1246 11968 : if (var->varlevelsup == context->sublevels_up &&
1247 20925 : !bms_is_member(var->varno, context->except_relids) &&
1248 10439 : bms_overlap(var->varnullingrels, context->removable_relids))
1249 : {
1250 : /* Copy the Var ... */
1251 3303 : var = copyObject(var);
1252 : /* ... and replace the copy's varnullingrels field */
1253 3303 : var->varnullingrels = bms_difference(var->varnullingrels,
1254 : context->removable_relids);
1255 3303 : return (Node *) var;
1256 : }
1257 : /* Otherwise fall through to copy the Var normally */
1258 : }
1259 33233 : else if (IsA(node, PlaceHolderVar))
1260 : {
1261 142 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
1262 :
1263 142 : if (phv->phlevelsup == context->sublevels_up &&
1264 142 : !bms_overlap(phv->phrels, context->except_relids))
1265 : {
1266 : /*
1267 : * Note: it might seem desirable to remove the PHV altogether if
1268 : * phnullingrels goes to empty. Currently we dare not do that
1269 : * because we use PHVs in some cases to enforce separate identity
1270 : * of subexpressions; see wrap_non_vars usages in prepjointree.c.
1271 : */
1272 : /* Copy the PlaceHolderVar and mutate what's below ... */
1273 : phv = (PlaceHolderVar *)
1274 142 : expression_tree_mutator(node,
1275 : remove_nulling_relids_mutator,
1276 : (void *) context);
1277 : /* ... and replace the copy's phnullingrels field */
1278 142 : phv->phnullingrels = bms_difference(phv->phnullingrels,
1279 : context->removable_relids);
1280 : /* We must also update phrels, if it contains a removable RTI */
1281 142 : phv->phrels = bms_difference(phv->phrels,
1282 : context->removable_relids);
1283 142 : Assert(!bms_is_empty(phv->phrels));
1284 142 : return (Node *) phv;
1285 : }
1286 : /* Otherwise fall through to copy the PlaceHolderVar normally */
1287 : }
1288 33091 : else if (IsA(node, Query))
1289 : {
1290 : /* Recurse into RTE or sublink subquery */
1291 : Query *newnode;
1292 :
1293 66 : context->sublevels_up++;
1294 66 : newnode = query_tree_mutator((Query *) node,
1295 : remove_nulling_relids_mutator,
1296 : (void *) context,
1297 : 0);
1298 66 : context->sublevels_up--;
1299 66 : return (Node *) newnode;
1300 : }
1301 41690 : return expression_tree_mutator(node, remove_nulling_relids_mutator,
1302 : (void *) context);
1303 : }
1304 :
1305 :
1306 : /*
1307 EUB : * replace_rte_variables() finds all Vars in an expression tree
1308 : * that reference a particular RTE, and replaces them with substitute
1309 : * expressions obtained from a caller-supplied callback function.
1310 : *
1311 : * When invoking replace_rte_variables on a portion of a Query, pass the
1312 ECB : * address of the containing Query's hasSubLinks field as outer_hasSubLinks.
1313 : * Otherwise, pass NULL, but inserting a SubLink into a non-Query expression
1314 : * will then cause an error.
1315 : *
1316 : * Note: the business with inserted_sublink is needed to update hasSubLinks
1317 : * in subqueries when the replacement adds a subquery inside a subquery.
1318 : * Messy, isn't it? We do not need to do similar pushups for hasAggs,
1319 EUB : * because it isn't possible for this transformation to insert a level-zero
1320 : * aggregate reference into a subquery --- it could only insert outer aggs.
1321 : * Likewise for hasWindowFuncs.
1322 : *
1323 : * Note: usually, we'd not expose the mutator function or context struct
1324 : * for a function like this. We do so because callbacks often find it
1325 ECB : * convenient to recurse directly to the mutator on sub-expressions of
1326 : * what they will return.
1327 : */
1328 : Node *
1329 GIC 71383 : replace_rte_variables(Node *node, int target_varno, int sublevels_up,
1330 : replace_rte_variables_callback callback,
1331 : void *callback_arg,
1332 : bool *outer_hasSubLinks)
1333 ECB : {
1334 : Node *result;
1335 : replace_rte_variables_context context;
1336 :
1337 GIC 71383 : context.callback = callback;
1338 71383 : context.callback_arg = callback_arg;
1339 CBC 71383 : context.target_varno = target_varno;
1340 71383 : context.sublevels_up = sublevels_up;
1341 :
1342 : /*
1343 : * We try to initialize inserted_sublink to true if there is no need to
1344 : * detect new sublinks because the query already has some.
1345 : */
1346 GIC 71383 : if (node && IsA(node, Query))
1347 1879 : context.inserted_sublink = ((Query *) node)->hasSubLinks;
1348 69504 : else if (outer_hasSubLinks)
1349 69504 : context.inserted_sublink = *outer_hasSubLinks;
1350 ECB : else
1351 UIC 0 : context.inserted_sublink = false;
1352 :
1353 : /*
1354 ECB : * Must be prepared to start with a Query or a bare expression tree; if
1355 EUB : * it's a Query, we don't want to increment sublevels_up.
1356 : */
1357 GIC 71383 : result = query_or_expression_tree_mutator(node,
1358 ECB : replace_rte_variables_mutator,
1359 : (void *) &context,
1360 : 0);
1361 :
1362 GIC 71380 : if (context.inserted_sublink)
1363 ECB : {
1364 GIC 17597 : if (result && IsA(result, Query))
1365 45 : ((Query *) result)->hasSubLinks = true;
1366 17552 : else if (outer_hasSubLinks)
1367 17552 : *outer_hasSubLinks = true;
1368 : else
1369 UIC 0 : elog(ERROR, "replace_rte_variables inserted a SubLink, but has noplace to record it");
1370 : }
1371 :
1372 GIC 71380 : return result;
1373 ECB : }
1374 :
1375 : Node *
1376 GIC 347591 : replace_rte_variables_mutator(Node *node,
1377 : replace_rte_variables_context *context)
1378 : {
1379 CBC 347591 : if (node == NULL)
1380 88159 : return NULL;
1381 259432 : if (IsA(node, Var))
1382 ECB : {
1383 GIC 93991 : Var *var = (Var *) node;
1384 :
1385 93991 : if (var->varno == context->target_varno &&
1386 60342 : var->varlevelsup == context->sublevels_up)
1387 : {
1388 : /* Found a matching variable, make the substitution */
1389 ECB : Node *newnode;
1390 :
1391 GIC 57171 : newnode = context->callback(var, context);
1392 ECB : /* Detect if we are adding a sublink to query */
1393 GBC 57171 : if (!context->inserted_sublink)
1394 CBC 47753 : context->inserted_sublink = checkExprHasSubLink(newnode);
1395 GIC 57171 : return newnode;
1396 ECB : }
1397 : /* otherwise fall through to copy the var normally */
1398 : }
1399 CBC 165441 : else if (IsA(node, CurrentOfExpr))
1400 : {
1401 3 : CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
1402 :
1403 GIC 3 : if (cexpr->cvarno == context->target_varno &&
1404 3 : context->sublevels_up == 0)
1405 ECB : {
1406 : /*
1407 : * We get here if a WHERE CURRENT OF expression turns out to apply
1408 : * to a view. Someday we might be able to translate the
1409 : * expression to apply to an underlying table of the view, but
1410 : * right now it's not implemented.
1411 : */
1412 CBC 3 : ereport(ERROR,
1413 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1414 ECB : errmsg("WHERE CURRENT OF on a view is not implemented")));
1415 : }
1416 : /* otherwise fall through to copy the expr normally */
1417 : }
1418 GIC 165438 : else if (IsA(node, Query))
1419 ECB : {
1420 : /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1421 : Query *newnode;
1422 : bool save_inserted_sublink;
1423 :
1424 GIC 753 : context->sublevels_up++;
1425 753 : save_inserted_sublink = context->inserted_sublink;
1426 753 : context->inserted_sublink = ((Query *) node)->hasSubLinks;
1427 753 : newnode = query_tree_mutator((Query *) node,
1428 ECB : replace_rte_variables_mutator,
1429 : (void *) context,
1430 : 0);
1431 CBC 753 : newnode->hasSubLinks |= context->inserted_sublink;
1432 753 : context->inserted_sublink = save_inserted_sublink;
1433 GIC 753 : context->sublevels_up--;
1434 753 : return (Node *) newnode;
1435 : }
1436 CBC 201505 : return expression_tree_mutator(node, replace_rte_variables_mutator,
1437 : (void *) context);
1438 : }
1439 :
1440 :
1441 EUB : /*
1442 : * map_variable_attnos() finds all user-column Vars in an expression tree
1443 : * that reference a particular RTE, and adjusts their varattnos according
1444 : * to the given mapping array (varattno n is replaced by attno_map[n-1]).
1445 : * Vars for system columns are not modified.
1446 : *
1447 : * A zero in the mapping array represents a dropped column, which should not
1448 : * appear in the expression.
1449 ECB : *
1450 : * If the expression tree contains a whole-row Var for the target RTE,
1451 : * *found_whole_row is set to true. In addition, if to_rowtype is
1452 : * not InvalidOid, we replace the Var with a Var of that vartype, inserting
1453 : * a ConvertRowtypeExpr to map back to the rowtype expected by the expression.
1454 : * (Therefore, to_rowtype had better be a child rowtype of the rowtype of the
1455 : * RTE we're changing references to.) Callers that don't provide to_rowtype
1456 : * should report an error if *found_whole_row is true; we don't do that here
1457 : * because we don't know exactly what wording for the error message would
1458 : * be most appropriate. The caller will be aware of the context.
1459 : *
1460 : * This could be built using replace_rte_variables and a callback function,
1461 : * but since we don't ever need to insert sublinks, replace_rte_variables is
1462 : * overly complicated.
1463 : */
1464 :
1465 : typedef struct
1466 : {
1467 : int target_varno; /* RTE index to search for */
1468 : int sublevels_up; /* (current) nesting depth */
1469 : const AttrMap *attno_map; /* map array for user attnos */
1470 : Oid to_rowtype; /* change whole-row Vars to this type */
1471 : bool *found_whole_row; /* output flag */
1472 : } map_variable_attnos_context;
1473 :
1474 : static Node *
1475 GIC 48440 : map_variable_attnos_mutator(Node *node,
1476 ECB : map_variable_attnos_context *context)
1477 : {
1478 GIC 48440 : if (node == NULL)
1479 CBC 452 : return NULL;
1480 47988 : if (IsA(node, Var))
1481 ECB : {
1482 GIC 11224 : Var *var = (Var *) node;
1483 ECB :
1484 GIC 11224 : if (var->varno == context->target_varno &&
1485 CBC 11116 : var->varlevelsup == context->sublevels_up)
1486 ECB : {
1487 : /* Found a matching variable, make the substitution */
1488 GIC 11116 : Var *newvar = (Var *) palloc(sizeof(Var));
1489 11116 : int attno = var->varattno;
1490 ECB :
1491 GIC 11116 : *newvar = *var; /* initially copy all fields of the Var */
1492 ECB :
1493 GIC 11116 : if (attno > 0)
1494 ECB : {
1495 : /* user-defined column, replace attno */
1496 GIC 11053 : if (attno > context->attno_map->maplen ||
1497 11053 : context->attno_map->attnums[attno - 1] == 0)
1498 LBC 0 : elog(ERROR, "unexpected varattno %d in expression to be mapped",
1499 : attno);
1500 CBC 11053 : newvar->varattno = context->attno_map->attnums[attno - 1];
1501 : /* If the syntactic referent is same RTE, fix it too */
1502 11053 : if (newvar->varnosyn == context->target_varno)
1503 11014 : newvar->varattnosyn = newvar->varattno;
1504 : }
1505 GIC 63 : else if (attno == 0)
1506 : {
1507 : /* whole-row variable, warn caller */
1508 27 : *(context->found_whole_row) = true;
1509 :
1510 : /* If the caller expects us to convert the Var, do so. */
1511 27 : if (OidIsValid(context->to_rowtype) &&
1512 24 : context->to_rowtype != var->vartype)
1513 ECB : {
1514 : ConvertRowtypeExpr *r;
1515 :
1516 : /* This certainly won't work for a RECORD variable. */
1517 CBC 24 : Assert(var->vartype != RECORDOID);
1518 :
1519 : /* Var itself is changed to the requested type. */
1520 24 : newvar->vartype = context->to_rowtype;
1521 :
1522 ECB : /*
1523 : * Add a conversion node on top to convert back to the
1524 : * original type expected by the expression.
1525 : */
1526 GIC 24 : r = makeNode(ConvertRowtypeExpr);
1527 CBC 24 : r->arg = (Expr *) newvar;
1528 GIC 24 : r->resulttype = var->vartype;
1529 24 : r->convertformat = COERCE_IMPLICIT_CAST;
1530 24 : r->location = -1;
1531 :
1532 CBC 24 : return (Node *) r;
1533 ECB : }
1534 : }
1535 GIC 11092 : return (Node *) newvar;
1536 : }
1537 ECB : /* otherwise fall through to copy the var normally */
1538 : }
1539 GIC 36764 : else if (IsA(node, ConvertRowtypeExpr))
1540 ECB : {
1541 GIC 18 : ConvertRowtypeExpr *r = (ConvertRowtypeExpr *) node;
1542 18 : Var *var = (Var *) r->arg;
1543 :
1544 : /*
1545 : * If this is coercing a whole-row Var that we need to convert, then
1546 : * just convert the Var without adding an extra ConvertRowtypeExpr.
1547 : * Effectively we're simplifying var::parenttype::grandparenttype into
1548 : * just var::grandparenttype. This avoids building stacks of CREs if
1549 : * this function is applied repeatedly.
1550 : */
1551 18 : if (IsA(var, Var) &&
1552 12 : var->varno == context->target_varno &&
1553 9 : var->varlevelsup == context->sublevels_up &&
1554 9 : var->varattno == 0 &&
1555 9 : OidIsValid(context->to_rowtype) &&
1556 9 : context->to_rowtype != var->vartype)
1557 : {
1558 : ConvertRowtypeExpr *newnode;
1559 9 : Var *newvar = (Var *) palloc(sizeof(Var));
1560 :
1561 : /* whole-row variable, warn caller */
1562 9 : *(context->found_whole_row) = true;
1563 :
1564 9 : *newvar = *var; /* initially copy all fields of the Var */
1565 :
1566 : /* This certainly won't work for a RECORD variable. */
1567 9 : Assert(var->vartype != RECORDOID);
1568 ECB :
1569 : /* Var itself is changed to the requested type. */
1570 GIC 9 : newvar->vartype = context->to_rowtype;
1571 :
1572 9 : newnode = (ConvertRowtypeExpr *) palloc(sizeof(ConvertRowtypeExpr));
1573 9 : *newnode = *r; /* initially copy all fields of the CRE */
1574 9 : newnode->arg = (Expr *) newvar;
1575 :
1576 CBC 9 : return (Node *) newnode;
1577 ECB : }
1578 : /* otherwise fall through to process the expression normally */
1579 : }
1580 GIC 36746 : else if (IsA(node, Query))
1581 : {
1582 : /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1583 : Query *newnode;
1584 :
1585 LBC 0 : context->sublevels_up++;
1586 0 : newnode = query_tree_mutator((Query *) node,
1587 ECB : map_variable_attnos_mutator,
1588 : (void *) context,
1589 : 0);
1590 UBC 0 : context->sublevels_up--;
1591 UIC 0 : return (Node *) newnode;
1592 : }
1593 GIC 36863 : return expression_tree_mutator(node, map_variable_attnos_mutator,
1594 : (void *) context);
1595 : }
1596 ECB :
1597 : Node *
1598 GIC 4172 : map_variable_attnos(Node *node,
1599 : int target_varno, int sublevels_up,
1600 : const AttrMap *attno_map,
1601 ECB : Oid to_rowtype, bool *found_whole_row)
1602 : {
1603 : map_variable_attnos_context context;
1604 :
1605 CBC 4172 : context.target_varno = target_varno;
1606 4172 : context.sublevels_up = sublevels_up;
1607 GIC 4172 : context.attno_map = attno_map;
1608 GBC 4172 : context.to_rowtype = to_rowtype;
1609 GIC 4172 : context.found_whole_row = found_whole_row;
1610 :
1611 CBC 4172 : *found_whole_row = false;
1612 :
1613 : /*
1614 : * Must be prepared to start with a Query or a bare expression tree; if
1615 ECB : * it's a Query, we don't want to increment sublevels_up.
1616 : */
1617 GIC 4172 : return query_or_expression_tree_mutator(node,
1618 ECB : map_variable_attnos_mutator,
1619 : (void *) &context,
1620 : 0);
1621 : }
1622 :
1623 :
1624 : /*
1625 : * ReplaceVarsFromTargetList - replace Vars with items from a targetlist
1626 : *
1627 : * Vars matching target_varno and sublevels_up are replaced by the
1628 : * entry with matching resno from targetlist, if there is one.
1629 : *
1630 : * If there is no matching resno for such a Var, the action depends on the
1631 : * nomatch_option:
1632 : * REPLACEVARS_REPORT_ERROR: throw an error
1633 : * REPLACEVARS_CHANGE_VARNO: change Var's varno to nomatch_varno
1634 : * REPLACEVARS_SUBSTITUTE_NULL: replace Var with a NULL Const of same type
1635 : *
1636 : * The caller must also provide target_rte, the RTE describing the target
1637 : * relation. This is needed to handle whole-row Vars referencing the target.
1638 : * We expand such Vars into RowExpr constructs.
1639 : *
1640 : * outer_hasSubLinks works the same as for replace_rte_variables().
1641 : */
1642 :
1643 : typedef struct
1644 : {
1645 : RangeTblEntry *target_rte;
1646 : List *targetlist;
1647 : ReplaceVarsNoMatchOption nomatch_option;
1648 : int nomatch_varno;
1649 : } ReplaceVarsFromTargetList_context;
1650 :
1651 : static Node *
1652 GIC 3573 : ReplaceVarsFromTargetList_callback(Var *var,
1653 : replace_rte_variables_context *context)
1654 : {
1655 3573 : ReplaceVarsFromTargetList_context *rcon = (ReplaceVarsFromTargetList_context *) context->callback_arg;
1656 : TargetEntry *tle;
1657 ECB :
1658 GIC 3573 : if (var->varattno == InvalidAttrNumber)
1659 : {
1660 : /* Must expand whole-tuple reference into RowExpr */
1661 : RowExpr *rowexpr;
1662 : List *colnames;
1663 ECB : List *fields;
1664 :
1665 : /*
1666 : * If generating an expansion for a var of a named rowtype (ie, this
1667 : * is a plain relation RTE), then we must include dummy items for
1668 : * dropped columns. If the var is RECORD (ie, this is a JOIN), then
1669 : * omit dropped columns. In the latter case, attach column names to
1670 : * the RowExpr for use of the executor and ruleutils.c.
1671 : */
1672 CBC 27 : expandRTE(rcon->target_rte,
1673 27 : var->varno, var->varlevelsup, var->location,
1674 GIC 27 : (var->vartype != RECORDOID),
1675 ECB : &colnames, &fields);
1676 : /* Adjust the generated per-field Vars... */
1677 GIC 27 : fields = (List *) replace_rte_variables_mutator((Node *) fields,
1678 : context);
1679 27 : rowexpr = makeNode(RowExpr);
1680 27 : rowexpr->args = fields;
1681 27 : rowexpr->row_typeid = var->vartype;
1682 27 : rowexpr->row_format = COERCE_IMPLICIT_CAST;
1683 27 : rowexpr->colnames = (var->vartype == RECORDOID) ? colnames : NIL;
1684 27 : rowexpr->location = var->location;
1685 :
1686 27 : return (Node *) rowexpr;
1687 : }
1688 :
1689 : /* Normal case referencing one targetlist element */
1690 3546 : tle = get_tle_by_resno(rcon->targetlist, var->varattno);
1691 :
1692 3546 : if (tle == NULL || tle->resjunk)
1693 : {
1694 : /* Failed to find column in targetlist */
1695 195 : switch (rcon->nomatch_option)
1696 : {
1697 UIC 0 : case REPLACEVARS_REPORT_ERROR:
1698 : /* fall through, throw error below */
1699 0 : break;
1700 :
1701 GIC 120 : case REPLACEVARS_CHANGE_VARNO:
1702 120 : var = (Var *) copyObject(var);
1703 120 : var->varno = rcon->nomatch_varno;
1704 : /* we leave the syntactic referent alone */
1705 120 : return (Node *) var;
1706 :
1707 75 : case REPLACEVARS_SUBSTITUTE_NULL:
1708 :
1709 : /*
1710 : * If Var is of domain type, we should add a CoerceToDomain
1711 : * node, in case there is a NOT NULL domain constraint.
1712 : */
1713 75 : return coerce_to_domain((Node *) makeNullConst(var->vartype,
1714 ECB : var->vartypmod,
1715 : var->varcollid),
1716 : InvalidOid, -1,
1717 : var->vartype,
1718 : COERCION_IMPLICIT,
1719 : COERCE_IMPLICIT_CAST,
1720 : -1,
1721 : false);
1722 : }
1723 LBC 0 : elog(ERROR, "could not find replacement targetlist entry for attno %d",
1724 ECB : var->varattno);
1725 : return NULL; /* keep compiler quiet */
1726 : }
1727 : else
1728 : {
1729 : /* Make a copy of the tlist item to return */
1730 CBC 3351 : Expr *newnode = copyObject(tle->expr);
1731 :
1732 ECB : /* Must adjust varlevelsup if tlist item is from higher query */
1733 GIC 3351 : if (var->varlevelsup > 0)
1734 81 : IncrementVarSublevelsUp((Node *) newnode, var->varlevelsup, 0);
1735 ECB :
1736 : /*
1737 EUB : * Check to see if the tlist item contains a PARAM_MULTIEXPR Param,
1738 : * and throw error if so. This case could only happen when expanding
1739 ECB : * an ON UPDATE rule's NEW variable and the referenced tlist item in
1740 : * the original UPDATE command is part of a multiple assignment. There
1741 : * seems no practical way to handle such cases without multiple
1742 : * evaluation of the multiple assignment's sub-select, which would
1743 : * create semantic oddities that users of rules would probably prefer
1744 : * not to cope with. So treat it as an unimplemented feature.
1745 : */
1746 GIC 3351 : if (contains_multiexpr_param((Node *) newnode, NULL))
1747 LBC 0 : ereport(ERROR,
1748 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1749 : errmsg("NEW variables in ON UPDATE rules cannot reference columns that are part of a multiple assignment in the subject UPDATE command")));
1750 ECB :
1751 CBC 3351 : return (Node *) newnode;
1752 : }
1753 : }
1754 :
1755 : Node *
1756 2495 : ReplaceVarsFromTargetList(Node *node,
1757 : int target_varno, int sublevels_up,
1758 : RangeTblEntry *target_rte,
1759 ECB : List *targetlist,
1760 : ReplaceVarsNoMatchOption nomatch_option,
1761 : int nomatch_varno,
1762 : bool *outer_hasSubLinks)
1763 : {
1764 : ReplaceVarsFromTargetList_context context;
1765 :
1766 CBC 2495 : context.target_rte = target_rte;
1767 2495 : context.targetlist = targetlist;
1768 2495 : context.nomatch_option = nomatch_option;
1769 2495 : context.nomatch_varno = nomatch_varno;
1770 :
1771 2495 : return replace_rte_variables(node, target_varno, sublevels_up,
1772 : ReplaceVarsFromTargetList_callback,
1773 : (void *) &context,
1774 ECB : outer_hasSubLinks);
1775 : }
|