diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c index c927b78..daec9e6 100644 --- a/src/backend/nodes/bitmapset.c +++ b/src/backend/nodes/bitmapset.c @@ -525,6 +525,61 @@ bms_singleton_member(const Bitmapset *a) } /* + * bms_get_singleton + * + * Returns True and sets singleton to the value of the singleton, if the + * bitmapset is a singleton, otherwise, if the bitmapset is NULL, empty or has + * multiple values, False is returned. + * + * This function can be useful if some processing only needs to take place + * when a Bitmapset is a singleton and that singleton value is required for + * that processing, for example, you could do: + * + * if (bms_membership(a) != BMS_SINGLETON) + * return; // nothing to do + * singleton = bms_singleton_member(a); + * + * But it would be more efficiently processed by doing: + * + * if (!bms_get_singleton(a, &singleton)) + * return; // nothing to do + */ +bool +bms_get_singleton(const Bitmapset *a, int *singleton) +{ + int result = -1; + int nwords; + int wordnum; + + if (a == NULL) + return false; + nwords = a->nwords; + for (wordnum = 0; wordnum < nwords; wordnum++) + { + bitmapword w = a->words[wordnum]; + + if (w != 0) + { + if (result >= 0 || HAS_MULTIPLE_ONES(w)) + return false; + result = wordnum * BITS_PER_BITMAPWORD; + while ((w & 255) == 0) + { + w >>= 8; + result += 8; + } + result += rightmost_one_pos[w & 255]; + } + } + if (result < 0) + return false; + + *singleton = result; + return true; +} + + +/* * bms_num_members - count members of set */ int diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index 63dbc1b..0d7722b 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -937,9 +937,9 @@ generate_base_implied_equalities_no_const(PlannerInfo *root, int relid; Assert(!cur_em->em_is_child); /* no children yet */ - if (bms_membership(cur_em->em_relids) != BMS_SINGLETON) + if (!bms_get_singleton(cur_em->em_relids, &relid)) continue; - relid = bms_singleton_member(cur_em->em_relids); + Assert(relid < root->simple_rel_array_size); if (prev_ems[relid] != NULL) diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c index b0a11d7..e906cd3 100644 --- a/src/backend/optimizer/plan/analyzejoins.c +++ b/src/backend/optimizer/plan/analyzejoins.c @@ -207,10 +207,9 @@ leftjoin_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo) * going to be able to do anything with it. */ if (sjinfo->delay_upper_joins || - bms_membership(sjinfo->min_righthand) != BMS_SINGLETON) + !bms_get_singleton(sjinfo->min_righthand, &innerrelid)) return false; - innerrelid = bms_singleton_member(sjinfo->min_righthand); innerrel = find_base_rel(root, innerrelid); if (innerrel->reloptkind != RELOPT_BASEREL) @@ -489,10 +488,9 @@ semiorantijoin_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo, * checking the right hand rel has any indexes. */ if (sjinfo->delay_upper_joins || - bms_membership(sjinfo->min_lefthand) != BMS_SINGLETON) + !bms_get_singleton(sjinfo->min_lefthand, &outerrelid)) return false; - outerrelid = bms_singleton_member(sjinfo->min_lefthand); outerrel = find_base_rel(root, outerrelid); /* @@ -504,10 +502,9 @@ semiorantijoin_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo, outerrel->fklist == NIL) return false; - if (bms_membership(sjinfo->min_righthand) != BMS_SINGLETON) + if (!bms_get_singleton(sjinfo->min_righthand, &innerrelid)) return false; - innerrelid = bms_singleton_member(sjinfo->min_righthand); innerrel = find_base_rel(root, innerrelid); /* diff --git a/src/backend/optimizer/util/placeholder.c b/src/backend/optimizer/util/placeholder.c index 8d7c4fe..d9d1c6a 100644 --- a/src/backend/optimizer/util/placeholder.c +++ b/src/backend/optimizer/util/placeholder.c @@ -383,10 +383,10 @@ add_placeholders_to_base_rels(PlannerInfo *root) { PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc); Relids eval_at = phinfo->ph_eval_at; + int varno; - if (bms_membership(eval_at) == BMS_SINGLETON) + if (bms_get_singleton(eval_at, &varno)) { - int varno = bms_singleton_member(eval_at); RelOptInfo *rel = find_base_rel(root, varno); /* add it to reltargetlist if needed above the rel scan level */ diff --git a/src/include/nodes/bitmapset.h b/src/include/nodes/bitmapset.h index f770608..6db7270 100644 --- a/src/include/nodes/bitmapset.h +++ b/src/include/nodes/bitmapset.h @@ -72,6 +72,8 @@ extern bool bms_is_member(int x, const Bitmapset *a); extern bool bms_overlap(const Bitmapset *a, const Bitmapset *b); extern bool bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b); extern int bms_singleton_member(const Bitmapset *a); +extern bool bms_get_singleton(const Bitmapset *a, int *singleton); + extern int bms_num_members(const Bitmapset *a); /* optimized tests when we don't need to know exact membership count: */