mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
Replace planner's representation of relation sets, per pghackers discussion.
Instead of Lists of integers, we now store variable-length bitmap sets. This should be faster as well as less error-prone.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
# Makefile for backend/nodes
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/nodes/Makefile,v 1.13 2000/08/31 16:10:06 petere Exp $
|
||||
# $Header: /cvsroot/pgsql/src/backend/nodes/Makefile,v 1.14 2003/02/08 20:20:53 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@@ -12,7 +12,7 @@ subdir = src/backend/nodes
|
||||
top_builddir = ../../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
|
||||
OBJS = nodeFuncs.o nodes.o list.o \
|
||||
OBJS = nodeFuncs.o nodes.o list.o bitmapset.o \
|
||||
copyfuncs.o equalfuncs.o makefuncs.o \
|
||||
outfuncs.o readfuncs.o print.o read.o
|
||||
|
||||
|
||||
759
src/backend/nodes/bitmapset.c
Normal file
759
src/backend/nodes/bitmapset.c
Normal file
@@ -0,0 +1,759 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* 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.)
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2003, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/bitmapset.c,v 1.1 2003/02/08 20:20:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "nodes/bitmapset.h"
|
||||
|
||||
|
||||
#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
|
||||
* where each y is the inverse of the corresponding x. Incrementing gives
|
||||
* 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))
|
||||
|
||||
|
||||
/*
|
||||
* Lookup tables to avoid need for bit-by-bit groveling
|
||||
*
|
||||
* rightmost_one_pos[x] gives the bit number (0-7) of the rightmost one bit
|
||||
* in a nonzero byte value x. The entry for x=0 is never used.
|
||||
*
|
||||
* number_of_ones[x] gives the number of one-bits (0-8) in a byte value x.
|
||||
*
|
||||
* We could make these tables larger and reduce the number of iterations
|
||||
* in the functions that use them, but bytewise shifts and masks are
|
||||
* especially fast on many machines, so working a byte at a time seems best.
|
||||
*/
|
||||
|
||||
static const uint8 rightmost_one_pos[256] = {
|
||||
0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
|
||||
};
|
||||
|
||||
static const uint8 number_of_ones[256] = {
|
||||
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* bms_copy - make a palloc'd copy of a bitmapset
|
||||
*/
|
||||
Bitmapset *
|
||||
bms_copy(const Bitmapset *a)
|
||||
{
|
||||
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
|
||||
bms_equal(const Bitmapset *a, const Bitmapset *b)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* bms_make_singleton - build a bitmapset containing a single member
|
||||
*/
|
||||
Bitmapset *
|
||||
bms_make_singleton(int x)
|
||||
{
|
||||
Bitmapset *result;
|
||||
int wordnum,
|
||||
bitnum;
|
||||
|
||||
if (x < 0)
|
||||
elog(ERROR, "bms_make_singleton: negative set member not allowed");
|
||||
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
|
||||
bms_free(Bitmapset *a)
|
||||
{
|
||||
if (a)
|
||||
pfree(a);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* These operations all make a freshly palloc'd result,
|
||||
* leaving their inputs untouched
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* bms_union - set union
|
||||
*/
|
||||
Bitmapset *
|
||||
bms_union(const Bitmapset *a, const Bitmapset *b)
|
||||
{
|
||||
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 *
|
||||
bms_intersect(const Bitmapset *a, const Bitmapset *b)
|
||||
{
|
||||
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 *
|
||||
bms_difference(const Bitmapset *a, const Bitmapset *b)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
result->words[i] &= ~ b->words[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* bms_is_subset - is A a subset of B?
|
||||
*/
|
||||
bool
|
||||
bms_is_subset(const Bitmapset *a, const Bitmapset *b)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
if ((a->words[i] & ~ b->words[i]) != 0)
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* bms_is_member - is X a member of A?
|
||||
*/
|
||||
bool
|
||||
bms_is_member(int x, const Bitmapset *a)
|
||||
{
|
||||
int wordnum,
|
||||
bitnum;
|
||||
|
||||
/* XXX better to just return false for x<0 ? */
|
||||
if (x < 0)
|
||||
elog(ERROR, "bms_is_member: negative set member not allowed");
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* bms_overlap - do sets overlap (ie, have a nonempty intersection)?
|
||||
*/
|
||||
bool
|
||||
bms_overlap(const Bitmapset *a, const Bitmapset *b)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* bms_singleton_member - return the sole integer member of set
|
||||
*
|
||||
* Raises error if |a| is not 1.
|
||||
*/
|
||||
int
|
||||
bms_singleton_member(const Bitmapset *a)
|
||||
{
|
||||
int result = -1;
|
||||
int nwords;
|
||||
int wordnum;
|
||||
|
||||
if (a == NULL)
|
||||
elog(ERROR, "bms_singleton_member: set is empty");
|
||||
nwords = a->nwords;
|
||||
for (wordnum = 0; wordnum < nwords; wordnum++)
|
||||
{
|
||||
bitmapword w = a->words[wordnum];
|
||||
|
||||
if (w != 0)
|
||||
{
|
||||
if (result >= 0 || HAS_MULTIPLE_ONES(w))
|
||||
elog(ERROR, "bms_singleton_member: set has multiple members");
|
||||
result = wordnum * BITS_PER_BITMAPWORD;
|
||||
while ((w & 255) == 0)
|
||||
{
|
||||
w >>= 8;
|
||||
result += 8;
|
||||
}
|
||||
result += rightmost_one_pos[w & 255];
|
||||
}
|
||||
}
|
||||
if (result < 0)
|
||||
elog(ERROR, "bms_singleton_member: set is empty");
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* bms_num_members - count members of set
|
||||
*/
|
||||
int
|
||||
bms_num_members(const Bitmapset *a)
|
||||
{
|
||||
int result = 0;
|
||||
int nwords;
|
||||
int wordnum;
|
||||
|
||||
if (a == NULL)
|
||||
return 0;
|
||||
nwords = a->nwords;
|
||||
for (wordnum = 0; wordnum < nwords; wordnum++)
|
||||
{
|
||||
bitmapword w = a->words[wordnum];
|
||||
|
||||
/* we assume here that bitmapword is an unsigned type */
|
||||
while (w != 0)
|
||||
{
|
||||
result += number_of_ones[w & 255];
|
||||
w >>= 8;
|
||||
}
|
||||
}
|
||||
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
|
||||
bms_membership(const Bitmapset *a)
|
||||
{
|
||||
BMS_Membership result = BMS_EMPTY_SET;
|
||||
int nwords;
|
||||
int wordnum;
|
||||
|
||||
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
|
||||
bms_is_empty(const Bitmapset *a)
|
||||
{
|
||||
int nwords;
|
||||
int wordnum;
|
||||
|
||||
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 *
|
||||
bms_add_member(Bitmapset *a, int x)
|
||||
{
|
||||
int wordnum,
|
||||
bitnum;
|
||||
|
||||
if (x < 0)
|
||||
elog(ERROR, "bms_add_member: negative set member not allowed");
|
||||
if (a == NULL)
|
||||
return bms_make_singleton(x);
|
||||
wordnum = WORDNUM(x);
|
||||
bitnum = BITNUM(x);
|
||||
if (wordnum >= a->nwords)
|
||||
{
|
||||
/* Slow path: make a larger set and union the input set into it */
|
||||
Bitmapset *result;
|
||||
int nwords;
|
||||
int i;
|
||||
|
||||
result = bms_make_singleton(x);
|
||||
nwords = a->nwords;
|
||||
for (i = 0; i < nwords; i++)
|
||||
{
|
||||
result->words[i] |= a->words[i];
|
||||
}
|
||||
pfree(a);
|
||||
return result;
|
||||
}
|
||||
/* Fast path: x fits in existing set */
|
||||
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 *
|
||||
bms_del_member(Bitmapset *a, int x)
|
||||
{
|
||||
int wordnum,
|
||||
bitnum;
|
||||
|
||||
if (x < 0)
|
||||
elog(ERROR, "bms_del_member: negative set member not allowed");
|
||||
if (a == NULL)
|
||||
return NULL;
|
||||
wordnum = WORDNUM(x);
|
||||
bitnum = BITNUM(x);
|
||||
if (wordnum < a->nwords)
|
||||
{
|
||||
a->words[wordnum] &= ~ ((bitmapword) 1 << bitnum);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/*
|
||||
* bms_add_members - like bms_union, but left input is recycled
|
||||
*/
|
||||
Bitmapset *
|
||||
bms_add_members(Bitmapset *a, const Bitmapset *b)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* bms_int_members - like bms_intersect, but left input is recycled
|
||||
*/
|
||||
Bitmapset *
|
||||
bms_int_members(Bitmapset *a, const Bitmapset *b)
|
||||
{
|
||||
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 *
|
||||
bms_del_members(Bitmapset *a, const Bitmapset *b)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
a->words[i] &= ~ b->words[i];
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/*
|
||||
* bms_join - like bms_union, but *both* inputs are recycled
|
||||
*/
|
||||
Bitmapset *
|
||||
bms_join(Bitmapset *a, Bitmapset *b)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/*----------
|
||||
* bms_first_member - find and remove first member of a set
|
||||
*
|
||||
* Returns -1 if set is empty. NB: set is destructively modified!
|
||||
*
|
||||
* This is intended as support for iterating through the members of a set.
|
||||
* The typical pattern is
|
||||
*
|
||||
* tmpset = bms_copy(inputset);
|
||||
* while ((x = bms_first_member(tmpset)) >= 0)
|
||||
* {
|
||||
* process member x;
|
||||
* }
|
||||
* bms_free(tmpset);
|
||||
*----------
|
||||
*/
|
||||
int
|
||||
bms_first_member(Bitmapset *a)
|
||||
{
|
||||
int nwords;
|
||||
int wordnum;
|
||||
|
||||
if (a == NULL)
|
||||
return -1;
|
||||
nwords = a->nwords;
|
||||
for (wordnum = 0; wordnum < nwords; wordnum++)
|
||||
{
|
||||
bitmapword w = a->words[wordnum];
|
||||
|
||||
if (w != 0)
|
||||
{
|
||||
int result;
|
||||
|
||||
w = RIGHTMOST_ONE(w);
|
||||
a->words[wordnum] &= ~ w;
|
||||
|
||||
result = wordnum * BITS_PER_BITMAPWORD;
|
||||
while ((w & 255) == 0)
|
||||
{
|
||||
w >>= 8;
|
||||
result += 8;
|
||||
}
|
||||
result += rightmost_one_pos[w & 255];
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.239 2003/02/03 21:15:43 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.240 2003/02/08 20:20:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -47,6 +47,10 @@
|
||||
#define COPY_INTLIST_FIELD(fldname) \
|
||||
(newnode->fldname = listCopy(from->fldname))
|
||||
|
||||
/* Copy a field that is a pointer to a Bitmapset */
|
||||
#define COPY_BITMAPSET_FIELD(fldname) \
|
||||
(newnode->fldname = bms_copy(from->fldname))
|
||||
|
||||
/* Copy a field that is a pointer to a C string, or perhaps NULL */
|
||||
#define COPY_STRING_FIELD(fldname) \
|
||||
(newnode->fldname = from->fldname ? pstrdup(from->fldname) : (char *) NULL)
|
||||
@@ -1058,8 +1062,8 @@ _copyRestrictInfo(RestrictInfo *from)
|
||||
COPY_NODE_FIELD(subclauseindices); /* XXX probably bad */
|
||||
COPY_SCALAR_FIELD(eval_cost);
|
||||
COPY_SCALAR_FIELD(this_selec);
|
||||
COPY_INTLIST_FIELD(left_relids);
|
||||
COPY_INTLIST_FIELD(right_relids);
|
||||
COPY_BITMAPSET_FIELD(left_relids);
|
||||
COPY_BITMAPSET_FIELD(right_relids);
|
||||
COPY_SCALAR_FIELD(mergejoinoperator);
|
||||
COPY_SCALAR_FIELD(left_sortop);
|
||||
COPY_SCALAR_FIELD(right_sortop);
|
||||
@@ -1088,7 +1092,7 @@ _copyJoinInfo(JoinInfo *from)
|
||||
{
|
||||
JoinInfo *newnode = makeNode(JoinInfo);
|
||||
|
||||
COPY_INTLIST_FIELD(unjoined_relids);
|
||||
COPY_BITMAPSET_FIELD(unjoined_relids);
|
||||
COPY_NODE_FIELD(jinfo_restrictinfo);
|
||||
|
||||
return newnode;
|
||||
@@ -1102,8 +1106,8 @@ _copyInClauseInfo(InClauseInfo *from)
|
||||
{
|
||||
InClauseInfo *newnode = makeNode(InClauseInfo);
|
||||
|
||||
COPY_INTLIST_FIELD(lefthand);
|
||||
COPY_INTLIST_FIELD(righthand);
|
||||
COPY_BITMAPSET_FIELD(lefthand);
|
||||
COPY_BITMAPSET_FIELD(righthand);
|
||||
COPY_NODE_FIELD(sub_targetlist);
|
||||
|
||||
return newnode;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.183 2003/02/03 21:15:44 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.184 2003/02/08 20:20:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -59,6 +59,13 @@
|
||||
return false; \
|
||||
} while (0)
|
||||
|
||||
/* Compare a field that is a pointer to a Bitmapset */
|
||||
#define COMPARE_BITMAPSET_FIELD(fldname) \
|
||||
do { \
|
||||
if (!bms_equal(a->fldname, b->fldname)) \
|
||||
return false; \
|
||||
} while (0)
|
||||
|
||||
/* Compare a field that is a pointer to a C string, or perhaps NULL */
|
||||
#define COMPARE_STRING_FIELD(fldname) \
|
||||
do { \
|
||||
@@ -486,7 +493,7 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
|
||||
static bool
|
||||
_equalJoinInfo(JoinInfo *a, JoinInfo *b)
|
||||
{
|
||||
COMPARE_INTLIST_FIELD(unjoined_relids);
|
||||
COMPARE_BITMAPSET_FIELD(unjoined_relids);
|
||||
COMPARE_NODE_FIELD(jinfo_restrictinfo);
|
||||
|
||||
return true;
|
||||
@@ -495,8 +502,8 @@ _equalJoinInfo(JoinInfo *a, JoinInfo *b)
|
||||
static bool
|
||||
_equalInClauseInfo(InClauseInfo *a, InClauseInfo *b)
|
||||
{
|
||||
COMPARE_INTLIST_FIELD(lefthand);
|
||||
COMPARE_INTLIST_FIELD(righthand);
|
||||
COMPARE_BITMAPSET_FIELD(lefthand);
|
||||
COMPARE_BITMAPSET_FIELD(righthand);
|
||||
COMPARE_NODE_FIELD(sub_targetlist);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.46 2003/01/27 20:51:49 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.47 2003/02/08 20:20:54 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* XXX a few of the following functions are duplicated to handle
|
||||
@@ -248,21 +248,6 @@ llast(List *l)
|
||||
return lfirst(l);
|
||||
}
|
||||
|
||||
/*
|
||||
* llasti
|
||||
*
|
||||
* As above, but for integer lists
|
||||
*/
|
||||
int
|
||||
llasti(List *l)
|
||||
{
|
||||
if (l == NIL)
|
||||
elog(ERROR, "llasti: empty list");
|
||||
while (lnext(l) != NIL)
|
||||
l = lnext(l);
|
||||
return lfirsti(l);
|
||||
}
|
||||
|
||||
/*
|
||||
* freeList
|
||||
*
|
||||
@@ -304,35 +289,6 @@ equali(List *list1, List *list2)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* sameseti
|
||||
*
|
||||
* Returns t if two integer lists contain the same elements
|
||||
* (but unlike equali(), they need not be in the same order)
|
||||
*
|
||||
* Caution: this routine could be fooled if list1 contains
|
||||
* duplicate elements. It is intended to be used on lists
|
||||
* containing only nonduplicate elements, eg Relids lists.
|
||||
*/
|
||||
bool
|
||||
sameseti(List *list1, List *list2)
|
||||
{
|
||||
List *temp;
|
||||
|
||||
if (list1 == NIL)
|
||||
return list2 == NIL;
|
||||
if (list2 == NIL)
|
||||
return false;
|
||||
if (length(list1) != length(list2))
|
||||
return false;
|
||||
foreach(temp, list1)
|
||||
{
|
||||
if (!intMember(lfirsti(temp), list2))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate the union of two lists,
|
||||
* ie, l1 plus all members of l2 that are not already in l1.
|
||||
@@ -397,7 +353,6 @@ set_ptrUnion(List *l1, List *l2)
|
||||
* The result is a fresh List, but it points to the same member nodes
|
||||
* as were in the inputs.
|
||||
*/
|
||||
#ifdef NOT_USED
|
||||
List *
|
||||
set_intersect(List *l1, List *l2)
|
||||
{
|
||||
@@ -411,7 +366,6 @@ set_intersect(List *l1, List *l2)
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
List *
|
||||
set_intersecti(List *l1, List *l2)
|
||||
@@ -664,6 +618,7 @@ set_ptrDifference(List *l1, List *l2)
|
||||
/*
|
||||
* Reverse a list, non-destructively
|
||||
*/
|
||||
#ifdef NOT_USED
|
||||
List *
|
||||
lreverse(List *l)
|
||||
{
|
||||
@@ -674,39 +629,4 @@ lreverse(List *l)
|
||||
result = lcons(lfirst(i), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return t if two integer lists have any members in common.
|
||||
*/
|
||||
bool
|
||||
overlap_setsi(List *list1, List *list2)
|
||||
{
|
||||
List *x;
|
||||
|
||||
foreach(x, list1)
|
||||
{
|
||||
int e = lfirsti(x);
|
||||
|
||||
if (intMember(e, list2))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return t if all members of integer list list1 appear in list2.
|
||||
*/
|
||||
bool
|
||||
is_subseti(List *list1, List *list2)
|
||||
{
|
||||
List *x;
|
||||
|
||||
foreach(x, list1)
|
||||
{
|
||||
int e = lfirsti(x);
|
||||
|
||||
if (!intMember(e, list2))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.195 2003/02/03 21:15:44 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.196 2003/02/08 20:20:54 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Every node type that can appear in stored rules' parsetrees *must*
|
||||
@@ -96,6 +96,11 @@
|
||||
(appendStringInfo(str, " :" CppAsString(fldname) " "), \
|
||||
_outOidList(str, node->fldname))
|
||||
|
||||
/* Write a bitmapset field */
|
||||
#define WRITE_BITMAPSET_FIELD(fldname) \
|
||||
(appendStringInfo(str, " :" CppAsString(fldname) " "), \
|
||||
_outBitmapset(str, node->fldname))
|
||||
|
||||
|
||||
#define booltostr(x) ((x) ? "true" : "false")
|
||||
|
||||
@@ -172,6 +177,29 @@ _outOidList(StringInfo str, List *list)
|
||||
appendStringInfoChar(str, ')');
|
||||
}
|
||||
|
||||
/*
|
||||
* _outBitmapset -
|
||||
* converts a bitmap set of integers
|
||||
*
|
||||
* Note: for historical reasons, the output is formatted exactly like
|
||||
* an integer List would be.
|
||||
*/
|
||||
static void
|
||||
_outBitmapset(StringInfo str, Bitmapset *bms)
|
||||
{
|
||||
Bitmapset *tmpset;
|
||||
int x;
|
||||
|
||||
appendStringInfoChar(str, '(');
|
||||
tmpset = bms_copy(bms);
|
||||
while ((x = bms_first_member(tmpset)) >= 0)
|
||||
{
|
||||
appendStringInfo(str, " %d", x);
|
||||
}
|
||||
bms_free(tmpset);
|
||||
appendStringInfoChar(str, ')');
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the value of a Datum given its type.
|
||||
*/
|
||||
@@ -963,8 +991,8 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
|
||||
WRITE_NODE_FIELD(clause);
|
||||
WRITE_BOOL_FIELD(ispusheddown);
|
||||
WRITE_NODE_FIELD(subclauseindices);
|
||||
WRITE_INTLIST_FIELD(left_relids);
|
||||
WRITE_INTLIST_FIELD(right_relids);
|
||||
WRITE_BITMAPSET_FIELD(left_relids);
|
||||
WRITE_BITMAPSET_FIELD(right_relids);
|
||||
WRITE_OID_FIELD(mergejoinoperator);
|
||||
WRITE_OID_FIELD(left_sortop);
|
||||
WRITE_OID_FIELD(right_sortop);
|
||||
@@ -976,7 +1004,7 @@ _outJoinInfo(StringInfo str, JoinInfo *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("JOININFO");
|
||||
|
||||
WRITE_INTLIST_FIELD(unjoined_relids);
|
||||
WRITE_BITMAPSET_FIELD(unjoined_relids);
|
||||
WRITE_NODE_FIELD(jinfo_restrictinfo);
|
||||
}
|
||||
|
||||
@@ -985,8 +1013,8 @@ _outInClauseInfo(StringInfo str, InClauseInfo *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("INCLAUSEINFO");
|
||||
|
||||
WRITE_INTLIST_FIELD(lefthand);
|
||||
WRITE_INTLIST_FIELD(righthand);
|
||||
WRITE_BITMAPSET_FIELD(lefthand);
|
||||
WRITE_BITMAPSET_FIELD(righthand);
|
||||
WRITE_NODE_FIELD(sub_targetlist);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user