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