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 | |
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 | 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 | |
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(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 | */ |
94 | Relids |
95 | pull_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 | */ |
119 | Relids |
120 | pull_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 | |
139 | static bool |
140 | pull_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 | */ |
218 | void |
219 | pull_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 | |
231 | static bool |
232 | pull_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 | */ |
262 | List * |
263 | pull_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 | |
282 | static bool |
283 | pull_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 | */ |
330 | bool |
331 | contain_var_clause(Node *node) |
332 | { |
333 | return contain_var_clause_walker(node, NULL); |
334 | } |
335 | |
336 | static bool |
337 | contain_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 | */ |
368 | bool |
369 | contain_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 | |
379 | static bool |
380 | contain_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 | */ |
436 | int |
437 | locate_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 | |
452 | static bool |
453 | locate_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 | */ |
534 | List * |
535 | 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 | 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 | |
554 | static bool |
555 | pull_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 | */ |
669 | Node * |
670 | flatten_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 | |
684 | static Node * |
685 | flatten_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 | */ |
825 | static Relids |
826 | alias_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 | |