Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * restrictinfo.c
4 : : * RestrictInfo node manipulation routines.
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/optimizer/util/restrictinfo.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres.h"
16 : :
17 : : #include "nodes/makefuncs.h"
18 : : #include "nodes/nodeFuncs.h"
19 : : #include "optimizer/clauses.h"
20 : : #include "optimizer/optimizer.h"
21 : : #include "optimizer/restrictinfo.h"
22 : :
23 : :
24 : : static RestrictInfo *make_restrictinfo_internal(PlannerInfo *root,
25 : : Expr *clause,
26 : : Expr *orclause,
27 : : bool is_pushed_down,
28 : : bool has_clone,
29 : : bool is_clone,
30 : : bool pseudoconstant,
31 : : Index security_level,
32 : : Relids required_relids,
33 : : Relids incompatible_relids,
34 : : Relids outer_relids);
35 : : static Expr *make_sub_restrictinfos(PlannerInfo *root,
36 : : Expr *clause,
37 : : bool is_pushed_down,
38 : : bool has_clone,
39 : : bool is_clone,
40 : : bool pseudoconstant,
41 : : Index security_level,
42 : : Relids required_relids,
43 : : Relids incompatible_relids,
44 : : Relids outer_relids);
45 : :
46 : :
47 : : /*
48 : : * make_restrictinfo
49 : : *
50 : : * Build a RestrictInfo node containing the given subexpression.
51 : : *
52 : : * The is_pushed_down, has_clone, is_clone, and pseudoconstant flags for the
53 : : * RestrictInfo must be supplied by the caller, as well as the correct values
54 : : * for security_level, incompatible_relids, and outer_relids.
55 : : * required_relids can be NULL, in which case it defaults to the actual clause
56 : : * contents (i.e., clause_relids).
57 : : *
58 : : * We initialize fields that depend only on the given subexpression, leaving
59 : : * others that depend on context (or may never be needed at all) to be filled
60 : : * later.
61 : : */
62 : : RestrictInfo *
1179 tgl@sss.pgh.pa.us 63 :CBC 292036 : make_restrictinfo(PlannerInfo *root,
64 : : Expr *clause,
65 : : bool is_pushed_down,
66 : : bool has_clone,
67 : : bool is_clone,
68 : : bool pseudoconstant,
69 : : Index security_level,
70 : : Relids required_relids,
71 : : Relids incompatible_relids,
72 : : Relids outer_relids)
73 : : {
74 : : /*
75 : : * If it's an OR clause, build a modified copy with RestrictInfos inserted
76 : : * above each subclause of the top-level AND/OR structure.
77 : : */
1902 78 [ + + ]: 292036 : if (is_orclause(clause))
1179 79 : 4052 : return (RestrictInfo *) make_sub_restrictinfos(root,
80 : : clause,
81 : : is_pushed_down,
82 : : has_clone,
83 : : is_clone,
84 : : pseudoconstant,
85 : : security_level,
86 : : required_relids,
87 : : incompatible_relids,
88 : : outer_relids);
89 : :
90 : : /* Shouldn't be an AND clause, else AND/OR flattening messed up */
1902 91 [ - + ]: 287984 : Assert(!is_andclause(clause));
92 : :
1179 93 : 287984 : return make_restrictinfo_internal(root,
94 : : clause,
95 : : NULL,
96 : : is_pushed_down,
97 : : has_clone,
98 : : is_clone,
99 : : pseudoconstant,
100 : : security_level,
101 : : required_relids,
102 : : incompatible_relids,
103 : : outer_relids);
104 : : }
105 : :
106 : : /*
107 : : * make_restrictinfo_internal
108 : : *
109 : : * Common code for the main entry points and the recursive cases.
110 : : */
111 : : static RestrictInfo *
112 : 303303 : make_restrictinfo_internal(PlannerInfo *root,
113 : : Expr *clause,
114 : : Expr *orclause,
115 : : bool is_pushed_down,
116 : : bool has_clone,
117 : : bool is_clone,
118 : : bool pseudoconstant,
119 : : Index security_level,
120 : : Relids required_relids,
121 : : Relids incompatible_relids,
122 : : Relids outer_relids)
123 : : {
7406 124 : 303303 : RestrictInfo *restrictinfo = makeNode(RestrictInfo);
125 : : Relids baserels;
126 : :
127 : 303303 : restrictinfo->clause = clause;
7405 128 : 303303 : restrictinfo->orclause = orclause;
129 : 303303 : restrictinfo->is_pushed_down = is_pushed_down;
6497 130 : 303303 : restrictinfo->pseudoconstant = pseudoconstant;
325 131 : 303303 : restrictinfo->has_clone = has_clone;
132 : 303303 : restrictinfo->is_clone = is_clone;
2489 133 : 303303 : restrictinfo->can_join = false; /* may get set below */
2643 134 : 303303 : restrictinfo->security_level = security_level;
325 135 : 303303 : restrictinfo->incompatible_relids = incompatible_relids;
4378 136 : 303303 : restrictinfo->outer_relids = outer_relids;
137 : :
138 : : /*
139 : : * If it's potentially delayable by lower-level security quals, figure out
140 : : * whether it's leakproof. We can skip testing this for level-zero quals,
141 : : * since they would never get delayed on security grounds anyway.
142 : : */
2643 143 [ + + ]: 303303 : if (security_level > 0)
144 : 2167 : restrictinfo->leakproof = !contain_leaked_vars((Node *) clause);
145 : : else
2489 146 : 301136 : restrictinfo->leakproof = false; /* really, "don't know" */
147 : :
148 : : /*
149 : : * Mark volatility as unknown. The contain_volatile_functions function
150 : : * will determine if there are any volatile functions when called for the
151 : : * first time with this RestrictInfo.
152 : : */
1112 drowley@postgresql.o 153 : 303303 : restrictinfo->has_volatile = VOLATILITY_UNKNOWN;
154 : :
155 : : /*
156 : : * If it's a binary opclause, set up left/right relids info. In any case
157 : : * set up the total clause relids info.
158 : : */
7259 neilc@samurai.com 159 [ + + + + ]: 303303 : if (is_opclause(clause) && list_length(((OpExpr *) clause)->args) == 2)
160 : : {
1179 tgl@sss.pgh.pa.us 161 : 253496 : restrictinfo->left_relids = pull_varnos(root, get_leftop(clause));
162 : 253496 : restrictinfo->right_relids = pull_varnos(root, get_rightop(clause));
163 : :
7406 164 : 506992 : restrictinfo->clause_relids = bms_union(restrictinfo->left_relids,
6756 bruce@momjian.us 165 : 253496 : restrictinfo->right_relids);
166 : :
167 : : /*
168 : : * Does it look like a normal join clause, i.e., a binary operator
169 : : * relating expressions that come from distinct relations? If so we
170 : : * might be able to use it in a join algorithm. Note that this is a
171 : : * purely syntactic test that is made regardless of context.
172 : : */
7406 tgl@sss.pgh.pa.us 173 [ + + ]: 253496 : if (!bms_is_empty(restrictinfo->left_relids) &&
174 [ + + ]: 248907 : !bms_is_empty(restrictinfo->right_relids) &&
175 [ + + ]: 89422 : !bms_overlap(restrictinfo->left_relids,
176 : 89422 : restrictinfo->right_relids))
177 : : {
7405 178 : 88427 : restrictinfo->can_join = true;
179 : : /* pseudoconstant should certainly not be true */
6497 180 [ - + ]: 88427 : Assert(!restrictinfo->pseudoconstant);
181 : : }
182 : : }
183 : : else
184 : : {
185 : : /* Not a binary opclause, so mark left/right relid sets as empty */
7406 186 : 49807 : restrictinfo->left_relids = NULL;
187 : 49807 : restrictinfo->right_relids = NULL;
188 : : /* and get the total relid set the hard way */
1179 189 : 49807 : restrictinfo->clause_relids = pull_varnos(root, (Node *) clause);
190 : : }
191 : :
192 : : /* required_relids defaults to clause_relids */
6884 193 [ + + ]: 303303 : if (required_relids != NULL)
194 : 273886 : restrictinfo->required_relids = required_relids;
195 : : else
196 : 29417 : restrictinfo->required_relids = restrictinfo->clause_relids;
197 : :
198 : : /*
199 : : * Count the number of base rels appearing in clause_relids. To do this,
200 : : * we just delete rels mentioned in root->outer_join_rels and count the
201 : : * survivors. Because we are called during deconstruct_jointree which is
202 : : * the same tree walk that populates outer_join_rels, this is a little bit
203 : : * unsafe-looking; but it should be fine because the recursion in
204 : : * deconstruct_jointree should already have visited any outer join that
205 : : * could be mentioned in this clause.
206 : : */
440 207 : 303303 : baserels = bms_difference(restrictinfo->clause_relids,
208 : 303303 : root->outer_join_rels);
209 : 303303 : restrictinfo->num_base_rels = bms_num_members(baserels);
210 : 303303 : bms_free(baserels);
211 : :
212 : : /*
213 : : * Label this RestrictInfo with a fresh serial number.
214 : : */
215 : 303303 : restrictinfo->rinfo_serial = ++(root->last_rinfo_serial);
216 : :
217 : : /*
218 : : * Fill in all the cacheable fields with "not yet set" markers. None of
219 : : * these will be computed until/unless needed. Note in particular that we
220 : : * don't mark a binary opclause as mergejoinable or hashjoinable here;
221 : : * that happens only if it appears in the right context (top level of a
222 : : * joinclause list).
223 : : */
6294 224 : 303303 : restrictinfo->parent_ec = NULL;
225 : :
7406 226 : 303303 : restrictinfo->eval_cost.startup = -1;
5546 227 : 303303 : restrictinfo->norm_selec = -1;
228 : 303303 : restrictinfo->outer_selec = -1;
229 : :
6294 230 : 303303 : restrictinfo->mergeopfamilies = NIL;
231 : :
232 : 303303 : restrictinfo->left_ec = NULL;
233 : 303303 : restrictinfo->right_ec = NULL;
6292 234 : 303303 : restrictinfo->left_em = NULL;
235 : 303303 : restrictinfo->right_em = NULL;
236 : 303303 : restrictinfo->scansel_cache = NIL;
237 : :
6294 238 : 303303 : restrictinfo->outer_is_left = false;
239 : :
7406 240 : 303303 : restrictinfo->hashjoinoperator = InvalidOid;
241 : :
242 : 303303 : restrictinfo->left_bucketsize = -1;
243 : 303303 : restrictinfo->right_bucketsize = -1;
2434 244 : 303303 : restrictinfo->left_mcvfreq = -1;
245 : 303303 : restrictinfo->right_mcvfreq = -1;
246 : :
888 drowley@postgresql.o 247 : 303303 : restrictinfo->left_hasheqoperator = InvalidOid;
248 : 303303 : restrictinfo->right_hasheqoperator = InvalidOid;
249 : :
7406 tgl@sss.pgh.pa.us 250 : 303303 : return restrictinfo;
251 : : }
252 : :
253 : : /*
254 : : * Recursively insert sub-RestrictInfo nodes into a boolean expression.
255 : : *
256 : : * We put RestrictInfos above simple (non-AND/OR) clauses and above
257 : : * sub-OR clauses, but not above sub-AND clauses, because there's no need.
258 : : * This may seem odd but it is closely related to the fact that we use
259 : : * implicit-AND lists at top level of RestrictInfo lists. Only ORs and
260 : : * simple clauses are valid RestrictInfos.
261 : : *
262 : : * The same is_pushed_down, has_clone, is_clone, and pseudoconstant flag
263 : : * values can be applied to all RestrictInfo nodes in the result. Likewise
264 : : * for security_level, incompatible_relids, and outer_relids.
265 : : *
266 : : * The given required_relids are attached to our top-level output,
267 : : * but any OR-clause constituents are allowed to default to just the
268 : : * contained rels.
269 : : */
270 : : static Expr *
1179 271 : 16760 : make_sub_restrictinfos(PlannerInfo *root,
272 : : Expr *clause,
273 : : bool is_pushed_down,
274 : : bool has_clone,
275 : : bool is_clone,
276 : : bool pseudoconstant,
277 : : Index security_level,
278 : : Relids required_relids,
279 : : Relids incompatible_relids,
280 : : Relids outer_relids)
281 : : {
1902 282 [ + + ]: 16760 : if (is_orclause(clause))
283 : : {
7406 284 : 4091 : List *orlist = NIL;
285 : : ListCell *temp;
286 : :
287 [ + - + + : 13637 : foreach(temp, ((BoolExpr *) clause)->args)
+ + ]
288 : 9546 : orlist = lappend(orlist,
1179 289 : 9546 : make_sub_restrictinfos(root,
290 : 9546 : lfirst(temp),
291 : : is_pushed_down,
292 : : has_clone,
293 : : is_clone,
294 : : pseudoconstant,
295 : : security_level,
296 : : NULL,
297 : : incompatible_relids,
298 : : outer_relids));
299 : 4091 : return (Expr *) make_restrictinfo_internal(root,
300 : : clause,
301 : : make_orclause(orlist),
302 : : is_pushed_down,
303 : : has_clone,
304 : : is_clone,
305 : : pseudoconstant,
306 : : security_level,
307 : : required_relids,
308 : : incompatible_relids,
309 : : outer_relids);
310 : : }
1902 311 [ + + ]: 12669 : else if (is_andclause(clause))
312 : : {
7406 313 : 1441 : List *andlist = NIL;
314 : : ListCell *temp;
315 : :
316 [ + - + + : 4603 : foreach(temp, ((BoolExpr *) clause)->args)
+ + ]
317 : 3162 : andlist = lappend(andlist,
1179 318 : 3162 : make_sub_restrictinfos(root,
319 : 3162 : lfirst(temp),
320 : : is_pushed_down,
321 : : has_clone,
322 : : is_clone,
323 : : pseudoconstant,
324 : : security_level,
325 : : required_relids,
326 : : incompatible_relids,
327 : : outer_relids));
7406 328 : 1441 : return make_andclause(andlist);
329 : : }
330 : : else
1179 331 : 11228 : return (Expr *) make_restrictinfo_internal(root,
332 : : clause,
333 : : NULL,
334 : : is_pushed_down,
335 : : has_clone,
336 : : is_clone,
337 : : pseudoconstant,
338 : : security_level,
339 : : required_relids,
340 : : incompatible_relids,
341 : : outer_relids);
342 : : }
343 : :
344 : : /*
345 : : * commute_restrictinfo
346 : : *
347 : : * Given a RestrictInfo containing a binary opclause, produce a RestrictInfo
348 : : * representing the commutation of that clause. The caller must pass the
349 : : * OID of the commutator operator (which it's presumably looked up, else
350 : : * it would not know this is valid).
351 : : *
352 : : * Beware that the result shares sub-structure with the given RestrictInfo.
353 : : * That's okay for the intended usage with derived index quals, but might
354 : : * be hazardous if the source is subject to change. Also notice that we
355 : : * assume without checking that the commutator op is a member of the same
356 : : * btree and hash opclasses as the original op.
357 : : */
358 : : RestrictInfo *
1891 359 : 26574 : commute_restrictinfo(RestrictInfo *rinfo, Oid comm_op)
360 : : {
361 : : RestrictInfo *result;
362 : : OpExpr *newclause;
363 : 26574 : OpExpr *clause = castNode(OpExpr, rinfo->clause);
364 : :
365 [ - + ]: 26574 : Assert(list_length(clause->args) == 2);
366 : :
367 : : /* flat-copy all the fields of clause ... */
368 : 26574 : newclause = makeNode(OpExpr);
369 : 26574 : memcpy(newclause, clause, sizeof(OpExpr));
370 : :
371 : : /* ... and adjust those we need to change to commute it */
372 : 26574 : newclause->opno = comm_op;
373 : 26574 : newclause->opfuncid = InvalidOid;
374 : 26574 : newclause->args = list_make2(lsecond(clause->args),
375 : : linitial(clause->args));
376 : :
377 : : /* likewise, flat-copy all the fields of rinfo ... */
378 : 26574 : result = makeNode(RestrictInfo);
379 : 26574 : memcpy(result, rinfo, sizeof(RestrictInfo));
380 : :
381 : : /*
382 : : * ... and adjust those we need to change. Note in particular that we can
383 : : * preserve any cached selectivity or cost estimates, since those ought to
384 : : * be the same for the new clause. Likewise we can keep the source's
385 : : * parent_ec. It's also important that we keep the same rinfo_serial.
386 : : */
387 : 26574 : result->clause = (Expr *) newclause;
388 : 26574 : result->left_relids = rinfo->right_relids;
389 : 26574 : result->right_relids = rinfo->left_relids;
390 [ - + ]: 26574 : Assert(result->orclause == NULL);
391 : 26574 : result->left_ec = rinfo->right_ec;
392 : 26574 : result->right_ec = rinfo->left_ec;
393 : 26574 : result->left_em = rinfo->right_em;
394 : 26574 : result->right_em = rinfo->left_em;
395 : 26574 : result->scansel_cache = NIL; /* not worth updating this */
396 [ + + ]: 26574 : if (rinfo->hashjoinoperator == clause->opno)
397 : 25817 : result->hashjoinoperator = comm_op;
398 : : else
399 : 757 : result->hashjoinoperator = InvalidOid;
400 : 26574 : result->left_bucketsize = rinfo->right_bucketsize;
401 : 26574 : result->right_bucketsize = rinfo->left_bucketsize;
402 : 26574 : result->left_mcvfreq = rinfo->right_mcvfreq;
403 : 26574 : result->right_mcvfreq = rinfo->left_mcvfreq;
888 drowley@postgresql.o 404 : 26574 : result->left_hasheqoperator = InvalidOid;
405 : 26574 : result->right_hasheqoperator = InvalidOid;
406 : :
1891 tgl@sss.pgh.pa.us 407 : 26574 : return result;
408 : : }
409 : :
410 : : /*
411 : : * restriction_is_or_clause
412 : : *
413 : : * Returns t iff the restrictinfo node contains an 'or' clause.
414 : : */
415 : : bool
9031 416 : 880945 : restriction_is_or_clause(RestrictInfo *restrictinfo)
417 : : {
7406 418 [ + + ]: 880945 : if (restrictinfo->orclause != NULL)
9357 bruce@momjian.us 419 : 25360 : return true;
420 : : else
421 : 855585 : return false;
422 : : }
423 : :
424 : : /*
425 : : * restriction_is_securely_promotable
426 : : *
427 : : * Returns true if it's okay to evaluate this clause "early", that is before
428 : : * other restriction clauses attached to the specified relation.
429 : : */
430 : : bool
2643 tgl@sss.pgh.pa.us 431 : 661426 : restriction_is_securely_promotable(RestrictInfo *restrictinfo,
432 : : RelOptInfo *rel)
433 : : {
434 : : /*
435 : : * It's okay if there are no baserestrictinfo clauses for the rel that
436 : : * would need to go before this one, *or* if this one is leakproof.
437 : : */
438 [ + + ]: 661426 : if (restrictinfo->security_level <= rel->baserestrict_min_security ||
439 [ + + ]: 2275 : restrictinfo->leakproof)
440 : 660396 : return true;
441 : : else
442 : 1030 : return false;
443 : : }
444 : :
445 : : /*
446 : : * Detect whether a RestrictInfo's clause is constant TRUE (note that it's
447 : : * surely of type boolean). No such WHERE clause could survive qual
448 : : * canonicalization, but equivclass.c may generate such RestrictInfos for
449 : : * reasons discussed therein. We should drop them again when creating
450 : : * the finished plan, which is handled by the next few functions.
451 : : */
452 : : static inline bool
440 453 : 174999 : rinfo_is_constant_true(RestrictInfo *rinfo)
454 : : {
455 : 175872 : return IsA(rinfo->clause, Const) &&
456 [ + + + + : 175842 : !((Const *) rinfo->clause)->constisnull &&
+ + ]
457 : 843 : DatumGetBool(((Const *) rinfo->clause)->constvalue);
458 : : }
459 : :
460 : : /*
461 : : * get_actual_clauses
462 : : *
463 : : * Returns a list containing the bare clauses from 'restrictinfo_list'.
464 : : *
465 : : * This is only to be used in cases where none of the RestrictInfos can
466 : : * be pseudoconstant clauses (for instance, it's OK on indexqual lists).
467 : : */
468 : : List *
2643 469 : 27676 : get_actual_clauses(List *restrictinfo_list)
470 : : {
5396 471 : 27676 : List *result = NIL;
472 : : ListCell *l;
473 : :
474 [ + + + + : 56911 : foreach(l, restrictinfo_list)
+ + ]
475 : : {
2561 476 : 29235 : RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
477 : :
2643 478 [ - + ]: 29235 : Assert(!rinfo->pseudoconstant);
440 479 [ - + ]: 29235 : Assert(!rinfo_is_constant_true(rinfo));
480 : :
5396 481 : 29235 : result = lappend(result, rinfo->clause);
482 : : }
483 : 27676 : return result;
484 : : }
485 : :
486 : : /*
487 : : * extract_actual_clauses
488 : : *
489 : : * Extract bare clauses from 'restrictinfo_list', returning either the
490 : : * regular ones or the pseudoconstant ones per 'pseudoconstant'.
491 : : * Constant-TRUE clauses are dropped in any case.
492 : : */
493 : : List *
6497 494 : 280546 : extract_actual_clauses(List *restrictinfo_list,
495 : : bool pseudoconstant)
496 : : {
497 : 280546 : List *result = NIL;
498 : : ListCell *l;
499 : :
500 [ + + + + : 422704 : foreach(l, restrictinfo_list)
+ + ]
501 : : {
2561 502 : 142158 : RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
503 : :
440 504 [ + + ]: 142158 : if (rinfo->pseudoconstant == pseudoconstant &&
505 [ + - ]: 130276 : !rinfo_is_constant_true(rinfo))
6497 506 : 130276 : result = lappend(result, rinfo->clause);
507 : : }
508 : 280546 : return result;
509 : : }
510 : :
511 : : /*
512 : : * extract_actual_join_clauses
513 : : *
514 : : * Extract bare clauses from 'restrictinfo_list', separating those that
515 : : * semantically match the join level from those that were pushed down.
516 : : * Pseudoconstant and constant-TRUE clauses are excluded from the results.
517 : : *
518 : : * This is only used at outer joins, since for plain joins we don't care
519 : : * about pushed-down-ness.
520 : : */
521 : : void
522 : 18639 : extract_actual_join_clauses(List *restrictinfo_list,
523 : : Relids joinrelids,
524 : : List **joinquals,
525 : : List **otherquals)
526 : : {
527 : : ListCell *l;
528 : :
8615 529 : 18639 : *joinquals = NIL;
530 : 18639 : *otherquals = NIL;
531 : :
6497 532 [ + + + + : 34130 : foreach(l, restrictinfo_list)
+ + ]
533 : : {
2561 534 : 15491 : RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
535 : :
2186 536 [ + + + + ]: 15491 : if (RINFO_IS_PUSHED_DOWN(rinfo, joinrelids))
537 : : {
440 538 [ + + ]: 1456 : if (!rinfo->pseudoconstant &&
539 [ + - ]: 1453 : !rinfo_is_constant_true(rinfo))
6497 540 : 1453 : *otherquals = lappend(*otherquals, rinfo->clause);
541 : : }
542 : : else
543 : : {
544 : : /* joinquals shouldn't have been marked pseudoconstant */
545 [ - + ]: 14035 : Assert(!rinfo->pseudoconstant);
325 546 [ + + ]: 14035 : if (!rinfo_is_constant_true(rinfo))
547 : 13252 : *joinquals = lappend(*joinquals, rinfo->clause);
548 : : }
549 : : }
8615 550 : 18639 : }
551 : :
552 : : /*
553 : : * join_clause_is_movable_to
554 : : * Test whether a join clause is a safe candidate for parameterization
555 : : * of a scan on the specified base relation.
556 : : *
557 : : * A movable join clause is one that can safely be evaluated at a rel below
558 : : * its normal semantic level (ie, its required_relids), if the values of
559 : : * variables that it would need from other rels are provided.
560 : : *
561 : : * We insist that the clause actually reference the target relation; this
562 : : * prevents undesirable movement of degenerate join clauses, and ensures
563 : : * that there is a unique place that a clause can be moved down to.
564 : : *
565 : : * We cannot move an outer-join clause into the non-nullable side of its
566 : : * outer join, as that would change the results (rows would be suppressed
567 : : * rather than being null-extended).
568 : : *
569 : : * Also there must not be an outer join below the clause that would null the
570 : : * Vars coming from the target relation. Otherwise the clause might give
571 : : * results different from what it would give at its normal semantic level.
572 : : *
573 : : * Also, the join clause must not use any relations that have LATERAL
574 : : * references to the target relation, since we could not put such rels on
575 : : * the outer side of a nestloop with the target relation.
576 : : *
577 : : * Also, we reject is_clone versions of outer-join clauses. This has the
578 : : * effect of preventing us from generating variant parameterized paths
579 : : * that differ only in which outer joins null the parameterization rel(s).
580 : : * Generating one path from the minimally-parameterized has_clone version
581 : : * is sufficient.
582 : : */
583 : : bool
3893 584 : 122853 : join_clause_is_movable_to(RestrictInfo *rinfo, RelOptInfo *baserel)
585 : : {
586 : : /* Clause must physically reference target rel */
587 [ + + ]: 122853 : if (!bms_is_member(baserel->relid, rinfo->clause_relids))
4378 588 : 16951 : return false;
589 : :
590 : : /* Cannot move an outer-join clause into the join's outer side */
3893 591 [ + + ]: 105902 : if (bms_is_member(baserel->relid, rinfo->outer_relids))
4378 592 : 47080 : return false;
593 : :
594 : : /*
595 : : * Target rel's Vars must not be nulled by any outer join. We can check
596 : : * this without groveling through the individual Vars by seeing whether
597 : : * clause_relids (which includes all such Vars' varnullingrels) includes
598 : : * any outer join that can null the target rel. You might object that
599 : : * this could reject the clause on the basis of an OJ relid that came from
600 : : * some other rel's Var. However, that would still mean that the clause
601 : : * came from above that outer join and shouldn't be pushed down; so there
602 : : * should be no false positives.
603 : : */
440 604 [ + + ]: 58822 : if (bms_overlap(rinfo->clause_relids, baserel->nulling_relids))
3893 605 : 2681 : return false;
606 : :
607 : : /* Clause must not use any rels with LATERAL references to this rel */
608 [ + + ]: 56141 : if (bms_overlap(baserel->lateral_referencers, rinfo->clause_relids))
4378 609 : 9 : return false;
610 : :
611 : : /* Ignore clones, too */
440 612 [ + + ]: 56132 : if (rinfo->is_clone)
613 : 5416 : return false;
614 : :
4378 615 : 50716 : return true;
616 : : }
617 : :
618 : : /*
619 : : * join_clause_is_movable_into
620 : : * Test whether a join clause is movable and can be evaluated within
621 : : * the current join context.
622 : : *
623 : : * currentrelids: the relids of the proposed evaluation location
624 : : * current_and_outer: the union of currentrelids and the required_outer
625 : : * relids (parameterization's outer relations)
626 : : *
627 : : * The API would be a bit clearer if we passed the current relids and the
628 : : * outer relids separately and did bms_union internally; but since most
629 : : * callers need to apply this function to multiple clauses, we make the
630 : : * caller perform the union.
631 : : *
632 : : * Obviously, the clause must only refer to Vars available from the current
633 : : * relation plus the outer rels. We also check that it does reference at
634 : : * least one current Var, ensuring that the clause will be pushed down to
635 : : * a unique place in a parameterized join tree. And we check that we're
636 : : * not pushing the clause into its outer-join outer side.
637 : : *
638 : : * We used to need to check that we're not pushing the clause into a lower
639 : : * outer join's inner side. However, now that clause_relids includes
640 : : * references to potentially-nulling outer joins, the other tests handle that
641 : : * concern. If the clause references any Var coming from the inside of a
642 : : * lower outer join, its clause_relids will mention that outer join, causing
643 : : * the evaluability check to fail; while if it references no such Vars, the
644 : : * references-a-target-rel check will fail.
645 : : *
646 : : * There's no check here equivalent to join_clause_is_movable_to's test on
647 : : * lateral_referencers. We assume the caller wouldn't be inquiring unless
648 : : * it'd verified that the proposed outer rels don't have lateral references
649 : : * to the current rel(s). (If we are considering join paths with the outer
650 : : * rels on the outside and the current rels on the inside, then this should
651 : : * have been checked at the outset of such consideration; see join_is_legal
652 : : * and the path parameterization checks in joinpath.c.) On the other hand,
653 : : * in join_clause_is_movable_to we are asking whether the clause could be
654 : : * moved for some valid set of outer rels, so we don't have the benefit of
655 : : * relying on prior checks for lateral-reference validity.
656 : : *
657 : : * Likewise, we don't check is_clone here: rejecting the inappropriate
658 : : * variants of a cloned clause must be handled upstream.
659 : : *
660 : : * Note: if this returns true, it means that the clause could be moved to
661 : : * this join relation, but that doesn't mean that this is the lowest join
662 : : * it could be moved to. Caller may need to make additional calls to verify
663 : : * that this doesn't succeed on either of the inputs of a proposed join.
664 : : *
665 : : * Note: get_joinrel_parampathinfo depends on the fact that if
666 : : * current_and_outer is NULL, this function will always return false
667 : : * (since one or the other of the first two tests must fail).
668 : : */
669 : : bool
670 : 149935 : join_clause_is_movable_into(RestrictInfo *rinfo,
671 : : Relids currentrelids,
672 : : Relids current_and_outer)
673 : : {
674 : : /* Clause must be evaluable given available context */
675 [ + + ]: 149935 : if (!bms_is_subset(rinfo->clause_relids, current_and_outer))
676 : 28223 : return false;
677 : :
678 : : /* Clause must physically reference at least one target rel */
679 [ + + ]: 121712 : if (!bms_overlap(currentrelids, rinfo->clause_relids))
680 : 8386 : return false;
681 : :
682 : : /* Cannot move an outer-join clause into the join's outer side */
683 [ + + ]: 113326 : if (bms_overlap(currentrelids, rinfo->outer_relids))
684 : 440 : return false;
685 : :
686 : 112886 : return true;
687 : : }
|