LCOV - code coverage report
Current view: top level - src/test/modules/test_bitmapset - test_bitmapset.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 285 290 98.3 %
Date: 2025-10-23 17:17:24 Functions: 67 67 100.0 %
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, 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           2 : PG_MODULE_MAGIC;
      31             : 
      32             : /* Bitmapset API functions in order of appearance in bitmapset.c */
      33           4 : PG_FUNCTION_INFO_V1(test_bms_make_singleton);
      34           4 : PG_FUNCTION_INFO_V1(test_bms_add_member);
      35           4 : PG_FUNCTION_INFO_V1(test_bms_del_member);
      36           4 : PG_FUNCTION_INFO_V1(test_bms_is_member);
      37           4 : PG_FUNCTION_INFO_V1(test_bms_num_members);
      38           4 : PG_FUNCTION_INFO_V1(test_bms_copy);
      39           4 : PG_FUNCTION_INFO_V1(test_bms_equal);
      40           4 : PG_FUNCTION_INFO_V1(test_bms_compare);
      41           4 : PG_FUNCTION_INFO_V1(test_bms_is_subset);
      42           4 : PG_FUNCTION_INFO_V1(test_bms_subset_compare);
      43           4 : PG_FUNCTION_INFO_V1(test_bms_union);
      44           4 : PG_FUNCTION_INFO_V1(test_bms_intersect);
      45           4 : PG_FUNCTION_INFO_V1(test_bms_difference);
      46           4 : PG_FUNCTION_INFO_V1(test_bms_is_empty);
      47           4 : PG_FUNCTION_INFO_V1(test_bms_membership);
      48           4 : PG_FUNCTION_INFO_V1(test_bms_singleton_member);
      49           4 : PG_FUNCTION_INFO_V1(test_bms_get_singleton_member);
      50           4 : PG_FUNCTION_INFO_V1(test_bms_next_member);
      51           4 : PG_FUNCTION_INFO_V1(test_bms_prev_member);
      52           4 : PG_FUNCTION_INFO_V1(test_bms_hash_value);
      53           4 : PG_FUNCTION_INFO_V1(test_bms_overlap);
      54           4 : PG_FUNCTION_INFO_V1(test_bms_overlap_list);
      55           4 : PG_FUNCTION_INFO_V1(test_bms_nonempty_difference);
      56           4 : PG_FUNCTION_INFO_V1(test_bms_member_index);
      57           4 : PG_FUNCTION_INFO_V1(test_bms_add_range);
      58           4 : PG_FUNCTION_INFO_V1(test_bms_add_members);
      59           4 : PG_FUNCTION_INFO_V1(test_bms_int_members);
      60           4 : PG_FUNCTION_INFO_V1(test_bms_del_members);
      61           4 : PG_FUNCTION_INFO_V1(test_bms_replace_members);
      62           4 : PG_FUNCTION_INFO_V1(test_bms_join);
      63           4 : PG_FUNCTION_INFO_V1(test_bitmap_hash);
      64           4 : PG_FUNCTION_INFO_V1(test_bitmap_match);
      65             : 
      66             : /* Test utility functions */
      67           4 : 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          14 : test_bms_add_member(PG_FUNCTION_ARGS)
     125             : {
     126             :     Bitmapset  *bms;
     127             :     int         member;
     128             : 
     129          14 :     if (PG_ARGISNULL(1))
     130           2 :         PG_RETURN_NULL();       /* invalid input */
     131             : 
     132          12 :     bms = PG_ARG_GETBITMAPSET(0);
     133          12 :     member = PG_GETARG_INT32(1);
     134             : 
     135          12 :     bms = bms_add_member(bms, member);
     136             : 
     137           8 :     PG_RETURN_BITMAPSET_AS_TEXT(bms);
     138             : }
     139             : 
     140             : Datum
     141           6 : test_bms_add_members(PG_FUNCTION_ARGS)
     142             : {
     143           6 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     144           6 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     145             : 
     146             :     /* left input is recycled */
     147           6 :     bms1 = bms_add_members(bms1, bms2);
     148             : 
     149           6 :     PG_RETURN_BITMAPSET_AS_TEXT(bms1);
     150             : }
     151             : 
     152             : Datum
     153          24 : test_bms_del_member(PG_FUNCTION_ARGS)
     154             : {
     155             :     Bitmapset  *bms;
     156             :     int32       member;
     157             : 
     158          24 :     if (PG_ARGISNULL(1))
     159           2 :         PG_RETURN_NULL();       /* invalid input */
     160             : 
     161          22 :     bms = PG_ARG_GETBITMAPSET(0);
     162          22 :     member = PG_GETARG_INT32(1);
     163             : 
     164          22 :     bms = bms_del_member(bms, member);
     165             : 
     166          20 :     PG_RETURN_BITMAPSET_AS_TEXT(bms);
     167             : }
     168             : 
     169             : Datum
     170          12 : test_bms_is_member(PG_FUNCTION_ARGS)
     171             : {
     172             :     Bitmapset  *bms;
     173             :     int32       member;
     174             :     bool        result;
     175             : 
     176          12 :     if (PG_ARGISNULL(1))
     177           2 :         PG_RETURN_NULL();       /* invalid input */
     178             : 
     179          10 :     bms = PG_ARG_GETBITMAPSET(0);
     180          10 :     member = PG_GETARG_INT32(1);
     181             : 
     182          10 :     result = bms_is_member(member, bms);
     183             : 
     184           8 :     PG_RETURN_BOOL(result);
     185             : }
     186             : 
     187             : Datum
     188           6 : test_bms_num_members(PG_FUNCTION_ARGS)
     189             : {
     190           6 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     191             :     int         result;
     192             : 
     193           6 :     result = bms_num_members(bms);
     194             : 
     195           6 :     PG_RETURN_INT32(result);
     196             : }
     197             : 
     198             : Datum
     199           8 : test_bms_make_singleton(PG_FUNCTION_ARGS)
     200             : {
     201             :     Bitmapset  *bms;
     202             :     int32       member;
     203             : 
     204           8 :     member = PG_GETARG_INT32(0);
     205           8 :     bms = bms_make_singleton(member);
     206             : 
     207           6 :     PG_RETURN_BITMAPSET_AS_TEXT(bms);
     208             : }
     209             : 
     210             : Datum
     211           4 : test_bms_copy(PG_FUNCTION_ARGS)
     212             : {
     213           4 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     214             :     Bitmapset  *copy_bms;
     215             : 
     216           4 :     copy_bms = bms_copy(bms);
     217             : 
     218           4 :     PG_RETURN_BITMAPSET_AS_TEXT(copy_bms);
     219             : }
     220             : 
     221             : Datum
     222          26 : test_bms_equal(PG_FUNCTION_ARGS)
     223             : {
     224          26 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     225          26 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     226             :     bool        result;
     227             : 
     228          26 :     result = bms_equal(bms1, bms2);
     229             : 
     230          26 :     PG_RETURN_BOOL(result);
     231             : }
     232             : 
     233             : Datum
     234          18 : test_bms_union(PG_FUNCTION_ARGS)
     235             : {
     236          18 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     237          18 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     238             :     Bitmapset  *result_bms;
     239             : 
     240          18 :     result_bms = bms_union(bms1, bms2);
     241             : 
     242          18 :     PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
     243             : }
     244             : 
     245             : Datum
     246           8 : test_bms_membership(PG_FUNCTION_ARGS)
     247             : {
     248           8 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     249             :     BMS_Membership result;
     250             : 
     251           8 :     result = bms_membership(bms);
     252             : 
     253           8 :     PG_RETURN_INT32((int32) result);
     254             : }
     255             : 
     256             : Datum
     257          12 : test_bms_next_member(PG_FUNCTION_ARGS)
     258             : {
     259             :     Bitmapset  *bms;
     260             :     int32       prevmember;
     261             :     int         result;
     262             : 
     263          12 :     if (PG_ARGISNULL(1))
     264           2 :         PG_RETURN_NULL();       /* invalid input */
     265             : 
     266          10 :     bms = PG_ARG_GETBITMAPSET(0);
     267          10 :     prevmember = PG_GETARG_INT32(1);
     268             : 
     269          10 :     result = bms_next_member(bms, prevmember);
     270             : 
     271          10 :     PG_RETURN_INT32(result);
     272             : }
     273             : 
     274             : Datum
     275          16 : test_bms_intersect(PG_FUNCTION_ARGS)
     276             : {
     277          16 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     278          16 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     279             :     Bitmapset  *result_bms;
     280             : 
     281          16 :     result_bms = bms_intersect(bms1, bms2);
     282             : 
     283          16 :     PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
     284             : }
     285             : 
     286             : Datum
     287          20 : test_bms_difference(PG_FUNCTION_ARGS)
     288             : {
     289          20 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     290          20 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     291             :     Bitmapset  *result_bms;
     292             : 
     293          20 :     result_bms = bms_difference(bms1, bms2);
     294             : 
     295          20 :     PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
     296             : }
     297             : 
     298             : Datum
     299          20 : test_bms_compare(PG_FUNCTION_ARGS)
     300             : {
     301          20 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     302          20 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     303             :     int         result;
     304             : 
     305          20 :     result = bms_compare(bms1, bms2);
     306             : 
     307          20 :     PG_RETURN_INT32(result);
     308             : }
     309             : 
     310             : Datum
     311           6 : test_bms_is_empty(PG_FUNCTION_ARGS)
     312             : {
     313           6 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     314             :     bool        result;
     315             : 
     316           6 :     result = bms_is_empty(bms);
     317             : 
     318           6 :     PG_RETURN_BOOL(result);
     319             : }
     320             : 
     321             : Datum
     322          20 : test_bms_is_subset(PG_FUNCTION_ARGS)
     323             : {
     324          20 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     325          20 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     326             :     bool        result;
     327             : 
     328          20 :     result = bms_is_subset(bms1, bms2);
     329             : 
     330          20 :     PG_RETURN_BOOL(result);
     331             : }
     332             : 
     333             : Datum
     334          46 : test_bms_subset_compare(PG_FUNCTION_ARGS)
     335             : {
     336          46 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     337          46 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     338             :     BMS_Comparison result;
     339             : 
     340          46 :     result = bms_subset_compare(bms1, bms2);
     341             : 
     342          46 :     PG_RETURN_INT32((int32) result);
     343             : }
     344             : 
     345             : Datum
     346           6 : test_bms_singleton_member(PG_FUNCTION_ARGS)
     347             : {
     348           6 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     349             :     int         result;
     350             : 
     351           6 :     result = bms_singleton_member(bms);
     352             : 
     353           2 :     PG_RETURN_INT32(result);
     354             : }
     355             : 
     356             : Datum
     357           8 : test_bms_get_singleton_member(PG_FUNCTION_ARGS)
     358             : {
     359           8 :     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           8 :     if (!bms_get_singleton_member(bms, &member))
     367           6 :         member = -1;
     368             : 
     369           8 :     PG_RETURN_INT32(member);
     370             : }
     371             : 
     372             : Datum
     373          14 : test_bms_prev_member(PG_FUNCTION_ARGS)
     374             : {
     375             :     Bitmapset  *bms;
     376             :     int32       prevmember;
     377             :     int         result;
     378             : 
     379          14 :     if (PG_ARGISNULL(1))
     380           2 :         PG_RETURN_NULL();       /* invalid input */
     381             : 
     382          12 :     bms = PG_ARG_GETBITMAPSET(0);
     383          12 :     prevmember = PG_GETARG_INT32(1);
     384             : 
     385          12 :     result = bms_prev_member(bms, prevmember);
     386             : 
     387          12 :     PG_RETURN_INT32(result);
     388             : }
     389             : 
     390             : Datum
     391          12 : test_bms_overlap(PG_FUNCTION_ARGS)
     392             : {
     393          12 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     394          12 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     395             :     bool        result;
     396             : 
     397          12 :     result = bms_overlap(bms1, bms2);
     398             : 
     399          12 :     PG_RETURN_BOOL(result);
     400             : }
     401             : 
     402             : Datum
     403          22 : test_bms_overlap_list(PG_FUNCTION_ARGS)
     404             : {
     405             :     Bitmapset  *bms;
     406             :     ArrayType  *array;
     407          22 :     List       *int_list = NIL;
     408             :     bool        result;
     409          22 :     Datum      *elem_datums = NULL;
     410          22 :     bool       *elem_nulls = NULL;
     411             :     int         elem_count;
     412             :     int         i;
     413             : 
     414          22 :     bms = PG_ARG_GETBITMAPSET(0);
     415             : 
     416          22 :     if (!PG_ARGISNULL(1))
     417             :     {
     418          18 :         array = PG_GETARG_ARRAYTYPE_P(1);
     419             : 
     420          18 :         deconstruct_array(array,
     421             :                           INT4OID, sizeof(int32), true, 'i',
     422             :                           &elem_datums, &elem_nulls, &elem_count);
     423             : 
     424          62 :         for (i = 0; i < elem_count; i++)
     425             :         {
     426          44 :             if (!elem_nulls[i])
     427             :             {
     428          44 :                 int32       member = DatumGetInt32(elem_datums[i]);
     429             : 
     430          44 :                 int_list = lappend_int(int_list, member);
     431             :             }
     432             :         }
     433             :     }
     434             : 
     435          22 :     result = bms_overlap_list(bms, int_list);
     436             : 
     437          18 :     list_free(int_list);
     438             : 
     439          18 :     if (elem_datums)
     440          14 :         pfree(elem_datums);
     441             : 
     442          18 :     if (elem_nulls)
     443          14 :         pfree(elem_nulls);
     444             : 
     445          18 :     PG_RETURN_BOOL(result);
     446             : }
     447             : 
     448             : Datum
     449          18 : test_bms_nonempty_difference(PG_FUNCTION_ARGS)
     450             : {
     451          18 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     452          18 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     453             :     bool        result;
     454             : 
     455          18 :     result = bms_nonempty_difference(bms1, bms2);
     456             : 
     457          18 :     PG_RETURN_BOOL(result);
     458             : }
     459             : 
     460             : Datum
     461          16 : test_bms_member_index(PG_FUNCTION_ARGS)
     462             : {
     463             :     Bitmapset  *bms;
     464             :     int32       member;
     465             :     int         result;
     466             : 
     467          16 :     if (PG_ARGISNULL(1))
     468           2 :         PG_RETURN_NULL();       /* invalid input */
     469             : 
     470          14 :     bms = PG_ARG_GETBITMAPSET(0);
     471          14 :     member = PG_GETARG_INT32(1);
     472             : 
     473          14 :     result = bms_member_index(bms, member);
     474             : 
     475          14 :     PG_RETURN_INT32(result);
     476             : }
     477             : 
     478             : Datum
     479          50 : test_bms_add_range(PG_FUNCTION_ARGS)
     480             : {
     481             :     Bitmapset  *bms;
     482             :     int32       lower,
     483             :                 upper;
     484             : 
     485          50 :     if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
     486           6 :         PG_RETURN_NULL();       /* invalid input */
     487             : 
     488          44 :     bms = PG_ARG_GETBITMAPSET(0);
     489          44 :     lower = PG_GETARG_INT32(1);
     490          44 :     upper = PG_GETARG_INT32(2);
     491             : 
     492          44 :     bms = bms_add_range(bms, lower, upper);
     493             : 
     494          42 :     PG_RETURN_BITMAPSET_AS_TEXT(bms);
     495             : }
     496             : 
     497             : Datum
     498          14 : test_bms_int_members(PG_FUNCTION_ARGS)
     499             : {
     500          14 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     501          14 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     502             : 
     503             :     /* left input gets recycled */
     504          14 :     bms1 = bms_int_members(bms1, bms2);
     505             : 
     506          14 :     PG_RETURN_BITMAPSET_AS_TEXT(bms1);
     507             : }
     508             : 
     509             : Datum
     510          20 : test_bms_del_members(PG_FUNCTION_ARGS)
     511             : {
     512          20 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     513          20 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     514             : 
     515             :     /* left input gets recycled */
     516          20 :     bms1 = bms_del_members(bms1, bms2);
     517             : 
     518          20 :     PG_RETURN_BITMAPSET_AS_TEXT(bms1);
     519             : }
     520             : 
     521             : Datum
     522          12 : test_bms_replace_members(PG_FUNCTION_ARGS)
     523             : {
     524          12 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     525          12 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     526             : 
     527             :     /* left input gets recycled */
     528          12 :     bms1 = bms_replace_members(bms1, bms2);
     529             : 
     530          12 :     PG_RETURN_BITMAPSET_AS_TEXT(bms1);
     531             : }
     532             : 
     533             : Datum
     534          18 : test_bms_join(PG_FUNCTION_ARGS)
     535             : {
     536          18 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     537          18 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     538             :     Bitmapset  *result_bms;
     539             : 
     540             :     /* either input can be recycled */
     541          18 :     result_bms = bms_join(bms1, bms2);
     542             : 
     543          18 :     PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
     544             : }
     545             : 
     546             : Datum
     547          14 : test_bms_hash_value(PG_FUNCTION_ARGS)
     548             : {
     549          14 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     550             :     uint32      hash_result;
     551             : 
     552          14 :     hash_result = bms_hash_value(bms);
     553             : 
     554          14 :     PG_RETURN_INT32(hash_result);
     555             : }
     556             : 
     557             : Datum
     558          14 : test_bitmap_hash(PG_FUNCTION_ARGS)
     559             : {
     560          14 :     Bitmapset  *bms = PG_ARG_GETBITMAPSET(0);
     561             :     uint32      hash_result;
     562             : 
     563             :     /* Call bitmap_hash */
     564          14 :     hash_result = bitmap_hash(&bms, sizeof(Bitmapset *));
     565             : 
     566          14 :     PG_RETURN_INT32(hash_result);
     567             : }
     568             : 
     569             : Datum
     570          24 : test_bitmap_match(PG_FUNCTION_ARGS)
     571             : {
     572          24 :     Bitmapset  *bms1 = PG_ARG_GETBITMAPSET(0);
     573          24 :     Bitmapset  *bms2 = PG_ARG_GETBITMAPSET(1);
     574             :     int         match_result;
     575             : 
     576             :     /* Call bitmap_match with addresses of the Bitmapset pointers */
     577          24 :     match_result = bitmap_match(&bms1, &bms2, sizeof(Bitmapset *));
     578             : 
     579          24 :     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           2 : test_random_operations(PG_FUNCTION_ARGS)
     596             : {
     597           2 :     Bitmapset  *bms1 = NULL;
     598           2 :     Bitmapset  *bms2 = NULL;
     599           2 :     Bitmapset  *bms = NULL;
     600           2 :     Bitmapset  *result = NULL;
     601             :     pg_prng_state state;
     602           2 :     uint64      seed = GetCurrentTimestamp();
     603             :     int         num_ops;
     604             :     int         max_range;
     605             :     int         min_value;
     606             :     int         member;
     607             :     int        *members;
     608           2 :     int         num_members = 0;
     609           2 :     int         total_ops = 0;
     610             : 
     611           2 :     if (PG_GETARG_INT32(0) > 0)
     612           0 :         seed = PG_GETARG_INT32(0);
     613             : 
     614           2 :     num_ops = PG_GETARG_INT32(1);
     615           2 :     max_range = PG_GETARG_INT32(2);
     616           2 :     min_value = PG_GETARG_INT32(3);
     617             : 
     618           2 :     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           2 :     members = palloc(sizeof(int) * num_ops);
     626             : 
     627             :     /* Phase 1: Random insertions in first set */
     628       10002 :     for (int i = 0; i < num_ops / 2; i++)
     629             :     {
     630       10000 :         member = pg_prng_uint32(&state) % max_range + min_value;
     631             : 
     632       10000 :         if (!bms_is_member(member, bms1))
     633        9682 :             members[num_members++] = member;
     634       10000 :         bms1 = bms_add_member(bms1, member);
     635             :     }
     636             : 
     637             :     /* Phase 2: Random insertions in second set */
     638        5002 :     for (int i = 0; i < num_ops / 4; i++)
     639             :     {
     640        5000 :         member = pg_prng_uint32(&state) % max_range + min_value;
     641             : 
     642        5000 :         if (!bms_is_member(member, bms2))
     643        4928 :             members[num_members++] = member;
     644        5000 :         bms2 = bms_add_member(bms2, member);
     645             :     }
     646             : 
     647             :     /* Test union */
     648           2 :     result = bms_union(bms1, bms2);
     649           2 :     EXPECT_NOT_NULL(result);
     650             : 
     651             :     /* Verify union contains all members from first and second sets */
     652       14612 :     for (int i = 0; i < num_members; i++)
     653             :     {
     654       14610 :         if (!bms_is_member(members[i], result))
     655           0 :             elog(ERROR, "union missing member %d", members[i]);
     656             :     }
     657           2 :     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           2 :     result = bms_intersect(bms1, bms2);
     664           2 :     if (result != NULL)
     665             :     {
     666           2 :         member = -1;
     667             : 
     668         322 :         while ((member = bms_next_member(result, member)) >= 0)
     669             :         {
     670         320 :             if (!bms_is_member(member, bms1) || !bms_is_member(member, bms2))
     671           0 :                 elog(ERROR, "intersection contains invalid member %d", member);
     672             :         }
     673           2 :         bms_free(result);
     674             :     }
     675             : 
     676             :     /* Phase 3: Test range operations */
     677           2 :     result = NULL;
     678       20002 :     for (int i = 0; i < num_ops; i++)
     679             :     {
     680       20000 :         int         lower = pg_prng_uint32(&state) % 100;
     681       20000 :         int         upper = lower + (pg_prng_uint32(&state) % 20);
     682             : 
     683       20000 :         result = bms_add_range(result, lower, upper);
     684             :     }
     685           2 :     if (result != NULL)
     686             :     {
     687           2 :         EXPECT_TRUE(bms_num_members(result) > 0);
     688           2 :         bms_free(result);
     689             :     }
     690             : 
     691           2 :     bms_free(bms1);
     692           2 :     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           2 :     num_members = 0;
     699             : 
     700       20002 :     for (int op = 0; op < num_ops; op++)
     701             :     {
     702       20000 :         switch (pg_prng_uint32(&state) % 3)
     703             :         {
     704        6756 :             case 0:             /* add */
     705        6756 :                 member = pg_prng_uint32(&state) % max_range + min_value;
     706        6756 :                 if (!bms_is_member(member, bms))
     707        6742 :                     members[num_members++] = member;
     708        6756 :                 bms = bms_add_member(bms, member);
     709        6756 :                 break;
     710        6540 :             case 1:             /* delete */
     711        6540 :                 if (num_members > 0)
     712             :                 {
     713        6472 :                     int         pos = pg_prng_uint32(&state) % num_members;
     714             : 
     715        6472 :                     member = members[pos];
     716        6472 :                     if (!bms_is_member(member, bms))
     717           0 :                         elog(ERROR, "expected %d to be a valid member", member);
     718             : 
     719        6472 :                     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        6472 :                     members[pos] = members[--num_members];
     726             :                 }
     727        6540 :                 break;
     728        6704 :             case 2:             /* test membership */
     729             :                 /* Verify that bitmap contains all members */
     730      713664 :                 for (int i = 0; i < num_members; i++)
     731             :                 {
     732      706960 :                     if (!bms_is_member(members[i], bms))
     733           0 :                         elog(ERROR, "missing member %d", members[i]);
     734             :                 }
     735        6704 :                 break;
     736             :         }
     737       20000 :         total_ops++;
     738             :     }
     739             : 
     740           2 :     bms_free(bms);
     741           2 :     pfree(members);
     742             : 
     743           2 :     PG_RETURN_INT32(total_ops);
     744             : }

Generated by: LCOV version 1.16