aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/joinpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/joinpath.c')
-rw-r--r--src/backend/optimizer/path/joinpath.c65
1 files changed, 61 insertions, 4 deletions
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index d345c0437a4..dfbb839be16 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -234,7 +234,9 @@ add_paths_to_joinrel(PlannerInfo *root,
* reduces the number of parameterized paths we have to deal with at
* higher join levels, without compromising the quality of the resulting
* plan. We express the restriction as a Relids set that must overlap the
- * parameterization of any proposed join path.
+ * parameterization of any proposed join path. Note: param_source_rels
+ * should contain only baserels, not OJ relids, so starting from
+ * all_baserels not all_query_rels is correct.
*/
foreach(lc, root->join_info_list)
{
@@ -366,6 +368,60 @@ allow_star_schema_join(PlannerInfo *root,
}
/*
+ * If the parameterization is only partly satisfied by the outer rel,
+ * the unsatisfied part can't include any outer-join relids that could
+ * null rels of the satisfied part. That would imply that we're trying
+ * to use a clause involving a Var with nonempty varnullingrels at
+ * a join level where that value isn't yet computable.
+ *
+ * In practice, this test never finds a problem because earlier join order
+ * restrictions prevent us from attempting a join that would cause a problem.
+ * (That's unsurprising, because the code worked before we ever added
+ * outer-join relids to expression relids.) It still seems worth checking
+ * as a backstop, but we don't go to a lot of trouble: just reject if the
+ * unsatisfied part includes any outer-join relids at all.
+ */
+static inline bool
+have_unsafe_outer_join_ref(PlannerInfo *root,
+ Relids outerrelids,
+ Relids inner_paramrels)
+{
+ bool result = false;
+ Relids unsatisfied = bms_difference(inner_paramrels, outerrelids);
+
+ if (unlikely(bms_overlap(unsatisfied, root->outer_join_rels)))
+ {
+#ifdef NOT_USED
+ /* If we ever weaken the join order restrictions, we might need this */
+ ListCell *lc;
+
+ foreach(lc, root->join_info_list)
+ {
+ SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
+
+ if (!bms_is_member(sjinfo->ojrelid, unsatisfied))
+ continue; /* not relevant */
+ if (bms_overlap(inner_paramrels, sjinfo->min_righthand) ||
+ (sjinfo->jointype == JOIN_FULL &&
+ bms_overlap(inner_paramrels, sjinfo->min_lefthand)))
+ {
+ result = true; /* doesn't work */
+ break;
+ }
+ }
+#else
+ /* For now, if we do see an overlap, just assume it's trouble */
+ result = true;
+#endif
+ }
+
+ /* Waste no memory when we reject a path here */
+ bms_free(unsatisfied);
+
+ return result;
+}
+
+/*
* paraminfo_get_equal_hashops
* Determine if param_info and innerrel's lateral_vars can be hashed.
* Returns true the hashing is possible, otherwise return false.
@@ -657,15 +713,16 @@ try_nestloop_path(PlannerInfo *root,
/*
* Check to see if proposed path is still parameterized, and reject if the
* parameterization wouldn't be sensible --- unless allow_star_schema_join
- * says to allow it anyway. Also, we must reject if have_dangerous_phv
- * doesn't like the look of it, which could only happen if the nestloop is
- * still parameterized.
+ * says to allow it anyway. Also, we must reject if either
+ * have_unsafe_outer_join_ref or have_dangerous_phv don't like the look of
+ * it, which could only happen if the nestloop is still parameterized.
*/
required_outer = calc_nestloop_required_outer(outerrelids, outer_paramrels,
innerrelids, inner_paramrels);
if (required_outer &&
((!bms_overlap(required_outer, extra->param_source_rels) &&
!allow_star_schema_join(root, outerrelids, inner_paramrels)) ||
+ have_unsafe_outer_join_ref(root, outerrelids, inner_paramrels) ||
have_dangerous_phv(root, outerrelids, inner_paramrels)))
{
/* Waste no memory when we reject a path here */