diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2015-12-07 17:41:45 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2015-12-07 17:41:45 -0500 |
commit | 25517ee14c1a018876b64dce73e8f7fb7e937783 (patch) | |
tree | 52f4bcc40e3b1d4dce4e4b535b46cd7a4f752f17 /src/backend/optimizer/util/relnode.c | |
parent | 9d1839fad945cba7e23e645a3c212f34e56495f7 (diff) | |
download | postgresql-25517ee14c1a018876b64dce73e8f7fb7e937783.tar.gz postgresql-25517ee14c1a018876b64dce73e8f7fb7e937783.zip |
Fix another oversight in checking if a join with LATERAL refs is legal.
It was possible for the planner to decide to join a LATERAL subquery to
the outer side of an outer join before the outer join itself is completed.
Normally that's fine because of the associativity rules, but it doesn't
work if the subquery contains a lateral reference to the inner side of the
outer join. In such a situation the outer join *must* be done first.
join_is_legal() missed this consideration and would allow the join to be
attempted, but the actual path-building code correctly decided that no
valid join path could be made, sometimes leading to planner errors such as
"failed to build any N-way joins".
Per report from Andreas Seltenreich. Back-patch to 9.3 where LATERAL
support was added.
Diffstat (limited to 'src/backend/optimizer/util/relnode.c')
-rw-r--r-- | src/backend/optimizer/util/relnode.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 68a93a1a5bd..58b995bd13c 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -479,6 +479,45 @@ build_join_rel(PlannerInfo *root, } /* + * min_join_parameterization + * + * Determine the minimum possible parameterization of a joinrel, that is, the + * set of other rels it contains LATERAL references to. + */ +Relids +min_join_parameterization(PlannerInfo *root, Relids joinrelids) +{ + Relids result; + ListCell *lc; + + /* Easy if there are no lateral references */ + if (root->lateral_info_list == NIL) + return NULL; + + /* + * Scan lateral_info_list to find all the lateral references occurring in + * or below this join. + */ + result = NULL; + foreach(lc, root->lateral_info_list) + { + LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(lc); + + if (bms_is_subset(ljinfo->lateral_rhs, joinrelids)) + result = bms_add_members(result, ljinfo->lateral_lhs); + } + + /* Remove any rels that are already included in the join */ + result = bms_del_members(result, joinrelids); + + /* Maintain invariant that result is exactly NULL if empty */ + if (bms_is_empty(result)) + result = NULL; + + return result; +} + +/* * build_joinrel_tlist * Builds a join relation's target list from an input relation. * (This is invoked twice to handle the two input relations.) |