1/*-------------------------------------------------------------------------
4 * Test the Bitmapset data structure.
6 * This module tests the Bitmapset implementation in PostgreSQL, covering
7 * all public API functions.
9 * Copyright (c) 2025, PostgreSQL Global Development Group
12 * src/test/modules/test_bitmapset/test_bitmapset.c
14 *-------------------------------------------------------------------------
32/* Bitmapset API functions in order of appearance in bitmapset.c */
66/* Test utility functions */
69/* Convenient macros to test results */
70 #define EXPECT_TRUE(expr) \
74 "%s was unexpectedly false in file \"%s\" line %u", \
75 #expr, __FILE__, __LINE__); \
78 #define EXPECT_NOT_NULL(expr) \
82 "%s was unexpectedly true in file \"%s\" line %u", \
83 #expr, __FILE__, __LINE__); \
86/* Encode/Decode to/from TEXT and Bitmapset */
87 #define BITMAPSET_TO_TEXT(bms) cstring_to_text(nodeToString(bms))
88 #define TEXT_TO_BITMAPSET(str) ((Bitmapset *) stringToNode(text_to_cstring(str)))
91 * Helper macro to fetch text parameters as Bitmapsets. SQL-NULL means empty
94 #define PG_ARG_GETBITMAPSET(n) \
95 (PG_ARGISNULL(n) ? NULL : TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(n)))
98 * Helper macro to handle converting sets back to text, returning the
99 * resulting text representation of the set.
101 #define PG_RETURN_BITMAPSET_AS_TEXT(bms) \
102 PG_RETURN_TEXT_P(BITMAPSET_TO_TEXT(bms))
105 * Individual test functions for each bitmapset API function
107 * Primarily, we aim to keep these as close to simple wrapper functions as
108 * possible in order to publish the functions of bitmapset.c to the SQL layer
109 * with as little interference as possible. We opt to return SQL NULL in
110 * cases where the input given to the SQL function isn't valid to pass to the
111 * underlying bitmapset.c function. For example we cannot do much useful
112 * testing if someone calls test_bms_make_singleton(NULL) since
113 * bms_make_singleton() expects an integer argument.
115 * For function arguments which are to be converted to Bitmapsets, we accept
116 * SQL NULL as a valid argument to mean an empty set. Optionally callers may
119 * For the test functions which return a Bitmapset, these are converted back
120 * to text with result generated by nodeToString().
146 /* left input is recycled */
363 * Keep this simple. Return -1 when we detect the set is not a singleton
364 * set, otherwise return the singleton member.
409 Datum *elem_datums = NULL;
410 bool *elem_nulls = NULL;
421 INT4OID,
sizeof(
int32),
true,
'i',
422 &elem_datums, &elem_nulls, &elem_count);
424 for (
i = 0;
i < elem_count;
i++)
503 /* left input gets recycled */
515 /* left input gets recycled */
527 /* left input gets recycled */
540 /* either input can be recycled */
563 /* Call bitmap_hash */
576 /* Call bitmap_match with addresses of the Bitmapset pointers */
583 * Contrary to all the other functions which are one-one mappings with the
584 * equivalent C functions, this stresses Bitmapsets in a random fashion for
585 * various operations.
587 * "min_value" is the minimal value used for the members, that will stand
588 * up to a range of "max_range". "num_ops" defines the number of time each
589 * operation is done. "seed" is a random seed used to calculate the member
590 * values. When "seed" is <= 0, a random seed will be chosen automatically.
592 * The return value is the number of times all operations have been executed.
619 members =
palloc(
sizeof(
int) * num_ops);
621 /* Phase 1: Random insertions */
622 for (
int i = 0;
i < num_ops / 2;
i++)
628 members[num_members++] = member;
633 /* Phase 2: Random set operations */
634 for (
int i = 0;
i < num_ops / 4;
i++)
645 /* Verify union contains all members from first set */
646 for (
int i = 0;
i < num_members;
i++)
649 elog(
ERROR,
"union missing member %d", members[
i]);
653 /* Test intersection */
662 elog(
ERROR,
"intersection contains invalid member %d", member);
667 /* Phase 3: Test range operations */
669 for (
int i = 0;
i < num_ops;
i++)
686 for (
int i = 0;
i < num_ops;
i++)
700 case 2:
/* test membership */
#define PG_GETARG_ARRAYTYPE_P(n)
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
TimestampTz GetCurrentTimestamp(void)
Bitmapset * bms_replace_members(Bitmapset *a, const Bitmapset *b)
Bitmapset * bms_difference(const Bitmapset *a, const Bitmapset *b)
int bms_prev_member(const Bitmapset *a, int prevbit)
Bitmapset * bms_make_singleton(int x)
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Bitmapset * bms_intersect(const Bitmapset *a, const Bitmapset *b)
uint32 bitmap_hash(const void *key, Size keysize)
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
BMS_Comparison bms_subset_compare(const Bitmapset *a, const Bitmapset *b)
int bms_next_member(const Bitmapset *a, int prevbit)
uint32 bms_hash_value(const Bitmapset *a)
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Bitmapset * bms_add_range(Bitmapset *a, int lower, int upper)
Bitmapset * bms_del_member(Bitmapset *a, int x)
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
int bms_singleton_member(const Bitmapset *a)
void bms_free(Bitmapset *a)
int bms_num_members(const Bitmapset *a)
bool bms_is_member(int x, const Bitmapset *a)
Bitmapset * bms_add_member(Bitmapset *a, int x)
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
int bitmap_match(const void *key1, const void *key2, Size keysize)
BMS_Membership bms_membership(const Bitmapset *a)
int bms_member_index(Bitmapset *a, int x)
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
int bms_compare(const Bitmapset *a, const Bitmapset *b)
bool bms_get_singleton_member(const Bitmapset *a, int *member)
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
bool bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
Bitmapset * bms_copy(const Bitmapset *a)
bool bms_overlap_list(const Bitmapset *a, const List *b)
#define PG_RETURN_INT32(x)
#define PG_GETARG_INT32(n)
#define PG_RETURN_BOOL(x)
List * lappend_int(List *list, int datum)
void list_free(List *list)
void pfree(void *pointer)
Datum lower(PG_FUNCTION_ARGS)
Datum upper(PG_FUNCTION_ARGS)
uint32 pg_prng_uint32(pg_prng_state *state)
void pg_prng_seed(pg_prng_state *state, uint64 seed)
static int32 DatumGetInt32(Datum X)
Datum test_bms_compare(PG_FUNCTION_ARGS)
Datum test_bms_difference(PG_FUNCTION_ARGS)
Datum test_random_operations(PG_FUNCTION_ARGS)
#define PG_RETURN_BITMAPSET_AS_TEXT(bms)
Datum test_bms_hash_value(PG_FUNCTION_ARGS)
#define EXPECT_TRUE(expr)
Datum test_bms_del_member(PG_FUNCTION_ARGS)
Datum test_bitmap_match(PG_FUNCTION_ARGS)
Datum test_bms_is_member(PG_FUNCTION_ARGS)
#define PG_ARG_GETBITMAPSET(n)
Datum test_bms_is_empty(PG_FUNCTION_ARGS)
Datum test_bms_add_member(PG_FUNCTION_ARGS)
Datum test_bms_int_members(PG_FUNCTION_ARGS)
Datum test_bms_add_members(PG_FUNCTION_ARGS)
Datum test_bitmap_hash(PG_FUNCTION_ARGS)
Datum test_bms_member_index(PG_FUNCTION_ARGS)
Datum test_bms_singleton_member(PG_FUNCTION_ARGS)
Datum test_bms_overlap_list(PG_FUNCTION_ARGS)
Datum test_bms_subset_compare(PG_FUNCTION_ARGS)
Datum test_bms_overlap(PG_FUNCTION_ARGS)
Datum test_bms_join(PG_FUNCTION_ARGS)
#define EXPECT_NOT_NULL(expr)
Datum test_bms_prev_member(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(test_bms_make_singleton)
Datum test_bms_equal(PG_FUNCTION_ARGS)
Datum test_bms_add_range(PG_FUNCTION_ARGS)
Datum test_bms_copy(PG_FUNCTION_ARGS)
Datum test_bms_make_singleton(PG_FUNCTION_ARGS)
Datum test_bms_replace_members(PG_FUNCTION_ARGS)
Datum test_bms_get_singleton_member(PG_FUNCTION_ARGS)
Datum test_bms_num_members(PG_FUNCTION_ARGS)
Datum test_bms_next_member(PG_FUNCTION_ARGS)
Datum test_bms_membership(PG_FUNCTION_ARGS)
Datum test_bms_union(PG_FUNCTION_ARGS)
Datum test_bms_intersect(PG_FUNCTION_ARGS)
Datum test_bms_del_members(PG_FUNCTION_ARGS)
Datum test_bms_is_subset(PG_FUNCTION_ARGS)
Datum test_bms_nonempty_difference(PG_FUNCTION_ARGS)