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