1/*-------------------------------------------------------------------------
2 *
3 * var.c
4 * Var node manipulation routines
5 *
6 * Note: for most purposes, PlaceHolderVar is considered a Var too,
7 * even if its contained expression is variable-free. Also, CurrentOfExpr
8 * is treated as a Var for purposes of determining whether an expression
9 * contains variables.
10 *
11 *
12 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
13 * Portions Copyright (c) 1994, Regents of the University of California
14 *
15 *
16 * IDENTIFICATION
17 * src/backend/optimizer/util/var.c
18 *
19 *-------------------------------------------------------------------------
20 */
21#include "postgres.h"
22
23#include "access/sysattr.h"
24#include "nodes/nodeFuncs.h"
25#include "optimizer/optimizer.h"
26#include "optimizer/prep.h"
27#include "parser/parsetree.h"
28#include "rewrite/rewriteManip.h"
29
30
31typedef struct
32{
33 Relids varnos;
34 int sublevels_up;
35} pull_varnos_context;
36
37typedef struct
38{
39 Bitmapset *varattnos;
40 Index varno;
41} pull_varattnos_context;
42
43typedef struct
44{
45 List *vars;
46 int sublevels_up;
47} pull_vars_context;
48
49typedef struct
50{
51 int var_location;
52 int sublevels_up;
53} locate_var_of_level_context;
54
55typedef struct
56{
57 List *varlist;
58 int flags;
59} pull_var_clause_context;
60
61typedef struct
62{
63 Query *query; /* outer Query */
64 int sublevels_up;
65 bool possible_sublink; /* could aliases include a SubLink? */
66 bool inserted_sublink; /* have we inserted a SubLink? */
67} flatten_join_alias_vars_context;
68
69static bool pull_varnos_walker(Node *node,
70 pull_varnos_context *context);
71static bool pull_varattnos_walker(Node *node, pull_varattnos_context *context);
72static bool pull_vars_walker(Node *node, pull_vars_context *context);
73static bool contain_var_clause_walker(Node *node, void *context);
74static bool contain_vars_of_level_walker(Node *node, int *sublevels_up);
75static bool locate_var_of_level_walker(Node *node,
76 locate_var_of_level_context *context);
77static bool pull_var_clause_walker(Node *node,
78 pull_var_clause_context *context);
79static Node *flatten_join_alias_vars_mutator(Node *node,
80 flatten_join_alias_vars_context *context);
81static Relids alias_relid_set(Query *query, Relids relids);
82
83
84/*
85 * pull_varnos
86 * Create a set of all the distinct varnos present in a parsetree.
87 * Only varnos that reference level-zero rtable entries are considered.
88 *
89 * NOTE: this is used on not-yet-planned expressions. It may therefore find
90 * bare SubLinks, and if so it needs to recurse into them to look for uplevel
91 * references to the desired rtable level! But when we find a completed
92 * SubPlan, we only need to look at the parameters passed to the subplan.
93 */
94Relids
95pull_varnos(Node *node)
96{
97 pull_varnos_context context;
98
99 context.varnos = NULL;
100 context.sublevels_up = 0;
101
102 /*
103 * Must be prepared to start with a Query or a bare expression tree; if
104 * it's a Query, we don't want to increment sublevels_up.
105 */
106 query_or_expression_tree_walker(node,
107 pull_varnos_walker,
108 (void *) &context,
109 0);
110
111 return context.varnos;
112}
113
114/*
115 * pull_varnos_of_level
116 * Create a set of all the distinct varnos present in a parsetree.
117 * Only Vars of the specified level are considered.
118 */
119Relids
120pull_varnos_of_level(Node *node, int levelsup)
121{
122 pull_varnos_context context;
123
124 context.varnos = NULL;
125 context.sublevels_up = levelsup;
126
127 /*
128 * Must be prepared to start with a Query or a bare expression tree; if
129 * it's a Query, we don't want to increment sublevels_up.
130 */
131 query_or_expression_tree_walker(node,
132 pull_varnos_walker,
133 (void *) &context,
134 0);
135
136 return context.varnos;
137}
138
139static bool
140pull_varnos_walker(Node *node, pull_varnos_context *context)
141{
142 if (node == NULL)
143 return false;
144 if (IsA(node, Var))
145 {
146 Var *var = (Var *) node;
147
148 if (var->varlevelsup == context->sublevels_up)
149 context->varnos = bms_add_member(context->varnos, var->varno);
150 return false;
151 }
152 if (IsA(node, CurrentOfExpr))
153 {
154 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
155
156 if (context->sublevels_up == 0)
157 context->varnos = bms_add_member(context->varnos, cexpr->cvarno);
158 return false;
159 }
160 if (IsA(node, PlaceHolderVar))
161 {
162 /*
163 * A PlaceHolderVar acts as a variable of its syntactic scope, or
164 * lower than that if it references only a subset of the rels in its
165 * syntactic scope. It might also contain lateral references, but we
166 * should ignore such references when computing the set of varnos in
167 * an expression tree. Also, if the PHV contains no variables within
168 * its syntactic scope, it will be forced to be evaluated exactly at
169 * the syntactic scope, so take that as the relid set.
170 */
171 PlaceHolderVar *phv = (PlaceHolderVar *) node;
172 pull_varnos_context subcontext;
173
174 subcontext.varnos = NULL;
175 subcontext.sublevels_up = context->sublevels_up;
176 (void) pull_varnos_walker((Node *) phv->phexpr, &subcontext);
177 if (phv->phlevelsup == context->sublevels_up)
178 {
179 subcontext.varnos = bms_int_members(subcontext.varnos,
180 phv->phrels);
181 if (bms_is_empty(subcontext.varnos))
182 context->varnos = bms_add_members(context->varnos,
183 phv->phrels);
184 }
185 context->varnos = bms_join(context->varnos, subcontext.varnos);
186 return false;
187 }
188 if (IsA(node, Query))
189 {
190 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
191 bool result;
192
193 context->sublevels_up++;
194 result = query_tree_walker((Query *) node, pull_varnos_walker,
195 (void *) context, 0);
196 context->sublevels_up--;
197 return result;
198 }
199 return expression_tree_walker(node, pull_varnos_walker,
200 (void *) context);
201}
202
203
204/*
205 * pull_varattnos
206 * Find all the distinct attribute numbers present in an expression tree,
207 * and add them to the initial contents of *varattnos.
208 * Only Vars of the given varno and rtable level zero are considered.
209 *
210 * Attribute numbers are offset by FirstLowInvalidHeapAttributeNumber so that
211 * we can include system attributes (e.g., OID) in the bitmap representation.
212 *
213 * Currently, this does not support unplanned subqueries; that is not needed
214 * for current uses. It will handle already-planned SubPlan nodes, though,
215 * looking into only the "testexpr" and the "args" list. (The subplan cannot
216 * contain any other references to Vars of the current level.)
217 */
218void
219pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
220{
221 pull_varattnos_context context;
222
223 context.varattnos = *varattnos;
224 context.varno = varno;
225
226 (void) pull_varattnos_walker(node, &context);
227
228 *varattnos = context.varattnos;
229}
230
231static bool
232pull_varattnos_walker(Node *node, pull_varattnos_context *context)
233{
234 if (node == NULL)
235 return false;
236 if (IsA(node, Var))
237 {
238 Var *var = (Var *) node;
239
240 if (var->varno == context->varno && var->varlevelsup == 0)
241 context->varattnos =
242 bms_add_member(context->varattnos,
243 var->varattno - FirstLowInvalidHeapAttributeNumber);
244 return false;
245 }
246
247 /* Should not find an unplanned subquery */
248 Assert(!IsA(node, Query));
249
250 return expression_tree_walker(node, pull_varattnos_walker,
251 (void *) context);
252}
253
254
255/*
256 * pull_vars_of_level
257 * Create a list of all Vars (and PlaceHolderVars) referencing the
258 * specified query level in the given parsetree.
259 *
260 * Caution: the Vars are not copied, only linked into the list.
261 */
262List *
263pull_vars_of_level(Node *node, int levelsup)
264{
265 pull_vars_context context;
266
267 context.vars = NIL;
268 context.sublevels_up = levelsup;
269
270 /*
271 * Must be prepared to start with a Query or a bare expression tree; if
272 * it's a Query, we don't want to increment sublevels_up.
273 */
274 query_or_expression_tree_walker(node,
275 pull_vars_walker,
276 (void *) &context,
277 0);
278
279 return context.vars;
280}
281
282static bool
283pull_vars_walker(Node *node, pull_vars_context *context)
284{
285 if (node == NULL)
286 return false;
287 if (IsA(node, Var))
288 {
289 Var *var = (Var *) node;
290
291 if (var->varlevelsup == context->sublevels_up)
292 context->vars = lappend(context->vars, var);
293 return false;
294 }
295 if (IsA(node, PlaceHolderVar))
296 {
297 PlaceHolderVar *phv = (PlaceHolderVar *) node;
298
299 if (phv->phlevelsup == context->sublevels_up)
300 context->vars = lappend(context->vars, phv);
301 /* we don't want to look into the contained expression */
302 return false;
303 }
304 if (IsA(node, Query))
305 {
306 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
307 bool result;
308
309 context->sublevels_up++;
310 result = query_tree_walker((Query *) node, pull_vars_walker,
311 (void *) context, 0);
312 context->sublevels_up--;
313 return result;
314 }
315 return expression_tree_walker(node, pull_vars_walker,
316 (void *) context);
317}
318
319
320/*
321 * contain_var_clause
322 * Recursively scan a clause to discover whether it contains any Var nodes
323 * (of the current query level).
324 *
325 * Returns true if any varnode found.
326 *
327 * Does not examine subqueries, therefore must only be used after reduction
328 * of sublinks to subplans!
329 */
330bool
331contain_var_clause(Node *node)
332{
333 return contain_var_clause_walker(node, NULL);
334}
335
336static bool
337contain_var_clause_walker(Node *node, void *context)
338{
339 if (node == NULL)
340 return false;
341 if (IsA(node, Var))
342 {
343 if (((Var *) node)->varlevelsup == 0)
344 return true; /* abort the tree traversal and return true */
345 return false;
346 }
347 if (IsA(node, CurrentOfExpr))
348 return true;
349 if (IsA(node, PlaceHolderVar))
350 {
351 if (((PlaceHolderVar *) node)->phlevelsup == 0)
352 return true; /* abort the tree traversal and return true */
353 /* else fall through to check the contained expr */
354 }
355 return expression_tree_walker(node, contain_var_clause_walker, context);
356}
357
358
359/*
360 * contain_vars_of_level
361 * Recursively scan a clause to discover whether it contains any Var nodes
362 * of the specified query level.
363 *
364 * Returns true if any such Var found.
365 *
366 * Will recurse into sublinks. Also, may be invoked directly on a Query.
367 */
368bool
369contain_vars_of_level(Node *node, int levelsup)
370{
371 int sublevels_up = levelsup;
372
373 return query_or_expression_tree_walker(node,
374 contain_vars_of_level_walker,
375 (void *) &sublevels_up,
376 0);
377}
378
379static bool
380contain_vars_of_level_walker(Node *node, int *sublevels_up)
381{
382 if (node == NULL)
383 return false;
384 if (IsA(node, Var))
385 {
386 if (((Var *) node)->varlevelsup == *sublevels_up)
387 return true; /* abort tree traversal and return true */
388 return false;
389 }
390 if (IsA(node, CurrentOfExpr))
391 {
392 if (*sublevels_up == 0)
393 return true;
394 return false;
395 }
396 if (IsA(node, PlaceHolderVar))
397 {
398 if (((PlaceHolderVar *) node)->phlevelsup == *sublevels_up)
399 return true; /* abort the tree traversal and return true */
400 /* else fall through to check the contained expr */
401 }
402 if (IsA(node, Query))
403 {
404 /* Recurse into subselects */
405 bool result;
406
407 (*sublevels_up)++;
408 result = query_tree_walker((Query *) node,
409 contain_vars_of_level_walker,
410 (void *) sublevels_up,
411 0);
412 (*sublevels_up)--;
413 return result;
414 }
415 return expression_tree_walker(node,
416 contain_vars_of_level_walker,
417 (void *) sublevels_up);
418}
419
420
421/*
422 * locate_var_of_level
423 * Find the parse location of any Var of the specified query level.
424 *
425 * Returns -1 if no such Var is in the querytree, or if they all have
426 * unknown parse location. (The former case is probably caller error,
427 * but we don't bother to distinguish it from the latter case.)
428 *
429 * Will recurse into sublinks. Also, may be invoked directly on a Query.
430 *
431 * Note: it might seem appropriate to merge this functionality into
432 * contain_vars_of_level, but that would complicate that function's API.
433 * Currently, the only uses of this function are for error reporting,
434 * and so shaving cycles probably isn't very important.
435 */
436int
437locate_var_of_level(Node *node, int levelsup)
438{
439 locate_var_of_level_context context;
440
441 context.var_location = -1; /* in case we find nothing */
442 context.sublevels_up = levelsup;
443
444 (void) query_or_expression_tree_walker(node,
445 locate_var_of_level_walker,
446 (void *) &context,
447 0);
448
449 return context.var_location;
450}
451
452static bool
453locate_var_of_level_walker(Node *node,
454 locate_var_of_level_context *context)
455{
456 if (node == NULL)
457 return false;
458 if (IsA(node, Var))
459 {
460 Var *var = (Var *) node;
461
462 if (var->varlevelsup == context->sublevels_up &&
463 var->location >= 0)
464 {
465 context->var_location = var->location;
466 return true; /* abort tree traversal and return true */
467 }
468 return false;
469 }
470 if (IsA(node, CurrentOfExpr))
471 {
472 /* since CurrentOfExpr doesn't carry location, nothing we can do */
473 return false;
474 }
475 /* No extra code needed for PlaceHolderVar; just look in contained expr */
476 if (IsA(node, Query))
477 {
478 /* Recurse into subselects */
479 bool result;
480
481 context->sublevels_up++;
482 result = query_tree_walker((Query *) node,
483 locate_var_of_level_walker,
484 (void *) context,
485 0);
486 context->sublevels_up--;
487 return result;
488 }
489 return expression_tree_walker(node,
490 locate_var_of_level_walker,
491 (void *) context);
492}
493
494
495/*
496 * pull_var_clause
497 * Recursively pulls all Var nodes from an expression clause.
498 *
499 * Aggrefs are handled according to these bits in 'flags':
500 * PVC_INCLUDE_AGGREGATES include Aggrefs in output list
501 * PVC_RECURSE_AGGREGATES recurse into Aggref arguments
502 * neither flag throw error if Aggref found
503 * Vars within an Aggref's expression are included in the result only
504 * when PVC_RECURSE_AGGREGATES is specified.
505 *
506 * WindowFuncs are handled according to these bits in 'flags':
507 * PVC_INCLUDE_WINDOWFUNCS include WindowFuncs in output list
508 * PVC_RECURSE_WINDOWFUNCS recurse into WindowFunc arguments
509 * neither flag throw error if WindowFunc found
510 * Vars within a WindowFunc's expression are included in the result only
511 * when PVC_RECURSE_WINDOWFUNCS is specified.
512 *
513 * PlaceHolderVars are handled according to these bits in 'flags':
514 * PVC_INCLUDE_PLACEHOLDERS include PlaceHolderVars in output list
515 * PVC_RECURSE_PLACEHOLDERS recurse into PlaceHolderVar arguments
516 * neither flag throw error if PlaceHolderVar found
517 * Vars within a PHV's expression are included in the result only
518 * when PVC_RECURSE_PLACEHOLDERS is specified.
519 *
520 * GroupingFuncs are treated mostly like Aggrefs, and so do not need
521 * their own flag bits.
522 *
523 * CurrentOfExpr nodes are ignored in all cases.
524 *
525 * Upper-level vars (with varlevelsup > 0) should not be seen here,
526 * likewise for upper-level Aggrefs and PlaceHolderVars.
527 *
528 * Returns list of nodes found. Note the nodes themselves are not
529 * copied, only referenced.
530 *
531 * Does not examine subqueries, therefore must only be used after reduction
532 * of sublinks to subplans!
533 */
534List *
535pull_var_clause(Node *node, int flags)
536{
537 pull_var_clause_context context;
538
539 /* Assert that caller has not specified inconsistent flags */
540 Assert((flags & (PVC_INCLUDE_AGGREGATES | PVC_RECURSE_AGGREGATES))
541 != (PVC_INCLUDE_AGGREGATES | PVC_RECURSE_AGGREGATES));
542 Assert((flags & (PVC_INCLUDE_WINDOWFUNCS | PVC_RECURSE_WINDOWFUNCS))
543 != (PVC_INCLUDE_WINDOWFUNCS | PVC_RECURSE_WINDOWFUNCS));
544 Assert((flags & (PVC_INCLUDE_PLACEHOLDERS | PVC_RECURSE_PLACEHOLDERS))
545 != (PVC_INCLUDE_PLACEHOLDERS | PVC_RECURSE_PLACEHOLDERS));
546
547 context.varlist = NIL;
548 context.flags = flags;
549
550 pull_var_clause_walker(node, &context);
551 return context.varlist;
552}
553
554static bool
555pull_var_clause_walker(Node *node, pull_var_clause_context *context)
556{
557 if (node == NULL)
558 return false;
559 if (IsA(node, Var))
560 {
561 if (((Var *) node)->varlevelsup != 0)
562 elog(ERROR, "Upper-level Var found where not expected");
563 context->varlist = lappend(context->varlist, node);
564 return false;
565 }
566 else if (IsA(node, Aggref))
567 {
568 if (((Aggref *) node)->agglevelsup != 0)
569 elog(ERROR, "Upper-level Aggref found where not expected");
570 if (context->flags & PVC_INCLUDE_AGGREGATES)
571 {
572 context->varlist = lappend(context->varlist, node);
573 /* we do NOT descend into the contained expression */
574 return false;
575 }
576 else if (context->flags & PVC_RECURSE_AGGREGATES)
577 {
578 /* fall through to recurse into the aggregate's arguments */
579 }
580 else
581 elog(ERROR, "Aggref found where not expected");
582 }
583 else if (IsA(node, GroupingFunc))
584 {
585 if (((GroupingFunc *) node)->agglevelsup != 0)
586 elog(ERROR, "Upper-level GROUPING found where not expected");
587 if (context->flags & PVC_INCLUDE_AGGREGATES)
588 {
589 context->varlist = lappend(context->varlist, node);
590 /* we do NOT descend into the contained expression */
591 return false;
592 }
593 else if (context->flags & PVC_RECURSE_AGGREGATES)
594 {
595 /*
596 * We do NOT descend into the contained expression, even if the
597 * caller asked for it, because we never actually evaluate it -
598 * the result is driven entirely off the associated GROUP BY
599 * clause, so we never need to extract the actual Vars here.
600 */
601 return false;
602 }
603 else
604 elog(ERROR, "GROUPING found where not expected");
605 }
606 else if (IsA(node, WindowFunc))
607 {
608 /* WindowFuncs have no levelsup field to check ... */
609 if (context->flags & PVC_INCLUDE_WINDOWFUNCS)
610 {
611 context->varlist = lappend(context->varlist, node);
612 /* we do NOT descend into the contained expressions */
613 return false;
614 }
615 else if (context->flags & PVC_RECURSE_WINDOWFUNCS)
616 {
617 /* fall through to recurse into the windowfunc's arguments */
618 }
619 else
620 elog(ERROR, "WindowFunc found where not expected");
621 }
622 else if (IsA(node, PlaceHolderVar))
623 {
624 if (((PlaceHolderVar *) node)->phlevelsup != 0)
625 elog(ERROR, "Upper-level PlaceHolderVar found where not expected");
626 if (context->flags & PVC_INCLUDE_PLACEHOLDERS)
627 {
628 context->varlist = lappend(context->varlist, node);
629 /* we do NOT descend into the contained expression */
630 return false;
631 }
632 else if (context->flags & PVC_RECURSE_PLACEHOLDERS)
633 {
634 /* fall through to recurse into the placeholder's expression */
635 }
636 else
637 elog(ERROR, "PlaceHolderVar found where not expected");
638 }
639 return expression_tree_walker(node, pull_var_clause_walker,
640 (void *) context);
641}
642
643
644/*
645 * flatten_join_alias_vars
646 * Replace Vars that reference JOIN outputs with references to the original
647 * relation variables instead. This allows quals involving such vars to be
648 * pushed down. Whole-row Vars that reference JOIN relations are expanded
649 * into RowExpr constructs that name the individual output Vars. This
650 * is necessary since we will not scan the JOIN as a base relation, which
651 * is the only way that the executor can directly handle whole-row Vars.
652 *
653 * This also adjusts relid sets found in some expression node types to
654 * substitute the contained base rels for any join relid.
655 *
656 * If a JOIN contains sub-selects that have been flattened, its join alias
657 * entries might now be arbitrary expressions, not just Vars. This affects
658 * this function in one important way: we might find ourselves inserting
659 * SubLink expressions into subqueries, and we must make sure that their
660 * Query.hasSubLinks fields get set to true if so. If there are any
661 * SubLinks in the join alias lists, the outer Query should already have
662 * hasSubLinks = true, so this is only relevant to un-flattened subqueries.
663 *
664 * NOTE: this is used on not-yet-planned expressions. We do not expect it
665 * to be applied directly to the whole Query, so if we see a Query to start
666 * with, we do want to increment sublevels_up (this occurs for LATERAL
667 * subqueries).
668 */
669Node *
670flatten_join_alias_vars(Query *query, Node *node)
671{
672 flatten_join_alias_vars_context context;
673
674 context.query = query;
675 context.sublevels_up = 0;
676 /* flag whether join aliases could possibly contain SubLinks */
677 context.possible_sublink = query->hasSubLinks;
678 /* if hasSubLinks is already true, no need to work hard */
679 context.inserted_sublink = query->hasSubLinks;
680
681 return flatten_join_alias_vars_mutator(node, &context);
682}
683
684static Node *
685flatten_join_alias_vars_mutator(Node *node,
686 flatten_join_alias_vars_context *context)
687{
688 if (node == NULL)
689 return NULL;
690 if (IsA(node, Var))
691 {
692 Var *var = (Var *) node;
693 RangeTblEntry *rte;
694 Node *newvar;
695
696 /* No change unless Var belongs to a JOIN of the target level */
697 if (var->varlevelsup != context->sublevels_up)
698 return node; /* no need to copy, really */
699 rte = rt_fetch(var->varno, context->query->rtable);
700 if (rte->rtekind != RTE_JOIN)
701 return node;
702 if (var->varattno == InvalidAttrNumber)
703 {
704 /* Must expand whole-row reference */
705 RowExpr *rowexpr;
706 List *fields = NIL;
707 List *colnames = NIL;
708 AttrNumber attnum;
709 ListCell *lv;
710 ListCell *ln;
711
712 attnum = 0;
713 Assert(list_length(rte->joinaliasvars) == list_length(rte->eref->colnames));
714 forboth(lv, rte->joinaliasvars, ln, rte->eref->colnames)
715 {
716 newvar = (Node *) lfirst(lv);
717 attnum++;
718 /* Ignore dropped columns */
719 if (newvar == NULL)
720 continue;
721 newvar = copyObject(newvar);
722
723 /*
724 * If we are expanding an alias carried down from an upper
725 * query, must adjust its varlevelsup fields.
726 */
727 if (context->sublevels_up != 0)
728 IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
729 /* Preserve original Var's location, if possible */
730 if (IsA(newvar, Var))
731 ((Var *) newvar)->location = var->location;
732 /* Recurse in case join input is itself a join */
733 /* (also takes care of setting inserted_sublink if needed) */
734 newvar = flatten_join_alias_vars_mutator(newvar, context);
735 fields = lappend(fields, newvar);
736 /* We need the names of non-dropped columns, too */
737 colnames = lappend(colnames, copyObject((Node *) lfirst(ln)));
738 }
739 rowexpr = makeNode(RowExpr);
740 rowexpr->args = fields;
741 rowexpr->row_typeid = var->vartype;
742 rowexpr->row_format = COERCE_IMPLICIT_CAST;
743 rowexpr->colnames = colnames;
744 rowexpr->location = var->location;
745
746 return (Node *) rowexpr;
747 }
748
749 /* Expand join alias reference */
750 Assert(var->varattno > 0);
751 newvar = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1);
752 Assert(newvar != NULL);
753 newvar = copyObject(newvar);
754
755 /*
756 * If we are expanding an alias carried down from an upper query, must
757 * adjust its varlevelsup fields.
758 */
759 if (context->sublevels_up != 0)
760 IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
761
762 /* Preserve original Var's location, if possible */
763 if (IsA(newvar, Var))
764 ((Var *) newvar)->location = var->location;
765
766 /* Recurse in case join input is itself a join */
767 newvar = flatten_join_alias_vars_mutator(newvar, context);
768
769 /* Detect if we are adding a sublink to query */
770 if (context->possible_sublink && !context->inserted_sublink)
771 context->inserted_sublink = checkExprHasSubLink(newvar);
772
773 return newvar;
774 }
775 if (IsA(node, PlaceHolderVar))
776 {
777 /* Copy the PlaceHolderVar node with correct mutation of subnodes */
778 PlaceHolderVar *phv;
779
780 phv = (PlaceHolderVar *) expression_tree_mutator(node,
781 flatten_join_alias_vars_mutator,
782 (void *) context);
783 /* now fix PlaceHolderVar's relid sets */
784 if (phv->phlevelsup == context->sublevels_up)
785 {
786 phv->phrels = alias_relid_set(context->query,
787 phv->phrels);
788 }
789 return (Node *) phv;
790 }
791
792 if (IsA(node, Query))
793 {
794 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
795 Query *newnode;
796 bool save_inserted_sublink;
797
798 context->sublevels_up++;
799 save_inserted_sublink = context->inserted_sublink;
800 context->inserted_sublink = ((Query *) node)->hasSubLinks;
801 newnode = query_tree_mutator((Query *) node,
802 flatten_join_alias_vars_mutator,
803 (void *) context,
804 QTW_IGNORE_JOINALIASES);
805 newnode->hasSubLinks |= context->inserted_sublink;
806 context->inserted_sublink = save_inserted_sublink;
807 context->sublevels_up--;
808 return (Node *) newnode;
809 }
810 /* Already-planned tree not supported */
811 Assert(!IsA(node, SubPlan));
812 /* Shouldn't need to handle these planner auxiliary nodes here */
813 Assert(!IsA(node, SpecialJoinInfo));
814 Assert(!IsA(node, PlaceHolderInfo));
815 Assert(!IsA(node, MinMaxAggInfo));
816
817 return expression_tree_mutator(node, flatten_join_alias_vars_mutator,
818 (void *) context);
819}
820
821/*
822 * alias_relid_set: in a set of RT indexes, replace joins by their
823 * underlying base relids
824 */
825static Relids
826alias_relid_set(Query *query, Relids relids)
827{
828 Relids result = NULL;
829 int rtindex;
830
831 rtindex = -1;
832 while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
833 {
834 RangeTblEntry *rte = rt_fetch(rtindex, query->rtable);
835
836 if (rte->rtekind == RTE_JOIN)
837 result = bms_join(result, get_relids_for_join(query, rtindex));
838 else
839 result = bms_add_member(result, rtindex);
840 }
841 return result;
842}
843