Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * prepjointree.c
4 : * Planner preprocessing for subqueries and join tree manipulation.
5 : *
6 : * NOTE: the intended sequence for invoking these operations is
7 : * pull_up_sublinks
8 : * inline_set_returning_functions
9 : * pull_up_subqueries
10 : * flatten_simple_union_all
11 : * do expression preprocessing (including flattening JOIN alias vars)
12 : * reduce_outer_joins
13 : *
14 : *
15 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
16 : * Portions Copyright (c) 1994, Regents of the University of California
17 : *
18 : *
19 : * IDENTIFICATION
20 : * src/backend/optimizer/prep/prepjointree.c
21 : *
22 : *-------------------------------------------------------------------------
23 : */
24 : #include "postgres.h"
25 :
26 : #include "catalog/pg_type.h"
27 : #include "nodes/makefuncs.h"
28 : #include "nodes/nodeFuncs.h"
29 : #include "optimizer/clauses.h"
30 : #include "optimizer/placeholder.h"
31 : #include "optimizer/prep.h"
32 : #include "optimizer/subselect.h"
33 : #include "optimizer/tlist.h"
34 : #include "optimizer/var.h"
35 : #include "parser/parse_relation.h"
36 : #include "parser/parsetree.h"
37 : #include "rewrite/rewriteManip.h"
38 :
39 :
40 : typedef struct pullup_replace_vars_context
41 : {
42 : PlannerInfo *root;
43 : List *targetlist; /* tlist of subquery being pulled up */
44 : RangeTblEntry *target_rte; /* RTE of subquery */
45 : Relids relids; /* relids within subquery, as numbered after
46 : * pullup (set only if target_rte->lateral) */
47 : bool *outer_hasSubLinks; /* -> outer query's hasSubLinks */
48 : int varno; /* varno of subquery */
49 : bool need_phvs; /* do we need PlaceHolderVars? */
50 : bool wrap_non_vars; /* do we need 'em on *all* non-Vars? */
51 : Node **rv_cache; /* cache for results with PHVs */
52 : } pullup_replace_vars_context;
53 :
54 : typedef struct reduce_outer_joins_state
55 : {
56 : Relids relids; /* base relids within this subtree */
57 : bool contains_outer; /* does subtree contain outer join(s)? */
58 : List *sub_states; /* List of states for subtree components */
59 : } reduce_outer_joins_state;
60 :
61 : static Node *pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode,
62 : Relids *relids);
63 : static Node *pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
64 : Node **jtlink1, Relids available_rels1,
65 : Node **jtlink2, Relids available_rels2);
66 : static Node *pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode,
67 : JoinExpr *lowest_outer_join,
68 : JoinExpr *lowest_nulling_outer_join,
69 : AppendRelInfo *containing_appendrel,
70 : bool deletion_ok);
71 : static Node *pull_up_simple_subquery(PlannerInfo *root, Node *jtnode,
72 : RangeTblEntry *rte,
73 : JoinExpr *lowest_outer_join,
74 : JoinExpr *lowest_nulling_outer_join,
75 : AppendRelInfo *containing_appendrel,
76 : bool deletion_ok);
77 : static Node *pull_up_simple_union_all(PlannerInfo *root, Node *jtnode,
78 : RangeTblEntry *rte);
79 : static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root,
80 : int parentRTindex, Query *setOpQuery,
81 : int childRToffset);
82 : static void make_setop_translation_list(Query *query, Index newvarno,
83 : List **translated_vars);
84 : static bool is_simple_subquery(Query *subquery, RangeTblEntry *rte,
85 : JoinExpr *lowest_outer_join,
86 : bool deletion_ok);
87 : static Node *pull_up_simple_values(PlannerInfo *root, Node *jtnode,
88 : RangeTblEntry *rte);
89 : static bool is_simple_values(PlannerInfo *root, RangeTblEntry *rte,
90 : bool deletion_ok);
91 : static bool is_simple_union_all(Query *subquery);
92 : static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery,
93 : List *colTypes);
94 : static bool is_safe_append_member(Query *subquery);
95 : static bool jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted,
96 : Relids safe_upper_varnos);
97 : static void replace_vars_in_jointree(Node *jtnode,
98 : pullup_replace_vars_context *context,
99 : JoinExpr *lowest_nulling_outer_join);
100 : static Node *pullup_replace_vars(Node *expr,
101 : pullup_replace_vars_context *context);
102 : static Node *pullup_replace_vars_callback(Var *var,
103 : replace_rte_variables_context *context);
104 : static Query *pullup_replace_vars_subquery(Query *query,
105 : pullup_replace_vars_context *context);
106 : static Node *pull_up_subqueries_cleanup(Node *jtnode);
107 : static reduce_outer_joins_state *reduce_outer_joins_pass1(Node *jtnode);
108 : static void reduce_outer_joins_pass2(Node *jtnode,
109 : reduce_outer_joins_state *state,
110 : PlannerInfo *root,
111 : Relids nonnullable_rels,
112 : List *nonnullable_vars,
113 : List *forced_null_vars);
114 : static void substitute_multiple_relids(Node *node,
115 : int varno, Relids subrelids);
116 : static void fix_append_rel_relids(List *append_rel_list, int varno,
117 : Relids subrelids);
118 : static Node *find_jointree_node_for_rel(Node *jtnode, int relid);
119 :
120 :
121 : /*
122 : * pull_up_sublinks
123 : * Attempt to pull up ANY and EXISTS SubLinks to be treated as
124 : * semijoins or anti-semijoins.
125 : *
126 : * A clause "foo op ANY (sub-SELECT)" can be processed by pulling the
127 : * sub-SELECT up to become a rangetable entry and treating the implied
128 : * comparisons as quals of a semijoin. However, this optimization *only*
129 : * works at the top level of WHERE or a JOIN/ON clause, because we cannot
130 : * distinguish whether the ANY ought to return FALSE or NULL in cases
131 : * involving NULL inputs. Also, in an outer join's ON clause we can only
132 : * do this if the sublink is degenerate (ie, references only the nullable
133 : * side of the join). In that case it is legal to push the semijoin
134 : * down into the nullable side of the join. If the sublink references any
135 : * nonnullable-side variables then it would have to be evaluated as part
136 : * of the outer join, which makes things way too complicated.
137 : *
138 : * Under similar conditions, EXISTS and NOT EXISTS clauses can be handled
139 : * by pulling up the sub-SELECT and creating a semijoin or anti-semijoin.
140 : *
141 : * This routine searches for such clauses and does the necessary parsetree
142 : * transformations if any are found.
143 : *
144 : * This routine has to run before preprocess_expression(), so the quals
145 : * clauses are not yet reduced to implicit-AND format, and are not guaranteed
146 : * to be AND/OR-flat either. That means we need to recursively search through
147 : * explicit AND clauses. We stop as soon as we hit a non-AND item.
148 : */
149 : void
150 1512 : pull_up_sublinks(PlannerInfo *root)
151 : {
152 : Node *jtnode;
153 : Relids relids;
154 :
155 : /* Begin recursion through the jointree */
156 1512 : jtnode = pull_up_sublinks_jointree_recurse(root,
157 1512 : (Node *) root->parse->jointree,
158 : &relids);
159 :
160 : /*
161 : * root->parse->jointree must always be a FromExpr, so insert a dummy one
162 : * if we got a bare RangeTblRef or JoinExpr out of the recursion.
163 : */
164 1512 : if (IsA(jtnode, FromExpr))
165 1251 : root->parse->jointree = (FromExpr *) jtnode;
166 : else
167 261 : root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
168 1512 : }
169 :
170 : /*
171 : * Recurse through jointree nodes for pull_up_sublinks()
172 : *
173 : * In addition to returning the possibly-modified jointree node, we return
174 : * a relids set of the contained rels into *relids.
175 : */
176 : static Node *
177 3739 : pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode,
178 : Relids *relids)
179 : {
180 3739 : if (jtnode == NULL)
181 : {
182 0 : *relids = NULL;
183 : }
184 3739 : else if (IsA(jtnode, RangeTblRef))
185 : {
186 1985 : int varno = ((RangeTblRef *) jtnode)->rtindex;
187 :
188 1985 : *relids = bms_make_singleton(varno);
189 : /* jtnode is returned unmodified */
190 : }
191 1754 : else if (IsA(jtnode, FromExpr))
192 : {
193 1512 : FromExpr *f = (FromExpr *) jtnode;
194 1512 : List *newfromlist = NIL;
195 1512 : Relids frelids = NULL;
196 : FromExpr *newf;
197 : Node *jtlink;
198 : ListCell *l;
199 :
200 : /* First, recurse to process children and collect their relids */
201 2987 : foreach(l, f->fromlist)
202 : {
203 : Node *newchild;
204 : Relids childrelids;
205 :
206 1475 : newchild = pull_up_sublinks_jointree_recurse(root,
207 1475 : lfirst(l),
208 : &childrelids);
209 1475 : newfromlist = lappend(newfromlist, newchild);
210 1475 : frelids = bms_join(frelids, childrelids);
211 : }
212 : /* Build the replacement FromExpr; no quals yet */
213 1512 : newf = makeFromExpr(newfromlist, NULL);
214 : /* Set up a link representing the rebuilt jointree */
215 1512 : jtlink = (Node *) newf;
216 : /* Now process qual --- all children are available for use */
217 1512 : newf->quals = pull_up_sublinks_qual_recurse(root, f->quals,
218 : &jtlink, frelids,
219 : NULL, NULL);
220 :
221 : /*
222 : * Note that the result will be either newf, or a stack of JoinExprs
223 : * with newf at the base. We rely on subsequent optimization steps to
224 : * flatten this and rearrange the joins as needed.
225 : *
226 : * Although we could include the pulled-up subqueries in the returned
227 : * relids, there's no need since upper quals couldn't refer to their
228 : * outputs anyway.
229 : */
230 1512 : *relids = frelids;
231 1512 : jtnode = jtlink;
232 : }
233 242 : else if (IsA(jtnode, JoinExpr))
234 : {
235 : JoinExpr *j;
236 : Relids leftrelids;
237 : Relids rightrelids;
238 : Node *jtlink;
239 :
240 : /*
241 : * Make a modifiable copy of join node, but don't bother copying its
242 : * subnodes (yet).
243 : */
244 242 : j = (JoinExpr *) palloc(sizeof(JoinExpr));
245 242 : memcpy(j, jtnode, sizeof(JoinExpr));
246 242 : jtlink = (Node *) j;
247 :
248 : /* Recurse to process children and collect their relids */
249 242 : j->larg = pull_up_sublinks_jointree_recurse(root, j->larg,
250 : &leftrelids);
251 242 : j->rarg = pull_up_sublinks_jointree_recurse(root, j->rarg,
252 : &rightrelids);
253 :
254 : /*
255 : * Now process qual, showing appropriate child relids as available,
256 : * and attach any pulled-up jointree items at the right place. In the
257 : * inner-join case we put new JoinExprs above the existing one (much
258 : * as for a FromExpr-style join). In outer-join cases the new
259 : * JoinExprs must go into the nullable side of the outer join. The
260 : * point of the available_rels machinations is to ensure that we only
261 : * pull up quals for which that's okay.
262 : *
263 : * We don't expect to see any pre-existing JOIN_SEMI or JOIN_ANTI
264 : * nodes here.
265 : */
266 242 : switch (j->jointype)
267 : {
268 : case JOIN_INNER:
269 50 : j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
270 : &jtlink,
271 : bms_union(leftrelids,
272 : rightrelids),
273 : NULL, NULL);
274 50 : break;
275 : case JOIN_LEFT:
276 192 : j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
277 : &j->rarg,
278 : rightrelids,
279 : NULL, NULL);
280 192 : break;
281 : case JOIN_FULL:
282 : /* can't do anything with full-join quals */
283 0 : break;
284 : case JOIN_RIGHT:
285 0 : j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
286 : &j->larg,
287 : leftrelids,
288 : NULL, NULL);
289 0 : break;
290 : default:
291 0 : elog(ERROR, "unrecognized join type: %d",
292 : (int) j->jointype);
293 : break;
294 : }
295 :
296 : /*
297 : * Although we could include the pulled-up subqueries in the returned
298 : * relids, there's no need since upper quals couldn't refer to their
299 : * outputs anyway. But we *do* need to include the join's own rtindex
300 : * because we haven't yet collapsed join alias variables, so upper
301 : * levels would mistakenly think they couldn't use references to this
302 : * join.
303 : */
304 242 : *relids = bms_join(leftrelids, rightrelids);
305 242 : if (j->rtindex)
306 242 : *relids = bms_add_member(*relids, j->rtindex);
307 242 : jtnode = jtlink;
308 : }
309 : else
310 0 : elog(ERROR, "unrecognized node type: %d",
311 : (int) nodeTag(jtnode));
312 3739 : return jtnode;
313 : }
314 :
315 : /*
316 : * Recurse through top-level qual nodes for pull_up_sublinks()
317 : *
318 : * jtlink1 points to the link in the jointree where any new JoinExprs should
319 : * be inserted if they reference available_rels1 (i.e., available_rels1
320 : * denotes the relations present underneath jtlink1). Optionally, jtlink2 can
321 : * point to a second link where new JoinExprs should be inserted if they
322 : * reference available_rels2 (pass NULL for both those arguments if not used).
323 : * Note that SubLinks referencing both sets of variables cannot be optimized.
324 : * If we find multiple pull-up-able SubLinks, they'll get stacked onto jtlink1
325 : * and/or jtlink2 in the order we encounter them. We rely on subsequent
326 : * optimization to rearrange the stack if appropriate.
327 : *
328 : * Returns the replacement qual node, or NULL if the qual should be removed.
329 : */
330 : static Node *
331 3754 : pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
332 : Node **jtlink1, Relids available_rels1,
333 : Node **jtlink2, Relids available_rels2)
334 : {
335 3754 : if (node == NULL)
336 283 : return NULL;
337 3471 : if (IsA(node, SubLink))
338 : {
339 94 : SubLink *sublink = (SubLink *) node;
340 : JoinExpr *j;
341 : Relids child_rels;
342 :
343 : /* Is it a convertible ANY or EXISTS clause? */
344 94 : if (sublink->subLinkType == ANY_SUBLINK)
345 : {
346 61 : if ((j = convert_ANY_sublink_to_join(root, sublink,
347 : available_rels1)) != NULL)
348 : {
349 : /* Yes; insert the new join node into the join tree */
350 49 : j->larg = *jtlink1;
351 49 : *jtlink1 = (Node *) j;
352 : /* Recursively process pulled-up jointree nodes */
353 49 : j->rarg = pull_up_sublinks_jointree_recurse(root,
354 : j->rarg,
355 : &child_rels);
356 :
357 : /*
358 : * Now recursively process the pulled-up quals. Any inserted
359 : * joins can get stacked onto either j->larg or j->rarg,
360 : * depending on which rels they reference.
361 : */
362 49 : j->quals = pull_up_sublinks_qual_recurse(root,
363 : j->quals,
364 : &j->larg,
365 : available_rels1,
366 : &j->rarg,
367 : child_rels);
368 : /* Return NULL representing constant TRUE */
369 49 : return NULL;
370 : }
371 12 : if (available_rels2 != NULL &&
372 : (j = convert_ANY_sublink_to_join(root, sublink,
373 : available_rels2)) != NULL)
374 : {
375 : /* Yes; insert the new join node into the join tree */
376 0 : j->larg = *jtlink2;
377 0 : *jtlink2 = (Node *) j;
378 : /* Recursively process pulled-up jointree nodes */
379 0 : j->rarg = pull_up_sublinks_jointree_recurse(root,
380 : j->rarg,
381 : &child_rels);
382 :
383 : /*
384 : * Now recursively process the pulled-up quals. Any inserted
385 : * joins can get stacked onto either j->larg or j->rarg,
386 : * depending on which rels they reference.
387 : */
388 0 : j->quals = pull_up_sublinks_qual_recurse(root,
389 : j->quals,
390 : &j->larg,
391 : available_rels2,
392 : &j->rarg,
393 : child_rels);
394 : /* Return NULL representing constant TRUE */
395 0 : return NULL;
396 : }
397 : }
398 33 : else if (sublink->subLinkType == EXISTS_SUBLINK)
399 : {
400 31 : if ((j = convert_EXISTS_sublink_to_join(root, sublink, false,
401 : available_rels1)) != NULL)
402 : {
403 : /* Yes; insert the new join node into the join tree */
404 23 : j->larg = *jtlink1;
405 23 : *jtlink1 = (Node *) j;
406 : /* Recursively process pulled-up jointree nodes */
407 23 : j->rarg = pull_up_sublinks_jointree_recurse(root,
408 : j->rarg,
409 : &child_rels);
410 :
411 : /*
412 : * Now recursively process the pulled-up quals. Any inserted
413 : * joins can get stacked onto either j->larg or j->rarg,
414 : * depending on which rels they reference.
415 : */
416 23 : j->quals = pull_up_sublinks_qual_recurse(root,
417 : j->quals,
418 : &j->larg,
419 : available_rels1,
420 : &j->rarg,
421 : child_rels);
422 : /* Return NULL representing constant TRUE */
423 23 : return NULL;
424 : }
425 8 : if (available_rels2 != NULL &&
426 : (j = convert_EXISTS_sublink_to_join(root, sublink, false,
427 : available_rels2)) != NULL)
428 : {
429 : /* Yes; insert the new join node into the join tree */
430 0 : j->larg = *jtlink2;
431 0 : *jtlink2 = (Node *) j;
432 : /* Recursively process pulled-up jointree nodes */
433 0 : j->rarg = pull_up_sublinks_jointree_recurse(root,
434 : j->rarg,
435 : &child_rels);
436 :
437 : /*
438 : * Now recursively process the pulled-up quals. Any inserted
439 : * joins can get stacked onto either j->larg or j->rarg,
440 : * depending on which rels they reference.
441 : */
442 0 : j->quals = pull_up_sublinks_qual_recurse(root,
443 : j->quals,
444 : &j->larg,
445 : available_rels2,
446 : &j->rarg,
447 : child_rels);
448 : /* Return NULL representing constant TRUE */
449 0 : return NULL;
450 : }
451 : }
452 : /* Else return it unmodified */
453 22 : return node;
454 : }
455 3377 : if (not_clause(node))
456 : {
457 : /* If the immediate argument of NOT is EXISTS, try to convert */
458 469 : SubLink *sublink = (SubLink *) get_notclausearg((Expr *) node);
459 : JoinExpr *j;
460 : Relids child_rels;
461 :
462 469 : if (sublink && IsA(sublink, SubLink))
463 : {
464 204 : if (sublink->subLinkType == EXISTS_SUBLINK)
465 : {
466 197 : if ((j = convert_EXISTS_sublink_to_join(root, sublink, true,
467 : available_rels1)) != NULL)
468 : {
469 : /* Yes; insert the new join node into the join tree */
470 196 : j->larg = *jtlink1;
471 196 : *jtlink1 = (Node *) j;
472 : /* Recursively process pulled-up jointree nodes */
473 196 : j->rarg = pull_up_sublinks_jointree_recurse(root,
474 : j->rarg,
475 : &child_rels);
476 :
477 : /*
478 : * Now recursively process the pulled-up quals. Because
479 : * we are underneath a NOT, we can't pull up sublinks that
480 : * reference the left-hand stuff, but it's still okay to
481 : * pull up sublinks referencing j->rarg.
482 : */
483 196 : j->quals = pull_up_sublinks_qual_recurse(root,
484 : j->quals,
485 : &j->rarg,
486 : child_rels,
487 : NULL, NULL);
488 : /* Return NULL representing constant TRUE */
489 196 : return NULL;
490 : }
491 1 : if (available_rels2 != NULL &&
492 : (j = convert_EXISTS_sublink_to_join(root, sublink, true,
493 : available_rels2)) != NULL)
494 : {
495 : /* Yes; insert the new join node into the join tree */
496 0 : j->larg = *jtlink2;
497 0 : *jtlink2 = (Node *) j;
498 : /* Recursively process pulled-up jointree nodes */
499 0 : j->rarg = pull_up_sublinks_jointree_recurse(root,
500 : j->rarg,
501 : &child_rels);
502 :
503 : /*
504 : * Now recursively process the pulled-up quals. Because
505 : * we are underneath a NOT, we can't pull up sublinks that
506 : * reference the left-hand stuff, but it's still okay to
507 : * pull up sublinks referencing j->rarg.
508 : */
509 0 : j->quals = pull_up_sublinks_qual_recurse(root,
510 : j->quals,
511 : &j->rarg,
512 : child_rels,
513 : NULL, NULL);
514 : /* Return NULL representing constant TRUE */
515 0 : return NULL;
516 : }
517 : }
518 : }
519 : /* Else return it unmodified */
520 273 : return node;
521 : }
522 2908 : if (and_clause(node))
523 : {
524 : /* Recurse into AND clause */
525 642 : List *newclauses = NIL;
526 : ListCell *l;
527 :
528 2374 : foreach(l, ((BoolExpr *) node)->args)
529 : {
530 1732 : Node *oldclause = (Node *) lfirst(l);
531 : Node *newclause;
532 :
533 1732 : newclause = pull_up_sublinks_qual_recurse(root,
534 : oldclause,
535 : jtlink1,
536 : available_rels1,
537 : jtlink2,
538 : available_rels2);
539 1732 : if (newclause)
540 1519 : newclauses = lappend(newclauses, newclause);
541 : }
542 : /* We might have got back fewer clauses than we started with */
543 642 : if (newclauses == NIL)
544 0 : return NULL;
545 642 : else if (list_length(newclauses) == 1)
546 201 : return (Node *) linitial(newclauses);
547 : else
548 441 : return (Node *) make_andclause(newclauses);
549 : }
550 : /* Stop if not an AND */
551 2266 : return node;
552 : }
553 :
554 : /*
555 : * inline_set_returning_functions
556 : * Attempt to "inline" set-returning functions in the FROM clause.
557 : *
558 : * If an RTE_FUNCTION rtable entry invokes a set-returning function that
559 : * contains just a simple SELECT, we can convert the rtable entry to an
560 : * RTE_SUBQUERY entry exposing the SELECT directly. This is especially
561 : * useful if the subquery can then be "pulled up" for further optimization,
562 : * but we do it even if not, to reduce executor overhead.
563 : *
564 : * This has to be done before we have started to do any optimization of
565 : * subqueries, else any such steps wouldn't get applied to subqueries
566 : * obtained via inlining. However, we do it after pull_up_sublinks
567 : * so that we can inline any functions used in SubLink subselects.
568 : *
569 : * Like most of the planner, this feels free to scribble on its input data
570 : * structure.
571 : */
572 : void
573 27181 : inline_set_returning_functions(PlannerInfo *root)
574 : {
575 : ListCell *rt;
576 :
577 55732 : foreach(rt, root->parse->rtable)
578 : {
579 28551 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
580 :
581 28551 : if (rte->rtekind == RTE_FUNCTION)
582 : {
583 : Query *funcquery;
584 :
585 : /* Check safety of expansion, and expand if possible */
586 1335 : funcquery = inline_set_returning_function(root, rte);
587 1335 : if (funcquery)
588 : {
589 : /* Successful expansion, replace the rtable entry */
590 8 : rte->rtekind = RTE_SUBQUERY;
591 8 : rte->subquery = funcquery;
592 8 : rte->functions = NIL;
593 : }
594 : }
595 : }
596 27181 : }
597 :
598 : /*
599 : * pull_up_subqueries
600 : * Look for subqueries in the rangetable that can be pulled up into
601 : * the parent query. If the subquery has no special features like
602 : * grouping/aggregation then we can merge it into the parent's jointree.
603 : * Also, subqueries that are simple UNION ALL structures can be
604 : * converted into "append relations".
605 : */
606 : void
607 27181 : pull_up_subqueries(PlannerInfo *root)
608 : {
609 : /* Top level of jointree must always be a FromExpr */
610 27181 : Assert(IsA(root->parse->jointree, FromExpr));
611 : /* Reset flag saying we need a deletion cleanup pass */
612 27181 : root->hasDeletedRTEs = false;
613 : /* Recursion starts with no containing join nor appendrel */
614 54361 : root->parse->jointree = (FromExpr *)
615 27181 : pull_up_subqueries_recurse(root, (Node *) root->parse->jointree,
616 : NULL, NULL, NULL, false);
617 : /* Apply cleanup phase if necessary */
618 27180 : if (root->hasDeletedRTEs)
619 310 : root->parse->jointree = (FromExpr *)
620 155 : pull_up_subqueries_cleanup((Node *) root->parse->jointree);
621 27180 : Assert(IsA(root->parse->jointree, FromExpr));
622 27180 : }
623 :
624 : /*
625 : * pull_up_subqueries_recurse
626 : * Recursive guts of pull_up_subqueries.
627 : *
628 : * This recursively processes the jointree and returns a modified jointree.
629 : * Or, if it's valid to drop the current node from the jointree completely,
630 : * it returns NULL.
631 : *
632 : * If this jointree node is within either side of an outer join, then
633 : * lowest_outer_join references the lowest such JoinExpr node; otherwise
634 : * it is NULL. We use this to constrain the effects of LATERAL subqueries.
635 : *
636 : * If this jointree node is within the nullable side of an outer join, then
637 : * lowest_nulling_outer_join references the lowest such JoinExpr node;
638 : * otherwise it is NULL. This forces use of the PlaceHolderVar mechanism for
639 : * references to non-nullable targetlist items, but only for references above
640 : * that join.
641 : *
642 : * If we are looking at a member subquery of an append relation,
643 : * containing_appendrel describes that relation; else it is NULL.
644 : * This forces use of the PlaceHolderVar mechanism for all non-Var targetlist
645 : * items, and puts some additional restrictions on what can be pulled up.
646 : *
647 : * deletion_ok is TRUE if the caller can cope with us returning NULL for a
648 : * deletable leaf node (for example, a VALUES RTE that could be pulled up).
649 : * If it's FALSE, we'll avoid pullup in such cases.
650 : *
651 : * A tricky aspect of this code is that if we pull up a subquery we have
652 : * to replace Vars that reference the subquery's outputs throughout the
653 : * parent query, including quals attached to jointree nodes above the one
654 : * we are currently processing! We handle this by being careful not to
655 : * change the jointree structure while recursing: no nodes other than leaf
656 : * RangeTblRef entries and entirely-empty FromExprs will be replaced or
657 : * deleted. Also, we can't turn pullup_replace_vars loose on the whole
658 : * jointree, because it'll return a mutated copy of the tree; we have to
659 : * invoke it just on the quals, instead. This behavior is what makes it
660 : * reasonable to pass lowest_outer_join and lowest_nulling_outer_join as
661 : * pointers rather than some more-indirect way of identifying the lowest
662 : * OJs. Likewise, we don't replace append_rel_list members but only their
663 : * substructure, so the containing_appendrel reference is safe to use.
664 : *
665 : * Because of the rule that no jointree nodes with substructure can be
666 : * replaced, we cannot fully handle the case of deleting nodes from the tree:
667 : * when we delete one child of a JoinExpr, we need to replace the JoinExpr
668 : * with a FromExpr, and that can't happen here. Instead, we set the
669 : * root->hasDeletedRTEs flag, which tells pull_up_subqueries() that an
670 : * additional pass over the tree is needed to clean up.
671 : */
672 : static Node *
673 49917 : pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode,
674 : JoinExpr *lowest_outer_join,
675 : JoinExpr *lowest_nulling_outer_join,
676 : AppendRelInfo *containing_appendrel,
677 : bool deletion_ok)
678 : {
679 49917 : Assert(jtnode != NULL);
680 49917 : if (IsA(jtnode, RangeTblRef))
681 : {
682 19830 : int varno = ((RangeTblRef *) jtnode)->rtindex;
683 19830 : RangeTblEntry *rte = rt_fetch(varno, root->parse->rtable);
684 :
685 : /*
686 : * Is this a subquery RTE, and if so, is the subquery simple enough to
687 : * pull up?
688 : *
689 : * If we are looking at an append-relation member, we can't pull it up
690 : * unless is_safe_append_member says so.
691 : */
692 22431 : if (rte->rtekind == RTE_SUBQUERY &&
693 2601 : is_simple_subquery(rte->subquery, rte,
694 2129 : lowest_outer_join, deletion_ok) &&
695 517 : (containing_appendrel == NULL ||
696 517 : is_safe_append_member(rte->subquery)))
697 1754 : return pull_up_simple_subquery(root, jtnode, rte,
698 : lowest_outer_join,
699 : lowest_nulling_outer_join,
700 : containing_appendrel,
701 : deletion_ok);
702 :
703 : /*
704 : * Alternatively, is it a simple UNION ALL subquery? If so, flatten
705 : * into an "append relation".
706 : *
707 : * It's safe to do this regardless of whether this query is itself an
708 : * appendrel member. (If you're thinking we should try to flatten the
709 : * two levels of appendrel together, you're right; but we handle that
710 : * in set_append_rel_pathlist, not here.)
711 : */
712 18923 : if (rte->rtekind == RTE_SUBQUERY &&
713 847 : is_simple_union_all(rte->subquery))
714 69 : return pull_up_simple_union_all(root, jtnode, rte);
715 :
716 : /*
717 : * Or perhaps it's a simple VALUES RTE?
718 : *
719 : * We don't allow VALUES pullup below an outer join nor into an
720 : * appendrel (such cases are impossible anyway at the moment).
721 : */
722 18007 : if (rte->rtekind == RTE_VALUES &&
723 539 : lowest_outer_join == NULL &&
724 539 : containing_appendrel == NULL &&
725 539 : is_simple_values(root, rte, deletion_ok))
726 74 : return pull_up_simple_values(root, jtnode, rte);
727 :
728 : /* Otherwise, do nothing at this node. */
729 : }
730 30087 : else if (IsA(jtnode, FromExpr))
731 : {
732 27442 : FromExpr *f = (FromExpr *) jtnode;
733 27442 : bool have_undeleted_child = false;
734 : ListCell *l;
735 :
736 27442 : Assert(containing_appendrel == NULL);
737 :
738 : /*
739 : * If the FromExpr has quals, it's not deletable even if its parent
740 : * would allow deletion.
741 : */
742 27442 : if (f->quals)
743 8818 : deletion_ok = false;
744 :
745 44318 : foreach(l, f->fromlist)
746 : {
747 : /*
748 : * In a non-deletable FromExpr, we can allow deletion of child
749 : * nodes so long as at least one child remains; so it's okay
750 : * either if any previous child survives, or if there's more to
751 : * come. If all children are deletable in themselves, we'll force
752 : * the last one to remain unflattened.
753 : *
754 : * As a separate matter, we can allow deletion of all children of
755 : * the top-level FromExpr in a query, since that's a special case
756 : * anyway.
757 : */
758 33754 : bool sub_deletion_ok = (deletion_ok ||
759 15406 : have_undeleted_child ||
760 46382 : lnext(l) != NULL ||
761 14099 : f == root->parse->jointree);
762 :
763 16877 : lfirst(l) = pull_up_subqueries_recurse(root, lfirst(l),
764 : lowest_outer_join,
765 : lowest_nulling_outer_join,
766 : NULL,
767 : sub_deletion_ok);
768 16876 : if (lfirst(l) != NULL)
769 16722 : have_undeleted_child = true;
770 : }
771 :
772 27441 : if (deletion_ok && !have_undeleted_child)
773 : {
774 : /* OK to delete this FromExpr entirely */
775 0 : root->hasDeletedRTEs = true; /* probably is set already */
776 0 : return NULL;
777 : }
778 : }
779 2645 : else if (IsA(jtnode, JoinExpr))
780 : {
781 2645 : JoinExpr *j = (JoinExpr *) jtnode;
782 :
783 2645 : Assert(containing_appendrel == NULL);
784 : /* Recurse, being careful to tell myself when inside outer join */
785 2645 : switch (j->jointype)
786 : {
787 : case JOIN_INNER:
788 :
789 : /*
790 : * INNER JOIN can allow deletion of either child node, but not
791 : * both. So right child gets permission to delete only if
792 : * left child didn't get removed.
793 : */
794 1054 : j->larg = pull_up_subqueries_recurse(root, j->larg,
795 : lowest_outer_join,
796 : lowest_nulling_outer_join,
797 : NULL,
798 : true);
799 1054 : j->rarg = pull_up_subqueries_recurse(root, j->rarg,
800 : lowest_outer_join,
801 : lowest_nulling_outer_join,
802 : NULL,
803 1054 : j->larg != NULL);
804 1054 : break;
805 : case JOIN_LEFT:
806 : case JOIN_SEMI:
807 : case JOIN_ANTI:
808 1546 : j->larg = pull_up_subqueries_recurse(root, j->larg,
809 : j,
810 : lowest_nulling_outer_join,
811 : NULL,
812 : false);
813 1546 : j->rarg = pull_up_subqueries_recurse(root, j->rarg,
814 : j,
815 : j,
816 : NULL,
817 : false);
818 1546 : break;
819 : case JOIN_FULL:
820 28 : j->larg = pull_up_subqueries_recurse(root, j->larg,
821 : j,
822 : j,
823 : NULL,
824 : false);
825 28 : j->rarg = pull_up_subqueries_recurse(root, j->rarg,
826 : j,
827 : j,
828 : NULL,
829 : false);
830 28 : break;
831 : case JOIN_RIGHT:
832 17 : j->larg = pull_up_subqueries_recurse(root, j->larg,
833 : j,
834 : j,
835 : NULL,
836 : false);
837 17 : j->rarg = pull_up_subqueries_recurse(root, j->rarg,
838 : j,
839 : lowest_nulling_outer_join,
840 : NULL,
841 : false);
842 17 : break;
843 : default:
844 0 : elog(ERROR, "unrecognized join type: %d",
845 : (int) j->jointype);
846 : break;
847 : }
848 : }
849 : else
850 0 : elog(ERROR, "unrecognized node type: %d",
851 : (int) nodeTag(jtnode));
852 48019 : return jtnode;
853 : }
854 :
855 : /*
856 : * pull_up_simple_subquery
857 : * Attempt to pull up a single simple subquery.
858 : *
859 : * jtnode is a RangeTblRef that has been tentatively identified as a simple
860 : * subquery by pull_up_subqueries. We return the replacement jointree node,
861 : * or NULL if the subquery can be deleted entirely, or jtnode itself if we
862 : * determine that the subquery can't be pulled up after all.
863 : *
864 : * rte is the RangeTblEntry referenced by jtnode. Remaining parameters are
865 : * as for pull_up_subqueries_recurse.
866 : */
867 : static Node *
868 1754 : pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
869 : JoinExpr *lowest_outer_join,
870 : JoinExpr *lowest_nulling_outer_join,
871 : AppendRelInfo *containing_appendrel,
872 : bool deletion_ok)
873 : {
874 1754 : Query *parse = root->parse;
875 1754 : int varno = ((RangeTblRef *) jtnode)->rtindex;
876 : Query *subquery;
877 : PlannerInfo *subroot;
878 : int rtoffset;
879 : pullup_replace_vars_context rvcontext;
880 : ListCell *lc;
881 :
882 : /*
883 : * Need a modifiable copy of the subquery to hack on. Even if we didn't
884 : * sometimes choose not to pull up below, we must do this to avoid
885 : * problems if the same subquery is referenced from multiple jointree
886 : * items (which can't happen normally, but might after rule rewriting).
887 : */
888 1754 : subquery = copyObject(rte->subquery);
889 :
890 : /*
891 : * Create a PlannerInfo data structure for this subquery.
892 : *
893 : * NOTE: the next few steps should match the first processing in
894 : * subquery_planner(). Can we refactor to avoid code duplication, or
895 : * would that just make things uglier?
896 : */
897 1754 : subroot = makeNode(PlannerInfo);
898 1754 : subroot->parse = subquery;
899 1754 : subroot->glob = root->glob;
900 1754 : subroot->query_level = root->query_level;
901 1754 : subroot->parent_root = root->parent_root;
902 1754 : subroot->plan_params = NIL;
903 1754 : subroot->outer_params = NULL;
904 1754 : subroot->planner_cxt = CurrentMemoryContext;
905 1754 : subroot->init_plans = NIL;
906 1754 : subroot->cte_plan_ids = NIL;
907 1754 : subroot->multiexpr_params = NIL;
908 1754 : subroot->eq_classes = NIL;
909 1754 : subroot->append_rel_list = NIL;
910 1754 : subroot->rowMarks = NIL;
911 1754 : memset(subroot->upper_rels, 0, sizeof(subroot->upper_rels));
912 1754 : memset(subroot->upper_targets, 0, sizeof(subroot->upper_targets));
913 1754 : subroot->processed_tlist = NIL;
914 1754 : subroot->grouping_map = NULL;
915 1754 : subroot->minmax_aggs = NIL;
916 1754 : subroot->qual_security_level = 0;
917 1754 : subroot->hasInheritedTarget = false;
918 1754 : subroot->hasRecursion = false;
919 1754 : subroot->wt_param_id = -1;
920 1754 : subroot->non_recursive_path = NULL;
921 :
922 : /* No CTEs to worry about */
923 1754 : Assert(subquery->cteList == NIL);
924 :
925 : /*
926 : * Pull up any SubLinks within the subquery's quals, so that we don't
927 : * leave unoptimized SubLinks behind.
928 : */
929 1754 : if (subquery->hasSubLinks)
930 87 : pull_up_sublinks(subroot);
931 :
932 : /*
933 : * Similarly, inline any set-returning functions in its rangetable.
934 : */
935 1754 : inline_set_returning_functions(subroot);
936 :
937 : /*
938 : * Recursively pull up the subquery's subqueries, so that
939 : * pull_up_subqueries' processing is complete for its jointree and
940 : * rangetable.
941 : *
942 : * Note: it's okay that the subquery's recursion starts with NULL for
943 : * containing-join info, even if we are within an outer join in the upper
944 : * query; the lower query starts with a clean slate for outer-join
945 : * semantics. Likewise, we needn't pass down appendrel state.
946 : */
947 1754 : pull_up_subqueries(subroot);
948 :
949 : /*
950 : * Now we must recheck whether the subquery is still simple enough to pull
951 : * up. If not, abandon processing it.
952 : *
953 : * We don't really need to recheck all the conditions involved, but it's
954 : * easier just to keep this "if" looking the same as the one in
955 : * pull_up_subqueries_recurse.
956 : */
957 3499 : if (is_simple_subquery(subquery, rte,
958 1745 : lowest_outer_join, deletion_ok) &&
959 137 : (containing_appendrel == NULL || is_safe_append_member(subquery)))
960 : {
961 : /* good to go */
962 : }
963 : else
964 : {
965 : /*
966 : * Give up, return unmodified RangeTblRef.
967 : *
968 : * Note: The work we just did will be redone when the subquery gets
969 : * planned on its own. Perhaps we could avoid that by storing the
970 : * modified subquery back into the rangetable, but I'm not gonna risk
971 : * it now.
972 : */
973 9 : return jtnode;
974 : }
975 :
976 : /*
977 : * We must flatten any join alias Vars in the subquery's targetlist,
978 : * because pulling up the subquery's subqueries might have changed their
979 : * expansions into arbitrary expressions, which could affect
980 : * pullup_replace_vars' decisions about whether PlaceHolderVar wrappers
981 : * are needed for tlist entries. (Likely it'd be better to do
982 : * flatten_join_alias_vars on the whole query tree at some earlier stage,
983 : * maybe even in the rewriter; but for now let's just fix this case here.)
984 : */
985 1745 : subquery->targetList = (List *)
986 1745 : flatten_join_alias_vars(subroot, (Node *) subquery->targetList);
987 :
988 : /*
989 : * Adjust level-0 varnos in subquery so that we can append its rangetable
990 : * to upper query's. We have to fix the subquery's append_rel_list as
991 : * well.
992 : */
993 1745 : rtoffset = list_length(parse->rtable);
994 1745 : OffsetVarNodes((Node *) subquery, rtoffset, 0);
995 1745 : OffsetVarNodes((Node *) subroot->append_rel_list, rtoffset, 0);
996 :
997 : /*
998 : * Upper-level vars in subquery are now one level closer to their parent
999 : * than before.
1000 : */
1001 1745 : IncrementVarSublevelsUp((Node *) subquery, -1, 1);
1002 1745 : IncrementVarSublevelsUp((Node *) subroot->append_rel_list, -1, 1);
1003 :
1004 : /*
1005 : * The subquery's targetlist items are now in the appropriate form to
1006 : * insert into the top query, but if we are under an outer join then
1007 : * non-nullable items and lateral references may have to be turned into
1008 : * PlaceHolderVars. If we are dealing with an appendrel member then
1009 : * anything that's not a simple Var has to be turned into a
1010 : * PlaceHolderVar. Set up required context data for pullup_replace_vars.
1011 : */
1012 1745 : rvcontext.root = root;
1013 1745 : rvcontext.targetlist = subquery->targetList;
1014 1745 : rvcontext.target_rte = rte;
1015 1745 : if (rte->lateral)
1016 49 : rvcontext.relids = get_relids_in_jointree((Node *) subquery->jointree,
1017 : true);
1018 : else /* won't need relids */
1019 1696 : rvcontext.relids = NULL;
1020 1745 : rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
1021 1745 : rvcontext.varno = varno;
1022 1745 : rvcontext.need_phvs = (lowest_nulling_outer_join != NULL ||
1023 : containing_appendrel != NULL);
1024 1745 : rvcontext.wrap_non_vars = (containing_appendrel != NULL);
1025 : /* initialize cache array with indexes 0 .. length(tlist) */
1026 1745 : rvcontext.rv_cache = palloc0((list_length(subquery->targetList) + 1) *
1027 : sizeof(Node *));
1028 :
1029 : /*
1030 : * Replace all of the top query's references to the subquery's outputs
1031 : * with copies of the adjusted subtlist items, being careful not to
1032 : * replace any of the jointree structure. (This'd be a lot cleaner if we
1033 : * could use query_tree_mutator.) We have to use PHVs in the targetList,
1034 : * returningList, and havingQual, since those are certainly above any
1035 : * outer join. replace_vars_in_jointree tracks its location in the
1036 : * jointree and uses PHVs or not appropriately.
1037 : */
1038 1745 : parse->targetList = (List *)
1039 1745 : pullup_replace_vars((Node *) parse->targetList, &rvcontext);
1040 1745 : parse->returningList = (List *)
1041 1745 : pullup_replace_vars((Node *) parse->returningList, &rvcontext);
1042 1745 : if (parse->onConflict)
1043 : {
1044 6 : parse->onConflict->onConflictSet = (List *)
1045 3 : pullup_replace_vars((Node *) parse->onConflict->onConflictSet,
1046 : &rvcontext);
1047 6 : parse->onConflict->onConflictWhere =
1048 3 : pullup_replace_vars(parse->onConflict->onConflictWhere,
1049 : &rvcontext);
1050 :
1051 : /*
1052 : * We assume ON CONFLICT's arbiterElems, arbiterWhere, exclRelTlist
1053 : * can't contain any references to a subquery
1054 : */
1055 : }
1056 1745 : replace_vars_in_jointree((Node *) parse->jointree, &rvcontext,
1057 : lowest_nulling_outer_join);
1058 1744 : Assert(parse->setOperations == NULL);
1059 1744 : parse->havingQual = pullup_replace_vars(parse->havingQual, &rvcontext);
1060 :
1061 : /*
1062 : * Replace references in the translated_vars lists of appendrels. When
1063 : * pulling up an appendrel member, we do not need PHVs in the list of the
1064 : * parent appendrel --- there isn't any outer join between. Elsewhere, use
1065 : * PHVs for safety. (This analysis could be made tighter but it seems
1066 : * unlikely to be worth much trouble.)
1067 : */
1068 1986 : foreach(lc, root->append_rel_list)
1069 : {
1070 242 : AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
1071 242 : bool save_need_phvs = rvcontext.need_phvs;
1072 :
1073 242 : if (appinfo == containing_appendrel)
1074 137 : rvcontext.need_phvs = false;
1075 242 : appinfo->translated_vars = (List *)
1076 242 : pullup_replace_vars((Node *) appinfo->translated_vars, &rvcontext);
1077 242 : rvcontext.need_phvs = save_need_phvs;
1078 : }
1079 :
1080 : /*
1081 : * Replace references in the joinaliasvars lists of join RTEs.
1082 : *
1083 : * You might think that we could avoid using PHVs for alias vars of joins
1084 : * below lowest_nulling_outer_join, but that doesn't work because the
1085 : * alias vars could be referenced above that join; we need the PHVs to be
1086 : * present in such references after the alias vars get flattened. (It
1087 : * might be worth trying to be smarter here, someday.)
1088 : */
1089 5861 : foreach(lc, parse->rtable)
1090 : {
1091 4117 : RangeTblEntry *otherrte = (RangeTblEntry *) lfirst(lc);
1092 :
1093 4117 : if (otherrte->rtekind == RTE_JOIN)
1094 383 : otherrte->joinaliasvars = (List *)
1095 383 : pullup_replace_vars((Node *) otherrte->joinaliasvars,
1096 : &rvcontext);
1097 : }
1098 :
1099 : /*
1100 : * If the subquery had a LATERAL marker, propagate that to any of its
1101 : * child RTEs that could possibly now contain lateral cross-references.
1102 : * The children might or might not contain any actual lateral
1103 : * cross-references, but we have to mark the pulled-up child RTEs so that
1104 : * later planner stages will check for such.
1105 : */
1106 1744 : if (rte->lateral)
1107 : {
1108 101 : foreach(lc, subquery->rtable)
1109 : {
1110 52 : RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(lc);
1111 :
1112 52 : switch (child_rte->rtekind)
1113 : {
1114 : case RTE_RELATION:
1115 32 : if (child_rte->tablesample)
1116 3 : child_rte->lateral = true;
1117 32 : break;
1118 : case RTE_SUBQUERY:
1119 : case RTE_FUNCTION:
1120 : case RTE_VALUES:
1121 : case RTE_TABLEFUNC:
1122 18 : child_rte->lateral = true;
1123 18 : break;
1124 : case RTE_JOIN:
1125 : case RTE_CTE:
1126 : case RTE_NAMEDTUPLESTORE:
1127 : /* these can't contain any lateral references */
1128 2 : break;
1129 : }
1130 : }
1131 : }
1132 :
1133 : /*
1134 : * Now append the adjusted rtable entries to upper query. (We hold off
1135 : * until after fixing the upper rtable entries; no point in running that
1136 : * code on the subquery ones too.)
1137 : */
1138 1744 : parse->rtable = list_concat(parse->rtable, subquery->rtable);
1139 :
1140 : /*
1141 : * Pull up any FOR UPDATE/SHARE markers, too. (OffsetVarNodes already
1142 : * adjusted the marker rtindexes, so just concat the lists.)
1143 : */
1144 1744 : parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks);
1145 :
1146 : /*
1147 : * We also have to fix the relid sets of any PlaceHolderVar nodes in the
1148 : * parent query. (This could perhaps be done by pullup_replace_vars(),
1149 : * but it seems cleaner to use two passes.) Note in particular that any
1150 : * PlaceHolderVar nodes just created by pullup_replace_vars() will be
1151 : * adjusted, so having created them with the subquery's varno is correct.
1152 : *
1153 : * Likewise, relids appearing in AppendRelInfo nodes have to be fixed. We
1154 : * already checked that this won't require introducing multiple subrelids
1155 : * into the single-slot AppendRelInfo structs.
1156 : */
1157 3245 : if (parse->hasSubLinks || root->glob->lastPHId != 0 ||
1158 1501 : root->append_rel_list)
1159 : {
1160 : Relids subrelids;
1161 :
1162 378 : subrelids = get_relids_in_jointree((Node *) subquery->jointree, false);
1163 378 : substitute_multiple_relids((Node *) parse, varno, subrelids);
1164 378 : fix_append_rel_relids(root->append_rel_list, varno, subrelids);
1165 : }
1166 :
1167 : /*
1168 : * And now add subquery's AppendRelInfos to our list.
1169 : */
1170 1744 : root->append_rel_list = list_concat(root->append_rel_list,
1171 : subroot->append_rel_list);
1172 :
1173 : /*
1174 : * We don't have to do the equivalent bookkeeping for outer-join info,
1175 : * because that hasn't been set up yet. placeholder_list likewise.
1176 : */
1177 1744 : Assert(root->join_info_list == NIL);
1178 1744 : Assert(subroot->join_info_list == NIL);
1179 1744 : Assert(root->placeholder_list == NIL);
1180 1744 : Assert(subroot->placeholder_list == NIL);
1181 :
1182 : /*
1183 : * Miscellaneous housekeeping.
1184 : *
1185 : * Although replace_rte_variables() faithfully updated parse->hasSubLinks
1186 : * if it copied any SubLinks out of the subquery's targetlist, we still
1187 : * could have SubLinks added to the query in the expressions of FUNCTION
1188 : * and VALUES RTEs copied up from the subquery. So it's necessary to copy
1189 : * subquery->hasSubLinks anyway. Perhaps this can be improved someday.
1190 : */
1191 1744 : parse->hasSubLinks |= subquery->hasSubLinks;
1192 :
1193 : /* If subquery had any RLS conditions, now main query does too */
1194 1744 : parse->hasRowSecurity |= subquery->hasRowSecurity;
1195 :
1196 : /*
1197 : * subquery won't be pulled up if it hasAggs, hasWindowFuncs, or
1198 : * hasTargetSRFs, so no work needed on those flags
1199 : */
1200 :
1201 : /*
1202 : * Return the adjusted subquery jointree to replace the RangeTblRef entry
1203 : * in parent's jointree; or, if we're flattening a subquery with empty
1204 : * FROM list, return NULL to signal deletion of the subquery from the
1205 : * parent jointree (and set hasDeletedRTEs to ensure cleanup later).
1206 : */
1207 1744 : if (subquery->jointree->fromlist == NIL)
1208 : {
1209 84 : Assert(deletion_ok);
1210 84 : Assert(subquery->jointree->quals == NULL);
1211 84 : root->hasDeletedRTEs = true;
1212 84 : return NULL;
1213 : }
1214 :
1215 1660 : return (Node *) subquery->jointree;
1216 : }
1217 :
1218 : /*
1219 : * pull_up_simple_union_all
1220 : * Pull up a single simple UNION ALL subquery.
1221 : *
1222 : * jtnode is a RangeTblRef that has been identified as a simple UNION ALL
1223 : * subquery by pull_up_subqueries. We pull up the leaf subqueries and
1224 : * build an "append relation" for the union set. The result value is just
1225 : * jtnode, since we don't actually need to change the query jointree.
1226 : */
1227 : static Node *
1228 69 : pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
1229 : {
1230 69 : int varno = ((RangeTblRef *) jtnode)->rtindex;
1231 69 : Query *subquery = rte->subquery;
1232 69 : int rtoffset = list_length(root->parse->rtable);
1233 : List *rtable;
1234 :
1235 : /*
1236 : * Make a modifiable copy of the subquery's rtable, so we can adjust
1237 : * upper-level Vars in it. There are no such Vars in the setOperations
1238 : * tree proper, so fixing the rtable should be sufficient.
1239 : */
1240 69 : rtable = copyObject(subquery->rtable);
1241 :
1242 : /*
1243 : * Upper-level vars in subquery are now one level closer to their parent
1244 : * than before. We don't have to worry about offsetting varnos, though,
1245 : * because the UNION leaf queries can't cross-reference each other.
1246 : */
1247 69 : IncrementVarSublevelsUp_rtable(rtable, -1, 1);
1248 :
1249 : /*
1250 : * If the UNION ALL subquery had a LATERAL marker, propagate that to all
1251 : * its children. The individual children might or might not contain any
1252 : * actual lateral cross-references, but we have to mark the pulled-up
1253 : * child RTEs so that later planner stages will check for such.
1254 : */
1255 69 : if (rte->lateral)
1256 : {
1257 : ListCell *rt;
1258 :
1259 15 : foreach(rt, rtable)
1260 : {
1261 10 : RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(rt);
1262 :
1263 10 : Assert(child_rte->rtekind == RTE_SUBQUERY);
1264 10 : child_rte->lateral = true;
1265 : }
1266 : }
1267 :
1268 : /*
1269 : * Append child RTEs to parent rtable.
1270 : */
1271 69 : root->parse->rtable = list_concat(root->parse->rtable, rtable);
1272 :
1273 : /*
1274 : * Recursively scan the subquery's setOperations tree and add
1275 : * AppendRelInfo nodes for leaf subqueries to the parent's
1276 : * append_rel_list. Also apply pull_up_subqueries to the leaf subqueries.
1277 : */
1278 69 : Assert(subquery->setOperations);
1279 69 : pull_up_union_leaf_queries(subquery->setOperations, root, varno, subquery,
1280 : rtoffset);
1281 :
1282 : /*
1283 : * Mark the parent as an append relation.
1284 : */
1285 69 : rte->inh = true;
1286 :
1287 69 : return jtnode;
1288 : }
1289 :
1290 : /*
1291 : * pull_up_union_leaf_queries -- recursive guts of pull_up_simple_union_all
1292 : *
1293 : * Build an AppendRelInfo for each leaf query in the setop tree, and then
1294 : * apply pull_up_subqueries to the leaf query.
1295 : *
1296 : * Note that setOpQuery is the Query containing the setOp node, whose tlist
1297 : * contains references to all the setop output columns. When called from
1298 : * pull_up_simple_union_all, this is *not* the same as root->parse, which is
1299 : * the parent Query we are pulling up into.
1300 : *
1301 : * parentRTindex is the appendrel parent's index in root->parse->rtable.
1302 : *
1303 : * The child RTEs have already been copied to the parent. childRToffset
1304 : * tells us where in the parent's range table they were copied. When called
1305 : * from flatten_simple_union_all, childRToffset is 0 since the child RTEs
1306 : * were already in root->parse->rtable and no RT index adjustment is needed.
1307 : */
1308 : static void
1309 865 : pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex,
1310 : Query *setOpQuery, int childRToffset)
1311 : {
1312 865 : if (IsA(setOp, RangeTblRef))
1313 : {
1314 569 : RangeTblRef *rtr = (RangeTblRef *) setOp;
1315 : int childRTindex;
1316 : AppendRelInfo *appinfo;
1317 :
1318 : /*
1319 : * Calculate the index in the parent's range table
1320 : */
1321 569 : childRTindex = childRToffset + rtr->rtindex;
1322 :
1323 : /*
1324 : * Build a suitable AppendRelInfo, and attach to parent's list.
1325 : */
1326 569 : appinfo = makeNode(AppendRelInfo);
1327 569 : appinfo->parent_relid = parentRTindex;
1328 569 : appinfo->child_relid = childRTindex;
1329 569 : appinfo->parent_reltype = InvalidOid;
1330 569 : appinfo->child_reltype = InvalidOid;
1331 569 : make_setop_translation_list(setOpQuery, childRTindex,
1332 : &appinfo->translated_vars);
1333 569 : appinfo->parent_reloid = InvalidOid;
1334 569 : root->append_rel_list = lappend(root->append_rel_list, appinfo);
1335 :
1336 : /*
1337 : * Recursively apply pull_up_subqueries to the new child RTE. (We
1338 : * must build the AppendRelInfo first, because this will modify it.)
1339 : * Note that we can pass NULL for containing-join info even if we're
1340 : * actually under an outer join, because the child's expressions
1341 : * aren't going to propagate up to the join. Also, we ignore the
1342 : * possibility that pull_up_subqueries_recurse() returns a different
1343 : * jointree node than what we pass it; if it does, the important thing
1344 : * is that it replaced the child relid in the AppendRelInfo node.
1345 : */
1346 569 : rtr = makeNode(RangeTblRef);
1347 569 : rtr->rtindex = childRTindex;
1348 569 : (void) pull_up_subqueries_recurse(root, (Node *) rtr,
1349 : NULL, NULL, appinfo, false);
1350 : }
1351 296 : else if (IsA(setOp, SetOperationStmt))
1352 : {
1353 296 : SetOperationStmt *op = (SetOperationStmt *) setOp;
1354 :
1355 : /* Recurse to reach leaf queries */
1356 296 : pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery,
1357 : childRToffset);
1358 296 : pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery,
1359 : childRToffset);
1360 : }
1361 : else
1362 : {
1363 0 : elog(ERROR, "unrecognized node type: %d",
1364 : (int) nodeTag(setOp));
1365 : }
1366 865 : }
1367 :
1368 : /*
1369 : * make_setop_translation_list
1370 : * Build the list of translations from parent Vars to child Vars for
1371 : * a UNION ALL member. (At this point it's just a simple list of
1372 : * referencing Vars, but if we succeed in pulling up the member
1373 : * subquery, the Vars will get replaced by pulled-up expressions.)
1374 : */
1375 : static void
1376 569 : make_setop_translation_list(Query *query, Index newvarno,
1377 : List **translated_vars)
1378 : {
1379 569 : List *vars = NIL;
1380 : ListCell *l;
1381 :
1382 1469 : foreach(l, query->targetList)
1383 : {
1384 900 : TargetEntry *tle = (TargetEntry *) lfirst(l);
1385 :
1386 900 : if (tle->resjunk)
1387 0 : continue;
1388 :
1389 900 : vars = lappend(vars, makeVarFromTargetEntry(newvarno, tle));
1390 : }
1391 :
1392 569 : *translated_vars = vars;
1393 569 : }
1394 :
1395 : /*
1396 : * is_simple_subquery
1397 : * Check a subquery in the range table to see if it's simple enough
1398 : * to pull up into the parent query.
1399 : *
1400 : * rte is the RTE_SUBQUERY RangeTblEntry that contained the subquery.
1401 : * (Note subquery is not necessarily equal to rte->subquery; it could be a
1402 : * processed copy of that.)
1403 : * lowest_outer_join is the lowest outer join above the subquery, or NULL.
1404 : * deletion_ok is TRUE if it'd be okay to delete the subquery entirely.
1405 : */
1406 : static bool
1407 4355 : is_simple_subquery(Query *subquery, RangeTblEntry *rte,
1408 : JoinExpr *lowest_outer_join,
1409 : bool deletion_ok)
1410 : {
1411 : /*
1412 : * Let's just make sure it's a valid subselect ...
1413 : */
1414 8710 : if (!IsA(subquery, Query) ||
1415 4355 : subquery->commandType != CMD_SELECT)
1416 0 : elog(ERROR, "subquery is bogus");
1417 :
1418 : /*
1419 : * Can't currently pull up a query with setops (unless it's simple UNION
1420 : * ALL, which is handled by a different code path). Maybe after querytree
1421 : * redesign...
1422 : */
1423 4355 : if (subquery->setOperations)
1424 89 : return false;
1425 :
1426 : /*
1427 : * Can't pull up a subquery involving grouping, aggregation, SRFs,
1428 : * sorting, limiting, or WITH. (XXX WITH could possibly be allowed later)
1429 : *
1430 : * We also don't pull up a subquery that has explicit FOR UPDATE/SHARE
1431 : * clauses, because pullup would cause the locking to occur semantically
1432 : * higher than it should. Implicit FOR UPDATE/SHARE is okay because in
1433 : * that case the locking was originally declared in the upper query
1434 : * anyway.
1435 : */
1436 8454 : if (subquery->hasAggs ||
1437 8369 : subquery->hasWindowFuncs ||
1438 8313 : subquery->hasTargetSRFs ||
1439 8256 : subquery->groupClause ||
1440 8248 : subquery->groupingSets ||
1441 8248 : subquery->havingQual ||
1442 8218 : subquery->sortClause ||
1443 8171 : subquery->distinctClause ||
1444 8115 : subquery->limitOffset ||
1445 8042 : subquery->limitCount ||
1446 8008 : subquery->hasForUpdate ||
1447 4004 : subquery->cteList)
1448 268 : return false;
1449 :
1450 : /*
1451 : * Don't pull up if the RTE represents a security-barrier view; we
1452 : * couldn't prevent information leakage once the RTE's Vars are scattered
1453 : * about in the upper query.
1454 : */
1455 3998 : if (rte->security_barrier)
1456 37 : return false;
1457 :
1458 : /*
1459 : * Don't pull up a subquery with an empty jointree, unless it has no quals
1460 : * and deletion_ok is TRUE and we're not underneath an outer join.
1461 : *
1462 : * query_planner() will correctly generate a Result plan for a jointree
1463 : * that's totally empty, but we can't cope with an empty FromExpr
1464 : * appearing lower down in a jointree: we identify join rels via baserelid
1465 : * sets, so we couldn't distinguish a join containing such a FromExpr from
1466 : * one without it. We can only handle such cases if the place where the
1467 : * subquery is linked is a FromExpr or inner JOIN that would still be
1468 : * nonempty after removal of the subquery, so that it's still identifiable
1469 : * via its contained baserelids. Safe contexts are signaled by
1470 : * deletion_ok.
1471 : *
1472 : * But even in a safe context, we must keep the subquery if it has any
1473 : * quals, because it's unclear where to put them in the upper query.
1474 : *
1475 : * Also, we must forbid pullup if such a subquery is underneath an outer
1476 : * join, because then we might need to wrap its output columns with
1477 : * PlaceHolderVars, and the PHVs would then have empty relid sets meaning
1478 : * we couldn't tell where to evaluate them. (This test is separate from
1479 : * the deletion_ok flag for possible future expansion: deletion_ok tells
1480 : * whether the immediate parent site in the jointree could cope, not
1481 : * whether we'd have PHV issues. It's possible this restriction could be
1482 : * fixed by letting the PHVs use the relids of the parent jointree item,
1483 : * but that complication is for another day.)
1484 : *
1485 : * Note that deletion of a subquery is also dependent on the check below
1486 : * that its targetlist contains no set-returning functions. Deletion from
1487 : * a FROM list or inner JOIN is okay only if the subquery must return
1488 : * exactly one row.
1489 : */
1490 4163 : if (subquery->jointree->fromlist == NIL &&
1491 403 : (subquery->jointree->quals != NULL ||
1492 137 : !deletion_ok ||
1493 : lowest_outer_join != NULL))
1494 67 : return false;
1495 :
1496 : /*
1497 : * If the subquery is LATERAL, check for pullup restrictions from that.
1498 : */
1499 3894 : if (rte->lateral)
1500 : {
1501 : bool restricted;
1502 : Relids safe_upper_varnos;
1503 :
1504 : /*
1505 : * The subquery's WHERE and JOIN/ON quals mustn't contain any lateral
1506 : * references to rels outside a higher outer join (including the case
1507 : * where the outer join is within the subquery itself). In such a
1508 : * case, pulling up would result in a situation where we need to
1509 : * postpone quals from below an outer join to above it, which is
1510 : * probably completely wrong and in any case is a complication that
1511 : * doesn't seem worth addressing at the moment.
1512 : */
1513 107 : if (lowest_outer_join != NULL)
1514 : {
1515 32 : restricted = true;
1516 32 : safe_upper_varnos = get_relids_in_jointree((Node *) lowest_outer_join,
1517 : true);
1518 : }
1519 : else
1520 : {
1521 75 : restricted = false;
1522 75 : safe_upper_varnos = NULL; /* doesn't matter */
1523 : }
1524 :
1525 107 : if (jointree_contains_lateral_outer_refs((Node *) subquery->jointree,
1526 : restricted, safe_upper_varnos))
1527 2 : return false;
1528 :
1529 : /*
1530 : * If there's an outer join above the LATERAL subquery, also disallow
1531 : * pullup if the subquery's targetlist has any references to rels
1532 : * outside the outer join, since these might get pulled into quals
1533 : * above the subquery (but in or below the outer join) and then lead
1534 : * to qual-postponement issues similar to the case checked for above.
1535 : * (We wouldn't need to prevent pullup if no such references appear in
1536 : * outer-query quals, but we don't have enough info here to check
1537 : * that. Also, maybe this restriction could be removed if we forced
1538 : * such refs to be wrapped in PlaceHolderVars, even when they're below
1539 : * the nearest outer join? But it's a pretty hokey usage, so not
1540 : * clear this is worth sweating over.)
1541 : */
1542 105 : if (lowest_outer_join != NULL)
1543 : {
1544 32 : Relids lvarnos = pull_varnos_of_level((Node *) subquery->targetList, 1);
1545 :
1546 32 : if (!bms_is_subset(lvarnos, safe_upper_varnos))
1547 2 : return false;
1548 : }
1549 : }
1550 :
1551 : /*
1552 : * Don't pull up a subquery that has any volatile functions in its
1553 : * targetlist. Otherwise we might introduce multiple evaluations of these
1554 : * functions, if they get copied to multiple places in the upper query,
1555 : * leading to surprising results. (Note: the PlaceHolderVar mechanism
1556 : * doesn't quite guarantee single evaluation; else we could pull up anyway
1557 : * and just wrap such items in PlaceHolderVars ...)
1558 : */
1559 3890 : if (contain_volatile_functions((Node *) subquery->targetList))
1560 16 : return false;
1561 :
1562 3874 : return true;
1563 : }
1564 :
1565 : /*
1566 : * pull_up_simple_values
1567 : * Pull up a single simple VALUES RTE.
1568 : *
1569 : * jtnode is a RangeTblRef that has been identified as a simple VALUES RTE
1570 : * by pull_up_subqueries. We always return NULL indicating that the RTE
1571 : * can be deleted entirely (all failure cases should have been detected by
1572 : * is_simple_values()).
1573 : *
1574 : * rte is the RangeTblEntry referenced by jtnode. Because of the limited
1575 : * possible usage of VALUES RTEs, we do not need the remaining parameters
1576 : * of pull_up_subqueries_recurse.
1577 : */
1578 : static Node *
1579 74 : pull_up_simple_values(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
1580 : {
1581 74 : Query *parse = root->parse;
1582 74 : int varno = ((RangeTblRef *) jtnode)->rtindex;
1583 : List *values_list;
1584 : List *tlist;
1585 : AttrNumber attrno;
1586 : pullup_replace_vars_context rvcontext;
1587 : ListCell *lc;
1588 :
1589 74 : Assert(rte->rtekind == RTE_VALUES);
1590 74 : Assert(list_length(rte->values_lists) == 1);
1591 :
1592 : /*
1593 : * Need a modifiable copy of the VALUES list to hack on, just in case it's
1594 : * multiply referenced.
1595 : */
1596 74 : values_list = copyObject(linitial(rte->values_lists));
1597 :
1598 : /*
1599 : * The VALUES RTE can't contain any Vars of level zero, let alone any that
1600 : * are join aliases, so no need to flatten join alias Vars.
1601 : */
1602 74 : Assert(!contain_vars_of_level((Node *) values_list, 0));
1603 :
1604 : /*
1605 : * Set up required context data for pullup_replace_vars. In particular,
1606 : * we have to make the VALUES list look like a subquery targetlist.
1607 : */
1608 74 : tlist = NIL;
1609 74 : attrno = 1;
1610 178 : foreach(lc, values_list)
1611 : {
1612 104 : tlist = lappend(tlist,
1613 104 : makeTargetEntry((Expr *) lfirst(lc),
1614 : attrno,
1615 : NULL,
1616 : false));
1617 104 : attrno++;
1618 : }
1619 74 : rvcontext.root = root;
1620 74 : rvcontext.targetlist = tlist;
1621 74 : rvcontext.target_rte = rte;
1622 74 : rvcontext.relids = NULL;
1623 74 : rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
1624 74 : rvcontext.varno = varno;
1625 74 : rvcontext.need_phvs = false;
1626 74 : rvcontext.wrap_non_vars = false;
1627 : /* initialize cache array with indexes 0 .. length(tlist) */
1628 74 : rvcontext.rv_cache = palloc0((list_length(tlist) + 1) *
1629 : sizeof(Node *));
1630 :
1631 : /*
1632 : * Replace all of the top query's references to the RTE's outputs with
1633 : * copies of the adjusted VALUES expressions, being careful not to replace
1634 : * any of the jointree structure. (This'd be a lot cleaner if we could use
1635 : * query_tree_mutator.) Much of this should be no-ops in the dummy Query
1636 : * that surrounds a VALUES RTE, but it's not enough code to be worth
1637 : * removing.
1638 : */
1639 74 : parse->targetList = (List *)
1640 74 : pullup_replace_vars((Node *) parse->targetList, &rvcontext);
1641 74 : parse->returningList = (List *)
1642 74 : pullup_replace_vars((Node *) parse->returningList, &rvcontext);
1643 74 : if (parse->onConflict)
1644 : {
1645 0 : parse->onConflict->onConflictSet = (List *)
1646 0 : pullup_replace_vars((Node *) parse->onConflict->onConflictSet,
1647 : &rvcontext);
1648 0 : parse->onConflict->onConflictWhere =
1649 0 : pullup_replace_vars(parse->onConflict->onConflictWhere,
1650 : &rvcontext);
1651 :
1652 : /*
1653 : * We assume ON CONFLICT's arbiterElems, arbiterWhere, exclRelTlist
1654 : * can't contain any references to a subquery
1655 : */
1656 : }
1657 74 : replace_vars_in_jointree((Node *) parse->jointree, &rvcontext, NULL);
1658 74 : Assert(parse->setOperations == NULL);
1659 74 : parse->havingQual = pullup_replace_vars(parse->havingQual, &rvcontext);
1660 :
1661 : /*
1662 : * There should be no appendrels to fix, nor any join alias Vars, nor any
1663 : * outer joins and hence no PlaceHolderVars.
1664 : */
1665 74 : Assert(root->append_rel_list == NIL);
1666 74 : Assert(list_length(parse->rtable) == 1);
1667 74 : Assert(root->join_info_list == NIL);
1668 74 : Assert(root->placeholder_list == NIL);
1669 :
1670 : /*
1671 : * Return NULL to signal deletion of the VALUES RTE from the parent
1672 : * jointree (and set hasDeletedRTEs to ensure cleanup later).
1673 : */
1674 74 : root->hasDeletedRTEs = true;
1675 74 : return NULL;
1676 : }
1677 :
1678 : /*
1679 : * is_simple_values
1680 : * Check a VALUES RTE in the range table to see if it's simple enough
1681 : * to pull up into the parent query.
1682 : *
1683 : * rte is the RTE_VALUES RangeTblEntry to check.
1684 : * deletion_ok is TRUE if it'd be okay to delete the VALUES RTE entirely.
1685 : */
1686 : static bool
1687 539 : is_simple_values(PlannerInfo *root, RangeTblEntry *rte, bool deletion_ok)
1688 : {
1689 539 : Assert(rte->rtekind == RTE_VALUES);
1690 :
1691 : /*
1692 : * We can only pull up a VALUES RTE if deletion_ok is TRUE. It's
1693 : * basically the same case as a sub-select with empty FROM list; see
1694 : * comments in is_simple_subquery().
1695 : */
1696 539 : if (!deletion_ok)
1697 0 : return false;
1698 :
1699 : /*
1700 : * Also, there must be exactly one VALUES list, else it's not semantically
1701 : * correct to delete the VALUES RTE.
1702 : */
1703 539 : if (list_length(rte->values_lists) != 1)
1704 465 : return false;
1705 :
1706 : /*
1707 : * Because VALUES can't appear under an outer join (or at least, we won't
1708 : * try to pull it up if it does), we need not worry about LATERAL, nor
1709 : * about validity of PHVs for the VALUES' outputs.
1710 : */
1711 :
1712 : /*
1713 : * Don't pull up a VALUES that contains any set-returning or volatile
1714 : * functions. Again, the considerations here are basically identical to
1715 : * restrictions on a subquery's targetlist.
1716 : */
1717 148 : if (expression_returns_set((Node *) rte->values_lists) ||
1718 74 : contain_volatile_functions((Node *) rte->values_lists))
1719 0 : return false;
1720 :
1721 : /*
1722 : * Do not pull up a VALUES that's not the only RTE in its parent query.
1723 : * This is actually the only case that the parser will generate at the
1724 : * moment, and assuming this is true greatly simplifies
1725 : * pull_up_simple_values().
1726 : */
1727 148 : if (list_length(root->parse->rtable) != 1 ||
1728 74 : rte != (RangeTblEntry *) linitial(root->parse->rtable))
1729 0 : return false;
1730 :
1731 74 : return true;
1732 : }
1733 :
1734 : /*
1735 : * is_simple_union_all
1736 : * Check a subquery to see if it's a simple UNION ALL.
1737 : *
1738 : * We require all the setops to be UNION ALL (no mixing) and there can't be
1739 : * any datatype coercions involved, ie, all the leaf queries must emit the
1740 : * same datatypes.
1741 : */
1742 : static bool
1743 847 : is_simple_union_all(Query *subquery)
1744 : {
1745 : SetOperationStmt *topop;
1746 :
1747 : /* Let's just make sure it's a valid subselect ... */
1748 1694 : if (!IsA(subquery, Query) ||
1749 847 : subquery->commandType != CMD_SELECT)
1750 0 : elog(ERROR, "subquery is bogus");
1751 :
1752 : /* Is it a set-operation query at all? */
1753 847 : topop = castNode(SetOperationStmt, subquery->setOperations);
1754 847 : if (!topop)
1755 758 : return false;
1756 :
1757 : /* Can't handle ORDER BY, LIMIT/OFFSET, locking, or WITH */
1758 175 : if (subquery->sortClause ||
1759 172 : subquery->limitOffset ||
1760 172 : subquery->limitCount ||
1761 172 : subquery->rowMarks ||
1762 86 : subquery->cteList)
1763 4 : return false;
1764 :
1765 : /* Recursively check the tree of set operations */
1766 85 : return is_simple_union_all_recurse((Node *) topop, subquery,
1767 : topop->colTypes);
1768 : }
1769 :
1770 : static bool
1771 983 : is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
1772 : {
1773 983 : if (IsA(setOp, RangeTblRef))
1774 : {
1775 580 : RangeTblRef *rtr = (RangeTblRef *) setOp;
1776 580 : RangeTblEntry *rte = rt_fetch(rtr->rtindex, setOpQuery->rtable);
1777 580 : Query *subquery = rte->subquery;
1778 :
1779 580 : Assert(subquery != NULL);
1780 :
1781 : /* Leaf nodes are OK if they match the toplevel column types */
1782 : /* We don't have to compare typmods or collations here */
1783 580 : return tlist_same_datatypes(subquery->targetList, colTypes, true);
1784 : }
1785 403 : else if (IsA(setOp, SetOperationStmt))
1786 : {
1787 403 : SetOperationStmt *op = (SetOperationStmt *) setOp;
1788 :
1789 : /* Must be UNION ALL */
1790 403 : if (op->op != SETOP_UNION || !op->all)
1791 96 : return false;
1792 :
1793 : /* Recurse to check inputs */
1794 607 : return is_simple_union_all_recurse(op->larg, setOpQuery, colTypes) &&
1795 300 : is_simple_union_all_recurse(op->rarg, setOpQuery, colTypes);
1796 : }
1797 : else
1798 : {
1799 0 : elog(ERROR, "unrecognized node type: %d",
1800 : (int) nodeTag(setOp));
1801 : return false; /* keep compiler quiet */
1802 : }
1803 : }
1804 :
1805 : /*
1806 : * is_safe_append_member
1807 : * Check a subquery that is a leaf of a UNION ALL appendrel to see if it's
1808 : * safe to pull up.
1809 : */
1810 : static bool
1811 654 : is_safe_append_member(Query *subquery)
1812 : {
1813 : FromExpr *jtnode;
1814 :
1815 : /*
1816 : * It's only safe to pull up the child if its jointree contains exactly
1817 : * one RTE, else the AppendRelInfo data structure breaks. The one base RTE
1818 : * could be buried in several levels of FromExpr, however.
1819 : *
1820 : * Also, the child can't have any WHERE quals because there's no place to
1821 : * put them in an appendrel. (This is a bit annoying...) If we didn't
1822 : * need to check this, we'd just test whether get_relids_in_jointree()
1823 : * yields a singleton set, to be more consistent with the coding of
1824 : * fix_append_rel_relids().
1825 : */
1826 654 : jtnode = subquery->jointree;
1827 1587 : while (IsA(jtnode, FromExpr))
1828 : {
1829 654 : if (jtnode->quals != NULL)
1830 375 : return false;
1831 279 : if (list_length(jtnode->fromlist) != 1)
1832 0 : return false;
1833 279 : jtnode = linitial(jtnode->fromlist);
1834 : }
1835 279 : if (!IsA(jtnode, RangeTblRef))
1836 0 : return false;
1837 :
1838 279 : return true;
1839 : }
1840 :
1841 : /*
1842 : * jointree_contains_lateral_outer_refs
1843 : * Check for disallowed lateral references in a jointree's quals
1844 : *
1845 : * If restricted is false, all level-1 Vars are allowed (but we still must
1846 : * search the jointree, since it might contain outer joins below which there
1847 : * will be restrictions). If restricted is true, return TRUE when any qual
1848 : * in the jointree contains level-1 Vars coming from outside the rels listed
1849 : * in safe_upper_varnos.
1850 : */
1851 : static bool
1852 216 : jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted,
1853 : Relids safe_upper_varnos)
1854 : {
1855 216 : if (jtnode == NULL)
1856 0 : return false;
1857 216 : if (IsA(jtnode, RangeTblRef))
1858 97 : return false;
1859 119 : else if (IsA(jtnode, FromExpr))
1860 : {
1861 111 : FromExpr *f = (FromExpr *) jtnode;
1862 : ListCell *l;
1863 :
1864 : /* First, recurse to check child joins */
1865 202 : foreach(l, f->fromlist)
1866 : {
1867 93 : if (jointree_contains_lateral_outer_refs(lfirst(l),
1868 : restricted,
1869 : safe_upper_varnos))
1870 2 : return true;
1871 : }
1872 :
1873 : /* Then check the top-level quals */
1874 143 : if (restricted &&
1875 34 : !bms_is_subset(pull_varnos_of_level(f->quals, 1),
1876 : safe_upper_varnos))
1877 0 : return true;
1878 : }
1879 8 : else if (IsA(jtnode, JoinExpr))
1880 : {
1881 8 : JoinExpr *j = (JoinExpr *) jtnode;
1882 :
1883 : /*
1884 : * If this is an outer join, we mustn't allow any upper lateral
1885 : * references in or below it.
1886 : */
1887 8 : if (j->jointype != JOIN_INNER)
1888 : {
1889 4 : restricted = true;
1890 4 : safe_upper_varnos = NULL;
1891 : }
1892 :
1893 : /* Check the child joins */
1894 8 : if (jointree_contains_lateral_outer_refs(j->larg,
1895 : restricted,
1896 : safe_upper_varnos))
1897 0 : return true;
1898 8 : if (jointree_contains_lateral_outer_refs(j->rarg,
1899 : restricted,
1900 : safe_upper_varnos))
1901 0 : return true;
1902 :
1903 : /* Check the JOIN's qual clauses */
1904 16 : if (restricted &&
1905 8 : !bms_is_subset(pull_varnos_of_level(j->quals, 1),
1906 : safe_upper_varnos))
1907 2 : return true;
1908 : }
1909 : else
1910 0 : elog(ERROR, "unrecognized node type: %d",
1911 : (int) nodeTag(jtnode));
1912 115 : return false;
1913 : }
1914 :
1915 : /*
1916 : * Helper routine for pull_up_subqueries: do pullup_replace_vars on every
1917 : * expression in the jointree, without changing the jointree structure itself.
1918 : * Ugly, but there's no other way...
1919 : *
1920 : * If we are at or below lowest_nulling_outer_join, we can suppress use of
1921 : * PlaceHolderVars wrapped around the replacement expressions.
1922 : */
1923 : static void
1924 4957 : replace_vars_in_jointree(Node *jtnode,
1925 : pullup_replace_vars_context *context,
1926 : JoinExpr *lowest_nulling_outer_join)
1927 : {
1928 4957 : if (jtnode == NULL)
1929 4961 : return;
1930 4952 : if (IsA(jtnode, RangeTblRef))
1931 : {
1932 : /*
1933 : * If the RangeTblRef refers to a LATERAL subquery (that isn't the
1934 : * same subquery we're pulling up), it might contain references to the
1935 : * target subquery, which we must replace. We drive this from the
1936 : * jointree scan, rather than a scan of the rtable, for a couple of
1937 : * reasons: we can avoid processing no-longer-referenced RTEs, and we
1938 : * can use the appropriate setting of need_phvs depending on whether
1939 : * the RTE is above possibly-nulling outer joins or not.
1940 : */
1941 2548 : int varno = ((RangeTblRef *) jtnode)->rtindex;
1942 :
1943 2548 : if (varno != context->varno) /* ignore target subquery itself */
1944 : {
1945 866 : RangeTblEntry *rte = rt_fetch(varno, context->root->parse->rtable);
1946 :
1947 866 : Assert(rte != context->target_rte);
1948 866 : if (rte->lateral)
1949 : {
1950 82 : switch (rte->rtekind)
1951 : {
1952 : case RTE_RELATION:
1953 : /* shouldn't be marked LATERAL unless tablesample */
1954 0 : Assert(rte->tablesample);
1955 0 : rte->tablesample = (TableSampleClause *)
1956 0 : pullup_replace_vars((Node *) rte->tablesample,
1957 : context);
1958 0 : break;
1959 : case RTE_SUBQUERY:
1960 40 : rte->subquery =
1961 40 : pullup_replace_vars_subquery(rte->subquery,
1962 : context);
1963 40 : break;
1964 : case RTE_FUNCTION:
1965 32 : rte->functions = (List *)
1966 32 : pullup_replace_vars((Node *) rte->functions,
1967 : context);
1968 32 : break;
1969 : case RTE_TABLEFUNC:
1970 10 : rte->tablefunc = (TableFunc *)
1971 10 : pullup_replace_vars((Node *) rte->tablefunc,
1972 : context);
1973 10 : break;
1974 : case RTE_VALUES:
1975 0 : rte->values_lists = (List *)
1976 0 : pullup_replace_vars((Node *) rte->values_lists,
1977 : context);
1978 0 : break;
1979 : case RTE_JOIN:
1980 : case RTE_CTE:
1981 : case RTE_NAMEDTUPLESTORE:
1982 : /* these shouldn't be marked LATERAL */
1983 0 : Assert(false);
1984 : break;
1985 : }
1986 : }
1987 : }
1988 : }
1989 2404 : else if (IsA(jtnode, FromExpr))
1990 : {
1991 1966 : FromExpr *f = (FromExpr *) jtnode;
1992 : ListCell *l;
1993 :
1994 4228 : foreach(l, f->fromlist)
1995 2262 : replace_vars_in_jointree(lfirst(l), context,
1996 : lowest_nulling_outer_join);
1997 1966 : f->quals = pullup_replace_vars(f->quals, context);
1998 : }
1999 438 : else if (IsA(jtnode, JoinExpr))
2000 : {
2001 438 : JoinExpr *j = (JoinExpr *) jtnode;
2002 438 : bool save_need_phvs = context->need_phvs;
2003 :
2004 438 : if (j == lowest_nulling_outer_join)
2005 : {
2006 : /* no more PHVs in or below this join */
2007 162 : context->need_phvs = false;
2008 162 : lowest_nulling_outer_join = NULL;
2009 : }
2010 438 : replace_vars_in_jointree(j->larg, context, lowest_nulling_outer_join);
2011 438 : replace_vars_in_jointree(j->rarg, context, lowest_nulling_outer_join);
2012 438 : j->quals = pullup_replace_vars(j->quals, context);
2013 :
2014 : /*
2015 : * We don't bother to update the colvars list, since it won't be used
2016 : * again ...
2017 : */
2018 438 : context->need_phvs = save_need_phvs;
2019 : }
2020 : else
2021 0 : elog(ERROR, "unrecognized node type: %d",
2022 : (int) nodeTag(jtnode));
2023 : }
2024 :
2025 : /*
2026 : * Apply pullup variable replacement throughout an expression tree
2027 : *
2028 : * Returns a modified copy of the tree, so this can't be used where we
2029 : * need to do in-place replacement.
2030 : */
2031 : static Node *
2032 8533 : pullup_replace_vars(Node *expr, pullup_replace_vars_context *context)
2033 : {
2034 8533 : return replace_rte_variables(expr,
2035 : context->varno, 0,
2036 : pullup_replace_vars_callback,
2037 : (void *) context,
2038 : context->outer_hasSubLinks);
2039 : }
2040 :
2041 : static Node *
2042 5792 : pullup_replace_vars_callback(Var *var,
2043 : replace_rte_variables_context *context)
2044 : {
2045 5792 : pullup_replace_vars_context *rcon = (pullup_replace_vars_context *) context->callback_arg;
2046 5792 : int varattno = var->varattno;
2047 : Node *newnode;
2048 :
2049 : /*
2050 : * If PlaceHolderVars are needed, we cache the modified expressions in
2051 : * rcon->rv_cache[]. This is not in hopes of any material speed gain
2052 : * within this function, but to avoid generating identical PHVs with
2053 : * different IDs. That would result in duplicate evaluations at runtime,
2054 : * and possibly prevent optimizations that rely on recognizing different
2055 : * references to the same subquery output as being equal(). So it's worth
2056 : * a bit of extra effort to avoid it.
2057 : */
2058 5792 : if (rcon->need_phvs &&
2059 589 : varattno >= InvalidAttrNumber &&
2060 1178 : varattno <= list_length(rcon->targetlist) &&
2061 589 : rcon->rv_cache[varattno] != NULL)
2062 : {
2063 : /* Just copy the entry and fall through to adjust its varlevelsup */
2064 101 : newnode = copyObject(rcon->rv_cache[varattno]);
2065 : }
2066 5691 : else if (varattno == InvalidAttrNumber)
2067 : {
2068 : /* Must expand whole-tuple reference into RowExpr */
2069 : RowExpr *rowexpr;
2070 : List *colnames;
2071 : List *fields;
2072 61 : bool save_need_phvs = rcon->need_phvs;
2073 61 : int save_sublevelsup = context->sublevels_up;
2074 :
2075 : /*
2076 : * If generating an expansion for a var of a named rowtype (ie, this
2077 : * is a plain relation RTE), then we must include dummy items for
2078 : * dropped columns. If the var is RECORD (ie, this is a JOIN), then
2079 : * omit dropped columns. Either way, attach column names to the
2080 : * RowExpr for use of ruleutils.c.
2081 : *
2082 : * In order to be able to cache the results, we always generate the
2083 : * expansion with varlevelsup = 0, and then adjust if needed.
2084 : */
2085 122 : expandRTE(rcon->target_rte,
2086 61 : var->varno, 0 /* not varlevelsup */ , var->location,
2087 61 : (var->vartype != RECORDOID),
2088 : &colnames, &fields);
2089 : /* Adjust the generated per-field Vars, but don't insert PHVs */
2090 61 : rcon->need_phvs = false;
2091 61 : context->sublevels_up = 0; /* to match the expandRTE output */
2092 61 : fields = (List *) replace_rte_variables_mutator((Node *) fields,
2093 : context);
2094 61 : rcon->need_phvs = save_need_phvs;
2095 61 : context->sublevels_up = save_sublevelsup;
2096 :
2097 61 : rowexpr = makeNode(RowExpr);
2098 61 : rowexpr->args = fields;
2099 61 : rowexpr->row_typeid = var->vartype;
2100 61 : rowexpr->row_format = COERCE_IMPLICIT_CAST;
2101 61 : rowexpr->colnames = colnames;
2102 61 : rowexpr->location = var->location;
2103 61 : newnode = (Node *) rowexpr;
2104 :
2105 : /*
2106 : * Insert PlaceHolderVar if needed. Notice that we are wrapping one
2107 : * PlaceHolderVar around the whole RowExpr, rather than putting one
2108 : * around each element of the row. This is because we need the
2109 : * expression to yield NULL, not ROW(NULL,NULL,...) when it is forced
2110 : * to null by an outer join.
2111 : */
2112 61 : if (rcon->need_phvs)
2113 : {
2114 : /* RowExpr is certainly not strict, so always need PHV */
2115 2 : newnode = (Node *)
2116 2 : make_placeholder_expr(rcon->root,
2117 : (Expr *) newnode,
2118 : bms_make_singleton(rcon->varno));
2119 : /* cache it with the PHV, and with varlevelsup still zero */
2120 2 : rcon->rv_cache[InvalidAttrNumber] = copyObject(newnode);
2121 : }
2122 : }
2123 : else
2124 : {
2125 : /* Normal case referencing one targetlist element */
2126 5630 : TargetEntry *tle = get_tle_by_resno(rcon->targetlist, varattno);
2127 :
2128 5630 : if (tle == NULL) /* shouldn't happen */
2129 0 : elog(ERROR, "could not find attribute %d in subquery targetlist",
2130 : varattno);
2131 :
2132 : /* Make a copy of the tlist item to return */
2133 5630 : newnode = (Node *) copyObject(tle->expr);
2134 :
2135 : /* Insert PlaceHolderVar if needed */
2136 5630 : if (rcon->need_phvs)
2137 : {
2138 : bool wrap;
2139 :
2140 881 : if (newnode && IsA(newnode, Var) &&
2141 395 : ((Var *) newnode)->varlevelsup == 0)
2142 : {
2143 : /*
2144 : * Simple Vars always escape being wrapped, unless they are
2145 : * lateral references to something outside the subquery being
2146 : * pulled up. (Even then, we could omit the PlaceHolderVar if
2147 : * the referenced rel is under the same lowest outer join, but
2148 : * it doesn't seem worth the trouble to check that.)
2149 : */
2150 813 : if (rcon->target_rte->lateral &&
2151 23 : !bms_is_member(((Var *) newnode)->varno, rcon->relids))
2152 2 : wrap = true;
2153 : else
2154 393 : wrap = false;
2155 : }
2156 94 : else if (newnode && IsA(newnode, PlaceHolderVar) &&
2157 3 : ((PlaceHolderVar *) newnode)->phlevelsup == 0)
2158 : {
2159 : /* No need to wrap a PlaceHolderVar with another one, either */
2160 3 : wrap = false;
2161 : }
2162 88 : else if (rcon->wrap_non_vars)
2163 : {
2164 : /* Wrap all non-Vars in a PlaceHolderVar */
2165 0 : wrap = true;
2166 : }
2167 : else
2168 : {
2169 : /*
2170 : * If it contains a Var of the subquery being pulled up, and
2171 : * does not contain any non-strict constructs, then it's
2172 : * certainly nullable so we don't need to insert a
2173 : * PlaceHolderVar.
2174 : *
2175 : * This analysis could be tighter: in particular, a non-strict
2176 : * construct hidden within a lower-level PlaceHolderVar is not
2177 : * reason to add another PHV. But for now it doesn't seem
2178 : * worth the code to be more exact.
2179 : *
2180 : * Note: in future maybe we should insert a PlaceHolderVar
2181 : * anyway, if the tlist item is expensive to evaluate?
2182 : *
2183 : * For a LATERAL subquery, we have to check the actual var
2184 : * membership of the node, but if it's non-lateral then any
2185 : * level-zero var must belong to the subquery.
2186 : */
2187 96 : if ((rcon->target_rte->lateral ?
2188 8 : bms_overlap(pull_varnos((Node *) newnode), rcon->relids) :
2189 111 : contain_vars_of_level((Node *) newnode, 0)) &&
2190 31 : !contain_nonstrict_functions((Node *) newnode))
2191 : {
2192 : /* No wrap needed */
2193 0 : wrap = false;
2194 : }
2195 : else
2196 : {
2197 : /* Else wrap it in a PlaceHolderVar */
2198 88 : wrap = true;
2199 : }
2200 : }
2201 :
2202 486 : if (wrap)
2203 90 : newnode = (Node *)
2204 90 : make_placeholder_expr(rcon->root,
2205 : (Expr *) newnode,
2206 : bms_make_singleton(rcon->varno));
2207 :
2208 : /*
2209 : * Cache it if possible (ie, if the attno is in range, which it
2210 : * probably always should be). We can cache the value even if we
2211 : * decided we didn't need a PHV, since this result will be
2212 : * suitable for any request that has need_phvs.
2213 : */
2214 972 : if (varattno > InvalidAttrNumber &&
2215 486 : varattno <= list_length(rcon->targetlist))
2216 486 : rcon->rv_cache[varattno] = copyObject(newnode);
2217 : }
2218 : }
2219 :
2220 : /* Must adjust varlevelsup if tlist item is from higher query */
2221 5792 : if (var->varlevelsup > 0)
2222 79 : IncrementVarSublevelsUp(newnode, var->varlevelsup, 0);
2223 :
2224 5792 : return newnode;
2225 : }
2226 :
2227 : /*
2228 : * Apply pullup variable replacement to a subquery
2229 : *
2230 : * This needs to be different from pullup_replace_vars() because
2231 : * replace_rte_variables will think that it shouldn't increment sublevels_up
2232 : * before entering the Query; so we need to call it with sublevels_up == 1.
2233 : */
2234 : static Query *
2235 40 : pullup_replace_vars_subquery(Query *query,
2236 : pullup_replace_vars_context *context)
2237 : {
2238 40 : Assert(IsA(query, Query));
2239 40 : return (Query *) replace_rte_variables((Node *) query,
2240 : context->varno, 1,
2241 : pullup_replace_vars_callback,
2242 : (void *) context,
2243 : NULL);
2244 : }
2245 :
2246 : /*
2247 : * pull_up_subqueries_cleanup
2248 : * Recursively fix up jointree after deletion of some subqueries.
2249 : *
2250 : * The jointree now contains some NULL subtrees, which we need to get rid of.
2251 : * In a FromExpr, just rebuild the child-node list with null entries deleted.
2252 : * In an inner JOIN, replace the JoinExpr node with a one-child FromExpr.
2253 : */
2254 : static Node *
2255 203 : pull_up_subqueries_cleanup(Node *jtnode)
2256 : {
2257 203 : Assert(jtnode != NULL);
2258 203 : if (IsA(jtnode, RangeTblRef))
2259 : {
2260 : /* Nothing to do at leaf nodes. */
2261 : }
2262 173 : else if (IsA(jtnode, FromExpr))
2263 : {
2264 163 : FromExpr *f = (FromExpr *) jtnode;
2265 163 : List *newfrom = NIL;
2266 : ListCell *l;
2267 :
2268 349 : foreach(l, f->fromlist)
2269 : {
2270 186 : Node *child = (Node *) lfirst(l);
2271 :
2272 186 : if (child == NULL)
2273 154 : continue;
2274 32 : child = pull_up_subqueries_cleanup(child);
2275 32 : newfrom = lappend(newfrom, child);
2276 : }
2277 163 : f->fromlist = newfrom;
2278 : }
2279 10 : else if (IsA(jtnode, JoinExpr))
2280 : {
2281 10 : JoinExpr *j = (JoinExpr *) jtnode;
2282 :
2283 10 : if (j->larg)
2284 8 : j->larg = pull_up_subqueries_cleanup(j->larg);
2285 10 : if (j->rarg)
2286 8 : j->rarg = pull_up_subqueries_cleanup(j->rarg);
2287 10 : if (j->larg == NULL)
2288 : {
2289 2 : Assert(j->jointype == JOIN_INNER);
2290 2 : Assert(j->rarg != NULL);
2291 2 : return (Node *) makeFromExpr(list_make1(j->rarg), j->quals);
2292 : }
2293 8 : else if (j->rarg == NULL)
2294 : {
2295 2 : Assert(j->jointype == JOIN_INNER);
2296 2 : return (Node *) makeFromExpr(list_make1(j->larg), j->quals);
2297 : }
2298 : }
2299 : else
2300 0 : elog(ERROR, "unrecognized node type: %d",
2301 : (int) nodeTag(jtnode));
2302 199 : return jtnode;
2303 : }
2304 :
2305 :
2306 : /*
2307 : * flatten_simple_union_all
2308 : * Try to optimize top-level UNION ALL structure into an appendrel
2309 : *
2310 : * If a query's setOperations tree consists entirely of simple UNION ALL
2311 : * operations, flatten it into an append relation, which we can process more
2312 : * intelligently than the general setops case. Otherwise, do nothing.
2313 : *
2314 : * In most cases, this can succeed only for a top-level query, because for a
2315 : * subquery in FROM, the parent query's invocation of pull_up_subqueries would
2316 : * already have flattened the UNION via pull_up_simple_union_all. But there
2317 : * are a few cases we can support here but not in that code path, for example
2318 : * when the subquery also contains ORDER BY.
2319 : */
2320 : void
2321 331 : flatten_simple_union_all(PlannerInfo *root)
2322 : {
2323 331 : Query *parse = root->parse;
2324 : SetOperationStmt *topop;
2325 : Node *leftmostjtnode;
2326 : int leftmostRTI;
2327 : RangeTblEntry *leftmostRTE;
2328 : int childRTI;
2329 : RangeTblEntry *childRTE;
2330 : RangeTblRef *rtr;
2331 :
2332 : /* Shouldn't be called unless query has setops */
2333 331 : topop = castNode(SetOperationStmt, parse->setOperations);
2334 331 : Assert(topop);
2335 :
2336 : /* Can't optimize away a recursive UNION */
2337 331 : if (root->hasRecursion)
2338 40 : return;
2339 :
2340 : /*
2341 : * Recursively check the tree of set operations. If not all UNION ALL
2342 : * with identical column types, punt.
2343 : */
2344 291 : if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
2345 87 : return;
2346 :
2347 : /*
2348 : * Locate the leftmost leaf query in the setops tree. The upper query's
2349 : * Vars all refer to this RTE (see transformSetOperationStmt).
2350 : */
2351 204 : leftmostjtnode = topop->larg;
2352 419 : while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
2353 11 : leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;
2354 204 : Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
2355 204 : leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
2356 204 : leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
2357 204 : Assert(leftmostRTE->rtekind == RTE_SUBQUERY);
2358 :
2359 : /*
2360 : * Make a copy of the leftmost RTE and add it to the rtable. This copy
2361 : * will represent the leftmost leaf query in its capacity as a member of
2362 : * the appendrel. The original will represent the appendrel as a whole.
2363 : * (We must do things this way because the upper query's Vars have to be
2364 : * seen as referring to the whole appendrel.)
2365 : */
2366 204 : childRTE = copyObject(leftmostRTE);
2367 204 : parse->rtable = lappend(parse->rtable, childRTE);
2368 204 : childRTI = list_length(parse->rtable);
2369 :
2370 : /* Modify the setops tree to reference the child copy */
2371 204 : ((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;
2372 :
2373 : /* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
2374 204 : leftmostRTE->inh = true;
2375 :
2376 : /*
2377 : * Form a RangeTblRef for the appendrel, and insert it into FROM. The top
2378 : * Query of a setops tree should have had an empty FromClause initially.
2379 : */
2380 204 : rtr = makeNode(RangeTblRef);
2381 204 : rtr->rtindex = leftmostRTI;
2382 204 : Assert(parse->jointree->fromlist == NIL);
2383 204 : parse->jointree->fromlist = list_make1(rtr);
2384 :
2385 : /*
2386 : * Now pretend the query has no setops. We must do this before trying to
2387 : * do subquery pullup, because of Assert in pull_up_simple_subquery.
2388 : */
2389 204 : parse->setOperations = NULL;
2390 :
2391 : /*
2392 : * Build AppendRelInfo information, and apply pull_up_subqueries to the
2393 : * leaf queries of the UNION ALL. (We must do that now because they
2394 : * weren't previously referenced by the jointree, and so were missed by
2395 : * the main invocation of pull_up_subqueries.)
2396 : */
2397 204 : pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
2398 : }
2399 :
2400 :
2401 : /*
2402 : * reduce_outer_joins
2403 : * Attempt to reduce outer joins to plain inner joins.
2404 : *
2405 : * The idea here is that given a query like
2406 : * SELECT ... FROM a LEFT JOIN b ON (...) WHERE b.y = 42;
2407 : * we can reduce the LEFT JOIN to a plain JOIN if the "=" operator in WHERE
2408 : * is strict. The strict operator will always return NULL, causing the outer
2409 : * WHERE to fail, on any row where the LEFT JOIN filled in NULLs for b's
2410 : * columns. Therefore, there's no need for the join to produce null-extended
2411 : * rows in the first place --- which makes it a plain join not an outer join.
2412 : * (This scenario may not be very likely in a query written out by hand, but
2413 : * it's reasonably likely when pushing quals down into complex views.)
2414 : *
2415 : * More generally, an outer join can be reduced in strength if there is a
2416 : * strict qual above it in the qual tree that constrains a Var from the
2417 : * nullable side of the join to be non-null. (For FULL joins this applies
2418 : * to each side separately.)
2419 : *
2420 : * Another transformation we apply here is to recognize cases like
2421 : * SELECT ... FROM a LEFT JOIN b ON (a.x = b.y) WHERE b.y IS NULL;
2422 : * If the join clause is strict for b.y, then only null-extended rows could
2423 : * pass the upper WHERE, and we can conclude that what the query is really
2424 : * specifying is an anti-semijoin. We change the join type from JOIN_LEFT
2425 : * to JOIN_ANTI. The IS NULL clause then becomes redundant, and must be
2426 : * removed to prevent bogus selectivity calculations, but we leave it to
2427 : * distribute_qual_to_rels to get rid of such clauses.
2428 : *
2429 : * Also, we get rid of JOIN_RIGHT cases by flipping them around to become
2430 : * JOIN_LEFT. This saves some code here and in some later planner routines,
2431 : * but the main reason to do it is to not need to invent a JOIN_REVERSE_ANTI
2432 : * join type.
2433 : *
2434 : * To ease recognition of strict qual clauses, we require this routine to be
2435 : * run after expression preprocessing (i.e., qual canonicalization and JOIN
2436 : * alias-var expansion).
2437 : */
2438 : void
2439 1126 : reduce_outer_joins(PlannerInfo *root)
2440 : {
2441 : reduce_outer_joins_state *state;
2442 :
2443 : /*
2444 : * To avoid doing strictness checks on more quals than necessary, we want
2445 : * to stop descending the jointree as soon as there are no outer joins
2446 : * below our current point. This consideration forces a two-pass process.
2447 : * The first pass gathers information about which base rels appear below
2448 : * each side of each join clause, and about whether there are outer
2449 : * join(s) below each side of each join clause. The second pass examines
2450 : * qual clauses and changes join types as it descends the tree.
2451 : */
2452 1126 : state = reduce_outer_joins_pass1((Node *) root->parse->jointree);
2453 :
2454 : /* planner.c shouldn't have called me if no outer joins */
2455 1126 : if (state == NULL || !state->contains_outer)
2456 0 : elog(ERROR, "so where are the outer joins?");
2457 :
2458 1126 : reduce_outer_joins_pass2((Node *) root->parse->jointree,
2459 : state, root, NULL, NIL, NIL);
2460 1126 : }
2461 :
2462 : /*
2463 : * reduce_outer_joins_pass1 - phase 1 data collection
2464 : *
2465 : * Returns a state node describing the given jointree node.
2466 : */
2467 : static reduce_outer_joins_state *
2468 6077 : reduce_outer_joins_pass1(Node *jtnode)
2469 : {
2470 : reduce_outer_joins_state *result;
2471 :
2472 6077 : result = (reduce_outer_joins_state *)
2473 : palloc(sizeof(reduce_outer_joins_state));
2474 6077 : result->relids = NULL;
2475 6077 : result->contains_outer = false;
2476 6077 : result->sub_states = NIL;
2477 :
2478 6077 : if (jtnode == NULL)
2479 0 : return result;
2480 6077 : if (IsA(jtnode, RangeTblRef))
2481 : {
2482 2832 : int varno = ((RangeTblRef *) jtnode)->rtindex;
2483 :
2484 2832 : result->relids = bms_make_singleton(varno);
2485 : }
2486 3245 : else if (IsA(jtnode, FromExpr))
2487 : {
2488 1653 : FromExpr *f = (FromExpr *) jtnode;
2489 : ListCell *l;
2490 :
2491 3420 : foreach(l, f->fromlist)
2492 : {
2493 : reduce_outer_joins_state *sub_state;
2494 :
2495 1767 : sub_state = reduce_outer_joins_pass1(lfirst(l));
2496 1767 : result->relids = bms_add_members(result->relids,
2497 1767 : sub_state->relids);
2498 1767 : result->contains_outer |= sub_state->contains_outer;
2499 1767 : result->sub_states = lappend(result->sub_states, sub_state);
2500 : }
2501 : }
2502 1592 : else if (IsA(jtnode, JoinExpr))
2503 : {
2504 1592 : JoinExpr *j = (JoinExpr *) jtnode;
2505 : reduce_outer_joins_state *sub_state;
2506 :
2507 : /* join's own RT index is not wanted in result->relids */
2508 1592 : if (IS_OUTER_JOIN(j->jointype))
2509 1325 : result->contains_outer = true;
2510 :
2511 1592 : sub_state = reduce_outer_joins_pass1(j->larg);
2512 1592 : result->relids = bms_add_members(result->relids,
2513 1592 : sub_state->relids);
2514 1592 : result->contains_outer |= sub_state->contains_outer;
2515 1592 : result->sub_states = lappend(result->sub_states, sub_state);
2516 :
2517 1592 : sub_state = reduce_outer_joins_pass1(j->rarg);
2518 1592 : result->relids = bms_add_members(result->relids,
2519 1592 : sub_state->relids);
2520 1592 : result->contains_outer |= sub_state->contains_outer;
2521 1592 : result->sub_states = lappend(result->sub_states, sub_state);
2522 : }
2523 : else
2524 0 : elog(ERROR, "unrecognized node type: %d",
2525 : (int) nodeTag(jtnode));
2526 6077 : return result;
2527 : }
2528 :
2529 : /*
2530 : * reduce_outer_joins_pass2 - phase 2 processing
2531 : *
2532 : * jtnode: current jointree node
2533 : * state: state data collected by phase 1 for this node
2534 : * root: toplevel planner state
2535 : * nonnullable_rels: set of base relids forced non-null by upper quals
2536 : * nonnullable_vars: list of Vars forced non-null by upper quals
2537 : * forced_null_vars: list of Vars forced null by upper quals
2538 : */
2539 : static void
2540 2924 : reduce_outer_joins_pass2(Node *jtnode,
2541 : reduce_outer_joins_state *state,
2542 : PlannerInfo *root,
2543 : Relids nonnullable_rels,
2544 : List *nonnullable_vars,
2545 : List *forced_null_vars)
2546 : {
2547 : /*
2548 : * pass 2 should never descend as far as an empty subnode or base rel,
2549 : * because it's only called on subtrees marked as contains_outer.
2550 : */
2551 2924 : if (jtnode == NULL)
2552 0 : elog(ERROR, "reached empty jointree");
2553 2924 : if (IsA(jtnode, RangeTblRef))
2554 0 : elog(ERROR, "reached base rel");
2555 2924 : else if (IsA(jtnode, FromExpr))
2556 : {
2557 1518 : FromExpr *f = (FromExpr *) jtnode;
2558 : ListCell *l;
2559 : ListCell *s;
2560 : Relids pass_nonnullable_rels;
2561 : List *pass_nonnullable_vars;
2562 : List *pass_forced_null_vars;
2563 :
2564 : /* Scan quals to see if we can add any constraints */
2565 1518 : pass_nonnullable_rels = find_nonnullable_rels(f->quals);
2566 1518 : pass_nonnullable_rels = bms_add_members(pass_nonnullable_rels,
2567 : nonnullable_rels);
2568 : /* NB: we rely on list_concat to not damage its second argument */
2569 1518 : pass_nonnullable_vars = find_nonnullable_vars(f->quals);
2570 1518 : pass_nonnullable_vars = list_concat(pass_nonnullable_vars,
2571 : nonnullable_vars);
2572 1518 : pass_forced_null_vars = find_forced_null_vars(f->quals);
2573 1518 : pass_forced_null_vars = list_concat(pass_forced_null_vars,
2574 : forced_null_vars);
2575 : /* And recurse --- but only into interesting subtrees */
2576 1518 : Assert(list_length(f->fromlist) == list_length(state->sub_states));
2577 3134 : forboth(l, f->fromlist, s, state->sub_states)
2578 : {
2579 1616 : reduce_outer_joins_state *sub_state = lfirst(s);
2580 :
2581 1616 : if (sub_state->contains_outer)
2582 1523 : reduce_outer_joins_pass2(lfirst(l), sub_state, root,
2583 : pass_nonnullable_rels,
2584 : pass_nonnullable_vars,
2585 : pass_forced_null_vars);
2586 : }
2587 1518 : bms_free(pass_nonnullable_rels);
2588 : /* can't so easily clean up var lists, unfortunately */
2589 : }
2590 1406 : else if (IsA(jtnode, JoinExpr))
2591 : {
2592 1406 : JoinExpr *j = (JoinExpr *) jtnode;
2593 1406 : int rtindex = j->rtindex;
2594 1406 : JoinType jointype = j->jointype;
2595 1406 : reduce_outer_joins_state *left_state = linitial(state->sub_states);
2596 1406 : reduce_outer_joins_state *right_state = lsecond(state->sub_states);
2597 1406 : List *local_nonnullable_vars = NIL;
2598 1406 : bool computed_local_nonnullable_vars = false;
2599 :
2600 : /* Can we simplify this join? */
2601 1406 : switch (jointype)
2602 : {
2603 : case JOIN_INNER:
2604 80 : break;
2605 : case JOIN_LEFT:
2606 1278 : if (bms_overlap(nonnullable_rels, right_state->relids))
2607 71 : jointype = JOIN_INNER;
2608 1278 : break;
2609 : case JOIN_RIGHT:
2610 17 : if (bms_overlap(nonnullable_rels, left_state->relids))
2611 0 : jointype = JOIN_INNER;
2612 17 : break;
2613 : case JOIN_FULL:
2614 28 : if (bms_overlap(nonnullable_rels, left_state->relids))
2615 : {
2616 0 : if (bms_overlap(nonnullable_rels, right_state->relids))
2617 0 : jointype = JOIN_INNER;
2618 : else
2619 0 : jointype = JOIN_LEFT;
2620 : }
2621 : else
2622 : {
2623 28 : if (bms_overlap(nonnullable_rels, right_state->relids))
2624 0 : jointype = JOIN_RIGHT;
2625 : }
2626 28 : break;
2627 : case JOIN_SEMI:
2628 : case JOIN_ANTI:
2629 :
2630 : /*
2631 : * These could only have been introduced by pull_up_sublinks,
2632 : * so there's no way that upper quals could refer to their
2633 : * righthand sides, and no point in checking.
2634 : */
2635 3 : break;
2636 : default:
2637 0 : elog(ERROR, "unrecognized join type: %d",
2638 : (int) jointype);
2639 : break;
2640 : }
2641 :
2642 : /*
2643 : * Convert JOIN_RIGHT to JOIN_LEFT. Note that in the case where we
2644 : * reduced JOIN_FULL to JOIN_RIGHT, this will mean the JoinExpr no
2645 : * longer matches the internal ordering of any CoalesceExpr's built to
2646 : * represent merged join variables. We don't care about that at
2647 : * present, but be wary of it ...
2648 : */
2649 1406 : if (jointype == JOIN_RIGHT)
2650 : {
2651 : Node *tmparg;
2652 :
2653 17 : tmparg = j->larg;
2654 17 : j->larg = j->rarg;
2655 17 : j->rarg = tmparg;
2656 17 : jointype = JOIN_LEFT;
2657 17 : right_state = linitial(state->sub_states);
2658 17 : left_state = lsecond(state->sub_states);
2659 : }
2660 :
2661 : /*
2662 : * See if we can reduce JOIN_LEFT to JOIN_ANTI. This is the case if
2663 : * the join's own quals are strict for any var that was forced null by
2664 : * higher qual levels. NOTE: there are other ways that we could
2665 : * detect an anti-join, in particular if we were to check whether Vars
2666 : * coming from the RHS must be non-null because of table constraints.
2667 : * That seems complicated and expensive though (in particular, one
2668 : * would have to be wary of lower outer joins). For the moment this
2669 : * seems sufficient.
2670 : */
2671 1406 : if (jointype == JOIN_LEFT)
2672 : {
2673 : List *overlap;
2674 :
2675 1224 : local_nonnullable_vars = find_nonnullable_vars(j->quals);
2676 1224 : computed_local_nonnullable_vars = true;
2677 :
2678 : /*
2679 : * It's not sufficient to check whether local_nonnullable_vars and
2680 : * forced_null_vars overlap: we need to know if the overlap
2681 : * includes any RHS variables.
2682 : */
2683 1224 : overlap = list_intersection(local_nonnullable_vars,
2684 : forced_null_vars);
2685 1258 : if (overlap != NIL &&
2686 34 : bms_overlap(pull_varnos((Node *) overlap),
2687 34 : right_state->relids))
2688 34 : jointype = JOIN_ANTI;
2689 : }
2690 :
2691 : /* Apply the jointype change, if any, to both jointree node and RTE */
2692 1406 : if (rtindex && jointype != j->jointype)
2693 : {
2694 122 : RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable);
2695 :
2696 122 : Assert(rte->rtekind == RTE_JOIN);
2697 122 : Assert(rte->jointype == j->jointype);
2698 122 : rte->jointype = jointype;
2699 : }
2700 1406 : j->jointype = jointype;
2701 :
2702 : /* Only recurse if there's more to do below here */
2703 1406 : if (left_state->contains_outer || right_state->contains_outer)
2704 : {
2705 : Relids local_nonnullable_rels;
2706 : List *local_forced_null_vars;
2707 : Relids pass_nonnullable_rels;
2708 : List *pass_nonnullable_vars;
2709 : List *pass_forced_null_vars;
2710 :
2711 : /*
2712 : * If this join is (now) inner, we can add any constraints its
2713 : * quals provide to those we got from above. But if it is outer,
2714 : * we can pass down the local constraints only into the nullable
2715 : * side, because an outer join never eliminates any rows from its
2716 : * non-nullable side. Also, there is no point in passing upper
2717 : * constraints into the nullable side, since if there were any
2718 : * we'd have been able to reduce the join. (In the case of upper
2719 : * forced-null constraints, we *must not* pass them into the
2720 : * nullable side --- they either applied here, or not.) The upshot
2721 : * is that we pass either the local or the upper constraints,
2722 : * never both, to the children of an outer join.
2723 : *
2724 : * Note that a SEMI join works like an inner join here: it's okay
2725 : * to pass down both local and upper constraints. (There can't be
2726 : * any upper constraints affecting its inner side, but it's not
2727 : * worth having a separate code path to avoid passing them.)
2728 : *
2729 : * At a FULL join we just punt and pass nothing down --- is it
2730 : * possible to be smarter?
2731 : */
2732 274 : if (jointype != JOIN_FULL)
2733 : {
2734 270 : local_nonnullable_rels = find_nonnullable_rels(j->quals);
2735 270 : if (!computed_local_nonnullable_vars)
2736 108 : local_nonnullable_vars = find_nonnullable_vars(j->quals);
2737 270 : local_forced_null_vars = find_forced_null_vars(j->quals);
2738 270 : if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
2739 : {
2740 : /* OK to merge upper and local constraints */
2741 106 : local_nonnullable_rels = bms_add_members(local_nonnullable_rels,
2742 : nonnullable_rels);
2743 106 : local_nonnullable_vars = list_concat(local_nonnullable_vars,
2744 : nonnullable_vars);
2745 106 : local_forced_null_vars = list_concat(local_forced_null_vars,
2746 : forced_null_vars);
2747 : }
2748 : }
2749 : else
2750 : {
2751 : /* no use in calculating these */
2752 4 : local_nonnullable_rels = NULL;
2753 4 : local_forced_null_vars = NIL;
2754 : }
2755 :
2756 274 : if (left_state->contains_outer)
2757 : {
2758 209 : if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
2759 : {
2760 : /* pass union of local and upper constraints */
2761 84 : pass_nonnullable_rels = local_nonnullable_rels;
2762 84 : pass_nonnullable_vars = local_nonnullable_vars;
2763 84 : pass_forced_null_vars = local_forced_null_vars;
2764 : }
2765 125 : else if (jointype != JOIN_FULL) /* ie, LEFT or ANTI */
2766 : {
2767 : /* can't pass local constraints to non-nullable side */
2768 123 : pass_nonnullable_rels = nonnullable_rels;
2769 123 : pass_nonnullable_vars = nonnullable_vars;
2770 123 : pass_forced_null_vars = forced_null_vars;
2771 : }
2772 : else
2773 : {
2774 : /* no constraints pass through JOIN_FULL */
2775 2 : pass_nonnullable_rels = NULL;
2776 2 : pass_nonnullable_vars = NIL;
2777 2 : pass_forced_null_vars = NIL;
2778 : }
2779 209 : reduce_outer_joins_pass2(j->larg, left_state, root,
2780 : pass_nonnullable_rels,
2781 : pass_nonnullable_vars,
2782 : pass_forced_null_vars);
2783 : }
2784 :
2785 274 : if (right_state->contains_outer)
2786 : {
2787 66 : if (jointype != JOIN_FULL) /* ie, INNER/LEFT/SEMI/ANTI */
2788 : {
2789 : /* pass appropriate constraints, per comment above */
2790 64 : pass_nonnullable_rels = local_nonnullable_rels;
2791 64 : pass_nonnullable_vars = local_nonnullable_vars;
2792 64 : pass_forced_null_vars = local_forced_null_vars;
2793 : }
2794 : else
2795 : {
2796 : /* no constraints pass through JOIN_FULL */
2797 2 : pass_nonnullable_rels = NULL;
2798 2 : pass_nonnullable_vars = NIL;
2799 2 : pass_forced_null_vars = NIL;
2800 : }
2801 66 : reduce_outer_joins_pass2(j->rarg, right_state, root,
2802 : pass_nonnullable_rels,
2803 : pass_nonnullable_vars,
2804 : pass_forced_null_vars);
2805 : }
2806 274 : bms_free(local_nonnullable_rels);
2807 : }
2808 : }
2809 : else
2810 0 : elog(ERROR, "unrecognized node type: %d",
2811 : (int) nodeTag(jtnode));
2812 2924 : }
2813 :
2814 : /*
2815 : * substitute_multiple_relids - adjust node relid sets after pulling up
2816 : * a subquery
2817 : *
2818 : * Find any PlaceHolderVar nodes in the given tree that reference the
2819 : * pulled-up relid, and change them to reference the replacement relid(s).
2820 : *
2821 : * NOTE: although this has the form of a walker, we cheat and modify the
2822 : * nodes in-place. This should be OK since the tree was copied by
2823 : * pullup_replace_vars earlier. Avoid scribbling on the original values of
2824 : * the bitmapsets, though, because expression_tree_mutator doesn't copy those.
2825 : */
2826 :
2827 : typedef struct
2828 : {
2829 : int varno;
2830 : int sublevels_up;
2831 : Relids subrelids;
2832 : } substitute_multiple_relids_context;
2833 :
2834 : static bool
2835 66757 : substitute_multiple_relids_walker(Node *node,
2836 : substitute_multiple_relids_context *context)
2837 : {
2838 66757 : if (node == NULL)
2839 26651 : return false;
2840 40106 : if (IsA(node, PlaceHolderVar))
2841 : {
2842 192 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
2843 :
2844 384 : if (phv->phlevelsup == context->sublevels_up &&
2845 192 : bms_is_member(context->varno, phv->phrels))
2846 : {
2847 127 : phv->phrels = bms_union(phv->phrels,
2848 127 : context->subrelids);
2849 127 : phv->phrels = bms_del_member(phv->phrels,
2850 : context->varno);
2851 : }
2852 : /* fall through to examine children */
2853 : }
2854 40106 : if (IsA(node, Query))
2855 : {
2856 : /* Recurse into subselects */
2857 : bool result;
2858 :
2859 1715 : context->sublevels_up++;
2860 1715 : result = query_tree_walker((Query *) node,
2861 : substitute_multiple_relids_walker,
2862 : (void *) context, 0);
2863 1715 : context->sublevels_up--;
2864 1715 : return result;
2865 : }
2866 : /* Shouldn't need to handle planner auxiliary nodes here */
2867 38391 : Assert(!IsA(node, SpecialJoinInfo));
2868 38391 : Assert(!IsA(node, AppendRelInfo));
2869 38391 : Assert(!IsA(node, PlaceHolderInfo));
2870 38391 : Assert(!IsA(node, MinMaxAggInfo));
2871 :
2872 38391 : return expression_tree_walker(node, substitute_multiple_relids_walker,
2873 : (void *) context);
2874 : }
2875 :
2876 : static void
2877 620 : substitute_multiple_relids(Node *node, int varno, Relids subrelids)
2878 : {
2879 : substitute_multiple_relids_context context;
2880 :
2881 620 : context.varno = varno;
2882 620 : context.sublevels_up = 0;
2883 620 : context.subrelids = subrelids;
2884 :
2885 : /*
2886 : * Must be prepared to start with a Query or a bare expression tree.
2887 : */
2888 620 : query_or_expression_tree_walker(node,
2889 : substitute_multiple_relids_walker,
2890 : (void *) &context,
2891 : 0);
2892 620 : }
2893 :
2894 : /*
2895 : * fix_append_rel_relids: update RT-index fields of AppendRelInfo nodes
2896 : *
2897 : * When we pull up a subquery, any AppendRelInfo references to the subquery's
2898 : * RT index have to be replaced by the substituted relid (and there had better
2899 : * be only one). We also need to apply substitute_multiple_relids to their
2900 : * translated_vars lists, since those might contain PlaceHolderVars.
2901 : *
2902 : * We assume we may modify the AppendRelInfo nodes in-place.
2903 : */
2904 : static void
2905 378 : fix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids)
2906 : {
2907 : ListCell *l;
2908 378 : int subvarno = -1;
2909 :
2910 : /*
2911 : * We only want to extract the member relid once, but we mustn't fail
2912 : * immediately if there are multiple members; it could be that none of the
2913 : * AppendRelInfo nodes refer to it. So compute it on first use. Note that
2914 : * bms_singleton_member will complain if set is not singleton.
2915 : */
2916 620 : foreach(l, append_rel_list)
2917 : {
2918 242 : AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
2919 :
2920 : /* The parent_relid shouldn't ever be a pullup target */
2921 242 : Assert(appinfo->parent_relid != varno);
2922 :
2923 242 : if (appinfo->child_relid == varno)
2924 : {
2925 137 : if (subvarno < 0)
2926 137 : subvarno = bms_singleton_member(subrelids);
2927 137 : appinfo->child_relid = subvarno;
2928 : }
2929 :
2930 : /* Also finish fixups for its translated vars */
2931 242 : substitute_multiple_relids((Node *) appinfo->translated_vars,
2932 : varno, subrelids);
2933 : }
2934 378 : }
2935 :
2936 : /*
2937 : * get_relids_in_jointree: get set of RT indexes present in a jointree
2938 : *
2939 : * If include_joins is true, join RT indexes are included; if false,
2940 : * only base rels are included.
2941 : */
2942 : Relids
2943 4811 : get_relids_in_jointree(Node *jtnode, bool include_joins)
2944 : {
2945 4811 : Relids result = NULL;
2946 :
2947 4811 : if (jtnode == NULL)
2948 0 : return result;
2949 4811 : if (IsA(jtnode, RangeTblRef))
2950 : {
2951 2441 : int varno = ((RangeTblRef *) jtnode)->rtindex;
2952 :
2953 2441 : result = bms_make_singleton(varno);
2954 : }
2955 2370 : else if (IsA(jtnode, FromExpr))
2956 : {
2957 2207 : FromExpr *f = (FromExpr *) jtnode;
2958 : ListCell *l;
2959 :
2960 4584 : foreach(l, f->fromlist)
2961 : {
2962 4754 : result = bms_join(result,
2963 2377 : get_relids_in_jointree(lfirst(l),
2964 : include_joins));
2965 : }
2966 : }
2967 163 : else if (IsA(jtnode, JoinExpr))
2968 : {
2969 163 : JoinExpr *j = (JoinExpr *) jtnode;
2970 :
2971 163 : result = get_relids_in_jointree(j->larg, include_joins);
2972 163 : result = bms_join(result,
2973 : get_relids_in_jointree(j->rarg, include_joins));
2974 163 : if (include_joins && j->rtindex)
2975 44 : result = bms_add_member(result, j->rtindex);
2976 : }
2977 : else
2978 0 : elog(ERROR, "unrecognized node type: %d",
2979 : (int) nodeTag(jtnode));
2980 4811 : return result;
2981 : }
2982 :
2983 : /*
2984 : * get_relids_for_join: get set of base RT indexes making up a join
2985 : */
2986 : Relids
2987 0 : get_relids_for_join(PlannerInfo *root, int joinrelid)
2988 : {
2989 : Node *jtnode;
2990 :
2991 0 : jtnode = find_jointree_node_for_rel((Node *) root->parse->jointree,
2992 : joinrelid);
2993 0 : if (!jtnode)
2994 0 : elog(ERROR, "could not find join node %d", joinrelid);
2995 0 : return get_relids_in_jointree(jtnode, false);
2996 : }
2997 :
2998 : /*
2999 : * find_jointree_node_for_rel: locate jointree node for a base or join RT index
3000 : *
3001 : * Returns NULL if not found
3002 : */
3003 : static Node *
3004 0 : find_jointree_node_for_rel(Node *jtnode, int relid)
3005 : {
3006 0 : if (jtnode == NULL)
3007 0 : return NULL;
3008 0 : if (IsA(jtnode, RangeTblRef))
3009 : {
3010 0 : int varno = ((RangeTblRef *) jtnode)->rtindex;
3011 :
3012 0 : if (relid == varno)
3013 0 : return jtnode;
3014 : }
3015 0 : else if (IsA(jtnode, FromExpr))
3016 : {
3017 0 : FromExpr *f = (FromExpr *) jtnode;
3018 : ListCell *l;
3019 :
3020 0 : foreach(l, f->fromlist)
3021 : {
3022 0 : jtnode = find_jointree_node_for_rel(lfirst(l), relid);
3023 0 : if (jtnode)
3024 0 : return jtnode;
3025 : }
3026 : }
3027 0 : else if (IsA(jtnode, JoinExpr))
3028 : {
3029 0 : JoinExpr *j = (JoinExpr *) jtnode;
3030 :
3031 0 : if (relid == j->rtindex)
3032 0 : return jtnode;
3033 0 : jtnode = find_jointree_node_for_rel(j->larg, relid);
3034 0 : if (jtnode)
3035 0 : return jtnode;
3036 0 : jtnode = find_jointree_node_for_rel(j->rarg, relid);
3037 0 : if (jtnode)
3038 0 : return jtnode;
3039 : }
3040 : else
3041 0 : elog(ERROR, "unrecognized node type: %d",
3042 : (int) nodeTag(jtnode));
3043 0 : return NULL;
3044 : }
|