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 : * replace_empty_jointree
8 : * pull_up_sublinks
9 : * preprocess_function_rtes
10 : * pull_up_subqueries
11 : * flatten_simple_union_all
12 : * do expression preprocessing (including flattening JOIN alias vars)
13 : * reduce_outer_joins
14 : * remove_useless_result_rtes
15 : *
16 : *
17 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
18 : * Portions Copyright (c) 1994, Regents of the University of California
19 : *
20 : *
21 : * IDENTIFICATION
22 : * src/backend/optimizer/prep/prepjointree.c
23 : *
24 : *-------------------------------------------------------------------------
25 : */
26 : #include "postgres.h"
27 :
28 : #include "catalog/pg_type.h"
29 : #include "funcapi.h"
30 : #include "miscadmin.h"
31 : #include "nodes/makefuncs.h"
32 : #include "nodes/multibitmapset.h"
33 : #include "nodes/nodeFuncs.h"
34 : #include "optimizer/clauses.h"
35 : #include "optimizer/optimizer.h"
36 : #include "optimizer/placeholder.h"
37 : #include "optimizer/prep.h"
38 : #include "optimizer/subselect.h"
39 : #include "optimizer/tlist.h"
40 : #include "parser/parse_relation.h"
41 : #include "parser/parsetree.h"
42 : #include "rewrite/rewriteManip.h"
43 :
44 :
45 : typedef struct nullingrel_info
46 : {
47 : /*
48 : * For each leaf RTE, nullingrels[rti] is the set of relids of outer joins
49 : * that potentially null that RTE.
50 : */
51 : Relids *nullingrels;
52 : /* Length of range table (maximum index in nullingrels[]) */
53 : int rtlength; /* used only for assertion checks */
54 : } nullingrel_info;
55 :
56 : typedef struct pullup_replace_vars_context
57 : {
58 : PlannerInfo *root;
59 : List *targetlist; /* tlist of subquery being pulled up */
60 : RangeTblEntry *target_rte; /* RTE of subquery */
61 : Relids relids; /* relids within subquery, as numbered after
62 : * pullup (set only if target_rte->lateral) */
63 : nullingrel_info *nullinfo; /* per-RTE nullingrel info (set only if
64 : * target_rte->lateral) */
65 : bool *outer_hasSubLinks; /* -> outer query's hasSubLinks */
66 : int varno; /* varno of subquery */
67 : bool wrap_non_vars; /* do we need all non-Var outputs to be PHVs? */
68 : Node **rv_cache; /* cache for results with PHVs */
69 : } pullup_replace_vars_context;
70 :
71 : typedef struct reduce_outer_joins_pass1_state
72 : {
73 : Relids relids; /* base relids within this subtree */
74 : bool contains_outer; /* does subtree contain outer join(s)? */
75 : List *sub_states; /* List of states for subtree components */
76 : } reduce_outer_joins_pass1_state;
77 :
78 : typedef struct reduce_outer_joins_pass2_state
79 : {
80 : Relids inner_reduced; /* OJ relids reduced to plain inner joins */
81 : List *partial_reduced; /* List of partially reduced FULL joins */
82 : } reduce_outer_joins_pass2_state;
83 :
84 : typedef struct reduce_outer_joins_partial_state
85 : {
86 : int full_join_rti; /* RT index of a formerly-FULL join */
87 : Relids unreduced_side; /* relids in its still-nullable side */
88 : } reduce_outer_joins_partial_state;
89 :
90 : static Node *pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode,
91 : Relids *relids);
92 : static Node *pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
93 : Node **jtlink1, Relids available_rels1,
94 : Node **jtlink2, Relids available_rels2);
95 : static Node *pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode,
96 : JoinExpr *lowest_outer_join,
97 : AppendRelInfo *containing_appendrel);
98 : static Node *pull_up_simple_subquery(PlannerInfo *root, Node *jtnode,
99 : RangeTblEntry *rte,
100 : JoinExpr *lowest_outer_join,
101 : AppendRelInfo *containing_appendrel);
102 : static Node *pull_up_simple_union_all(PlannerInfo *root, Node *jtnode,
103 : RangeTblEntry *rte);
104 : static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root,
105 : int parentRTindex, Query *setOpQuery,
106 : int childRToffset);
107 : static void make_setop_translation_list(Query *query, int newvarno,
108 : AppendRelInfo *appinfo);
109 : static bool is_simple_subquery(PlannerInfo *root, Query *subquery,
110 : RangeTblEntry *rte,
111 : JoinExpr *lowest_outer_join);
112 : static Node *pull_up_simple_values(PlannerInfo *root, Node *jtnode,
113 : RangeTblEntry *rte);
114 : static bool is_simple_values(PlannerInfo *root, RangeTblEntry *rte);
115 : static Node *pull_up_constant_function(PlannerInfo *root, Node *jtnode,
116 : RangeTblEntry *rte,
117 : AppendRelInfo *containing_appendrel);
118 : static bool is_simple_union_all(Query *subquery);
119 : static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery,
120 : List *colTypes);
121 : static bool is_safe_append_member(Query *subquery);
122 : static bool jointree_contains_lateral_outer_refs(PlannerInfo *root,
123 : Node *jtnode, bool restricted,
124 : Relids safe_upper_varnos);
125 : static void perform_pullup_replace_vars(PlannerInfo *root,
126 : pullup_replace_vars_context *rvcontext,
127 : AppendRelInfo *containing_appendrel);
128 : static void replace_vars_in_jointree(Node *jtnode,
129 : pullup_replace_vars_context *context);
130 : static Node *pullup_replace_vars(Node *expr,
131 : pullup_replace_vars_context *context);
132 : static Node *pullup_replace_vars_callback(Var *var,
133 : replace_rte_variables_context *context);
134 : static Query *pullup_replace_vars_subquery(Query *query,
135 : pullup_replace_vars_context *context);
136 : static reduce_outer_joins_pass1_state *reduce_outer_joins_pass1(Node *jtnode);
137 : static void reduce_outer_joins_pass2(Node *jtnode,
138 : reduce_outer_joins_pass1_state *state1,
139 : reduce_outer_joins_pass2_state *state2,
140 : PlannerInfo *root,
141 : Relids nonnullable_rels,
142 : List *forced_null_vars);
143 : static void report_reduced_full_join(reduce_outer_joins_pass2_state *state2,
144 : int rtindex, Relids relids);
145 : static Node *remove_useless_results_recurse(PlannerInfo *root, Node *jtnode,
146 : Node **parent_quals,
147 : Relids *dropped_outer_joins);
148 : static int get_result_relid(PlannerInfo *root, Node *jtnode);
149 : static void remove_result_refs(PlannerInfo *root, int varno, Node *newjtloc);
150 : static bool find_dependent_phvs(PlannerInfo *root, int varno);
151 : static bool find_dependent_phvs_in_jointree(PlannerInfo *root,
152 : Node *node, int varno);
153 : static void substitute_phv_relids(Node *node,
154 : int varno, Relids subrelids);
155 : static void fix_append_rel_relids(PlannerInfo *root, int varno,
156 : Relids subrelids);
157 : static Node *find_jointree_node_for_rel(Node *jtnode, int relid);
158 : static nullingrel_info *get_nullingrels(Query *parse);
159 : static void get_nullingrels_recurse(Node *jtnode, Relids upper_nullingrels,
160 : nullingrel_info *info);
161 :
162 :
163 : /*
164 : * transform_MERGE_to_join
165 : * Replace a MERGE's jointree to also include the target relation.
166 : */
167 : void
168 510160 : transform_MERGE_to_join(Query *parse)
169 : {
170 : RangeTblEntry *joinrte;
171 : JoinExpr *joinexpr;
172 : bool have_action[NUM_MERGE_MATCH_KINDS];
173 : JoinType jointype;
174 : int joinrti;
175 : List *vars;
176 : RangeTblRef *rtr;
177 : FromExpr *target;
178 : Node *source;
179 : int sourcerti;
180 :
181 510160 : if (parse->commandType != CMD_MERGE)
182 508402 : return;
183 :
184 : /* XXX probably bogus */
185 1758 : vars = NIL;
186 :
187 : /*
188 : * Work out what kind of join is required. If there any WHEN NOT MATCHED
189 : * BY SOURCE/TARGET actions, an outer join is required so that we process
190 : * all unmatched tuples from the source and/or target relations.
191 : * Otherwise, we can use an inner join.
192 : */
193 1758 : have_action[MERGE_WHEN_MATCHED] = false;
194 1758 : have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE] = false;
195 1758 : have_action[MERGE_WHEN_NOT_MATCHED_BY_TARGET] = false;
196 :
197 6210 : foreach_node(MergeAction, action, parse->mergeActionList)
198 : {
199 2694 : if (action->commandType != CMD_NOTHING)
200 2628 : have_action[action->matchKind] = true;
201 : }
202 :
203 1758 : if (have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE] &&
204 126 : have_action[MERGE_WHEN_NOT_MATCHED_BY_TARGET])
205 96 : jointype = JOIN_FULL;
206 1662 : else if (have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE])
207 30 : jointype = JOIN_LEFT;
208 1632 : else if (have_action[MERGE_WHEN_NOT_MATCHED_BY_TARGET])
209 746 : jointype = JOIN_RIGHT;
210 : else
211 886 : jointype = JOIN_INNER;
212 :
213 : /* Manufacture a join RTE to use. */
214 1758 : joinrte = makeNode(RangeTblEntry);
215 1758 : joinrte->rtekind = RTE_JOIN;
216 1758 : joinrte->jointype = jointype;
217 1758 : joinrte->joinmergedcols = 0;
218 1758 : joinrte->joinaliasvars = vars;
219 1758 : joinrte->joinleftcols = NIL; /* MERGE does not allow JOIN USING */
220 1758 : joinrte->joinrightcols = NIL; /* ditto */
221 1758 : joinrte->join_using_alias = NULL;
222 :
223 1758 : joinrte->alias = NULL;
224 1758 : joinrte->eref = makeAlias("*MERGE*", NIL);
225 1758 : joinrte->lateral = false;
226 1758 : joinrte->inh = false;
227 1758 : joinrte->inFromCl = true;
228 :
229 : /*
230 : * Add completed RTE to pstate's range table list, so that we know its
231 : * index.
232 : */
233 1758 : parse->rtable = lappend(parse->rtable, joinrte);
234 1758 : joinrti = list_length(parse->rtable);
235 :
236 : /*
237 : * Create a JOIN between the target and the source relation.
238 : *
239 : * Here the target is identified by parse->mergeTargetRelation. For a
240 : * regular table, this will equal parse->resultRelation, but for a
241 : * trigger-updatable view, it will be the expanded view subquery that we
242 : * need to pull data from.
243 : *
244 : * The source relation is in parse->jointree->fromlist, but any quals in
245 : * parse->jointree->quals are restrictions on the target relation (if the
246 : * target relation is an auto-updatable view).
247 : */
248 : /* target rel, with any quals */
249 1758 : rtr = makeNode(RangeTblRef);
250 1758 : rtr->rtindex = parse->mergeTargetRelation;
251 1758 : target = makeFromExpr(list_make1(rtr), parse->jointree->quals);
252 :
253 : /* source rel (expect exactly one -- see transformMergeStmt()) */
254 : Assert(list_length(parse->jointree->fromlist) == 1);
255 1758 : source = linitial(parse->jointree->fromlist);
256 :
257 : /*
258 : * index of source rel (expect either a RangeTblRef or a JoinExpr -- see
259 : * transformFromClauseItem()).
260 : */
261 1758 : if (IsA(source, RangeTblRef))
262 1722 : sourcerti = ((RangeTblRef *) source)->rtindex;
263 36 : else if (IsA(source, JoinExpr))
264 36 : sourcerti = ((JoinExpr *) source)->rtindex;
265 : else
266 : {
267 0 : elog(ERROR, "unrecognized source node type: %d",
268 : (int) nodeTag(source));
269 : sourcerti = 0; /* keep compiler quiet */
270 : }
271 :
272 : /* Join the source and target */
273 1758 : joinexpr = makeNode(JoinExpr);
274 1758 : joinexpr->jointype = jointype;
275 1758 : joinexpr->isNatural = false;
276 1758 : joinexpr->larg = (Node *) target;
277 1758 : joinexpr->rarg = source;
278 1758 : joinexpr->usingClause = NIL;
279 1758 : joinexpr->join_using_alias = NULL;
280 1758 : joinexpr->quals = parse->mergeJoinCondition;
281 1758 : joinexpr->alias = NULL;
282 1758 : joinexpr->rtindex = joinrti;
283 :
284 : /* Make the new join be the sole entry in the query's jointree */
285 1758 : parse->jointree->fromlist = list_make1(joinexpr);
286 1758 : parse->jointree->quals = NULL;
287 :
288 : /*
289 : * If necessary, mark parse->targetlist entries that refer to the target
290 : * as nullable by the join. Normally the targetlist will be empty for a
291 : * MERGE, but if the target is a trigger-updatable view, it will contain a
292 : * whole-row Var referring to the expanded view query.
293 : */
294 1758 : if (parse->targetList != NIL &&
295 42 : (jointype == JOIN_RIGHT || jointype == JOIN_FULL))
296 42 : parse->targetList = (List *)
297 42 : add_nulling_relids((Node *) parse->targetList,
298 42 : bms_make_singleton(parse->mergeTargetRelation),
299 42 : bms_make_singleton(joinrti));
300 :
301 : /*
302 : * If the source relation is on the outer side of the join, mark any
303 : * source relation Vars in the join condition, actions, and RETURNING list
304 : * as nullable by the join. These Vars will be added to the targetlist by
305 : * preprocess_targetlist(), so it's important to mark them correctly here.
306 : *
307 : * It might seem that this is not necessary for Vars in the join
308 : * condition, since it is inside the join, but it is also needed above the
309 : * join (in the ModifyTable node) to distinguish between the MATCHED and
310 : * NOT MATCHED BY SOURCE cases -- see ExecMergeMatched(). Note that this
311 : * creates a modified copy of the join condition, for use above the join,
312 : * without modifying the original join condition, inside the join.
313 : */
314 1758 : if (jointype == JOIN_LEFT || jointype == JOIN_FULL)
315 : {
316 126 : parse->mergeJoinCondition =
317 126 : add_nulling_relids(parse->mergeJoinCondition,
318 126 : bms_make_singleton(sourcerti),
319 126 : bms_make_singleton(joinrti));
320 :
321 600 : foreach_node(MergeAction, action, parse->mergeActionList)
322 : {
323 348 : action->qual =
324 348 : add_nulling_relids(action->qual,
325 348 : bms_make_singleton(sourcerti),
326 348 : bms_make_singleton(joinrti));
327 :
328 348 : action->targetList = (List *)
329 348 : add_nulling_relids((Node *) action->targetList,
330 348 : bms_make_singleton(sourcerti),
331 348 : bms_make_singleton(joinrti));
332 : }
333 :
334 126 : parse->returningList = (List *)
335 126 : add_nulling_relids((Node *) parse->returningList,
336 126 : bms_make_singleton(sourcerti),
337 126 : bms_make_singleton(joinrti));
338 : }
339 :
340 : /*
341 : * If there are any WHEN NOT MATCHED BY SOURCE actions, the executor will
342 : * use the join condition to distinguish between MATCHED and NOT MATCHED
343 : * BY SOURCE cases. Otherwise, it's no longer needed, and we set it to
344 : * NULL, saving cycles during planning and execution.
345 : *
346 : * We need to be careful though: the executor evaluates this condition
347 : * using the output of the join subplan node, which nulls the output from
348 : * the source relation when the join condition doesn't match. That risks
349 : * producing incorrect results when rechecking using a "non-strict" join
350 : * condition, such as "src.col IS NOT DISTINCT FROM tgt.col". To guard
351 : * against that, we add an additional "src IS NOT NULL" check to the join
352 : * condition, so that it does the right thing when performing a recheck
353 : * based on the output of the join subplan.
354 : */
355 1758 : if (have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE])
356 : {
357 : Var *var;
358 : NullTest *ntest;
359 :
360 : /* source wholerow Var (nullable by the new join) */
361 126 : var = makeWholeRowVar(rt_fetch(sourcerti, parse->rtable),
362 : sourcerti, 0, false);
363 126 : var->varnullingrels = bms_make_singleton(joinrti);
364 :
365 : /* "src IS NOT NULL" check */
366 126 : ntest = makeNode(NullTest);
367 126 : ntest->arg = (Expr *) var;
368 126 : ntest->nulltesttype = IS_NOT_NULL;
369 126 : ntest->argisrow = false;
370 126 : ntest->location = -1;
371 :
372 : /* combine it with the original join condition */
373 126 : parse->mergeJoinCondition =
374 126 : (Node *) make_and_qual((Node *) ntest, parse->mergeJoinCondition);
375 : }
376 : else
377 1632 : parse->mergeJoinCondition = NULL; /* join condition not needed */
378 : }
379 :
380 : /*
381 : * replace_empty_jointree
382 : * If the Query's jointree is empty, replace it with a dummy RTE_RESULT
383 : * relation.
384 : *
385 : * By doing this, we can avoid a bunch of corner cases that formerly existed
386 : * for SELECTs with omitted FROM clauses. An example is that a subquery
387 : * with empty jointree previously could not be pulled up, because that would
388 : * have resulted in an empty relid set, making the subquery not uniquely
389 : * identifiable for join or PlaceHolderVar processing.
390 : *
391 : * Unlike most other functions in this file, this function doesn't recurse;
392 : * we rely on other processing to invoke it on sub-queries at suitable times.
393 : */
394 : void
395 544158 : replace_empty_jointree(Query *parse)
396 : {
397 : RangeTblEntry *rte;
398 : Index rti;
399 : RangeTblRef *rtr;
400 :
401 : /* Nothing to do if jointree is already nonempty */
402 544158 : if (parse->jointree->fromlist != NIL)
403 328710 : return;
404 :
405 : /* We mustn't change it in the top level of a setop tree, either */
406 221300 : if (parse->setOperations)
407 5852 : return;
408 :
409 : /* Create suitable RTE */
410 215448 : rte = makeNode(RangeTblEntry);
411 215448 : rte->rtekind = RTE_RESULT;
412 215448 : rte->eref = makeAlias("*RESULT*", NIL);
413 :
414 : /* Add it to rangetable */
415 215448 : parse->rtable = lappend(parse->rtable, rte);
416 215448 : rti = list_length(parse->rtable);
417 :
418 : /* And jam a reference into the jointree */
419 215448 : rtr = makeNode(RangeTblRef);
420 215448 : rtr->rtindex = rti;
421 215448 : parse->jointree->fromlist = list_make1(rtr);
422 : }
423 :
424 : /*
425 : * pull_up_sublinks
426 : * Attempt to pull up ANY and EXISTS SubLinks to be treated as
427 : * semijoins or anti-semijoins.
428 : *
429 : * A clause "foo op ANY (sub-SELECT)" can be processed by pulling the
430 : * sub-SELECT up to become a rangetable entry and treating the implied
431 : * comparisons as quals of a semijoin. However, this optimization *only*
432 : * works at the top level of WHERE or a JOIN/ON clause, because we cannot
433 : * distinguish whether the ANY ought to return FALSE or NULL in cases
434 : * involving NULL inputs. Also, in an outer join's ON clause we can only
435 : * do this if the sublink is degenerate (ie, references only the nullable
436 : * side of the join). In that case it is legal to push the semijoin
437 : * down into the nullable side of the join. If the sublink references any
438 : * nonnullable-side variables then it would have to be evaluated as part
439 : * of the outer join, which makes things way too complicated.
440 : *
441 : * Under similar conditions, EXISTS and NOT EXISTS clauses can be handled
442 : * by pulling up the sub-SELECT and creating a semijoin or anti-semijoin.
443 : *
444 : * This routine searches for such clauses and does the necessary parsetree
445 : * transformations if any are found.
446 : *
447 : * This routine has to run before preprocess_expression(), so the quals
448 : * clauses are not yet reduced to implicit-AND format, and are not guaranteed
449 : * to be AND/OR-flat either. That means we need to recursively search through
450 : * explicit AND clauses. We stop as soon as we hit a non-AND item.
451 : */
452 : void
453 32374 : pull_up_sublinks(PlannerInfo *root)
454 : {
455 : Node *jtnode;
456 : Relids relids;
457 :
458 : /* Begin recursion through the jointree */
459 32374 : jtnode = pull_up_sublinks_jointree_recurse(root,
460 32374 : (Node *) root->parse->jointree,
461 : &relids);
462 :
463 : /*
464 : * root->parse->jointree must always be a FromExpr, so insert a dummy one
465 : * if we got a bare RangeTblRef or JoinExpr out of the recursion.
466 : */
467 32374 : if (IsA(jtnode, FromExpr))
468 28028 : root->parse->jointree = (FromExpr *) jtnode;
469 : else
470 4346 : root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
471 32374 : }
472 :
473 : /*
474 : * Recurse through jointree nodes for pull_up_sublinks()
475 : *
476 : * In addition to returning the possibly-modified jointree node, we return
477 : * a relids set of the contained rels into *relids.
478 : */
479 : static Node *
480 108620 : pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode,
481 : Relids *relids)
482 : {
483 : /* Since this function recurses, it could be driven to stack overflow. */
484 108620 : check_stack_depth();
485 :
486 108620 : if (jtnode == NULL)
487 : {
488 0 : *relids = NULL;
489 : }
490 108620 : else if (IsA(jtnode, RangeTblRef))
491 : {
492 58036 : int varno = ((RangeTblRef *) jtnode)->rtindex;
493 :
494 58036 : *relids = bms_make_singleton(varno);
495 : /* jtnode is returned unmodified */
496 : }
497 50584 : else if (IsA(jtnode, FromExpr))
498 : {
499 32590 : FromExpr *f = (FromExpr *) jtnode;
500 32590 : List *newfromlist = NIL;
501 32590 : Relids frelids = NULL;
502 : FromExpr *newf;
503 : Node *jtlink;
504 : ListCell *l;
505 :
506 : /* First, recurse to process children and collect their relids */
507 68290 : foreach(l, f->fromlist)
508 : {
509 : Node *newchild;
510 : Relids childrelids;
511 :
512 35700 : newchild = pull_up_sublinks_jointree_recurse(root,
513 35700 : lfirst(l),
514 : &childrelids);
515 35700 : newfromlist = lappend(newfromlist, newchild);
516 35700 : frelids = bms_join(frelids, childrelids);
517 : }
518 : /* Build the replacement FromExpr; no quals yet */
519 32590 : newf = makeFromExpr(newfromlist, NULL);
520 : /* Set up a link representing the rebuilt jointree */
521 32590 : jtlink = (Node *) newf;
522 : /* Now process qual --- all children are available for use */
523 32590 : newf->quals = pull_up_sublinks_qual_recurse(root, f->quals,
524 : &jtlink, frelids,
525 : NULL, NULL);
526 :
527 : /*
528 : * Note that the result will be either newf, or a stack of JoinExprs
529 : * with newf at the base. We rely on subsequent optimization steps to
530 : * flatten this and rearrange the joins as needed.
531 : *
532 : * Although we could include the pulled-up subqueries in the returned
533 : * relids, there's no need since upper quals couldn't refer to their
534 : * outputs anyway.
535 : */
536 32590 : *relids = frelids;
537 32590 : jtnode = jtlink;
538 : }
539 17994 : else if (IsA(jtnode, JoinExpr))
540 : {
541 : JoinExpr *j;
542 : Relids leftrelids;
543 : Relids rightrelids;
544 : Node *jtlink;
545 :
546 : /*
547 : * Make a modifiable copy of join node, but don't bother copying its
548 : * subnodes (yet).
549 : */
550 17994 : j = (JoinExpr *) palloc(sizeof(JoinExpr));
551 17994 : memcpy(j, jtnode, sizeof(JoinExpr));
552 17994 : jtlink = (Node *) j;
553 :
554 : /* Recurse to process children and collect their relids */
555 17994 : j->larg = pull_up_sublinks_jointree_recurse(root, j->larg,
556 : &leftrelids);
557 17994 : j->rarg = pull_up_sublinks_jointree_recurse(root, j->rarg,
558 : &rightrelids);
559 :
560 : /*
561 : * Now process qual, showing appropriate child relids as available,
562 : * and attach any pulled-up jointree items at the right place. In the
563 : * inner-join case we put new JoinExprs above the existing one (much
564 : * as for a FromExpr-style join). In outer-join cases the new
565 : * JoinExprs must go into the nullable side of the outer join. The
566 : * point of the available_rels machinations is to ensure that we only
567 : * pull up quals for which that's okay.
568 : *
569 : * We don't expect to see any pre-existing JOIN_SEMI, JOIN_ANTI,
570 : * JOIN_RIGHT_SEMI, or JOIN_RIGHT_ANTI jointypes here.
571 : */
572 17994 : switch (j->jointype)
573 : {
574 8166 : case JOIN_INNER:
575 8166 : j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
576 : &jtlink,
577 : bms_union(leftrelids,
578 : rightrelids),
579 : NULL, NULL);
580 8166 : break;
581 9720 : case JOIN_LEFT:
582 9720 : j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
583 : &j->rarg,
584 : rightrelids,
585 : NULL, NULL);
586 9720 : break;
587 12 : case JOIN_FULL:
588 : /* can't do anything with full-join quals */
589 12 : break;
590 96 : case JOIN_RIGHT:
591 96 : j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
592 : &j->larg,
593 : leftrelids,
594 : NULL, NULL);
595 96 : break;
596 0 : default:
597 0 : elog(ERROR, "unrecognized join type: %d",
598 : (int) j->jointype);
599 : break;
600 : }
601 :
602 : /*
603 : * Although we could include the pulled-up subqueries in the returned
604 : * relids, there's no need since upper quals couldn't refer to their
605 : * outputs anyway. But we *do* need to include the join's own rtindex
606 : * because we haven't yet collapsed join alias variables, so upper
607 : * levels would mistakenly think they couldn't use references to this
608 : * join.
609 : */
610 17994 : *relids = bms_join(leftrelids, rightrelids);
611 17994 : if (j->rtindex)
612 17994 : *relids = bms_add_member(*relids, j->rtindex);
613 17994 : jtnode = jtlink;
614 : }
615 : else
616 0 : elog(ERROR, "unrecognized node type: %d",
617 : (int) nodeTag(jtnode));
618 108620 : return jtnode;
619 : }
620 :
621 : /*
622 : * Recurse through top-level qual nodes for pull_up_sublinks()
623 : *
624 : * jtlink1 points to the link in the jointree where any new JoinExprs should
625 : * be inserted if they reference available_rels1 (i.e., available_rels1
626 : * denotes the relations present underneath jtlink1). Optionally, jtlink2 can
627 : * point to a second link where new JoinExprs should be inserted if they
628 : * reference available_rels2 (pass NULL for both those arguments if not used).
629 : * Note that SubLinks referencing both sets of variables cannot be optimized.
630 : * If we find multiple pull-up-able SubLinks, they'll get stacked onto jtlink1
631 : * and/or jtlink2 in the order we encounter them. We rely on subsequent
632 : * optimization to rearrange the stack if appropriate.
633 : *
634 : * Returns the replacement qual node, or NULL if the qual should be removed.
635 : */
636 : static Node *
637 93786 : pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
638 : Node **jtlink1, Relids available_rels1,
639 : Node **jtlink2, Relids available_rels2)
640 : {
641 93786 : if (node == NULL)
642 6756 : return NULL;
643 87030 : if (IsA(node, SubLink))
644 : {
645 2310 : SubLink *sublink = (SubLink *) node;
646 : JoinExpr *j;
647 : Relids child_rels;
648 :
649 : /* Is it a convertible ANY or EXISTS clause? */
650 2310 : if (sublink->subLinkType == ANY_SUBLINK)
651 : {
652 1538 : if ((j = convert_ANY_sublink_to_join(root, sublink,
653 : available_rels1)) != NULL)
654 : {
655 : /* Yes; insert the new join node into the join tree */
656 1432 : j->larg = *jtlink1;
657 1432 : *jtlink1 = (Node *) j;
658 : /* Recursively process pulled-up jointree nodes */
659 1432 : j->rarg = pull_up_sublinks_jointree_recurse(root,
660 : j->rarg,
661 : &child_rels);
662 :
663 : /*
664 : * Now recursively process the pulled-up quals. Any inserted
665 : * joins can get stacked onto either j->larg or j->rarg,
666 : * depending on which rels they reference.
667 : */
668 1432 : j->quals = pull_up_sublinks_qual_recurse(root,
669 : j->quals,
670 : &j->larg,
671 : available_rels1,
672 : &j->rarg,
673 : child_rels);
674 : /* Return NULL representing constant TRUE */
675 1432 : return NULL;
676 : }
677 112 : if (available_rels2 != NULL &&
678 6 : (j = convert_ANY_sublink_to_join(root, sublink,
679 : available_rels2)) != NULL)
680 : {
681 : /* Yes; insert the new join node into the join tree */
682 0 : j->larg = *jtlink2;
683 0 : *jtlink2 = (Node *) j;
684 : /* Recursively process pulled-up jointree nodes */
685 0 : j->rarg = pull_up_sublinks_jointree_recurse(root,
686 : j->rarg,
687 : &child_rels);
688 :
689 : /*
690 : * Now recursively process the pulled-up quals. Any inserted
691 : * joins can get stacked onto either j->larg or j->rarg,
692 : * depending on which rels they reference.
693 : */
694 0 : j->quals = pull_up_sublinks_qual_recurse(root,
695 : j->quals,
696 : &j->larg,
697 : available_rels2,
698 : &j->rarg,
699 : child_rels);
700 : /* Return NULL representing constant TRUE */
701 0 : return NULL;
702 : }
703 : }
704 772 : else if (sublink->subLinkType == EXISTS_SUBLINK)
705 : {
706 712 : if ((j = convert_EXISTS_sublink_to_join(root, sublink, false,
707 : available_rels1)) != NULL)
708 : {
709 : /* Yes; insert the new join node into the join tree */
710 600 : j->larg = *jtlink1;
711 600 : *jtlink1 = (Node *) j;
712 : /* Recursively process pulled-up jointree nodes */
713 600 : j->rarg = pull_up_sublinks_jointree_recurse(root,
714 : j->rarg,
715 : &child_rels);
716 :
717 : /*
718 : * Now recursively process the pulled-up quals. Any inserted
719 : * joins can get stacked onto either j->larg or j->rarg,
720 : * depending on which rels they reference.
721 : */
722 600 : j->quals = pull_up_sublinks_qual_recurse(root,
723 : j->quals,
724 : &j->larg,
725 : available_rels1,
726 : &j->rarg,
727 : child_rels);
728 : /* Return NULL representing constant TRUE */
729 600 : return NULL;
730 : }
731 144 : if (available_rels2 != NULL &&
732 32 : (j = convert_EXISTS_sublink_to_join(root, sublink, false,
733 : available_rels2)) != NULL)
734 : {
735 : /* Yes; insert the new join node into the join tree */
736 32 : j->larg = *jtlink2;
737 32 : *jtlink2 = (Node *) j;
738 : /* Recursively process pulled-up jointree nodes */
739 32 : j->rarg = pull_up_sublinks_jointree_recurse(root,
740 : j->rarg,
741 : &child_rels);
742 :
743 : /*
744 : * Now recursively process the pulled-up quals. Any inserted
745 : * joins can get stacked onto either j->larg or j->rarg,
746 : * depending on which rels they reference.
747 : */
748 32 : j->quals = pull_up_sublinks_qual_recurse(root,
749 : j->quals,
750 : &j->larg,
751 : available_rels2,
752 : &j->rarg,
753 : child_rels);
754 : /* Return NULL representing constant TRUE */
755 32 : return NULL;
756 : }
757 : }
758 : /* Else return it unmodified */
759 246 : return node;
760 : }
761 84720 : if (is_notclause(node))
762 : {
763 : /* If the immediate argument of NOT is EXISTS, try to convert */
764 6476 : SubLink *sublink = (SubLink *) get_notclausearg((Expr *) node);
765 : JoinExpr *j;
766 : Relids child_rels;
767 :
768 6476 : if (sublink && IsA(sublink, SubLink))
769 : {
770 2604 : if (sublink->subLinkType == EXISTS_SUBLINK)
771 : {
772 2508 : if ((j = convert_EXISTS_sublink_to_join(root, sublink, true,
773 : available_rels1)) != NULL)
774 : {
775 : /* Yes; insert the new join node into the join tree */
776 2494 : j->larg = *jtlink1;
777 2494 : *jtlink1 = (Node *) j;
778 : /* Recursively process pulled-up jointree nodes */
779 2494 : j->rarg = pull_up_sublinks_jointree_recurse(root,
780 : j->rarg,
781 : &child_rels);
782 :
783 : /*
784 : * Now recursively process the pulled-up quals. Because
785 : * we are underneath a NOT, we can't pull up sublinks that
786 : * reference the left-hand stuff, but it's still okay to
787 : * pull up sublinks referencing j->rarg.
788 : */
789 2494 : j->quals = pull_up_sublinks_qual_recurse(root,
790 : j->quals,
791 : &j->rarg,
792 : child_rels,
793 : NULL, NULL);
794 : /* Return NULL representing constant TRUE */
795 2494 : return NULL;
796 : }
797 14 : if (available_rels2 != NULL &&
798 0 : (j = convert_EXISTS_sublink_to_join(root, sublink, true,
799 : available_rels2)) != NULL)
800 : {
801 : /* Yes; insert the new join node into the join tree */
802 0 : j->larg = *jtlink2;
803 0 : *jtlink2 = (Node *) j;
804 : /* Recursively process pulled-up jointree nodes */
805 0 : j->rarg = pull_up_sublinks_jointree_recurse(root,
806 : j->rarg,
807 : &child_rels);
808 :
809 : /*
810 : * Now recursively process the pulled-up quals. Because
811 : * we are underneath a NOT, we can't pull up sublinks that
812 : * reference the left-hand stuff, but it's still okay to
813 : * pull up sublinks referencing j->rarg.
814 : */
815 0 : j->quals = pull_up_sublinks_qual_recurse(root,
816 : j->quals,
817 : &j->rarg,
818 : child_rels,
819 : NULL, NULL);
820 : /* Return NULL representing constant TRUE */
821 0 : return NULL;
822 : }
823 : }
824 : }
825 : /* Else return it unmodified */
826 3982 : return node;
827 : }
828 78244 : if (is_andclause(node))
829 : {
830 : /* Recurse into AND clause */
831 13592 : List *newclauses = NIL;
832 : ListCell *l;
833 :
834 52248 : foreach(l, ((BoolExpr *) node)->args)
835 : {
836 38656 : Node *oldclause = (Node *) lfirst(l);
837 : Node *newclause;
838 :
839 38656 : newclause = pull_up_sublinks_qual_recurse(root,
840 : oldclause,
841 : jtlink1,
842 : available_rels1,
843 : jtlink2,
844 : available_rels2);
845 38656 : if (newclause)
846 36114 : newclauses = lappend(newclauses, newclause);
847 : }
848 : /* We might have got back fewer clauses than we started with */
849 13592 : if (newclauses == NIL)
850 114 : return NULL;
851 13478 : else if (list_length(newclauses) == 1)
852 1066 : return (Node *) linitial(newclauses);
853 : else
854 12412 : return (Node *) make_andclause(newclauses);
855 : }
856 : /* Stop if not an AND */
857 64652 : return node;
858 : }
859 :
860 : /*
861 : * preprocess_function_rtes
862 : * Constant-simplify any FUNCTION RTEs in the FROM clause, and then
863 : * attempt to "inline" any that are set-returning functions.
864 : *
865 : * If an RTE_FUNCTION rtable entry invokes a set-returning function that
866 : * contains just a simple SELECT, we can convert the rtable entry to an
867 : * RTE_SUBQUERY entry exposing the SELECT directly. This is especially
868 : * useful if the subquery can then be "pulled up" for further optimization,
869 : * but we do it even if not, to reduce executor overhead.
870 : *
871 : * This has to be done before we have started to do any optimization of
872 : * subqueries, else any such steps wouldn't get applied to subqueries
873 : * obtained via inlining. However, we do it after pull_up_sublinks
874 : * so that we can inline any functions used in SubLink subselects.
875 : *
876 : * The reason for applying const-simplification at this stage is that
877 : * (a) we'd need to do it anyway to inline a SRF, and (b) by doing it now,
878 : * we can be sure that pull_up_constant_function() will see constants
879 : * if there are constants to be seen. This approach also guarantees
880 : * that every FUNCTION RTE has been const-simplified, allowing planner.c's
881 : * preprocess_expression() to skip doing it again.
882 : *
883 : * Like most of the planner, this feels free to scribble on its input data
884 : * structure.
885 : */
886 : void
887 541000 : preprocess_function_rtes(PlannerInfo *root)
888 : {
889 : ListCell *rt;
890 :
891 1382196 : foreach(rt, root->parse->rtable)
892 : {
893 841202 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
894 :
895 841202 : if (rte->rtekind == RTE_FUNCTION)
896 : {
897 : Query *funcquery;
898 :
899 : /* Apply const-simplification */
900 44724 : rte->functions = (List *)
901 44724 : eval_const_expressions(root, (Node *) rte->functions);
902 :
903 : /* Check safety of expansion, and expand if possible */
904 44724 : funcquery = inline_set_returning_function(root, rte);
905 44718 : if (funcquery)
906 : {
907 : /* Successful expansion, convert the RTE to a subquery */
908 210 : rte->rtekind = RTE_SUBQUERY;
909 210 : rte->subquery = funcquery;
910 210 : rte->security_barrier = false;
911 : /* Clear fields that should not be set in a subquery RTE */
912 210 : rte->functions = NIL;
913 210 : rte->funcordinality = false;
914 : }
915 : }
916 : }
917 540994 : }
918 :
919 : /*
920 : * pull_up_subqueries
921 : * Look for subqueries in the rangetable that can be pulled up into
922 : * the parent query. If the subquery has no special features like
923 : * grouping/aggregation then we can merge it into the parent's jointree.
924 : * Also, subqueries that are simple UNION ALL structures can be
925 : * converted into "append relations".
926 : */
927 : void
928 540994 : pull_up_subqueries(PlannerInfo *root)
929 : {
930 : /* Top level of jointree must always be a FromExpr */
931 : Assert(IsA(root->parse->jointree, FromExpr));
932 : /* Recursion starts with no containing join nor appendrel */
933 1081982 : root->parse->jointree = (FromExpr *)
934 540994 : pull_up_subqueries_recurse(root, (Node *) root->parse->jointree,
935 : NULL, NULL);
936 : /* We should still have a FromExpr */
937 : Assert(IsA(root->parse->jointree, FromExpr));
938 540988 : }
939 :
940 : /*
941 : * pull_up_subqueries_recurse
942 : * Recursive guts of pull_up_subqueries.
943 : *
944 : * This recursively processes the jointree and returns a modified jointree.
945 : *
946 : * If this jointree node is within either side of an outer join, then
947 : * lowest_outer_join references the lowest such JoinExpr node; otherwise
948 : * it is NULL. We use this to constrain the effects of LATERAL subqueries.
949 : *
950 : * If we are looking at a member subquery of an append relation,
951 : * containing_appendrel describes that relation; else it is NULL.
952 : * This forces use of the PlaceHolderVar mechanism for all non-Var targetlist
953 : * items, and puts some additional restrictions on what can be pulled up.
954 : *
955 : * A tricky aspect of this code is that if we pull up a subquery we have
956 : * to replace Vars that reference the subquery's outputs throughout the
957 : * parent query, including quals attached to jointree nodes above the one
958 : * we are currently processing! We handle this by being careful to maintain
959 : * validity of the jointree structure while recursing, in the following sense:
960 : * whenever we recurse, all qual expressions in the tree must be reachable
961 : * from the top level, in case the recursive call needs to modify them.
962 : *
963 : * Notice also that we can't turn pullup_replace_vars loose on the whole
964 : * jointree, because it'd return a mutated copy of the tree; we have to
965 : * invoke it just on the quals, instead. This behavior is what makes it
966 : * reasonable to pass lowest_outer_join as a pointer rather than some
967 : * more-indirect way of identifying the lowest OJ. Likewise, we don't
968 : * replace append_rel_list members but only their substructure, so the
969 : * containing_appendrel reference is safe to use.
970 : */
971 : static Node *
972 1297152 : pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode,
973 : JoinExpr *lowest_outer_join,
974 : AppendRelInfo *containing_appendrel)
975 : {
976 : /* Since this function recurses, it could be driven to stack overflow. */
977 1297152 : check_stack_depth();
978 : /* Also, since it's a bit expensive, let's check for query cancel. */
979 1297152 : CHECK_FOR_INTERRUPTS();
980 :
981 : Assert(jtnode != NULL);
982 1297152 : if (IsA(jtnode, RangeTblRef))
983 : {
984 668366 : int varno = ((RangeTblRef *) jtnode)->rtindex;
985 668366 : RangeTblEntry *rte = rt_fetch(varno, root->parse->rtable);
986 :
987 : /*
988 : * Is this a subquery RTE, and if so, is the subquery simple enough to
989 : * pull up?
990 : *
991 : * If we are looking at an append-relation member, we can't pull it up
992 : * unless is_safe_append_member says so.
993 : */
994 708894 : if (rte->rtekind == RTE_SUBQUERY &&
995 72104 : is_simple_subquery(root, rte->subquery, rte, lowest_outer_join) &&
996 3752 : (containing_appendrel == NULL ||
997 3752 : is_safe_append_member(rte->subquery)))
998 30840 : return pull_up_simple_subquery(root, jtnode, rte,
999 : lowest_outer_join,
1000 : containing_appendrel);
1001 :
1002 : /*
1003 : * Alternatively, is it a simple UNION ALL subquery? If so, flatten
1004 : * into an "append relation".
1005 : *
1006 : * It's safe to do this regardless of whether this query is itself an
1007 : * appendrel member. (If you're thinking we should try to flatten the
1008 : * two levels of appendrel together, you're right; but we handle that
1009 : * in set_append_rel_pathlist, not here.)
1010 : */
1011 647214 : if (rte->rtekind == RTE_SUBQUERY &&
1012 9688 : is_simple_union_all(rte->subquery))
1013 1530 : return pull_up_simple_union_all(root, jtnode, rte);
1014 :
1015 : /*
1016 : * Or perhaps it's a simple VALUES RTE?
1017 : *
1018 : * We don't allow VALUES pullup below an outer join nor into an
1019 : * appendrel (such cases are impossible anyway at the moment).
1020 : */
1021 635996 : if (rte->rtekind == RTE_VALUES &&
1022 9866 : lowest_outer_join == NULL &&
1023 9866 : containing_appendrel == NULL &&
1024 9866 : is_simple_values(root, rte))
1025 1874 : return pull_up_simple_values(root, jtnode, rte);
1026 :
1027 : /*
1028 : * Or perhaps it's a FUNCTION RTE that we could inline?
1029 : */
1030 634122 : if (rte->rtekind == RTE_FUNCTION)
1031 44508 : return pull_up_constant_function(root, jtnode, rte,
1032 : containing_appendrel);
1033 :
1034 : /* Otherwise, do nothing at this node. */
1035 : }
1036 628786 : else if (IsA(jtnode, FromExpr))
1037 : {
1038 547104 : FromExpr *f = (FromExpr *) jtnode;
1039 : ListCell *l;
1040 :
1041 : Assert(containing_appendrel == NULL);
1042 : /* Recursively transform all the child nodes */
1043 1135520 : foreach(l, f->fromlist)
1044 : {
1045 588422 : lfirst(l) = pull_up_subqueries_recurse(root, lfirst(l),
1046 : lowest_outer_join,
1047 : NULL);
1048 : }
1049 : }
1050 81682 : else if (IsA(jtnode, JoinExpr))
1051 : {
1052 81682 : JoinExpr *j = (JoinExpr *) jtnode;
1053 :
1054 : Assert(containing_appendrel == NULL);
1055 : /* Recurse, being careful to tell myself when inside outer join */
1056 81682 : switch (j->jointype)
1057 : {
1058 33862 : case JOIN_INNER:
1059 33862 : j->larg = pull_up_subqueries_recurse(root, j->larg,
1060 : lowest_outer_join,
1061 : NULL);
1062 33862 : j->rarg = pull_up_subqueries_recurse(root, j->rarg,
1063 : lowest_outer_join,
1064 : NULL);
1065 33862 : break;
1066 45670 : case JOIN_LEFT:
1067 : case JOIN_SEMI:
1068 : case JOIN_ANTI:
1069 45670 : j->larg = pull_up_subqueries_recurse(root, j->larg,
1070 : j,
1071 : NULL);
1072 45670 : j->rarg = pull_up_subqueries_recurse(root, j->rarg,
1073 : j,
1074 : NULL);
1075 45670 : break;
1076 1066 : case JOIN_FULL:
1077 1066 : j->larg = pull_up_subqueries_recurse(root, j->larg,
1078 : j,
1079 : NULL);
1080 1066 : j->rarg = pull_up_subqueries_recurse(root, j->rarg,
1081 : j,
1082 : NULL);
1083 1066 : break;
1084 1084 : case JOIN_RIGHT:
1085 1084 : j->larg = pull_up_subqueries_recurse(root, j->larg,
1086 : j,
1087 : NULL);
1088 1084 : j->rarg = pull_up_subqueries_recurse(root, j->rarg,
1089 : j,
1090 : NULL);
1091 1084 : break;
1092 0 : default:
1093 0 : elog(ERROR, "unrecognized join type: %d",
1094 : (int) j->jointype);
1095 : break;
1096 : }
1097 : }
1098 : else
1099 0 : elog(ERROR, "unrecognized node type: %d",
1100 : (int) nodeTag(jtnode));
1101 1218394 : return jtnode;
1102 : }
1103 :
1104 : /*
1105 : * pull_up_simple_subquery
1106 : * Attempt to pull up a single simple subquery.
1107 : *
1108 : * jtnode is a RangeTblRef that has been tentatively identified as a simple
1109 : * subquery by pull_up_subqueries. We return the replacement jointree node,
1110 : * or jtnode itself if we determine that the subquery can't be pulled up
1111 : * after all.
1112 : *
1113 : * rte is the RangeTblEntry referenced by jtnode. Remaining parameters are
1114 : * as for pull_up_subqueries_recurse.
1115 : */
1116 : static Node *
1117 30840 : pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
1118 : JoinExpr *lowest_outer_join,
1119 : AppendRelInfo *containing_appendrel)
1120 : {
1121 30840 : Query *parse = root->parse;
1122 30840 : int varno = ((RangeTblRef *) jtnode)->rtindex;
1123 : Query *subquery;
1124 : PlannerInfo *subroot;
1125 : int rtoffset;
1126 : pullup_replace_vars_context rvcontext;
1127 : ListCell *lc;
1128 :
1129 : /*
1130 : * Make a modifiable copy of the subquery to hack on, so that the RTE will
1131 : * be left unchanged in case we decide below that we can't pull it up
1132 : * after all.
1133 : */
1134 30840 : subquery = copyObject(rte->subquery);
1135 :
1136 : /*
1137 : * Create a PlannerInfo data structure for this subquery.
1138 : *
1139 : * NOTE: the next few steps should match the first processing in
1140 : * subquery_planner(). Can we refactor to avoid code duplication, or
1141 : * would that just make things uglier?
1142 : */
1143 30840 : subroot = makeNode(PlannerInfo);
1144 30840 : subroot->parse = subquery;
1145 30840 : subroot->glob = root->glob;
1146 30840 : subroot->query_level = root->query_level;
1147 30840 : subroot->parent_root = root->parent_root;
1148 30840 : subroot->plan_params = NIL;
1149 30840 : subroot->outer_params = NULL;
1150 30840 : subroot->planner_cxt = CurrentMemoryContext;
1151 30840 : subroot->init_plans = NIL;
1152 30840 : subroot->cte_plan_ids = NIL;
1153 30840 : subroot->multiexpr_params = NIL;
1154 30840 : subroot->join_domains = NIL;
1155 30840 : subroot->eq_classes = NIL;
1156 30840 : subroot->ec_merging_done = false;
1157 30840 : subroot->last_rinfo_serial = 0;
1158 30840 : subroot->all_result_relids = NULL;
1159 30840 : subroot->leaf_result_relids = NULL;
1160 30840 : subroot->append_rel_list = NIL;
1161 30840 : subroot->row_identity_vars = NIL;
1162 30840 : subroot->rowMarks = NIL;
1163 30840 : memset(subroot->upper_rels, 0, sizeof(subroot->upper_rels));
1164 30840 : memset(subroot->upper_targets, 0, sizeof(subroot->upper_targets));
1165 30840 : subroot->processed_groupClause = NIL;
1166 30840 : subroot->processed_distinctClause = NIL;
1167 30840 : subroot->processed_tlist = NIL;
1168 30840 : subroot->update_colnos = NIL;
1169 30840 : subroot->grouping_map = NULL;
1170 30840 : subroot->minmax_aggs = NIL;
1171 30840 : subroot->qual_security_level = 0;
1172 30840 : subroot->placeholdersFrozen = false;
1173 30840 : subroot->hasRecursion = false;
1174 30840 : subroot->wt_param_id = -1;
1175 30840 : subroot->non_recursive_path = NULL;
1176 : /* We don't currently need a top JoinDomain for the subroot */
1177 :
1178 : /* No CTEs to worry about */
1179 : Assert(subquery->cteList == NIL);
1180 :
1181 : /*
1182 : * If the FROM clause is empty, replace it with a dummy RTE_RESULT RTE, so
1183 : * that we don't need so many special cases to deal with that situation.
1184 : */
1185 30840 : replace_empty_jointree(subquery);
1186 :
1187 : /*
1188 : * Pull up any SubLinks within the subquery's quals, so that we don't
1189 : * leave unoptimized SubLinks behind.
1190 : */
1191 30840 : if (subquery->hasSubLinks)
1192 1974 : pull_up_sublinks(subroot);
1193 :
1194 : /*
1195 : * Similarly, preprocess its function RTEs to inline any set-returning
1196 : * functions in its rangetable.
1197 : */
1198 30840 : preprocess_function_rtes(subroot);
1199 :
1200 : /*
1201 : * Recursively pull up the subquery's subqueries, so that
1202 : * pull_up_subqueries' processing is complete for its jointree and
1203 : * rangetable.
1204 : *
1205 : * Note: it's okay that the subquery's recursion starts with NULL for
1206 : * containing-join info, even if we are within an outer join in the upper
1207 : * query; the lower query starts with a clean slate for outer-join
1208 : * semantics. Likewise, we needn't pass down appendrel state.
1209 : */
1210 30840 : pull_up_subqueries(subroot);
1211 :
1212 : /*
1213 : * Now we must recheck whether the subquery is still simple enough to pull
1214 : * up. If not, abandon processing it.
1215 : *
1216 : * We don't really need to recheck all the conditions involved, but it's
1217 : * easier just to keep this "if" looking the same as the one in
1218 : * pull_up_subqueries_recurse.
1219 : */
1220 30840 : if (is_simple_subquery(root, subquery, rte, lowest_outer_join) &&
1221 3016 : (containing_appendrel == NULL || is_safe_append_member(subquery)))
1222 : {
1223 : /* good to go */
1224 : }
1225 : else
1226 : {
1227 : /*
1228 : * Give up, return unmodified RangeTblRef.
1229 : *
1230 : * Note: The work we just did will be redone when the subquery gets
1231 : * planned on its own. Perhaps we could avoid that by storing the
1232 : * modified subquery back into the rangetable, but I'm not gonna risk
1233 : * it now.
1234 : */
1235 116 : return jtnode;
1236 : }
1237 :
1238 : /*
1239 : * We must flatten any join alias Vars in the subquery's targetlist,
1240 : * because pulling up the subquery's subqueries might have changed their
1241 : * expansions into arbitrary expressions, which could affect
1242 : * pullup_replace_vars' decisions about whether PlaceHolderVar wrappers
1243 : * are needed for tlist entries. (Likely it'd be better to do
1244 : * flatten_join_alias_vars on the whole query tree at some earlier stage,
1245 : * maybe even in the rewriter; but for now let's just fix this case here.)
1246 : */
1247 30724 : subquery->targetList = (List *)
1248 30724 : flatten_join_alias_vars(subroot, subroot->parse,
1249 30724 : (Node *) subquery->targetList);
1250 :
1251 : /*
1252 : * Adjust level-0 varnos in subquery so that we can append its rangetable
1253 : * to upper query's. We have to fix the subquery's append_rel_list as
1254 : * well.
1255 : */
1256 30724 : rtoffset = list_length(parse->rtable);
1257 30724 : OffsetVarNodes((Node *) subquery, rtoffset, 0);
1258 30724 : OffsetVarNodes((Node *) subroot->append_rel_list, rtoffset, 0);
1259 :
1260 : /*
1261 : * Upper-level vars in subquery are now one level closer to their parent
1262 : * than before.
1263 : */
1264 30724 : IncrementVarSublevelsUp((Node *) subquery, -1, 1);
1265 30724 : IncrementVarSublevelsUp((Node *) subroot->append_rel_list, -1, 1);
1266 :
1267 : /*
1268 : * The subquery's targetlist items are now in the appropriate form to
1269 : * insert into the top query, except that we may need to wrap them in
1270 : * PlaceHolderVars. Set up required context data for pullup_replace_vars.
1271 : * (Note that we should include the subquery's inner joins in relids,
1272 : * since it may include join alias vars referencing them.)
1273 : */
1274 30724 : rvcontext.root = root;
1275 30724 : rvcontext.targetlist = subquery->targetList;
1276 30724 : rvcontext.target_rte = rte;
1277 30724 : if (rte->lateral)
1278 : {
1279 908 : rvcontext.relids = get_relids_in_jointree((Node *) subquery->jointree,
1280 : true, true);
1281 908 : rvcontext.nullinfo = get_nullingrels(parse);
1282 : }
1283 : else /* won't need these values */
1284 : {
1285 29816 : rvcontext.relids = NULL;
1286 29816 : rvcontext.nullinfo = NULL;
1287 : }
1288 30724 : rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
1289 30724 : rvcontext.varno = varno;
1290 : /* this flag will be set below, if needed */
1291 30724 : rvcontext.wrap_non_vars = false;
1292 : /* initialize cache array with indexes 0 .. length(tlist) */
1293 30724 : rvcontext.rv_cache = palloc0((list_length(subquery->targetList) + 1) *
1294 : sizeof(Node *));
1295 :
1296 : /*
1297 : * If we are dealing with an appendrel member then anything that's not a
1298 : * simple Var has to be turned into a PlaceHolderVar. We force this to
1299 : * ensure that what we pull up doesn't get merged into a surrounding
1300 : * expression during later processing and then fail to match the
1301 : * expression actually available from the appendrel.
1302 : */
1303 30724 : if (containing_appendrel != NULL)
1304 2912 : rvcontext.wrap_non_vars = true;
1305 :
1306 : /*
1307 : * If the parent query uses grouping sets, we need a PlaceHolderVar for
1308 : * anything that's not a simple Var. Again, this ensures that expressions
1309 : * retain their separate identity so that they will match grouping set
1310 : * columns when appropriate. (It'd be sufficient to wrap values used in
1311 : * grouping set columns, and do so only in non-aggregated portions of the
1312 : * tlist and havingQual, but that would require a lot of infrastructure
1313 : * that pullup_replace_vars hasn't currently got.)
1314 : */
1315 30724 : if (parse->groupingSets)
1316 320 : rvcontext.wrap_non_vars = true;
1317 :
1318 : /*
1319 : * Replace all of the top query's references to the subquery's outputs
1320 : * with copies of the adjusted subtlist items, being careful not to
1321 : * replace any of the jointree structure.
1322 : */
1323 30724 : perform_pullup_replace_vars(root, &rvcontext,
1324 : containing_appendrel);
1325 :
1326 : /*
1327 : * If the subquery had a LATERAL marker, propagate that to any of its
1328 : * child RTEs that could possibly now contain lateral cross-references.
1329 : * The children might or might not contain any actual lateral
1330 : * cross-references, but we have to mark the pulled-up child RTEs so that
1331 : * later planner stages will check for such.
1332 : */
1333 30718 : if (rte->lateral)
1334 : {
1335 2176 : foreach(lc, subquery->rtable)
1336 : {
1337 1268 : RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(lc);
1338 :
1339 1268 : switch (child_rte->rtekind)
1340 : {
1341 654 : case RTE_RELATION:
1342 654 : if (child_rte->tablesample)
1343 30 : child_rte->lateral = true;
1344 654 : break;
1345 238 : case RTE_SUBQUERY:
1346 : case RTE_FUNCTION:
1347 : case RTE_VALUES:
1348 : case RTE_TABLEFUNC:
1349 238 : child_rte->lateral = true;
1350 238 : break;
1351 376 : case RTE_JOIN:
1352 : case RTE_CTE:
1353 : case RTE_NAMEDTUPLESTORE:
1354 : case RTE_RESULT:
1355 : case RTE_GROUP:
1356 : /* these can't contain any lateral references */
1357 376 : break;
1358 : }
1359 1268 : }
1360 : }
1361 :
1362 : /*
1363 : * Now append the adjusted rtable entries and their perminfos to upper
1364 : * query. (We hold off until after fixing the upper rtable entries; no
1365 : * point in running that code on the subquery ones too.)
1366 : */
1367 30718 : CombineRangeTables(&parse->rtable, &parse->rteperminfos,
1368 : subquery->rtable, subquery->rteperminfos);
1369 :
1370 : /*
1371 : * Pull up any FOR UPDATE/SHARE markers, too. (OffsetVarNodes already
1372 : * adjusted the marker rtindexes, so just concat the lists.)
1373 : */
1374 30718 : parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks);
1375 :
1376 : /*
1377 : * We also have to fix the relid sets of any PlaceHolderVar nodes in the
1378 : * parent query. (This could perhaps be done by pullup_replace_vars(),
1379 : * but it seems cleaner to use two passes.) Note in particular that any
1380 : * PlaceHolderVar nodes just created by pullup_replace_vars() will be
1381 : * adjusted, so having created them with the subquery's varno is correct.
1382 : *
1383 : * Likewise, relids appearing in AppendRelInfo nodes have to be fixed. We
1384 : * already checked that this won't require introducing multiple subrelids
1385 : * into the single-slot AppendRelInfo structs.
1386 : */
1387 30718 : if (root->glob->lastPHId != 0 || root->append_rel_list)
1388 : {
1389 : Relids subrelids;
1390 :
1391 4492 : subrelids = get_relids_in_jointree((Node *) subquery->jointree,
1392 : true, false);
1393 4492 : if (root->glob->lastPHId != 0)
1394 1634 : substitute_phv_relids((Node *) parse, varno, subrelids);
1395 4492 : fix_append_rel_relids(root, varno, subrelids);
1396 : }
1397 :
1398 : /*
1399 : * And now add subquery's AppendRelInfos to our list.
1400 : */
1401 61436 : root->append_rel_list = list_concat(root->append_rel_list,
1402 30718 : subroot->append_rel_list);
1403 :
1404 : /*
1405 : * We don't have to do the equivalent bookkeeping for outer-join info,
1406 : * because that hasn't been set up yet. placeholder_list likewise.
1407 : */
1408 : Assert(root->join_info_list == NIL);
1409 : Assert(subroot->join_info_list == NIL);
1410 : Assert(root->placeholder_list == NIL);
1411 : Assert(subroot->placeholder_list == NIL);
1412 :
1413 : /*
1414 : * We no longer need the RTE's copy of the subquery's query tree. Getting
1415 : * rid of it saves nothing in particular so far as this level of query is
1416 : * concerned; but if this query level is in turn pulled up into a parent,
1417 : * we'd waste cycles copying the now-unused query tree.
1418 : */
1419 30718 : rte->subquery = NULL;
1420 :
1421 : /*
1422 : * Miscellaneous housekeeping.
1423 : *
1424 : * Although replace_rte_variables() faithfully updated parse->hasSubLinks
1425 : * if it copied any SubLinks out of the subquery's targetlist, we still
1426 : * could have SubLinks added to the query in the expressions of FUNCTION
1427 : * and VALUES RTEs copied up from the subquery. So it's necessary to copy
1428 : * subquery->hasSubLinks anyway. Perhaps this can be improved someday.
1429 : */
1430 30718 : parse->hasSubLinks |= subquery->hasSubLinks;
1431 :
1432 : /* If subquery had any RLS conditions, now main query does too */
1433 30718 : parse->hasRowSecurity |= subquery->hasRowSecurity;
1434 :
1435 : /*
1436 : * subquery won't be pulled up if it hasAggs, hasWindowFuncs, or
1437 : * hasTargetSRFs, so no work needed on those flags
1438 : */
1439 :
1440 : /*
1441 : * Return the adjusted subquery jointree to replace the RangeTblRef entry
1442 : * in parent's jointree; or, if the FromExpr is degenerate, just return
1443 : * its single member.
1444 : */
1445 : Assert(IsA(subquery->jointree, FromExpr));
1446 : Assert(subquery->jointree->fromlist != NIL);
1447 56642 : if (subquery->jointree->quals == NULL &&
1448 25924 : list_length(subquery->jointree->fromlist) == 1)
1449 25610 : return (Node *) linitial(subquery->jointree->fromlist);
1450 :
1451 5108 : return (Node *) subquery->jointree;
1452 : }
1453 :
1454 : /*
1455 : * pull_up_simple_union_all
1456 : * Pull up a single simple UNION ALL subquery.
1457 : *
1458 : * jtnode is a RangeTblRef that has been identified as a simple UNION ALL
1459 : * subquery by pull_up_subqueries. We pull up the leaf subqueries and
1460 : * build an "append relation" for the union set. The result value is just
1461 : * jtnode, since we don't actually need to change the query jointree.
1462 : */
1463 : static Node *
1464 1530 : pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
1465 : {
1466 1530 : int varno = ((RangeTblRef *) jtnode)->rtindex;
1467 1530 : Query *subquery = rte->subquery;
1468 1530 : int rtoffset = list_length(root->parse->rtable);
1469 : List *rtable;
1470 :
1471 : /*
1472 : * Make a modifiable copy of the subquery's rtable, so we can adjust
1473 : * upper-level Vars in it. There are no such Vars in the setOperations
1474 : * tree proper, so fixing the rtable should be sufficient.
1475 : */
1476 1530 : rtable = copyObject(subquery->rtable);
1477 :
1478 : /*
1479 : * Upper-level vars in subquery are now one level closer to their parent
1480 : * than before. We don't have to worry about offsetting varnos, though,
1481 : * because the UNION leaf queries can't cross-reference each other.
1482 : */
1483 1530 : IncrementVarSublevelsUp_rtable(rtable, -1, 1);
1484 :
1485 : /*
1486 : * If the UNION ALL subquery had a LATERAL marker, propagate that to all
1487 : * its children. The individual children might or might not contain any
1488 : * actual lateral cross-references, but we have to mark the pulled-up
1489 : * child RTEs so that later planner stages will check for such.
1490 : */
1491 1530 : if (rte->lateral)
1492 : {
1493 : ListCell *rt;
1494 :
1495 198 : foreach(rt, rtable)
1496 : {
1497 132 : RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(rt);
1498 :
1499 : Assert(child_rte->rtekind == RTE_SUBQUERY);
1500 132 : child_rte->lateral = true;
1501 : }
1502 : }
1503 :
1504 : /*
1505 : * Append child RTEs (and their perminfos) to parent rtable.
1506 : */
1507 1530 : CombineRangeTables(&root->parse->rtable, &root->parse->rteperminfos,
1508 : rtable, subquery->rteperminfos);
1509 :
1510 : /*
1511 : * Recursively scan the subquery's setOperations tree and add
1512 : * AppendRelInfo nodes for leaf subqueries to the parent's
1513 : * append_rel_list. Also apply pull_up_subqueries to the leaf subqueries.
1514 : */
1515 : Assert(subquery->setOperations);
1516 1530 : pull_up_union_leaf_queries(subquery->setOperations, root, varno, subquery,
1517 : rtoffset);
1518 :
1519 : /*
1520 : * Mark the parent as an append relation.
1521 : */
1522 1530 : rte->inh = true;
1523 :
1524 1530 : return jtnode;
1525 : }
1526 :
1527 : /*
1528 : * pull_up_union_leaf_queries -- recursive guts of pull_up_simple_union_all
1529 : *
1530 : * Build an AppendRelInfo for each leaf query in the setop tree, and then
1531 : * apply pull_up_subqueries to the leaf query.
1532 : *
1533 : * Note that setOpQuery is the Query containing the setOp node, whose tlist
1534 : * contains references to all the setop output columns. When called from
1535 : * pull_up_simple_union_all, this is *not* the same as root->parse, which is
1536 : * the parent Query we are pulling up into.
1537 : *
1538 : * parentRTindex is the appendrel parent's index in root->parse->rtable.
1539 : *
1540 : * The child RTEs have already been copied to the parent. childRToffset
1541 : * tells us where in the parent's range table they were copied. When called
1542 : * from flatten_simple_union_all, childRToffset is 0 since the child RTEs
1543 : * were already in root->parse->rtable and no RT index adjustment is needed.
1544 : */
1545 : static void
1546 6866 : pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex,
1547 : Query *setOpQuery, int childRToffset)
1548 : {
1549 6866 : if (IsA(setOp, RangeTblRef))
1550 : {
1551 4372 : RangeTblRef *rtr = (RangeTblRef *) setOp;
1552 : int childRTindex;
1553 : AppendRelInfo *appinfo;
1554 :
1555 : /*
1556 : * Calculate the index in the parent's range table
1557 : */
1558 4372 : childRTindex = childRToffset + rtr->rtindex;
1559 :
1560 : /*
1561 : * Build a suitable AppendRelInfo, and attach to parent's list.
1562 : */
1563 4372 : appinfo = makeNode(AppendRelInfo);
1564 4372 : appinfo->parent_relid = parentRTindex;
1565 4372 : appinfo->child_relid = childRTindex;
1566 4372 : appinfo->parent_reltype = InvalidOid;
1567 4372 : appinfo->child_reltype = InvalidOid;
1568 4372 : make_setop_translation_list(setOpQuery, childRTindex, appinfo);
1569 4372 : appinfo->parent_reloid = InvalidOid;
1570 4372 : root->append_rel_list = lappend(root->append_rel_list, appinfo);
1571 :
1572 : /*
1573 : * Recursively apply pull_up_subqueries to the new child RTE. (We
1574 : * must build the AppendRelInfo first, because this will modify it;
1575 : * indeed, that's the only part of the upper query where Vars
1576 : * referencing childRTindex can exist at this point.)
1577 : *
1578 : * Note that we can pass NULL for containing-join info even if we're
1579 : * actually under an outer join, because the child's expressions
1580 : * aren't going to propagate up to the join. Also, we ignore the
1581 : * possibility that pull_up_subqueries_recurse() returns a different
1582 : * jointree node than what we pass it; if it does, the important thing
1583 : * is that it replaced the child relid in the AppendRelInfo node.
1584 : */
1585 4372 : rtr = makeNode(RangeTblRef);
1586 4372 : rtr->rtindex = childRTindex;
1587 4372 : (void) pull_up_subqueries_recurse(root, (Node *) rtr,
1588 : NULL, appinfo);
1589 : }
1590 2494 : else if (IsA(setOp, SetOperationStmt))
1591 : {
1592 2494 : SetOperationStmt *op = (SetOperationStmt *) setOp;
1593 :
1594 : /* Recurse to reach leaf queries */
1595 2494 : pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery,
1596 : childRToffset);
1597 2494 : pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery,
1598 : childRToffset);
1599 : }
1600 : else
1601 : {
1602 0 : elog(ERROR, "unrecognized node type: %d",
1603 : (int) nodeTag(setOp));
1604 : }
1605 6866 : }
1606 :
1607 : /*
1608 : * make_setop_translation_list
1609 : * Build the list of translations from parent Vars to child Vars for
1610 : * a UNION ALL member. (At this point it's just a simple list of
1611 : * referencing Vars, but if we succeed in pulling up the member
1612 : * subquery, the Vars will get replaced by pulled-up expressions.)
1613 : * Also create the rather trivial reverse-translation array.
1614 : */
1615 : static void
1616 4372 : make_setop_translation_list(Query *query, int newvarno,
1617 : AppendRelInfo *appinfo)
1618 : {
1619 4372 : List *vars = NIL;
1620 : AttrNumber *pcolnos;
1621 : ListCell *l;
1622 :
1623 : /* Initialize reverse-translation array with all entries zero */
1624 : /* (entries for resjunk columns will stay that way) */
1625 4372 : appinfo->num_child_cols = list_length(query->targetList);
1626 4372 : appinfo->parent_colnos = pcolnos =
1627 4372 : (AttrNumber *) palloc0(appinfo->num_child_cols * sizeof(AttrNumber));
1628 :
1629 13994 : foreach(l, query->targetList)
1630 : {
1631 9622 : TargetEntry *tle = (TargetEntry *) lfirst(l);
1632 :
1633 9622 : if (tle->resjunk)
1634 0 : continue;
1635 :
1636 9622 : vars = lappend(vars, makeVarFromTargetEntry(newvarno, tle));
1637 9622 : pcolnos[tle->resno - 1] = tle->resno;
1638 : }
1639 :
1640 4372 : appinfo->translated_vars = vars;
1641 4372 : }
1642 :
1643 : /*
1644 : * is_simple_subquery
1645 : * Check a subquery in the range table to see if it's simple enough
1646 : * to pull up into the parent query.
1647 : *
1648 : * rte is the RTE_SUBQUERY RangeTblEntry that contained the subquery.
1649 : * (Note subquery is not necessarily equal to rte->subquery; it could be a
1650 : * processed copy of that.)
1651 : * lowest_outer_join is the lowest outer join above the subquery, or NULL.
1652 : */
1653 : static bool
1654 71368 : is_simple_subquery(PlannerInfo *root, Query *subquery, RangeTblEntry *rte,
1655 : JoinExpr *lowest_outer_join)
1656 : {
1657 : /*
1658 : * Let's just make sure it's a valid subselect ...
1659 : */
1660 71368 : if (!IsA(subquery, Query) ||
1661 71368 : subquery->commandType != CMD_SELECT)
1662 0 : elog(ERROR, "subquery is bogus");
1663 :
1664 : /*
1665 : * Can't currently pull up a query with setops (unless it's simple UNION
1666 : * ALL, which is handled by a different code path). Maybe after querytree
1667 : * redesign...
1668 : */
1669 71368 : if (subquery->setOperations)
1670 2132 : return false;
1671 :
1672 : /*
1673 : * Can't pull up a subquery involving grouping, aggregation, SRFs,
1674 : * sorting, limiting, or WITH. (XXX WITH could possibly be allowed later)
1675 : *
1676 : * We also don't pull up a subquery that has explicit FOR UPDATE/SHARE
1677 : * clauses, because pullup would cause the locking to occur semantically
1678 : * higher than it should. Implicit FOR UPDATE/SHARE is okay because in
1679 : * that case the locking was originally declared in the upper query
1680 : * anyway.
1681 : */
1682 69236 : if (subquery->hasAggs ||
1683 67754 : subquery->hasWindowFuncs ||
1684 67376 : subquery->hasTargetSRFs ||
1685 65782 : subquery->groupClause ||
1686 65714 : subquery->groupingSets ||
1687 65714 : subquery->havingQual ||
1688 65714 : subquery->sortClause ||
1689 64854 : subquery->distinctClause ||
1690 64604 : subquery->limitOffset ||
1691 64214 : subquery->limitCount ||
1692 63946 : subquery->hasForUpdate ||
1693 63328 : subquery->cteList)
1694 6070 : return false;
1695 :
1696 : /*
1697 : * Don't pull up if the RTE represents a security-barrier view; we
1698 : * couldn't prevent information leakage once the RTE's Vars are scattered
1699 : * about in the upper query.
1700 : */
1701 63166 : if (rte->security_barrier)
1702 492 : return false;
1703 :
1704 : /*
1705 : * If the subquery is LATERAL, check for pullup restrictions from that.
1706 : */
1707 62674 : if (rte->lateral)
1708 : {
1709 : bool restricted;
1710 : Relids safe_upper_varnos;
1711 :
1712 : /*
1713 : * The subquery's WHERE and JOIN/ON quals mustn't contain any lateral
1714 : * references to rels outside a higher outer join (including the case
1715 : * where the outer join is within the subquery itself). In such a
1716 : * case, pulling up would result in a situation where we need to
1717 : * postpone quals from below an outer join to above it, which is
1718 : * probably completely wrong and in any case is a complication that
1719 : * doesn't seem worth addressing at the moment.
1720 : */
1721 1906 : if (lowest_outer_join != NULL)
1722 : {
1723 900 : restricted = true;
1724 900 : safe_upper_varnos = get_relids_in_jointree((Node *) lowest_outer_join,
1725 : true, true);
1726 : }
1727 : else
1728 : {
1729 1006 : restricted = false;
1730 1006 : safe_upper_varnos = NULL; /* doesn't matter */
1731 : }
1732 :
1733 1906 : if (jointree_contains_lateral_outer_refs(root,
1734 1906 : (Node *) subquery->jointree,
1735 : restricted, safe_upper_varnos))
1736 24 : return false;
1737 :
1738 : /*
1739 : * If there's an outer join above the LATERAL subquery, also disallow
1740 : * pullup if the subquery's targetlist has any references to rels
1741 : * outside the outer join, since these might get pulled into quals
1742 : * above the subquery (but in or below the outer join) and then lead
1743 : * to qual-postponement issues similar to the case checked for above.
1744 : * (We wouldn't need to prevent pullup if no such references appear in
1745 : * outer-query quals, but we don't have enough info here to check
1746 : * that. Also, maybe this restriction could be removed if we forced
1747 : * such refs to be wrapped in PlaceHolderVars, even when they're below
1748 : * the nearest outer join? But it's a pretty hokey usage, so not
1749 : * clear this is worth sweating over.)
1750 : *
1751 : * If you change this, see also the comments about lateral references
1752 : * in pullup_replace_vars_callback().
1753 : */
1754 1882 : if (lowest_outer_join != NULL)
1755 : {
1756 900 : Relids lvarnos = pull_varnos_of_level(root,
1757 900 : (Node *) subquery->targetList,
1758 : 1);
1759 :
1760 900 : if (!bms_is_subset(lvarnos, safe_upper_varnos))
1761 12 : return false;
1762 : }
1763 : }
1764 :
1765 : /*
1766 : * Don't pull up a subquery that has any volatile functions in its
1767 : * targetlist. Otherwise we might introduce multiple evaluations of these
1768 : * functions, if they get copied to multiple places in the upper query,
1769 : * leading to surprising results. (Note: the PlaceHolderVar mechanism
1770 : * doesn't quite guarantee single evaluation; else we could pull up anyway
1771 : * and just wrap such items in PlaceHolderVars ...)
1772 : */
1773 62638 : if (contain_volatile_functions((Node *) subquery->targetList))
1774 234 : return false;
1775 :
1776 62404 : return true;
1777 : }
1778 :
1779 : /*
1780 : * pull_up_simple_values
1781 : * Pull up a single simple VALUES RTE.
1782 : *
1783 : * jtnode is a RangeTblRef that has been identified as a simple VALUES RTE
1784 : * by pull_up_subqueries. We always return a RangeTblRef representing a
1785 : * RESULT RTE to replace it (all failure cases should have been detected by
1786 : * is_simple_values()). Actually, what we return is just jtnode, because
1787 : * we replace the VALUES RTE in the rangetable with the RESULT RTE.
1788 : *
1789 : * rte is the RangeTblEntry referenced by jtnode. Because of the limited
1790 : * possible usage of VALUES RTEs, we do not need the remaining parameters
1791 : * of pull_up_subqueries_recurse.
1792 : */
1793 : static Node *
1794 1874 : pull_up_simple_values(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
1795 : {
1796 1874 : Query *parse = root->parse;
1797 1874 : int varno = ((RangeTblRef *) jtnode)->rtindex;
1798 : List *values_list;
1799 : List *tlist;
1800 : AttrNumber attrno;
1801 : pullup_replace_vars_context rvcontext;
1802 : ListCell *lc;
1803 :
1804 : Assert(rte->rtekind == RTE_VALUES);
1805 : Assert(list_length(rte->values_lists) == 1);
1806 :
1807 : /*
1808 : * Need a modifiable copy of the VALUES list to hack on, just in case it's
1809 : * multiply referenced.
1810 : */
1811 1874 : values_list = copyObject(linitial(rte->values_lists));
1812 :
1813 : /*
1814 : * The VALUES RTE can't contain any Vars of level zero, let alone any that
1815 : * are join aliases, so no need to flatten join alias Vars.
1816 : */
1817 : Assert(!contain_vars_of_level((Node *) values_list, 0));
1818 :
1819 : /*
1820 : * Set up required context data for pullup_replace_vars. In particular,
1821 : * we have to make the VALUES list look like a subquery targetlist.
1822 : */
1823 1874 : tlist = NIL;
1824 1874 : attrno = 1;
1825 4372 : foreach(lc, values_list)
1826 : {
1827 2498 : tlist = lappend(tlist,
1828 2498 : makeTargetEntry((Expr *) lfirst(lc),
1829 : attrno,
1830 : NULL,
1831 : false));
1832 2498 : attrno++;
1833 : }
1834 1874 : rvcontext.root = root;
1835 1874 : rvcontext.targetlist = tlist;
1836 1874 : rvcontext.target_rte = rte;
1837 1874 : rvcontext.relids = NULL; /* can't be any lateral references here */
1838 1874 : rvcontext.nullinfo = NULL;
1839 1874 : rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
1840 1874 : rvcontext.varno = varno;
1841 1874 : rvcontext.wrap_non_vars = false;
1842 : /* initialize cache array with indexes 0 .. length(tlist) */
1843 1874 : rvcontext.rv_cache = palloc0((list_length(tlist) + 1) *
1844 : sizeof(Node *));
1845 :
1846 : /*
1847 : * Replace all of the top query's references to the RTE's outputs with
1848 : * copies of the adjusted VALUES expressions, being careful not to replace
1849 : * any of the jointree structure. We can assume there's no outer joins or
1850 : * appendrels in the dummy Query that surrounds a VALUES RTE.
1851 : */
1852 1874 : perform_pullup_replace_vars(root, &rvcontext, NULL);
1853 :
1854 : /*
1855 : * There should be no appendrels to fix, nor any outer joins and hence no
1856 : * PlaceHolderVars.
1857 : */
1858 : Assert(root->append_rel_list == NIL);
1859 : Assert(root->join_info_list == NIL);
1860 : Assert(root->placeholder_list == NIL);
1861 :
1862 : /*
1863 : * Replace the VALUES RTE with a RESULT RTE. The VALUES RTE is the only
1864 : * rtable entry in the current query level, so this is easy.
1865 : */
1866 : Assert(list_length(parse->rtable) == 1);
1867 :
1868 : /* Create suitable RTE */
1869 1874 : rte = makeNode(RangeTblEntry);
1870 1874 : rte->rtekind = RTE_RESULT;
1871 1874 : rte->eref = makeAlias("*RESULT*", NIL);
1872 :
1873 : /* Replace rangetable */
1874 1874 : parse->rtable = list_make1(rte);
1875 :
1876 : /* We could manufacture a new RangeTblRef, but the one we have is fine */
1877 : Assert(varno == 1);
1878 :
1879 1874 : return jtnode;
1880 : }
1881 :
1882 : /*
1883 : * is_simple_values
1884 : * Check a VALUES RTE in the range table to see if it's simple enough
1885 : * to pull up into the parent query.
1886 : *
1887 : * rte is the RTE_VALUES RangeTblEntry to check.
1888 : */
1889 : static bool
1890 9866 : is_simple_values(PlannerInfo *root, RangeTblEntry *rte)
1891 : {
1892 : Assert(rte->rtekind == RTE_VALUES);
1893 :
1894 : /*
1895 : * There must be exactly one VALUES list, else it's not semantically
1896 : * correct to replace the VALUES RTE with a RESULT RTE, nor would we have
1897 : * a unique set of expressions to substitute into the parent query.
1898 : */
1899 9866 : if (list_length(rte->values_lists) != 1)
1900 7992 : return false;
1901 :
1902 : /*
1903 : * Because VALUES can't appear under an outer join (or at least, we won't
1904 : * try to pull it up if it does), we need not worry about LATERAL, nor
1905 : * about validity of PHVs for the VALUES' outputs.
1906 : */
1907 :
1908 : /*
1909 : * Don't pull up a VALUES that contains any set-returning or volatile
1910 : * functions. The considerations here are basically identical to the
1911 : * restrictions on a pull-able subquery's targetlist.
1912 : */
1913 3748 : if (expression_returns_set((Node *) rte->values_lists) ||
1914 1874 : contain_volatile_functions((Node *) rte->values_lists))
1915 0 : return false;
1916 :
1917 : /*
1918 : * Do not pull up a VALUES that's not the only RTE in its parent query.
1919 : * This is actually the only case that the parser will generate at the
1920 : * moment, and assuming this is true greatly simplifies
1921 : * pull_up_simple_values().
1922 : */
1923 1874 : if (list_length(root->parse->rtable) != 1 ||
1924 1874 : rte != (RangeTblEntry *) linitial(root->parse->rtable))
1925 0 : return false;
1926 :
1927 1874 : return true;
1928 : }
1929 :
1930 : /*
1931 : * pull_up_constant_function
1932 : * Pull up an RTE_FUNCTION expression that was simplified to a constant.
1933 : *
1934 : * jtnode is a RangeTblRef that has been identified as a FUNCTION RTE by
1935 : * pull_up_subqueries. If its expression is just a Const, hoist that value
1936 : * up into the parent query, and replace the RTE_FUNCTION with RTE_RESULT.
1937 : *
1938 : * In principle we could pull up any immutable expression, but we don't.
1939 : * That might result in multiple evaluations of the expression, which could
1940 : * be costly if it's not just a Const. Also, the main value of this is
1941 : * to let the constant participate in further const-folding, and of course
1942 : * that won't happen for a non-Const.
1943 : *
1944 : * The pulled-up value might need to be wrapped in a PlaceHolderVar if the
1945 : * RTE is below an outer join or is part of an appendrel; the extra
1946 : * parameters show whether that's needed.
1947 : */
1948 : static Node *
1949 44508 : pull_up_constant_function(PlannerInfo *root, Node *jtnode,
1950 : RangeTblEntry *rte,
1951 : AppendRelInfo *containing_appendrel)
1952 : {
1953 44508 : Query *parse = root->parse;
1954 : RangeTblFunction *rtf;
1955 : TypeFuncClass functypclass;
1956 : Oid funcrettype;
1957 : TupleDesc tupdesc;
1958 : pullup_replace_vars_context rvcontext;
1959 :
1960 : /* Fail if the RTE has ORDINALITY - we don't implement that here. */
1961 44508 : if (rte->funcordinality)
1962 698 : return jtnode;
1963 :
1964 : /* Fail if RTE isn't a single, simple Const expr */
1965 43810 : if (list_length(rte->functions) != 1)
1966 72 : return jtnode;
1967 43738 : rtf = linitial_node(RangeTblFunction, rte->functions);
1968 43738 : if (!IsA(rtf->funcexpr, Const))
1969 43366 : return jtnode;
1970 :
1971 : /*
1972 : * If the function's result is not a scalar, we punt. In principle we
1973 : * could break the composite constant value apart into per-column
1974 : * constants, but for now it seems not worth the work.
1975 : */
1976 372 : if (rtf->funccolcount != 1)
1977 30 : return jtnode; /* definitely composite */
1978 :
1979 : /* If it has a coldeflist, it certainly returns RECORD */
1980 342 : if (rtf->funccolnames != NIL)
1981 0 : return jtnode; /* must be a one-column RECORD type */
1982 :
1983 342 : functypclass = get_expr_result_type(rtf->funcexpr,
1984 : &funcrettype,
1985 : &tupdesc);
1986 342 : if (functypclass != TYPEFUNC_SCALAR)
1987 12 : return jtnode; /* must be a one-column composite type */
1988 :
1989 : /* Create context for applying pullup_replace_vars */
1990 330 : rvcontext.root = root;
1991 330 : rvcontext.targetlist = list_make1(makeTargetEntry((Expr *) rtf->funcexpr,
1992 : 1, /* resno */
1993 : NULL, /* resname */
1994 : false)); /* resjunk */
1995 330 : rvcontext.target_rte = rte;
1996 :
1997 : /*
1998 : * Since this function was reduced to a Const, it doesn't contain any
1999 : * lateral references, even if it's marked as LATERAL. This means we
2000 : * don't need to fill relids or nullinfo.
2001 : */
2002 330 : rvcontext.relids = NULL;
2003 330 : rvcontext.nullinfo = NULL;
2004 :
2005 330 : rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
2006 330 : rvcontext.varno = ((RangeTblRef *) jtnode)->rtindex;
2007 : /* this flag will be set below, if needed */
2008 330 : rvcontext.wrap_non_vars = false;
2009 : /* initialize cache array with indexes 0 .. length(tlist) */
2010 330 : rvcontext.rv_cache = palloc0((list_length(rvcontext.targetlist) + 1) *
2011 : sizeof(Node *));
2012 :
2013 : /*
2014 : * If we are dealing with an appendrel member then anything that's not a
2015 : * simple Var has to be turned into a PlaceHolderVar. (See comments in
2016 : * pull_up_simple_subquery().)
2017 : */
2018 330 : if (containing_appendrel != NULL)
2019 0 : rvcontext.wrap_non_vars = true;
2020 :
2021 : /*
2022 : * If the parent query uses grouping sets, we need a PlaceHolderVar for
2023 : * anything that's not a simple Var.
2024 : */
2025 330 : if (parse->groupingSets)
2026 0 : rvcontext.wrap_non_vars = true;
2027 :
2028 : /*
2029 : * Replace all of the top query's references to the RTE's output with
2030 : * copies of the funcexpr, being careful not to replace any of the
2031 : * jointree structure.
2032 : */
2033 330 : perform_pullup_replace_vars(root, &rvcontext,
2034 : containing_appendrel);
2035 :
2036 : /*
2037 : * We don't need to bother with changing PlaceHolderVars in the parent
2038 : * query. Their references to the RT index are still good for now, and
2039 : * will get removed later if we're able to drop the RTE_RESULT.
2040 : */
2041 :
2042 : /*
2043 : * Convert the RTE to be RTE_RESULT type, signifying that we don't need to
2044 : * scan it anymore, and zero out RTE_FUNCTION-specific fields. Also make
2045 : * sure the RTE is not marked LATERAL, since elsewhere we don't expect
2046 : * RTE_RESULTs to be LATERAL.
2047 : */
2048 330 : rte->rtekind = RTE_RESULT;
2049 330 : rte->functions = NIL;
2050 330 : rte->lateral = false;
2051 :
2052 : /*
2053 : * We can reuse the RangeTblRef node.
2054 : */
2055 330 : return jtnode;
2056 : }
2057 :
2058 : /*
2059 : * is_simple_union_all
2060 : * Check a subquery to see if it's a simple UNION ALL.
2061 : *
2062 : * We require all the setops to be UNION ALL (no mixing) and there can't be
2063 : * any datatype coercions involved, ie, all the leaf queries must emit the
2064 : * same datatypes.
2065 : */
2066 : static bool
2067 9688 : is_simple_union_all(Query *subquery)
2068 : {
2069 : SetOperationStmt *topop;
2070 :
2071 : /* Let's just make sure it's a valid subselect ... */
2072 9688 : if (!IsA(subquery, Query) ||
2073 9688 : subquery->commandType != CMD_SELECT)
2074 0 : elog(ERROR, "subquery is bogus");
2075 :
2076 : /* Is it a set-operation query at all? */
2077 9688 : topop = castNode(SetOperationStmt, subquery->setOperations);
2078 9688 : if (!topop)
2079 7556 : return false;
2080 :
2081 : /* Can't handle ORDER BY, LIMIT/OFFSET, locking, or WITH */
2082 2132 : if (subquery->sortClause ||
2083 2068 : subquery->limitOffset ||
2084 2068 : subquery->limitCount ||
2085 2068 : subquery->rowMarks ||
2086 2068 : subquery->cteList)
2087 156 : return false;
2088 :
2089 : /* Recursively check the tree of set operations */
2090 1976 : return is_simple_union_all_recurse((Node *) topop, subquery,
2091 : topop->colTypes);
2092 : }
2093 :
2094 : static bool
2095 13436 : is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
2096 : {
2097 : /* Since this function recurses, it could be driven to stack overflow. */
2098 13436 : check_stack_depth();
2099 :
2100 13436 : if (IsA(setOp, RangeTblRef))
2101 : {
2102 5412 : RangeTblRef *rtr = (RangeTblRef *) setOp;
2103 5412 : RangeTblEntry *rte = rt_fetch(rtr->rtindex, setOpQuery->rtable);
2104 5412 : Query *subquery = rte->subquery;
2105 :
2106 : Assert(subquery != NULL);
2107 :
2108 : /* Leaf nodes are OK if they match the toplevel column types */
2109 : /* We don't have to compare typmods or collations here */
2110 5412 : return tlist_same_datatypes(subquery->targetList, colTypes, true);
2111 : }
2112 8024 : else if (IsA(setOp, SetOperationStmt))
2113 : {
2114 8024 : SetOperationStmt *op = (SetOperationStmt *) setOp;
2115 :
2116 : /* Must be UNION ALL */
2117 8024 : if (op->op != SETOP_UNION || !op->all)
2118 4562 : return false;
2119 :
2120 : /* Recurse to check inputs */
2121 6430 : return is_simple_union_all_recurse(op->larg, setOpQuery, colTypes) &&
2122 2968 : is_simple_union_all_recurse(op->rarg, setOpQuery, colTypes);
2123 : }
2124 : else
2125 : {
2126 0 : elog(ERROR, "unrecognized node type: %d",
2127 : (int) nodeTag(setOp));
2128 : return false; /* keep compiler quiet */
2129 : }
2130 : }
2131 :
2132 : /*
2133 : * is_safe_append_member
2134 : * Check a subquery that is a leaf of a UNION ALL appendrel to see if it's
2135 : * safe to pull up.
2136 : */
2137 : static bool
2138 6768 : is_safe_append_member(Query *subquery)
2139 : {
2140 : FromExpr *jtnode;
2141 :
2142 : /*
2143 : * It's only safe to pull up the child if its jointree contains exactly
2144 : * one RTE, else the AppendRelInfo data structure breaks. The one base RTE
2145 : * could be buried in several levels of FromExpr, however. Also, if the
2146 : * child's jointree is completely empty, we can pull up because
2147 : * pull_up_simple_subquery will insert a single RTE_RESULT RTE instead.
2148 : *
2149 : * Also, the child can't have any WHERE quals because there's no place to
2150 : * put them in an appendrel. (This is a bit annoying...) If we didn't
2151 : * need to check this, we'd just test whether get_relids_in_jointree()
2152 : * yields a singleton set, to be more consistent with the coding of
2153 : * fix_append_rel_relids().
2154 : */
2155 6768 : jtnode = subquery->jointree;
2156 : Assert(IsA(jtnode, FromExpr));
2157 : /* Check the completely-empty case */
2158 6768 : if (jtnode->fromlist == NIL && jtnode->quals == NULL)
2159 542 : return true;
2160 : /* Check the more general case */
2161 11766 : while (IsA(jtnode, FromExpr))
2162 : {
2163 6238 : if (jtnode->quals != NULL)
2164 698 : return false;
2165 5540 : if (list_length(jtnode->fromlist) != 1)
2166 0 : return false;
2167 5540 : jtnode = linitial(jtnode->fromlist);
2168 : }
2169 5528 : if (!IsA(jtnode, RangeTblRef))
2170 142 : return false;
2171 :
2172 5386 : return true;
2173 : }
2174 :
2175 : /*
2176 : * jointree_contains_lateral_outer_refs
2177 : * Check for disallowed lateral references in a jointree's quals
2178 : *
2179 : * If restricted is false, all level-1 Vars are allowed (but we still must
2180 : * search the jointree, since it might contain outer joins below which there
2181 : * will be restrictions). If restricted is true, return true when any qual
2182 : * in the jointree contains level-1 Vars coming from outside the rels listed
2183 : * in safe_upper_varnos.
2184 : */
2185 : static bool
2186 4302 : jointree_contains_lateral_outer_refs(PlannerInfo *root, Node *jtnode,
2187 : bool restricted,
2188 : Relids safe_upper_varnos)
2189 : {
2190 4302 : if (jtnode == NULL)
2191 0 : return false;
2192 4302 : if (IsA(jtnode, RangeTblRef))
2193 2070 : return false;
2194 2232 : else if (IsA(jtnode, FromExpr))
2195 : {
2196 1942 : FromExpr *f = (FromExpr *) jtnode;
2197 : ListCell *l;
2198 :
2199 : /* First, recurse to check child joins */
2200 3734 : foreach(l, f->fromlist)
2201 : {
2202 1816 : if (jointree_contains_lateral_outer_refs(root,
2203 1816 : lfirst(l),
2204 : restricted,
2205 : safe_upper_varnos))
2206 24 : return true;
2207 : }
2208 :
2209 : /* Then check the top-level quals */
2210 1918 : if (restricted &&
2211 936 : !bms_is_subset(pull_varnos_of_level(root, f->quals, 1),
2212 : safe_upper_varnos))
2213 0 : return true;
2214 : }
2215 290 : else if (IsA(jtnode, JoinExpr))
2216 : {
2217 290 : JoinExpr *j = (JoinExpr *) jtnode;
2218 :
2219 : /*
2220 : * If this is an outer join, we mustn't allow any upper lateral
2221 : * references in or below it.
2222 : */
2223 290 : if (j->jointype != JOIN_INNER)
2224 : {
2225 146 : restricted = true;
2226 146 : safe_upper_varnos = NULL;
2227 : }
2228 :
2229 : /* Check the child joins */
2230 290 : if (jointree_contains_lateral_outer_refs(root,
2231 : j->larg,
2232 : restricted,
2233 : safe_upper_varnos))
2234 0 : return true;
2235 290 : if (jointree_contains_lateral_outer_refs(root,
2236 : j->rarg,
2237 : restricted,
2238 : safe_upper_varnos))
2239 0 : return true;
2240 :
2241 : /* Check the JOIN's qual clauses */
2242 290 : if (restricted &&
2243 266 : !bms_is_subset(pull_varnos_of_level(root, j->quals, 1),
2244 : safe_upper_varnos))
2245 24 : return true;
2246 : }
2247 : else
2248 0 : elog(ERROR, "unrecognized node type: %d",
2249 : (int) nodeTag(jtnode));
2250 2184 : return false;
2251 : }
2252 :
2253 : /*
2254 : * Perform pullup_replace_vars everyplace it's needed in the query tree.
2255 : *
2256 : * Caller has already filled *rvcontext with data describing what to
2257 : * substitute for Vars referencing the target subquery. In addition
2258 : * we need the identity of the containing appendrel if any.
2259 : */
2260 : static void
2261 32928 : perform_pullup_replace_vars(PlannerInfo *root,
2262 : pullup_replace_vars_context *rvcontext,
2263 : AppendRelInfo *containing_appendrel)
2264 : {
2265 32928 : Query *parse = root->parse;
2266 : ListCell *lc;
2267 :
2268 : /*
2269 : * If we are considering an appendrel child subquery (that is, a UNION ALL
2270 : * member query that we're pulling up), then the only part of the upper
2271 : * query that could reference the child yet is the translated_vars list of
2272 : * the associated AppendRelInfo. Furthermore, we do not want to force use
2273 : * of PHVs in the AppendRelInfo --- there isn't any outer join between.
2274 : */
2275 32928 : if (containing_appendrel)
2276 : {
2277 2912 : bool save_wrap_non_vars = rvcontext->wrap_non_vars;
2278 :
2279 2912 : rvcontext->wrap_non_vars = false;
2280 2912 : containing_appendrel->translated_vars = (List *)
2281 2912 : pullup_replace_vars((Node *) containing_appendrel->translated_vars,
2282 : rvcontext);
2283 2912 : rvcontext->wrap_non_vars = save_wrap_non_vars;
2284 2912 : return;
2285 : }
2286 :
2287 : /*
2288 : * Replace all of the top query's references to the subquery's outputs
2289 : * with copies of the adjusted subtlist items, being careful not to
2290 : * replace any of the jointree structure. (This'd be a lot cleaner if we
2291 : * could use query_tree_mutator.) We have to use PHVs in the targetList,
2292 : * returningList, and havingQual, since those are certainly above any
2293 : * outer join. replace_vars_in_jointree tracks its location in the
2294 : * jointree and uses PHVs or not appropriately.
2295 : */
2296 30016 : parse->targetList = (List *)
2297 30016 : pullup_replace_vars((Node *) parse->targetList, rvcontext);
2298 30016 : parse->returningList = (List *)
2299 30016 : pullup_replace_vars((Node *) parse->returningList, rvcontext);
2300 :
2301 30016 : if (parse->onConflict)
2302 : {
2303 44 : parse->onConflict->onConflictSet = (List *)
2304 22 : pullup_replace_vars((Node *) parse->onConflict->onConflictSet,
2305 : rvcontext);
2306 22 : parse->onConflict->onConflictWhere =
2307 22 : pullup_replace_vars(parse->onConflict->onConflictWhere,
2308 : rvcontext);
2309 :
2310 : /*
2311 : * We assume ON CONFLICT's arbiterElems, arbiterWhere, exclRelTlist
2312 : * can't contain any references to a subquery.
2313 : */
2314 : }
2315 30016 : if (parse->mergeActionList)
2316 : {
2317 2708 : foreach(lc, parse->mergeActionList)
2318 : {
2319 1610 : MergeAction *action = lfirst(lc);
2320 :
2321 1610 : action->qual = pullup_replace_vars(action->qual, rvcontext);
2322 1610 : action->targetList = (List *)
2323 1610 : pullup_replace_vars((Node *) action->targetList, rvcontext);
2324 : }
2325 : }
2326 30016 : parse->mergeJoinCondition = pullup_replace_vars(parse->mergeJoinCondition,
2327 : rvcontext);
2328 30016 : replace_vars_in_jointree((Node *) parse->jointree, rvcontext);
2329 : Assert(parse->setOperations == NULL);
2330 30010 : parse->havingQual = pullup_replace_vars(parse->havingQual, rvcontext);
2331 :
2332 : /*
2333 : * Replace references in the translated_vars lists of appendrels.
2334 : */
2335 30022 : foreach(lc, root->append_rel_list)
2336 : {
2337 12 : AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
2338 :
2339 12 : appinfo->translated_vars = (List *)
2340 12 : pullup_replace_vars((Node *) appinfo->translated_vars, rvcontext);
2341 : }
2342 :
2343 : /*
2344 : * Replace references in the joinaliasvars lists of join RTEs and the
2345 : * groupexprs list of group RTE.
2346 : */
2347 85172 : foreach(lc, parse->rtable)
2348 : {
2349 55162 : RangeTblEntry *otherrte = (RangeTblEntry *) lfirst(lc);
2350 :
2351 55162 : if (otherrte->rtekind == RTE_JOIN)
2352 5696 : otherrte->joinaliasvars = (List *)
2353 5696 : pullup_replace_vars((Node *) otherrte->joinaliasvars,
2354 : rvcontext);
2355 49466 : else if (otherrte->rtekind == RTE_GROUP)
2356 724 : otherrte->groupexprs = (List *)
2357 724 : pullup_replace_vars((Node *) otherrte->groupexprs,
2358 : rvcontext);
2359 : }
2360 : }
2361 :
2362 : /*
2363 : * Helper routine for perform_pullup_replace_vars: do pullup_replace_vars on
2364 : * every expression in the jointree, without changing the jointree structure
2365 : * itself. Ugly, but there's no other way...
2366 : */
2367 : static void
2368 78422 : replace_vars_in_jointree(Node *jtnode,
2369 : pullup_replace_vars_context *context)
2370 : {
2371 78422 : if (jtnode == NULL)
2372 0 : return;
2373 78422 : if (IsA(jtnode, RangeTblRef))
2374 : {
2375 : /*
2376 : * If the RangeTblRef refers to a LATERAL subquery (that isn't the
2377 : * same subquery we're pulling up), it might contain references to the
2378 : * target subquery, which we must replace. We drive this from the
2379 : * jointree scan, rather than a scan of the rtable, so that we can
2380 : * avoid processing no-longer-referenced RTEs.
2381 : */
2382 39390 : int varno = ((RangeTblRef *) jtnode)->rtindex;
2383 :
2384 39390 : if (varno != context->varno) /* ignore target subquery itself */
2385 : {
2386 9374 : RangeTblEntry *rte = rt_fetch(varno, context->root->parse->rtable);
2387 :
2388 : Assert(rte != context->target_rte);
2389 9374 : if (rte->lateral)
2390 : {
2391 852 : switch (rte->rtekind)
2392 : {
2393 0 : case RTE_RELATION:
2394 : /* shouldn't be marked LATERAL unless tablesample */
2395 : Assert(rte->tablesample);
2396 0 : rte->tablesample = (TableSampleClause *)
2397 0 : pullup_replace_vars((Node *) rte->tablesample,
2398 : context);
2399 0 : break;
2400 408 : case RTE_SUBQUERY:
2401 408 : rte->subquery =
2402 408 : pullup_replace_vars_subquery(rte->subquery,
2403 : context);
2404 408 : break;
2405 336 : case RTE_FUNCTION:
2406 336 : rte->functions = (List *)
2407 336 : pullup_replace_vars((Node *) rte->functions,
2408 : context);
2409 336 : break;
2410 108 : case RTE_TABLEFUNC:
2411 108 : rte->tablefunc = (TableFunc *)
2412 108 : pullup_replace_vars((Node *) rte->tablefunc,
2413 : context);
2414 108 : break;
2415 0 : case RTE_VALUES:
2416 0 : rte->values_lists = (List *)
2417 0 : pullup_replace_vars((Node *) rte->values_lists,
2418 : context);
2419 0 : break;
2420 0 : case RTE_JOIN:
2421 : case RTE_CTE:
2422 : case RTE_NAMEDTUPLESTORE:
2423 : case RTE_RESULT:
2424 : case RTE_GROUP:
2425 : /* these shouldn't be marked LATERAL */
2426 : Assert(false);
2427 0 : break;
2428 : }
2429 39390 : }
2430 : }
2431 : }
2432 39032 : else if (IsA(jtnode, FromExpr))
2433 : {
2434 32356 : FromExpr *f = (FromExpr *) jtnode;
2435 : ListCell *l;
2436 :
2437 67410 : foreach(l, f->fromlist)
2438 35054 : replace_vars_in_jointree(lfirst(l), context);
2439 32356 : f->quals = pullup_replace_vars(f->quals, context);
2440 : }
2441 6676 : else if (IsA(jtnode, JoinExpr))
2442 : {
2443 6676 : JoinExpr *j = (JoinExpr *) jtnode;
2444 6676 : bool save_wrap_non_vars = context->wrap_non_vars;
2445 :
2446 6676 : replace_vars_in_jointree(j->larg, context);
2447 6676 : replace_vars_in_jointree(j->rarg, context);
2448 :
2449 : /*
2450 : * Use PHVs within the join quals of a full join. Otherwise, we
2451 : * cannot identify which side of the join a pulled-up var-free
2452 : * expression came from, which can lead to failure to make a plan at
2453 : * all because none of the quals appear to be mergeable or hashable
2454 : * conditions.
2455 : */
2456 6676 : if (j->jointype == JOIN_FULL)
2457 610 : context->wrap_non_vars = true;
2458 :
2459 6676 : j->quals = pullup_replace_vars(j->quals, context);
2460 :
2461 6676 : context->wrap_non_vars = save_wrap_non_vars;
2462 : }
2463 : else
2464 0 : elog(ERROR, "unrecognized node type: %d",
2465 : (int) nodeTag(jtnode));
2466 : }
2467 :
2468 : /*
2469 : * Apply pullup variable replacement throughout an expression tree
2470 : *
2471 : * Returns a modified copy of the tree, so this can't be used where we
2472 : * need to do in-place replacement.
2473 : */
2474 : static Node *
2475 172142 : pullup_replace_vars(Node *expr, pullup_replace_vars_context *context)
2476 : {
2477 172142 : return replace_rte_variables(expr,
2478 : context->varno, 0,
2479 : pullup_replace_vars_callback,
2480 : context,
2481 : context->outer_hasSubLinks);
2482 : }
2483 :
2484 : static Node *
2485 101298 : pullup_replace_vars_callback(Var *var,
2486 : replace_rte_variables_context *context)
2487 : {
2488 101298 : pullup_replace_vars_context *rcon = (pullup_replace_vars_context *) context->callback_arg;
2489 101298 : int varattno = var->varattno;
2490 : bool need_phv;
2491 : Node *newnode;
2492 :
2493 : /*
2494 : * We need a PlaceHolderVar if the Var-to-be-replaced has nonempty
2495 : * varnullingrels (unless we find below that the replacement expression is
2496 : * a Var or PlaceHolderVar that we can just add the nullingrels to). We
2497 : * also need one if the caller has instructed us that all non-Var/PHV
2498 : * replacements need to be wrapped for identification purposes.
2499 : */
2500 101298 : need_phv = (var->varnullingrels != NULL) || rcon->wrap_non_vars;
2501 :
2502 : /*
2503 : * If PlaceHolderVars are needed, we cache the modified expressions in
2504 : * rcon->rv_cache[]. This is not in hopes of any material speed gain
2505 : * within this function, but to avoid generating identical PHVs with
2506 : * different IDs. That would result in duplicate evaluations at runtime,
2507 : * and possibly prevent optimizations that rely on recognizing different
2508 : * references to the same subquery output as being equal(). So it's worth
2509 : * a bit of extra effort to avoid it.
2510 : *
2511 : * The cached items have phlevelsup = 0 and phnullingrels = NULL; we'll
2512 : * copy them and adjust those values for this reference site below.
2513 : */
2514 101298 : if (need_phv &&
2515 13668 : varattno >= InvalidAttrNumber &&
2516 13668 : varattno <= list_length(rcon->targetlist) &&
2517 13668 : rcon->rv_cache[varattno] != NULL)
2518 : {
2519 : /* Just copy the entry and fall through to adjust phlevelsup etc */
2520 2060 : newnode = copyObject(rcon->rv_cache[varattno]);
2521 : }
2522 99238 : else if (varattno == InvalidAttrNumber)
2523 : {
2524 : /* Must expand whole-tuple reference into RowExpr */
2525 : RowExpr *rowexpr;
2526 : List *colnames;
2527 : List *fields;
2528 562 : bool save_wrap_non_vars = rcon->wrap_non_vars;
2529 562 : int save_sublevelsup = context->sublevels_up;
2530 :
2531 : /*
2532 : * If generating an expansion for a var of a named rowtype (ie, this
2533 : * is a plain relation RTE), then we must include dummy items for
2534 : * dropped columns. If the var is RECORD (ie, this is a JOIN), then
2535 : * omit dropped columns. In the latter case, attach column names to
2536 : * the RowExpr for use of the executor and ruleutils.c.
2537 : *
2538 : * In order to be able to cache the results, we always generate the
2539 : * expansion with varlevelsup = 0, and then adjust below if needed.
2540 : */
2541 562 : expandRTE(rcon->target_rte,
2542 : var->varno, 0 /* not varlevelsup */ ,
2543 : var->varreturningtype, var->location,
2544 562 : (var->vartype != RECORDOID),
2545 : &colnames, &fields);
2546 : /* Expand the generated per-field Vars, but don't insert PHVs there */
2547 562 : rcon->wrap_non_vars = false;
2548 562 : context->sublevels_up = 0; /* to match the expandRTE output */
2549 562 : fields = (List *) replace_rte_variables_mutator((Node *) fields,
2550 : context);
2551 562 : rcon->wrap_non_vars = save_wrap_non_vars;
2552 562 : context->sublevels_up = save_sublevelsup;
2553 :
2554 562 : rowexpr = makeNode(RowExpr);
2555 562 : rowexpr->args = fields;
2556 562 : rowexpr->row_typeid = var->vartype;
2557 562 : rowexpr->row_format = COERCE_IMPLICIT_CAST;
2558 562 : rowexpr->colnames = (var->vartype == RECORDOID) ? colnames : NIL;
2559 562 : rowexpr->location = var->location;
2560 562 : newnode = (Node *) rowexpr;
2561 :
2562 : /*
2563 : * Insert PlaceHolderVar if needed. Notice that we are wrapping one
2564 : * PlaceHolderVar around the whole RowExpr, rather than putting one
2565 : * around each element of the row. This is because we need the
2566 : * expression to yield NULL, not ROW(NULL,NULL,...) when it is forced
2567 : * to null by an outer join.
2568 : */
2569 562 : if (need_phv)
2570 : {
2571 : newnode = (Node *)
2572 66 : make_placeholder_expr(rcon->root,
2573 : (Expr *) newnode,
2574 : bms_make_singleton(rcon->varno));
2575 : /* cache it with the PHV, and with phlevelsup etc not set yet */
2576 66 : rcon->rv_cache[InvalidAttrNumber] = copyObject(newnode);
2577 : }
2578 : }
2579 : else
2580 : {
2581 : /* Normal case referencing one targetlist element */
2582 98676 : TargetEntry *tle = get_tle_by_resno(rcon->targetlist, varattno);
2583 :
2584 98676 : if (tle == NULL) /* shouldn't happen */
2585 0 : elog(ERROR, "could not find attribute %d in subquery targetlist",
2586 : varattno);
2587 :
2588 : /* Make a copy of the tlist item to return */
2589 98676 : newnode = (Node *) copyObject(tle->expr);
2590 :
2591 : /* Insert PlaceHolderVar if needed */
2592 98676 : if (need_phv)
2593 : {
2594 : bool wrap;
2595 :
2596 11542 : if (newnode && IsA(newnode, Var) &&
2597 9654 : ((Var *) newnode)->varlevelsup == 0)
2598 : {
2599 : /*
2600 : * Simple Vars always escape being wrapped, unless they are
2601 : * lateral references to something outside the subquery being
2602 : * pulled up and the referenced rel is not under the same
2603 : * lowest nulling outer join.
2604 : */
2605 9638 : wrap = false;
2606 9638 : if (rcon->target_rte->lateral &&
2607 1326 : !bms_is_member(((Var *) newnode)->varno, rcon->relids))
2608 : {
2609 114 : nullingrel_info *nullinfo = rcon->nullinfo;
2610 114 : int lvarno = ((Var *) newnode)->varno;
2611 :
2612 : Assert(lvarno > 0 && lvarno <= nullinfo->rtlength);
2613 114 : if (!bms_is_subset(nullinfo->nullingrels[rcon->varno],
2614 114 : nullinfo->nullingrels[lvarno]))
2615 90 : wrap = true;
2616 : }
2617 : }
2618 1904 : else if (newnode && IsA(newnode, PlaceHolderVar) &&
2619 180 : ((PlaceHolderVar *) newnode)->phlevelsup == 0)
2620 : {
2621 : /* The same rules apply for a PlaceHolderVar */
2622 180 : wrap = false;
2623 180 : if (rcon->target_rte->lateral &&
2624 48 : !bms_is_subset(((PlaceHolderVar *) newnode)->phrels,
2625 48 : rcon->relids))
2626 : {
2627 48 : nullingrel_info *nullinfo = rcon->nullinfo;
2628 48 : Relids lvarnos = ((PlaceHolderVar *) newnode)->phrels;
2629 : int lvarno;
2630 :
2631 48 : lvarno = -1;
2632 72 : while ((lvarno = bms_next_member(lvarnos, lvarno)) >= 0)
2633 : {
2634 : Assert(lvarno > 0 && lvarno <= nullinfo->rtlength);
2635 48 : if (!bms_is_subset(nullinfo->nullingrels[rcon->varno],
2636 48 : nullinfo->nullingrels[lvarno]))
2637 : {
2638 24 : wrap = true;
2639 24 : break;
2640 : }
2641 : }
2642 : }
2643 : }
2644 1724 : else if (rcon->wrap_non_vars)
2645 : {
2646 : /* Caller told us to wrap all non-Vars in a PlaceHolderVar */
2647 188 : wrap = true;
2648 : }
2649 : else
2650 : {
2651 : /*
2652 : * If the node contains Var(s) or PlaceHolderVar(s) of the
2653 : * subquery being pulled up, or of rels that are under the
2654 : * same lowest nulling outer join as the subquery, and does
2655 : * not contain any non-strict constructs, then instead of
2656 : * adding a PHV on top we can add the required nullingrels to
2657 : * those Vars/PHVs. (This is fundamentally a generalization
2658 : * of the above cases for bare Vars and PHVs.)
2659 : *
2660 : * This test is somewhat expensive, but it avoids pessimizing
2661 : * the plan in cases where the nullingrels get removed again
2662 : * later by outer join reduction.
2663 : *
2664 : * Note that we don't force wrapping of expressions containing
2665 : * lateral references, so long as they also contain Vars/PHVs
2666 : * of the subquery, or of rels that are under the same lowest
2667 : * nulling outer join as the subquery. This is okay because
2668 : * of the restriction to strict constructs: if those Vars/PHVs
2669 : * have been forced to NULL by an outer join then the end
2670 : * result of the expression will be NULL too, regardless of
2671 : * the lateral references. So it's not necessary to force the
2672 : * expression to be evaluated below the outer join. This can
2673 : * be a very valuable optimization, because it may allow us to
2674 : * avoid using a nested loop to pass the lateral reference
2675 : * down.
2676 : *
2677 : * This analysis could be tighter: in particular, a non-strict
2678 : * construct hidden within a lower-level PlaceHolderVar is not
2679 : * reason to add another PHV. But for now it doesn't seem
2680 : * worth the code to be more exact.
2681 : *
2682 : * For a LATERAL subquery, we have to check the actual var
2683 : * membership of the node, but if it's non-lateral then any
2684 : * level-zero var must belong to the subquery.
2685 : */
2686 1536 : bool contain_nullable_vars = false;
2687 :
2688 1536 : if (!rcon->target_rte->lateral)
2689 : {
2690 1308 : if (contain_vars_of_level(newnode, 0))
2691 306 : contain_nullable_vars = true;
2692 : }
2693 : else
2694 : {
2695 : Relids all_varnos;
2696 :
2697 228 : all_varnos = pull_varnos(rcon->root, newnode);
2698 228 : if (bms_overlap(all_varnos, rcon->relids))
2699 132 : contain_nullable_vars = true;
2700 : else
2701 : {
2702 96 : nullingrel_info *nullinfo = rcon->nullinfo;
2703 : int varno;
2704 :
2705 96 : varno = -1;
2706 180 : while ((varno = bms_next_member(all_varnos, varno)) >= 0)
2707 : {
2708 : Assert(varno > 0 && varno <= nullinfo->rtlength);
2709 108 : if (bms_is_subset(nullinfo->nullingrels[rcon->varno],
2710 108 : nullinfo->nullingrels[varno]))
2711 : {
2712 24 : contain_nullable_vars = true;
2713 24 : break;
2714 : }
2715 : }
2716 : }
2717 : }
2718 :
2719 1536 : if (contain_nullable_vars &&
2720 462 : !contain_nonstrict_functions(newnode))
2721 : {
2722 : /* No wrap needed */
2723 192 : wrap = false;
2724 : }
2725 : else
2726 : {
2727 : /* Else wrap it in a PlaceHolderVar */
2728 1344 : wrap = true;
2729 : }
2730 : }
2731 :
2732 11542 : if (wrap)
2733 : {
2734 : newnode = (Node *)
2735 1646 : make_placeholder_expr(rcon->root,
2736 : (Expr *) newnode,
2737 : bms_make_singleton(rcon->varno));
2738 :
2739 : /*
2740 : * Cache it if possible (ie, if the attno is in range, which
2741 : * it probably always should be).
2742 : */
2743 3292 : if (varattno > InvalidAttrNumber &&
2744 1646 : varattno <= list_length(rcon->targetlist))
2745 1646 : rcon->rv_cache[varattno] = copyObject(newnode);
2746 : }
2747 : }
2748 : }
2749 :
2750 : /* Propagate any varnullingrels into the replacement expression */
2751 101298 : if (var->varnullingrels != NULL)
2752 : {
2753 11792 : if (IsA(newnode, Var))
2754 : {
2755 7942 : Var *newvar = (Var *) newnode;
2756 :
2757 : Assert(newvar->varlevelsup == 0);
2758 7942 : newvar->varnullingrels = bms_add_members(newvar->varnullingrels,
2759 7942 : var->varnullingrels);
2760 : }
2761 3850 : else if (IsA(newnode, PlaceHolderVar))
2762 : {
2763 3658 : PlaceHolderVar *newphv = (PlaceHolderVar *) newnode;
2764 :
2765 : Assert(newphv->phlevelsup == 0);
2766 3658 : newphv->phnullingrels = bms_add_members(newphv->phnullingrels,
2767 3658 : var->varnullingrels);
2768 : }
2769 : else
2770 : {
2771 : /*
2772 : * There should be Vars/PHVs within the expression that we can
2773 : * modify. Vars/PHVs of the subquery should have the full
2774 : * var->varnullingrels added to them, but if there are lateral
2775 : * references within the expression, those must be marked with
2776 : * only the nullingrels that potentially apply to them. (This
2777 : * corresponds to the fact that the expression will now be
2778 : * evaluated at the join level of the Var that we are replacing:
2779 : * the lateral references may have bubbled up through fewer outer
2780 : * joins than the subquery's Vars have. Per the discussion above,
2781 : * we'll still get the right answers.) That relid set could be
2782 : * different for different lateral relations, so we have to do
2783 : * this work for each one.
2784 : *
2785 : * (Currently, the restrictions in is_simple_subquery() mean that
2786 : * at most we have to remove the lowest outer join's relid from
2787 : * the nullingrels of a lateral reference. However, we might
2788 : * relax those restrictions someday, so let's do this right.)
2789 : */
2790 192 : if (rcon->target_rte->lateral)
2791 : {
2792 84 : nullingrel_info *nullinfo = rcon->nullinfo;
2793 : Relids lvarnos;
2794 : int lvarno;
2795 :
2796 : /*
2797 : * Identify lateral varnos used within newnode. We must do
2798 : * this before injecting var->varnullingrels into the tree.
2799 : */
2800 84 : lvarnos = pull_varnos(rcon->root, newnode);
2801 84 : lvarnos = bms_del_members(lvarnos, rcon->relids);
2802 : /* For each one, add relevant nullingrels if any */
2803 84 : lvarno = -1;
2804 168 : while ((lvarno = bms_next_member(lvarnos, lvarno)) >= 0)
2805 : {
2806 : Relids lnullingrels;
2807 :
2808 : Assert(lvarno > 0 && lvarno <= nullinfo->rtlength);
2809 84 : lnullingrels = bms_intersect(var->varnullingrels,
2810 84 : nullinfo->nullingrels[lvarno]);
2811 84 : if (!bms_is_empty(lnullingrels))
2812 48 : newnode = add_nulling_relids(newnode,
2813 48 : bms_make_singleton(lvarno),
2814 : lnullingrels);
2815 : }
2816 : }
2817 :
2818 : /* Finally, deal with Vars/PHVs of the subquery itself */
2819 192 : newnode = add_nulling_relids(newnode,
2820 192 : rcon->relids,
2821 192 : var->varnullingrels);
2822 : /* Assert we did put the varnullingrels into the expression */
2823 : Assert(bms_is_subset(var->varnullingrels,
2824 : pull_varnos(rcon->root, newnode)));
2825 : }
2826 : }
2827 :
2828 : /* Must adjust varlevelsup if replaced Var is within a subquery */
2829 101298 : if (var->varlevelsup > 0)
2830 1006 : IncrementVarSublevelsUp(newnode, var->varlevelsup, 0);
2831 :
2832 101298 : return newnode;
2833 : }
2834 :
2835 : /*
2836 : * Apply pullup variable replacement to a subquery
2837 : *
2838 : * This needs to be different from pullup_replace_vars() because
2839 : * replace_rte_variables will think that it shouldn't increment sublevels_up
2840 : * before entering the Query; so we need to call it with sublevels_up == 1.
2841 : */
2842 : static Query *
2843 408 : pullup_replace_vars_subquery(Query *query,
2844 : pullup_replace_vars_context *context)
2845 : {
2846 : Assert(IsA(query, Query));
2847 408 : return (Query *) replace_rte_variables((Node *) query,
2848 : context->varno, 1,
2849 : pullup_replace_vars_callback,
2850 : context,
2851 : NULL);
2852 : }
2853 :
2854 :
2855 : /*
2856 : * flatten_simple_union_all
2857 : * Try to optimize top-level UNION ALL structure into an appendrel
2858 : *
2859 : * If a query's setOperations tree consists entirely of simple UNION ALL
2860 : * operations, flatten it into an append relation, which we can process more
2861 : * intelligently than the general setops case. Otherwise, do nothing.
2862 : *
2863 : * In most cases, this can succeed only for a top-level query, because for a
2864 : * subquery in FROM, the parent query's invocation of pull_up_subqueries would
2865 : * already have flattened the UNION via pull_up_simple_union_all. But there
2866 : * are a few cases we can support here but not in that code path, for example
2867 : * when the subquery also contains ORDER BY.
2868 : */
2869 : void
2870 5852 : flatten_simple_union_all(PlannerInfo *root)
2871 : {
2872 5852 : Query *parse = root->parse;
2873 : SetOperationStmt *topop;
2874 : Node *leftmostjtnode;
2875 : int leftmostRTI;
2876 : RangeTblEntry *leftmostRTE;
2877 : int childRTI;
2878 : RangeTblEntry *childRTE;
2879 : RangeTblRef *rtr;
2880 :
2881 : /* Shouldn't be called unless query has setops */
2882 5852 : topop = castNode(SetOperationStmt, parse->setOperations);
2883 : Assert(topop);
2884 :
2885 : /* Can't optimize away a recursive UNION */
2886 5852 : if (root->hasRecursion)
2887 5504 : return;
2888 :
2889 : /*
2890 : * Recursively check the tree of set operations. If not all UNION ALL
2891 : * with identical column types, punt.
2892 : */
2893 5030 : if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
2894 4682 : return;
2895 :
2896 : /*
2897 : * Locate the leftmost leaf query in the setops tree. The upper query's
2898 : * Vars all refer to this RTE (see transformSetOperationStmt).
2899 : */
2900 348 : leftmostjtnode = topop->larg;
2901 556 : while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
2902 208 : leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;
2903 : Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
2904 348 : leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
2905 348 : leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
2906 : Assert(leftmostRTE->rtekind == RTE_SUBQUERY);
2907 :
2908 : /*
2909 : * Make a copy of the leftmost RTE and add it to the rtable. This copy
2910 : * will represent the leftmost leaf query in its capacity as a member of
2911 : * the appendrel. The original will represent the appendrel as a whole.
2912 : * (We must do things this way because the upper query's Vars have to be
2913 : * seen as referring to the whole appendrel.)
2914 : */
2915 348 : childRTE = copyObject(leftmostRTE);
2916 348 : parse->rtable = lappend(parse->rtable, childRTE);
2917 348 : childRTI = list_length(parse->rtable);
2918 :
2919 : /* Modify the setops tree to reference the child copy */
2920 348 : ((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;
2921 :
2922 : /* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
2923 348 : leftmostRTE->inh = true;
2924 :
2925 : /*
2926 : * Form a RangeTblRef for the appendrel, and insert it into FROM. The top
2927 : * Query of a setops tree should have had an empty FromClause initially.
2928 : */
2929 348 : rtr = makeNode(RangeTblRef);
2930 348 : rtr->rtindex = leftmostRTI;
2931 : Assert(parse->jointree->fromlist == NIL);
2932 348 : parse->jointree->fromlist = list_make1(rtr);
2933 :
2934 : /*
2935 : * Now pretend the query has no setops. We must do this before trying to
2936 : * do subquery pullup, because of Assert in pull_up_simple_subquery.
2937 : */
2938 348 : parse->setOperations = NULL;
2939 :
2940 : /*
2941 : * Build AppendRelInfo information, and apply pull_up_subqueries to the
2942 : * leaf queries of the UNION ALL. (We must do that now because they
2943 : * weren't previously referenced by the jointree, and so were missed by
2944 : * the main invocation of pull_up_subqueries.)
2945 : */
2946 348 : pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
2947 : }
2948 :
2949 :
2950 : /*
2951 : * reduce_outer_joins
2952 : * Attempt to reduce outer joins to plain inner joins.
2953 : *
2954 : * The idea here is that given a query like
2955 : * SELECT ... FROM a LEFT JOIN b ON (...) WHERE b.y = 42;
2956 : * we can reduce the LEFT JOIN to a plain JOIN if the "=" operator in WHERE
2957 : * is strict. The strict operator will always return NULL, causing the outer
2958 : * WHERE to fail, on any row where the LEFT JOIN filled in NULLs for b's
2959 : * columns. Therefore, there's no need for the join to produce null-extended
2960 : * rows in the first place --- which makes it a plain join not an outer join.
2961 : * (This scenario may not be very likely in a query written out by hand, but
2962 : * it's reasonably likely when pushing quals down into complex views.)
2963 : *
2964 : * More generally, an outer join can be reduced in strength if there is a
2965 : * strict qual above it in the qual tree that constrains a Var from the
2966 : * nullable side of the join to be non-null. (For FULL joins this applies
2967 : * to each side separately.)
2968 : *
2969 : * Another transformation we apply here is to recognize cases like
2970 : * SELECT ... FROM a LEFT JOIN b ON (a.x = b.y) WHERE b.y IS NULL;
2971 : * If the join clause is strict for b.y, then only null-extended rows could
2972 : * pass the upper WHERE, and we can conclude that what the query is really
2973 : * specifying is an anti-semijoin. We change the join type from JOIN_LEFT
2974 : * to JOIN_ANTI. The IS NULL clause then becomes redundant, and must be
2975 : * removed to prevent bogus selectivity calculations, but we leave it to
2976 : * distribute_qual_to_rels to get rid of such clauses.
2977 : *
2978 : * Also, we get rid of JOIN_RIGHT cases by flipping them around to become
2979 : * JOIN_LEFT. This saves some code here and in some later planner routines;
2980 : * the main benefit is to reduce the number of jointypes that can appear in
2981 : * SpecialJoinInfo nodes. Note that we can still generate Paths and Plans
2982 : * that use JOIN_RIGHT (or JOIN_RIGHT_ANTI) by switching the inputs again.
2983 : *
2984 : * To ease recognition of strict qual clauses, we require this routine to be
2985 : * run after expression preprocessing (i.e., qual canonicalization and JOIN
2986 : * alias-var expansion).
2987 : */
2988 : void
2989 30452 : reduce_outer_joins(PlannerInfo *root)
2990 : {
2991 : reduce_outer_joins_pass1_state *state1;
2992 : reduce_outer_joins_pass2_state state2;
2993 : ListCell *lc;
2994 :
2995 : /*
2996 : * To avoid doing strictness checks on more quals than necessary, we want
2997 : * to stop descending the jointree as soon as there are no outer joins
2998 : * below our current point. This consideration forces a two-pass process.
2999 : * The first pass gathers information about which base rels appear below
3000 : * each side of each join clause, and about whether there are outer
3001 : * join(s) below each side of each join clause. The second pass examines
3002 : * qual clauses and changes join types as it descends the tree.
3003 : */
3004 30452 : state1 = reduce_outer_joins_pass1((Node *) root->parse->jointree);
3005 :
3006 : /* planner.c shouldn't have called me if no outer joins */
3007 30452 : if (state1 == NULL || !state1->contains_outer)
3008 0 : elog(ERROR, "so where are the outer joins?");
3009 :
3010 30452 : state2.inner_reduced = NULL;
3011 30452 : state2.partial_reduced = NIL;
3012 :
3013 30452 : reduce_outer_joins_pass2((Node *) root->parse->jointree,
3014 : state1, &state2,
3015 : root, NULL, NIL);
3016 :
3017 : /*
3018 : * If we successfully reduced the strength of any outer joins, we must
3019 : * remove references to those joins as nulling rels. This is handled as
3020 : * an additional pass, for simplicity and because we can handle all
3021 : * fully-reduced joins in a single pass over the parse tree.
3022 : */
3023 30452 : if (!bms_is_empty(state2.inner_reduced))
3024 : {
3025 1740 : root->parse = (Query *)
3026 1740 : remove_nulling_relids((Node *) root->parse,
3027 1740 : state2.inner_reduced,
3028 : NULL);
3029 : /* There could be references in the append_rel_list, too */
3030 1740 : root->append_rel_list = (List *)
3031 1740 : remove_nulling_relids((Node *) root->append_rel_list,
3032 1740 : state2.inner_reduced,
3033 : NULL);
3034 : }
3035 :
3036 : /*
3037 : * Partially-reduced full joins have to be done one at a time, since
3038 : * they'll each need a different setting of except_relids.
3039 : */
3040 30502 : foreach(lc, state2.partial_reduced)
3041 : {
3042 50 : reduce_outer_joins_partial_state *statep = lfirst(lc);
3043 50 : Relids full_join_relids = bms_make_singleton(statep->full_join_rti);
3044 :
3045 50 : root->parse = (Query *)
3046 50 : remove_nulling_relids((Node *) root->parse,
3047 : full_join_relids,
3048 50 : statep->unreduced_side);
3049 50 : root->append_rel_list = (List *)
3050 50 : remove_nulling_relids((Node *) root->append_rel_list,
3051 : full_join_relids,
3052 50 : statep->unreduced_side);
3053 : }
3054 30452 : }
3055 :
3056 : /*
3057 : * reduce_outer_joins_pass1 - phase 1 data collection
3058 : *
3059 : * Returns a state node describing the given jointree node.
3060 : */
3061 : static reduce_outer_joins_pass1_state *
3062 171686 : reduce_outer_joins_pass1(Node *jtnode)
3063 : {
3064 : reduce_outer_joins_pass1_state *result;
3065 :
3066 : result = (reduce_outer_joins_pass1_state *)
3067 171686 : palloc(sizeof(reduce_outer_joins_pass1_state));
3068 171686 : result->relids = NULL;
3069 171686 : result->contains_outer = false;
3070 171686 : result->sub_states = NIL;
3071 :
3072 171686 : if (jtnode == NULL)
3073 0 : return result;
3074 171686 : if (IsA(jtnode, RangeTblRef))
3075 : {
3076 85688 : int varno = ((RangeTblRef *) jtnode)->rtindex;
3077 :
3078 85688 : result->relids = bms_make_singleton(varno);
3079 : }
3080 85998 : else if (IsA(jtnode, FromExpr))
3081 : {
3082 33386 : FromExpr *f = (FromExpr *) jtnode;
3083 : ListCell *l;
3084 :
3085 69396 : foreach(l, f->fromlist)
3086 : {
3087 : reduce_outer_joins_pass1_state *sub_state;
3088 :
3089 36010 : sub_state = reduce_outer_joins_pass1(lfirst(l));
3090 72020 : result->relids = bms_add_members(result->relids,
3091 36010 : sub_state->relids);
3092 36010 : result->contains_outer |= sub_state->contains_outer;
3093 36010 : result->sub_states = lappend(result->sub_states, sub_state);
3094 : }
3095 : }
3096 52612 : else if (IsA(jtnode, JoinExpr))
3097 : {
3098 52612 : JoinExpr *j = (JoinExpr *) jtnode;
3099 : reduce_outer_joins_pass1_state *sub_state;
3100 :
3101 : /* join's own RT index is not wanted in result->relids */
3102 52612 : if (IS_OUTER_JOIN(j->jointype))
3103 43624 : result->contains_outer = true;
3104 :
3105 52612 : sub_state = reduce_outer_joins_pass1(j->larg);
3106 105224 : result->relids = bms_add_members(result->relids,
3107 52612 : sub_state->relids);
3108 52612 : result->contains_outer |= sub_state->contains_outer;
3109 52612 : result->sub_states = lappend(result->sub_states, sub_state);
3110 :
3111 52612 : sub_state = reduce_outer_joins_pass1(j->rarg);
3112 105224 : result->relids = bms_add_members(result->relids,
3113 52612 : sub_state->relids);
3114 52612 : result->contains_outer |= sub_state->contains_outer;
3115 52612 : result->sub_states = lappend(result->sub_states, sub_state);
3116 : }
3117 : else
3118 0 : elog(ERROR, "unrecognized node type: %d",
3119 : (int) nodeTag(jtnode));
3120 171686 : return result;
3121 : }
3122 :
3123 : /*
3124 : * reduce_outer_joins_pass2 - phase 2 processing
3125 : *
3126 : * jtnode: current jointree node
3127 : * state1: state data collected by phase 1 for this node
3128 : * state2: where to accumulate info about successfully-reduced joins
3129 : * root: toplevel planner state
3130 : * nonnullable_rels: set of base relids forced non-null by upper quals
3131 : * forced_null_vars: multibitmapset of Vars forced null by upper quals
3132 : *
3133 : * Returns info in state2 about outer joins that were successfully simplified.
3134 : * Joins that were fully reduced to inner joins are all added to
3135 : * state2->inner_reduced. If a full join is reduced to a left join,
3136 : * it needs its own entry in state2->partial_reduced, since that will
3137 : * require custom processing to remove only the correct nullingrel markers.
3138 : */
3139 : static void
3140 75932 : reduce_outer_joins_pass2(Node *jtnode,
3141 : reduce_outer_joins_pass1_state *state1,
3142 : reduce_outer_joins_pass2_state *state2,
3143 : PlannerInfo *root,
3144 : Relids nonnullable_rels,
3145 : List *forced_null_vars)
3146 : {
3147 : /*
3148 : * pass 2 should never descend as far as an empty subnode or base rel,
3149 : * because it's only called on subtrees marked as contains_outer.
3150 : */
3151 75932 : if (jtnode == NULL)
3152 0 : elog(ERROR, "reached empty jointree");
3153 75932 : if (IsA(jtnode, RangeTblRef))
3154 0 : elog(ERROR, "reached base rel");
3155 75932 : else if (IsA(jtnode, FromExpr))
3156 : {
3157 31708 : FromExpr *f = (FromExpr *) jtnode;
3158 : ListCell *l;
3159 : ListCell *s;
3160 : Relids pass_nonnullable_rels;
3161 : List *pass_forced_null_vars;
3162 :
3163 : /* Scan quals to see if we can add any constraints */
3164 31708 : pass_nonnullable_rels = find_nonnullable_rels(f->quals);
3165 31708 : pass_nonnullable_rels = bms_add_members(pass_nonnullable_rels,
3166 : nonnullable_rels);
3167 31708 : pass_forced_null_vars = find_forced_null_vars(f->quals);
3168 31708 : pass_forced_null_vars = mbms_add_members(pass_forced_null_vars,
3169 : forced_null_vars);
3170 : /* And recurse --- but only into interesting subtrees */
3171 : Assert(list_length(f->fromlist) == list_length(state1->sub_states));
3172 65914 : forboth(l, f->fromlist, s, state1->sub_states)
3173 : {
3174 34206 : reduce_outer_joins_pass1_state *sub_state = lfirst(s);
3175 :
3176 34206 : if (sub_state->contains_outer)
3177 31738 : reduce_outer_joins_pass2(lfirst(l), sub_state,
3178 : state2, root,
3179 : pass_nonnullable_rels,
3180 : pass_forced_null_vars);
3181 : }
3182 31708 : bms_free(pass_nonnullable_rels);
3183 : /* can't so easily clean up var lists, unfortunately */
3184 : }
3185 44224 : else if (IsA(jtnode, JoinExpr))
3186 : {
3187 44224 : JoinExpr *j = (JoinExpr *) jtnode;
3188 44224 : int rtindex = j->rtindex;
3189 44224 : JoinType jointype = j->jointype;
3190 44224 : reduce_outer_joins_pass1_state *left_state = linitial(state1->sub_states);
3191 44224 : reduce_outer_joins_pass1_state *right_state = lsecond(state1->sub_states);
3192 :
3193 : /* Can we simplify this join? */
3194 44224 : switch (jointype)
3195 : {
3196 564 : case JOIN_INNER:
3197 564 : break;
3198 41112 : case JOIN_LEFT:
3199 41112 : if (bms_overlap(nonnullable_rels, right_state->relids))
3200 1816 : jointype = JOIN_INNER;
3201 41112 : break;
3202 1084 : case JOIN_RIGHT:
3203 1084 : if (bms_overlap(nonnullable_rels, left_state->relids))
3204 62 : jointype = JOIN_INNER;
3205 1084 : break;
3206 1066 : case JOIN_FULL:
3207 1066 : if (bms_overlap(nonnullable_rels, left_state->relids))
3208 : {
3209 24 : if (bms_overlap(nonnullable_rels, right_state->relids))
3210 12 : jointype = JOIN_INNER;
3211 : else
3212 : {
3213 12 : jointype = JOIN_LEFT;
3214 : /* Also report partial reduction in state2 */
3215 12 : report_reduced_full_join(state2, rtindex,
3216 : right_state->relids);
3217 : }
3218 : }
3219 : else
3220 : {
3221 1042 : if (bms_overlap(nonnullable_rels, right_state->relids))
3222 : {
3223 38 : jointype = JOIN_RIGHT;
3224 : /* Also report partial reduction in state2 */
3225 38 : report_reduced_full_join(state2, rtindex,
3226 : left_state->relids);
3227 : }
3228 : }
3229 1066 : break;
3230 398 : case JOIN_SEMI:
3231 : case JOIN_ANTI:
3232 :
3233 : /*
3234 : * These could only have been introduced by pull_up_sublinks,
3235 : * so there's no way that upper quals could refer to their
3236 : * righthand sides, and no point in checking. We don't expect
3237 : * to see JOIN_RIGHT_SEMI or JOIN_RIGHT_ANTI yet.
3238 : */
3239 398 : break;
3240 0 : default:
3241 0 : elog(ERROR, "unrecognized join type: %d",
3242 : (int) jointype);
3243 : break;
3244 : }
3245 :
3246 : /*
3247 : * Convert JOIN_RIGHT to JOIN_LEFT. Note that in the case where we
3248 : * reduced JOIN_FULL to JOIN_RIGHT, this will mean the JoinExpr no
3249 : * longer matches the internal ordering of any CoalesceExpr's built to
3250 : * represent merged join variables. We don't care about that at
3251 : * present, but be wary of it ...
3252 : */
3253 44224 : if (jointype == JOIN_RIGHT)
3254 : {
3255 : Node *tmparg;
3256 :
3257 1060 : tmparg = j->larg;
3258 1060 : j->larg = j->rarg;
3259 1060 : j->rarg = tmparg;
3260 1060 : jointype = JOIN_LEFT;
3261 1060 : right_state = linitial(state1->sub_states);
3262 1060 : left_state = lsecond(state1->sub_states);
3263 : }
3264 :
3265 : /*
3266 : * See if we can reduce JOIN_LEFT to JOIN_ANTI. This is the case if
3267 : * the join's own quals are strict for any var that was forced null by
3268 : * higher qual levels. NOTE: there are other ways that we could
3269 : * detect an anti-join, in particular if we were to check whether Vars
3270 : * coming from the RHS must be non-null because of table constraints.
3271 : * That seems complicated and expensive though (in particular, one
3272 : * would have to be wary of lower outer joins). For the moment this
3273 : * seems sufficient.
3274 : */
3275 44224 : if (jointype == JOIN_LEFT)
3276 : {
3277 : List *nonnullable_vars;
3278 : Bitmapset *overlap;
3279 :
3280 : /* Find Vars in j->quals that must be non-null in joined rows */
3281 40368 : nonnullable_vars = find_nonnullable_vars(j->quals);
3282 :
3283 : /*
3284 : * It's not sufficient to check whether nonnullable_vars and
3285 : * forced_null_vars overlap: we need to know if the overlap
3286 : * includes any RHS variables.
3287 : */
3288 40368 : overlap = mbms_overlap_sets(nonnullable_vars, forced_null_vars);
3289 40368 : if (bms_overlap(overlap, right_state->relids))
3290 1020 : jointype = JOIN_ANTI;
3291 : }
3292 :
3293 : /*
3294 : * Apply the jointype change, if any, to both jointree node and RTE.
3295 : * Also, if we changed an RTE to INNER, add its RTI to inner_reduced.
3296 : */
3297 44224 : if (rtindex && jointype != j->jointype)
3298 : {
3299 3982 : RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable);
3300 :
3301 : Assert(rte->rtekind == RTE_JOIN);
3302 : Assert(rte->jointype == j->jointype);
3303 3982 : rte->jointype = jointype;
3304 3982 : if (jointype == JOIN_INNER)
3305 1890 : state2->inner_reduced = bms_add_member(state2->inner_reduced,
3306 : rtindex);
3307 : }
3308 44224 : j->jointype = jointype;
3309 :
3310 : /* Only recurse if there's more to do below here */
3311 44224 : if (left_state->contains_outer || right_state->contains_outer)
3312 : {
3313 : Relids local_nonnullable_rels;
3314 : List *local_forced_null_vars;
3315 : Relids pass_nonnullable_rels;
3316 : List *pass_forced_null_vars;
3317 :
3318 : /*
3319 : * If this join is (now) inner, we can add any constraints its
3320 : * quals provide to those we got from above. But if it is outer,
3321 : * we can pass down the local constraints only into the nullable
3322 : * side, because an outer join never eliminates any rows from its
3323 : * non-nullable side. Also, there is no point in passing upper
3324 : * constraints into the nullable side, since if there were any
3325 : * we'd have been able to reduce the join. (In the case of upper
3326 : * forced-null constraints, we *must not* pass them into the
3327 : * nullable side --- they either applied here, or not.) The upshot
3328 : * is that we pass either the local or the upper constraints,
3329 : * never both, to the children of an outer join.
3330 : *
3331 : * Note that a SEMI join works like an inner join here: it's okay
3332 : * to pass down both local and upper constraints. (There can't be
3333 : * any upper constraints affecting its inner side, but it's not
3334 : * worth having a separate code path to avoid passing them.)
3335 : *
3336 : * At a FULL join we just punt and pass nothing down --- is it
3337 : * possible to be smarter?
3338 : */
3339 13674 : if (jointype != JOIN_FULL)
3340 : {
3341 13538 : local_nonnullable_rels = find_nonnullable_rels(j->quals);
3342 13538 : local_forced_null_vars = find_forced_null_vars(j->quals);
3343 13538 : if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
3344 : {
3345 : /* OK to merge upper and local constraints */
3346 986 : local_nonnullable_rels = bms_add_members(local_nonnullable_rels,
3347 : nonnullable_rels);
3348 986 : local_forced_null_vars = mbms_add_members(local_forced_null_vars,
3349 : forced_null_vars);
3350 : }
3351 : }
3352 : else
3353 : {
3354 : /* no use in calculating these */
3355 136 : local_nonnullable_rels = NULL;
3356 136 : local_forced_null_vars = NIL;
3357 : }
3358 :
3359 13674 : if (left_state->contains_outer)
3360 : {
3361 12912 : if (jointype == JOIN_INNER || jointype == JOIN_SEMI)
3362 : {
3363 : /* pass union of local and upper constraints */
3364 766 : pass_nonnullable_rels = local_nonnullable_rels;
3365 766 : pass_forced_null_vars = local_forced_null_vars;
3366 : }
3367 12146 : else if (jointype != JOIN_FULL) /* ie, LEFT or ANTI */
3368 : {
3369 : /* can't pass local constraints to non-nullable side */
3370 12038 : pass_nonnullable_rels = nonnullable_rels;
3371 12038 : pass_forced_null_vars = forced_null_vars;
3372 : }
3373 : else
3374 : {
3375 : /* no constraints pass through JOIN_FULL */
3376 108 : pass_nonnullable_rels = NULL;
3377 108 : pass_forced_null_vars = NIL;
3378 : }
3379 12912 : reduce_outer_joins_pass2(j->larg, left_state,
3380 : state2, root,
3381 : pass_nonnullable_rels,
3382 : pass_forced_null_vars);
3383 : }
3384 :
3385 13674 : if (right_state->contains_outer)
3386 : {
3387 830 : if (jointype != JOIN_FULL) /* ie, INNER/LEFT/SEMI/ANTI */
3388 : {
3389 : /* pass appropriate constraints, per comment above */
3390 802 : pass_nonnullable_rels = local_nonnullable_rels;
3391 802 : pass_forced_null_vars = local_forced_null_vars;
3392 : }
3393 : else
3394 : {
3395 : /* no constraints pass through JOIN_FULL */
3396 28 : pass_nonnullable_rels = NULL;
3397 28 : pass_forced_null_vars = NIL;
3398 : }
3399 830 : reduce_outer_joins_pass2(j->rarg, right_state,
3400 : state2, root,
3401 : pass_nonnullable_rels,
3402 : pass_forced_null_vars);
3403 : }
3404 13674 : bms_free(local_nonnullable_rels);
3405 : }
3406 : }
3407 : else
3408 0 : elog(ERROR, "unrecognized node type: %d",
3409 : (int) nodeTag(jtnode));
3410 75932 : }
3411 :
3412 : /* Helper for reduce_outer_joins_pass2 */
3413 : static void
3414 50 : report_reduced_full_join(reduce_outer_joins_pass2_state *state2,
3415 : int rtindex, Relids relids)
3416 : {
3417 : reduce_outer_joins_partial_state *statep;
3418 :
3419 50 : statep = palloc(sizeof(reduce_outer_joins_partial_state));
3420 50 : statep->full_join_rti = rtindex;
3421 50 : statep->unreduced_side = relids;
3422 50 : state2->partial_reduced = lappend(state2->partial_reduced, statep);
3423 50 : }
3424 :
3425 :
3426 : /*
3427 : * remove_useless_result_rtes
3428 : * Attempt to remove RTE_RESULT RTEs from the join tree.
3429 : * Also, elide single-child FromExprs where possible.
3430 : *
3431 : * We can remove RTE_RESULT entries from the join tree using the knowledge
3432 : * that RTE_RESULT returns exactly one row and has no output columns. Hence,
3433 : * if one is inner-joined to anything else, we can delete it. Optimizations
3434 : * are also possible for some outer-join cases, as detailed below.
3435 : *
3436 : * This pass also replaces single-child FromExprs with their child node
3437 : * where possible. It's appropriate to do that here and not earlier because
3438 : * RTE_RESULT removal might reduce a multiple-child FromExpr to have only one
3439 : * child. We can remove such a FromExpr if its quals are empty, or if it's
3440 : * semantically valid to merge the quals into those of the parent node.
3441 : * While removing unnecessary join tree nodes has some micro-efficiency value,
3442 : * the real reason to do this is to eliminate cases where the nullable side of
3443 : * an outer join node is a FromExpr whose single child is another outer join.
3444 : * To correctly determine whether the two outer joins can commute,
3445 : * deconstruct_jointree() must treat any quals of such a FromExpr as being
3446 : * degenerate quals of the upper outer join. The best way to do that is to
3447 : * make them actually *be* quals of the upper join, by dropping the FromExpr
3448 : * and hoisting the quals up into the upper join's quals. (Note that there is
3449 : * no hazard when the intermediate FromExpr has multiple children, since then
3450 : * it represents an inner join that cannot commute with the upper outer join.)
3451 : * As long as we have to do that, we might as well elide such FromExprs
3452 : * everywhere.
3453 : *
3454 : * Some of these optimizations depend on recognizing empty (constant-true)
3455 : * quals for FromExprs and JoinExprs. That makes it useful to apply this
3456 : * optimization pass after expression preprocessing, since that will have
3457 : * eliminated constant-true quals, allowing more cases to be recognized as
3458 : * optimizable. What's more, the usual reason for an RTE_RESULT to be present
3459 : * is that we pulled up a subquery or VALUES clause, thus very possibly
3460 : * replacing Vars with constants, making it more likely that a qual can be
3461 : * reduced to constant true. Also, because some optimizations depend on
3462 : * the outer-join type, it's best to have done reduce_outer_joins() first.
3463 : *
3464 : * A PlaceHolderVar referencing an RTE_RESULT RTE poses an obstacle to this
3465 : * process: we must remove the RTE_RESULT's relid from the PHV's phrels, but
3466 : * we must not reduce the phrels set to empty. If that would happen, and
3467 : * the RTE_RESULT is an immediate child of an outer join, we have to give up
3468 : * and not remove the RTE_RESULT: there is noplace else to evaluate the
3469 : * PlaceHolderVar. (That is, in such cases the RTE_RESULT *does* have output
3470 : * columns.) But if the RTE_RESULT is an immediate child of an inner join,
3471 : * we can usually change the PlaceHolderVar's phrels so as to evaluate it at
3472 : * the inner join instead. This is OK because we really only care that PHVs
3473 : * are evaluated above or below the correct outer joins. We can't, however,
3474 : * postpone the evaluation of a PHV to above where it is used; so there are
3475 : * some checks below on whether output PHVs are laterally referenced in the
3476 : * other join input rel(s).
3477 : *
3478 : * We used to try to do this work as part of pull_up_subqueries() where the
3479 : * potentially-optimizable cases get introduced; but it's way simpler, and
3480 : * more effective, to do it separately.
3481 : */
3482 : void
3483 243408 : remove_useless_result_rtes(PlannerInfo *root)
3484 : {
3485 243408 : Relids dropped_outer_joins = NULL;
3486 : ListCell *cell;
3487 :
3488 : /* Top level of jointree must always be a FromExpr */
3489 : Assert(IsA(root->parse->jointree, FromExpr));
3490 : /* Recurse ... */
3491 486816 : root->parse->jointree = (FromExpr *)
3492 243408 : remove_useless_results_recurse(root,
3493 243408 : (Node *) root->parse->jointree,
3494 : NULL,
3495 : &dropped_outer_joins);
3496 : /* We should still have a FromExpr */
3497 : Assert(IsA(root->parse->jointree, FromExpr));
3498 :
3499 : /*
3500 : * If we removed any outer-join nodes from the jointree, run around and
3501 : * remove references to those joins as nulling rels. (There could be such
3502 : * references in PHVs that we pulled up out of the original subquery that
3503 : * the RESULT rel replaced. This is kosher on the grounds that we now
3504 : * know that such an outer join wouldn't really have nulled anything.) We
3505 : * don't do this during the main recursion, for simplicity and because we
3506 : * can handle all such joins in a single pass over the parse tree.
3507 : */
3508 243408 : if (!bms_is_empty(dropped_outer_joins))
3509 : {
3510 60 : root->parse = (Query *)
3511 60 : remove_nulling_relids((Node *) root->parse,
3512 : dropped_outer_joins,
3513 : NULL);
3514 : /* There could be references in the append_rel_list, too */
3515 60 : root->append_rel_list = (List *)
3516 60 : remove_nulling_relids((Node *) root->append_rel_list,
3517 : dropped_outer_joins,
3518 : NULL);
3519 : }
3520 :
3521 : /*
3522 : * Remove any PlanRowMark referencing an RTE_RESULT RTE. We obviously
3523 : * must do that for any RTE_RESULT that we just removed. But one for a
3524 : * RTE that we did not remove can be dropped anyway: since the RTE has
3525 : * only one possible output row, there is no need for EPQ to mark and
3526 : * restore that row.
3527 : *
3528 : * It's necessary, not optional, to remove the PlanRowMark for a surviving
3529 : * RTE_RESULT RTE; otherwise we'll generate a whole-row Var for the
3530 : * RTE_RESULT, which the executor has no support for.
3531 : */
3532 245308 : foreach(cell, root->rowMarks)
3533 : {
3534 1900 : PlanRowMark *rc = (PlanRowMark *) lfirst(cell);
3535 :
3536 1900 : if (rt_fetch(rc->rti, root->parse->rtable)->rtekind == RTE_RESULT)
3537 834 : root->rowMarks = foreach_delete_current(root->rowMarks, cell);
3538 : }
3539 243408 : }
3540 :
3541 : /*
3542 : * remove_useless_results_recurse
3543 : * Recursive guts of remove_useless_result_rtes.
3544 : *
3545 : * This recursively processes the jointree and returns a modified jointree.
3546 : * In addition, the RT indexes of any removed outer-join nodes are added to
3547 : * *dropped_outer_joins.
3548 : *
3549 : * jtnode is the current jointree node. If it could be valid to merge
3550 : * its quals into those of the parent node, parent_quals should point to
3551 : * the parent's quals list; otherwise, pass NULL for parent_quals.
3552 : * (Note that in some cases, parent_quals points to the quals of a parent
3553 : * more than one level up in the tree.)
3554 : */
3555 : static Node *
3556 601604 : remove_useless_results_recurse(PlannerInfo *root, Node *jtnode,
3557 : Node **parent_quals,
3558 : Relids *dropped_outer_joins)
3559 : {
3560 : Assert(jtnode != NULL);
3561 601604 : if (IsA(jtnode, RangeTblRef))
3562 : {
3563 : /* Can't immediately do anything with a RangeTblRef */
3564 : }
3565 301190 : else if (IsA(jtnode, FromExpr))
3566 : {
3567 247424 : FromExpr *f = (FromExpr *) jtnode;
3568 247424 : Relids result_relids = NULL;
3569 : ListCell *cell;
3570 :
3571 : /*
3572 : * We can drop RTE_RESULT rels from the fromlist so long as at least
3573 : * one child remains, since joining to a one-row table changes
3574 : * nothing. (But we can't drop a RTE_RESULT that computes PHV(s) that
3575 : * are needed by some sibling. The cleanup transformation below would
3576 : * reassign the PHVs to be computed at the join, which is too late for
3577 : * the sibling's use.) The easiest way to mechanize this rule is to
3578 : * modify the list in-place.
3579 : */
3580 498088 : foreach(cell, f->fromlist)
3581 : {
3582 250664 : Node *child = (Node *) lfirst(cell);
3583 : int varno;
3584 :
3585 : /* Recursively transform child, allowing it to push up quals ... */
3586 250664 : child = remove_useless_results_recurse(root, child,
3587 : &f->quals,
3588 : dropped_outer_joins);
3589 : /* ... and stick it back into the tree */
3590 250664 : lfirst(cell) = child;
3591 :
3592 : /*
3593 : * If it's an RTE_RESULT with at least one sibling, and no sibling
3594 : * references dependent PHVs, we can drop it. We don't yet know
3595 : * what the inner join's final relid set will be, so postpone
3596 : * cleanup of PHVs etc till after this loop.
3597 : */
3598 255844 : if (list_length(f->fromlist) > 1 &&
3599 5180 : (varno = get_result_relid(root, child)) != 0 &&
3600 334 : !find_dependent_phvs_in_jointree(root, (Node *) f, varno))
3601 : {
3602 310 : f->fromlist = foreach_delete_current(f->fromlist, cell);
3603 310 : result_relids = bms_add_member(result_relids, varno);
3604 : }
3605 : }
3606 :
3607 : /*
3608 : * Clean up if we dropped any RTE_RESULT RTEs. This is a bit
3609 : * inefficient if there's more than one, but it seems better to
3610 : * optimize the support code for the single-relid case.
3611 : */
3612 247424 : if (result_relids)
3613 : {
3614 298 : int varno = -1;
3615 :
3616 608 : while ((varno = bms_next_member(result_relids, varno)) >= 0)
3617 310 : remove_result_refs(root, varno, (Node *) f);
3618 : }
3619 :
3620 : /*
3621 : * If the FromExpr now has only one child, see if we can elide it.
3622 : * This is always valid if there are no quals, except at the top of
3623 : * the jointree (since Query.jointree is required to point to a
3624 : * FromExpr). Otherwise, we can do it if we can push the quals up to
3625 : * the parent node.
3626 : *
3627 : * Note: while it would not be terribly hard to generalize this
3628 : * transformation to merge multi-child FromExprs into their parent
3629 : * FromExpr, that risks making the parent join too expensive to plan.
3630 : * We leave it to later processing to decide heuristically whether
3631 : * that's a good idea. Pulling up a single child is always OK,
3632 : * however.
3633 : */
3634 247424 : if (list_length(f->fromlist) == 1 &&
3635 245680 : f != root->parse->jointree &&
3636 3830 : (f->quals == NULL || parent_quals != NULL))
3637 : {
3638 : /*
3639 : * Merge any quals up to parent. They should be in implicit-AND
3640 : * format by now, so we just need to concatenate lists. Put the
3641 : * child quals at the front, on the grounds that they should
3642 : * nominally be evaluated earlier.
3643 : */
3644 2638 : if (f->quals != NULL)
3645 1268 : *parent_quals = (Node *)
3646 1268 : list_concat(castNode(List, f->quals),
3647 : castNode(List, *parent_quals));
3648 2638 : return (Node *) linitial(f->fromlist);
3649 : }
3650 : }
3651 53766 : else if (IsA(jtnode, JoinExpr))
3652 : {
3653 53766 : JoinExpr *j = (JoinExpr *) jtnode;
3654 : int varno;
3655 :
3656 : /*
3657 : * First, recurse. We can absorb pushed-up FromExpr quals from either
3658 : * child into this node if the jointype is INNER, since then this is
3659 : * equivalent to a FromExpr. When the jointype is LEFT, we can absorb
3660 : * quals from the RHS child into the current node, as they're
3661 : * essentially degenerate quals of the outer join. Moreover, if we've
3662 : * been passed down a parent_quals pointer then we can allow quals of
3663 : * the LHS child to be absorbed into the parent. (This is important
3664 : * to ensure we remove single-child FromExprs immediately below
3665 : * commutable left joins.) For other jointypes, we can't move child
3666 : * quals up, or at least there's no particular reason to.
3667 : */
3668 53766 : j->larg = remove_useless_results_recurse(root, j->larg,
3669 53766 : (j->jointype == JOIN_INNER) ?
3670 : &j->quals :
3671 42338 : (j->jointype == JOIN_LEFT) ?
3672 42338 : parent_quals : NULL,
3673 : dropped_outer_joins);
3674 53766 : j->rarg = remove_useless_results_recurse(root, j->rarg,
3675 53766 : (j->jointype == JOIN_INNER ||
3676 42338 : j->jointype == JOIN_LEFT) ?
3677 : &j->quals : NULL,
3678 : dropped_outer_joins);
3679 :
3680 : /* Apply join-type-specific optimization rules */
3681 53766 : switch (j->jointype)
3682 : {
3683 11428 : case JOIN_INNER:
3684 :
3685 : /*
3686 : * An inner join is equivalent to a FromExpr, so if either
3687 : * side was simplified to an RTE_RESULT rel, we can replace
3688 : * the join with a FromExpr with just the other side.
3689 : * Furthermore, we can elide that FromExpr according to the
3690 : * same rules as above.
3691 : *
3692 : * Just as in the FromExpr case, we can't simplify if the
3693 : * other input rel references any PHVs that are marked as to
3694 : * be evaluated at the RTE_RESULT rel, because we can't
3695 : * postpone their evaluation in that case. But we only have
3696 : * to check this in cases where it's syntactically legal for
3697 : * the other input to have a LATERAL reference to the
3698 : * RTE_RESULT rel. Only RHSes of inner and left joins are
3699 : * allowed to have such refs.
3700 : */
3701 11428 : if ((varno = get_result_relid(root, j->larg)) != 0 &&
3702 48 : !find_dependent_phvs_in_jointree(root, j->rarg, varno))
3703 : {
3704 48 : remove_result_refs(root, varno, j->rarg);
3705 48 : if (j->quals != NULL && parent_quals == NULL)
3706 12 : jtnode = (Node *)
3707 12 : makeFromExpr(list_make1(j->rarg), j->quals);
3708 : else
3709 : {
3710 : /* Merge any quals up to parent */
3711 36 : if (j->quals != NULL)
3712 12 : *parent_quals = (Node *)
3713 12 : list_concat(castNode(List, j->quals),
3714 : castNode(List, *parent_quals));
3715 36 : jtnode = j->rarg;
3716 : }
3717 : }
3718 11380 : else if ((varno = get_result_relid(root, j->rarg)) != 0)
3719 : {
3720 644 : remove_result_refs(root, varno, j->larg);
3721 644 : if (j->quals != NULL && parent_quals == NULL)
3722 12 : jtnode = (Node *)
3723 12 : makeFromExpr(list_make1(j->larg), j->quals);
3724 : else
3725 : {
3726 : /* Merge any quals up to parent */
3727 632 : if (j->quals != NULL)
3728 582 : *parent_quals = (Node *)
3729 582 : list_concat(castNode(List, j->quals),
3730 : castNode(List, *parent_quals));
3731 632 : jtnode = j->larg;
3732 : }
3733 : }
3734 11428 : break;
3735 39348 : case JOIN_LEFT:
3736 :
3737 : /*
3738 : * We can simplify this case if the RHS is an RTE_RESULT, with
3739 : * two different possibilities:
3740 : *
3741 : * If the qual is empty (JOIN ON TRUE), then the join can be
3742 : * strength-reduced to a plain inner join, since each LHS row
3743 : * necessarily has exactly one join partner. So we can always
3744 : * discard the RHS, much as in the JOIN_INNER case above.
3745 : * (Again, the LHS could not contain a lateral reference to
3746 : * the RHS.)
3747 : *
3748 : * Otherwise, it's still true that each LHS row should be
3749 : * returned exactly once, and since the RHS returns no columns
3750 : * (unless there are PHVs that have to be evaluated there), we
3751 : * don't much care if it's null-extended or not. So in this
3752 : * case also, we can just ignore the qual and discard the left
3753 : * join.
3754 : */
3755 39348 : if ((varno = get_result_relid(root, j->rarg)) != 0 &&
3756 150 : (j->quals == NULL ||
3757 90 : !find_dependent_phvs(root, varno)))
3758 : {
3759 60 : remove_result_refs(root, varno, j->larg);
3760 60 : *dropped_outer_joins = bms_add_member(*dropped_outer_joins,
3761 : j->rtindex);
3762 60 : jtnode = j->larg;
3763 : }
3764 39348 : break;
3765 604 : case JOIN_SEMI:
3766 :
3767 : /*
3768 : * We may simplify this case if the RHS is an RTE_RESULT; the
3769 : * join qual becomes effectively just a filter qual for the
3770 : * LHS, since we should either return the LHS row or not. The
3771 : * filter clause must go into a new FromExpr if we can't push
3772 : * it up to the parent.
3773 : *
3774 : * There is a fine point about PHVs that are supposed to be
3775 : * evaluated at the RHS. Such PHVs could only appear in the
3776 : * semijoin's qual, since the rest of the query cannot
3777 : * reference any outputs of the semijoin's RHS. Therefore,
3778 : * they can't actually go to null before being examined, and
3779 : * it'd be OK to just remove the PHV wrapping. We don't have
3780 : * infrastructure for that, but remove_result_refs() will
3781 : * relabel them as to be evaluated at the LHS, which is fine.
3782 : *
3783 : * Also, we don't need to worry about removing traces of the
3784 : * join's rtindex, since it hasn't got one.
3785 : */
3786 604 : if ((varno = get_result_relid(root, j->rarg)) != 0)
3787 : {
3788 : Assert(j->rtindex == 0);
3789 36 : remove_result_refs(root, varno, j->larg);
3790 36 : if (j->quals != NULL && parent_quals == NULL)
3791 0 : jtnode = (Node *)
3792 0 : makeFromExpr(list_make1(j->larg), j->quals);
3793 : else
3794 : {
3795 : /* Merge any quals up to parent */
3796 36 : if (j->quals != NULL)
3797 36 : *parent_quals = (Node *)
3798 36 : list_concat(castNode(List, j->quals),
3799 : castNode(List, *parent_quals));
3800 36 : jtnode = j->larg;
3801 : }
3802 : }
3803 604 : break;
3804 2386 : case JOIN_FULL:
3805 : case JOIN_ANTI:
3806 : /* We have no special smarts for these cases */
3807 2386 : break;
3808 0 : default:
3809 : /* Note: JOIN_RIGHT should be gone at this point */
3810 0 : elog(ERROR, "unrecognized join type: %d",
3811 : (int) j->jointype);
3812 : break;
3813 : }
3814 : }
3815 : else
3816 0 : elog(ERROR, "unrecognized node type: %d",
3817 : (int) nodeTag(jtnode));
3818 598966 : return jtnode;
3819 : }
3820 :
3821 : /*
3822 : * get_result_relid
3823 : * If jtnode is a RangeTblRef for an RTE_RESULT RTE, return its relid;
3824 : * otherwise return 0.
3825 : */
3826 : static int
3827 67940 : get_result_relid(PlannerInfo *root, Node *jtnode)
3828 : {
3829 : int varno;
3830 :
3831 67940 : if (!IsA(jtnode, RangeTblRef))
3832 5672 : return 0;
3833 62268 : varno = ((RangeTblRef *) jtnode)->rtindex;
3834 62268 : if (rt_fetch(varno, root->parse->rtable)->rtekind != RTE_RESULT)
3835 61056 : return 0;
3836 1212 : return varno;
3837 : }
3838 :
3839 : /*
3840 : * remove_result_refs
3841 : * Helper routine for dropping an unneeded RTE_RESULT RTE.
3842 : *
3843 : * This doesn't physically remove the RTE from the jointree, because that's
3844 : * more easily handled in remove_useless_results_recurse. What it does do
3845 : * is the necessary cleanup in the rest of the tree: we must adjust any PHVs
3846 : * that may reference the RTE. Be sure to call this at a point where the
3847 : * jointree is valid (no disconnected nodes).
3848 : *
3849 : * Note that we don't need to process the append_rel_list, since RTEs
3850 : * referenced directly in the jointree won't be appendrel members.
3851 : *
3852 : * varno is the RTE_RESULT's relid.
3853 : * newjtloc is the jointree location at which any PHVs referencing the
3854 : * RTE_RESULT should be evaluated instead.
3855 : */
3856 : static void
3857 1098 : remove_result_refs(PlannerInfo *root, int varno, Node *newjtloc)
3858 : {
3859 : /* Fix up PlaceHolderVars as needed */
3860 : /* If there are no PHVs anywhere, we can skip this bit */
3861 1098 : if (root->glob->lastPHId != 0)
3862 : {
3863 : Relids subrelids;
3864 :
3865 176 : subrelids = get_relids_in_jointree(newjtloc, true, false);
3866 : Assert(!bms_is_empty(subrelids));
3867 176 : substitute_phv_relids((Node *) root->parse, varno, subrelids);
3868 176 : fix_append_rel_relids(root, varno, subrelids);
3869 : }
3870 :
3871 : /*
3872 : * We also need to remove any PlanRowMark referencing the RTE, but we
3873 : * postpone that work until we return to remove_useless_result_rtes.
3874 : */
3875 1098 : }
3876 :
3877 :
3878 : /*
3879 : * find_dependent_phvs - are there any PlaceHolderVars whose relids are
3880 : * exactly the given varno?
3881 : *
3882 : * find_dependent_phvs should be used when we want to see if there are
3883 : * any such PHVs anywhere in the Query. Another use-case is to see if
3884 : * a subtree of the join tree contains such PHVs; but for that, we have
3885 : * to look not only at the join tree nodes themselves but at the
3886 : * referenced RTEs. For that, use find_dependent_phvs_in_jointree.
3887 : */
3888 :
3889 : typedef struct
3890 : {
3891 : Relids relids;
3892 : int sublevels_up;
3893 : } find_dependent_phvs_context;
3894 :
3895 : static bool
3896 2400 : find_dependent_phvs_walker(Node *node,
3897 : find_dependent_phvs_context *context)
3898 : {
3899 2400 : if (node == NULL)
3900 564 : return false;
3901 1836 : if (IsA(node, PlaceHolderVar))
3902 : {
3903 156 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
3904 :
3905 312 : if (phv->phlevelsup == context->sublevels_up &&
3906 156 : bms_equal(context->relids, phv->phrels))
3907 114 : return true;
3908 : /* fall through to examine children */
3909 : }
3910 1722 : if (IsA(node, Query))
3911 : {
3912 : /* Recurse into subselects */
3913 : bool result;
3914 :
3915 48 : context->sublevels_up++;
3916 48 : result = query_tree_walker((Query *) node,
3917 : find_dependent_phvs_walker,
3918 : context, 0);
3919 48 : context->sublevels_up--;
3920 48 : return result;
3921 : }
3922 : /* Shouldn't need to handle most planner auxiliary nodes here */
3923 : Assert(!IsA(node, SpecialJoinInfo));
3924 : Assert(!IsA(node, PlaceHolderInfo));
3925 : Assert(!IsA(node, MinMaxAggInfo));
3926 :
3927 1674 : return expression_tree_walker(node, find_dependent_phvs_walker, context);
3928 : }
3929 :
3930 : static bool
3931 90 : find_dependent_phvs(PlannerInfo *root, int varno)
3932 : {
3933 : find_dependent_phvs_context context;
3934 :
3935 : /* If there are no PHVs anywhere, we needn't work hard */
3936 90 : if (root->glob->lastPHId == 0)
3937 0 : return false;
3938 :
3939 90 : context.relids = bms_make_singleton(varno);
3940 90 : context.sublevels_up = 0;
3941 :
3942 90 : if (query_tree_walker(root->parse, find_dependent_phvs_walker, &context, 0))
3943 90 : return true;
3944 : /* The append_rel_list could be populated already, so check it too */
3945 0 : if (expression_tree_walker((Node *) root->append_rel_list,
3946 : find_dependent_phvs_walker,
3947 : &context))
3948 0 : return true;
3949 0 : return false;
3950 : }
3951 :
3952 : static bool
3953 382 : find_dependent_phvs_in_jointree(PlannerInfo *root, Node *node, int varno)
3954 : {
3955 : find_dependent_phvs_context context;
3956 : Relids subrelids;
3957 : int relid;
3958 :
3959 : /* If there are no PHVs anywhere, we needn't work hard */
3960 382 : if (root->glob->lastPHId == 0)
3961 316 : return false;
3962 :
3963 66 : context.relids = bms_make_singleton(varno);
3964 66 : context.sublevels_up = 0;
3965 :
3966 : /*
3967 : * See if the jointree fragment itself contains references (in join quals)
3968 : */
3969 66 : if (find_dependent_phvs_walker(node, &context))
3970 0 : return true;
3971 :
3972 : /*
3973 : * Otherwise, identify the set of referenced RTEs (we can ignore joins,
3974 : * since they should be flattened already, so their join alias lists no
3975 : * longer matter), and tediously check each RTE. We can ignore RTEs that
3976 : * are not marked LATERAL, though, since they couldn't possibly contain
3977 : * any cross-references to other RTEs.
3978 : */
3979 66 : subrelids = get_relids_in_jointree(node, false, false);
3980 66 : relid = -1;
3981 144 : while ((relid = bms_next_member(subrelids, relid)) >= 0)
3982 : {
3983 102 : RangeTblEntry *rte = rt_fetch(relid, root->parse->rtable);
3984 :
3985 126 : if (rte->lateral &&
3986 24 : range_table_entry_walker(rte, find_dependent_phvs_walker, &context, 0))
3987 24 : return true;
3988 : }
3989 :
3990 42 : return false;
3991 : }
3992 :
3993 : /*
3994 : * substitute_phv_relids - adjust PlaceHolderVar relid sets after pulling up
3995 : * a subquery or removing an RTE_RESULT jointree item
3996 : *
3997 : * Find any PlaceHolderVar nodes in the given tree that reference the
3998 : * pulled-up relid, and change them to reference the replacement relid(s).
3999 : *
4000 : * NOTE: although this has the form of a walker, we cheat and modify the
4001 : * nodes in-place. This should be OK since the tree was copied by
4002 : * pullup_replace_vars earlier. Avoid scribbling on the original values of
4003 : * the bitmapsets, though, because expression_tree_mutator doesn't copy those.
4004 : */
4005 :
4006 : typedef struct
4007 : {
4008 : int varno;
4009 : int sublevels_up;
4010 : Relids subrelids;
4011 : } substitute_phv_relids_context;
4012 :
4013 : static bool
4014 204208 : substitute_phv_relids_walker(Node *node,
4015 : substitute_phv_relids_context *context)
4016 : {
4017 204208 : if (node == NULL)
4018 78410 : return false;
4019 125798 : if (IsA(node, PlaceHolderVar))
4020 : {
4021 5942 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
4022 :
4023 11852 : if (phv->phlevelsup == context->sublevels_up &&
4024 5910 : bms_is_member(context->varno, phv->phrels))
4025 : {
4026 7996 : phv->phrels = bms_union(phv->phrels,
4027 3998 : context->subrelids);
4028 3998 : phv->phrels = bms_del_member(phv->phrels,
4029 : context->varno);
4030 : /* Assert we haven't broken the PHV */
4031 : Assert(!bms_is_empty(phv->phrels));
4032 : }
4033 : /* fall through to examine children */
4034 : }
4035 125798 : if (IsA(node, Query))
4036 : {
4037 : /* Recurse into subselects */
4038 : bool result;
4039 :
4040 3244 : context->sublevels_up++;
4041 3244 : result = query_tree_walker((Query *) node,
4042 : substitute_phv_relids_walker,
4043 : context, 0);
4044 3244 : context->sublevels_up--;
4045 3244 : return result;
4046 : }
4047 : /* Shouldn't need to handle planner auxiliary nodes here */
4048 : Assert(!IsA(node, SpecialJoinInfo));
4049 : Assert(!IsA(node, AppendRelInfo));
4050 : Assert(!IsA(node, PlaceHolderInfo));
4051 : Assert(!IsA(node, MinMaxAggInfo));
4052 :
4053 122554 : return expression_tree_walker(node, substitute_phv_relids_walker, context);
4054 : }
4055 :
4056 : static void
4057 1924 : substitute_phv_relids(Node *node, int varno, Relids subrelids)
4058 : {
4059 : substitute_phv_relids_context context;
4060 :
4061 1924 : context.varno = varno;
4062 1924 : context.sublevels_up = 0;
4063 1924 : context.subrelids = subrelids;
4064 :
4065 : /*
4066 : * Must be prepared to start with a Query or a bare expression tree.
4067 : */
4068 1924 : query_or_expression_tree_walker(node,
4069 : substitute_phv_relids_walker,
4070 : &context,
4071 : 0);
4072 1924 : }
4073 :
4074 : /*
4075 : * fix_append_rel_relids: update RT-index fields of AppendRelInfo nodes
4076 : *
4077 : * When we pull up a subquery, any AppendRelInfo references to the subquery's
4078 : * RT index have to be replaced by the substituted relid (and there had better
4079 : * be only one). We also need to apply substitute_phv_relids to their
4080 : * translated_vars lists, since those might contain PlaceHolderVars.
4081 : *
4082 : * We assume we may modify the AppendRelInfo nodes in-place.
4083 : */
4084 : static void
4085 4668 : fix_append_rel_relids(PlannerInfo *root, int varno, Relids subrelids)
4086 : {
4087 : ListCell *l;
4088 4668 : int subvarno = -1;
4089 :
4090 : /*
4091 : * We only want to extract the member relid once, but we mustn't fail
4092 : * immediately if there are multiple members; it could be that none of the
4093 : * AppendRelInfo nodes refer to it. So compute it on first use. Note that
4094 : * bms_singleton_member will complain if set is not singleton.
4095 : */
4096 9910 : foreach(l, root->append_rel_list)
4097 : {
4098 5242 : AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
4099 :
4100 : /* The parent_relid shouldn't ever be a pullup target */
4101 : Assert(appinfo->parent_relid != varno);
4102 :
4103 5242 : if (appinfo->child_relid == varno)
4104 : {
4105 2912 : if (subvarno < 0)
4106 2912 : subvarno = bms_singleton_member(subrelids);
4107 2912 : appinfo->child_relid = subvarno;
4108 : }
4109 :
4110 : /* Also fix up any PHVs in its translated vars */
4111 5242 : if (root->glob->lastPHId != 0)
4112 114 : substitute_phv_relids((Node *) appinfo->translated_vars,
4113 : varno, subrelids);
4114 : }
4115 4668 : }
4116 :
4117 : /*
4118 : * get_relids_in_jointree: get set of RT indexes present in a jointree
4119 : *
4120 : * Base-relation relids are always included in the result.
4121 : * If include_outer_joins is true, outer-join RT indexes are included.
4122 : * If include_inner_joins is true, inner-join RT indexes are included.
4123 : *
4124 : * Note that for most purposes in the planner, outer joins are included
4125 : * in standard relid sets. Setting include_inner_joins true is only
4126 : * appropriate for special purposes during subquery flattening.
4127 : */
4128 : Relids
4129 79880 : get_relids_in_jointree(Node *jtnode, bool include_outer_joins,
4130 : bool include_inner_joins)
4131 : {
4132 79880 : Relids result = NULL;
4133 :
4134 79880 : if (jtnode == NULL)
4135 0 : return result;
4136 79880 : if (IsA(jtnode, RangeTblRef))
4137 : {
4138 40048 : int varno = ((RangeTblRef *) jtnode)->rtindex;
4139 :
4140 40048 : result = bms_make_singleton(varno);
4141 : }
4142 39832 : else if (IsA(jtnode, FromExpr))
4143 : {
4144 35132 : FromExpr *f = (FromExpr *) jtnode;
4145 : ListCell *l;
4146 :
4147 71404 : foreach(l, f->fromlist)
4148 : {
4149 36272 : result = bms_join(result,
4150 36272 : get_relids_in_jointree(lfirst(l),
4151 : include_outer_joins,
4152 : include_inner_joins));
4153 : }
4154 : }
4155 4700 : else if (IsA(jtnode, JoinExpr))
4156 : {
4157 4700 : JoinExpr *j = (JoinExpr *) jtnode;
4158 :
4159 4700 : result = get_relids_in_jointree(j->larg,
4160 : include_outer_joins,
4161 : include_inner_joins);
4162 4700 : result = bms_join(result,
4163 : get_relids_in_jointree(j->rarg,
4164 : include_outer_joins,
4165 : include_inner_joins));
4166 4700 : if (j->rtindex)
4167 : {
4168 4422 : if (j->jointype == JOIN_INNER)
4169 : {
4170 1684 : if (include_inner_joins)
4171 240 : result = bms_add_member(result, j->rtindex);
4172 : }
4173 : else
4174 : {
4175 2738 : if (include_outer_joins)
4176 1670 : result = bms_add_member(result, j->rtindex);
4177 : }
4178 : }
4179 : }
4180 : else
4181 0 : elog(ERROR, "unrecognized node type: %d",
4182 : (int) nodeTag(jtnode));
4183 79880 : return result;
4184 : }
4185 :
4186 : /*
4187 : * get_relids_for_join: get set of base+OJ RT indexes making up a join
4188 : */
4189 : Relids
4190 322 : get_relids_for_join(Query *query, int joinrelid)
4191 : {
4192 : Node *jtnode;
4193 :
4194 322 : jtnode = find_jointree_node_for_rel((Node *) query->jointree,
4195 : joinrelid);
4196 322 : if (!jtnode)
4197 0 : elog(ERROR, "could not find join node %d", joinrelid);
4198 322 : return get_relids_in_jointree(jtnode, true, false);
4199 : }
4200 :
4201 : /*
4202 : * find_jointree_node_for_rel: locate jointree node for a base or join RT index
4203 : *
4204 : * Returns NULL if not found
4205 : */
4206 : static Node *
4207 1562 : find_jointree_node_for_rel(Node *jtnode, int relid)
4208 : {
4209 1562 : if (jtnode == NULL)
4210 0 : return NULL;
4211 1562 : if (IsA(jtnode, RangeTblRef))
4212 : {
4213 406 : int varno = ((RangeTblRef *) jtnode)->rtindex;
4214 :
4215 406 : if (relid == varno)
4216 0 : return jtnode;
4217 : }
4218 1156 : else if (IsA(jtnode, FromExpr))
4219 : {
4220 332 : FromExpr *f = (FromExpr *) jtnode;
4221 : ListCell *l;
4222 :
4223 350 : foreach(l, f->fromlist)
4224 : {
4225 350 : jtnode = find_jointree_node_for_rel(lfirst(l), relid);
4226 350 : if (jtnode)
4227 332 : return jtnode;
4228 : }
4229 : }
4230 824 : else if (IsA(jtnode, JoinExpr))
4231 : {
4232 824 : JoinExpr *j = (JoinExpr *) jtnode;
4233 :
4234 824 : if (relid == j->rtindex)
4235 322 : return jtnode;
4236 502 : jtnode = find_jointree_node_for_rel(j->larg, relid);
4237 502 : if (jtnode)
4238 114 : return jtnode;
4239 388 : jtnode = find_jointree_node_for_rel(j->rarg, relid);
4240 388 : if (jtnode)
4241 388 : return jtnode;
4242 : }
4243 : else
4244 0 : elog(ERROR, "unrecognized node type: %d",
4245 : (int) nodeTag(jtnode));
4246 406 : return NULL;
4247 : }
4248 :
4249 : /*
4250 : * get_nullingrels: collect info about which outer joins null which relations
4251 : *
4252 : * The result struct contains, for each leaf relation used in the query,
4253 : * the set of relids of outer joins that potentially null that rel.
4254 : */
4255 : static nullingrel_info *
4256 908 : get_nullingrels(Query *parse)
4257 : {
4258 908 : nullingrel_info *result = palloc_object(nullingrel_info);
4259 :
4260 908 : result->rtlength = list_length(parse->rtable);
4261 908 : result->nullingrels = palloc0_array(Relids, result->rtlength + 1);
4262 908 : get_nullingrels_recurse((Node *) parse->jointree, NULL, result);
4263 908 : return result;
4264 : }
4265 :
4266 : /*
4267 : * Recursive guts of get_nullingrels().
4268 : *
4269 : * Note: at any recursion level, the passed-down upper_nullingrels must be
4270 : * treated as a constant, but it can be stored directly into *info
4271 : * if we're at leaf level. Upper recursion levels do not free their mutated
4272 : * copies of the nullingrels, because those are probably referenced by
4273 : * at least one leaf rel.
4274 : */
4275 : static void
4276 4206 : get_nullingrels_recurse(Node *jtnode, Relids upper_nullingrels,
4277 : nullingrel_info *info)
4278 : {
4279 4206 : if (jtnode == NULL)
4280 0 : return;
4281 4206 : if (IsA(jtnode, RangeTblRef))
4282 : {
4283 2284 : int varno = ((RangeTblRef *) jtnode)->rtindex;
4284 :
4285 : Assert(varno > 0 && varno <= info->rtlength);
4286 2284 : info->nullingrels[varno] = upper_nullingrels;
4287 : }
4288 1922 : else if (IsA(jtnode, FromExpr))
4289 : {
4290 974 : FromExpr *f = (FromExpr *) jtnode;
4291 : ListCell *l;
4292 :
4293 2376 : foreach(l, f->fromlist)
4294 : {
4295 1402 : get_nullingrels_recurse(lfirst(l), upper_nullingrels, info);
4296 : }
4297 : }
4298 948 : else if (IsA(jtnode, JoinExpr))
4299 : {
4300 948 : JoinExpr *j = (JoinExpr *) jtnode;
4301 : Relids local_nullingrels;
4302 :
4303 948 : switch (j->jointype)
4304 : {
4305 186 : case JOIN_INNER:
4306 186 : get_nullingrels_recurse(j->larg, upper_nullingrels, info);
4307 186 : get_nullingrels_recurse(j->rarg, upper_nullingrels, info);
4308 186 : break;
4309 756 : case JOIN_LEFT:
4310 : case JOIN_SEMI:
4311 : case JOIN_ANTI:
4312 756 : local_nullingrels = bms_add_member(bms_copy(upper_nullingrels),
4313 : j->rtindex);
4314 756 : get_nullingrels_recurse(j->larg, upper_nullingrels, info);
4315 756 : get_nullingrels_recurse(j->rarg, local_nullingrels, info);
4316 756 : break;
4317 6 : case JOIN_FULL:
4318 6 : local_nullingrels = bms_add_member(bms_copy(upper_nullingrels),
4319 : j->rtindex);
4320 6 : get_nullingrels_recurse(j->larg, local_nullingrels, info);
4321 6 : get_nullingrels_recurse(j->rarg, local_nullingrels, info);
4322 6 : break;
4323 0 : case JOIN_RIGHT:
4324 0 : local_nullingrels = bms_add_member(bms_copy(upper_nullingrels),
4325 : j->rtindex);
4326 0 : get_nullingrels_recurse(j->larg, local_nullingrels, info);
4327 0 : get_nullingrels_recurse(j->rarg, upper_nullingrels, info);
4328 0 : break;
4329 0 : default:
4330 0 : elog(ERROR, "unrecognized join type: %d",
4331 : (int) j->jointype);
4332 : break;
4333 : }
4334 : }
4335 : else
4336 0 : elog(ERROR, "unrecognized node type: %d",
4337 : (int) nodeTag(jtnode));
4338 : }
|