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