From d25367ec4f869aac80e97964fa5d7143536818b1 Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Fri, 28 Nov 2014 14:16:24 -0500 Subject: [PATCH] Add bms_get_singleton_member(), and use it where appropriate. This patch adds a function that replaces a bms_membership() test followed by a bms_singleton_member() call, performing both the test and the extraction of a singleton set's member in one scan of the bitmapset. The performance advantage over the old way is probably minimal in current usage, but it seems worthwhile on notational grounds anyway. David Rowley --- src/backend/nodes/bitmapset.c | 44 +++++++++++++++++++++++ src/backend/optimizer/path/equivclass.c | 3 +- src/backend/optimizer/plan/analyzejoins.c | 7 ++-- src/backend/optimizer/util/placeholder.c | 4 +-- src/include/nodes/bitmapset.h | 1 + 5 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c index 26a0f872b3b..c4e1d26a49d 100644 --- a/src/backend/nodes/bitmapset.c +++ b/src/backend/nodes/bitmapset.c @@ -524,6 +524,50 @@ bms_singleton_member(const Bitmapset *a) return result; } +/* + * bms_get_singleton_member + * + * Test whether the given set is a singleton. + * If so, set *member to the value of its sole member, and return TRUE. + * If not, return FALSE, without changing *member. + * + * This is more convenient and faster than calling bms_membership() and then + * bms_singleton_member(), if we don't care about distinguishing empty sets + * from multiple-member sets. + */ +bool +bms_get_singleton_member(const Bitmapset *a, int *member) +{ + 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; + *member = result; + return true; +} + /* * bms_num_members - count members of set */ diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index e5dd58efe33..9919d27374f 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -867,9 +867,8 @@ 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_member(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 773f8a458e2..e99d416e852 100644 --- a/src/backend/optimizer/plan/analyzejoins.c +++ b/src/backend/optimizer/plan/analyzejoins.c @@ -162,11 +162,12 @@ join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo) * going to be able to do anything with it. */ if (sjinfo->jointype != JOIN_LEFT || - sjinfo->delay_upper_joins || - bms_membership(sjinfo->min_righthand) != BMS_SINGLETON) + sjinfo->delay_upper_joins) + return false; + + if (!bms_get_singleton_member(sjinfo->min_righthand, &innerrelid)) return false; - innerrelid = bms_singleton_member(sjinfo->min_righthand); innerrel = find_base_rel(root, innerrelid); if (innerrel->reloptkind != RELOPT_BASEREL) diff --git a/src/backend/optimizer/util/placeholder.c b/src/backend/optimizer/util/placeholder.c index 8d7c4feca46..36d19b84e88 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_member(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 a78ff4886d6..a314192b71a 100644 --- a/src/include/nodes/bitmapset.h +++ b/src/include/nodes/bitmapset.h @@ -72,6 +72,7 @@ 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_member(const Bitmapset *a, int *member); extern int bms_num_members(const Bitmapset *a); /* optimized tests when we don't need to know exact membership count: */ -- GitLab