Line data Source code
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-2017, 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 : int flags;
59 : } pull_var_clause_context;
60 :
61 : typedef struct
62 : {
63 : PlannerInfo *root;
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 :
69 : static bool pull_varnos_walker(Node *node,
70 : pull_varnos_context *context);
71 : static bool pull_varattnos_walker(Node *node, pull_varattnos_context *context);
72 : static bool pull_vars_walker(Node *node, pull_vars_context *context);
73 : static bool contain_var_clause_walker(Node *node, void *context);
74 : static bool contain_vars_of_level_walker(Node *node, int *sublevels_up);
75 : static bool locate_var_of_level_walker(Node *node,
76 : locate_var_of_level_context *context);
77 : static bool pull_var_clause_walker(Node *node,
78 : pull_var_clause_context *context);
79 : static Node *flatten_join_alias_vars_mutator(Node *node,
80 : flatten_join_alias_vars_context *context);
81 : static Relids alias_relid_set(PlannerInfo *root, 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 : */
94 : Relids
95 146413 : pull_varnos(Node *node)
96 : {
97 : pull_varnos_context context;
98 :
99 146413 : context.varnos = NULL;
100 146413 : 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 146413 : query_or_expression_tree_walker(node,
107 : pull_varnos_walker,
108 : (void *) &context,
109 : 0);
110 :
111 146413 : 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 : */
119 : Relids
120 74 : pull_varnos_of_level(Node *node, int levelsup)
121 : {
122 : pull_varnos_context context;
123 :
124 74 : context.varnos = NULL;
125 74 : 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 74 : query_or_expression_tree_walker(node,
132 : pull_varnos_walker,
133 : (void *) &context,
134 : 0);
135 :
136 74 : return context.varnos;
137 : }
138 :
139 : static bool
140 216662 : pull_varnos_walker(Node *node, pull_varnos_context *context)
141 : {
142 216662 : if (node == NULL)
143 1086 : return false;
144 215576 : if (IsA(node, Var))
145 : {
146 124725 : Var *var = (Var *) node;
147 :
148 124725 : if (var->varlevelsup == context->sublevels_up)
149 124638 : context->varnos = bms_add_member(context->varnos, var->varno);
150 124725 : return false;
151 : }
152 90851 : if (IsA(node, CurrentOfExpr))
153 : {
154 114 : CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
155 :
156 114 : if (context->sublevels_up == 0)
157 114 : context->varnos = bms_add_member(context->varnos, cexpr->cvarno);
158 114 : return false;
159 : }
160 90737 : 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 182 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
172 : pull_varnos_context subcontext;
173 :
174 182 : subcontext.varnos = NULL;
175 182 : subcontext.sublevels_up = context->sublevels_up;
176 182 : (void) pull_varnos_walker((Node *) phv->phexpr, &subcontext);
177 182 : if (phv->phlevelsup == context->sublevels_up)
178 : {
179 182 : subcontext.varnos = bms_int_members(subcontext.varnos,
180 182 : phv->phrels);
181 182 : if (bms_is_empty(subcontext.varnos))
182 102 : context->varnos = bms_add_members(context->varnos,
183 102 : phv->phrels);
184 : }
185 182 : context->varnos = bms_join(context->varnos, subcontext.varnos);
186 182 : return false;
187 : }
188 90555 : if (IsA(node, Query))
189 : {
190 : /* Recurse into RTE subquery or not-yet-planned sublink subquery */
191 : bool result;
192 :
193 6 : context->sublevels_up++;
194 6 : result = query_tree_walker((Query *) node, pull_varnos_walker,
195 : (void *) context, 0);
196 6 : context->sublevels_up--;
197 6 : return result;
198 : }
199 90549 : 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 : */
218 : void
219 54056 : pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
220 : {
221 : pull_varattnos_context context;
222 :
223 54056 : context.varattnos = *varattnos;
224 54056 : context.varno = varno;
225 :
226 54056 : (void) pull_varattnos_walker(node, &context);
227 :
228 54056 : *varattnos = context.varattnos;
229 54056 : }
230 :
231 : static bool
232 179040 : pull_varattnos_walker(Node *node, pull_varattnos_context *context)
233 : {
234 179040 : if (node == NULL)
235 3407 : return false;
236 175633 : if (IsA(node, Var))
237 : {
238 98715 : Var *var = (Var *) node;
239 :
240 98715 : if (var->varno == context->varno && var->varlevelsup == 0)
241 98715 : context->varattnos =
242 98715 : bms_add_member(context->varattnos,
243 98715 : var->varattno - FirstLowInvalidHeapAttributeNumber);
244 98715 : return false;
245 : }
246 :
247 : /* Should not find an unplanned subquery */
248 76918 : Assert(!IsA(node, Query));
249 :
250 76918 : 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 : */
262 : List *
263 124 : pull_vars_of_level(Node *node, int levelsup)
264 : {
265 : pull_vars_context context;
266 :
267 124 : context.vars = NIL;
268 124 : 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 124 : query_or_expression_tree_walker(node,
275 : pull_vars_walker,
276 : (void *) &context,
277 : 0);
278 :
279 124 : return context.vars;
280 : }
281 :
282 : static bool
283 2132 : pull_vars_walker(Node *node, pull_vars_context *context)
284 : {
285 2132 : if (node == NULL)
286 784 : return false;
287 1348 : if (IsA(node, Var))
288 : {
289 288 : Var *var = (Var *) node;
290 :
291 288 : if (var->varlevelsup == context->sublevels_up)
292 181 : context->vars = lappend(context->vars, var);
293 288 : return false;
294 : }
295 1060 : if (IsA(node, PlaceHolderVar))
296 : {
297 6 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
298 :
299 6 : if (phv->phlevelsup == context->sublevels_up)
300 6 : context->vars = lappend(context->vars, phv);
301 : /* we don't want to look into the contained expression */
302 6 : return false;
303 : }
304 1054 : if (IsA(node, Query))
305 : {
306 : /* Recurse into RTE subquery or not-yet-planned sublink subquery */
307 : bool result;
308 :
309 20 : context->sublevels_up++;
310 20 : result = query_tree_walker((Query *) node, pull_vars_walker,
311 : (void *) context, 0);
312 20 : context->sublevels_up--;
313 20 : return result;
314 : }
315 1034 : 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 : */
330 : bool
331 735 : contain_var_clause(Node *node)
332 : {
333 735 : return contain_var_clause_walker(node, NULL);
334 : }
335 :
336 : static bool
337 1283 : contain_var_clause_walker(Node *node, void *context)
338 : {
339 1283 : if (node == NULL)
340 11 : return false;
341 1272 : if (IsA(node, Var))
342 : {
343 296 : if (((Var *) node)->varlevelsup == 0)
344 296 : return true; /* abort the tree traversal and return true */
345 0 : return false;
346 : }
347 976 : if (IsA(node, CurrentOfExpr))
348 0 : return true;
349 976 : if (IsA(node, PlaceHolderVar))
350 : {
351 0 : if (((PlaceHolderVar *) node)->phlevelsup == 0)
352 0 : return true; /* abort the tree traversal and return true */
353 : /* else fall through to check the contained expr */
354 : }
355 976 : 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 : */
368 : bool
369 4473 : contain_vars_of_level(Node *node, int levelsup)
370 : {
371 4473 : int sublevels_up = levelsup;
372 :
373 4473 : return query_or_expression_tree_walker(node,
374 : contain_vars_of_level_walker,
375 : (void *) &sublevels_up,
376 : 0);
377 : }
378 :
379 : static bool
380 17377 : contain_vars_of_level_walker(Node *node, int *sublevels_up)
381 : {
382 17377 : if (node == NULL)
383 4918 : return false;
384 12459 : if (IsA(node, Var))
385 : {
386 2633 : if (((Var *) node)->varlevelsup == *sublevels_up)
387 1209 : return true; /* abort tree traversal and return true */
388 1424 : return false;
389 : }
390 9826 : if (IsA(node, CurrentOfExpr))
391 : {
392 0 : if (*sublevels_up == 0)
393 0 : return true;
394 0 : return false;
395 : }
396 9826 : if (IsA(node, PlaceHolderVar))
397 : {
398 3 : if (((PlaceHolderVar *) node)->phlevelsup == *sublevels_up)
399 2 : return true; /* abort the tree traversal and return true */
400 : /* else fall through to check the contained expr */
401 : }
402 9824 : if (IsA(node, Query))
403 : {
404 : /* Recurse into subselects */
405 : bool result;
406 :
407 51 : (*sublevels_up)++;
408 51 : result = query_tree_walker((Query *) node,
409 : contain_vars_of_level_walker,
410 : (void *) sublevels_up,
411 : 0);
412 51 : (*sublevels_up)--;
413 51 : return result;
414 : }
415 9773 : 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 : */
436 : int
437 1 : locate_var_of_level(Node *node, int levelsup)
438 : {
439 : locate_var_of_level_context context;
440 :
441 1 : context.var_location = -1; /* in case we find nothing */
442 1 : context.sublevels_up = levelsup;
443 :
444 1 : (void) query_or_expression_tree_walker(node,
445 : locate_var_of_level_walker,
446 : (void *) &context,
447 : 0);
448 :
449 1 : return context.var_location;
450 : }
451 :
452 : static bool
453 3 : locate_var_of_level_walker(Node *node,
454 : locate_var_of_level_context *context)
455 : {
456 3 : if (node == NULL)
457 0 : return false;
458 3 : if (IsA(node, Var))
459 : {
460 1 : Var *var = (Var *) node;
461 :
462 2 : if (var->varlevelsup == context->sublevels_up &&
463 1 : var->location >= 0)
464 : {
465 1 : context->var_location = var->location;
466 1 : return true; /* abort tree traversal and return true */
467 : }
468 0 : return false;
469 : }
470 2 : if (IsA(node, CurrentOfExpr))
471 : {
472 : /* since CurrentOfExpr doesn't carry location, nothing we can do */
473 0 : return false;
474 : }
475 : /* No extra code needed for PlaceHolderVar; just look in contained expr */
476 2 : if (IsA(node, Query))
477 : {
478 : /* Recurse into subselects */
479 : bool result;
480 :
481 0 : context->sublevels_up++;
482 0 : result = query_tree_walker((Query *) node,
483 : locate_var_of_level_walker,
484 : (void *) context,
485 : 0);
486 0 : context->sublevels_up--;
487 0 : return result;
488 : }
489 2 : 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 : */
534 : List *
535 26231 : pull_var_clause(Node *node, int flags)
536 : {
537 : pull_var_clause_context context;
538 :
539 : /* Assert that caller has not specified inconsistent flags */
540 26231 : Assert((flags & (PVC_INCLUDE_AGGREGATES | PVC_RECURSE_AGGREGATES))
541 : != (PVC_INCLUDE_AGGREGATES | PVC_RECURSE_AGGREGATES));
542 26231 : Assert((flags & (PVC_INCLUDE_WINDOWFUNCS | PVC_RECURSE_WINDOWFUNCS))
543 : != (PVC_INCLUDE_WINDOWFUNCS | PVC_RECURSE_WINDOWFUNCS));
544 26231 : Assert((flags & (PVC_INCLUDE_PLACEHOLDERS | PVC_RECURSE_PLACEHOLDERS))
545 : != (PVC_INCLUDE_PLACEHOLDERS | PVC_RECURSE_PLACEHOLDERS));
546 :
547 26231 : context.varlist = NIL;
548 26231 : context.flags = flags;
549 :
550 26231 : pull_var_clause_walker(node, &context);
551 26231 : return context.varlist;
552 : }
553 :
554 : static bool
555 165199 : pull_var_clause_walker(Node *node, pull_var_clause_context *context)
556 : {
557 165199 : if (node == NULL)
558 8093 : return false;
559 157106 : if (IsA(node, Var))
560 : {
561 55207 : if (((Var *) node)->varlevelsup != 0)
562 0 : elog(ERROR, "Upper-level Var found where not expected");
563 55207 : context->varlist = lappend(context->varlist, node);
564 55207 : return false;
565 : }
566 101899 : else if (IsA(node, Aggref))
567 : {
568 5199 : if (((Aggref *) node)->agglevelsup != 0)
569 0 : elog(ERROR, "Upper-level Aggref found where not expected");
570 5199 : if (context->flags & PVC_INCLUDE_AGGREGATES)
571 : {
572 74 : context->varlist = lappend(context->varlist, node);
573 : /* we do NOT descend into the contained expression */
574 74 : return false;
575 : }
576 5125 : else if (context->flags & PVC_RECURSE_AGGREGATES)
577 : {
578 : /* fall through to recurse into the aggregate's arguments */
579 : }
580 : else
581 0 : elog(ERROR, "Aggref found where not expected");
582 : }
583 96700 : else if (IsA(node, GroupingFunc))
584 : {
585 73 : if (((GroupingFunc *) node)->agglevelsup != 0)
586 0 : elog(ERROR, "Upper-level GROUPING found where not expected");
587 73 : if (context->flags & PVC_INCLUDE_AGGREGATES)
588 : {
589 0 : context->varlist = lappend(context->varlist, node);
590 : /* we do NOT descend into the contained expression */
591 0 : return false;
592 : }
593 73 : 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 73 : return false;
602 : }
603 : else
604 0 : elog(ERROR, "GROUPING found where not expected");
605 : }
606 96627 : else if (IsA(node, WindowFunc))
607 : {
608 : /* WindowFuncs have no levelsup field to check ... */
609 353 : if (context->flags & PVC_INCLUDE_WINDOWFUNCS)
610 : {
611 2 : context->varlist = lappend(context->varlist, node);
612 : /* we do NOT descend into the contained expressions */
613 2 : return false;
614 : }
615 351 : else if (context->flags & PVC_RECURSE_WINDOWFUNCS)
616 : {
617 : /* fall through to recurse into the windowfunc's arguments */
618 : }
619 : else
620 0 : elog(ERROR, "WindowFunc found where not expected");
621 : }
622 96274 : else if (IsA(node, PlaceHolderVar))
623 : {
624 105 : if (((PlaceHolderVar *) node)->phlevelsup != 0)
625 0 : elog(ERROR, "Upper-level PlaceHolderVar found where not expected");
626 105 : if (context->flags & PVC_INCLUDE_PLACEHOLDERS)
627 : {
628 105 : context->varlist = lappend(context->varlist, node);
629 : /* we do NOT descend into the contained expression */
630 105 : return false;
631 : }
632 0 : else if (context->flags & PVC_RECURSE_PLACEHOLDERS)
633 : {
634 : /* fall through to recurse into the placeholder's expression */
635 : }
636 : else
637 0 : elog(ERROR, "PlaceHolderVar found where not expected");
638 : }
639 101645 : 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 : */
669 : Node *
670 8263 : flatten_join_alias_vars(PlannerInfo *root, Node *node)
671 : {
672 : flatten_join_alias_vars_context context;
673 :
674 8263 : context.root = root;
675 8263 : context.sublevels_up = 0;
676 : /* flag whether join aliases could possibly contain SubLinks */
677 8263 : context.possible_sublink = root->parse->hasSubLinks;
678 : /* if hasSubLinks is already true, no need to work hard */
679 8263 : context.inserted_sublink = root->parse->hasSubLinks;
680 :
681 8263 : return flatten_join_alias_vars_mutator(node, &context);
682 : }
683 :
684 : static Node *
685 111955 : flatten_join_alias_vars_mutator(Node *node,
686 : flatten_join_alias_vars_context *context)
687 : {
688 111955 : if (node == NULL)
689 8309 : return NULL;
690 103646 : if (IsA(node, Var))
691 : {
692 33635 : 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 33635 : if (var->varlevelsup != context->sublevels_up)
698 1449 : return node; /* no need to copy, really */
699 32186 : rte = rt_fetch(var->varno, context->root->parse->rtable);
700 32186 : if (rte->rtekind != RTE_JOIN)
701 26323 : return node;
702 5863 : if (var->varattno == InvalidAttrNumber)
703 : {
704 : /* Must expand whole-row reference */
705 : RowExpr *rowexpr;
706 1 : List *fields = NIL;
707 1 : List *colnames = NIL;
708 : AttrNumber attnum;
709 : ListCell *lv;
710 : ListCell *ln;
711 :
712 1 : attnum = 0;
713 1 : Assert(list_length(rte->joinaliasvars) == list_length(rte->eref->colnames));
714 8 : forboth(lv, rte->joinaliasvars, ln, rte->eref->colnames)
715 : {
716 7 : newvar = (Node *) lfirst(lv);
717 7 : attnum++;
718 : /* Ignore dropped columns */
719 7 : if (newvar == NULL)
720 0 : continue;
721 7 : 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 7 : if (context->sublevels_up != 0)
728 0 : IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
729 : /* Preserve original Var's location, if possible */
730 7 : if (IsA(newvar, Var))
731 7 : ((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 7 : newvar = flatten_join_alias_vars_mutator(newvar, context);
735 7 : fields = lappend(fields, newvar);
736 : /* We need the names of non-dropped columns, too */
737 7 : colnames = lappend(colnames, copyObject((Node *) lfirst(ln)));
738 : }
739 1 : rowexpr = makeNode(RowExpr);
740 1 : rowexpr->args = fields;
741 1 : rowexpr->row_typeid = var->vartype;
742 1 : rowexpr->row_format = COERCE_IMPLICIT_CAST;
743 1 : rowexpr->colnames = colnames;
744 1 : rowexpr->location = var->location;
745 :
746 1 : return (Node *) rowexpr;
747 : }
748 :
749 : /* Expand join alias reference */
750 5862 : Assert(var->varattno > 0);
751 5862 : newvar = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1);
752 5862 : Assert(newvar != NULL);
753 5862 : 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 5862 : if (context->sublevels_up != 0)
760 38 : IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
761 :
762 : /* Preserve original Var's location, if possible */
763 5862 : if (IsA(newvar, Var))
764 5784 : ((Var *) newvar)->location = var->location;
765 :
766 : /* Recurse in case join input is itself a join */
767 5862 : newvar = flatten_join_alias_vars_mutator(newvar, context);
768 :
769 : /* Detect if we are adding a sublink to query */
770 5862 : if (context->possible_sublink && !context->inserted_sublink)
771 35 : context->inserted_sublink = checkExprHasSubLink(newvar);
772 :
773 5862 : return newvar;
774 : }
775 70011 : if (IsA(node, PlaceHolderVar))
776 : {
777 : /* Copy the PlaceHolderVar node with correct mutation of subnodes */
778 : PlaceHolderVar *phv;
779 :
780 104 : phv = (PlaceHolderVar *) expression_tree_mutator(node,
781 : flatten_join_alias_vars_mutator,
782 : (void *) context);
783 : /* now fix PlaceHolderVar's relid sets */
784 104 : if (phv->phlevelsup == context->sublevels_up)
785 : {
786 98 : phv->phrels = alias_relid_set(context->root,
787 : phv->phrels);
788 : }
789 104 : return (Node *) phv;
790 : }
791 :
792 69907 : 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 456 : context->sublevels_up++;
799 456 : save_inserted_sublink = context->inserted_sublink;
800 456 : context->inserted_sublink = ((Query *) node)->hasSubLinks;
801 456 : newnode = query_tree_mutator((Query *) node,
802 : flatten_join_alias_vars_mutator,
803 : (void *) context,
804 : QTW_IGNORE_JOINALIASES);
805 456 : newnode->hasSubLinks |= context->inserted_sublink;
806 456 : context->inserted_sublink = save_inserted_sublink;
807 456 : context->sublevels_up--;
808 456 : return (Node *) newnode;
809 : }
810 : /* Already-planned tree not supported */
811 69451 : Assert(!IsA(node, SubPlan));
812 : /* Shouldn't need to handle these planner auxiliary nodes here */
813 69451 : Assert(!IsA(node, SpecialJoinInfo));
814 69451 : Assert(!IsA(node, PlaceHolderInfo));
815 69451 : Assert(!IsA(node, MinMaxAggInfo));
816 :
817 69451 : 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 : */
825 : static Relids
826 98 : alias_relid_set(PlannerInfo *root, Relids relids)
827 : {
828 98 : Relids result = NULL;
829 : int rtindex;
830 :
831 98 : rtindex = -1;
832 334 : while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
833 : {
834 138 : RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable);
835 :
836 138 : if (rte->rtekind == RTE_JOIN)
837 0 : result = bms_join(result, get_relids_for_join(root, rtindex));
838 : else
839 138 : result = bms_add_member(result, rtindex);
840 : }
841 98 : return result;
842 : }
|