diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2023-06-29 12:12:52 -0400 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2023-06-29 12:12:52 -0400 |
| commit | a798660ebe3ff1feb310db13b957c5cda4c8c50d (patch) | |
| tree | 3061c9172724f41cac19a273341f583d932f5656 /src/backend/optimizer/path | |
| parent | 43af714defa00145981eb542cb71647836b3efa4 (diff) | |
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
Diffstat (limited to 'src/backend/optimizer/path')
| -rw-r--r-- | src/backend/optimizer/path/joinpath.c | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index c2f211a60d1..f047ad9ba46 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -699,6 +699,17 @@ try_nestloop_path(PlannerInfo *root, 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. */ @@ -909,6 +920,17 @@ try_mergejoin_path(PlannerInfo *root, } /* + * 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. */ @@ -1055,6 +1077,17 @@ try_hashjoin_path(PlannerInfo *root, 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. */ |
