LCOV - code coverage report
Current view: top level - src/test/modules/test_bitmapset - test_bitmapset.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 98.3 % 290 285
Test Date: 2026-02-28 15:14:49 Functions: 100.0 % 67 67
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * test_bitmapset.c
       4              :  *      Test the Bitmapset data structure.
       5              :  *
       6              :  * This module tests the Bitmapset implementation in PostgreSQL, covering
       7              :  * all public API functions.
       8              :  *
       9              :  * Copyright (c) 2025-2026, PostgreSQL Global Development Group
      10              :  *
      11              :  * IDENTIFICATION
      12              :  *      src/test/modules/test_bitmapset/test_bitmapset.c
      13              :  *
      14              :  *-------------------------------------------------------------------------
      15              :  */
      16              : 
      17              : #include "postgres.h"
      18              : 
      19              : #include <stddef.h>
      20              : #include "catalog/pg_type.h"
      21              : #include "common/pg_prng.h"
      22              : #include "utils/array.h"
      23              : #include "fmgr.h"
      24              : #include "nodes/bitmapset.h"
      25              : #include "nodes/nodes.h"
      26              : #include "nodes/pg_list.h"
      27              : #include "utils/builtins.h"
      28              : #include "utils/timestamp.h"
      29              : 
      30            1 : PG_MODULE_MAGIC;
      31              : 
      32              : /* Bitmapset API functions in order of appearance in bitmapset.c */
      33            2 : PG_FUNCTION_INFO_V1(test_bms_make_singleton);
      34            2 : PG_FUNCTION_INFO_V1(test_bms_add_member);
      35            2 : PG_FUNCTION_INFO_V1(test_bms_del_member);
      36            2 : PG_FUNCTION_INFO_V1(test_bms_is_member);
      37            2 : PG_FUNCTION_INFO_V1(test_bms_num_members);
      38            2 : PG_FUNCTION_INFO_V1(test_bms_copy);
      39            2 : PG_FUNCTION_INFO_V1(test_bms_equal);
      40            2 : PG_FUNCTION_INFO_V1(test_bms_compare);
      41            2 : PG_FUNCTION_INFO_V1(test_bms_is_subset);
      42            2 : PG_FUNCTION_INFO_V1(test_bms_subset_compare);
      43            2 : PG_FUNCTION_INFO_V1(test_bms_union);
      44            2 : PG_FUNCTION_INFO_V1(test_bms_intersect);
      45            2 : PG_FUNCTION_INFO_V1(test_bms_difference);
      46            2 : PG_FUNCTION_INFO_V1(test_bms_is_empty);
      47            2 : PG_FUNCTION_INFO_V1(test_bms_membership);
      48            2 : PG_FUNCTION_INFO_V1(test_bms_singleton_member);
      49            2 : PG_FUNCTION_INFO_V1(test_bms_get_singleton_member);
      50            2 : PG_FUNCTION_INFO_V1(test_bms_next_member);
      51            2 : PG_FUNCTION_INFO_V1(test_bms_prev_member);
      52            2 : PG_FUNCTION_INFO_V1(test_bms_hash_value);
      53            2 : PG_FUNCTION_INFO_V1(test_bms_overlap);
      54            2 : PG_FUNCTION_INFO_V1(test_bms_overlap_list);
      55            2 : PG_FUNCTION_INFO_V1(test_bms_nonempty_difference);
      56            2 : PG_FUNCTION_INFO_V1(test_bms_member_index);
      57            2 : PG_FUNCTION_INFO_V1(test_bms_add_range);
      58            2 : PG_FUNCTION_INFO_V1(test_bms_add_members);
      59            2 : PG_FUNCTION_INFO_V1(test_bms_int_members);
      60            2 : PG_FUNCTION_INFO_V1(test_bms_del_members);
      61            2 : PG_FUNCTION_INFO_V1(test_bms_replace_members);
      62            2 : PG_FUNCTION_INFO_V1(test_bms_join);
      63            2 : PG_FUNCTION_INFO_V1(test_bitmap_hash);
      64            2 : PG_FUNCTION_INFO_V1(test_bitmap_match);
      65              : 
      66              : /* Test utility functions */
      67            2 : PG_FUNCTION_INFO_V1(test_random_operations);
      68              : 
      69              : /* Convenient macros to test results */
      70              : #define EXPECT_TRUE(expr)   \
      71              :     do { \
      72              :         if (!(expr)) \
      73              :             elog(ERROR, \
      74              :                  "%s was unexpectedly false in file \"%s\" line %u", \
      75              :                  #expr, __FILE__, __LINE__); \
      76              :     } while (0)
      77              : 
      78              : #define EXPECT_NOT_NULL(expr)   \
      79              :     do { \
      80              :         if ((expr) == NULL) \
      81              :             elog(ERROR, \
      82              :                  "%s was unexpectedly true in file \"%s\" line %u", \
      83              :                  #expr, __FILE__, __LINE__); \
      84              :     } while (0)
      85              : 
      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)))
      89              : 
      90              : /*
      91              :  * Helper macro to fetch text parameters as Bitmapsets. SQL-NULL means empty
      92              :  * set.
      93              :  */
      94              : #define PG_ARG_GETBITMAPSET(n) \
      95              :     (PG_ARGISNULL(n) ? NULL : TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(n)))
      96              : 
      97              : /*
      98              :  * Helper macro to handle converting sets back to text, returning the
      99              :  * resulting text representation of the set.
     100              :  */
     101              : #define PG_RETURN_BITMAPSET_AS_TEXT(bms) \
     102              :     PG_RETURN_TEXT_P(BITMAPSET_TO_TEXT(bms))
     103              : 
     104              : /*
     105              :  * Individual test functions for each bitmapset API function
     106              :  *
     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.
     114              :  *
     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
     117              :  * pass '(b)'.
     118              :  *
     119              :  * For the test functions which return a Bitmapset, these are converted back
     120              :  * to text with result generated by nodeToString().
     121              :  */
     122              : 
     123              : Datum
     124            7 : test_bms_add_member(PG_FUNCTION_ARGS)
     125              : {
     126              :     Bitmapset  *bms;
     127              :     int         member;
     128              : 
     129            7 :     if (PG_ARGISNULL(1))
     130            1 :         PG_RETURN_NULL();       /* invalid input */
     131              : 
     132            6 :     bms = PG_ARG_GETBITMAPSET(0);
     133            6 :     member = PG_GETARG_INT32(1);
     134              : 
     135            6 :     bms = bms_add_member(bms, member);
     136              : 
     137            4 :     PG_RETURN_BITMAPSET_AS_TEXT(bms);
     138              : }
     139              : 
     140              : Datum
     141            3 : test_bms_add_members(PG_FUNCTION_ARGS)
     142              : {
     143            3 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     144            3 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     145              : 
     146              :     /* left input is recycled */
     147            3 :     bms1 = bms_add_members(bms1, bms2);
     148              : 
     149            3 :     PG_RETURN_BITMAPSET_AS_TEXT(bms1);
     150              : }
     151              : 
     152              : Datum
     153           12 : test_bms_del_member(PG_FUNCTION_ARGS)
     154              : {
     155              :     Bitmapset  *bms;
     156              :     int32       member;
     157              : 
     158           12 :     if (PG_ARGISNULL(1))
     159            1 :         PG_RETURN_NULL();       /* invalid input */
     160              : 
     161           11 :     bms = PG_ARG_GETBITMAPSET(0);
     162           11 :     member = PG_GETARG_INT32(1);
     163              : 
     164           11 :     bms = bms_del_member(bms, member);
     165              : 
     166           10 :     PG_RETURN_BITMAPSET_AS_TEXT(bms);
     167              : }
     168              : 
     169              : Datum
     170            6 : test_bms_is_member(PG_FUNCTION_ARGS)
     171              : {
     172              :     Bitmapset  *bms;
     173              :     int32       member;
     174              :     bool        result;
     175              : 
     176            6 :     if (PG_ARGISNULL(1))
     177            1 :         PG_RETURN_NULL();       /* invalid input */
     178              : 
     179            5 :     bms = PG_ARG_GETBITMAPSET(0);
     180            5 :     member = PG_GETARG_INT32(1);
     181              : 
     182            5 :     result = bms_is_member(member, bms);
     183              : 
     184            4 :     PG_RETURN_BOOL(result);
     185              : }
     186              : 
     187              : Datum
     188            3 : test_bms_num_members(PG_FUNCTION_ARGS)
     189              : {
     190            3 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     191              :     int         result;
     192              : 
     193            3 :     result = bms_num_members(bms);
     194              : 
     195            3 :     PG_RETURN_INT32(result);
     196              : }
     197              : 
     198              : Datum
     199            4 : test_bms_make_singleton(PG_FUNCTION_ARGS)
     200              : {
     201              :     Bitmapset  *bms;
     202              :     int32       member;
     203              : 
     204            4 :     member = PG_GETARG_INT32(0);
     205            4 :     bms = bms_make_singleton(member);
     206              : 
     207            3 :     PG_RETURN_BITMAPSET_AS_TEXT(bms);
     208              : }
     209              : 
     210              : Datum
     211            2 : test_bms_copy(PG_FUNCTION_ARGS)
     212              : {
     213            2 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     214              :     Bitmapset  *copy_bms;
     215              : 
     216            2 :     copy_bms = bms_copy(bms);
     217              : 
     218            2 :     PG_RETURN_BITMAPSET_AS_TEXT(copy_bms);
     219              : }
     220              : 
     221              : Datum
     222           13 : test_bms_equal(PG_FUNCTION_ARGS)
     223              : {
     224           13 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     225           13 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     226              :     bool        result;
     227              : 
     228           13 :     result = bms_equal(bms1, bms2);
     229              : 
     230           13 :     PG_RETURN_BOOL(result);
     231              : }
     232              : 
     233              : Datum
     234            9 : test_bms_union(PG_FUNCTION_ARGS)
     235              : {
     236            9 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     237            9 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     238              :     Bitmapset  *result_bms;
     239              : 
     240            9 :     result_bms = bms_union(bms1, bms2);
     241              : 
     242            9 :     PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
     243              : }
     244              : 
     245              : Datum
     246            4 : test_bms_membership(PG_FUNCTION_ARGS)
     247              : {
     248            4 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     249              :     BMS_Membership result;
     250              : 
     251            4 :     result = bms_membership(bms);
     252              : 
     253            4 :     PG_RETURN_INT32((int32) result);
     254              : }
     255              : 
     256              : Datum
     257            6 : test_bms_next_member(PG_FUNCTION_ARGS)
     258              : {
     259              :     Bitmapset  *bms;
     260              :     int32       prevmember;
     261              :     int         result;
     262              : 
     263            6 :     if (PG_ARGISNULL(1))
     264            1 :         PG_RETURN_NULL();       /* invalid input */
     265              : 
     266            5 :     bms = PG_ARG_GETBITMAPSET(0);
     267            5 :     prevmember = PG_GETARG_INT32(1);
     268              : 
     269            5 :     result = bms_next_member(bms, prevmember);
     270              : 
     271            5 :     PG_RETURN_INT32(result);
     272              : }
     273              : 
     274              : Datum
     275            8 : test_bms_intersect(PG_FUNCTION_ARGS)
     276              : {
     277            8 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     278            8 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     279              :     Bitmapset  *result_bms;
     280              : 
     281            8 :     result_bms = bms_intersect(bms1, bms2);
     282              : 
     283            8 :     PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
     284              : }
     285              : 
     286              : Datum
     287           10 : test_bms_difference(PG_FUNCTION_ARGS)
     288              : {
     289           10 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     290           10 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     291              :     Bitmapset  *result_bms;
     292              : 
     293           10 :     result_bms = bms_difference(bms1, bms2);
     294              : 
     295           10 :     PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
     296              : }
     297              : 
     298              : Datum
     299           10 : test_bms_compare(PG_FUNCTION_ARGS)
     300              : {
     301           10 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     302           10 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     303              :     int         result;
     304              : 
     305           10 :     result = bms_compare(bms1, bms2);
     306              : 
     307           10 :     PG_RETURN_INT32(result);
     308              : }
     309              : 
     310              : Datum
     311            3 : test_bms_is_empty(PG_FUNCTION_ARGS)
     312              : {
     313            3 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     314              :     bool        result;
     315              : 
     316            3 :     result = bms_is_empty(bms);
     317              : 
     318            3 :     PG_RETURN_BOOL(result);
     319              : }
     320              : 
     321              : Datum
     322           10 : test_bms_is_subset(PG_FUNCTION_ARGS)
     323              : {
     324           10 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     325           10 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     326              :     bool        result;
     327              : 
     328           10 :     result = bms_is_subset(bms1, bms2);
     329              : 
     330           10 :     PG_RETURN_BOOL(result);
     331              : }
     332              : 
     333              : Datum
     334           23 : test_bms_subset_compare(PG_FUNCTION_ARGS)
     335              : {
     336           23 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     337           23 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     338              :     BMS_Comparison result;
     339              : 
     340           23 :     result = bms_subset_compare(bms1, bms2);
     341              : 
     342           23 :     PG_RETURN_INT32((int32) result);
     343              : }
     344              : 
     345              : Datum
     346            3 : test_bms_singleton_member(PG_FUNCTION_ARGS)
     347              : {
     348            3 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     349              :     int         result;
     350              : 
     351            3 :     result = bms_singleton_member(bms);
     352              : 
     353            1 :     PG_RETURN_INT32(result);
     354              : }
     355              : 
     356              : Datum
     357            4 : test_bms_get_singleton_member(PG_FUNCTION_ARGS)
     358              : {
     359            4 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     360              :     int         member;
     361              : 
     362              :     /*
     363              :      * Keep this simple.  Return -1 when we detect the set is not a singleton
     364              :      * set, otherwise return the singleton member.
     365              :      */
     366            4 :     if (!bms_get_singleton_member(bms, &member))
     367            3 :         member = -1;
     368              : 
     369            4 :     PG_RETURN_INT32(member);
     370              : }
     371              : 
     372              : Datum
     373            7 : test_bms_prev_member(PG_FUNCTION_ARGS)
     374              : {
     375              :     Bitmapset  *bms;
     376              :     int32       prevmember;
     377              :     int         result;
     378              : 
     379            7 :     if (PG_ARGISNULL(1))
     380            1 :         PG_RETURN_NULL();       /* invalid input */
     381              : 
     382            6 :     bms = PG_ARG_GETBITMAPSET(0);
     383            6 :     prevmember = PG_GETARG_INT32(1);
     384              : 
     385            6 :     result = bms_prev_member(bms, prevmember);
     386              : 
     387            6 :     PG_RETURN_INT32(result);
     388              : }
     389              : 
     390              : Datum
     391            6 : test_bms_overlap(PG_FUNCTION_ARGS)
     392              : {
     393            6 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     394            6 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     395              :     bool        result;
     396              : 
     397            6 :     result = bms_overlap(bms1, bms2);
     398              : 
     399            6 :     PG_RETURN_BOOL(result);
     400              : }
     401              : 
     402              : Datum
     403           11 : test_bms_overlap_list(PG_FUNCTION_ARGS)
     404              : {
     405              :     Bitmapset  *bms;
     406              :     ArrayType  *array;
     407           11 :     List       *int_list = NIL;
     408              :     bool        result;
     409           11 :     Datum      *elem_datums = NULL;
     410           11 :     bool       *elem_nulls = NULL;
     411              :     int         elem_count;
     412              :     int         i;
     413              : 
     414           11 :     bms = PG_ARG_GETBITMAPSET(0);
     415              : 
     416           11 :     if (!PG_ARGISNULL(1))
     417              :     {
     418            9 :         array = PG_GETARG_ARRAYTYPE_P(1);
     419              : 
     420            9 :         deconstruct_array(array,
     421              :                           INT4OID, sizeof(int32), true, 'i',
     422              :                           &elem_datums, &elem_nulls, &elem_count);
     423              : 
     424           31 :         for (i = 0; i < elem_count; i++)
     425              :         {
     426           22 :             if (!elem_nulls[i])
     427              :             {
     428           22 :                 int32       member = DatumGetInt32(elem_datums[i]);
     429              : 
     430           22 :                 int_list = lappend_int(int_list, member);
     431              :             }
     432              :         }
     433              :     }
     434              : 
     435           11 :     result = bms_overlap_list(bms, int_list);
     436              : 
     437            9 :     list_free(int_list);
     438              : 
     439            9 :     if (elem_datums)
     440            7 :         pfree(elem_datums);
     441              : 
     442            9 :     if (elem_nulls)
     443            7 :         pfree(elem_nulls);
     444              : 
     445            9 :     PG_RETURN_BOOL(result);
     446              : }
     447              : 
     448              : Datum
     449            9 : test_bms_nonempty_difference(PG_FUNCTION_ARGS)
     450              : {
     451            9 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     452            9 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     453              :     bool        result;
     454              : 
     455            9 :     result = bms_nonempty_difference(bms1, bms2);
     456              : 
     457            9 :     PG_RETURN_BOOL(result);
     458              : }
     459              : 
     460              : Datum
     461            8 : test_bms_member_index(PG_FUNCTION_ARGS)
     462              : {
     463              :     Bitmapset  *bms;
     464              :     int32       member;
     465              :     int         result;
     466              : 
     467            8 :     if (PG_ARGISNULL(1))
     468            1 :         PG_RETURN_NULL();       /* invalid input */
     469              : 
     470            7 :     bms = PG_ARG_GETBITMAPSET(0);
     471            7 :     member = PG_GETARG_INT32(1);
     472              : 
     473            7 :     result = bms_member_index(bms, member);
     474              : 
     475            7 :     PG_RETURN_INT32(result);
     476              : }
     477              : 
     478              : Datum
     479           25 : test_bms_add_range(PG_FUNCTION_ARGS)
     480              : {
     481              :     Bitmapset  *bms;
     482              :     int32       lower,
     483              :                 upper;
     484              : 
     485           25 :     if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
     486            3 :         PG_RETURN_NULL();       /* invalid input */
     487              : 
     488           22 :     bms = PG_ARG_GETBITMAPSET(0);
     489           22 :     lower = PG_GETARG_INT32(1);
     490           22 :     upper = PG_GETARG_INT32(2);
     491              : 
     492           22 :     bms = bms_add_range(bms, lower, upper);
     493              : 
     494           21 :     PG_RETURN_BITMAPSET_AS_TEXT(bms);
     495              : }
     496              : 
     497              : Datum
     498            7 : test_bms_int_members(PG_FUNCTION_ARGS)
     499              : {
     500            7 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     501            7 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     502              : 
     503              :     /* left input gets recycled */
     504            7 :     bms1 = bms_int_members(bms1, bms2);
     505              : 
     506            7 :     PG_RETURN_BITMAPSET_AS_TEXT(bms1);
     507              : }
     508              : 
     509              : Datum
     510           10 : test_bms_del_members(PG_FUNCTION_ARGS)
     511              : {
     512           10 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     513           10 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     514              : 
     515              :     /* left input gets recycled */
     516           10 :     bms1 = bms_del_members(bms1, bms2);
     517              : 
     518           10 :     PG_RETURN_BITMAPSET_AS_TEXT(bms1);
     519              : }
     520              : 
     521              : Datum
     522            6 : test_bms_replace_members(PG_FUNCTION_ARGS)
     523              : {
     524            6 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     525            6 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     526              : 
     527              :     /* left input gets recycled */
     528            6 :     bms1 = bms_replace_members(bms1, bms2);
     529              : 
     530            6 :     PG_RETURN_BITMAPSET_AS_TEXT(bms1);
     531              : }
     532              : 
     533              : Datum
     534            9 : test_bms_join(PG_FUNCTION_ARGS)
     535              : {
     536            9 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     537            9 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     538              :     Bitmapset  *result_bms;
     539              : 
     540              :     /* either input can be recycled */
     541            9 :     result_bms = bms_join(bms1, bms2);
     542              : 
     543            9 :     PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
     544              : }
     545              : 
     546              : Datum
     547            7 : test_bms_hash_value(PG_FUNCTION_ARGS)
     548              : {
     549            7 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     550              :     uint32      hash_result;
     551              : 
     552            7 :     hash_result = bms_hash_value(bms);
     553              : 
     554            7 :     PG_RETURN_INT32(hash_result);
     555              : }
     556              : 
     557              : Datum
     558            7 : test_bitmap_hash(PG_FUNCTION_ARGS)
     559              : {
     560            7 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     561              :     uint32      hash_result;
     562              : 
     563              :     /* Call bitmap_hash */
     564            7 :     hash_result = bitmap_hash(&bms, sizeof(Bitmapset *));
     565              : 
     566            7 :     PG_RETURN_INT32(hash_result);
     567              : }
     568              : 
     569              : Datum
     570           12 : test_bitmap_match(PG_FUNCTION_ARGS)
     571              : {
     572           12 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     573           12 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     574              :     int         match_result;
     575              : 
     576              :     /* Call bitmap_match with addresses of the Bitmapset pointers */
     577           12 :     match_result = bitmap_match(&bms1, &bms2, sizeof(Bitmapset *));
     578              : 
     579           12 :     PG_RETURN_INT32(match_result);
     580              : }
     581              : 
     582              : /*
     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.
     586              :  *
     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.
     591              :  *
     592              :  * The return value is the number of times all operations have been executed.
     593              :  */
     594              : Datum
     595            1 : test_random_operations(PG_FUNCTION_ARGS)
     596              : {
     597            1 :     Bitmapset  *bms1 = NULL;
     598            1 :     Bitmapset  *bms2 = NULL;
     599            1 :     Bitmapset  *bms = NULL;
     600            1 :     Bitmapset  *result = NULL;
     601              :     pg_prng_state state;
     602            1 :     uint64      seed = GetCurrentTimestamp();
     603              :     int         num_ops;
     604              :     int         max_range;
     605              :     int         min_value;
     606              :     int         member;
     607              :     int        *members;
     608            1 :     int         num_members = 0;
     609            1 :     int         total_ops = 0;
     610              : 
     611            1 :     if (PG_GETARG_INT32(0) > 0)
     612            0 :         seed = PG_GETARG_INT32(0);
     613              : 
     614            1 :     num_ops = PG_GETARG_INT32(1);
     615            1 :     max_range = PG_GETARG_INT32(2);
     616            1 :     min_value = PG_GETARG_INT32(3);
     617              : 
     618            1 :     pg_prng_seed(&state, seed);
     619              : 
     620              :     /*
     621              :      * There can be up to "num_ops" members added.  This is very unlikely,
     622              :      * still possible if all the operations hit the "0" case during phase 4
     623              :      * where multiple operation types are mixed together.
     624              :      */
     625            1 :     members = palloc_array(int, num_ops);
     626              : 
     627              :     /* Phase 1: Random insertions in first set */
     628         5001 :     for (int i = 0; i < num_ops / 2; i++)
     629              :     {
     630         5000 :         member = pg_prng_uint32(&state) % max_range + min_value;
     631              : 
     632         5000 :         if (!bms_is_member(member, bms1))
     633         4875 :             members[num_members++] = member;
     634         5000 :         bms1 = bms_add_member(bms1, member);
     635              :     }
     636              : 
     637              :     /* Phase 2: Random insertions in second set */
     638         2501 :     for (int i = 0; i < num_ops / 4; i++)
     639              :     {
     640         2500 :         member = pg_prng_uint32(&state) % max_range + min_value;
     641              : 
     642         2500 :         if (!bms_is_member(member, bms2))
     643         2462 :             members[num_members++] = member;
     644         2500 :         bms2 = bms_add_member(bms2, member);
     645              :     }
     646              : 
     647              :     /* Test union */
     648            1 :     result = bms_union(bms1, bms2);
     649            1 :     EXPECT_NOT_NULL(result);
     650              : 
     651              :     /* Verify union contains all members from first and second sets */
     652         7338 :     for (int i = 0; i < num_members; i++)
     653              :     {
     654         7337 :         if (!bms_is_member(members[i], result))
     655            0 :             elog(ERROR, "union missing member %d", members[i]);
     656              :     }
     657            1 :     bms_free(result);
     658              : 
     659              :     /*
     660              :      * Test intersection, checking that all the members in the result are from
     661              :      * both the first and second sets.
     662              :      */
     663            1 :     result = bms_intersect(bms1, bms2);
     664            1 :     if (result != NULL)
     665              :     {
     666            1 :         member = -1;
     667              : 
     668          171 :         while ((member = bms_next_member(result, member)) >= 0)
     669              :         {
     670          170 :             if (!bms_is_member(member, bms1) || !bms_is_member(member, bms2))
     671            0 :                 elog(ERROR, "intersection contains invalid member %d", member);
     672              :         }
     673            1 :         bms_free(result);
     674              :     }
     675              : 
     676              :     /* Phase 3: Test range operations */
     677            1 :     result = NULL;
     678        10001 :     for (int i = 0; i < num_ops; i++)
     679              :     {
     680        10000 :         int         lower = pg_prng_uint32(&state) % 100;
     681        10000 :         int         upper = lower + (pg_prng_uint32(&state) % 20);
     682              : 
     683        10000 :         result = bms_add_range(result, lower, upper);
     684              :     }
     685            1 :     if (result != NULL)
     686              :     {
     687            1 :         EXPECT_TRUE(bms_num_members(result) > 0);
     688            1 :         bms_free(result);
     689              :     }
     690              : 
     691            1 :     bms_free(bms1);
     692            1 :     bms_free(bms2);
     693              : 
     694              :     /*
     695              :      * Phase 4: mix of operations on a single set, cross-checking a bitmap
     696              :      * with a secondary state, "members".
     697              :      */
     698            1 :     num_members = 0;
     699              : 
     700        10001 :     for (int op = 0; op < num_ops; op++)
     701              :     {
     702        10000 :         switch (pg_prng_uint32(&state) % 3)
     703              :         {
     704         3377 :             case 0:             /* add */
     705         3377 :                 member = pg_prng_uint32(&state) % max_range + min_value;
     706         3377 :                 if (!bms_is_member(member, bms))
     707         3374 :                     members[num_members++] = member;
     708         3377 :                 bms = bms_add_member(bms, member);
     709         3377 :                 break;
     710         3329 :             case 1:             /* delete */
     711         3329 :                 if (num_members > 0)
     712              :                 {
     713         3247 :                     int         pos = pg_prng_uint32(&state) % num_members;
     714              : 
     715         3247 :                     member = members[pos];
     716         3247 :                     if (!bms_is_member(member, bms))
     717            0 :                         elog(ERROR, "expected %d to be a valid member", member);
     718              : 
     719         3247 :                     bms = bms_del_member(bms, member);
     720              : 
     721              :                     /*
     722              :                      * Move the final array member at the position of the
     723              :                      * member just deleted, reducing the array size by one.
     724              :                      */
     725         3247 :                     members[pos] = members[--num_members];
     726              :                 }
     727         3329 :                 break;
     728         3294 :             case 2:             /* test membership */
     729              :                 /* Verify that bitmap contains all members */
     730       302515 :                 for (int i = 0; i < num_members; i++)
     731              :                 {
     732       299221 :                     if (!bms_is_member(members[i], bms))
     733            0 :                         elog(ERROR, "missing member %d", members[i]);
     734              :                 }
     735         3294 :                 break;
     736              :         }
     737        10000 :         total_ops++;
     738              :     }
     739              : 
     740            1 :     bms_free(bms);
     741            1 :     pfree(members);
     742              : 
     743            1 :     PG_RETURN_INT32(total_ops);
     744              : }
        

Generated by: LCOV version 2.0-1