Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * relnode.c
4 : : * Relation-node lookup/construction routines
5 : : *
6 : : * Portions Copyright (c) 1996-2025, 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 <limits.h>
18 : :
19 : : #include "miscadmin.h"
20 : : #include "nodes/nodeFuncs.h"
21 : : #include "optimizer/appendinfo.h"
22 : : #include "optimizer/clauses.h"
23 : : #include "optimizer/cost.h"
24 : : #include "optimizer/inherit.h"
25 : : #include "optimizer/optimizer.h"
26 : : #include "optimizer/pathnode.h"
27 : : #include "optimizer/paths.h"
28 : : #include "optimizer/placeholder.h"
29 : : #include "optimizer/plancat.h"
30 : : #include "optimizer/restrictinfo.h"
31 : : #include "optimizer/tlist.h"
32 : : #include "parser/parse_relation.h"
33 : : #include "rewrite/rewriteManip.h"
34 : : #include "utils/hsearch.h"
35 : : #include "utils/lsyscache.h"
36 : :
37 : :
38 : : typedef struct JoinHashEntry
39 : : {
40 : : Relids join_relids; /* hash key --- MUST BE FIRST */
41 : : RelOptInfo *join_rel;
42 : : } JoinHashEntry;
43 : :
44 : : static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
45 : : RelOptInfo *input_rel,
46 : : SpecialJoinInfo *sjinfo,
47 : : List *pushed_down_joins,
48 : : bool can_null);
49 : : static List *build_joinrel_restrictlist(PlannerInfo *root,
50 : : RelOptInfo *joinrel,
51 : : RelOptInfo *outer_rel,
52 : : RelOptInfo *inner_rel,
53 : : SpecialJoinInfo *sjinfo);
54 : : static void build_joinrel_joinlist(RelOptInfo *joinrel,
55 : : RelOptInfo *outer_rel,
56 : : RelOptInfo *inner_rel);
57 : : static List *subbuild_joinrel_restrictlist(PlannerInfo *root,
58 : : RelOptInfo *joinrel,
59 : : RelOptInfo *input_rel,
60 : : Relids both_input_relids,
61 : : List *new_restrictlist);
62 : : static List *subbuild_joinrel_joinlist(RelOptInfo *joinrel,
63 : : List *joininfo_list,
64 : : List *new_joininfo);
65 : : static void set_foreign_rel_properties(RelOptInfo *joinrel,
66 : : RelOptInfo *outer_rel, RelOptInfo *inner_rel);
67 : : static void add_join_rel(PlannerInfo *root, RelOptInfo *joinrel);
68 : : static void build_joinrel_partition_info(PlannerInfo *root,
69 : : RelOptInfo *joinrel,
70 : : RelOptInfo *outer_rel, RelOptInfo *inner_rel,
71 : : SpecialJoinInfo *sjinfo,
72 : : List *restrictlist);
73 : : static bool have_partkey_equi_join(PlannerInfo *root, RelOptInfo *joinrel,
74 : : RelOptInfo *rel1, RelOptInfo *rel2,
75 : : JoinType jointype, List *restrictlist);
76 : : static int match_expr_to_partition_keys(Expr *expr, RelOptInfo *rel,
77 : : bool strict_op);
78 : : static void set_joinrel_partition_key_exprs(RelOptInfo *joinrel,
79 : : RelOptInfo *outer_rel, RelOptInfo *inner_rel,
80 : : JoinType jointype);
81 : : static void build_child_join_reltarget(PlannerInfo *root,
82 : : RelOptInfo *parentrel,
83 : : RelOptInfo *childrel,
84 : : int nappinfos,
85 : : AppendRelInfo **appinfos);
86 : :
87 : :
88 : : /*
89 : : * setup_simple_rel_arrays
90 : : * Prepare the arrays we use for quickly accessing base relations
91 : : * and AppendRelInfos.
92 : : */
93 : : void
5117 tgl@sss.pgh.pa.us 94 :CBC 274133 : setup_simple_rel_arrays(PlannerInfo *root)
95 : : {
96 : : int size;
97 : : Index rti;
98 : : ListCell *lc;
99 : :
100 : : /* Arrays are accessed using RT indexes (1..N) */
2220 101 : 274133 : size = list_length(root->parse->rtable) + 1;
102 : 274133 : root->simple_rel_array_size = size;
103 : :
104 : : /*
105 : : * simple_rel_array is initialized to all NULLs, since no RelOptInfos
106 : : * exist yet. It'll be filled by later calls to build_simple_rel().
107 : : */
5117 108 : 274133 : root->simple_rel_array = (RelOptInfo **)
2220 109 : 274133 : palloc0(size * sizeof(RelOptInfo *));
110 : :
111 : : /* simple_rte_array is an array equivalent of the rtable list */
5117 112 : 274133 : root->simple_rte_array = (RangeTblEntry **)
2220 113 : 274133 : palloc0(size * sizeof(RangeTblEntry *));
5117 114 : 274133 : rti = 1;
115 [ + - + + : 729580 : foreach(lc, root->parse->rtable)
+ + ]
116 : : {
117 : 455447 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
118 : :
119 : 455447 : root->simple_rte_array[rti++] = rte;
120 : : }
121 : :
122 : : /* append_rel_array is not needed if there are no AppendRelInfos */
2629 alvherre@alvh.no-ip. 123 [ + + ]: 274133 : if (root->append_rel_list == NIL)
124 : : {
125 : 271811 : root->append_rel_array = NULL;
126 : 271811 : return;
127 : : }
128 : :
129 : 2322 : root->append_rel_array = (AppendRelInfo **)
130 : 2322 : palloc0(size * sizeof(AppendRelInfo *));
131 : :
132 : : /*
133 : : * append_rel_array is filled with any already-existing AppendRelInfos,
134 : : * which currently could only come from UNION ALL flattening. We might
135 : : * add more later during inheritance expansion, but it's the
136 : : * responsibility of the expansion code to update the array properly.
137 : : */
138 [ + - + + : 7510 : foreach(lc, root->append_rel_list)
+ + ]
139 : : {
140 : 5188 : AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
141 : 5188 : int child_relid = appinfo->child_relid;
142 : :
143 : : /* Sanity check */
144 [ - + ]: 5188 : Assert(child_relid < size);
145 : :
146 [ - + ]: 5188 : if (root->append_rel_array[child_relid])
2629 alvherre@alvh.no-ip. 147 [ # # ]:UBC 0 : elog(ERROR, "child relation already exists");
148 : :
2629 alvherre@alvh.no-ip. 149 :CBC 5188 : root->append_rel_array[child_relid] = appinfo;
150 : : }
151 : : }
152 : :
153 : : /*
154 : : * expand_planner_arrays
155 : : * Expand the PlannerInfo's per-RTE arrays by add_size members
156 : : * and initialize the newly added entries to NULLs
157 : : *
158 : : * Note: this causes the append_rel_array to become allocated even if
159 : : * it was not before. This is okay for current uses, because we only call
160 : : * this when adding child relations, which always have AppendRelInfos.
161 : : */
162 : : void
2352 tgl@sss.pgh.pa.us 163 : 9728 : expand_planner_arrays(PlannerInfo *root, int add_size)
164 : : {
165 : : int new_size;
166 : :
167 [ - + ]: 9728 : Assert(add_size > 0);
168 : :
169 : 9728 : new_size = root->simple_rel_array_size + add_size;
170 : :
1029 peter@eisentraut.org 171 : 9728 : root->simple_rel_array =
172 : 9728 : repalloc0_array(root->simple_rel_array, RelOptInfo *, root->simple_rel_array_size, new_size);
173 : :
174 : 9728 : root->simple_rte_array =
175 : 9728 : repalloc0_array(root->simple_rte_array, RangeTblEntry *, root->simple_rel_array_size, new_size);
176 : :
2352 tgl@sss.pgh.pa.us 177 [ + + ]: 9728 : if (root->append_rel_array)
1029 peter@eisentraut.org 178 : 2732 : root->append_rel_array =
179 : 2732 : repalloc0_array(root->append_rel_array, AppendRelInfo *, root->simple_rel_array_size, new_size);
180 : : else
181 : 6996 : root->append_rel_array =
182 : 6996 : palloc0_array(AppendRelInfo *, new_size);
183 : :
2352 tgl@sss.pgh.pa.us 184 : 9728 : root->simple_rel_array_size = new_size;
185 : 9728 : }
186 : :
187 : : /*
188 : : * build_simple_rel
189 : : * Construct a new RelOptInfo for a base relation or 'other' relation.
190 : : */
191 : : RelOptInfo *
3078 rhaas@postgresql.org 192 : 375393 : build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
193 : : {
194 : : RelOptInfo *rel;
195 : : RangeTblEntry *rte;
196 : :
197 : : /* Rel should not exist already */
6713 tgl@sss.pgh.pa.us 198 [ + - - + ]: 375393 : Assert(relid > 0 && relid < root->simple_rel_array_size);
7158 199 [ - + ]: 375393 : if (root->simple_rel_array[relid] != NULL)
7158 tgl@sss.pgh.pa.us 200 [ # # ]:UBC 0 : elog(ERROR, "rel %d already exists", relid);
201 : :
202 : : /* Fetch RTE for relation */
6713 tgl@sss.pgh.pa.us 203 :CBC 375393 : rte = root->simple_rte_array[relid];
204 [ - + ]: 375393 : Assert(rte != NULL);
205 : :
7158 206 : 375393 : rel = makeNode(RelOptInfo);
3078 rhaas@postgresql.org 207 [ + + ]: 375393 : rel->reloptkind = parent ? RELOPT_OTHER_MEMBER_REL : RELOPT_BASEREL;
8246 tgl@sss.pgh.pa.us 208 : 375393 : rel->relids = bms_make_singleton(relid);
9343 209 : 375393 : rel->rows = 0;
210 : : /* cheap startup cost is interesting iff not all tuples to be retrieved */
4753 211 : 375393 : rel->consider_startup = (root->tuple_fraction > 0);
2999 212 : 375393 : rel->consider_param_startup = false; /* might get changed later */
213 : 375393 : rel->consider_parallel = false; /* might get changed later */
3463 214 : 375393 : rel->reltarget = create_empty_pathtarget();
9343 215 : 375393 : rel->pathlist = NIL;
4888 216 : 375393 : rel->ppilist = NIL;
3517 rhaas@postgresql.org 217 : 375393 : rel->partial_pathlist = NIL;
9335 tgl@sss.pgh.pa.us 218 : 375393 : rel->cheapest_startup_path = NULL;
219 : 375393 : rel->cheapest_total_path = NULL;
4971 220 : 375393 : rel->cheapest_parameterized_paths = NIL;
8246 221 : 375393 : rel->relid = relid;
8518 222 : 375393 : rel->rtekind = rte->rtekind;
223 : : /* min_attr, max_attr, attr_needed, attr_widths are set below */
592 drowley@postgresql.o 224 : 375393 : rel->notnullattnums = NULL;
4759 tgl@sss.pgh.pa.us 225 : 375393 : rel->lateral_vars = NIL;
8875 226 : 375393 : rel->indexlist = NIL;
3074 227 : 375393 : rel->statlist = NIL;
9343 228 : 375393 : rel->pages = 0;
229 : 375393 : rel->tuples = 0;
5076 230 : 375393 : rel->allvisfrac = 0;
2239 drowley@postgresql.o 231 : 375393 : rel->eclass_indexes = NULL;
5117 tgl@sss.pgh.pa.us 232 : 375393 : rel->subroot = NULL;
4749 233 : 375393 : rel->subplan_params = NIL;
2999 234 : 375393 : rel->rel_parallel_workers = -1; /* set up in get_relation_info */
1652 drowley@postgresql.o 235 : 375393 : rel->amflags = 0;
3772 tgl@sss.pgh.pa.us 236 : 375393 : rel->serverid = InvalidOid;
1005 alvherre@alvh.no-ip. 237 [ + + ]: 375393 : if (rte->rtekind == RTE_RELATION)
238 : : {
929 239 [ + + + + : 230828 : Assert(parent == NULL ||
- + ]
240 : : parent->rtekind == RTE_RELATION ||
241 : : parent->rtekind == RTE_SUBQUERY);
242 : :
243 : : /*
244 : : * For any RELATION rte, we need a userid with which to check
245 : : * permission access. Baserels simply use their own
246 : : * RTEPermissionInfo's checkAsUser.
247 : : *
248 : : * For otherrels normally there's no RTEPermissionInfo, so we use the
249 : : * parent's, which normally has one. The exceptional case is that the
250 : : * parent is a subquery, in which case the otherrel will have its own.
251 : : */
252 [ + + ]: 230828 : if (rel->reloptkind == RELOPT_BASEREL ||
253 [ + - ]: 20916 : (rel->reloptkind == RELOPT_OTHER_MEMBER_REL &&
254 [ + + ]: 20916 : parent->rtekind == RTE_SUBQUERY))
1005 255 : 210467 : {
256 : : RTEPermissionInfo *perminfo;
257 : :
258 : 210467 : perminfo = getRTEPermissionInfo(root->parse->rteperminfos, rte);
259 : 210467 : rel->userid = perminfo->checkAsUser;
260 : : }
261 : : else
262 : 20361 : rel->userid = parent->userid;
263 : : }
264 : : else
265 : 144565 : rel->userid = InvalidOid;
3340 tgl@sss.pgh.pa.us 266 : 375393 : rel->useridiscurrent = false;
4929 267 : 375393 : rel->fdwroutine = NULL;
268 : 375393 : rel->fdw_private = NULL;
3074 269 : 375393 : rel->unique_for_rels = NIL;
270 : 375393 : rel->non_unique_for_rels = NIL;
18 rguo@postgresql.org 271 :GNC 375393 : rel->unique_rel = NULL;
272 : 375393 : rel->unique_pathkeys = NIL;
273 : 375393 : rel->unique_groupclause = NIL;
9343 tgl@sss.pgh.pa.us 274 :CBC 375393 : rel->baserestrictinfo = NIL;
8273 275 : 375393 : rel->baserestrictcost.startup = 0;
276 : 375393 : rel->baserestrictcost.per_tuple = 0;
3153 277 : 375393 : rel->baserestrict_min_security = UINT_MAX;
9343 278 : 375393 : rel->joininfo = NIL;
6804 279 : 375393 : rel->has_eclass_joins = false;
2413 280 : 375393 : rel->consider_partitionwise_join = false; /* might get changed later */
2908 rhaas@postgresql.org 281 : 375393 : rel->part_scheme = NULL;
1977 efujita@postgresql.o 282 : 375393 : rel->nparts = -1;
2908 rhaas@postgresql.org 283 : 375393 : rel->boundinfo = NULL;
1977 efujita@postgresql.o 284 : 375393 : rel->partbounds_merged = false;
2710 alvherre@alvh.no-ip. 285 : 375393 : rel->partition_qual = NIL;
2908 rhaas@postgresql.org 286 : 375393 : rel->part_rels = NULL;
1495 drowley@postgresql.o 287 : 375393 : rel->live_parts = NULL;
1977 efujita@postgresql.o 288 : 375393 : rel->all_partrels = NULL;
2908 rhaas@postgresql.org 289 : 375393 : rel->partexprs = NULL;
2892 290 : 375393 : rel->nullable_partexprs = NULL;
291 : :
292 : : /*
293 : : * Pass assorted information down the inheritance hierarchy.
294 : : */
3078 295 [ + + ]: 375393 : if (parent)
296 : : {
297 : : /* We keep back-links to immediate parent and topmost parent. */
1115 tgl@sss.pgh.pa.us 298 : 25549 : rel->parent = parent;
299 [ + + ]: 25549 : rel->top_parent = parent->top_parent ? parent->top_parent : parent;
300 : 25549 : rel->top_parent_relids = rel->top_parent->relids;
301 : :
302 : : /*
303 : : * A child rel is below the same outer joins as its parent. (We
304 : : * presume this info was already calculated for the parent.)
305 : : */
950 306 : 25549 : rel->nulling_relids = parent->nulling_relids;
307 : :
308 : : /*
309 : : * Also propagate lateral-reference information from appendrel parent
310 : : * rels to their child rels. We intentionally give each child rel the
311 : : * same minimum parameterization, even though it's quite possible that
312 : : * some don't reference all the lateral rels. This is because any
313 : : * append path for the parent will have to have the same
314 : : * parameterization for every child anyway, and there's no value in
315 : : * forcing extra reparameterize_path() calls. Similarly, a lateral
316 : : * reference to the parent prevents use of otherwise-movable join rels
317 : : * for each child.
318 : : *
319 : : * It's possible for child rels to have their own children, in which
320 : : * case the topmost parent's lateral info propagates all the way down.
321 : : */
2356 322 : 25549 : rel->direct_lateral_relids = parent->direct_lateral_relids;
323 : 25549 : rel->lateral_relids = parent->lateral_relids;
324 : 25549 : rel->lateral_referencers = parent->lateral_referencers;
325 : : }
326 : : else
327 : : {
1115 328 : 349844 : rel->parent = NULL;
329 : 349844 : rel->top_parent = NULL;
3078 rhaas@postgresql.org 330 : 349844 : rel->top_parent_relids = NULL;
950 tgl@sss.pgh.pa.us 331 : 349844 : rel->nulling_relids = NULL;
2356 332 : 349844 : rel->direct_lateral_relids = NULL;
333 : 349844 : rel->lateral_relids = NULL;
334 : 349844 : rel->lateral_referencers = NULL;
335 : : }
336 : :
337 : : /* Check type of rtable entry */
8579 338 [ + + + - ]: 375393 : switch (rte->rtekind)
339 : : {
340 : 230828 : case RTE_RELATION:
341 : : /* Table --- retrieve statistics from the system catalogs */
6927 342 : 230828 : get_relation_info(root, rte->relid, rte->inh, rel);
8251 343 : 230819 : break;
8579 344 : 47932 : case RTE_SUBQUERY:
345 : : case RTE_FUNCTION:
346 : : case RTE_TABLEFUNC:
347 : : case RTE_VALUES:
348 : : case RTE_CTE:
349 : : case RTE_NAMEDTUPLESTORE:
350 : :
351 : : /*
352 : : * Subquery, function, tablefunc, values list, CTE, or ENR --- set
353 : : * up attr range and arrays
354 : : *
355 : : * Note: 0 is included in range to support whole-row Vars
356 : : */
7943 357 : 47932 : rel->min_attr = 0;
7769 neilc@samurai.com 358 : 47932 : rel->max_attr = list_length(rte->eref->colnames);
7584 tgl@sss.pgh.pa.us 359 : 47932 : rel->attr_needed = (Relids *)
360 : 47932 : palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids));
361 : 47932 : rel->attr_widths = (int32 *)
362 : 47932 : palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32));
8579 363 : 47932 : break;
2413 364 : 96633 : case RTE_RESULT:
365 : : /* RTE_RESULT has no columns, nor could it have whole-row Var */
366 : 96633 : rel->min_attr = 0;
367 : 96633 : rel->max_attr = -1;
368 : 96633 : rel->attr_needed = NULL;
369 : 96633 : rel->attr_widths = NULL;
370 : 96633 : break;
8579 tgl@sss.pgh.pa.us 371 :UBC 0 : default:
8079 372 [ # # ]: 0 : elog(ERROR, "unrecognized RTE kind: %d",
373 : : (int) rte->rtekind);
374 : : break;
375 : : }
376 : :
377 : : /*
378 : : * We must apply the partially filled in RelOptInfo before calling
379 : : * apply_child_basequals due to some transformations within that function
380 : : * which require the RelOptInfo to be available in the simple_rel_array.
381 : : */
512 drowley@postgresql.o 382 :CBC 375384 : root->simple_rel_array[relid] = rel;
383 : :
384 : : /*
385 : : * Apply the parent's quals to the child, with appropriate substitution of
386 : : * variables. If the resulting clause is constant-FALSE or NULL after
387 : : * applying transformations, apply_child_basequals returns false to
388 : : * indicate that scanning this relation won't yield any rows. In this
389 : : * case, we mark the child as dummy right away. (We must do this
390 : : * immediately so that pruning works correctly when recursing in
391 : : * expand_partitioned_rtentry.)
392 : : */
2352 tgl@sss.pgh.pa.us 393 [ + + ]: 375384 : if (parent)
394 : : {
395 : 25549 : AppendRelInfo *appinfo = root->append_rel_array[relid];
396 : :
397 [ - + ]: 25549 : Assert(appinfo != NULL);
398 [ + + ]: 25549 : if (!apply_child_basequals(root, parent, rel, rte, appinfo))
399 : : {
400 : : /*
401 : : * Restriction clause reduced to constant FALSE or NULL. Mark as
402 : : * dummy so we won't scan this relation.
403 : : */
404 : 45 : mark_dummy_rel(rel);
405 : : }
406 : : }
407 : :
408 : 375384 : return rel;
409 : : }
410 : :
411 : : /*
412 : : * find_base_rel
413 : : * Find a base or otherrel relation entry, which must already exist.
414 : : */
415 : : RelOptInfo *
7398 416 : 3328928 : find_base_rel(PlannerInfo *root, int relid)
417 : : {
418 : : RelOptInfo *rel;
419 : :
420 : : /* use an unsigned comparison to prevent negative array element access */
708 drowley@postgresql.o 421 [ + - ]: 3328928 : if ((uint32) relid < (uint32) root->simple_rel_array_size)
422 : : {
7158 tgl@sss.pgh.pa.us 423 : 3328928 : rel = root->simple_rel_array[relid];
7397 424 [ + - ]: 3328928 : if (rel)
8875 425 : 3328928 : return rel;
426 : : }
427 : :
8079 tgl@sss.pgh.pa.us 428 [ # # ]:UBC 0 : elog(ERROR, "no relation entry for relid %d", relid);
429 : :
430 : : return NULL; /* keep compiler quiet */
431 : : }
432 : :
433 : : /*
434 : : * find_base_rel_noerr
435 : : * Find a base or otherrel relation entry, returning NULL if there's none
436 : : */
437 : : RelOptInfo *
607 tgl@sss.pgh.pa.us 438 :CBC 755581 : find_base_rel_noerr(PlannerInfo *root, int relid)
439 : : {
440 : : /* use an unsigned comparison to prevent negative array element access */
441 [ + - ]: 755581 : if ((uint32) relid < (uint32) root->simple_rel_array_size)
442 : 755581 : return root->simple_rel_array[relid];
607 tgl@sss.pgh.pa.us 443 :UBC 0 : return NULL;
444 : : }
445 : :
446 : : /*
447 : : * find_base_rel_ignore_join
448 : : * Find a base or otherrel relation entry, which must already exist.
449 : : *
450 : : * Unlike find_base_rel, if relid references an outer join then this
451 : : * will return NULL rather than raising an error. This is convenient
452 : : * for callers that must deal with relid sets including both base and
453 : : * outer joins.
454 : : */
455 : : RelOptInfo *
950 tgl@sss.pgh.pa.us 456 :CBC 89999 : find_base_rel_ignore_join(PlannerInfo *root, int relid)
457 : : {
458 : : /* use an unsigned comparison to prevent negative array element access */
708 drowley@postgresql.o 459 [ + - ]: 89999 : if ((uint32) relid < (uint32) root->simple_rel_array_size)
460 : : {
461 : : RelOptInfo *rel;
462 : : RangeTblEntry *rte;
463 : :
950 tgl@sss.pgh.pa.us 464 : 89999 : rel = root->simple_rel_array[relid];
465 [ + + ]: 89999 : if (rel)
466 : 83358 : return rel;
467 : :
468 : : /*
469 : : * We could just return NULL here, but for debugging purposes it seems
470 : : * best to actually verify that the relid is an outer join and not
471 : : * something weird.
472 : : */
473 : 6641 : rte = root->simple_rte_array[relid];
474 [ + - + - : 6641 : if (rte && rte->rtekind == RTE_JOIN && rte->jointype != JOIN_INNER)
+ - ]
475 : 6641 : return NULL;
476 : : }
477 : :
950 tgl@sss.pgh.pa.us 478 [ # # ]:UBC 0 : elog(ERROR, "no relation entry for relid %d", relid);
479 : :
480 : : return NULL; /* keep compiler quiet */
481 : : }
482 : :
483 : : /*
484 : : * build_join_rel_hash
485 : : * Construct the auxiliary hash table for join relations.
486 : : */
487 : : static void
7395 tgl@sss.pgh.pa.us 488 :CBC 28 : build_join_rel_hash(PlannerInfo *root)
489 : : {
490 : : HTAB *hashtab;
491 : : HASHCTL hash_ctl;
492 : : ListCell *l;
493 : :
494 : : /* Create the hash table */
495 : 28 : hash_ctl.keysize = sizeof(Relids);
496 : 28 : hash_ctl.entrysize = sizeof(JoinHashEntry);
497 : 28 : hash_ctl.hash = bitmap_hash;
498 : 28 : hash_ctl.match = bitmap_match;
499 : 28 : hash_ctl.hcxt = CurrentMemoryContext;
500 : 28 : hashtab = hash_create("JoinRelHashTable",
501 : : 256L,
502 : : &hash_ctl,
503 : : HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT);
504 : :
505 : : /* Insert all the already-existing joinrels */
506 [ + - + + : 952 : foreach(l, root->join_rel_list)
+ + ]
507 : : {
508 : 924 : RelOptInfo *rel = (RelOptInfo *) lfirst(l);
509 : : JoinHashEntry *hentry;
510 : : bool found;
511 : :
512 : 924 : hentry = (JoinHashEntry *) hash_search(hashtab,
513 : 924 : &(rel->relids),
514 : : HASH_ENTER,
515 : : &found);
516 [ - + ]: 924 : Assert(!found);
517 : 924 : hentry->join_rel = rel;
518 : : }
519 : :
520 : 28 : root->join_rel_hash = hashtab;
521 : 28 : }
522 : :
523 : : /*
524 : : * find_join_rel
525 : : * Returns relation entry corresponding to 'relids' (a set of RT indexes),
526 : : * or NULL if none exists. This is for join relations.
527 : : */
528 : : RelOptInfo *
7398 529 : 161347 : find_join_rel(PlannerInfo *root, Relids relids)
530 : : {
531 : : /*
532 : : * Switch to using hash lookup when list grows "too long". The threshold
533 : : * is arbitrary and is known only here.
534 : : */
7395 535 [ + + + + ]: 161347 : if (!root->join_rel_hash && list_length(root->join_rel_list) > 32)
536 : 28 : build_join_rel_hash(root);
537 : :
538 : : /*
539 : : * Use either hashtable lookup or linear search, as appropriate.
540 : : *
541 : : * Note: the seemingly redundant hashkey variable is used to avoid taking
542 : : * the address of relids; unless the compiler is exceedingly smart, doing
543 : : * so would force relids out of a register and thus probably slow down the
544 : : * list-search case.
545 : : */
546 [ + + ]: 161347 : if (root->join_rel_hash)
547 : : {
548 : 2352 : Relids hashkey = relids;
549 : : JoinHashEntry *hentry;
550 : :
551 : 2352 : hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
552 : : &hashkey,
553 : : HASH_FIND,
554 : : NULL);
555 [ + + ]: 2352 : if (hentry)
556 : 2079 : return hentry->join_rel;
557 : : }
558 : : else
559 : : {
560 : : ListCell *l;
561 : :
562 [ + + + + : 987625 : foreach(l, root->join_rel_list)
+ + ]
563 : : {
564 : 883109 : RelOptInfo *rel = (RelOptInfo *) lfirst(l);
565 : :
566 [ + + ]: 883109 : if (bms_equal(rel->relids, relids))
567 : 54479 : return rel;
568 : : }
569 : : }
570 : :
9343 571 : 104789 : return NULL;
572 : : }
573 : :
574 : : /*
575 : : * set_foreign_rel_properties
576 : : * Set up foreign-join fields if outer and inner relation are foreign
577 : : * tables (or joins) belonging to the same server and assigned to the same
578 : : * user to check access permissions as.
579 : : *
580 : : * In addition to an exact match of userid, we allow the case where one side
581 : : * has zero userid (implying current user) and the other side has explicit
582 : : * userid that happens to equal the current user; but in that case, pushdown of
583 : : * the join is only valid for the current user. The useridiscurrent field
584 : : * records whether we had to make such an assumption for this join or any
585 : : * sub-join.
586 : : *
587 : : * Otherwise these fields are left invalid, so GetForeignJoinPaths will not be
588 : : * called for the join relation.
589 : : */
590 : : static void
3098 rhaas@postgresql.org 591 : 103828 : set_foreign_rel_properties(RelOptInfo *joinrel, RelOptInfo *outer_rel,
592 : : RelOptInfo *inner_rel)
593 : : {
594 [ + + ]: 103828 : if (OidIsValid(outer_rel->serverid) &&
595 [ + + ]: 445 : inner_rel->serverid == outer_rel->serverid)
596 : : {
597 [ + + ]: 399 : if (inner_rel->userid == outer_rel->userid)
598 : : {
599 : 393 : joinrel->serverid = outer_rel->serverid;
600 : 393 : joinrel->userid = outer_rel->userid;
601 [ + - - + ]: 393 : joinrel->useridiscurrent = outer_rel->useridiscurrent || inner_rel->useridiscurrent;
602 : 393 : joinrel->fdwroutine = outer_rel->fdwroutine;
603 : : }
604 [ + + + + ]: 10 : else if (!OidIsValid(inner_rel->userid) &&
605 : 4 : outer_rel->userid == GetUserId())
606 : : {
607 : 2 : joinrel->serverid = outer_rel->serverid;
608 : 2 : joinrel->userid = outer_rel->userid;
609 : 2 : joinrel->useridiscurrent = true;
610 : 2 : joinrel->fdwroutine = outer_rel->fdwroutine;
611 : : }
612 [ - + - - ]: 4 : else if (!OidIsValid(outer_rel->userid) &&
3098 rhaas@postgresql.org 613 :UBC 0 : inner_rel->userid == GetUserId())
614 : : {
615 : 0 : joinrel->serverid = outer_rel->serverid;
616 : 0 : joinrel->userid = inner_rel->userid;
617 : 0 : joinrel->useridiscurrent = true;
618 : 0 : joinrel->fdwroutine = outer_rel->fdwroutine;
619 : : }
620 : : }
3098 rhaas@postgresql.org 621 :CBC 103828 : }
622 : :
623 : : /*
624 : : * add_join_rel
625 : : * Add given join relation to the list of join relations in the given
626 : : * PlannerInfo. Also add it to the auxiliary hashtable if there is one.
627 : : */
628 : : static void
629 : 103828 : add_join_rel(PlannerInfo *root, RelOptInfo *joinrel)
630 : : {
631 : : /* GEQO requires us to append the new joinrel to the end of the list! */
632 : 103828 : root->join_rel_list = lappend(root->join_rel_list, joinrel);
633 : :
634 : : /* store it into the auxiliary hashtable if there is one. */
635 [ + + ]: 103828 : if (root->join_rel_hash)
636 : : {
637 : : JoinHashEntry *hentry;
638 : : bool found;
639 : :
640 : 273 : hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
641 : 273 : &(joinrel->relids),
642 : : HASH_ENTER,
643 : : &found);
644 [ - + ]: 273 : Assert(!found);
645 : 273 : hentry->join_rel = joinrel;
646 : : }
647 : 103828 : }
648 : :
649 : : /*
650 : : * build_join_rel
651 : : * Returns relation entry corresponding to the union of two given rels,
652 : : * creating a new relation entry if none already exists.
653 : : *
654 : : * 'joinrelids' is the Relids set that uniquely identifies the join
655 : : * 'outer_rel' and 'inner_rel' are relation nodes for the relations to be
656 : : * joined
657 : : * 'sjinfo': join context info
658 : : * 'pushed_down_joins': any pushed-down outer joins that are now completed
659 : : * 'restrictlist_ptr': result variable. If not NULL, *restrictlist_ptr
660 : : * receives the list of RestrictInfo nodes that apply to this
661 : : * particular pair of joinable relations.
662 : : *
663 : : * restrictlist_ptr makes the routine's API a little grotty, but it saves
664 : : * duplicated calculation of the restrictlist...
665 : : */
666 : : RelOptInfo *
7398 tgl@sss.pgh.pa.us 667 : 156698 : build_join_rel(PlannerInfo *root,
668 : : Relids joinrelids,
669 : : RelOptInfo *outer_rel,
670 : : RelOptInfo *inner_rel,
671 : : SpecialJoinInfo *sjinfo,
672 : : List *pushed_down_joins,
673 : : List **restrictlist_ptr)
674 : : {
675 : : RelOptInfo *joinrel;
676 : : List *restrictlist;
677 : :
678 : : /* This function should be used only for join between parents. */
2892 rhaas@postgresql.org 679 [ + - + - : 156698 : Assert(!IS_OTHER_REL(outer_rel) && !IS_OTHER_REL(inner_rel));
+ - + - +
- - + ]
680 : :
681 : : /*
682 : : * See if we already have a joinrel for this set of base rels.
683 : : */
9343 tgl@sss.pgh.pa.us 684 : 156698 : joinrel = find_join_rel(root, joinrelids);
685 : :
686 [ + + ]: 156698 : if (joinrel)
687 : : {
688 : : /*
689 : : * Yes, so we only need to figure the restrictlist for this particular
690 : : * pair of component relations.
691 : : */
692 [ + - ]: 55377 : if (restrictlist_ptr)
8724 693 : 55377 : *restrictlist_ptr = build_joinrel_restrictlist(root,
694 : : joinrel,
695 : : outer_rel,
696 : : inner_rel,
697 : : sjinfo);
9343 698 : 55377 : return joinrel;
699 : : }
700 : :
701 : : /*
702 : : * Nope, so make one.
703 : : */
704 : 101321 : joinrel = makeNode(RelOptInfo);
8579 705 : 101321 : joinrel->reloptkind = RELOPT_JOINREL;
8246 706 : 101321 : joinrel->relids = bms_copy(joinrelids);
9343 707 : 101321 : joinrel->rows = 0;
708 : : /* cheap startup cost is interesting iff not all tuples to be retrieved */
4753 709 : 101321 : joinrel->consider_startup = (root->tuple_fraction > 0);
3748 710 : 101321 : joinrel->consider_param_startup = false;
3587 rhaas@postgresql.org 711 : 101321 : joinrel->consider_parallel = false;
3463 tgl@sss.pgh.pa.us 712 : 101321 : joinrel->reltarget = create_empty_pathtarget();
9343 713 : 101321 : joinrel->pathlist = NIL;
4888 714 : 101321 : joinrel->ppilist = NIL;
3517 rhaas@postgresql.org 715 : 101321 : joinrel->partial_pathlist = NIL;
9335 tgl@sss.pgh.pa.us 716 : 101321 : joinrel->cheapest_startup_path = NULL;
717 : 101321 : joinrel->cheapest_total_path = NULL;
4971 718 : 101321 : joinrel->cheapest_parameterized_paths = NIL;
719 : : /* init direct_lateral_relids from children; we'll finish it up below */
3557 720 : 101321 : joinrel->direct_lateral_relids =
721 : 101321 : bms_union(outer_rel->direct_lateral_relids,
722 : 101321 : inner_rel->direct_lateral_relids);
723 : 101321 : joinrel->lateral_relids = min_join_parameterization(root, joinrel->relids,
724 : : outer_rel, inner_rel);
8246 725 : 101321 : joinrel->relid = 0; /* indicates not a baserel */
8518 726 : 101321 : joinrel->rtekind = RTE_JOIN;
8105 727 : 101321 : joinrel->min_attr = 0;
728 : 101321 : joinrel->max_attr = 0;
729 : 101321 : joinrel->attr_needed = NULL;
730 : 101321 : joinrel->attr_widths = NULL;
592 drowley@postgresql.o 731 : 101321 : joinrel->notnullattnums = NULL;
950 tgl@sss.pgh.pa.us 732 : 101321 : joinrel->nulling_relids = NULL;
4759 733 : 101321 : joinrel->lateral_vars = NIL;
4403 734 : 101321 : joinrel->lateral_referencers = NULL;
8875 735 : 101321 : joinrel->indexlist = NIL;
3074 736 : 101321 : joinrel->statlist = NIL;
9343 737 : 101321 : joinrel->pages = 0;
738 : 101321 : joinrel->tuples = 0;
5076 739 : 101321 : joinrel->allvisfrac = 0;
2239 drowley@postgresql.o 740 : 101321 : joinrel->eclass_indexes = NULL;
5117 tgl@sss.pgh.pa.us 741 : 101321 : joinrel->subroot = NULL;
4749 742 : 101321 : joinrel->subplan_params = NIL;
3340 743 : 101321 : joinrel->rel_parallel_workers = -1;
1652 drowley@postgresql.o 744 : 101321 : joinrel->amflags = 0;
3772 tgl@sss.pgh.pa.us 745 : 101321 : joinrel->serverid = InvalidOid;
3340 746 : 101321 : joinrel->userid = InvalidOid;
747 : 101321 : joinrel->useridiscurrent = false;
4929 748 : 101321 : joinrel->fdwroutine = NULL;
749 : 101321 : joinrel->fdw_private = NULL;
3074 750 : 101321 : joinrel->unique_for_rels = NIL;
751 : 101321 : joinrel->non_unique_for_rels = NIL;
18 rguo@postgresql.org 752 :GNC 101321 : joinrel->unique_rel = NULL;
753 : 101321 : joinrel->unique_pathkeys = NIL;
754 : 101321 : joinrel->unique_groupclause = NIL;
9343 tgl@sss.pgh.pa.us 755 :CBC 101321 : joinrel->baserestrictinfo = NIL;
8273 756 : 101321 : joinrel->baserestrictcost.startup = 0;
757 : 101321 : joinrel->baserestrictcost.per_tuple = 0;
3153 758 : 101321 : joinrel->baserestrict_min_security = UINT_MAX;
9343 759 : 101321 : joinrel->joininfo = NIL;
6804 760 : 101321 : joinrel->has_eclass_joins = false;
2413 761 : 101321 : joinrel->consider_partitionwise_join = false; /* might get changed later */
1115 762 : 101321 : joinrel->parent = NULL;
763 : 101321 : joinrel->top_parent = NULL;
3078 rhaas@postgresql.org 764 : 101321 : joinrel->top_parent_relids = NULL;
2908 765 : 101321 : joinrel->part_scheme = NULL;
1977 efujita@postgresql.o 766 : 101321 : joinrel->nparts = -1;
2908 rhaas@postgresql.org 767 : 101321 : joinrel->boundinfo = NULL;
1977 efujita@postgresql.o 768 : 101321 : joinrel->partbounds_merged = false;
2710 alvherre@alvh.no-ip. 769 : 101321 : joinrel->partition_qual = NIL;
2908 rhaas@postgresql.org 770 : 101321 : joinrel->part_rels = NULL;
1495 drowley@postgresql.o 771 : 101321 : joinrel->live_parts = NULL;
1977 efujita@postgresql.o 772 : 101321 : joinrel->all_partrels = NULL;
2908 rhaas@postgresql.org 773 : 101321 : joinrel->partexprs = NULL;
2892 774 : 101321 : joinrel->nullable_partexprs = NULL;
775 : :
776 : : /* Compute information relevant to the foreign relations. */
3098 777 : 101321 : set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
778 : :
779 : : /*
780 : : * Fill the joinrel's tlist with just the Vars and PHVs that need to be
781 : : * output from this join (ie, are needed for higher joinclauses or final
782 : : * output).
783 : : *
784 : : * NOTE: the tlist order for a join rel will depend on which pair of outer
785 : : * and inner rels we first try to build it from. But the contents should
786 : : * be the same regardless.
787 : : */
843 tgl@sss.pgh.pa.us 788 : 101321 : build_joinrel_tlist(root, joinrel, outer_rel, sjinfo, pushed_down_joins,
950 789 : 101321 : (sjinfo->jointype == JOIN_FULL));
843 790 : 101321 : build_joinrel_tlist(root, joinrel, inner_rel, sjinfo, pushed_down_joins,
950 791 : 101321 : (sjinfo->jointype != JOIN_INNER));
792 : 101321 : add_placeholders_to_joinrel(root, joinrel, outer_rel, inner_rel, sjinfo);
793 : :
794 : : /*
795 : : * add_placeholders_to_joinrel also took care of adding the ph_lateral
796 : : * sets of any PlaceHolderVars computed here to direct_lateral_relids, so
797 : : * now we can finish computing that. This is much like the computation of
798 : : * the transitively-closed lateral_relids in min_join_parameterization,
799 : : * except that here we *do* have to consider the added PHVs.
800 : : */
3557 801 : 101321 : joinrel->direct_lateral_relids =
802 : 101321 : bms_del_members(joinrel->direct_lateral_relids, joinrel->relids);
803 : :
804 : : /*
805 : : * Construct restrict and join clause lists for the new joinrel. (The
806 : : * caller might or might not need the restrictlist, but I need it anyway
807 : : * for set_joinrel_size_estimates().)
808 : : */
6804 809 : 101321 : restrictlist = build_joinrel_restrictlist(root, joinrel,
810 : : outer_rel, inner_rel,
811 : : sjinfo);
9343 812 [ + - ]: 101321 : if (restrictlist_ptr)
813 : 101321 : *restrictlist_ptr = restrictlist;
814 : 101321 : build_joinrel_joinlist(joinrel, outer_rel, inner_rel);
815 : :
816 : : /*
817 : : * This is also the right place to check whether the joinrel has any
818 : : * pending EquivalenceClass joins.
819 : : */
6804 820 : 101321 : joinrel->has_eclass_joins = has_relevant_eclass_joinclause(root, joinrel);
821 : :
822 : : /* Store the partition information. */
950 823 : 101321 : build_joinrel_partition_info(root, joinrel, outer_rel, inner_rel, sjinfo,
824 : : restrictlist);
825 : :
826 : : /*
827 : : * Set estimates of the joinrel's size.
828 : : */
9343 829 : 101321 : set_joinrel_size_estimates(root, joinrel, outer_rel, inner_rel,
830 : : sjinfo, restrictlist);
831 : :
832 : : /*
833 : : * Set the consider_parallel flag if this joinrel could potentially be
834 : : * scanned within a parallel worker. If this flag is false for either
835 : : * inner_rel or outer_rel, then it must be false for the joinrel also.
836 : : * Even if both are true, there might be parallel-restricted expressions
837 : : * in the targetlist or quals.
838 : : *
839 : : * Note that if there are more than two rels in this relation, they could
840 : : * be divided between inner_rel and outer_rel in any arbitrary way. We
841 : : * assume this doesn't matter, because we should hit all the same baserels
842 : : * and joinclauses while building up to this joinrel no matter which we
843 : : * take; therefore, we should make the same decision here however we get
844 : : * here.
845 : : */
3587 rhaas@postgresql.org 846 [ + + + + : 185056 : if (inner_rel->consider_parallel && outer_rel->consider_parallel &&
+ + ]
3305 tgl@sss.pgh.pa.us 847 [ + + ]: 167165 : is_parallel_safe(root, (Node *) restrictlist) &&
848 : 83430 : is_parallel_safe(root, (Node *) joinrel->reltarget->exprs))
3587 rhaas@postgresql.org 849 : 83424 : joinrel->consider_parallel = true;
850 : :
851 : : /* Add the joinrel to the PlannerInfo. */
3098 852 : 101321 : add_join_rel(root, joinrel);
853 : :
854 : : /*
855 : : * Also, if dynamic-programming join search is active, add the new joinrel
856 : : * to the appropriate sublist. Note: you might think the Assert on number
857 : : * of members should be for equality, but some of the level 1 rels might
858 : : * have been joinrels already, so we can only assert <=.
859 : : */
5761 tgl@sss.pgh.pa.us 860 [ + + ]: 101321 : if (root->join_rel_level)
861 : : {
862 [ - + ]: 99773 : Assert(root->join_cur_level > 0);
863 [ - + ]: 99773 : Assert(root->join_cur_level <= bms_num_members(joinrel->relids));
864 : 99773 : root->join_rel_level[root->join_cur_level] =
865 : 99773 : lappend(root->join_rel_level[root->join_cur_level], joinrel);
866 : : }
867 : :
9343 868 : 101321 : return joinrel;
869 : : }
870 : :
871 : : /*
872 : : * build_child_join_rel
873 : : * Builds RelOptInfo representing join between given two child relations.
874 : : *
875 : : * 'outer_rel' and 'inner_rel' are the RelOptInfos of child relations being
876 : : * joined
877 : : * 'parent_joinrel' is the RelOptInfo representing the join between parent
878 : : * relations. Some of the members of new RelOptInfo are produced by
879 : : * translating corresponding members of this RelOptInfo
880 : : * 'restrictlist': list of RestrictInfo nodes that apply to this particular
881 : : * pair of joinable relations
882 : : * 'sjinfo': child join's join-type details
883 : : * 'nappinfos' and 'appinfos': AppendRelInfo array for child relids
884 : : */
885 : : RelOptInfo *
2892 rhaas@postgresql.org 886 : 2507 : build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
887 : : RelOptInfo *inner_rel, RelOptInfo *parent_joinrel,
888 : : List *restrictlist, SpecialJoinInfo *sjinfo,
889 : : int nappinfos, AppendRelInfo **appinfos)
890 : : {
891 : 2507 : RelOptInfo *joinrel = makeNode(RelOptInfo);
892 : :
893 : : /* Only joins between "other" relations land here. */
894 [ + + - + : 2507 : Assert(IS_OTHER_REL(outer_rel) && IS_OTHER_REL(inner_rel));
- - + + -
+ - - ]
895 : :
896 : : /* The parent joinrel should have consider_partitionwise_join set. */
2563 efujita@postgresql.o 897 [ - + ]: 2507 : Assert(parent_joinrel->consider_partitionwise_join);
898 : :
2892 rhaas@postgresql.org 899 : 2507 : joinrel->reloptkind = RELOPT_OTHER_JOINREL;
778 tgl@sss.pgh.pa.us 900 : 2507 : joinrel->relids = adjust_child_relids(parent_joinrel->relids,
901 : : nappinfos, appinfos);
2892 rhaas@postgresql.org 902 : 2507 : joinrel->rows = 0;
903 : : /* cheap startup cost is interesting iff not all tuples to be retrieved */
904 : 2507 : joinrel->consider_startup = (root->tuple_fraction > 0);
905 : 2507 : joinrel->consider_param_startup = false;
906 : 2507 : joinrel->consider_parallel = false;
907 : 2507 : joinrel->reltarget = create_empty_pathtarget();
908 : 2507 : joinrel->pathlist = NIL;
909 : 2507 : joinrel->ppilist = NIL;
910 : 2507 : joinrel->partial_pathlist = NIL;
911 : 2507 : joinrel->cheapest_startup_path = NULL;
912 : 2507 : joinrel->cheapest_total_path = NULL;
913 : 2507 : joinrel->cheapest_parameterized_paths = NIL;
914 : 2507 : joinrel->direct_lateral_relids = NULL;
915 : 2507 : joinrel->lateral_relids = NULL;
916 : 2507 : joinrel->relid = 0; /* indicates not a baserel */
917 : 2507 : joinrel->rtekind = RTE_JOIN;
918 : 2507 : joinrel->min_attr = 0;
919 : 2507 : joinrel->max_attr = 0;
920 : 2507 : joinrel->attr_needed = NULL;
921 : 2507 : joinrel->attr_widths = NULL;
592 drowley@postgresql.o 922 : 2507 : joinrel->notnullattnums = NULL;
950 tgl@sss.pgh.pa.us 923 : 2507 : joinrel->nulling_relids = NULL;
2892 rhaas@postgresql.org 924 : 2507 : joinrel->lateral_vars = NIL;
925 : 2507 : joinrel->lateral_referencers = NULL;
926 : 2507 : joinrel->indexlist = NIL;
927 : 2507 : joinrel->pages = 0;
928 : 2507 : joinrel->tuples = 0;
929 : 2507 : joinrel->allvisfrac = 0;
2239 drowley@postgresql.o 930 : 2507 : joinrel->eclass_indexes = NULL;
2892 rhaas@postgresql.org 931 : 2507 : joinrel->subroot = NULL;
932 : 2507 : joinrel->subplan_params = NIL;
1652 drowley@postgresql.o 933 : 2507 : joinrel->amflags = 0;
2892 rhaas@postgresql.org 934 : 2507 : joinrel->serverid = InvalidOid;
935 : 2507 : joinrel->userid = InvalidOid;
936 : 2507 : joinrel->useridiscurrent = false;
937 : 2507 : joinrel->fdwroutine = NULL;
938 : 2507 : joinrel->fdw_private = NULL;
18 rguo@postgresql.org 939 :GNC 2507 : joinrel->unique_rel = NULL;
940 : 2507 : joinrel->unique_pathkeys = NIL;
941 : 2507 : joinrel->unique_groupclause = NIL;
2892 rhaas@postgresql.org 942 :CBC 2507 : joinrel->baserestrictinfo = NIL;
943 : 2507 : joinrel->baserestrictcost.startup = 0;
944 : 2507 : joinrel->baserestrictcost.per_tuple = 0;
945 : 2507 : joinrel->joininfo = NIL;
946 : 2507 : joinrel->has_eclass_joins = false;
2413 tgl@sss.pgh.pa.us 947 : 2507 : joinrel->consider_partitionwise_join = false; /* might get changed later */
1115 948 : 2507 : joinrel->parent = parent_joinrel;
949 [ + + ]: 2507 : joinrel->top_parent = parent_joinrel->top_parent ? parent_joinrel->top_parent : parent_joinrel;
950 : 2507 : joinrel->top_parent_relids = joinrel->top_parent->relids;
2892 rhaas@postgresql.org 951 : 2507 : joinrel->part_scheme = NULL;
1977 efujita@postgresql.o 952 : 2507 : joinrel->nparts = -1;
2710 alvherre@alvh.no-ip. 953 : 2507 : joinrel->boundinfo = NULL;
1977 efujita@postgresql.o 954 : 2507 : joinrel->partbounds_merged = false;
2710 alvherre@alvh.no-ip. 955 : 2507 : joinrel->partition_qual = NIL;
2892 rhaas@postgresql.org 956 : 2507 : joinrel->part_rels = NULL;
1495 drowley@postgresql.o 957 : 2507 : joinrel->live_parts = NULL;
1977 efujita@postgresql.o 958 : 2507 : joinrel->all_partrels = NULL;
2892 rhaas@postgresql.org 959 : 2507 : joinrel->partexprs = NULL;
960 : 2507 : joinrel->nullable_partexprs = NULL;
961 : :
962 : : /* Compute information relevant to foreign relations. */
963 : 2507 : set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
964 : :
965 : : /* Set up reltarget struct */
2563 efujita@postgresql.o 966 : 2507 : build_child_join_reltarget(root, parent_joinrel, joinrel,
967 : : nappinfos, appinfos);
968 : :
969 : : /* Construct joininfo list. */
2892 rhaas@postgresql.org 970 : 5014 : joinrel->joininfo = (List *) adjust_appendrel_attrs(root,
971 : 2507 : (Node *) parent_joinrel->joininfo,
972 : : nappinfos,
973 : : appinfos);
974 : :
975 : : /*
976 : : * Lateral relids referred in child join will be same as that referred in
977 : : * the parent relation.
978 : : */
979 : 2507 : joinrel->direct_lateral_relids = (Relids) bms_copy(parent_joinrel->direct_lateral_relids);
980 : 2507 : joinrel->lateral_relids = (Relids) bms_copy(parent_joinrel->lateral_relids);
981 : :
982 : : /*
983 : : * If the parent joinrel has pending equivalence classes, so does the
984 : : * child.
985 : : */
986 : 2507 : joinrel->has_eclass_joins = parent_joinrel->has_eclass_joins;
987 : :
988 : : /* Is the join between partitions itself partitioned? */
950 tgl@sss.pgh.pa.us 989 : 2507 : build_joinrel_partition_info(root, joinrel, outer_rel, inner_rel, sjinfo,
990 : : restrictlist);
991 : :
992 : : /* Child joinrel is parallel safe if parent is parallel safe. */
2892 rhaas@postgresql.org 993 : 2507 : joinrel->consider_parallel = parent_joinrel->consider_parallel;
994 : :
995 : : /* Set estimates of the child-joinrel's size. */
996 : 2507 : set_joinrel_size_estimates(root, joinrel, outer_rel, inner_rel,
997 : : sjinfo, restrictlist);
998 : :
999 : : /* We build the join only once. */
1000 [ - + ]: 2507 : Assert(!find_join_rel(root, joinrel->relids));
1001 : :
1002 : : /* Add the relation to the PlannerInfo. */
1003 : 2507 : add_join_rel(root, joinrel);
1004 : :
1005 : : /*
1006 : : * We might need EquivalenceClass members corresponding to the child join,
1007 : : * so that we can represent sort pathkeys for it. As with children of
1008 : : * baserels, we shouldn't need this unless there are relevant eclass joins
1009 : : * (implying that a merge join might be possible) or pathkeys to sort by.
1010 : : */
2132 tgl@sss.pgh.pa.us 1011 [ + + + + ]: 2507 : if (joinrel->has_eclass_joins || has_useful_pathkeys(root, parent_joinrel))
1012 : 2231 : add_child_join_rel_equivalences(root,
1013 : : nappinfos, appinfos,
1014 : : parent_joinrel, joinrel);
1015 : :
2892 rhaas@postgresql.org 1016 : 2507 : return joinrel;
1017 : : }
1018 : :
1019 : : /*
1020 : : * min_join_parameterization
1021 : : *
1022 : : * Determine the minimum possible parameterization of a joinrel, that is, the
1023 : : * set of other rels it contains LATERAL references to. We save this value in
1024 : : * the join's RelOptInfo. This function is split out of build_join_rel()
1025 : : * because join_is_legal() needs the value to check a prospective join.
1026 : : */
1027 : : Relids
3557 tgl@sss.pgh.pa.us 1028 : 110180 : min_join_parameterization(PlannerInfo *root,
1029 : : Relids joinrelids,
1030 : : RelOptInfo *outer_rel,
1031 : : RelOptInfo *inner_rel)
1032 : : {
1033 : : Relids result;
1034 : :
1035 : : /*
1036 : : * Basically we just need the union of the inputs' lateral_relids, less
1037 : : * whatever is already in the join.
1038 : : *
1039 : : * It's not immediately obvious that this is a valid way to compute the
1040 : : * result, because it might seem that we're ignoring possible lateral refs
1041 : : * of PlaceHolderVars that are due to be computed at the join but not in
1042 : : * either input. However, because create_lateral_join_info() already
1043 : : * charged all such PHV refs to each member baserel of the join, they'll
1044 : : * be accounted for already in the inputs' lateral_relids. Likewise, we
1045 : : * do not need to worry about doing transitive closure here, because that
1046 : : * was already accounted for in the original baserel lateral_relids.
1047 : : */
1048 : 110180 : result = bms_union(outer_rel->lateral_relids, inner_rel->lateral_relids);
3561 1049 : 110180 : result = bms_del_members(result, joinrelids);
1050 : 110180 : return result;
1051 : : }
1052 : :
1053 : : /*
1054 : : * build_joinrel_tlist
1055 : : * Builds a join relation's target list from an input relation.
1056 : : * (This is invoked twice to handle the two input relations.)
1057 : : *
1058 : : * The join's targetlist includes all Vars of its member relations that
1059 : : * will still be needed above the join. This subroutine adds all such
1060 : : * Vars from the specified input rel's tlist to the join rel's tlist.
1061 : : * Likewise for any PlaceHolderVars emitted by the input rel.
1062 : : *
1063 : : * We also compute the expected width of the join's output, making use
1064 : : * of data that was cached at the baserel level by set_rel_width().
1065 : : *
1066 : : * Pass can_null as true if the join is an outer join that can null Vars
1067 : : * from this input relation. If so, we will (normally) add the join's relid
1068 : : * to the nulling bitmaps of Vars and PHVs bubbled up from the input.
1069 : : *
1070 : : * When forming an outer join's target list, special handling is needed in
1071 : : * case the outer join was commuted with another one per outer join identity 3
1072 : : * (see optimizer/README). We must take steps to ensure that the output Vars
1073 : : * have the same nulling bitmaps that they would if the two joins had been
1074 : : * done in syntactic order; else they won't match Vars appearing higher in
1075 : : * the query tree. An exception to the match-the-syntactic-order rule is
1076 : : * that when an outer join is pushed down into another one's RHS per identity
1077 : : * 3, we can't mark its Vars as nulled until the now-upper outer join is also
1078 : : * completed. So we need to do three things:
1079 : : *
1080 : : * First, we add the outer join's relid to the nulling bitmap only if the
1081 : : * outer join has been completely performed and the Var or PHV actually
1082 : : * comes from within the syntactically nullable side(s) of the outer join.
1083 : : * This takes care of the possibility that we have transformed
1084 : : * (A leftjoin B on (Pab)) leftjoin C on (Pbc)
1085 : : * to
1086 : : * A leftjoin (B leftjoin C on (Pbc)) on (Pab)
1087 : : * Here the pushed-down B/C join cannot mark C columns as nulled yet,
1088 : : * while the now-upper A/B join must not mark C columns as nulled by itself.
1089 : : *
1090 : : * Second, perform the same operation for each SpecialJoinInfo listed in
1091 : : * pushed_down_joins (which, in this example, would be the B/C join when
1092 : : * we are at the now-upper A/B join). This allows the now-upper join to
1093 : : * complete the marking of "C" Vars that now have fully valid values.
1094 : : *
1095 : : * Third, any relid in sjinfo->commute_above_r that is already part of
1096 : : * the joinrel is added to the nulling bitmaps of nullable Vars and PHVs.
1097 : : * This takes care of the reverse case where we implement
1098 : : * A leftjoin (B leftjoin C on (Pbc)) on (Pab)
1099 : : * as
1100 : : * (A leftjoin B on (Pab)) leftjoin C on (Pbc)
1101 : : * The C columns emitted by the B/C join need to be shown as nulled by both
1102 : : * the B/C and A/B joins, even though they've not physically traversed the
1103 : : * A/B join.
1104 : : */
1105 : : static void
7397 1106 : 202642 : build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
1107 : : RelOptInfo *input_rel,
1108 : : SpecialJoinInfo *sjinfo,
1109 : : List *pushed_down_joins,
1110 : : bool can_null)
1111 : : {
2563 efujita@postgresql.o 1112 : 202642 : Relids relids = joinrel->relids;
627 tgl@sss.pgh.pa.us 1113 : 202642 : int64 tuple_width = joinrel->reltarget->width;
1114 : : ListCell *vars;
1115 : : ListCell *lc;
1116 : :
3463 1117 [ + + + + : 1031028 : foreach(vars, input_rel->reltarget->exprs)
+ + ]
1118 : : {
4759 1119 : 828386 : Var *var = (Var *) lfirst(vars);
1120 : :
1121 : : /*
1122 : : * For a PlaceHolderVar, we have to look up the PlaceHolderInfo.
1123 : : */
1124 [ + + ]: 828386 : if (IsA(var, PlaceHolderVar))
1116 1125 : 1028 : {
1126 : 1028 : PlaceHolderVar *phv = (PlaceHolderVar *) var;
1127 : 1028 : PlaceHolderInfo *phinfo = find_placeholder_info(root, phv);
1128 : :
1129 : : /* Is it still needed above this joinrel? */
1130 [ + + ]: 1028 : if (bms_nonempty_difference(phinfo->ph_needed, relids))
1131 : : {
1132 : : /*
1133 : : * Yup, add it to the output. If this join potentially nulls
1134 : : * this input, we have to update the PHV's phnullingrels,
1135 : : * which means making a copy.
1136 : : */
950 1137 [ + + ]: 770 : if (can_null)
1138 : : {
1139 : 497 : phv = copyObject(phv);
1140 : : /* See comments above to understand this logic */
1141 [ + - + + ]: 994 : if (sjinfo->ojrelid != 0 &&
843 1142 [ + + ]: 982 : bms_is_member(sjinfo->ojrelid, relids) &&
942 1143 : 485 : (bms_is_subset(phv->phrels, sjinfo->syn_righthand) ||
1144 [ + + + - ]: 120 : (sjinfo->jointype == JOIN_FULL &&
1145 : 57 : bms_is_subset(phv->phrels, sjinfo->syn_lefthand))))
950 1146 : 479 : phv->phnullingrels = bms_add_member(phv->phnullingrels,
1147 : 479 : sjinfo->ojrelid);
843 1148 [ + + + + : 506 : foreach(lc, pushed_down_joins)
+ + ]
1149 : : {
1150 : 9 : SpecialJoinInfo *othersj = (SpecialJoinInfo *) lfirst(lc);
1151 : :
1152 [ - + ]: 9 : Assert(bms_is_member(othersj->ojrelid, relids));
1153 [ + + ]: 9 : if (bms_is_subset(phv->phrels, othersj->syn_righthand))
1154 : 6 : phv->phnullingrels = bms_add_member(phv->phnullingrels,
1155 : 6 : othersj->ojrelid);
1156 : : }
941 1157 : 497 : phv->phnullingrels =
1158 : 497 : bms_join(phv->phnullingrels,
1159 : 497 : bms_intersect(sjinfo->commute_above_r,
1160 : : relids));
1161 : : }
1162 : :
1116 1163 : 770 : joinrel->reltarget->exprs = lappend(joinrel->reltarget->exprs,
1164 : : phv);
1165 : : /* Bubbling up the precomputed result has cost zero */
627 1166 : 770 : tuple_width += phinfo->ph_width;
1167 : : }
6164 1168 : 1028 : continue;
1169 : : }
1170 : :
1171 : : /*
1172 : : * Otherwise, anything in a baserel or joinrel targetlist ought to be
1173 : : * a Var. (More general cases can only appear in appendrel child
1174 : : * rels, which will never be seen here.)
1175 : : */
2563 efujita@postgresql.o 1176 [ - + ]: 827358 : if (!IsA(var, Var))
3488 tgl@sss.pgh.pa.us 1177 [ # # ]:UBC 0 : elog(ERROR, "unexpected node type in rel targetlist: %d",
1178 : : (int) nodeTag(var));
1179 : :
1620 tgl@sss.pgh.pa.us 1180 [ + + ]:CBC 827358 : if (var->varno == ROWID_VAR)
1181 : : {
1182 : : /* UPDATE/DELETE/MERGE row identity vars are always needed */
1183 : : RowIdentityVarInfo *ridinfo = (RowIdentityVarInfo *)
841 1184 : 624 : list_nth(root->row_identity_vars, var->varattno - 1);
1185 : :
1186 : : /* Update reltarget width estimate from RowIdentityVarInfo */
627 1187 : 624 : tuple_width += ridinfo->rowidwidth;
1188 : : }
1189 : : else
1190 : : {
1191 : : RelOptInfo *baserel;
1192 : : int ndx;
1193 : :
1194 : : /* Get the Var's original base rel */
1620 1195 : 826734 : baserel = find_base_rel(root, var->varno);
1196 : :
1197 : : /* Is it still needed above this joinrel? */
1198 : 826734 : ndx = var->varattno - baserel->min_attr;
950 1199 [ + + ]: 826734 : if (!bms_nonempty_difference(baserel->attr_needed[ndx], relids))
1200 : 149140 : continue; /* nope, skip it */
1201 : :
1202 : : /* Update reltarget width estimate from baserel's attr_widths */
627 1203 : 677594 : tuple_width += baserel->attr_widths[ndx];
1204 : : }
1205 : :
1206 : : /*
1207 : : * Add the Var to the output. If this join potentially nulls this
1208 : : * input, we have to update the Var's varnullingrels, which means
1209 : : * making a copy. But note that we don't ever add nullingrel bits to
1210 : : * row identity Vars (cf. comments in setrefs.c).
1211 : : */
942 1212 [ + + + + ]: 678218 : if (can_null && var->varno != ROWID_VAR)
1213 : : {
950 1214 : 68083 : var = copyObject(var);
1215 : : /* See comments above to understand this logic */
1216 [ + + + + ]: 135807 : if (sjinfo->ojrelid != 0 &&
843 1217 [ + + ]: 132748 : bms_is_member(sjinfo->ojrelid, relids) &&
942 1218 : 65024 : (bms_is_member(var->varno, sjinfo->syn_righthand) ||
1219 [ + + + - ]: 1944 : (sjinfo->jointype == JOIN_FULL &&
1220 : 906 : bms_is_member(var->varno, sjinfo->syn_lefthand))))
950 1221 : 64892 : var->varnullingrels = bms_add_member(var->varnullingrels,
1222 : 64892 : sjinfo->ojrelid);
843 1223 [ + + + + : 68422 : foreach(lc, pushed_down_joins)
+ + ]
1224 : : {
1225 : 339 : SpecialJoinInfo *othersj = (SpecialJoinInfo *) lfirst(lc);
1226 : :
1227 [ - + ]: 339 : Assert(bms_is_member(othersj->ojrelid, relids));
1228 [ + + ]: 339 : if (bms_is_member(var->varno, othersj->syn_righthand))
1229 : 132 : var->varnullingrels = bms_add_member(var->varnullingrels,
1230 : 132 : othersj->ojrelid);
1231 : : }
941 1232 : 68083 : var->varnullingrels =
1233 : 68083 : bms_join(var->varnullingrels,
1234 : 68083 : bms_intersect(sjinfo->commute_above_r,
1235 : : relids));
1236 : : }
1237 : :
950 1238 : 678218 : joinrel->reltarget->exprs = lappend(joinrel->reltarget->exprs,
1239 : : var);
1240 : :
1241 : : /* Vars have cost zero, so no need to adjust reltarget->cost */
1242 : : }
1243 : :
627 1244 : 202642 : joinrel->reltarget->width = clamp_width_est(tuple_width);
9343 1245 : 202642 : }
1246 : :
1247 : : /*
1248 : : * build_joinrel_restrictlist
1249 : : * build_joinrel_joinlist
1250 : : * These routines build lists of restriction and join clauses for a
1251 : : * join relation from the joininfo lists of the relations it joins.
1252 : : *
1253 : : * These routines are separate because the restriction list must be
1254 : : * built afresh for each pair of input sub-relations we consider, whereas
1255 : : * the join list need only be computed once for any join RelOptInfo.
1256 : : * The join list is fully determined by the set of rels making up the
1257 : : * joinrel, so we should get the same results (up to ordering) from any
1258 : : * candidate pair of sub-relations. But the restriction list is whatever
1259 : : * is not handled in the sub-relations, so it depends on which
1260 : : * sub-relations are considered.
1261 : : *
1262 : : * If a join clause from an input relation refers to base+OJ rels still not
1263 : : * present in the joinrel, then it is still a join clause for the joinrel;
1264 : : * we put it into the joininfo list for the joinrel. Otherwise,
1265 : : * the clause is now a restrict clause for the joined relation, and we
1266 : : * return it to the caller of build_joinrel_restrictlist() to be stored in
1267 : : * join paths made from this pair of sub-relations. (It will not need to
1268 : : * be considered further up the join tree.)
1269 : : *
1270 : : * In many cases we will find the same RestrictInfos in both input
1271 : : * relations' joinlists, so be careful to eliminate duplicates.
1272 : : * Pointer equality should be a sufficient test for dups, since all
1273 : : * the various joinlist entries ultimately refer to RestrictInfos
1274 : : * pushed into them by distribute_restrictinfo_to_rels().
1275 : : *
1276 : : * 'joinrel' is a join relation node
1277 : : * 'outer_rel' and 'inner_rel' are a pair of relations that can be joined
1278 : : * to form joinrel.
1279 : : * 'sjinfo': join context info
1280 : : *
1281 : : * build_joinrel_restrictlist() returns a list of relevant restrictinfos,
1282 : : * whereas build_joinrel_joinlist() stores its results in the joinrel's
1283 : : * joininfo list. One or the other must accept each given clause!
1284 : : *
1285 : : * NB: Formerly, we made deep(!) copies of each input RestrictInfo to pass
1286 : : * up to the join relation. I believe this is no longer necessary, because
1287 : : * RestrictInfo nodes are no longer context-dependent. Instead, just include
1288 : : * the original nodes in the lists made for the join relation.
1289 : : */
1290 : : static List *
7398 1291 : 156698 : build_joinrel_restrictlist(PlannerInfo *root,
1292 : : RelOptInfo *joinrel,
1293 : : RelOptInfo *outer_rel,
1294 : : RelOptInfo *inner_rel,
1295 : : SpecialJoinInfo *sjinfo)
1296 : : {
1297 : : List *result;
1298 : : Relids both_input_relids;
1299 : :
950 1300 : 156698 : both_input_relids = bms_union(outer_rel->relids, inner_rel->relids);
1301 : :
1302 : : /*
1303 : : * Collect all the clauses that syntactically belong at this level,
1304 : : * eliminating any duplicates (important since we will see many of the
1305 : : * same clauses arriving from both input relations).
1306 : : */
1307 : 156698 : result = subbuild_joinrel_restrictlist(root, joinrel, outer_rel,
1308 : : both_input_relids, NIL);
1309 : 156698 : result = subbuild_joinrel_restrictlist(root, joinrel, inner_rel,
1310 : : both_input_relids, result);
1311 : :
1312 : : /*
1313 : : * Add on any clauses derived from EquivalenceClasses. These cannot be
1314 : : * redundant with the clauses in the joininfo lists, so don't bother
1315 : : * checking.
1316 : : */
6804 1317 : 156698 : result = list_concat(result,
1318 : 156698 : generate_join_implied_equalities(root,
1319 : : joinrel->relids,
1320 : : outer_rel->relids,
1321 : : inner_rel,
1322 : : sjinfo));
1323 : :
8724 1324 : 156698 : return result;
1325 : : }
1326 : :
1327 : : static void
9343 1328 : 101321 : build_joinrel_joinlist(RelOptInfo *joinrel,
1329 : : RelOptInfo *outer_rel,
1330 : : RelOptInfo *inner_rel)
1331 : : {
1332 : : List *result;
1333 : :
1334 : : /*
1335 : : * Collect all the clauses that syntactically belong above this level,
1336 : : * eliminating any duplicates (important since we will see many of the
1337 : : * same clauses arriving from both input relations).
1338 : : */
6804 1339 : 101321 : result = subbuild_joinrel_joinlist(joinrel, outer_rel->joininfo, NIL);
1340 : 101321 : result = subbuild_joinrel_joinlist(joinrel, inner_rel->joininfo, result);
1341 : :
1342 : 101321 : joinrel->joininfo = result;
9343 1343 : 101321 : }
1344 : :
1345 : : static List *
950 1346 : 313396 : subbuild_joinrel_restrictlist(PlannerInfo *root,
1347 : : RelOptInfo *joinrel,
1348 : : RelOptInfo *input_rel,
1349 : : Relids both_input_relids,
1350 : : List *new_restrictlist)
1351 : : {
1352 : : ListCell *l;
1353 : :
1354 [ + + + + : 612817 : foreach(l, input_rel->joininfo)
+ + ]
1355 : : {
7394 1356 : 299421 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
1357 : :
1358 [ + + ]: 299421 : if (bms_is_subset(rinfo->required_relids, joinrel->relids))
1359 : : {
1360 : : /*
1361 : : * This clause should become a restriction clause for the joinrel,
1362 : : * since it refers to no outside rels. However, if it's a clone
1363 : : * clause then it might be too late to evaluate it, so we have to
1364 : : * check. (If it is too late, just ignore the clause, taking it
1365 : : * on faith that another clone was or will be selected.) Clone
1366 : : * clauses should always be outer-join clauses, so we compare
1367 : : * against both_input_relids.
1368 : : */
950 1369 [ + + + + ]: 177651 : if (rinfo->has_clone || rinfo->is_clone)
1370 : : {
1371 [ + - - + ]: 32104 : Assert(!RINFO_IS_PUSHED_DOWN(rinfo, joinrel->relids));
1372 [ + + ]: 32104 : if (!bms_is_subset(rinfo->required_relids, both_input_relids))
1373 : 5372 : continue;
835 1374 [ + + ]: 26732 : if (bms_overlap(rinfo->incompatible_relids, both_input_relids))
950 1375 : 10602 : continue;
1376 : : }
1377 : : else
1378 : : {
1379 : : /*
1380 : : * For non-clone clauses, we just Assert it's OK. These might
1381 : : * be either join or filter clauses; if it's a join clause
1382 : : * then it should not refer to the current join's output.
1383 : : * (There is little point in checking incompatible_relids,
1384 : : * because it'll be NULL.)
1385 : : */
835 1386 [ + + + - : 145547 : Assert(RINFO_IS_PUSHED_DOWN(rinfo, joinrel->relids) ||
- + ]
1387 : : bms_is_subset(rinfo->required_relids,
1388 : : both_input_relids));
1389 : : }
1390 : :
1391 : : /*
1392 : : * OK, so add it to the list, being careful to eliminate
1393 : : * duplicates. (Since RestrictInfo nodes in different joinlists
1394 : : * will have been multiply-linked rather than copied, pointer
1395 : : * equality should be a sufficient test.)
1396 : : */
6804 1397 : 161677 : new_restrictlist = list_append_unique_ptr(new_restrictlist, rinfo);
1398 : : }
1399 : : else
1400 : : {
1401 : : /*
1402 : : * This clause is still a join clause at this level, so we ignore
1403 : : * it in this routine.
1404 : : */
1405 : : }
1406 : : }
1407 : :
1408 : 313396 : return new_restrictlist;
1409 : : }
1410 : :
1411 : : static List *
9343 1412 : 202642 : subbuild_joinrel_joinlist(RelOptInfo *joinrel,
1413 : : List *joininfo_list,
1414 : : List *new_joininfo)
1415 : : {
1416 : : ListCell *l;
1417 : :
1418 : : /* Expected to be called only for join between parent relations. */
2892 rhaas@postgresql.org 1419 [ - + ]: 202642 : Assert(joinrel->reloptkind == RELOPT_JOINREL);
1420 : :
7394 tgl@sss.pgh.pa.us 1421 [ + + + + : 390228 : foreach(l, joininfo_list)
+ + ]
1422 : : {
1423 : 187586 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
1424 : :
1425 [ + + ]: 187586 : if (bms_is_subset(rinfo->required_relids, joinrel->relids))
1426 : : {
1427 : : /*
1428 : : * This clause becomes a restriction clause for the joinrel, since
1429 : : * it refers to no outside rels. So we can ignore it in this
1430 : : * routine.
1431 : : */
1432 : : }
1433 : : else
1434 : : {
1435 : : /*
1436 : : * This clause is still a join clause at this level, so add it to
1437 : : * the new joininfo list, being careful to eliminate duplicates.
1438 : : * (Since RestrictInfo nodes in different joinlists will have been
1439 : : * multiply-linked rather than copied, pointer equality should be
1440 : : * a sufficient test.)
1441 : : */
6804 1442 : 74263 : new_joininfo = list_append_unique_ptr(new_joininfo, rinfo);
1443 : : }
1444 : : }
1445 : :
1446 : 202642 : return new_joininfo;
1447 : : }
1448 : :
1449 : :
1450 : : /*
1451 : : * fetch_upper_rel
1452 : : * Build a RelOptInfo describing some post-scan/join query processing,
1453 : : * or return a pre-existing one if somebody already built it.
1454 : : *
1455 : : * An "upper" relation is identified by an UpperRelationKind and a Relids set.
1456 : : * The meaning of the Relids set is not specified here, and very likely will
1457 : : * vary for different relation kinds.
1458 : : *
1459 : : * Most of the fields in an upper-level RelOptInfo are not used and are not
1460 : : * set here (though makeNode should ensure they're zeroes). We basically only
1461 : : * care about fields that are of interest to add_path() and set_cheapest().
1462 : : */
1463 : : RelOptInfo *
3470 1464 : 859799 : fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
1465 : : {
1466 : : RelOptInfo *upperrel;
1467 : : ListCell *lc;
1468 : :
1469 : : /*
1470 : : * For the moment, our indexing data structure is just a List for each
1471 : : * relation kind. If we ever get so many of one kind that this stops
1472 : : * working well, we can improve it. No code outside this function should
1473 : : * assume anything about how to find a particular upperrel.
1474 : : */
1475 : :
1476 : : /* If we already made this upperrel for the query, return it */
1477 [ + + + + : 863270 : foreach(lc, root->upper_rels[kind])
+ + ]
1478 : : {
1479 : 544041 : upperrel = (RelOptInfo *) lfirst(lc);
1480 : :
1481 [ + + ]: 544041 : if (bms_equal(upperrel->relids, relids))
1482 : 540570 : return upperrel;
1483 : : }
1484 : :
1485 : 319229 : upperrel = makeNode(RelOptInfo);
1486 : 319229 : upperrel->reloptkind = RELOPT_UPPER_REL;
1487 : 319229 : upperrel->relids = bms_copy(relids);
1488 : :
1489 : : /* cheap startup cost is interesting iff not all tuples to be retrieved */
1490 : 319229 : upperrel->consider_startup = (root->tuple_fraction > 0);
1491 : 319229 : upperrel->consider_param_startup = false;
2999 1492 : 319229 : upperrel->consider_parallel = false; /* might get changed later */
3463 1493 : 319229 : upperrel->reltarget = create_empty_pathtarget();
3470 1494 : 319229 : upperrel->pathlist = NIL;
1495 : 319229 : upperrel->cheapest_startup_path = NULL;
1496 : 319229 : upperrel->cheapest_total_path = NULL;
1497 : 319229 : upperrel->cheapest_parameterized_paths = NIL;
1498 : :
1499 : 319229 : root->upper_rels[kind] = lappend(root->upper_rels[kind], upperrel);
1500 : :
1501 : 319229 : return upperrel;
1502 : : }
1503 : :
1504 : :
1505 : : /*
1506 : : * find_childrel_parents
1507 : : * Compute the set of parent relids of an appendrel child rel.
1508 : : *
1509 : : * Since appendrels can be nested, a child could have multiple levels of
1510 : : * appendrel ancestors. This function computes a Relids set of all the
1511 : : * parent relation IDs.
1512 : : */
1513 : : Relids
3993 1514 : 6095 : find_childrel_parents(PlannerInfo *root, RelOptInfo *rel)
1515 : : {
1516 : 6095 : Relids result = NULL;
1517 : :
3078 rhaas@postgresql.org 1518 [ - + ]: 6095 : Assert(rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
2629 alvherre@alvh.no-ip. 1519 [ + - - + ]: 6095 : Assert(rel->relid > 0 && rel->relid < root->simple_rel_array_size);
1520 : :
1521 : : do
1522 : : {
1523 : 7185 : AppendRelInfo *appinfo = root->append_rel_array[rel->relid];
3993 tgl@sss.pgh.pa.us 1524 : 7185 : Index prelid = appinfo->parent_relid;
1525 : :
1526 : 7185 : result = bms_add_member(result, prelid);
1527 : :
1528 : : /* traverse up to the parent rel, loop if it's also a child rel */
1529 : 7185 : rel = find_base_rel(root, prelid);
1530 [ + + ]: 7185 : } while (rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
1531 : :
1532 [ - + ]: 6095 : Assert(rel->reloptkind == RELOPT_BASEREL);
1533 : :
1534 : 6095 : return result;
1535 : : }
1536 : :
1537 : :
1538 : : /*
1539 : : * get_baserel_parampathinfo
1540 : : * Get the ParamPathInfo for a parameterized path for a base relation,
1541 : : * constructing one if we don't have one already.
1542 : : *
1543 : : * This centralizes estimating the rowcounts for parameterized paths.
1544 : : * We need to cache those to be sure we use the same rowcount for all paths
1545 : : * of the same parameterization for a given rel. This is also a convenient
1546 : : * place to determine which movable join clauses the parameterized path will
1547 : : * be responsible for evaluating.
1548 : : */
1549 : : ParamPathInfo *
4888 1550 : 883926 : get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel,
1551 : : Relids required_outer)
1552 : : {
1553 : : ParamPathInfo *ppi;
1554 : : Relids joinrelids;
1555 : : List *pclauses;
1556 : : List *eqclauses;
1557 : : Bitmapset *pserials;
1558 : : double rows;
1559 : : ListCell *lc;
1560 : :
1561 : : /* If rel has LATERAL refs, every path for it should account for them */
2403 1562 [ - + ]: 883926 : Assert(bms_is_subset(baserel->lateral_relids, required_outer));
1563 : :
1564 : : /* Unparameterized paths have no ParamPathInfo */
4888 1565 [ + + ]: 883926 : if (bms_is_empty(required_outer))
1566 : 730062 : return NULL;
1567 : :
1568 [ - + ]: 153864 : Assert(!bms_overlap(baserel->relids, required_outer));
1569 : :
1570 : : /* If we already have a PPI for this parameterization, just return it */
2944 rhaas@postgresql.org 1571 [ + + ]: 153864 : if ((ppi = find_param_path_info(baserel, required_outer)))
1572 : 81775 : return ppi;
1573 : :
1574 : : /*
1575 : : * Identify all joinclauses that are movable to this base rel given this
1576 : : * parameterization.
1577 : : */
4888 tgl@sss.pgh.pa.us 1578 : 72089 : joinrelids = bms_union(baserel->relids, required_outer);
1579 : 72089 : pclauses = NIL;
1580 [ + + + + : 120792 : foreach(lc, baserel->joininfo)
+ + ]
1581 : : {
1582 : 48703 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1583 : :
1584 [ + + ]: 48703 : if (join_clause_is_movable_into(rinfo,
1585 : : baserel->relids,
1586 : : joinrelids))
1587 : 20633 : pclauses = lappend(pclauses, rinfo);
1588 : : }
1589 : :
1590 : : /*
1591 : : * Add in joinclauses generated by EquivalenceClasses, too. (These
1592 : : * necessarily satisfy join_clause_is_movable_into; but in assert-enabled
1593 : : * builds, let's verify that.)
1594 : : */
508 1595 : 72089 : eqclauses = generate_join_implied_equalities(root,
1596 : : joinrelids,
1597 : : required_outer,
1598 : : baserel,
1599 : : NULL);
1600 : : #ifdef USE_ASSERT_CHECKING
1601 [ + + + + : 125217 : foreach(lc, eqclauses)
+ + ]
1602 : : {
1603 : 53128 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1604 : :
1605 [ - + ]: 53128 : Assert(join_clause_is_movable_into(rinfo,
1606 : : baserel->relids,
1607 : : joinrelids));
1608 : : }
1609 : : #endif
1610 : 72089 : pclauses = list_concat(pclauses, eqclauses);
1611 : :
1612 : : /* Compute set of serial numbers of the enforced clauses */
950 1613 : 72089 : pserials = NULL;
1614 [ + + + + : 145850 : foreach(lc, pclauses)
+ + ]
1615 : : {
1616 : 73761 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1617 : :
1618 : 73761 : pserials = bms_add_member(pserials, rinfo->rinfo_serial);
1619 : : }
1620 : :
1621 : : /* Estimate the number of rows returned by the parameterized scan */
4888 1622 : 72089 : rows = get_parameterized_baserel_size(root, baserel, pclauses);
1623 : :
1624 : : /* And now we can build the ParamPathInfo */
1625 : 72089 : ppi = makeNode(ParamPathInfo);
1626 : 72089 : ppi->ppi_req_outer = required_outer;
1627 : 72089 : ppi->ppi_rows = rows;
1628 : 72089 : ppi->ppi_clauses = pclauses;
950 1629 : 72089 : ppi->ppi_serials = pserials;
4888 1630 : 72089 : baserel->ppilist = lappend(baserel->ppilist, ppi);
1631 : :
1632 : 72089 : return ppi;
1633 : : }
1634 : :
1635 : : /*
1636 : : * get_joinrel_parampathinfo
1637 : : * Get the ParamPathInfo for a parameterized path for a join relation,
1638 : : * constructing one if we don't have one already.
1639 : : *
1640 : : * This centralizes estimating the rowcounts for parameterized paths.
1641 : : * We need to cache those to be sure we use the same rowcount for all paths
1642 : : * of the same parameterization for a given rel. This is also a convenient
1643 : : * place to determine which movable join clauses the parameterized path will
1644 : : * be responsible for evaluating.
1645 : : *
1646 : : * outer_path and inner_path are a pair of input paths that can be used to
1647 : : * construct the join, and restrict_clauses is the list of regular join
1648 : : * clauses (including clauses derived from EquivalenceClasses) that must be
1649 : : * applied at the join node when using these inputs.
1650 : : *
1651 : : * Unlike the situation for base rels, the set of movable join clauses to be
1652 : : * enforced at a join varies with the selected pair of input paths, so we
1653 : : * must calculate that and pass it back, even if we already have a matching
1654 : : * ParamPathInfo. We handle this by adding any clauses moved down to this
1655 : : * join to *restrict_clauses, which is an in/out parameter. (The addition
1656 : : * is done in such a way as to not modify the passed-in List structure.)
1657 : : *
1658 : : * Note: when considering a nestloop join, the caller must have removed from
1659 : : * restrict_clauses any movable clauses that are themselves scheduled to be
1660 : : * pushed into the right-hand path. We do not do that here since it's
1661 : : * unnecessary for other join types.
1662 : : */
1663 : : ParamPathInfo *
1664 : 966193 : get_joinrel_parampathinfo(PlannerInfo *root, RelOptInfo *joinrel,
1665 : : Path *outer_path,
1666 : : Path *inner_path,
1667 : : SpecialJoinInfo *sjinfo,
1668 : : Relids required_outer,
1669 : : List **restrict_clauses)
1670 : : {
1671 : : ParamPathInfo *ppi;
1672 : : Relids join_and_req;
1673 : : Relids outer_and_req;
1674 : : Relids inner_and_req;
1675 : : List *pclauses;
1676 : : List *eclauses;
1677 : : List *dropped_ecs;
1678 : : double rows;
1679 : : ListCell *lc;
1680 : :
1681 : : /* If rel has LATERAL refs, every path for it should account for them */
2403 1682 [ - + ]: 966193 : Assert(bms_is_subset(joinrel->lateral_relids, required_outer));
1683 : :
1684 : : /* Unparameterized paths have no ParamPathInfo or extra join clauses */
4888 1685 [ + + ]: 966193 : if (bms_is_empty(required_outer))
1686 : 948921 : return NULL;
1687 : :
1688 [ - + ]: 17272 : Assert(!bms_overlap(joinrel->relids, required_outer));
1689 : :
1690 : : /*
1691 : : * Identify all joinclauses that are movable to this join rel given this
1692 : : * parameterization. These are the clauses that are movable into this
1693 : : * join, but not movable into either input path. Treat an unparameterized
1694 : : * input path as not accepting parameterized clauses (because it won't,
1695 : : * per the shortcut exit above), even though the joinclause movement rules
1696 : : * might allow the same clauses to be moved into a parameterized path for
1697 : : * that rel.
1698 : : */
1699 : 17272 : join_and_req = bms_union(joinrel->relids, required_outer);
1700 [ + + ]: 17272 : if (outer_path->param_info)
1701 : 14407 : outer_and_req = bms_union(outer_path->parent->relids,
1702 [ + - ]: 14407 : PATH_REQ_OUTER(outer_path));
1703 : : else
4836 bruce@momjian.us 1704 : 2865 : outer_and_req = NULL; /* outer path does not accept parameters */
4888 tgl@sss.pgh.pa.us 1705 [ + + ]: 17272 : if (inner_path->param_info)
1706 : 9574 : inner_and_req = bms_union(inner_path->parent->relids,
1707 [ + - ]: 9574 : PATH_REQ_OUTER(inner_path));
1708 : : else
4836 bruce@momjian.us 1709 : 7698 : inner_and_req = NULL; /* inner path does not accept parameters */
1710 : :
4888 tgl@sss.pgh.pa.us 1711 : 17272 : pclauses = NIL;
1712 [ + + + + : 43261 : foreach(lc, joinrel->joininfo)
+ + ]
1713 : : {
1714 : 25989 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1715 : :
1716 [ + + ]: 25989 : if (join_clause_is_movable_into(rinfo,
1717 : : joinrel->relids,
1718 : 12446 : join_and_req) &&
1719 [ + + ]: 12446 : !join_clause_is_movable_into(rinfo,
1720 : 12446 : outer_path->parent->relids,
1721 : 370 : outer_and_req) &&
1722 [ + + ]: 370 : !join_clause_is_movable_into(rinfo,
1723 : 370 : inner_path->parent->relids,
1724 : : inner_and_req))
1725 : 48 : pclauses = lappend(pclauses, rinfo);
1726 : : }
1727 : :
1728 : : /* Consider joinclauses generated by EquivalenceClasses, too */
1729 : 17272 : eclauses = generate_join_implied_equalities(root,
1730 : : join_and_req,
1731 : : required_outer,
1732 : : joinrel,
1733 : : NULL);
1734 : : /* We only want ones that aren't movable to lower levels */
3417 1735 : 17272 : dropped_ecs = NIL;
4888 1736 [ + + + + : 21348 : foreach(lc, eclauses)
+ + ]
1737 : : {
1738 : 4076 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1739 : :
1740 [ - + ]: 4076 : Assert(join_clause_is_movable_into(rinfo,
1741 : : joinrel->relids,
1742 : : join_and_req));
3417 1743 [ + + ]: 4076 : if (join_clause_is_movable_into(rinfo,
1744 : 4076 : outer_path->parent->relids,
1745 : : outer_and_req))
1746 : 1622 : continue; /* drop if movable into LHS */
1747 [ + + ]: 2454 : if (join_clause_is_movable_into(rinfo,
1748 : 2454 : inner_path->parent->relids,
1749 : : inner_and_req))
1750 : : {
1751 : : /* drop if movable into RHS, but remember EC for use below */
1752 [ - + ]: 1823 : Assert(rinfo->left_ec == rinfo->right_ec);
1753 : 1823 : dropped_ecs = lappend(dropped_ecs, rinfo->left_ec);
1754 : 1823 : continue;
1755 : : }
1756 : 631 : pclauses = lappend(pclauses, rinfo);
1757 : : }
1758 : :
1759 : : /*
1760 : : * EquivalenceClasses are harder to deal with than we could wish, because
1761 : : * of the fact that a given EC can generate different clauses depending on
1762 : : * context. Suppose we have an EC {X.X, Y.Y, Z.Z} where X and Y are the
1763 : : * LHS and RHS of the current join and Z is in required_outer, and further
1764 : : * suppose that the inner_path is parameterized by both X and Z. The code
1765 : : * above will have produced either Z.Z = X.X or Z.Z = Y.Y from that EC,
1766 : : * and in the latter case will have discarded it as being movable into the
1767 : : * RHS. However, the EC machinery might have produced either Y.Y = X.X or
1768 : : * Y.Y = Z.Z as the EC enforcement clause within the inner_path; it will
1769 : : * not have produced both, and we can't readily tell from here which one
1770 : : * it did pick. If we add no clause to this join, we'll end up with
1771 : : * insufficient enforcement of the EC; either Z.Z or X.X will fail to be
1772 : : * constrained to be equal to the other members of the EC. (When we come
1773 : : * to join Z to this X/Y path, we will certainly drop whichever EC clause
1774 : : * is generated at that join, so this omission won't get fixed later.)
1775 : : *
1776 : : * To handle this, for each EC we discarded such a clause from, try to
1777 : : * generate a clause connecting the required_outer rels to the join's LHS
1778 : : * ("Z.Z = X.X" in the terms of the above example). If successful, and if
1779 : : * the clause can't be moved to the LHS, add it to the current join's
1780 : : * restriction clauses. (If an EC cannot generate such a clause then it
1781 : : * has nothing that needs to be enforced here, while if the clause can be
1782 : : * moved into the LHS then it should have been enforced within that path.)
1783 : : *
1784 : : * Note that we don't need similar processing for ECs whose clause was
1785 : : * considered to be movable into the LHS, because the LHS can't refer to
1786 : : * the RHS so there is no comparable ambiguity about what it might
1787 : : * actually be enforcing internally.
1788 : : */
1789 [ + + ]: 17272 : if (dropped_ecs)
1790 : : {
1791 : : Relids real_outer_and_req;
1792 : :
1793 : 1790 : real_outer_and_req = bms_union(outer_path->parent->relids,
1794 : : required_outer);
1795 : : eclauses =
1796 : 1790 : generate_join_implied_equalities_for_ecs(root,
1797 : : dropped_ecs,
1798 : : real_outer_and_req,
1799 : : required_outer,
1800 : : outer_path->parent);
1801 [ + + + + : 1940 : foreach(lc, eclauses)
+ + ]
1802 : : {
1803 : 150 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1804 : :
1805 [ - + ]: 150 : Assert(join_clause_is_movable_into(rinfo,
1806 : : outer_path->parent->relids,
1807 : : real_outer_and_req));
1808 [ + + ]: 150 : if (!join_clause_is_movable_into(rinfo,
1809 : 150 : outer_path->parent->relids,
1810 : : outer_and_req))
1811 : 135 : pclauses = lappend(pclauses, rinfo);
1812 : : }
1813 : : }
1814 : :
1815 : : /*
1816 : : * Now, attach the identified moved-down clauses to the caller's
1817 : : * restrict_clauses list. By using list_concat in this order, we leave
1818 : : * the original list structure of restrict_clauses undamaged.
1819 : : */
4888 1820 : 17272 : *restrict_clauses = list_concat(pclauses, *restrict_clauses);
1821 : :
1822 : : /* If we already have a PPI for this parameterization, just return it */
2944 rhaas@postgresql.org 1823 [ + + ]: 17272 : if ((ppi = find_param_path_info(joinrel, required_outer)))
1824 : 12695 : return ppi;
1825 : :
1826 : : /* Estimate the number of rows returned by the parameterized join */
4888 tgl@sss.pgh.pa.us 1827 : 4577 : rows = get_parameterized_joinrel_size(root, joinrel,
1828 : : outer_path,
1829 : : inner_path,
1830 : : sjinfo,
1831 : : *restrict_clauses);
1832 : :
1833 : : /*
1834 : : * And now we can build the ParamPathInfo. No point in saving the
1835 : : * input-pair-dependent clause list, though.
1836 : : *
1837 : : * Note: in GEQO mode, we'll be called in a temporary memory context, but
1838 : : * the joinrel structure is there too, so no problem.
1839 : : */
1840 : 4577 : ppi = makeNode(ParamPathInfo);
1841 : 4577 : ppi->ppi_req_outer = required_outer;
1842 : 4577 : ppi->ppi_rows = rows;
1843 : 4577 : ppi->ppi_clauses = NIL;
950 1844 : 4577 : ppi->ppi_serials = NULL;
4888 1845 : 4577 : joinrel->ppilist = lappend(joinrel->ppilist, ppi);
1846 : :
1847 : 4577 : return ppi;
1848 : : }
1849 : :
1850 : : /*
1851 : : * get_appendrel_parampathinfo
1852 : : * Get the ParamPathInfo for a parameterized path for an append relation.
1853 : : *
1854 : : * For an append relation, the rowcount estimate will just be the sum of
1855 : : * the estimates for its children. However, we still need a ParamPathInfo
1856 : : * to flag the fact that the path requires parameters. So this just creates
1857 : : * a suitable struct with zero ppi_rows (and no ppi_clauses either, since
1858 : : * the Append node isn't responsible for checking quals).
1859 : : */
1860 : : ParamPathInfo *
1861 : 19226 : get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer)
1862 : : {
1863 : : ParamPathInfo *ppi;
1864 : :
1865 : : /* If rel has LATERAL refs, every path for it should account for them */
2403 1866 [ - + ]: 19226 : Assert(bms_is_subset(appendrel->lateral_relids, required_outer));
1867 : :
1868 : : /* Unparameterized paths have no ParamPathInfo */
4888 1869 [ + + ]: 19226 : if (bms_is_empty(required_outer))
1870 : 18942 : return NULL;
1871 : :
1872 [ - + ]: 284 : Assert(!bms_overlap(appendrel->relids, required_outer));
1873 : :
1874 : : /* If we already have a PPI for this parameterization, just return it */
2944 rhaas@postgresql.org 1875 [ + + ]: 284 : if ((ppi = find_param_path_info(appendrel, required_outer)))
1876 : 66 : return ppi;
1877 : :
1878 : : /* Else build the ParamPathInfo */
4888 tgl@sss.pgh.pa.us 1879 : 218 : ppi = makeNode(ParamPathInfo);
1880 : 218 : ppi->ppi_req_outer = required_outer;
1881 : 218 : ppi->ppi_rows = 0;
1882 : 218 : ppi->ppi_clauses = NIL;
950 1883 : 218 : ppi->ppi_serials = NULL;
4888 1884 : 218 : appendrel->ppilist = lappend(appendrel->ppilist, ppi);
1885 : :
1886 : 218 : return ppi;
1887 : : }
1888 : :
1889 : : /*
1890 : : * Returns a ParamPathInfo for the parameterization given by required_outer, if
1891 : : * already available in the given rel. Returns NULL otherwise.
1892 : : */
1893 : : ParamPathInfo *
2944 rhaas@postgresql.org 1894 : 171933 : find_param_path_info(RelOptInfo *rel, Relids required_outer)
1895 : : {
1896 : : ListCell *lc;
1897 : :
1898 [ + + + + : 199279 : foreach(lc, rel->ppilist)
+ + ]
1899 : : {
1900 : 121963 : ParamPathInfo *ppi = (ParamPathInfo *) lfirst(lc);
1901 : :
1902 [ + + ]: 121963 : if (bms_equal(ppi->ppi_req_outer, required_outer))
1903 : 94617 : return ppi;
1904 : : }
1905 : :
1906 : 77316 : return NULL;
1907 : : }
1908 : :
1909 : : /*
1910 : : * get_param_path_clause_serials
1911 : : * Given a parameterized Path, return the set of pushed-down clauses
1912 : : * (identified by rinfo_serial numbers) enforced within the Path.
1913 : : */
1914 : : Bitmapset *
950 tgl@sss.pgh.pa.us 1915 : 200554 : get_param_path_clause_serials(Path *path)
1916 : : {
1917 [ + + ]: 200554 : if (path->param_info == NULL)
1918 : 956 : return NULL; /* not parameterized */
1919 : :
1920 : : /*
1921 : : * We don't currently support parameterized MergeAppend paths, as
1922 : : * explained in the comments for generate_orderedappend_paths.
1923 : : */
284 rguo@postgresql.org 1924 [ - + ]: 199598 : Assert(!IsA(path, MergeAppendPath));
1925 : :
950 tgl@sss.pgh.pa.us 1926 [ + + ]: 199598 : if (IsA(path, NestPath) ||
1927 [ + + ]: 195215 : IsA(path, MergePath) ||
1928 [ + + ]: 195212 : IsA(path, HashPath))
1929 : : {
1930 : : /*
1931 : : * For a join path, combine clauses enforced within either input path
1932 : : * with those enforced as joinrestrictinfo in this path. Note that
1933 : : * joinrestrictinfo may include some non-pushed-down clauses, but for
1934 : : * current purposes it's okay if we include those in the result. (To
1935 : : * be more careful, we could check for clause_relids overlapping the
1936 : : * path parameterization, but it's not worth the cycles for now.)
1937 : : */
1938 : 4800 : JoinPath *jpath = (JoinPath *) path;
1939 : : Bitmapset *pserials;
1940 : : ListCell *lc;
1941 : :
1942 : 4800 : pserials = NULL;
1943 : 4800 : pserials = bms_add_members(pserials,
1944 : 4800 : get_param_path_clause_serials(jpath->outerjoinpath));
1945 : 4800 : pserials = bms_add_members(pserials,
1946 : 4800 : get_param_path_clause_serials(jpath->innerjoinpath));
1947 [ + + + + : 5740 : foreach(lc, jpath->joinrestrictinfo)
+ + ]
1948 : : {
1949 : 940 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1950 : :
1951 : 940 : pserials = bms_add_member(pserials, rinfo->rinfo_serial);
1952 : : }
1953 : 4800 : return pserials;
1954 : : }
1955 [ + + ]: 194798 : else if (IsA(path, AppendPath))
1956 : : {
1957 : : /*
1958 : : * For an appendrel, take the intersection of the sets of clauses
1959 : : * enforced in each input path.
1960 : : */
1961 : 1174 : AppendPath *apath = (AppendPath *) path;
1962 : : Bitmapset *pserials;
1963 : : ListCell *lc;
1964 : :
1965 : 1174 : pserials = NULL;
1966 [ + + + + : 4858 : foreach(lc, apath->subpaths)
+ + ]
1967 : : {
1968 : 3684 : Path *subpath = (Path *) lfirst(lc);
1969 : : Bitmapset *subserials;
1970 : :
1971 : 3684 : subserials = get_param_path_clause_serials(subpath);
1972 [ + + ]: 3684 : if (lc == list_head(apath->subpaths))
1973 : 1162 : pserials = bms_copy(subserials);
1974 : : else
1975 : 2522 : pserials = bms_int_members(pserials, subserials);
1976 : : }
1977 : 1174 : return pserials;
1978 : : }
1979 : : else
1980 : : {
1981 : : /*
1982 : : * Otherwise, it's a baserel path and we can use the
1983 : : * previously-computed set of serial numbers.
1984 : : */
1985 : 193624 : return path->param_info->ppi_serials;
1986 : : }
1987 : : }
1988 : :
1989 : : /*
1990 : : * build_joinrel_partition_info
1991 : : * Checks if the two relations being joined can use partitionwise join
1992 : : * and if yes, initialize partitioning information of the resulting
1993 : : * partitioned join relation.
1994 : : */
1995 : : static void
1996 : 103828 : build_joinrel_partition_info(PlannerInfo *root,
1997 : : RelOptInfo *joinrel, RelOptInfo *outer_rel,
1998 : : RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo,
1999 : : List *restrictlist)
2000 : : {
2001 : : PartitionScheme part_scheme;
2002 : :
2003 : : /* Nothing to do if partitionwise join technique is disabled. */
2759 peter_e@gmx.net 2004 [ + + ]: 103828 : if (!enable_partitionwise_join)
2005 : : {
2892 rhaas@postgresql.org 2006 [ - + - - : 100279 : Assert(!IS_PARTITIONED_REL(joinrel));
- - - - -
- ]
2007 : 100279 : return;
2008 : : }
2009 : :
2010 : : /*
2011 : : * We can only consider this join as an input to further partitionwise
2012 : : * joins if (a) the input relations are partitioned and have
2013 : : * consider_partitionwise_join=true, (b) the partition schemes match, and
2014 : : * (c) we can identify an equi-join between the partition keys. Note that
2015 : : * if it were possible for have_partkey_equi_join to return different
2016 : : * answers for the same joinrel depending on which join ordering we try
2017 : : * first, this logic would break. That shouldn't happen, though, because
2018 : : * of the way the query planner deduces implied equalities and reorders
2019 : : * the joins. Please see optimizer/README for details.
2020 : : */
1977 efujita@postgresql.o 2021 [ + + + + ]: 3549 : if (outer_rel->part_scheme == NULL || inner_rel->part_scheme == NULL ||
2563 2022 [ + + ]: 1159 : !outer_rel->consider_partitionwise_join ||
2023 [ + + ]: 1137 : !inner_rel->consider_partitionwise_join ||
2892 rhaas@postgresql.org 2024 [ + + ]: 1119 : outer_rel->part_scheme != inner_rel->part_scheme ||
950 tgl@sss.pgh.pa.us 2025 [ + + ]: 1107 : !have_partkey_equi_join(root, joinrel, outer_rel, inner_rel,
2026 : : sjinfo->jointype, restrictlist))
2027 : : {
2892 rhaas@postgresql.org 2028 [ - + - - : 2526 : Assert(!IS_PARTITIONED_REL(joinrel));
- - - - -
- ]
2029 : 2526 : return;
2030 : : }
2031 : :
2032 : 1023 : part_scheme = outer_rel->part_scheme;
2033 : :
2034 : : /*
2035 : : * This function will be called only once for each joinrel, hence it
2036 : : * should not have partitioning fields filled yet.
2037 : : */
2038 [ + - + - : 1023 : Assert(!joinrel->part_scheme && !joinrel->partexprs &&
+ - + - -
+ ]
2039 : : !joinrel->nullable_partexprs && !joinrel->part_rels &&
2040 : : !joinrel->boundinfo);
2041 : :
2042 : : /*
2043 : : * If the join relation is partitioned, it uses the same partitioning
2044 : : * scheme as the joining relations.
2045 : : *
2046 : : * Note: we calculate the partition bounds, number of partitions, and
2047 : : * child-join relations of the join relation in try_partitionwise_join().
2048 : : */
2049 : 1023 : joinrel->part_scheme = part_scheme;
950 tgl@sss.pgh.pa.us 2050 : 1023 : set_joinrel_partition_key_exprs(joinrel, outer_rel, inner_rel,
2051 : : sjinfo->jointype);
2052 : :
2053 : : /*
2054 : : * Set the consider_partitionwise_join flag.
2055 : : */
2563 efujita@postgresql.o 2056 [ - + ]: 1023 : Assert(outer_rel->consider_partitionwise_join);
2057 [ - + ]: 1023 : Assert(inner_rel->consider_partitionwise_join);
2058 : 1023 : joinrel->consider_partitionwise_join = true;
2059 : : }
2060 : :
2061 : : /*
2062 : : * have_partkey_equi_join
2063 : : *
2064 : : * Returns true if there exist equi-join conditions involving pairs
2065 : : * of matching partition keys of the relations being joined for all
2066 : : * partition keys.
2067 : : */
2068 : : static bool
950 tgl@sss.pgh.pa.us 2069 : 1107 : have_partkey_equi_join(PlannerInfo *root, RelOptInfo *joinrel,
2070 : : RelOptInfo *rel1, RelOptInfo *rel2,
2071 : : JoinType jointype, List *restrictlist)
2072 : : {
1982 2073 : 1107 : PartitionScheme part_scheme = rel1->part_scheme;
2074 : : bool pk_known_equal[PARTITION_MAX_KEYS];
2075 : : int num_equal_pks;
2076 : : ListCell *lc;
2077 : :
2078 : : /*
2079 : : * This function must only be called when the joined relations have same
2080 : : * partitioning scheme.
2081 : : */
2082 [ - + ]: 1107 : Assert(rel1->part_scheme == rel2->part_scheme);
2083 [ - + ]: 1107 : Assert(part_scheme);
2084 : :
2085 : : /* We use a bool array to track which partkey columns are known equal */
403 rguo@postgresql.org 2086 : 1107 : memset(pk_known_equal, 0, sizeof(pk_known_equal));
2087 : : /* ... as well as a count of how many are known equal */
2088 : 1107 : num_equal_pks = 0;
2089 : :
2090 : : /* First, look through the join's restriction clauses */
1982 tgl@sss.pgh.pa.us 2091 [ + + + + : 1716 : foreach(lc, restrictlist)
+ + ]
2092 : : {
2093 : 1611 : RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
2094 : : OpExpr *opexpr;
2095 : : Expr *expr1;
2096 : : Expr *expr2;
2097 : : bool strict_op;
2098 : : int ipk1;
2099 : : int ipk2;
2100 : :
2101 : : /* If processing an outer join, only use its own join clauses. */
2102 [ + + ]: 1611 : if (IS_OUTER_JOIN(jointype) &&
2103 [ + + - + ]: 829 : RINFO_IS_PUSHED_DOWN(rinfo, joinrel->relids))
2104 : 123 : continue;
2105 : :
2106 : : /* Skip clauses which can not be used for a join. */
2107 [ + + ]: 1488 : if (!rinfo->can_join)
2108 : 9 : continue;
2109 : :
2110 : : /* Skip clauses which are not equality conditions. */
2111 [ + + + - ]: 1479 : if (!rinfo->mergeopfamilies && !OidIsValid(rinfo->hashjoinoperator))
2112 : 3 : continue;
2113 : :
2114 : : /* Should be OK to assume it's an OpExpr. */
2115 : 1476 : opexpr = castNode(OpExpr, rinfo->clause);
2116 : :
2117 : : /* Match the operands to the relation. */
2118 [ + + + - ]: 2877 : if (bms_is_subset(rinfo->left_relids, rel1->relids) &&
2119 : 1401 : bms_is_subset(rinfo->right_relids, rel2->relids))
2120 : : {
2121 : 1401 : expr1 = linitial(opexpr->args);
2122 : 1401 : expr2 = lsecond(opexpr->args);
2123 : : }
2124 [ + - + - ]: 150 : else if (bms_is_subset(rinfo->left_relids, rel2->relids) &&
2125 : 75 : bms_is_subset(rinfo->right_relids, rel1->relids))
2126 : : {
2127 : 75 : expr1 = lsecond(opexpr->args);
2128 : 75 : expr2 = linitial(opexpr->args);
2129 : : }
2130 : : else
1982 tgl@sss.pgh.pa.us 2131 :UBC 0 : continue;
2132 : :
2133 : : /*
2134 : : * Now we need to know whether the join operator is strict; see
2135 : : * comments in pathnodes.h.
2136 : : */
1982 tgl@sss.pgh.pa.us 2137 :CBC 1476 : strict_op = op_strict(opexpr->opno);
2138 : :
2139 : : /*
2140 : : * Vars appearing in the relation's partition keys will not have any
2141 : : * varnullingrels, but those in expr1 and expr2 will if we're above
2142 : : * outer joins that could null the respective rels. It's okay to
2143 : : * match anyway, if the join operator is strict.
2144 : : */
950 2145 [ + - ]: 1476 : if (strict_op)
2146 : : {
2147 [ + + ]: 1476 : if (bms_overlap(rel1->relids, root->outer_join_rels))
2148 : 90 : expr1 = (Expr *) remove_nulling_relids((Node *) expr1,
2149 : 90 : root->outer_join_rels,
2150 : : NULL);
2151 [ - + ]: 1476 : if (bms_overlap(rel2->relids, root->outer_join_rels))
950 tgl@sss.pgh.pa.us 2152 :UBC 0 : expr2 = (Expr *) remove_nulling_relids((Node *) expr2,
2153 : 0 : root->outer_join_rels,
2154 : : NULL);
2155 : : }
2156 : :
2157 : : /*
2158 : : * Only clauses referencing the partition keys are useful for
2159 : : * partitionwise join.
2160 : : */
1982 tgl@sss.pgh.pa.us 2161 :CBC 1476 : ipk1 = match_expr_to_partition_keys(expr1, rel1, strict_op);
2162 [ + + ]: 1476 : if (ipk1 < 0)
2163 : 438 : continue;
2164 : 1038 : ipk2 = match_expr_to_partition_keys(expr2, rel2, strict_op);
2165 [ + + ]: 1038 : if (ipk2 < 0)
2166 : 24 : continue;
2167 : :
2168 : : /*
2169 : : * If the clause refers to keys at different ordinal positions, it can
2170 : : * not be used for partitionwise join.
2171 : : */
2172 [ + + ]: 1014 : if (ipk1 != ipk2)
2173 : 3 : continue;
2174 : :
2175 : : /* Ignore clause if we already proved these keys equal. */
403 rguo@postgresql.org 2176 [ - + ]: 1011 : if (pk_known_equal[ipk1])
403 rguo@postgresql.org 2177 :UBC 0 : continue;
2178 : :
2179 : : /* Reject if the partition key collation differs from the clause's. */
302 amitlan@postgresql.o 2180 [ + + ]:CBC 1011 : if (rel1->part_scheme->partcollation[ipk1] != opexpr->inputcollid)
2181 : 1002 : return false;
2182 : :
2183 : : /*
2184 : : * The clause allows partitionwise join only if it uses the same
2185 : : * operator family as that specified by the partition key.
2186 : : */
403 rguo@postgresql.org 2187 [ + + ]: 1005 : if (part_scheme->strategy == PARTITION_STRATEGY_HASH)
2188 : : {
1982 tgl@sss.pgh.pa.us 2189 [ + - ]: 36 : if (!OidIsValid(rinfo->hashjoinoperator) ||
2190 [ - + ]: 36 : !op_in_opfamily(rinfo->hashjoinoperator,
2191 : 36 : part_scheme->partopfamily[ipk1]))
1982 tgl@sss.pgh.pa.us 2192 :UBC 0 : continue;
2193 : : }
1982 tgl@sss.pgh.pa.us 2194 [ - + ]:CBC 969 : else if (!list_member_oid(rinfo->mergeopfamilies,
2195 : 969 : part_scheme->partopfamily[ipk1]))
1982 tgl@sss.pgh.pa.us 2196 :UBC 0 : continue;
2197 : :
2198 : : /* Mark the partition key as having an equi-join clause. */
403 rguo@postgresql.org 2199 :CBC 1005 : pk_known_equal[ipk1] = true;
2200 : :
2201 : : /* We can stop examining clauses once we prove all keys equal. */
2202 [ + + ]: 1005 : if (++num_equal_pks == part_scheme->partnatts)
2203 : 996 : return true;
2204 : : }
2205 : :
2206 : : /*
2207 : : * Also check to see if any keys are known equal by equivclass.c. In most
2208 : : * cases there would have been a join restriction clause generated from
2209 : : * any EC that had such knowledge, but there might be no such clause, or
2210 : : * it might happen to constrain other members of the ECs than the ones we
2211 : : * are looking for.
2212 : : */
2213 [ + - ]: 108 : for (int ipk = 0; ipk < part_scheme->partnatts; ipk++)
2214 : : {
2215 : : Oid btree_opfamily;
2216 : :
2217 : : /* Ignore if we already proved these keys equal. */
2218 [ + + ]: 108 : if (pk_known_equal[ipk])
2219 : 3 : continue;
2220 : :
2221 : : /*
2222 : : * We need a btree opfamily to ask equivclass.c about. If the
2223 : : * partopfamily is a hash opfamily, look up its equality operator, and
2224 : : * select some btree opfamily that that operator is part of. (Any
2225 : : * such opfamily should be good enough, since equivclass.c will track
2226 : : * multiple opfamilies as appropriate.)
2227 : : */
2228 [ - + ]: 105 : if (part_scheme->strategy == PARTITION_STRATEGY_HASH)
2229 : : {
2230 : : Oid eq_op;
2231 : : List *eq_opfamilies;
2232 : :
403 rguo@postgresql.org 2233 :UBC 0 : eq_op = get_opfamily_member(part_scheme->partopfamily[ipk],
2234 : 0 : part_scheme->partopcintype[ipk],
2235 : 0 : part_scheme->partopcintype[ipk],
2236 : : HTEqualStrategyNumber);
2237 [ # # ]: 0 : if (!OidIsValid(eq_op))
2238 : 0 : break; /* we're not going to succeed */
2239 : 0 : eq_opfamilies = get_mergejoin_opfamilies(eq_op);
2240 [ # # ]: 0 : if (eq_opfamilies == NIL)
2241 : 0 : break; /* we're not going to succeed */
2242 : 0 : btree_opfamily = linitial_oid(eq_opfamilies);
2243 : : }
2244 : : else
403 rguo@postgresql.org 2245 :CBC 105 : btree_opfamily = part_scheme->partopfamily[ipk];
2246 : :
2247 : : /*
2248 : : * We consider only non-nullable partition keys here; nullable ones
2249 : : * would not be treated as part of the same equivalence classes as
2250 : : * non-nullable ones.
2251 : : */
2252 [ + - + + : 183 : foreach(lc, rel1->partexprs[ipk])
+ + ]
2253 : : {
2254 : 105 : Node *expr1 = (Node *) lfirst(lc);
2255 : : ListCell *lc2;
302 amitlan@postgresql.o 2256 : 105 : Oid partcoll1 = rel1->part_scheme->partcollation[ipk];
2257 : 105 : Oid exprcoll1 = exprCollation(expr1);
2258 : :
403 rguo@postgresql.org 2259 [ + - + + : 189 : foreach(lc2, rel2->partexprs[ipk])
+ + ]
2260 : : {
2261 : 111 : Node *expr2 = (Node *) lfirst(lc2);
2262 : :
2263 [ + + ]: 111 : if (exprs_known_equal(root, expr1, expr2, btree_opfamily))
2264 : : {
2265 : : /*
2266 : : * Ensure that the collation of the expression matches
2267 : : * that of the partition key. Checking just one collation
2268 : : * (partcoll1 and exprcoll1) suffices because partcoll1
2269 : : * and partcoll2, as well as exprcoll1 and exprcoll2,
2270 : : * should be identical. This holds because both rel1 and
2271 : : * rel2 use the same PartitionScheme and expr1 and expr2
2272 : : * are equal.
2273 : : */
302 amitlan@postgresql.o 2274 [ + + ]: 33 : if (partcoll1 == exprcoll1)
2275 : : {
2276 : 27 : Oid partcoll2 PG_USED_FOR_ASSERTS_ONLY =
2277 : 27 : rel2->part_scheme->partcollation[ipk];
2278 : : Oid exprcoll2 PG_USED_FOR_ASSERTS_ONLY =
2279 : 27 : exprCollation(expr2);
2280 : :
2281 [ - + ]: 27 : Assert(partcoll2 == exprcoll2);
2282 : 27 : pk_known_equal[ipk] = true;
2283 : 27 : break;
2284 : : }
2285 : : }
2286 : : }
403 rguo@postgresql.org 2287 [ + + ]: 105 : if (pk_known_equal[ipk])
2288 : 27 : break;
2289 : : }
2290 : :
2291 [ + + ]: 105 : if (pk_known_equal[ipk])
2292 : : {
2293 : : /* We can stop examining keys once we prove all keys equal. */
2294 [ + - ]: 27 : if (++num_equal_pks == part_scheme->partnatts)
2295 : 27 : return true;
2296 : : }
2297 : : else
2298 : 78 : break; /* no chance to succeed, give up */
2299 : : }
2300 : :
2301 : 78 : return false;
2302 : : }
2303 : :
2304 : : /*
2305 : : * match_expr_to_partition_keys
2306 : : *
2307 : : * Tries to match an expression to one of the nullable or non-nullable
2308 : : * partition keys of "rel". Returns the matched key's ordinal position,
2309 : : * or -1 if the expression could not be matched to any of the keys.
2310 : : *
2311 : : * strict_op must be true if the expression will be compared with the
2312 : : * partition key using a strict operator. This allows us to consider
2313 : : * nullable as well as nonnullable partition keys.
2314 : : */
2315 : : static int
1982 tgl@sss.pgh.pa.us 2316 : 2514 : match_expr_to_partition_keys(Expr *expr, RelOptInfo *rel, bool strict_op)
2317 : : {
2318 : : int cnt;
2319 : :
2320 : : /* This function should be called only for partitioned relations. */
2321 [ - + ]: 2514 : Assert(rel->part_scheme);
2322 [ - + ]: 2514 : Assert(rel->partexprs);
2323 [ - + ]: 2514 : Assert(rel->nullable_partexprs);
2324 : :
2325 : : /* Remove any relabel decorations. */
2326 [ + + ]: 2658 : while (IsA(expr, RelabelType))
2327 : 144 : expr = (Expr *) (castNode(RelabelType, expr))->arg;
2328 : :
2329 [ + + ]: 2994 : for (cnt = 0; cnt < rel->part_scheme->partnatts; cnt++)
2330 : : {
2331 : : ListCell *lc;
2332 : :
2333 : : /* We can always match to the non-nullable partition keys. */
2334 [ + + + + : 3030 : foreach(lc, rel->partexprs[cnt])
+ + ]
2335 : : {
2336 [ + + ]: 2508 : if (equal(lfirst(lc), expr))
2337 : 2010 : return cnt;
2338 : : }
2339 : :
2340 [ - + ]: 522 : if (!strict_op)
1982 tgl@sss.pgh.pa.us 2341 :UBC 0 : continue;
2342 : :
2343 : : /*
2344 : : * If it's a strict join operator then a NULL partition key on one
2345 : : * side will not join to any partition key on the other side, and in
2346 : : * particular such a row can't join to a row from a different
2347 : : * partition on the other side. So, it's okay to search the nullable
2348 : : * partition keys as well.
2349 : : */
1982 tgl@sss.pgh.pa.us 2350 [ + + + + :CBC 594 : foreach(lc, rel->nullable_partexprs[cnt])
+ + ]
2351 : : {
2352 [ + + ]: 114 : if (equal(lfirst(lc), expr))
2353 : 42 : return cnt;
2354 : : }
2355 : : }
2356 : :
2357 : 462 : return -1;
2358 : : }
2359 : :
2360 : : /*
2361 : : * set_joinrel_partition_key_exprs
2362 : : * Initialize partition key expressions for a partitioned joinrel.
2363 : : */
2364 : : static void
2365 : 1023 : set_joinrel_partition_key_exprs(RelOptInfo *joinrel,
2366 : : RelOptInfo *outer_rel, RelOptInfo *inner_rel,
2367 : : JoinType jointype)
2368 : : {
1978 2369 : 1023 : PartitionScheme part_scheme = joinrel->part_scheme;
2370 : 1023 : int partnatts = part_scheme->partnatts;
2371 : :
1982 2372 : 1023 : joinrel->partexprs = (List **) palloc0(sizeof(List *) * partnatts);
2373 : 1023 : joinrel->nullable_partexprs =
2374 : 1023 : (List **) palloc0(sizeof(List *) * partnatts);
2375 : :
2376 : : /*
2377 : : * The joinrel's partition expressions are the same as those of the input
2378 : : * rels, but we must properly classify them as nullable or not in the
2379 : : * joinrel's output. (Also, we add some more partition expressions if
2380 : : * it's a FULL JOIN.)
2381 : : */
2382 [ + + ]: 2052 : for (int cnt = 0; cnt < partnatts; cnt++)
2383 : : {
2384 : : /* mark these const to enforce that we copy them properly */
2217 2385 : 1029 : const List *outer_expr = outer_rel->partexprs[cnt];
2386 : 1029 : const List *outer_null_expr = outer_rel->nullable_partexprs[cnt];
2387 : 1029 : const List *inner_expr = inner_rel->partexprs[cnt];
2388 : 1029 : const List *inner_null_expr = inner_rel->nullable_partexprs[cnt];
2892 rhaas@postgresql.org 2389 : 1029 : List *partexpr = NIL;
2390 : 1029 : List *nullable_partexpr = NIL;
2391 : : ListCell *lc;
2392 : :
2393 [ + + + + : 1029 : switch (jointype)
- ]
2394 : : {
2395 : : /*
2396 : : * A join relation resulting from an INNER join may be
2397 : : * regarded as partitioned by either of the inner and outer
2398 : : * relation keys. For example, A INNER JOIN B ON A.a = B.b
2399 : : * can be regarded as partitioned on either A.a or B.b. So we
2400 : : * add both keys to the joinrel's partexpr lists. However,
2401 : : * anything that was already nullable still has to be treated
2402 : : * as nullable.
2403 : : */
2404 : 440 : case JOIN_INNER:
2217 tgl@sss.pgh.pa.us 2405 : 440 : partexpr = list_concat_copy(outer_expr, inner_expr);
2406 : 440 : nullable_partexpr = list_concat_copy(outer_null_expr,
2407 : : inner_null_expr);
2892 rhaas@postgresql.org 2408 : 440 : break;
2409 : :
2410 : : /*
2411 : : * A join relation resulting from a SEMI or ANTI join may be
2412 : : * regarded as partitioned by the outer relation keys. The
2413 : : * inner relation's keys are no longer interesting; since they
2414 : : * aren't visible in the join output, nothing could join to
2415 : : * them.
2416 : : */
2417 : 156 : case JOIN_SEMI:
2418 : : case JOIN_ANTI:
2217 tgl@sss.pgh.pa.us 2419 : 156 : partexpr = list_copy(outer_expr);
2420 : 156 : nullable_partexpr = list_copy(outer_null_expr);
2892 rhaas@postgresql.org 2421 : 156 : break;
2422 : :
2423 : : /*
2424 : : * A join relation resulting from a LEFT OUTER JOIN likewise
2425 : : * may be regarded as partitioned on the (non-nullable) outer
2426 : : * relation keys. The inner (nullable) relation keys are okay
2427 : : * as partition keys for further joins as long as they involve
2428 : : * strict join operators.
2429 : : */
2430 : 290 : case JOIN_LEFT:
2217 tgl@sss.pgh.pa.us 2431 : 290 : partexpr = list_copy(outer_expr);
2432 : 290 : nullable_partexpr = list_concat_copy(inner_expr,
2433 : : outer_null_expr);
2892 rhaas@postgresql.org 2434 : 290 : nullable_partexpr = list_concat(nullable_partexpr,
2435 : : inner_null_expr);
2436 : 290 : break;
2437 : :
2438 : : /*
2439 : : * For FULL OUTER JOINs, both relations are nullable, so the
2440 : : * resulting join relation may be regarded as partitioned on
2441 : : * either of inner and outer relation keys, but only for joins
2442 : : * that involve strict join operators.
2443 : : */
2444 : 143 : case JOIN_FULL:
2217 tgl@sss.pgh.pa.us 2445 : 143 : nullable_partexpr = list_concat_copy(outer_expr,
2446 : : inner_expr);
2892 rhaas@postgresql.org 2447 : 143 : nullable_partexpr = list_concat(nullable_partexpr,
2448 : : outer_null_expr);
2449 : 143 : nullable_partexpr = list_concat(nullable_partexpr,
2450 : : inner_null_expr);
2451 : :
2452 : : /*
2453 : : * Also add CoalesceExprs corresponding to each possible
2454 : : * full-join output variable (that is, left side coalesced to
2455 : : * right side), so that we can match equijoin expressions
2456 : : * using those variables. We really only need these for
2457 : : * columns merged by JOIN USING, and only with the pairs of
2458 : : * input items that correspond to the data structures that
2459 : : * parse analysis would build for such variables. But it's
2460 : : * hard to tell which those are, so just make all the pairs.
2461 : : * Extra items in the nullable_partexprs list won't cause big
2462 : : * problems. (It's possible that such items will get matched
2463 : : * to user-written COALESCEs, but it should still be valid to
2464 : : * partition on those, since they're going to be either the
2465 : : * partition column or NULL; it's the same argument as for
2466 : : * partitionwise nesting of any outer join.) We assume no
2467 : : * type coercions are needed to make the coalesce expressions,
2468 : : * since columns of different types won't have gotten
2469 : : * classified as the same PartitionScheme. Note that we
2470 : : * intentionally leave out the varnullingrels decoration that
2471 : : * would ordinarily appear on the Vars inside these
2472 : : * CoalesceExprs, because have_partkey_equi_join will strip
2473 : : * varnullingrels from the expressions it will compare to the
2474 : : * partexprs.
2475 : : */
1978 tgl@sss.pgh.pa.us 2476 [ + - + + : 364 : foreach(lc, list_concat_copy(outer_expr, outer_null_expr))
+ + ]
2477 : : {
2478 : 221 : Node *larg = (Node *) lfirst(lc);
2479 : : ListCell *lc2;
2480 : :
2481 [ + - + + : 442 : foreach(lc2, list_concat_copy(inner_expr, inner_null_expr))
+ + ]
2482 : : {
2483 : 221 : Node *rarg = (Node *) lfirst(lc2);
2484 : 221 : CoalesceExpr *c = makeNode(CoalesceExpr);
2485 : :
2486 : 221 : c->coalescetype = exprType(larg);
2487 : 221 : c->coalescecollid = exprCollation(larg);
2488 : 221 : c->args = list_make2(larg, rarg);
2489 : 221 : c->location = -1;
2490 : 221 : nullable_partexpr = lappend(nullable_partexpr, c);
2491 : : }
2492 : : }
2892 rhaas@postgresql.org 2493 : 143 : break;
2494 : :
2892 rhaas@postgresql.org 2495 :UBC 0 : default:
2496 [ # # ]: 0 : elog(ERROR, "unrecognized join type: %d", (int) jointype);
2497 : : }
2498 : :
2892 rhaas@postgresql.org 2499 :CBC 1029 : joinrel->partexprs[cnt] = partexpr;
2500 : 1029 : joinrel->nullable_partexprs[cnt] = nullable_partexpr;
2501 : : }
2502 : 1023 : }
2503 : :
2504 : : /*
2505 : : * build_child_join_reltarget
2506 : : * Set up a child-join relation's reltarget from a parent-join relation.
2507 : : */
2508 : : static void
2563 efujita@postgresql.o 2509 : 2507 : build_child_join_reltarget(PlannerInfo *root,
2510 : : RelOptInfo *parentrel,
2511 : : RelOptInfo *childrel,
2512 : : int nappinfos,
2513 : : AppendRelInfo **appinfos)
2514 : : {
2515 : : /* Build the targetlist */
2516 : 5014 : childrel->reltarget->exprs = (List *)
2517 : 2507 : adjust_appendrel_attrs(root,
2518 : 2507 : (Node *) parentrel->reltarget->exprs,
2519 : : nappinfos, appinfos);
2520 : :
2521 : : /* Set the cost and width fields */
2522 : 2507 : childrel->reltarget->cost.startup = parentrel->reltarget->cost.startup;
2523 : 2507 : childrel->reltarget->cost.per_tuple = parentrel->reltarget->cost.per_tuple;
2524 : 2507 : childrel->reltarget->width = parentrel->reltarget->width;
2525 : 2507 : }
|