1 /*-------------------------------------------------------------------------
2 *
3 * relnode.c
4 * Relation-node lookup/construction routines
5 *
6 * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/optimizer/util/relnode.c
12 *
13 *-------------------------------------------------------------------------
14 */
15 #include "postgres.h"
16
17 #include "miscadmin.h"
18 #include "optimizer/clauses.h"
19 #include "optimizer/cost.h"
20 #include "optimizer/pathnode.h"
21 #include "optimizer/paths.h"
22 #include "optimizer/placeholder.h"
23 #include "optimizer/plancat.h"
24 #include "optimizer/restrictinfo.h"
25 #include "optimizer/tlist.h"
26 #include "utils/hsearch.h"
27
28
29 typedef struct JoinHashEntry
30 {
31 Relids join_relids; /* hash key --- MUST BE FIRST */
32 RelOptInfo *join_rel;
33 } JoinHashEntry;
34
35 static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
36 RelOptInfo *input_rel);
37 static List *build_joinrel_restrictlist(PlannerInfo *root,
38 RelOptInfo *joinrel,
39 RelOptInfo *outer_rel,
40 RelOptInfo *inner_rel);
41 static void build_joinrel_joinlist(RelOptInfo *joinrel,
42 RelOptInfo *outer_rel,
43 RelOptInfo *inner_rel);
44 static List *subbuild_joinrel_restrictlist(RelOptInfo *joinrel,
45 List *joininfo_list,
46 List *new_restrictlist);
47 static List *subbuild_joinrel_joinlist(RelOptInfo *joinrel,
48 List *joininfo_list,
49 List *new_joininfo);
50
51
52 /*
53 * setup_simple_rel_arrays
54 * Prepare the arrays we use for quickly accessing base relations.
55 */
56 void
setup_simple_rel_arrays(PlannerInfo * root)57 setup_simple_rel_arrays(PlannerInfo *root)
58 {
59 Index rti;
60 ListCell *lc;
61
62 /* Arrays are accessed using RT indexes (1..N) */
63 root->simple_rel_array_size = list_length(root->parse->rtable) + 1;
64
65 /* simple_rel_array is initialized to all NULLs */
66 root->simple_rel_array = (RelOptInfo **)
67 palloc0(root->simple_rel_array_size * sizeof(RelOptInfo *));
68
69 /* simple_rte_array is an array equivalent of the rtable list */
70 root->simple_rte_array = (RangeTblEntry **)
71 palloc0(root->simple_rel_array_size * sizeof(RangeTblEntry *));
72 rti = 1;
73 foreach(lc, root->parse->rtable)
74 {
75 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
76
77 root->simple_rte_array[rti++] = rte;
78 }
79 }
80
81 /*
82 * build_simple_rel
83 * Construct a new RelOptInfo for a base relation or 'other' relation.
84 */
85 RelOptInfo *
build_simple_rel(PlannerInfo * root,int relid,RelOptKind reloptkind)86 build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
87 {
88 RelOptInfo *rel;
89 RangeTblEntry *rte;
90
91 /* Rel should not exist already */
92 Assert(relid > 0 && relid < root->simple_rel_array_size);
93 if (root->simple_rel_array[relid] != NULL)
94 elog(ERROR, "rel %d already exists", relid);
95
96 /* Fetch RTE for relation */
97 rte = root->simple_rte_array[relid];
98 Assert(rte != NULL);
99
100 rel = makeNode(RelOptInfo);
101 rel->reloptkind = reloptkind;
102 rel->relids = bms_make_singleton(relid);
103 rel->rows = 0;
104 /* cheap startup cost is interesting iff not all tuples to be retrieved */
105 rel->consider_startup = (root->tuple_fraction > 0);
106 rel->consider_param_startup = false; /* might get changed later */
107 rel->consider_parallel = false; /* might get changed later */
108 rel->reltarget = create_empty_pathtarget();
109 rel->pathlist = NIL;
110 rel->ppilist = NIL;
111 rel->partial_pathlist = NIL;
112 rel->cheapest_startup_path = NULL;
113 rel->cheapest_total_path = NULL;
114 rel->cheapest_unique_path = NULL;
115 rel->cheapest_parameterized_paths = NIL;
116 rel->direct_lateral_relids = NULL;
117 rel->lateral_relids = NULL;
118 rel->relid = relid;
119 rel->rtekind = rte->rtekind;
120 /* min_attr, max_attr, attr_needed, attr_widths are set below */
121 rel->lateral_vars = NIL;
122 rel->lateral_referencers = NULL;
123 rel->indexlist = NIL;
124 rel->pages = 0;
125 rel->tuples = 0;
126 rel->allvisfrac = 0;
127 rel->subroot = NULL;
128 rel->subplan_params = NIL;
129 rel->rel_parallel_workers = -1; /* set up in get_relation_info */
130 rel->serverid = InvalidOid;
131 rel->userid = rte->checkAsUser;
132 rel->useridiscurrent = false;
133 rel->fdwroutine = NULL;
134 rel->fdw_private = NULL;
135 rel->baserestrictinfo = NIL;
136 rel->baserestrictcost.startup = 0;
137 rel->baserestrictcost.per_tuple = 0;
138 rel->joininfo = NIL;
139 rel->has_eclass_joins = false;
140
141 /* Check type of rtable entry */
142 switch (rte->rtekind)
143 {
144 case RTE_RELATION:
145 /* Table --- retrieve statistics from the system catalogs */
146 get_relation_info(root, rte->relid, rte->inh, rel);
147 break;
148 case RTE_SUBQUERY:
149 case RTE_FUNCTION:
150 case RTE_VALUES:
151 case RTE_CTE:
152
153 /*
154 * Subquery, function, or values list --- set up attr range and
155 * arrays
156 *
157 * Note: 0 is included in range to support whole-row Vars
158 */
159 rel->min_attr = 0;
160 rel->max_attr = list_length(rte->eref->colnames);
161 rel->attr_needed = (Relids *)
162 palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids));
163 rel->attr_widths = (int32 *)
164 palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32));
165 break;
166 default:
167 elog(ERROR, "unrecognized RTE kind: %d",
168 (int) rte->rtekind);
169 break;
170 }
171
172 /* Save the finished struct in the query's simple_rel_array */
173 root->simple_rel_array[relid] = rel;
174
175 /*
176 * If this rel is an appendrel parent, recurse to build "other rel"
177 * RelOptInfos for its children. They are "other rels" because they are
178 * not in the main join tree, but we will need RelOptInfos to plan access
179 * to them.
180 */
181 if (rte->inh)
182 {
183 ListCell *l;
184
185 foreach(l, root->append_rel_list)
186 {
187 AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
188
189 /* append_rel_list contains all append rels; ignore others */
190 if (appinfo->parent_relid != relid)
191 continue;
192
193 (void) build_simple_rel(root, appinfo->child_relid,
194 RELOPT_OTHER_MEMBER_REL);
195 }
196 }
197
198 return rel;
199 }
200
201 /*
202 * find_base_rel
203 * Find a base or other relation entry, which must already exist.
204 */
205 RelOptInfo *
find_base_rel(PlannerInfo * root,int relid)206 find_base_rel(PlannerInfo *root, int relid)
207 {
208 RelOptInfo *rel;
209
210 Assert(relid > 0);
211
212 if (relid < root->simple_rel_array_size)
213 {
214 rel = root->simple_rel_array[relid];
215 if (rel)
216 return rel;
217 }
218
219 elog(ERROR, "no relation entry for relid %d", relid);
220
221 return NULL; /* keep compiler quiet */
222 }
223
224 /*
225 * build_join_rel_hash
226 * Construct the auxiliary hash table for join relations.
227 */
228 static void
build_join_rel_hash(PlannerInfo * root)229 build_join_rel_hash(PlannerInfo *root)
230 {
231 HTAB *hashtab;
232 HASHCTL hash_ctl;
233 ListCell *l;
234
235 /* Create the hash table */
236 MemSet(&hash_ctl, 0, sizeof(hash_ctl));
237 hash_ctl.keysize = sizeof(Relids);
238 hash_ctl.entrysize = sizeof(JoinHashEntry);
239 hash_ctl.hash = bitmap_hash;
240 hash_ctl.match = bitmap_match;
241 hash_ctl.hcxt = CurrentMemoryContext;
242 hashtab = hash_create("JoinRelHashTable",
243 256L,
244 &hash_ctl,
245 HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT);
246
247 /* Insert all the already-existing joinrels */
248 foreach(l, root->join_rel_list)
249 {
250 RelOptInfo *rel = (RelOptInfo *) lfirst(l);
251 JoinHashEntry *hentry;
252 bool found;
253
254 hentry = (JoinHashEntry *) hash_search(hashtab,
255 &(rel->relids),
256 HASH_ENTER,
257 &found);
258 Assert(!found);
259 hentry->join_rel = rel;
260 }
261
262 root->join_rel_hash = hashtab;
263 }
264
265 /*
266 * find_join_rel
267 * Returns relation entry corresponding to 'relids' (a set of RT indexes),
268 * or NULL if none exists. This is for join relations.
269 */
270 RelOptInfo *
find_join_rel(PlannerInfo * root,Relids relids)271 find_join_rel(PlannerInfo *root, Relids relids)
272 {
273 /*
274 * Switch to using hash lookup when list grows "too long". The threshold
275 * is arbitrary and is known only here.
276 */
277 if (!root->join_rel_hash && list_length(root->join_rel_list) > 32)
278 build_join_rel_hash(root);
279
280 /*
281 * Use either hashtable lookup or linear search, as appropriate.
282 *
283 * Note: the seemingly redundant hashkey variable is used to avoid taking
284 * the address of relids; unless the compiler is exceedingly smart, doing
285 * so would force relids out of a register and thus probably slow down the
286 * list-search case.
287 */
288 if (root->join_rel_hash)
289 {
290 Relids hashkey = relids;
291 JoinHashEntry *hentry;
292
293 hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
294 &hashkey,
295 HASH_FIND,
296 NULL);
297 if (hentry)
298 return hentry->join_rel;
299 }
300 else
301 {
302 ListCell *l;
303
304 foreach(l, root->join_rel_list)
305 {
306 RelOptInfo *rel = (RelOptInfo *) lfirst(l);
307
308 if (bms_equal(rel->relids, relids))
309 return rel;
310 }
311 }
312
313 return NULL;
314 }
315
316 /*
317 * build_join_rel
318 * Returns relation entry corresponding to the union of two given rels,
319 * creating a new relation entry if none already exists.
320 *
321 * 'joinrelids' is the Relids set that uniquely identifies the join
322 * 'outer_rel' and 'inner_rel' are relation nodes for the relations to be
323 * joined
324 * 'sjinfo': join context info
325 * 'restrictlist_ptr': result variable. If not NULL, *restrictlist_ptr
326 * receives the list of RestrictInfo nodes that apply to this
327 * particular pair of joinable relations.
328 *
329 * restrictlist_ptr makes the routine's API a little grotty, but it saves
330 * duplicated calculation of the restrictlist...
331 */
332 RelOptInfo *
build_join_rel(PlannerInfo * root,Relids joinrelids,RelOptInfo * outer_rel,RelOptInfo * inner_rel,SpecialJoinInfo * sjinfo,List ** restrictlist_ptr)333 build_join_rel(PlannerInfo *root,
334 Relids joinrelids,
335 RelOptInfo *outer_rel,
336 RelOptInfo *inner_rel,
337 SpecialJoinInfo *sjinfo,
338 List **restrictlist_ptr)
339 {
340 RelOptInfo *joinrel;
341 List *restrictlist;
342
343 /*
344 * See if we already have a joinrel for this set of base rels.
345 */
346 joinrel = find_join_rel(root, joinrelids);
347
348 if (joinrel)
349 {
350 /*
351 * Yes, so we only need to figure the restrictlist for this particular
352 * pair of component relations.
353 */
354 if (restrictlist_ptr)
355 *restrictlist_ptr = build_joinrel_restrictlist(root,
356 joinrel,
357 outer_rel,
358 inner_rel);
359 return joinrel;
360 }
361
362 /*
363 * Nope, so make one.
364 */
365 joinrel = makeNode(RelOptInfo);
366 joinrel->reloptkind = RELOPT_JOINREL;
367 joinrel->relids = bms_copy(joinrelids);
368 joinrel->rows = 0;
369 /* cheap startup cost is interesting iff not all tuples to be retrieved */
370 joinrel->consider_startup = (root->tuple_fraction > 0);
371 joinrel->consider_param_startup = false;
372 joinrel->consider_parallel = false;
373 joinrel->reltarget = create_empty_pathtarget();
374 joinrel->pathlist = NIL;
375 joinrel->ppilist = NIL;
376 joinrel->partial_pathlist = NIL;
377 joinrel->cheapest_startup_path = NULL;
378 joinrel->cheapest_total_path = NULL;
379 joinrel->cheapest_unique_path = NULL;
380 joinrel->cheapest_parameterized_paths = NIL;
381 /* init direct_lateral_relids from children; we'll finish it up below */
382 joinrel->direct_lateral_relids =
383 bms_union(outer_rel->direct_lateral_relids,
384 inner_rel->direct_lateral_relids);
385 joinrel->lateral_relids = min_join_parameterization(root, joinrel->relids,
386 outer_rel, inner_rel);
387 joinrel->relid = 0; /* indicates not a baserel */
388 joinrel->rtekind = RTE_JOIN;
389 joinrel->min_attr = 0;
390 joinrel->max_attr = 0;
391 joinrel->attr_needed = NULL;
392 joinrel->attr_widths = NULL;
393 joinrel->lateral_vars = NIL;
394 joinrel->lateral_referencers = NULL;
395 joinrel->indexlist = NIL;
396 joinrel->pages = 0;
397 joinrel->tuples = 0;
398 joinrel->allvisfrac = 0;
399 joinrel->subroot = NULL;
400 joinrel->subplan_params = NIL;
401 joinrel->rel_parallel_workers = -1;
402 joinrel->serverid = InvalidOid;
403 joinrel->userid = InvalidOid;
404 joinrel->useridiscurrent = false;
405 joinrel->fdwroutine = NULL;
406 joinrel->fdw_private = NULL;
407 joinrel->baserestrictinfo = NIL;
408 joinrel->baserestrictcost.startup = 0;
409 joinrel->baserestrictcost.per_tuple = 0;
410 joinrel->joininfo = NIL;
411 joinrel->has_eclass_joins = false;
412
413 /*
414 * Set up foreign-join fields if outer and inner relation are foreign
415 * tables (or joins) belonging to the same server and assigned to the same
416 * user to check access permissions as. In addition to an exact match of
417 * userid, we allow the case where one side has zero userid (implying
418 * current user) and the other side has explicit userid that happens to
419 * equal the current user; but in that case, pushdown of the join is only
420 * valid for the current user. The useridiscurrent field records whether
421 * we had to make such an assumption for this join or any sub-join.
422 *
423 * Otherwise these fields are left invalid, so GetForeignJoinPaths will
424 * not be called for the join relation.
425 */
426 if (OidIsValid(outer_rel->serverid) &&
427 inner_rel->serverid == outer_rel->serverid)
428 {
429 if (inner_rel->userid == outer_rel->userid)
430 {
431 joinrel->serverid = outer_rel->serverid;
432 joinrel->userid = outer_rel->userid;
433 joinrel->useridiscurrent = outer_rel->useridiscurrent || inner_rel->useridiscurrent;
434 joinrel->fdwroutine = outer_rel->fdwroutine;
435 }
436 else if (!OidIsValid(inner_rel->userid) &&
437 outer_rel->userid == GetUserId())
438 {
439 joinrel->serverid = outer_rel->serverid;
440 joinrel->userid = outer_rel->userid;
441 joinrel->useridiscurrent = true;
442 joinrel->fdwroutine = outer_rel->fdwroutine;
443 }
444 else if (!OidIsValid(outer_rel->userid) &&
445 inner_rel->userid == GetUserId())
446 {
447 joinrel->serverid = outer_rel->serverid;
448 joinrel->userid = inner_rel->userid;
449 joinrel->useridiscurrent = true;
450 joinrel->fdwroutine = outer_rel->fdwroutine;
451 }
452 }
453
454 /*
455 * Create a new tlist containing just the vars that need to be output from
456 * this join (ie, are needed for higher joinclauses or final output).
457 *
458 * NOTE: the tlist order for a join rel will depend on which pair of outer
459 * and inner rels we first try to build it from. But the contents should
460 * be the same regardless.
461 */
462 build_joinrel_tlist(root, joinrel, outer_rel);
463 build_joinrel_tlist(root, joinrel, inner_rel);
464 add_placeholders_to_joinrel(root, joinrel, outer_rel, inner_rel);
465
466 /*
467 * add_placeholders_to_joinrel also took care of adding the ph_lateral
468 * sets of any PlaceHolderVars computed here to direct_lateral_relids, so
469 * now we can finish computing that. This is much like the computation of
470 * the transitively-closed lateral_relids in min_join_parameterization,
471 * except that here we *do* have to consider the added PHVs.
472 */
473 joinrel->direct_lateral_relids =
474 bms_del_members(joinrel->direct_lateral_relids, joinrel->relids);
475 if (bms_is_empty(joinrel->direct_lateral_relids))
476 joinrel->direct_lateral_relids = NULL;
477
478 /*
479 * Construct restrict and join clause lists for the new joinrel. (The
480 * caller might or might not need the restrictlist, but I need it anyway
481 * for set_joinrel_size_estimates().)
482 */
483 restrictlist = build_joinrel_restrictlist(root, joinrel,
484 outer_rel, inner_rel);
485 if (restrictlist_ptr)
486 *restrictlist_ptr = restrictlist;
487 build_joinrel_joinlist(joinrel, outer_rel, inner_rel);
488
489 /*
490 * This is also the right place to check whether the joinrel has any
491 * pending EquivalenceClass joins.
492 */
493 joinrel->has_eclass_joins = has_relevant_eclass_joinclause(root, joinrel);
494
495 /*
496 * Set estimates of the joinrel's size.
497 */
498 set_joinrel_size_estimates(root, joinrel, outer_rel, inner_rel,
499 sjinfo, restrictlist);
500
501 /*
502 * Set the consider_parallel flag if this joinrel could potentially be
503 * scanned within a parallel worker. If this flag is false for either
504 * inner_rel or outer_rel, then it must be false for the joinrel also.
505 * Even if both are true, there might be parallel-restricted expressions
506 * in the targetlist or quals.
507 *
508 * Note that if there are more than two rels in this relation, they could
509 * be divided between inner_rel and outer_rel in any arbitrary way. We
510 * assume this doesn't matter, because we should hit all the same baserels
511 * and joinclauses while building up to this joinrel no matter which we
512 * take; therefore, we should make the same decision here however we get
513 * here.
514 */
515 if (inner_rel->consider_parallel && outer_rel->consider_parallel &&
516 !has_parallel_hazard((Node *) restrictlist, false) &&
517 !has_parallel_hazard((Node *) joinrel->reltarget->exprs, false))
518 joinrel->consider_parallel = true;
519
520 /*
521 * Add the joinrel to the query's joinrel list, and store it into the
522 * auxiliary hashtable if there is one. NB: GEQO requires us to append
523 * the new joinrel to the end of the list!
524 */
525 root->join_rel_list = lappend(root->join_rel_list, joinrel);
526
527 if (root->join_rel_hash)
528 {
529 JoinHashEntry *hentry;
530 bool found;
531
532 hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
533 &(joinrel->relids),
534 HASH_ENTER,
535 &found);
536 Assert(!found);
537 hentry->join_rel = joinrel;
538 }
539
540 /*
541 * Also, if dynamic-programming join search is active, add the new joinrel
542 * to the appropriate sublist. Note: you might think the Assert on number
543 * of members should be for equality, but some of the level 1 rels might
544 * have been joinrels already, so we can only assert <=.
545 */
546 if (root->join_rel_level)
547 {
548 Assert(root->join_cur_level > 0);
549 Assert(root->join_cur_level <= bms_num_members(joinrel->relids));
550 root->join_rel_level[root->join_cur_level] =
551 lappend(root->join_rel_level[root->join_cur_level], joinrel);
552 }
553
554 return joinrel;
555 }
556
557 /*
558 * min_join_parameterization
559 *
560 * Determine the minimum possible parameterization of a joinrel, that is, the
561 * set of other rels it contains LATERAL references to. We save this value in
562 * the join's RelOptInfo. This function is split out of build_join_rel()
563 * because join_is_legal() needs the value to check a prospective join.
564 */
565 Relids
min_join_parameterization(PlannerInfo * root,Relids joinrelids,RelOptInfo * outer_rel,RelOptInfo * inner_rel)566 min_join_parameterization(PlannerInfo *root,
567 Relids joinrelids,
568 RelOptInfo *outer_rel,
569 RelOptInfo *inner_rel)
570 {
571 Relids result;
572
573 /*
574 * Basically we just need the union of the inputs' lateral_relids, less
575 * whatever is already in the join.
576 *
577 * It's not immediately obvious that this is a valid way to compute the
578 * result, because it might seem that we're ignoring possible lateral refs
579 * of PlaceHolderVars that are due to be computed at the join but not in
580 * either input. However, because create_lateral_join_info() already
581 * charged all such PHV refs to each member baserel of the join, they'll
582 * be accounted for already in the inputs' lateral_relids. Likewise, we
583 * do not need to worry about doing transitive closure here, because that
584 * was already accounted for in the original baserel lateral_relids.
585 */
586 result = bms_union(outer_rel->lateral_relids, inner_rel->lateral_relids);
587 result = bms_del_members(result, joinrelids);
588
589 /* Maintain invariant that result is exactly NULL if empty */
590 if (bms_is_empty(result))
591 result = NULL;
592
593 return result;
594 }
595
596 /*
597 * build_joinrel_tlist
598 * Builds a join relation's target list from an input relation.
599 * (This is invoked twice to handle the two input relations.)
600 *
601 * The join's targetlist includes all Vars of its member relations that
602 * will still be needed above the join. This subroutine adds all such
603 * Vars from the specified input rel's tlist to the join rel's tlist.
604 *
605 * We also compute the expected width of the join's output, making use
606 * of data that was cached at the baserel level by set_rel_width().
607 */
608 static void
build_joinrel_tlist(PlannerInfo * root,RelOptInfo * joinrel,RelOptInfo * input_rel)609 build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
610 RelOptInfo *input_rel)
611 {
612 Relids relids = joinrel->relids;
613 ListCell *vars;
614
615 foreach(vars, input_rel->reltarget->exprs)
616 {
617 Var *var = (Var *) lfirst(vars);
618 RelOptInfo *baserel;
619 int ndx;
620
621 /*
622 * Ignore PlaceHolderVars in the input tlists; we'll make our own
623 * decisions about whether to copy them.
624 */
625 if (IsA(var, PlaceHolderVar))
626 continue;
627
628 /*
629 * Otherwise, anything in a baserel or joinrel targetlist ought to be
630 * a Var. (More general cases can only appear in appendrel child
631 * rels, which will never be seen here.)
632 */
633 if (!IsA(var, Var))
634 elog(ERROR, "unexpected node type in rel targetlist: %d",
635 (int) nodeTag(var));
636
637 /* Get the Var's original base rel */
638 baserel = find_base_rel(root, var->varno);
639
640 /* Is it still needed above this joinrel? */
641 ndx = var->varattno - baserel->min_attr;
642 if (bms_nonempty_difference(baserel->attr_needed[ndx], relids))
643 {
644 /* Yup, add it to the output */
645 joinrel->reltarget->exprs = lappend(joinrel->reltarget->exprs, var);
646 /* Vars have cost zero, so no need to adjust reltarget->cost */
647 joinrel->reltarget->width += baserel->attr_widths[ndx];
648 }
649 }
650 }
651
652 /*
653 * build_joinrel_restrictlist
654 * build_joinrel_joinlist
655 * These routines build lists of restriction and join clauses for a
656 * join relation from the joininfo lists of the relations it joins.
657 *
658 * These routines are separate because the restriction list must be
659 * built afresh for each pair of input sub-relations we consider, whereas
660 * the join list need only be computed once for any join RelOptInfo.
661 * The join list is fully determined by the set of rels making up the
662 * joinrel, so we should get the same results (up to ordering) from any
663 * candidate pair of sub-relations. But the restriction list is whatever
664 * is not handled in the sub-relations, so it depends on which
665 * sub-relations are considered.
666 *
667 * If a join clause from an input relation refers to base rels still not
668 * present in the joinrel, then it is still a join clause for the joinrel;
669 * we put it into the joininfo list for the joinrel. Otherwise,
670 * the clause is now a restrict clause for the joined relation, and we
671 * return it to the caller of build_joinrel_restrictlist() to be stored in
672 * join paths made from this pair of sub-relations. (It will not need to
673 * be considered further up the join tree.)
674 *
675 * In many cases we will find the same RestrictInfos in both input
676 * relations' joinlists, so be careful to eliminate duplicates.
677 * Pointer equality should be a sufficient test for dups, since all
678 * the various joinlist entries ultimately refer to RestrictInfos
679 * pushed into them by distribute_restrictinfo_to_rels().
680 *
681 * 'joinrel' is a join relation node
682 * 'outer_rel' and 'inner_rel' are a pair of relations that can be joined
683 * to form joinrel.
684 *
685 * build_joinrel_restrictlist() returns a list of relevant restrictinfos,
686 * whereas build_joinrel_joinlist() stores its results in the joinrel's
687 * joininfo list. One or the other must accept each given clause!
688 *
689 * NB: Formerly, we made deep(!) copies of each input RestrictInfo to pass
690 * up to the join relation. I believe this is no longer necessary, because
691 * RestrictInfo nodes are no longer context-dependent. Instead, just include
692 * the original nodes in the lists made for the join relation.
693 */
694 static List *
build_joinrel_restrictlist(PlannerInfo * root,RelOptInfo * joinrel,RelOptInfo * outer_rel,RelOptInfo * inner_rel)695 build_joinrel_restrictlist(PlannerInfo *root,
696 RelOptInfo *joinrel,
697 RelOptInfo *outer_rel,
698 RelOptInfo *inner_rel)
699 {
700 List *result;
701
702 /*
703 * Collect all the clauses that syntactically belong at this level,
704 * eliminating any duplicates (important since we will see many of the
705 * same clauses arriving from both input relations).
706 */
707 result = subbuild_joinrel_restrictlist(joinrel, outer_rel->joininfo, NIL);
708 result = subbuild_joinrel_restrictlist(joinrel, inner_rel->joininfo, result);
709
710 /*
711 * Add on any clauses derived from EquivalenceClasses. These cannot be
712 * redundant with the clauses in the joininfo lists, so don't bother
713 * checking.
714 */
715 result = list_concat(result,
716 generate_join_implied_equalities(root,
717 joinrel->relids,
718 outer_rel->relids,
719 inner_rel));
720
721 return result;
722 }
723
724 static void
build_joinrel_joinlist(RelOptInfo * joinrel,RelOptInfo * outer_rel,RelOptInfo * inner_rel)725 build_joinrel_joinlist(RelOptInfo *joinrel,
726 RelOptInfo *outer_rel,
727 RelOptInfo *inner_rel)
728 {
729 List *result;
730
731 /*
732 * Collect all the clauses that syntactically belong above this level,
733 * eliminating any duplicates (important since we will see many of the
734 * same clauses arriving from both input relations).
735 */
736 result = subbuild_joinrel_joinlist(joinrel, outer_rel->joininfo, NIL);
737 result = subbuild_joinrel_joinlist(joinrel, inner_rel->joininfo, result);
738
739 joinrel->joininfo = result;
740 }
741
742 static List *
subbuild_joinrel_restrictlist(RelOptInfo * joinrel,List * joininfo_list,List * new_restrictlist)743 subbuild_joinrel_restrictlist(RelOptInfo *joinrel,
744 List *joininfo_list,
745 List *new_restrictlist)
746 {
747 ListCell *l;
748
749 foreach(l, joininfo_list)
750 {
751 RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
752
753 if (bms_is_subset(rinfo->required_relids, joinrel->relids))
754 {
755 /*
756 * This clause becomes a restriction clause for the joinrel, since
757 * it refers to no outside rels. Add it to the list, being
758 * careful to eliminate duplicates. (Since RestrictInfo nodes in
759 * different joinlists will have been multiply-linked rather than
760 * copied, pointer equality should be a sufficient test.)
761 */
762 new_restrictlist = list_append_unique_ptr(new_restrictlist, rinfo);
763 }
764 else
765 {
766 /*
767 * This clause is still a join clause at this level, so we ignore
768 * it in this routine.
769 */
770 }
771 }
772
773 return new_restrictlist;
774 }
775
776 static List *
subbuild_joinrel_joinlist(RelOptInfo * joinrel,List * joininfo_list,List * new_joininfo)777 subbuild_joinrel_joinlist(RelOptInfo *joinrel,
778 List *joininfo_list,
779 List *new_joininfo)
780 {
781 ListCell *l;
782
783 foreach(l, joininfo_list)
784 {
785 RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
786
787 if (bms_is_subset(rinfo->required_relids, joinrel->relids))
788 {
789 /*
790 * This clause becomes a restriction clause for the joinrel, since
791 * it refers to no outside rels. So we can ignore it in this
792 * routine.
793 */
794 }
795 else
796 {
797 /*
798 * This clause is still a join clause at this level, so add it to
799 * the new joininfo list, being careful to eliminate duplicates.
800 * (Since RestrictInfo nodes in different joinlists will have been
801 * multiply-linked rather than copied, pointer equality should be
802 * a sufficient test.)
803 */
804 new_joininfo = list_append_unique_ptr(new_joininfo, rinfo);
805 }
806 }
807
808 return new_joininfo;
809 }
810
811
812 /*
813 * build_empty_join_rel
814 * Build a dummy join relation describing an empty set of base rels.
815 *
816 * This is used for queries with empty FROM clauses, such as "SELECT 2+2" or
817 * "INSERT INTO foo VALUES(...)". We don't try very hard to make the empty
818 * joinrel completely valid, since no real planning will be done with it ---
819 * we just need it to carry a simple Result path out of query_planner().
820 */
821 RelOptInfo *
build_empty_join_rel(PlannerInfo * root)822 build_empty_join_rel(PlannerInfo *root)
823 {
824 RelOptInfo *joinrel;
825
826 /* The dummy join relation should be the only one ... */
827 Assert(root->join_rel_list == NIL);
828
829 joinrel = makeNode(RelOptInfo);
830 joinrel->reloptkind = RELOPT_JOINREL;
831 joinrel->relids = NULL; /* empty set */
832 joinrel->rows = 1; /* we produce one row for such cases */
833 joinrel->rtekind = RTE_JOIN;
834 joinrel->reltarget = create_empty_pathtarget();
835
836 root->join_rel_list = lappend(root->join_rel_list, joinrel);
837
838 return joinrel;
839 }
840
841
842 /*
843 * fetch_upper_rel
844 * Build a RelOptInfo describing some post-scan/join query processing,
845 * or return a pre-existing one if somebody already built it.
846 *
847 * An "upper" relation is identified by an UpperRelationKind and a Relids set.
848 * The meaning of the Relids set is not specified here, and very likely will
849 * vary for different relation kinds.
850 *
851 * Most of the fields in an upper-level RelOptInfo are not used and are not
852 * set here (though makeNode should ensure they're zeroes). We basically only
853 * care about fields that are of interest to add_path() and set_cheapest().
854 */
855 RelOptInfo *
fetch_upper_rel(PlannerInfo * root,UpperRelationKind kind,Relids relids)856 fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
857 {
858 RelOptInfo *upperrel;
859 ListCell *lc;
860
861 /*
862 * For the moment, our indexing data structure is just a List for each
863 * relation kind. If we ever get so many of one kind that this stops
864 * working well, we can improve it. No code outside this function should
865 * assume anything about how to find a particular upperrel.
866 */
867
868 /* If we already made this upperrel for the query, return it */
869 foreach(lc, root->upper_rels[kind])
870 {
871 upperrel = (RelOptInfo *) lfirst(lc);
872
873 if (bms_equal(upperrel->relids, relids))
874 return upperrel;
875 }
876
877 upperrel = makeNode(RelOptInfo);
878 upperrel->reloptkind = RELOPT_UPPER_REL;
879 upperrel->relids = bms_copy(relids);
880
881 /* cheap startup cost is interesting iff not all tuples to be retrieved */
882 upperrel->consider_startup = (root->tuple_fraction > 0);
883 upperrel->consider_param_startup = false;
884 upperrel->consider_parallel = false; /* might get changed later */
885 upperrel->reltarget = create_empty_pathtarget();
886 upperrel->pathlist = NIL;
887 upperrel->cheapest_startup_path = NULL;
888 upperrel->cheapest_total_path = NULL;
889 upperrel->cheapest_unique_path = NULL;
890 upperrel->cheapest_parameterized_paths = NIL;
891
892 root->upper_rels[kind] = lappend(root->upper_rels[kind], upperrel);
893
894 return upperrel;
895 }
896
897
898 /*
899 * find_childrel_appendrelinfo
900 * Get the AppendRelInfo associated with an appendrel child rel.
901 *
902 * This search could be eliminated by storing a link in child RelOptInfos,
903 * but for now it doesn't seem performance-critical. (Also, it might be
904 * difficult to maintain such a link during mutation of the append_rel_list.)
905 */
906 AppendRelInfo *
find_childrel_appendrelinfo(PlannerInfo * root,RelOptInfo * rel)907 find_childrel_appendrelinfo(PlannerInfo *root, RelOptInfo *rel)
908 {
909 Index relid = rel->relid;
910 ListCell *lc;
911
912 /* Should only be called on child rels */
913 Assert(rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
914
915 foreach(lc, root->append_rel_list)
916 {
917 AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
918
919 if (appinfo->child_relid == relid)
920 return appinfo;
921 }
922 /* should have found the entry ... */
923 elog(ERROR, "child rel %d not found in append_rel_list", relid);
924 return NULL; /* not reached */
925 }
926
927
928 /*
929 * find_childrel_top_parent
930 * Fetch the topmost appendrel parent rel of an appendrel child rel.
931 *
932 * Since appendrels can be nested, a child could have multiple levels of
933 * appendrel ancestors. This function locates the topmost ancestor,
934 * which will be a regular baserel not an otherrel.
935 */
936 RelOptInfo *
find_childrel_top_parent(PlannerInfo * root,RelOptInfo * rel)937 find_childrel_top_parent(PlannerInfo *root, RelOptInfo *rel)
938 {
939 do
940 {
941 AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, rel);
942 Index prelid = appinfo->parent_relid;
943
944 /* traverse up to the parent rel, loop if it's also a child rel */
945 rel = find_base_rel(root, prelid);
946 } while (rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
947
948 Assert(rel->reloptkind == RELOPT_BASEREL);
949
950 return rel;
951 }
952
953
954 /*
955 * find_childrel_parents
956 * Compute the set of parent relids of an appendrel child rel.
957 *
958 * Since appendrels can be nested, a child could have multiple levels of
959 * appendrel ancestors. This function computes a Relids set of all the
960 * parent relation IDs.
961 */
962 Relids
find_childrel_parents(PlannerInfo * root,RelOptInfo * rel)963 find_childrel_parents(PlannerInfo *root, RelOptInfo *rel)
964 {
965 Relids result = NULL;
966
967 do
968 {
969 AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, rel);
970 Index prelid = appinfo->parent_relid;
971
972 result = bms_add_member(result, prelid);
973
974 /* traverse up to the parent rel, loop if it's also a child rel */
975 rel = find_base_rel(root, prelid);
976 } while (rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
977
978 Assert(rel->reloptkind == RELOPT_BASEREL);
979
980 return result;
981 }
982
983
984 /*
985 * get_baserel_parampathinfo
986 * Get the ParamPathInfo for a parameterized path for a base relation,
987 * constructing one if we don't have one already.
988 *
989 * This centralizes estimating the rowcounts for parameterized paths.
990 * We need to cache those to be sure we use the same rowcount for all paths
991 * of the same parameterization for a given rel. This is also a convenient
992 * place to determine which movable join clauses the parameterized path will
993 * be responsible for evaluating.
994 */
995 ParamPathInfo *
get_baserel_parampathinfo(PlannerInfo * root,RelOptInfo * baserel,Relids required_outer)996 get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel,
997 Relids required_outer)
998 {
999 ParamPathInfo *ppi;
1000 Relids joinrelids;
1001 List *pclauses;
1002 double rows;
1003 ListCell *lc;
1004
1005 /* If rel has LATERAL refs, every path for it should account for them */
1006 Assert(bms_is_subset(baserel->lateral_relids, required_outer));
1007
1008 /* Unparameterized paths have no ParamPathInfo */
1009 if (bms_is_empty(required_outer))
1010 return NULL;
1011
1012 Assert(!bms_overlap(baserel->relids, required_outer));
1013
1014 /* If we already have a PPI for this parameterization, just return it */
1015 foreach(lc, baserel->ppilist)
1016 {
1017 ppi = (ParamPathInfo *) lfirst(lc);
1018 if (bms_equal(ppi->ppi_req_outer, required_outer))
1019 return ppi;
1020 }
1021
1022 /*
1023 * Identify all joinclauses that are movable to this base rel given this
1024 * parameterization.
1025 */
1026 joinrelids = bms_union(baserel->relids, required_outer);
1027 pclauses = NIL;
1028 foreach(lc, baserel->joininfo)
1029 {
1030 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1031
1032 if (join_clause_is_movable_into(rinfo,
1033 baserel->relids,
1034 joinrelids))
1035 pclauses = lappend(pclauses, rinfo);
1036 }
1037
1038 /*
1039 * Add in joinclauses generated by EquivalenceClasses, too. (These
1040 * necessarily satisfy join_clause_is_movable_into.)
1041 */
1042 pclauses = list_concat(pclauses,
1043 generate_join_implied_equalities(root,
1044 joinrelids,
1045 required_outer,
1046 baserel));
1047
1048 /* Estimate the number of rows returned by the parameterized scan */
1049 rows = get_parameterized_baserel_size(root, baserel, pclauses);
1050
1051 /* And now we can build the ParamPathInfo */
1052 ppi = makeNode(ParamPathInfo);
1053 ppi->ppi_req_outer = required_outer;
1054 ppi->ppi_rows = rows;
1055 ppi->ppi_clauses = pclauses;
1056 baserel->ppilist = lappend(baserel->ppilist, ppi);
1057
1058 return ppi;
1059 }
1060
1061 /*
1062 * get_joinrel_parampathinfo
1063 * Get the ParamPathInfo for a parameterized path for a join relation,
1064 * constructing one if we don't have one already.
1065 *
1066 * This centralizes estimating the rowcounts for parameterized paths.
1067 * We need to cache those to be sure we use the same rowcount for all paths
1068 * of the same parameterization for a given rel. This is also a convenient
1069 * place to determine which movable join clauses the parameterized path will
1070 * be responsible for evaluating.
1071 *
1072 * outer_path and inner_path are a pair of input paths that can be used to
1073 * construct the join, and restrict_clauses is the list of regular join
1074 * clauses (including clauses derived from EquivalenceClasses) that must be
1075 * applied at the join node when using these inputs.
1076 *
1077 * Unlike the situation for base rels, the set of movable join clauses to be
1078 * enforced at a join varies with the selected pair of input paths, so we
1079 * must calculate that and pass it back, even if we already have a matching
1080 * ParamPathInfo. We handle this by adding any clauses moved down to this
1081 * join to *restrict_clauses, which is an in/out parameter. (The addition
1082 * is done in such a way as to not modify the passed-in List structure.)
1083 *
1084 * Note: when considering a nestloop join, the caller must have removed from
1085 * restrict_clauses any movable clauses that are themselves scheduled to be
1086 * pushed into the right-hand path. We do not do that here since it's
1087 * unnecessary for other join types.
1088 */
1089 ParamPathInfo *
get_joinrel_parampathinfo(PlannerInfo * root,RelOptInfo * joinrel,Path * outer_path,Path * inner_path,SpecialJoinInfo * sjinfo,Relids required_outer,List ** restrict_clauses)1090 get_joinrel_parampathinfo(PlannerInfo *root, RelOptInfo *joinrel,
1091 Path *outer_path,
1092 Path *inner_path,
1093 SpecialJoinInfo *sjinfo,
1094 Relids required_outer,
1095 List **restrict_clauses)
1096 {
1097 ParamPathInfo *ppi;
1098 Relids join_and_req;
1099 Relids outer_and_req;
1100 Relids inner_and_req;
1101 List *pclauses;
1102 List *eclauses;
1103 List *dropped_ecs;
1104 double rows;
1105 ListCell *lc;
1106
1107 /* If rel has LATERAL refs, every path for it should account for them */
1108 Assert(bms_is_subset(joinrel->lateral_relids, required_outer));
1109
1110 /* Unparameterized paths have no ParamPathInfo or extra join clauses */
1111 if (bms_is_empty(required_outer))
1112 return NULL;
1113
1114 Assert(!bms_overlap(joinrel->relids, required_outer));
1115
1116 /*
1117 * Identify all joinclauses that are movable to this join rel given this
1118 * parameterization. These are the clauses that are movable into this
1119 * join, but not movable into either input path. Treat an unparameterized
1120 * input path as not accepting parameterized clauses (because it won't,
1121 * per the shortcut exit above), even though the joinclause movement rules
1122 * might allow the same clauses to be moved into a parameterized path for
1123 * that rel.
1124 */
1125 join_and_req = bms_union(joinrel->relids, required_outer);
1126 if (outer_path->param_info)
1127 outer_and_req = bms_union(outer_path->parent->relids,
1128 PATH_REQ_OUTER(outer_path));
1129 else
1130 outer_and_req = NULL; /* outer path does not accept parameters */
1131 if (inner_path->param_info)
1132 inner_and_req = bms_union(inner_path->parent->relids,
1133 PATH_REQ_OUTER(inner_path));
1134 else
1135 inner_and_req = NULL; /* inner path does not accept parameters */
1136
1137 pclauses = NIL;
1138 foreach(lc, joinrel->joininfo)
1139 {
1140 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1141
1142 if (join_clause_is_movable_into(rinfo,
1143 joinrel->relids,
1144 join_and_req) &&
1145 !join_clause_is_movable_into(rinfo,
1146 outer_path->parent->relids,
1147 outer_and_req) &&
1148 !join_clause_is_movable_into(rinfo,
1149 inner_path->parent->relids,
1150 inner_and_req))
1151 pclauses = lappend(pclauses, rinfo);
1152 }
1153
1154 /* Consider joinclauses generated by EquivalenceClasses, too */
1155 eclauses = generate_join_implied_equalities(root,
1156 join_and_req,
1157 required_outer,
1158 joinrel);
1159 /* We only want ones that aren't movable to lower levels */
1160 dropped_ecs = NIL;
1161 foreach(lc, eclauses)
1162 {
1163 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1164
1165 /*
1166 * In principle, join_clause_is_movable_into() should accept anything
1167 * returned by generate_join_implied_equalities(); but because its
1168 * analysis is only approximate, sometimes it doesn't. So we
1169 * currently cannot use this Assert; instead just assume it's okay to
1170 * apply the joinclause at this level.
1171 */
1172 #ifdef NOT_USED
1173 Assert(join_clause_is_movable_into(rinfo,
1174 joinrel->relids,
1175 join_and_req));
1176 #endif
1177 if (join_clause_is_movable_into(rinfo,
1178 outer_path->parent->relids,
1179 outer_and_req))
1180 continue; /* drop if movable into LHS */
1181 if (join_clause_is_movable_into(rinfo,
1182 inner_path->parent->relids,
1183 inner_and_req))
1184 {
1185 /* drop if movable into RHS, but remember EC for use below */
1186 Assert(rinfo->left_ec == rinfo->right_ec);
1187 dropped_ecs = lappend(dropped_ecs, rinfo->left_ec);
1188 continue;
1189 }
1190 pclauses = lappend(pclauses, rinfo);
1191 }
1192
1193 /*
1194 * EquivalenceClasses are harder to deal with than we could wish, because
1195 * of the fact that a given EC can generate different clauses depending on
1196 * context. Suppose we have an EC {X.X, Y.Y, Z.Z} where X and Y are the
1197 * LHS and RHS of the current join and Z is in required_outer, and further
1198 * suppose that the inner_path is parameterized by both X and Z. The code
1199 * above will have produced either Z.Z = X.X or Z.Z = Y.Y from that EC,
1200 * and in the latter case will have discarded it as being movable into the
1201 * RHS. However, the EC machinery might have produced either Y.Y = X.X or
1202 * Y.Y = Z.Z as the EC enforcement clause within the inner_path; it will
1203 * not have produced both, and we can't readily tell from here which one
1204 * it did pick. If we add no clause to this join, we'll end up with
1205 * insufficient enforcement of the EC; either Z.Z or X.X will fail to be
1206 * constrained to be equal to the other members of the EC. (When we come
1207 * to join Z to this X/Y path, we will certainly drop whichever EC clause
1208 * is generated at that join, so this omission won't get fixed later.)
1209 *
1210 * To handle this, for each EC we discarded such a clause from, try to
1211 * generate a clause connecting the required_outer rels to the join's LHS
1212 * ("Z.Z = X.X" in the terms of the above example). If successful, and if
1213 * the clause can't be moved to the LHS, add it to the current join's
1214 * restriction clauses. (If an EC cannot generate such a clause then it
1215 * has nothing that needs to be enforced here, while if the clause can be
1216 * moved into the LHS then it should have been enforced within that path.)
1217 *
1218 * Note that we don't need similar processing for ECs whose clause was
1219 * considered to be movable into the LHS, because the LHS can't refer to
1220 * the RHS so there is no comparable ambiguity about what it might
1221 * actually be enforcing internally.
1222 */
1223 if (dropped_ecs)
1224 {
1225 Relids real_outer_and_req;
1226
1227 real_outer_and_req = bms_union(outer_path->parent->relids,
1228 required_outer);
1229 eclauses =
1230 generate_join_implied_equalities_for_ecs(root,
1231 dropped_ecs,
1232 real_outer_and_req,
1233 required_outer,
1234 outer_path->parent);
1235 foreach(lc, eclauses)
1236 {
1237 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1238
1239 /* As above, can't quite assert this here */
1240 #ifdef NOT_USED
1241 Assert(join_clause_is_movable_into(rinfo,
1242 outer_path->parent->relids,
1243 real_outer_and_req));
1244 #endif
1245 if (!join_clause_is_movable_into(rinfo,
1246 outer_path->parent->relids,
1247 outer_and_req))
1248 pclauses = lappend(pclauses, rinfo);
1249 }
1250 }
1251
1252 /*
1253 * Now, attach the identified moved-down clauses to the caller's
1254 * restrict_clauses list. By using list_concat in this order, we leave
1255 * the original list structure of restrict_clauses undamaged.
1256 */
1257 *restrict_clauses = list_concat(pclauses, *restrict_clauses);
1258
1259 /* If we already have a PPI for this parameterization, just return it */
1260 foreach(lc, joinrel->ppilist)
1261 {
1262 ppi = (ParamPathInfo *) lfirst(lc);
1263 if (bms_equal(ppi->ppi_req_outer, required_outer))
1264 return ppi;
1265 }
1266
1267 /* Estimate the number of rows returned by the parameterized join */
1268 rows = get_parameterized_joinrel_size(root, joinrel,
1269 outer_path,
1270 inner_path,
1271 sjinfo,
1272 *restrict_clauses);
1273
1274 /*
1275 * And now we can build the ParamPathInfo. No point in saving the
1276 * input-pair-dependent clause list, though.
1277 *
1278 * Note: in GEQO mode, we'll be called in a temporary memory context, but
1279 * the joinrel structure is there too, so no problem.
1280 */
1281 ppi = makeNode(ParamPathInfo);
1282 ppi->ppi_req_outer = required_outer;
1283 ppi->ppi_rows = rows;
1284 ppi->ppi_clauses = NIL;
1285 joinrel->ppilist = lappend(joinrel->ppilist, ppi);
1286
1287 return ppi;
1288 }
1289
1290 /*
1291 * get_appendrel_parampathinfo
1292 * Get the ParamPathInfo for a parameterized path for an append relation.
1293 *
1294 * For an append relation, the rowcount estimate will just be the sum of
1295 * the estimates for its children. However, we still need a ParamPathInfo
1296 * to flag the fact that the path requires parameters. So this just creates
1297 * a suitable struct with zero ppi_rows (and no ppi_clauses either, since
1298 * the Append node isn't responsible for checking quals).
1299 */
1300 ParamPathInfo *
get_appendrel_parampathinfo(RelOptInfo * appendrel,Relids required_outer)1301 get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer)
1302 {
1303 ParamPathInfo *ppi;
1304 ListCell *lc;
1305
1306 /* If rel has LATERAL refs, every path for it should account for them */
1307 Assert(bms_is_subset(appendrel->lateral_relids, required_outer));
1308
1309 /* Unparameterized paths have no ParamPathInfo */
1310 if (bms_is_empty(required_outer))
1311 return NULL;
1312
1313 Assert(!bms_overlap(appendrel->relids, required_outer));
1314
1315 /* If we already have a PPI for this parameterization, just return it */
1316 foreach(lc, appendrel->ppilist)
1317 {
1318 ppi = (ParamPathInfo *) lfirst(lc);
1319 if (bms_equal(ppi->ppi_req_outer, required_outer))
1320 return ppi;
1321 }
1322
1323 /* Else build the ParamPathInfo */
1324 ppi = makeNode(ParamPathInfo);
1325 ppi->ppi_req_outer = required_outer;
1326 ppi->ppi_rows = 0;
1327 ppi->ppi_clauses = NIL;
1328 appendrel->ppilist = lappend(appendrel->ppilist, ppi);
1329
1330 return ppi;
1331 }
1332