1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-24 09:27:52 +03:00

Defend against bogus parameterization of join input paths.

An outer join cannot be formed using an input path that is parameterized
by a value that is supposed to be nulled by the outer join.  This is
obviously nonsensical, and it could lead to a bad plan being selected;
although currently it seems that we'll hit various sanity-check
assertions first.

I think that such cases were formerly prevented by the delay_upper_joins
mechanism, but now that that's gone we need an explicit check.

(Perhaps we should avoid generating baserel paths that could
lead to this situation in the first place; but it seems like
having a defense at the join level would be a good idea anyway.)

Richard Guo and Tom Lane, per report from Jaime Casanova

Discussion: https://postgr.es/m/CAJKUy5g2uZRrUDZJ8p-=giwcSHVUn0c9nmdxPSY0jF0Ov8VoEA@mail.gmail.com
This commit is contained in:
Tom Lane
2023-06-29 12:12:52 -04:00
parent 43af714def
commit a798660ebe
3 changed files with 78 additions and 0 deletions

View File

@@ -698,6 +698,17 @@ try_nestloop_path(PlannerInfo *root,
Relids inner_paramrels = PATH_REQ_OUTER(inner_path);
Relids outer_paramrels = PATH_REQ_OUTER(outer_path);
/*
* If we are forming an outer join at this join, it's nonsensical to use
* an input path that uses the outer join as part of its parameterization.
* (This can happen despite our join order restrictions, since those apply
* to what is in an input relation not what its parameters are.)
*/
if (extra->sjinfo->ojrelid != 0 &&
(bms_is_member(extra->sjinfo->ojrelid, inner_paramrels) ||
bms_is_member(extra->sjinfo->ojrelid, outer_paramrels)))
return;
/*
* Paths are parameterized by top-level parents, so run parameterization
* tests on the parent relids.
@@ -908,6 +919,17 @@ try_mergejoin_path(PlannerInfo *root,
return;
}
/*
* If we are forming an outer join at this join, it's nonsensical to use
* an input path that uses the outer join as part of its parameterization.
* (This can happen despite our join order restrictions, since those apply
* to what is in an input relation not what its parameters are.)
*/
if (extra->sjinfo->ojrelid != 0 &&
(bms_is_member(extra->sjinfo->ojrelid, PATH_REQ_OUTER(inner_path)) ||
bms_is_member(extra->sjinfo->ojrelid, PATH_REQ_OUTER(outer_path))))
return;
/*
* Check to see if proposed path is still parameterized, and reject if the
* parameterization wouldn't be sensible.
@@ -1054,6 +1076,17 @@ try_hashjoin_path(PlannerInfo *root,
Relids required_outer;
JoinCostWorkspace workspace;
/*
* If we are forming an outer join at this join, it's nonsensical to use
* an input path that uses the outer join as part of its parameterization.
* (This can happen despite our join order restrictions, since those apply
* to what is in an input relation not what its parameters are.)
*/
if (extra->sjinfo->ojrelid != 0 &&
(bms_is_member(extra->sjinfo->ojrelid, PATH_REQ_OUTER(inner_path)) ||
bms_is_member(extra->sjinfo->ojrelid, PATH_REQ_OUTER(outer_path))))
return;
/*
* Check to see if proposed path is still parameterized, and reject if the
* parameterization wouldn't be sensible.