2003-02-08 21:20:55 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* bitmapset.c
|
|
|
|
* PostgreSQL generic bitmap set package
|
|
|
|
*
|
|
|
|
* A bitmap set can represent any set of nonnegative integers, although
|
|
|
|
* it is mainly intended for sets where the maximum value is not large,
|
|
|
|
* say at most a few hundred. By convention, a NULL pointer is always
|
|
|
|
* accepted by all operations to represent the empty set. (But beware
|
|
|
|
* that this is not the only representation of the empty set. Use
|
|
|
|
* bms_is_empty() in preference to testing for NULL.)
|
|
|
|
*
|
|
|
|
*
|
2020-01-01 18:21:45 +01:00
|
|
|
* Copyright (c) 2003-2020, PostgreSQL Global Development Group
|
2003-02-08 21:20:55 +01:00
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/nodes/bitmapset.c
|
2003-02-08 21:20:55 +01:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2019-03-11 17:17:50 +01:00
|
|
|
#include "nodes/bitmapset.h"
|
2017-03-27 05:20:54 +02:00
|
|
|
#include "nodes/pg_list.h"
|
Make use of compiler builtins and/or assembly for CLZ, CTZ, POPCNT.
Test for the compiler builtins __builtin_clz, __builtin_ctz, and
__builtin_popcount, and make use of these in preference to
handwritten C code if they're available. Create src/port
infrastructure for "leftmost one", "rightmost one", and "popcount"
so as to centralize these decisions.
On x86_64, __builtin_popcount generally won't make use of the POPCNT
opcode because that's not universally supported yet. Provide code
that checks CPUID and then calls POPCNT via asm() if available.
This requires indirecting through a function pointer, which is
an annoying amount of overhead for a one-instruction operation,
but it's probably not worth working harder than this for our
current use-cases.
I'm not sure we've found all the existing places that could profit
from this new infrastructure; but we at least touched all the
ones that used copied-and-pasted versions of the bitmapset.c code,
and got rid of multiple copies of the associated constant arrays.
While at it, replace c-compiler.m4's one-per-builtin-function
macros with a single one that can handle all the cases we need
to worry about so far. Also, because I'm paranoid, make those
checks into AC_LINK checks rather than just AC_COMPILE; the
former coding failed to verify that libgcc has support for the
builtin, in cases where it's not inline code.
David Rowley, Thomas Munro, Alvaro Herrera, Tom Lane
Discussion: https://postgr.es/m/CAKJS1f9WTAGG1tPeJnD18hiQW5gAk59fQ6WK-vfdAKEHyRg2RA@mail.gmail.com
2019-02-16 05:22:27 +01:00
|
|
|
#include "port/pg_bitutils.h"
|
2019-03-11 17:17:50 +01:00
|
|
|
#include "utils/hashutils.h"
|
2003-02-08 21:20:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
#define WORDNUM(x) ((x) / BITS_PER_BITMAPWORD)
|
|
|
|
#define BITNUM(x) ((x) % BITS_PER_BITMAPWORD)
|
|
|
|
|
|
|
|
#define BITMAPSET_SIZE(nwords) \
|
|
|
|
(offsetof(Bitmapset, words) + (nwords) * sizeof(bitmapword))
|
|
|
|
|
|
|
|
/*----------
|
|
|
|
* This is a well-known cute trick for isolating the rightmost one-bit
|
|
|
|
* in a word. It assumes two's complement arithmetic. Consider any
|
|
|
|
* nonzero value, and focus attention on the rightmost one. The value is
|
|
|
|
* then something like
|
|
|
|
* xxxxxx10000
|
|
|
|
* where x's are unspecified bits. The two's complement negative is formed
|
|
|
|
* by inverting all the bits and adding one. Inversion gives
|
|
|
|
* yyyyyy01111
|
2014-05-06 18:12:18 +02:00
|
|
|
* where each y is the inverse of the corresponding x. Incrementing gives
|
2003-02-08 21:20:55 +01:00
|
|
|
* yyyyyy10000
|
|
|
|
* and then ANDing with the original value gives
|
|
|
|
* 00000010000
|
|
|
|
* This works for all cases except original value = zero, where of course
|
|
|
|
* we get zero.
|
|
|
|
*----------
|
|
|
|
*/
|
|
|
|
#define RIGHTMOST_ONE(x) ((signedbitmapword) (x) & -((signedbitmapword) (x)))
|
|
|
|
|
|
|
|
#define HAS_MULTIPLE_ONES(x) ((bitmapword) RIGHTMOST_ONE(x) != (x))
|
|
|
|
|
Make use of compiler builtins and/or assembly for CLZ, CTZ, POPCNT.
Test for the compiler builtins __builtin_clz, __builtin_ctz, and
__builtin_popcount, and make use of these in preference to
handwritten C code if they're available. Create src/port
infrastructure for "leftmost one", "rightmost one", and "popcount"
so as to centralize these decisions.
On x86_64, __builtin_popcount generally won't make use of the POPCNT
opcode because that's not universally supported yet. Provide code
that checks CPUID and then calls POPCNT via asm() if available.
This requires indirecting through a function pointer, which is
an annoying amount of overhead for a one-instruction operation,
but it's probably not worth working harder than this for our
current use-cases.
I'm not sure we've found all the existing places that could profit
from this new infrastructure; but we at least touched all the
ones that used copied-and-pasted versions of the bitmapset.c code,
and got rid of multiple copies of the associated constant arrays.
While at it, replace c-compiler.m4's one-per-builtin-function
macros with a single one that can handle all the cases we need
to worry about so far. Also, because I'm paranoid, make those
checks into AC_LINK checks rather than just AC_COMPILE; the
former coding failed to verify that libgcc has support for the
builtin, in cases where it's not inline code.
David Rowley, Thomas Munro, Alvaro Herrera, Tom Lane
Discussion: https://postgr.es/m/CAKJS1f9WTAGG1tPeJnD18hiQW5gAk59fQ6WK-vfdAKEHyRg2RA@mail.gmail.com
2019-02-16 05:22:27 +01:00
|
|
|
/* Select appropriate bit-twiddling functions for bitmap word size */
|
|
|
|
#if BITS_PER_BITMAPWORD == 32
|
|
|
|
#define bmw_leftmost_one_pos(w) pg_leftmost_one_pos32(w)
|
|
|
|
#define bmw_rightmost_one_pos(w) pg_rightmost_one_pos32(w)
|
|
|
|
#define bmw_popcount(w) pg_popcount32(w)
|
|
|
|
#elif BITS_PER_BITMAPWORD == 64
|
|
|
|
#define bmw_leftmost_one_pos(w) pg_leftmost_one_pos64(w)
|
|
|
|
#define bmw_rightmost_one_pos(w) pg_rightmost_one_pos64(w)
|
|
|
|
#define bmw_popcount(w) pg_popcount64(w)
|
|
|
|
#else
|
|
|
|
#error "invalid BITS_PER_BITMAPWORD"
|
|
|
|
#endif
|
2003-02-08 21:20:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bms_copy - make a palloc'd copy of a bitmapset
|
|
|
|
*/
|
|
|
|
Bitmapset *
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_copy(const Bitmapset *a)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
Bitmapset *result;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
if (a == NULL)
|
|
|
|
return NULL;
|
|
|
|
size = BITMAPSET_SIZE(a->nwords);
|
|
|
|
result = (Bitmapset *) palloc(size);
|
|
|
|
memcpy(result, a, size);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bms_equal - are two bitmapsets equal?
|
|
|
|
*
|
|
|
|
* This is logical not physical equality; in particular, a NULL pointer will
|
|
|
|
* be reported as equal to a palloc'd value containing no members.
|
|
|
|
*/
|
|
|
|
bool
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_equal(const Bitmapset *a, const Bitmapset *b)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
const Bitmapset *shorter;
|
|
|
|
const Bitmapset *longer;
|
|
|
|
int shortlen;
|
|
|
|
int longlen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Handle cases where either input is NULL */
|
|
|
|
if (a == NULL)
|
|
|
|
{
|
|
|
|
if (b == NULL)
|
|
|
|
return true;
|
|
|
|
return bms_is_empty(b);
|
|
|
|
}
|
|
|
|
else if (b == NULL)
|
|
|
|
return bms_is_empty(a);
|
|
|
|
/* Identify shorter and longer input */
|
|
|
|
if (a->nwords <= b->nwords)
|
|
|
|
{
|
|
|
|
shorter = a;
|
|
|
|
longer = b;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
shorter = b;
|
|
|
|
longer = a;
|
|
|
|
}
|
|
|
|
/* And process */
|
|
|
|
shortlen = shorter->nwords;
|
|
|
|
for (i = 0; i < shortlen; i++)
|
|
|
|
{
|
|
|
|
if (shorter->words[i] != longer->words[i])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
longlen = longer->nwords;
|
|
|
|
for (; i < longlen; i++)
|
|
|
|
{
|
|
|
|
if (longer->words[i] != 0)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Improve the heuristic for ordering child paths of a parallel append.
Commit ab7271677 introduced code that attempts to order the child
scans of a Parallel Append node in a way that will minimize execution
time, based on total cost and startup cost. However, it failed to
think hard about what to do when estimated costs are exactly equal;
a case that's particularly likely to occur when comparing on startup
cost. In such a case the ordering of the child paths would be left
to the whims of qsort, an algorithm that isn't even stable.
We can improve matters by applying the rule used elsewhere in the
planner: if total costs are equal, sort on startup cost, and
vice versa. When both cost estimates are exactly equal, rather
than letting qsort do something unpredictable, sort based on the
child paths' relids, which should typically result in sorting in
inheritance order. (The latter provision requires inventing a
qsort-style comparator for bitmapsets, but maybe we'll have use
for that for other reasons in future.)
This results in a few plan changes in the select_parallel test,
but those all look more reasonable than before, when the actual
underlying cost numbers are taken into account.
Discussion: https://postgr.es/m/4944.1515446989@sss.pgh.pa.us
2018-01-09 19:07:52 +01:00
|
|
|
/*
|
|
|
|
* bms_compare - qsort-style comparator for bitmapsets
|
|
|
|
*
|
|
|
|
* This guarantees to report values as equal iff bms_equal would say they are
|
|
|
|
* equal. Otherwise, the highest-numbered bit that is set in one value but
|
|
|
|
* not the other determines the result. (This rule means that, for example,
|
|
|
|
* {6} is greater than {5}, which seems plausible.)
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
bms_compare(const Bitmapset *a, const Bitmapset *b)
|
|
|
|
{
|
|
|
|
int shortlen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Handle cases where either input is NULL */
|
|
|
|
if (a == NULL)
|
|
|
|
return bms_is_empty(b) ? 0 : -1;
|
|
|
|
else if (b == NULL)
|
|
|
|
return bms_is_empty(a) ? 0 : +1;
|
|
|
|
/* Handle cases where one input is longer than the other */
|
|
|
|
shortlen = Min(a->nwords, b->nwords);
|
|
|
|
for (i = shortlen; i < a->nwords; i++)
|
|
|
|
{
|
|
|
|
if (a->words[i] != 0)
|
|
|
|
return +1;
|
|
|
|
}
|
|
|
|
for (i = shortlen; i < b->nwords; i++)
|
|
|
|
{
|
|
|
|
if (b->words[i] != 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* Process words in common */
|
|
|
|
i = shortlen;
|
|
|
|
while (--i >= 0)
|
|
|
|
{
|
|
|
|
bitmapword aw = a->words[i];
|
|
|
|
bitmapword bw = b->words[i];
|
|
|
|
|
|
|
|
if (aw != bw)
|
|
|
|
return (aw > bw) ? +1 : -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-02-08 21:20:55 +01:00
|
|
|
/*
|
|
|
|
* bms_make_singleton - build a bitmapset containing a single member
|
|
|
|
*/
|
|
|
|
Bitmapset *
|
|
|
|
bms_make_singleton(int x)
|
|
|
|
{
|
|
|
|
Bitmapset *result;
|
|
|
|
int wordnum,
|
|
|
|
bitnum;
|
|
|
|
|
|
|
|
if (x < 0)
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(ERROR, "negative bitmapset member not allowed");
|
2003-02-08 21:20:55 +01:00
|
|
|
wordnum = WORDNUM(x);
|
|
|
|
bitnum = BITNUM(x);
|
|
|
|
result = (Bitmapset *) palloc0(BITMAPSET_SIZE(wordnum + 1));
|
|
|
|
result->nwords = wordnum + 1;
|
|
|
|
result->words[wordnum] = ((bitmapword) 1 << bitnum);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bms_free - free a bitmapset
|
|
|
|
*
|
|
|
|
* Same as pfree except for allowing NULL input
|
|
|
|
*/
|
|
|
|
void
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_free(Bitmapset *a)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
if (a)
|
|
|
|
pfree(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* These operations all make a freshly palloc'd result,
|
|
|
|
* leaving their inputs untouched
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bms_union - set union
|
|
|
|
*/
|
|
|
|
Bitmapset *
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_union(const Bitmapset *a, const Bitmapset *b)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
Bitmapset *result;
|
|
|
|
const Bitmapset *other;
|
|
|
|
int otherlen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Handle cases where either input is NULL */
|
|
|
|
if (a == NULL)
|
|
|
|
return bms_copy(b);
|
|
|
|
if (b == NULL)
|
|
|
|
return bms_copy(a);
|
|
|
|
/* Identify shorter and longer input; copy the longer one */
|
|
|
|
if (a->nwords <= b->nwords)
|
|
|
|
{
|
|
|
|
result = bms_copy(b);
|
|
|
|
other = a;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result = bms_copy(a);
|
|
|
|
other = b;
|
|
|
|
}
|
|
|
|
/* And union the shorter input into the result */
|
|
|
|
otherlen = other->nwords;
|
|
|
|
for (i = 0; i < otherlen; i++)
|
|
|
|
result->words[i] |= other->words[i];
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bms_intersect - set intersection
|
|
|
|
*/
|
|
|
|
Bitmapset *
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_intersect(const Bitmapset *a, const Bitmapset *b)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
Bitmapset *result;
|
|
|
|
const Bitmapset *other;
|
|
|
|
int resultlen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Handle cases where either input is NULL */
|
|
|
|
if (a == NULL || b == NULL)
|
|
|
|
return NULL;
|
|
|
|
/* Identify shorter and longer input; copy the shorter one */
|
|
|
|
if (a->nwords <= b->nwords)
|
|
|
|
{
|
|
|
|
result = bms_copy(a);
|
|
|
|
other = b;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result = bms_copy(b);
|
|
|
|
other = a;
|
|
|
|
}
|
|
|
|
/* And intersect the longer input with the result */
|
|
|
|
resultlen = result->nwords;
|
|
|
|
for (i = 0; i < resultlen; i++)
|
|
|
|
result->words[i] &= other->words[i];
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bms_difference - set difference (ie, A without members of B)
|
|
|
|
*/
|
|
|
|
Bitmapset *
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_difference(const Bitmapset *a, const Bitmapset *b)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
Bitmapset *result;
|
|
|
|
int shortlen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Handle cases where either input is NULL */
|
|
|
|
if (a == NULL)
|
|
|
|
return NULL;
|
|
|
|
if (b == NULL)
|
|
|
|
return bms_copy(a);
|
|
|
|
/* Copy the left input */
|
|
|
|
result = bms_copy(a);
|
|
|
|
/* And remove b's bits from result */
|
|
|
|
shortlen = Min(a->nwords, b->nwords);
|
|
|
|
for (i = 0; i < shortlen; i++)
|
2003-08-04 02:43:34 +02:00
|
|
|
result->words[i] &= ~b->words[i];
|
2003-02-08 21:20:55 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bms_is_subset - is A a subset of B?
|
|
|
|
*/
|
|
|
|
bool
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_is_subset(const Bitmapset *a, const Bitmapset *b)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
int shortlen;
|
|
|
|
int longlen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Handle cases where either input is NULL */
|
|
|
|
if (a == NULL)
|
|
|
|
return true; /* empty set is a subset of anything */
|
|
|
|
if (b == NULL)
|
|
|
|
return bms_is_empty(a);
|
|
|
|
/* Check common words */
|
|
|
|
shortlen = Min(a->nwords, b->nwords);
|
|
|
|
for (i = 0; i < shortlen; i++)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
if ((a->words[i] & ~b->words[i]) != 0)
|
2003-02-08 21:20:55 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
/* Check extra words */
|
|
|
|
if (a->nwords > b->nwords)
|
|
|
|
{
|
|
|
|
longlen = a->nwords;
|
|
|
|
for (; i < longlen; i++)
|
|
|
|
{
|
|
|
|
if (a->words[i] != 0)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-01-28 01:26:38 +01:00
|
|
|
/*
|
|
|
|
* bms_subset_compare - compare A and B for equality/subset relationships
|
|
|
|
*
|
|
|
|
* This is more efficient than testing bms_is_subset in both directions.
|
|
|
|
*/
|
|
|
|
BMS_Comparison
|
|
|
|
bms_subset_compare(const Bitmapset *a, const Bitmapset *b)
|
|
|
|
{
|
|
|
|
BMS_Comparison result;
|
|
|
|
int shortlen;
|
|
|
|
int longlen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Handle cases where either input is NULL */
|
|
|
|
if (a == NULL)
|
|
|
|
{
|
|
|
|
if (b == NULL)
|
|
|
|
return BMS_EQUAL;
|
|
|
|
return bms_is_empty(b) ? BMS_EQUAL : BMS_SUBSET1;
|
|
|
|
}
|
|
|
|
if (b == NULL)
|
|
|
|
return bms_is_empty(a) ? BMS_EQUAL : BMS_SUBSET2;
|
|
|
|
/* Check common words */
|
|
|
|
result = BMS_EQUAL; /* status so far */
|
|
|
|
shortlen = Min(a->nwords, b->nwords);
|
|
|
|
for (i = 0; i < shortlen; i++)
|
|
|
|
{
|
2012-06-10 21:20:04 +02:00
|
|
|
bitmapword aword = a->words[i];
|
|
|
|
bitmapword bword = b->words[i];
|
2012-01-28 01:26:38 +01:00
|
|
|
|
|
|
|
if ((aword & ~bword) != 0)
|
|
|
|
{
|
|
|
|
/* a is not a subset of b */
|
|
|
|
if (result == BMS_SUBSET1)
|
|
|
|
return BMS_DIFFERENT;
|
|
|
|
result = BMS_SUBSET2;
|
|
|
|
}
|
|
|
|
if ((bword & ~aword) != 0)
|
|
|
|
{
|
|
|
|
/* b is not a subset of a */
|
|
|
|
if (result == BMS_SUBSET2)
|
|
|
|
return BMS_DIFFERENT;
|
|
|
|
result = BMS_SUBSET1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Check extra words */
|
|
|
|
if (a->nwords > b->nwords)
|
|
|
|
{
|
|
|
|
longlen = a->nwords;
|
|
|
|
for (; i < longlen; i++)
|
|
|
|
{
|
|
|
|
if (a->words[i] != 0)
|
|
|
|
{
|
|
|
|
/* a is not a subset of b */
|
|
|
|
if (result == BMS_SUBSET1)
|
|
|
|
return BMS_DIFFERENT;
|
|
|
|
result = BMS_SUBSET2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (a->nwords < b->nwords)
|
|
|
|
{
|
|
|
|
longlen = b->nwords;
|
|
|
|
for (; i < longlen; i++)
|
|
|
|
{
|
|
|
|
if (b->words[i] != 0)
|
|
|
|
{
|
|
|
|
/* b is not a subset of a */
|
|
|
|
if (result == BMS_SUBSET2)
|
|
|
|
return BMS_DIFFERENT;
|
|
|
|
result = BMS_SUBSET1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2003-02-08 21:20:55 +01:00
|
|
|
/*
|
|
|
|
* bms_is_member - is X a member of A?
|
|
|
|
*/
|
|
|
|
bool
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_is_member(int x, const Bitmapset *a)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
int wordnum,
|
|
|
|
bitnum;
|
|
|
|
|
|
|
|
/* XXX better to just return false for x<0 ? */
|
|
|
|
if (x < 0)
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(ERROR, "negative bitmapset member not allowed");
|
2003-02-08 21:20:55 +01:00
|
|
|
if (a == NULL)
|
|
|
|
return false;
|
|
|
|
wordnum = WORDNUM(x);
|
|
|
|
bitnum = BITNUM(x);
|
|
|
|
if (wordnum >= a->nwords)
|
|
|
|
return false;
|
|
|
|
if ((a->words[wordnum] & ((bitmapword) 1 << bitnum)) != 0)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
Add support for multivariate MCV lists
Introduce a third extended statistic type, supported by the CREATE
STATISTICS command - MCV lists, a generalization of the statistic
already built and used for individual columns.
Compared to the already supported types (n-distinct coefficients and
functional dependencies), MCV lists are more complex, include column
values and allow estimation of much wider range of common clauses
(equality and inequality conditions, IS NULL, IS NOT NULL etc.).
Similarly to the other types, a new pseudo-type (pg_mcv_list) is used.
Author: Tomas Vondra
Reviewed-by: Dean Rasheed, David Rowley, Mark Dilger, Alvaro Herrera
Discussion: https://postgr.es/m/dfdac334-9cf2-2597-fb27-f0fb3753f435@2ndquadrant.com
2019-03-27 18:32:18 +01:00
|
|
|
/*
|
|
|
|
* bms_member_index
|
|
|
|
* determine 0-based index of member x in the bitmap
|
|
|
|
*
|
|
|
|
* Returns (-1) when x is not a member.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
bms_member_index(Bitmapset *a, int x)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int bitnum;
|
|
|
|
int wordnum;
|
|
|
|
int result = 0;
|
|
|
|
bitmapword mask;
|
|
|
|
|
|
|
|
/* return -1 if not a member of the bitmap */
|
|
|
|
if (!bms_is_member(x, a))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
wordnum = WORDNUM(x);
|
|
|
|
bitnum = BITNUM(x);
|
|
|
|
|
|
|
|
/* count bits in preceding words */
|
|
|
|
for (i = 0; i < wordnum; i++)
|
|
|
|
{
|
|
|
|
bitmapword w = a->words[i];
|
|
|
|
|
|
|
|
/* No need to count the bits in a zero word */
|
|
|
|
if (w != 0)
|
|
|
|
result += bmw_popcount(w);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2019-05-22 18:55:34 +02:00
|
|
|
* Now add bits of the last word, but only those before the item. We can
|
|
|
|
* do that by applying a mask and then using popcount again. To get
|
|
|
|
* 0-based index, we want to count only preceding bits, not the item
|
|
|
|
* itself, so we subtract 1.
|
Add support for multivariate MCV lists
Introduce a third extended statistic type, supported by the CREATE
STATISTICS command - MCV lists, a generalization of the statistic
already built and used for individual columns.
Compared to the already supported types (n-distinct coefficients and
functional dependencies), MCV lists are more complex, include column
values and allow estimation of much wider range of common clauses
(equality and inequality conditions, IS NULL, IS NOT NULL etc.).
Similarly to the other types, a new pseudo-type (pg_mcv_list) is used.
Author: Tomas Vondra
Reviewed-by: Dean Rasheed, David Rowley, Mark Dilger, Alvaro Herrera
Discussion: https://postgr.es/m/dfdac334-9cf2-2597-fb27-f0fb3753f435@2ndquadrant.com
2019-03-27 18:32:18 +01:00
|
|
|
*/
|
|
|
|
mask = ((bitmapword) 1 << bitnum) - 1;
|
|
|
|
result += bmw_popcount(a->words[wordnum] & mask);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2003-02-08 21:20:55 +01:00
|
|
|
/*
|
|
|
|
* bms_overlap - do sets overlap (ie, have a nonempty intersection)?
|
|
|
|
*/
|
|
|
|
bool
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_overlap(const Bitmapset *a, const Bitmapset *b)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
int shortlen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Handle cases where either input is NULL */
|
|
|
|
if (a == NULL || b == NULL)
|
|
|
|
return false;
|
|
|
|
/* Check words in common */
|
|
|
|
shortlen = Min(a->nwords, b->nwords);
|
|
|
|
for (i = 0; i < shortlen; i++)
|
|
|
|
{
|
|
|
|
if ((a->words[i] & b->words[i]) != 0)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-03-27 05:20:54 +02:00
|
|
|
/*
|
|
|
|
* bms_overlap_list - does a set overlap an integer list?
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
bms_overlap_list(const Bitmapset *a, const List *b)
|
|
|
|
{
|
|
|
|
ListCell *lc;
|
|
|
|
int wordnum,
|
|
|
|
bitnum;
|
|
|
|
|
|
|
|
if (a == NULL || b == NIL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
foreach(lc, b)
|
|
|
|
{
|
|
|
|
int x = lfirst_int(lc);
|
|
|
|
|
|
|
|
if (x < 0)
|
|
|
|
elog(ERROR, "negative bitmapset member not allowed");
|
|
|
|
wordnum = WORDNUM(x);
|
|
|
|
bitnum = BITNUM(x);
|
|
|
|
if (wordnum < a->nwords)
|
|
|
|
if ((a->words[wordnum] & ((bitmapword) 1 << bitnum)) != 0)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2003-06-30 01:05:05 +02:00
|
|
|
/*
|
|
|
|
* bms_nonempty_difference - do sets have a nonempty difference?
|
|
|
|
*/
|
|
|
|
bool
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
|
2003-06-30 01:05:05 +02:00
|
|
|
{
|
|
|
|
int shortlen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Handle cases where either input is NULL */
|
|
|
|
if (a == NULL)
|
|
|
|
return false;
|
|
|
|
if (b == NULL)
|
|
|
|
return !bms_is_empty(a);
|
|
|
|
/* Check words in common */
|
|
|
|
shortlen = Min(a->nwords, b->nwords);
|
|
|
|
for (i = 0; i < shortlen; i++)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
if ((a->words[i] & ~b->words[i]) != 0)
|
2003-06-30 01:05:05 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
/* Check extra words in a */
|
|
|
|
for (; i < a->nwords; i++)
|
|
|
|
{
|
|
|
|
if (a->words[i] != 0)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2003-02-08 21:20:55 +01:00
|
|
|
/*
|
|
|
|
* bms_singleton_member - return the sole integer member of set
|
|
|
|
*
|
|
|
|
* Raises error if |a| is not 1.
|
|
|
|
*/
|
|
|
|
int
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_singleton_member(const Bitmapset *a)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
int result = -1;
|
|
|
|
int nwords;
|
|
|
|
int wordnum;
|
2003-02-08 21:20:55 +01:00
|
|
|
|
|
|
|
if (a == NULL)
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(ERROR, "bitmapset is empty");
|
2003-02-08 21:20:55 +01:00
|
|
|
nwords = a->nwords;
|
|
|
|
for (wordnum = 0; wordnum < nwords; wordnum++)
|
|
|
|
{
|
|
|
|
bitmapword w = a->words[wordnum];
|
|
|
|
|
|
|
|
if (w != 0)
|
|
|
|
{
|
|
|
|
if (result >= 0 || HAS_MULTIPLE_ONES(w))
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(ERROR, "bitmapset has multiple members");
|
2003-02-08 21:20:55 +01:00
|
|
|
result = wordnum * BITS_PER_BITMAPWORD;
|
Make use of compiler builtins and/or assembly for CLZ, CTZ, POPCNT.
Test for the compiler builtins __builtin_clz, __builtin_ctz, and
__builtin_popcount, and make use of these in preference to
handwritten C code if they're available. Create src/port
infrastructure for "leftmost one", "rightmost one", and "popcount"
so as to centralize these decisions.
On x86_64, __builtin_popcount generally won't make use of the POPCNT
opcode because that's not universally supported yet. Provide code
that checks CPUID and then calls POPCNT via asm() if available.
This requires indirecting through a function pointer, which is
an annoying amount of overhead for a one-instruction operation,
but it's probably not worth working harder than this for our
current use-cases.
I'm not sure we've found all the existing places that could profit
from this new infrastructure; but we at least touched all the
ones that used copied-and-pasted versions of the bitmapset.c code,
and got rid of multiple copies of the associated constant arrays.
While at it, replace c-compiler.m4's one-per-builtin-function
macros with a single one that can handle all the cases we need
to worry about so far. Also, because I'm paranoid, make those
checks into AC_LINK checks rather than just AC_COMPILE; the
former coding failed to verify that libgcc has support for the
builtin, in cases where it's not inline code.
David Rowley, Thomas Munro, Alvaro Herrera, Tom Lane
Discussion: https://postgr.es/m/CAKJS1f9WTAGG1tPeJnD18hiQW5gAk59fQ6WK-vfdAKEHyRg2RA@mail.gmail.com
2019-02-16 05:22:27 +01:00
|
|
|
result += bmw_rightmost_one_pos(w);
|
2003-02-08 21:20:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (result < 0)
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(ERROR, "bitmapset is empty");
|
2003-02-08 21:20:55 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-11-28 20:16:24 +01:00
|
|
|
/*
|
|
|
|
* bms_get_singleton_member
|
|
|
|
*
|
|
|
|
* Test whether the given set is a singleton.
|
2017-08-16 06:22:32 +02:00
|
|
|
* If so, set *member to the value of its sole member, and return true.
|
|
|
|
* If not, return false, without changing *member.
|
2014-11-28 20:16:24 +01:00
|
|
|
*
|
|
|
|
* 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;
|
Make use of compiler builtins and/or assembly for CLZ, CTZ, POPCNT.
Test for the compiler builtins __builtin_clz, __builtin_ctz, and
__builtin_popcount, and make use of these in preference to
handwritten C code if they're available. Create src/port
infrastructure for "leftmost one", "rightmost one", and "popcount"
so as to centralize these decisions.
On x86_64, __builtin_popcount generally won't make use of the POPCNT
opcode because that's not universally supported yet. Provide code
that checks CPUID and then calls POPCNT via asm() if available.
This requires indirecting through a function pointer, which is
an annoying amount of overhead for a one-instruction operation,
but it's probably not worth working harder than this for our
current use-cases.
I'm not sure we've found all the existing places that could profit
from this new infrastructure; but we at least touched all the
ones that used copied-and-pasted versions of the bitmapset.c code,
and got rid of multiple copies of the associated constant arrays.
While at it, replace c-compiler.m4's one-per-builtin-function
macros with a single one that can handle all the cases we need
to worry about so far. Also, because I'm paranoid, make those
checks into AC_LINK checks rather than just AC_COMPILE; the
former coding failed to verify that libgcc has support for the
builtin, in cases where it's not inline code.
David Rowley, Thomas Munro, Alvaro Herrera, Tom Lane
Discussion: https://postgr.es/m/CAKJS1f9WTAGG1tPeJnD18hiQW5gAk59fQ6WK-vfdAKEHyRg2RA@mail.gmail.com
2019-02-16 05:22:27 +01:00
|
|
|
result += bmw_rightmost_one_pos(w);
|
2014-11-28 20:16:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (result < 0)
|
|
|
|
return false;
|
|
|
|
*member = result;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-02-08 21:20:55 +01:00
|
|
|
/*
|
|
|
|
* bms_num_members - count members of set
|
|
|
|
*/
|
|
|
|
int
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_num_members(const Bitmapset *a)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
int result = 0;
|
|
|
|
int nwords;
|
|
|
|
int wordnum;
|
2003-02-08 21:20:55 +01:00
|
|
|
|
|
|
|
if (a == NULL)
|
|
|
|
return 0;
|
|
|
|
nwords = a->nwords;
|
|
|
|
for (wordnum = 0; wordnum < nwords; wordnum++)
|
|
|
|
{
|
|
|
|
bitmapword w = a->words[wordnum];
|
|
|
|
|
Make use of compiler builtins and/or assembly for CLZ, CTZ, POPCNT.
Test for the compiler builtins __builtin_clz, __builtin_ctz, and
__builtin_popcount, and make use of these in preference to
handwritten C code if they're available. Create src/port
infrastructure for "leftmost one", "rightmost one", and "popcount"
so as to centralize these decisions.
On x86_64, __builtin_popcount generally won't make use of the POPCNT
opcode because that's not universally supported yet. Provide code
that checks CPUID and then calls POPCNT via asm() if available.
This requires indirecting through a function pointer, which is
an annoying amount of overhead for a one-instruction operation,
but it's probably not worth working harder than this for our
current use-cases.
I'm not sure we've found all the existing places that could profit
from this new infrastructure; but we at least touched all the
ones that used copied-and-pasted versions of the bitmapset.c code,
and got rid of multiple copies of the associated constant arrays.
While at it, replace c-compiler.m4's one-per-builtin-function
macros with a single one that can handle all the cases we need
to worry about so far. Also, because I'm paranoid, make those
checks into AC_LINK checks rather than just AC_COMPILE; the
former coding failed to verify that libgcc has support for the
builtin, in cases where it's not inline code.
David Rowley, Thomas Munro, Alvaro Herrera, Tom Lane
Discussion: https://postgr.es/m/CAKJS1f9WTAGG1tPeJnD18hiQW5gAk59fQ6WK-vfdAKEHyRg2RA@mail.gmail.com
2019-02-16 05:22:27 +01:00
|
|
|
/* No need to count the bits in a zero word */
|
|
|
|
if (w != 0)
|
|
|
|
result += bmw_popcount(w);
|
2003-02-08 21:20:55 +01:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bms_membership - does a set have zero, one, or multiple members?
|
|
|
|
*
|
|
|
|
* This is faster than making an exact count with bms_num_members().
|
|
|
|
*/
|
|
|
|
BMS_Membership
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_membership(const Bitmapset *a)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
BMS_Membership result = BMS_EMPTY_SET;
|
2003-08-04 02:43:34 +02:00
|
|
|
int nwords;
|
|
|
|
int wordnum;
|
2003-02-08 21:20:55 +01:00
|
|
|
|
|
|
|
if (a == NULL)
|
|
|
|
return BMS_EMPTY_SET;
|
|
|
|
nwords = a->nwords;
|
|
|
|
for (wordnum = 0; wordnum < nwords; wordnum++)
|
|
|
|
{
|
|
|
|
bitmapword w = a->words[wordnum];
|
|
|
|
|
|
|
|
if (w != 0)
|
|
|
|
{
|
|
|
|
if (result != BMS_EMPTY_SET || HAS_MULTIPLE_ONES(w))
|
|
|
|
return BMS_MULTIPLE;
|
|
|
|
result = BMS_SINGLETON;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bms_is_empty - is a set empty?
|
|
|
|
*
|
|
|
|
* This is even faster than bms_membership().
|
|
|
|
*/
|
|
|
|
bool
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_is_empty(const Bitmapset *a)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
int nwords;
|
|
|
|
int wordnum;
|
2003-02-08 21:20:55 +01:00
|
|
|
|
|
|
|
if (a == NULL)
|
|
|
|
return true;
|
|
|
|
nwords = a->nwords;
|
|
|
|
for (wordnum = 0; wordnum < nwords; wordnum++)
|
|
|
|
{
|
|
|
|
bitmapword w = a->words[wordnum];
|
|
|
|
|
|
|
|
if (w != 0)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* These operations all "recycle" their non-const inputs, ie, either
|
|
|
|
* return the modified input or pfree it if it can't hold the result.
|
|
|
|
*
|
|
|
|
* These should generally be used in the style
|
|
|
|
*
|
|
|
|
* foo = bms_add_member(foo, x);
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bms_add_member - add a specified member to set
|
|
|
|
*
|
|
|
|
* Input set is modified or recycled!
|
|
|
|
*/
|
|
|
|
Bitmapset *
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_add_member(Bitmapset *a, int x)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
int wordnum,
|
|
|
|
bitnum;
|
|
|
|
|
|
|
|
if (x < 0)
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(ERROR, "negative bitmapset member not allowed");
|
2003-02-08 21:20:55 +01:00
|
|
|
if (a == NULL)
|
|
|
|
return bms_make_singleton(x);
|
|
|
|
wordnum = WORDNUM(x);
|
|
|
|
bitnum = BITNUM(x);
|
2013-09-30 15:37:00 +02:00
|
|
|
|
|
|
|
/* enlarge the set if necessary */
|
2003-02-08 21:20:55 +01:00
|
|
|
if (wordnum >= a->nwords)
|
|
|
|
{
|
2013-09-30 15:37:00 +02:00
|
|
|
int oldnwords = a->nwords;
|
2003-02-08 21:20:55 +01:00
|
|
|
int i;
|
|
|
|
|
2013-09-30 15:37:00 +02:00
|
|
|
a = (Bitmapset *) repalloc(a, BITMAPSET_SIZE(wordnum + 1));
|
|
|
|
a->nwords = wordnum + 1;
|
|
|
|
/* zero out the enlarged portion */
|
|
|
|
for (i = oldnwords; i < a->nwords; i++)
|
|
|
|
a->words[i] = 0;
|
2003-02-08 21:20:55 +01:00
|
|
|
}
|
2013-09-30 15:37:00 +02:00
|
|
|
|
2003-02-08 21:20:55 +01:00
|
|
|
a->words[wordnum] |= ((bitmapword) 1 << bitnum);
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bms_del_member - remove a specified member from set
|
|
|
|
*
|
|
|
|
* No error if x is not currently a member of set
|
|
|
|
*
|
|
|
|
* Input set is modified in-place!
|
|
|
|
*/
|
|
|
|
Bitmapset *
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_del_member(Bitmapset *a, int x)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
int wordnum,
|
|
|
|
bitnum;
|
|
|
|
|
|
|
|
if (x < 0)
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(ERROR, "negative bitmapset member not allowed");
|
2003-02-08 21:20:55 +01:00
|
|
|
if (a == NULL)
|
|
|
|
return NULL;
|
|
|
|
wordnum = WORDNUM(x);
|
|
|
|
bitnum = BITNUM(x);
|
|
|
|
if (wordnum < a->nwords)
|
2003-08-04 02:43:34 +02:00
|
|
|
a->words[wordnum] &= ~((bitmapword) 1 << bitnum);
|
2003-02-08 21:20:55 +01:00
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bms_add_members - like bms_union, but left input is recycled
|
|
|
|
*/
|
|
|
|
Bitmapset *
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_add_members(Bitmapset *a, const Bitmapset *b)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
Bitmapset *result;
|
|
|
|
const Bitmapset *other;
|
|
|
|
int otherlen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Handle cases where either input is NULL */
|
|
|
|
if (a == NULL)
|
|
|
|
return bms_copy(b);
|
|
|
|
if (b == NULL)
|
|
|
|
return a;
|
|
|
|
/* Identify shorter and longer input; copy the longer one if needed */
|
|
|
|
if (a->nwords < b->nwords)
|
|
|
|
{
|
|
|
|
result = bms_copy(b);
|
|
|
|
other = a;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result = a;
|
|
|
|
other = b;
|
|
|
|
}
|
|
|
|
/* And union the shorter input into the result */
|
|
|
|
otherlen = other->nwords;
|
|
|
|
for (i = 0; i < otherlen; i++)
|
|
|
|
result->words[i] |= other->words[i];
|
|
|
|
if (result != a)
|
|
|
|
pfree(a);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-11-29 23:06:14 +01:00
|
|
|
/*
|
|
|
|
* bms_add_range
|
|
|
|
* Add members in the range of 'lower' to 'upper' to the set.
|
|
|
|
*
|
|
|
|
* Note this could also be done by calling bms_add_member in a loop, however,
|
2017-11-30 22:22:38 +01:00
|
|
|
* using this function will be faster when the range is large as we work at
|
|
|
|
* the bitmapword level rather than at bit level.
|
2017-11-29 23:06:14 +01:00
|
|
|
*/
|
|
|
|
Bitmapset *
|
|
|
|
bms_add_range(Bitmapset *a, int lower, int upper)
|
|
|
|
{
|
|
|
|
int lwordnum,
|
|
|
|
lbitnum,
|
|
|
|
uwordnum,
|
|
|
|
ushiftbits,
|
|
|
|
wordnum;
|
|
|
|
|
2018-07-30 23:18:42 +02:00
|
|
|
/* do nothing if nothing is called for, without further checking */
|
|
|
|
if (upper < lower)
|
|
|
|
return a;
|
|
|
|
|
2018-07-31 01:11:02 +02:00
|
|
|
if (lower < 0)
|
2017-11-29 23:06:14 +01:00
|
|
|
elog(ERROR, "negative bitmapset member not allowed");
|
|
|
|
uwordnum = WORDNUM(upper);
|
|
|
|
|
|
|
|
if (a == NULL)
|
|
|
|
{
|
|
|
|
a = (Bitmapset *) palloc0(BITMAPSET_SIZE(uwordnum + 1));
|
|
|
|
a->nwords = uwordnum + 1;
|
|
|
|
}
|
|
|
|
else if (uwordnum >= a->nwords)
|
|
|
|
{
|
|
|
|
int oldnwords = a->nwords;
|
|
|
|
int i;
|
|
|
|
|
2018-07-30 23:18:42 +02:00
|
|
|
/* ensure we have enough words to store the upper bit */
|
2017-11-29 23:06:14 +01:00
|
|
|
a = (Bitmapset *) repalloc(a, BITMAPSET_SIZE(uwordnum + 1));
|
|
|
|
a->nwords = uwordnum + 1;
|
|
|
|
/* zero out the enlarged portion */
|
|
|
|
for (i = oldnwords; i < a->nwords; i++)
|
|
|
|
a->words[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
wordnum = lwordnum = WORDNUM(lower);
|
|
|
|
|
|
|
|
lbitnum = BITNUM(lower);
|
|
|
|
ushiftbits = BITS_PER_BITMAPWORD - (BITNUM(upper) + 1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Special case when lwordnum is the same as uwordnum we must perform the
|
|
|
|
* upper and lower masking on the word.
|
|
|
|
*/
|
|
|
|
if (lwordnum == uwordnum)
|
|
|
|
{
|
|
|
|
a->words[lwordnum] |= ~(bitmapword) (((bitmapword) 1 << lbitnum) - 1)
|
Improve the heuristic for ordering child paths of a parallel append.
Commit ab7271677 introduced code that attempts to order the child
scans of a Parallel Append node in a way that will minimize execution
time, based on total cost and startup cost. However, it failed to
think hard about what to do when estimated costs are exactly equal;
a case that's particularly likely to occur when comparing on startup
cost. In such a case the ordering of the child paths would be left
to the whims of qsort, an algorithm that isn't even stable.
We can improve matters by applying the rule used elsewhere in the
planner: if total costs are equal, sort on startup cost, and
vice versa. When both cost estimates are exactly equal, rather
than letting qsort do something unpredictable, sort based on the
child paths' relids, which should typically result in sorting in
inheritance order. (The latter provision requires inventing a
qsort-style comparator for bitmapsets, but maybe we'll have use
for that for other reasons in future.)
This results in a few plan changes in the select_parallel test,
but those all look more reasonable than before, when the actual
underlying cost numbers are taken into account.
Discussion: https://postgr.es/m/4944.1515446989@sss.pgh.pa.us
2018-01-09 19:07:52 +01:00
|
|
|
& (~(bitmapword) 0) >> ushiftbits;
|
2017-11-29 23:06:14 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* turn on lbitnum and all bits left of it */
|
|
|
|
a->words[wordnum++] |= ~(bitmapword) (((bitmapword) 1 << lbitnum) - 1);
|
|
|
|
|
|
|
|
/* turn on all bits for any intermediate words */
|
|
|
|
while (wordnum < uwordnum)
|
|
|
|
a->words[wordnum++] = ~(bitmapword) 0;
|
|
|
|
|
|
|
|
/* turn on upper's bit and all bits right of it. */
|
|
|
|
a->words[uwordnum] |= (~(bitmapword) 0) >> ushiftbits;
|
|
|
|
}
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
2003-02-08 21:20:55 +01:00
|
|
|
/*
|
|
|
|
* bms_int_members - like bms_intersect, but left input is recycled
|
|
|
|
*/
|
|
|
|
Bitmapset *
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_int_members(Bitmapset *a, const Bitmapset *b)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
int shortlen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Handle cases where either input is NULL */
|
|
|
|
if (a == NULL)
|
|
|
|
return NULL;
|
|
|
|
if (b == NULL)
|
|
|
|
{
|
|
|
|
pfree(a);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* Intersect b into a; we need never copy */
|
|
|
|
shortlen = Min(a->nwords, b->nwords);
|
|
|
|
for (i = 0; i < shortlen; i++)
|
|
|
|
a->words[i] &= b->words[i];
|
|
|
|
for (; i < a->nwords; i++)
|
|
|
|
a->words[i] = 0;
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bms_del_members - like bms_difference, but left input is recycled
|
|
|
|
*/
|
|
|
|
Bitmapset *
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_del_members(Bitmapset *a, const Bitmapset *b)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
int shortlen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Handle cases where either input is NULL */
|
|
|
|
if (a == NULL)
|
|
|
|
return NULL;
|
|
|
|
if (b == NULL)
|
|
|
|
return a;
|
|
|
|
/* Remove b's bits from a; we need never copy */
|
|
|
|
shortlen = Min(a->nwords, b->nwords);
|
|
|
|
for (i = 0; i < shortlen; i++)
|
2003-08-04 02:43:34 +02:00
|
|
|
a->words[i] &= ~b->words[i];
|
2003-02-08 21:20:55 +01:00
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bms_join - like bms_union, but *both* inputs are recycled
|
|
|
|
*/
|
|
|
|
Bitmapset *
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_join(Bitmapset *a, Bitmapset *b)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
|
|
|
Bitmapset *result;
|
|
|
|
Bitmapset *other;
|
|
|
|
int otherlen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Handle cases where either input is NULL */
|
|
|
|
if (a == NULL)
|
|
|
|
return b;
|
|
|
|
if (b == NULL)
|
|
|
|
return a;
|
|
|
|
/* Identify shorter and longer input; use longer one as result */
|
|
|
|
if (a->nwords < b->nwords)
|
|
|
|
{
|
|
|
|
result = b;
|
|
|
|
other = a;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result = a;
|
|
|
|
other = b;
|
|
|
|
}
|
|
|
|
/* And union the shorter input into the result */
|
|
|
|
otherlen = other->nwords;
|
|
|
|
for (i = 0; i < otherlen; i++)
|
|
|
|
result->words[i] |= other->words[i];
|
|
|
|
if (other != result) /* pure paranoia */
|
|
|
|
pfree(other);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-11-28 19:37:25 +01:00
|
|
|
/*
|
2003-02-08 21:20:55 +01:00
|
|
|
* bms_first_member - find and remove first member of a set
|
|
|
|
*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Returns -1 if set is empty. NB: set is destructively modified!
|
2003-02-08 21:20:55 +01:00
|
|
|
*
|
|
|
|
* This is intended as support for iterating through the members of a set.
|
|
|
|
* The typical pattern is
|
|
|
|
*
|
2014-11-28 19:37:25 +01:00
|
|
|
* while ((x = bms_first_member(inputset)) >= 0)
|
2003-02-08 21:20:55 +01:00
|
|
|
* process member x;
|
2014-11-28 19:37:25 +01:00
|
|
|
*
|
|
|
|
* CAUTION: this destroys the content of "inputset". If the set must
|
|
|
|
* not be modified, use bms_next_member instead.
|
2003-02-08 21:20:55 +01:00
|
|
|
*/
|
|
|
|
int
|
2003-08-08 23:42:59 +02:00
|
|
|
bms_first_member(Bitmapset *a)
|
2003-02-08 21:20:55 +01:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
int nwords;
|
|
|
|
int wordnum;
|
2003-02-08 21:20:55 +01:00
|
|
|
|
|
|
|
if (a == NULL)
|
|
|
|
return -1;
|
|
|
|
nwords = a->nwords;
|
|
|
|
for (wordnum = 0; wordnum < nwords; wordnum++)
|
|
|
|
{
|
|
|
|
bitmapword w = a->words[wordnum];
|
|
|
|
|
|
|
|
if (w != 0)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
int result;
|
2003-02-08 21:20:55 +01:00
|
|
|
|
|
|
|
w = RIGHTMOST_ONE(w);
|
2003-08-04 02:43:34 +02:00
|
|
|
a->words[wordnum] &= ~w;
|
2003-02-08 21:20:55 +01:00
|
|
|
|
|
|
|
result = wordnum * BITS_PER_BITMAPWORD;
|
Make use of compiler builtins and/or assembly for CLZ, CTZ, POPCNT.
Test for the compiler builtins __builtin_clz, __builtin_ctz, and
__builtin_popcount, and make use of these in preference to
handwritten C code if they're available. Create src/port
infrastructure for "leftmost one", "rightmost one", and "popcount"
so as to centralize these decisions.
On x86_64, __builtin_popcount generally won't make use of the POPCNT
opcode because that's not universally supported yet. Provide code
that checks CPUID and then calls POPCNT via asm() if available.
This requires indirecting through a function pointer, which is
an annoying amount of overhead for a one-instruction operation,
but it's probably not worth working harder than this for our
current use-cases.
I'm not sure we've found all the existing places that could profit
from this new infrastructure; but we at least touched all the
ones that used copied-and-pasted versions of the bitmapset.c code,
and got rid of multiple copies of the associated constant arrays.
While at it, replace c-compiler.m4's one-per-builtin-function
macros with a single one that can handle all the cases we need
to worry about so far. Also, because I'm paranoid, make those
checks into AC_LINK checks rather than just AC_COMPILE; the
former coding failed to verify that libgcc has support for the
builtin, in cases where it's not inline code.
David Rowley, Thomas Munro, Alvaro Herrera, Tom Lane
Discussion: https://postgr.es/m/CAKJS1f9WTAGG1tPeJnD18hiQW5gAk59fQ6WK-vfdAKEHyRg2RA@mail.gmail.com
2019-02-16 05:22:27 +01:00
|
|
|
result += bmw_rightmost_one_pos(w);
|
2003-02-08 21:20:55 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
2005-06-09 01:02:05 +02:00
|
|
|
|
2014-11-28 19:37:25 +01:00
|
|
|
/*
|
|
|
|
* bms_next_member - find next member of a set
|
|
|
|
*
|
|
|
|
* Returns smallest member greater than "prevbit", or -2 if there is none.
|
|
|
|
* "prevbit" must NOT be less than -1, or the behavior is unpredictable.
|
|
|
|
*
|
|
|
|
* This is intended as support for iterating through the members of a set.
|
|
|
|
* The typical pattern is
|
|
|
|
*
|
|
|
|
* x = -1;
|
|
|
|
* while ((x = bms_next_member(inputset, x)) >= 0)
|
|
|
|
* process member x;
|
|
|
|
*
|
|
|
|
* Notice that when there are no more members, we return -2, not -1 as you
|
|
|
|
* might expect. The rationale for that is to allow distinguishing the
|
|
|
|
* loop-not-started state (x == -1) from the loop-completed state (x == -2).
|
|
|
|
* It makes no difference in simple loop usage, but complex iteration logic
|
|
|
|
* might need such an ability.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
bms_next_member(const Bitmapset *a, int prevbit)
|
|
|
|
{
|
|
|
|
int nwords;
|
|
|
|
int wordnum;
|
|
|
|
bitmapword mask;
|
|
|
|
|
|
|
|
if (a == NULL)
|
|
|
|
return -2;
|
|
|
|
nwords = a->nwords;
|
|
|
|
prevbit++;
|
|
|
|
mask = (~(bitmapword) 0) << BITNUM(prevbit);
|
|
|
|
for (wordnum = WORDNUM(prevbit); wordnum < nwords; wordnum++)
|
|
|
|
{
|
|
|
|
bitmapword w = a->words[wordnum];
|
|
|
|
|
|
|
|
/* ignore bits before prevbit */
|
|
|
|
w &= mask;
|
|
|
|
|
|
|
|
if (w != 0)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
|
|
|
result = wordnum * BITS_PER_BITMAPWORD;
|
Make use of compiler builtins and/or assembly for CLZ, CTZ, POPCNT.
Test for the compiler builtins __builtin_clz, __builtin_ctz, and
__builtin_popcount, and make use of these in preference to
handwritten C code if they're available. Create src/port
infrastructure for "leftmost one", "rightmost one", and "popcount"
so as to centralize these decisions.
On x86_64, __builtin_popcount generally won't make use of the POPCNT
opcode because that's not universally supported yet. Provide code
that checks CPUID and then calls POPCNT via asm() if available.
This requires indirecting through a function pointer, which is
an annoying amount of overhead for a one-instruction operation,
but it's probably not worth working harder than this for our
current use-cases.
I'm not sure we've found all the existing places that could profit
from this new infrastructure; but we at least touched all the
ones that used copied-and-pasted versions of the bitmapset.c code,
and got rid of multiple copies of the associated constant arrays.
While at it, replace c-compiler.m4's one-per-builtin-function
macros with a single one that can handle all the cases we need
to worry about so far. Also, because I'm paranoid, make those
checks into AC_LINK checks rather than just AC_COMPILE; the
former coding failed to verify that libgcc has support for the
builtin, in cases where it's not inline code.
David Rowley, Thomas Munro, Alvaro Herrera, Tom Lane
Discussion: https://postgr.es/m/CAKJS1f9WTAGG1tPeJnD18hiQW5gAk59fQ6WK-vfdAKEHyRg2RA@mail.gmail.com
2019-02-16 05:22:27 +01:00
|
|
|
result += bmw_rightmost_one_pos(w);
|
2014-11-28 19:37:25 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* in subsequent words, consider all bits */
|
|
|
|
mask = (~(bitmapword) 0);
|
|
|
|
}
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
2018-04-07 17:01:11 +02:00
|
|
|
/*
|
|
|
|
* bms_prev_member - find prev member of a set
|
|
|
|
*
|
|
|
|
* Returns largest member less than "prevbit", or -2 if there is none.
|
|
|
|
* "prevbit" must NOT be more than one above the highest possible bit that can
|
|
|
|
* be set at the Bitmapset at its current size.
|
|
|
|
*
|
|
|
|
* To ease finding the highest set bit for the initial loop, the special
|
|
|
|
* prevbit value of -1 can be passed to have the function find the highest
|
|
|
|
* valued member in the set.
|
|
|
|
*
|
|
|
|
* This is intended as support for iterating through the members of a set in
|
|
|
|
* reverse. The typical pattern is
|
|
|
|
*
|
|
|
|
* x = -1;
|
|
|
|
* while ((x = bms_prev_member(inputset, x)) >= 0)
|
|
|
|
* process member x;
|
|
|
|
*
|
|
|
|
* Notice that when there are no more members, we return -2, not -1 as you
|
|
|
|
* might expect. The rationale for that is to allow distinguishing the
|
|
|
|
* loop-not-started state (x == -1) from the loop-completed state (x == -2).
|
|
|
|
* It makes no difference in simple loop usage, but complex iteration logic
|
|
|
|
* might need such an ability.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
bms_prev_member(const Bitmapset *a, int prevbit)
|
|
|
|
{
|
|
|
|
int wordnum;
|
|
|
|
int ushiftbits;
|
|
|
|
bitmapword mask;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If set is NULL or if there are no more bits to the right then we've
|
|
|
|
* nothing to do.
|
|
|
|
*/
|
|
|
|
if (a == NULL || prevbit == 0)
|
|
|
|
return -2;
|
|
|
|
|
|
|
|
/* transform -1 to the highest possible bit we could have set */
|
|
|
|
if (prevbit == -1)
|
|
|
|
prevbit = a->nwords * BITS_PER_BITMAPWORD - 1;
|
|
|
|
else
|
|
|
|
prevbit--;
|
|
|
|
|
|
|
|
ushiftbits = BITS_PER_BITMAPWORD - (BITNUM(prevbit) + 1);
|
|
|
|
mask = (~(bitmapword) 0) >> ushiftbits;
|
|
|
|
for (wordnum = WORDNUM(prevbit); wordnum >= 0; wordnum--)
|
|
|
|
{
|
|
|
|
bitmapword w = a->words[wordnum];
|
|
|
|
|
|
|
|
/* mask out bits left of prevbit */
|
|
|
|
w &= mask;
|
|
|
|
|
|
|
|
if (w != 0)
|
|
|
|
{
|
|
|
|
int result;
|
2018-04-26 20:47:16 +02:00
|
|
|
|
2018-04-07 17:01:11 +02:00
|
|
|
result = wordnum * BITS_PER_BITMAPWORD;
|
Make use of compiler builtins and/or assembly for CLZ, CTZ, POPCNT.
Test for the compiler builtins __builtin_clz, __builtin_ctz, and
__builtin_popcount, and make use of these in preference to
handwritten C code if they're available. Create src/port
infrastructure for "leftmost one", "rightmost one", and "popcount"
so as to centralize these decisions.
On x86_64, __builtin_popcount generally won't make use of the POPCNT
opcode because that's not universally supported yet. Provide code
that checks CPUID and then calls POPCNT via asm() if available.
This requires indirecting through a function pointer, which is
an annoying amount of overhead for a one-instruction operation,
but it's probably not worth working harder than this for our
current use-cases.
I'm not sure we've found all the existing places that could profit
from this new infrastructure; but we at least touched all the
ones that used copied-and-pasted versions of the bitmapset.c code,
and got rid of multiple copies of the associated constant arrays.
While at it, replace c-compiler.m4's one-per-builtin-function
macros with a single one that can handle all the cases we need
to worry about so far. Also, because I'm paranoid, make those
checks into AC_LINK checks rather than just AC_COMPILE; the
former coding failed to verify that libgcc has support for the
builtin, in cases where it's not inline code.
David Rowley, Thomas Munro, Alvaro Herrera, Tom Lane
Discussion: https://postgr.es/m/CAKJS1f9WTAGG1tPeJnD18hiQW5gAk59fQ6WK-vfdAKEHyRg2RA@mail.gmail.com
2019-02-16 05:22:27 +01:00
|
|
|
result += bmw_leftmost_one_pos(w);
|
2018-04-07 17:01:11 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* in subsequent words, consider all bits */
|
|
|
|
mask = (~(bitmapword) 0);
|
|
|
|
}
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
2005-06-09 01:02:05 +02:00
|
|
|
/*
|
|
|
|
* bms_hash_value - compute a hash key for a Bitmapset
|
|
|
|
*
|
|
|
|
* Note: we must ensure that any two bitmapsets that are bms_equal() will
|
|
|
|
* hash to the same value; in practice this means that trailing all-zero
|
2007-06-01 17:33:19 +02:00
|
|
|
* words must not affect the result. Hence we strip those before applying
|
|
|
|
* hash_any().
|
2005-06-09 01:02:05 +02:00
|
|
|
*/
|
|
|
|
uint32
|
|
|
|
bms_hash_value(const Bitmapset *a)
|
|
|
|
{
|
2007-06-01 17:33:19 +02:00
|
|
|
int lastword;
|
2005-06-09 01:02:05 +02:00
|
|
|
|
2007-06-01 17:33:19 +02:00
|
|
|
if (a == NULL)
|
2005-06-09 01:02:05 +02:00
|
|
|
return 0; /* All empty sets hash to 0 */
|
2007-06-01 17:33:19 +02:00
|
|
|
for (lastword = a->nwords; --lastword >= 0;)
|
2005-06-09 01:02:05 +02:00
|
|
|
{
|
2007-06-01 17:33:19 +02:00
|
|
|
if (a->words[lastword] != 0)
|
|
|
|
break;
|
2005-06-09 01:02:05 +02:00
|
|
|
}
|
2007-06-01 17:33:19 +02:00
|
|
|
if (lastword < 0)
|
|
|
|
return 0; /* All empty sets hash to 0 */
|
|
|
|
return DatumGetUInt32(hash_any((const unsigned char *) a->words,
|
|
|
|
(lastword + 1) * sizeof(bitmapword)));
|
2005-06-09 01:02:05 +02:00
|
|
|
}
|