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