diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 9da3ff2f9ab..96e95a04ea9 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -52,7 +52,7 @@ static void compute_partition_bounds(PlannerInfo *root, RelOptInfo *rel1, static void get_matching_part_pairs(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *rel1, RelOptInfo *rel2, List **parts1, List **parts2); - +static bool rel_is_nullable_side(PlannerInfo *root, Relids joinrelids, Index relid); /* * join_search_one_level @@ -746,6 +746,25 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) joinrel = build_join_rel(root, joinrelids, rel1, rel2, sjinfo, &restrictlist); + /* test code. */ + + if (sjinfo->jointype == JOIN_LEFT) + { + int relid = -1; + while((relid = bms_next_member(rel2->relids, relid)) >= 0) + { + Assert(rel_is_nullable_side(root, joinrelids, relid)); + } + } + else if (sjinfo->jointype == JOIN_FULL) + { + int relid = -1; + while((relid = bms_next_member(joinrelids, relid)) >= 0) + { + Assert(rel_is_nullable_side(root, joinrelids, relid)); + } + } + /* * If we've already proven this join is empty, we needn't consider any * more paths for it. @@ -1781,3 +1800,69 @@ get_matching_part_pairs(PlannerInfo *root, RelOptInfo *joinrel, *parts2 = lappend(*parts2, child_rel2); } } + + +/* + * rel_in_nullable_side + * + * After the SpecialJoinInfo has been applied, return if relid + * is in the nullable side. + */ +static bool +rel_in_nullable_side(SpecialJoinInfo *sjinfo, Index relid) +{ + if (sjinfo->jointype == JOIN_FULL) + { + if (bms_is_member(relid, sjinfo->min_lefthand) || + bms_is_member(relid, sjinfo->min_righthand)) + return true; + } + else if (sjinfo->jointype == JOIN_LEFT) + { + if (bms_is_member(relid, sjinfo->min_righthand)) + return true; + } + + return false; +} + + +/* + * rel_is_nullable_side + * + * For the given join ID joinrelids, return if the relid is in the nullable + * side. + */ +static bool +rel_is_nullable_side(PlannerInfo *root, Relids joinrelids, Index relid) +{ + ListCell *lc; + Assert(bms_is_member(relid, joinrelids)); + + /* Find the SepcialJoinInfo which is possible nullable the relid. */ + foreach(lc, root->join_info_list) + { + SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc); + + /* + * If the sjinfo is possible takes effects on joinrelis, then it must + * contain both sides of min relids. + */ + Relids min_relids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand); + + if (!bms_is_subset(min_relids, joinrelids)) + { + bms_free(min_relids); + continue; + } + + if (rel_in_nullable_side(sjinfo, relid)) + { + bms_free(min_relids); + return true; + } + bms_free(min_relids); + } + + return false; +}