From a3ce1eeb35d3430ce55e8e7189c3aa8e74645db6 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Thu, 25 Sep 2025 12:14:49 -0400 Subject: [PATCH v1] Further improve the test coverage of Bitmapset Improve test coverage on both bitmapset.c and the code that tests it, test_bitmapset.c with a few more tests that trigger branch conditions and special cases. This extends commit 00c3d87 and f83fe65. Author: Greg Burd Reviewed-by: Michael Paquier Discussion: https://postgr.es/m/3027069.1758606227@sss.pgh.pa.us --- .../expected/test_bitmapset.out | 852 +++++++++++++++++- .../test_bitmapset/sql/test_bitmapset.sql | 173 +++- .../test_bitmapset/test_bitmapset--1.0.sql | 4 + .../modules/test_bitmapset/test_bitmapset.c | 62 +- 4 files changed, 1013 insertions(+), 78 deletions(-) diff --git a/src/test/modules/test_bitmapset/expected/test_bitmapset.out b/src/test/modules/test_bitmapset/expected/test_bitmapset.out index abbfef1f7a6..cb6d71fb7b1 100644 --- a/src/test/modules/test_bitmapset/expected/test_bitmapset.out +++ b/src/test/modules/test_bitmapset/expected/test_bitmapset.out @@ -83,6 +83,13 @@ SELECT test_bms_replace_members('(b 1 2)', '(b 3 5 7)') AS result; (b 3 5 7) (1 row) +-- Force repalloc() with larger set +SELECT test_bms_replace_members('(b 1 2 3 4 5)', '(b 500 600)') AS result; + result +------------- + (b 500 600) +(1 row) + -- bms_del_member() SELECT test_bms_del_member('(b)', -20); -- error ERROR: negative bitmapset member not allowed @@ -124,6 +131,74 @@ SELECT test_bms_del_member(test_bms_add_range('(b)', 30, 34), 32) AS result; (b 30 31 33 34) (1 row) +-- Force word count changes +SELECT test_bms_del_member('(b 1 200)', 200) AS result; + result +-------- + (b 1) +(1 row) + +SELECT test_bms_del_member('(b 1 50 100 200)', 200) AS result; + result +-------------- + (b 1 50 100) +(1 row) + +SELECT test_bms_del_member('(b 1 50 100 200)', 100) AS result; + result +-------------- + (b 1 50 200) +(1 row) + +-- bms_del_members() +SELECT test_bms_del_members('(b)', '(b 10)') AS result; + result +-------- + +(1 row) + +SELECT test_bms_del_members('(b 10)', '(b 10)') AS result; + result +-------- + +(1 row) + +SELECT test_bms_del_members('(b 10)', '(b 5)') AS result; + result +-------- + (b 10) +(1 row) + +SELECT test_bms_del_members('(b 1 2 3)', '(b 2)') AS result; + result +--------- + (b 1 3) +(1 row) + +SELECT test_bms_del_members('(b 5 100)', '(b 100)') AS result; + result +-------- + (b 5) +(1 row) + +SELECT test_bms_del_members('(b 5 100 200)', '(b 200)') AS result; + result +----------- + (b 5 100) +(1 row) + +SELECT test_bms_del_members('(b 1 2 100 200 300)', '(b 1 2)') AS result; + result +----------------- + (b 100 200 300) +(1 row) + +SELECT test_bms_del_members('(b 1 2 100 200 300)', '(b 200 300)') AS result; + result +------------- + (b 1 2 100) +(1 row) + -- bms_join() SELECT test_bms_join('(b 1 3 5)', NULL) AS result; result @@ -149,8 +224,21 @@ SELECT test_bms_join('(b 1 3 5)', '(b 1 4 5)') AS result; (b 1 3 4 5) (1 row) +-- Force word count changes +SELECT test_bms_join('(b 5)', '(b 100)') AS result; + result +----------- + (b 5 100) +(1 row) + +SELECT test_bms_join('(b 1 2)', '(b 100 200 300)') AS result; + result +--------------------- + (b 1 2 100 200 300) +(1 row) + -- bms_union() --- Overlapping sets. +-- Overlapping sets SELECT test_bms_union('(b 1 3 5)', '(b 3 5 7)') AS result; result ------------- @@ -181,6 +269,19 @@ SELECT test_bms_union( (b 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20) (1 row) +-- Union with varrying word counts +SELECT test_bms_union('(b 1 2)', '(b 100 300)') AS result; + result +----------------- + (b 1 2 100 300) +(1 row) + +SELECT test_bms_union('(b 100 300)', '(b 1 2)') AS result; + result +----------------- + (b 1 2 100 300) +(1 row) + -- bms_intersect() -- Overlapping sets SELECT test_bms_intersect('(b 1 3 5)', '(b 3 5 7)') AS result; @@ -196,13 +297,26 @@ SELECT test_bms_intersect('(b 1 3 5)', '(b 2 4 6)') AS result; (1 row) --- Intersect with empty. +-- Intersect with empty SELECT test_bms_intersect('(b 1 3 5)', '(b)') AS result; result -------- (1 row) +-- Intersect with varrying word counts +SELECT test_bms_intersect('(b 1 300)', '(b 1 2 3 4 5)') AS result; + result +-------- + (b 1) +(1 row) + +SELECT test_bms_intersect('(b 1 2 3 4 5)', '(b 1 300)') AS result; + result +-------- + (b 1) +(1 row) + -- bms_int_members() -- Overlapping sets SELECT test_bms_int_members('(b 1 3 5)', '(b 3 5 7)') AS result; @@ -218,7 +332,7 @@ SELECT test_bms_int_members('(b 1 3 5)', '(b 2 4 6)') AS result; (1 row) --- Intersect with empty. +-- Intersect with empty SELECT test_bms_int_members('(b 1 3 5)', '(b)') AS result; result -------- @@ -262,13 +376,26 @@ SELECT test_bms_difference('(b 42)', '(b 42)') AS result; (1 row) -- Subtraction edge case -SELECT test_bms_difference( +SELECT length(test_bms_difference( test_bms_add_range('(b)', 0, 100), test_bms_add_range('(b)', 50, 150) - ) AS result; - result -------------------------------------------------------------------------------------------------------------------------------------------------- - (b 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49) + )) AS result; + result +-------- + 143 +(1 row) + +-- Difference with different word counts +SELECT test_bms_difference('(b 5 100)', '(b 5)') AS result; + result +--------- + (b 100) +(1 row) + +SELECT test_bms_difference('(b 1 2 100 200)', '(b 1 2)') AS result; + result +------------- + (b 100 200) (1 row) -- bms_is_member() @@ -323,6 +450,25 @@ SELECT test_bms_member_index('(b 1 3 5)', 3) AS result; 1 (1 row) +-- Member index with various word positions +SELECT test_bms_member_index('(b 100 200)', 100) AS result; + result +-------- + 0 +(1 row) + +SELECT test_bms_member_index('(b 100 200)', 200) AS result; + result +-------- + 1 +(1 row) + +SELECT test_bms_member_index('(b 1 50 100 200)', 200) AS result; + result +-------- + 3 +(1 row) + -- bms_num_members() SELECT test_bms_num_members('(b)') AS result; result @@ -373,6 +519,19 @@ SELECT test_bms_equal('(b 1 3 5)', '(b 2 4 6)') AS result; f (1 row) +-- Equal with different word counts +SELECT test_bms_equal('(b 5)', '(b 100)') AS result; + result +-------- + f +(1 row) + +SELECT test_bms_equal('(b 5 10)', '(b 100 200 300)') AS result; + result +-------- + f +(1 row) + -- bms_compare() SELECT test_bms_compare('(b)', '(b)') AS result; result @@ -474,6 +633,19 @@ SELECT length(test_bms_add_range('(b)', 1000, 1100)) AS result; 508 (1 row) +-- Force word count expansion +SELECT test_bms_add_range('(b 5)', 100, 105) AS result; + result +------------------------------- + (b 5 100 101 102 103 104 105) +(1 row) + +SELECT length(test_bms_add_range('(b 1 2)', 200, 250)) AS result; + result +-------- + 211 +(1 row) + -- bms_membership() SELECT test_bms_membership('(b)') AS result; result @@ -513,6 +685,8 @@ SELECT test_bms_is_empty('(b 1)') AS result; (1 row) -- bms_singleton_member() +SELECT test_bms_singleton_member('(b)'); -- error +ERROR: bitmapset is empty SELECT test_bms_singleton_member('(b 1 2)'); -- error ERROR: bitmapset has multiple members SELECT test_bms_singleton_member('(b 42)') AS result; @@ -522,11 +696,17 @@ SELECT test_bms_singleton_member('(b 42)') AS result; (1 row) -- bms_get_singleton_member() +SELECT test_bms_get_singleton_member('(b)', 1000); -- error + test_bms_get_singleton_member +------------------------------- + -1 +(1 row) + -- Not a singleton, returns input default SELECT test_bms_get_singleton_member('(b 3 6)', 1000) AS result; result -------- - 1000 + -1 (1 row) -- Singletone, returns sole member @@ -593,6 +773,13 @@ SELECT test_bms_prev_member('(b)', 100) AS result; -2 (1 row) +-- Negative prevbit should result in highest possible bit in set +SELECT test_bms_prev_member('(b 0 63 64 127)', -1) AS result; + result +-------- + 127 +(1 row) + -- bms_hash_value() SELECT test_bms_hash_value('(b)') = 0 AS result; result @@ -663,47 +850,156 @@ SELECT test_bms_is_subset(test_bms_add_range(NULL, 0, 31), t (1 row) --- bms_subset_compare() -SELECT test_bms_subset_compare(NULL, NULL) AS result; +-- Is subset with shorter word counts +SELECT test_bms_is_subset('(b 5 100)', '(b 5)') AS result; result -------- - 0 + f (1 row) -SELECT test_bms_subset_compare('(b 1 3)', NULL) AS result; +SELECT test_bms_is_subset('(b 1 2 50 100)', '(b 1 2)') AS result; result -------- - 2 + f (1 row) -SELECT test_bms_subset_compare(NULL, '(b 1 3)') AS result; - result --------- - 1 +-- bms_subset_compare() +SELECT test_bms_subset_compare(NULL, NULL); + test_bms_subset_compare +------------------------- + 0 (1 row) -SELECT test_bms_subset_compare('(b 1 3 5)', '(b 1 3)') AS result; - result --------- - 2 +SELECT test_bms_subset_compare(NULL, '(b 1 3)'); + test_bms_subset_compare +------------------------- + 1 (1 row) -SELECT test_bms_subset_compare('(b 1 3)', '(b 1 3 5)') AS result; - result --------- - 1 +SELECT test_bms_subset_compare('(b)', '(b)'); + test_bms_subset_compare +------------------------- + 0 (1 row) -SELECT test_bms_subset_compare('(b 1 3 5)', '(b 1 3 5)') AS result; - result --------- - 0 +SELECT test_bms_subset_compare('(b)', '(b 1)'); + test_bms_subset_compare +------------------------- + 1 (1 row) -SELECT test_bms_subset_compare('(b 1 3 5)', '(b 2 4 6)') AS result; - result --------- - 3 +SELECT test_bms_subset_compare('(b 1)', '(b)'); + test_bms_subset_compare +------------------------- + 2 +(1 row) + +SELECT test_bms_subset_compare('(b 1 3)', NULL); + test_bms_subset_compare +------------------------- + 2 +(1 row) + +SELECT test_bms_subset_compare('(b 1 3 5)', '(b 1 3 5)'); + test_bms_subset_compare +------------------------- + 0 +(1 row) + +SELECT test_bms_subset_compare('(b 1 3)', '(b 1 3 5)'); + test_bms_subset_compare +------------------------- + 1 +(1 row) + +SELECT test_bms_subset_compare('(b 1 3 5)', '(b 1 3)'); + test_bms_subset_compare +------------------------- + 2 +(1 row) + +SELECT test_bms_subset_compare('(b 1 2)', '(b 1 3)'); + test_bms_subset_compare +------------------------- + 3 +(1 row) + +SELECT test_bms_subset_compare('(b 1 2)', '(b 1 4)'); + test_bms_subset_compare +------------------------- + 3 +(1 row) + +SELECT test_bms_subset_compare('(b 1 3)', '(b 1 3 64)'); + test_bms_subset_compare +------------------------- + 1 +(1 row) + +SELECT test_bms_subset_compare('(b 1 3 64)', '(b 1 3)'); + test_bms_subset_compare +------------------------- + 2 +(1 row) + +SELECT test_bms_subset_compare('(b 1 3 64)', '(b 1 3 65)'); + test_bms_subset_compare +------------------------- + 3 +(1 row) + +SELECT test_bms_subset_compare('(b 1 3)', '(b 2 4)'); + test_bms_subset_compare +------------------------- + 3 +(1 row) + +SELECT test_bms_subset_compare('(b 1)', '(b 64)'); + test_bms_subset_compare +------------------------- + 3 +(1 row) + +SELECT test_bms_subset_compare('(b 0)', '(b 32)'); + test_bms_subset_compare +------------------------- + 3 +(1 row) + +SELECT test_bms_subset_compare('(b 0)', '(b 64)'); + test_bms_subset_compare +------------------------- + 3 +(1 row) + +SELECT test_bms_subset_compare('(b 64)', '(b 1)'); + test_bms_subset_compare +------------------------- + 3 +(1 row) + +SELECT test_bms_subset_compare('(b 1 2)', '(b 1 2 64)'); + test_bms_subset_compare +------------------------- + 1 +(1 row) + +SELECT test_bms_subset_compare('(b 64 200)', '(b 1 201)'); + test_bms_subset_compare +------------------------- + 3 +(1 row) + +SELECT test_bms_subset_compare('(b 1 64 65)', '(b 1 2 64)'); + test_bms_subset_compare +------------------------- + 3 +(1 row) + +SELECT test_bms_subset_compare('(b 2 64 128)', '(b 1 65)'); + test_bms_subset_compare +------------------------- + 3 (1 row) -- bms_copy() @@ -720,12 +1016,6 @@ SELECT test_bms_copy('(b 1 3 5 7)') AS result; (1 row) -- bms_add_members() -SELECT test_bms_add_member('(b)', 1000); -- error - test_bms_add_member ---------------------- - (b 1000) -(1 row) - SELECT test_bms_add_members('(b 1 3)', '(b 5 7)') AS result; result ------------- @@ -866,6 +1156,11 @@ SELECT test_bms_overlap_list('(b 1)', ARRAY[]::integer[]) AS result; f (1 row) +-- Overlap list with negative numbers +SELECT test_bms_overlap_list('(b 5 10)', ARRAY[-1,5]) AS result; -- error +ERROR: negative bitmapset member not allowed +SELECT test_bms_overlap_list('(b 1 2 3)', ARRAY[-5,-1,0]) AS result; -- error +ERROR: negative bitmapset member not allowed -- bms_nonempty_difference() SELECT test_bms_nonempty_difference(NULL, '(b 1 3 5)') AS result; result @@ -897,6 +1192,25 @@ SELECT test_bms_nonempty_difference('(b 1 3 5)', '(b 1 3 5)') AS result; f (1 row) +-- Difference with different word counts +SELECT test_bms_nonempty_difference('(b 5)', '(b 100)') AS result; + result +-------- + t +(1 row) + +SELECT test_bms_nonempty_difference('(b 100)', '(b 5)') AS result; + result +-------- + t +(1 row) + +SELECT test_bms_nonempty_difference('(b 1 2)', '(b 50 100)') AS result; + result +-------- + t +(1 row) + -- random operations SELECT test_random_operations(-1, 10000, 81920, 0) > 0 AS result; result @@ -904,4 +1218,462 @@ SELECT test_random_operations(-1, 10000, 81920, 0) > 0 AS result; t (1 row) +-- Cover the test API's corner cases such as when ARGISNULL, +-- or VARSIZE_ANY_EXHDR == 0, etc. +SELECT test_bitmap_hash(NULL) AS result; + result +-------- + 0 +(1 row) + +SELECT test_bitmap_match('(b 5)', NULL) AS result; + result +-------- + 1 +(1 row) + +SELECT test_bitmap_match(NULL, '(b 5)') AS result; + result +-------- + 1 +(1 row) + +SELECT test_bitmap_match(NULL, NULL) AS result; + result +-------- + 0 +(1 row) + +SELECT test_bms_add_member('(b)', NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_add_range('(b 5)', 5, NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_add_range('(b 5)', NULL, 10) AS result; + result +-------- + +(1 row) + +SELECT test_bms_add_range('(b 5)', NULL, NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_add_range(NULL, 5, 10) AS result; + result +------------------ + (b 5 6 7 8 9 10) +(1 row) + +SELECT test_bms_add_range(NULL, 10, 5) AS result; + result +-------- + +(1 row) + +SELECT test_bms_add_range(NULL, NULL, NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_compare('(b 5)', NULL) AS result; + result +-------- + 1 +(1 row) + +SELECT test_bms_compare(NULL, '(b 5)') AS result; + result +-------- + -1 +(1 row) + +SELECT test_bms_compare(NULL, NULL) AS result; + result +-------- + 0 +(1 row) + +SELECT test_bms_copy(NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_del_member('(b 42)', 42) AS result; + result +-------- + +(1 row) + +SELECT test_bms_del_member('(b 5)', NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_del_members('(b 5)', NULL) AS result; + result +-------- + (b 5) +(1 row) + +SELECT test_bms_del_members(NULL, '(b 5)') AS result; + result +-------- + +(1 row) + +SELECT test_bms_difference('(b 5)', '(b 5 10)') AS result; + result +-------- + +(1 row) + +SELECT test_bms_difference('(b 5)', NULL) AS result; + result +-------- + (b 5) +(1 row) + +SELECT test_bms_difference(NULL, '(b 5)') AS result; + result +-------- + +(1 row) + +SELECT test_bms_difference(NULL, NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_equal('(b 5)', NULL) AS result; + result +-------- + f +(1 row) + +SELECT test_bms_equal(NULL, '(b 5)') AS result; + result +-------- + f +(1 row) + +SELECT test_bms_equal(NULL, NULL) AS result; + result +-------- + t +(1 row) + +SELECT test_bms_get_singleton_member('', 1000) AS result; + result +-------- + -1 +(1 row) + +SELECT test_bms_get_singleton_member(NULL, -1) AS result; + result +-------- + -1 +(1 row) + +SELECT test_bms_hash_value(NULL) AS result; + result +-------- + 0 +(1 row) + +SELECT test_bms_int_members('(b 1)', '(b 2)') AS result; + result +-------- + +(1 row) + +SELECT test_bms_int_members('(b 5)', NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_int_members(NULL, '(b 5)') AS result; + result +-------- + +(1 row) + +SELECT test_bms_int_members(NULL, NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_intersect('(b 1)', '(b 2)') AS result; + result +-------- + +(1 row) + +SELECT test_bms_intersect('(b 5)', NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_intersect(NULL, '(b 5)') AS result; + result +-------- + +(1 row) + +SELECT test_bms_intersect(NULL, NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_is_empty(NULL) AS result; + result +-------- + t +(1 row) + +SELECT test_bms_is_member('(b 5)', NULL) AS result; + result +-------- + f +(1 row) + +SELECT test_bms_is_subset('(b 5)', NULL) AS result; + result +-------- + f +(1 row) + +SELECT test_bms_is_subset(NULL, '(b 5)') AS result; + result +-------- + t +(1 row) + +SELECT test_bms_is_subset(NULL, NULL) AS result; + result +-------- + t +(1 row) + +SELECT test_bms_join('(b 5)', NULL) AS result; + result +-------- + (b 5) +(1 row) + +SELECT test_bms_join(NULL, '(b 5)') AS result; + result +-------- + (b 5) +(1 row) + +SELECT test_bms_join(NULL, NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_make_singleton(NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_member_index('', 5) AS result; + result +-------- + -1 +(1 row) + +SELECT test_bms_member_index(NULL, 5) AS result; + result +-------- + -1 +(1 row) + +SELECT test_bms_membership(NULL) AS result; + result +-------- + 0 +(1 row) + +SELECT test_bms_next_member('', 5) AS result; + result +-------- + -2 +(1 row) + +SELECT test_bms_next_member('(b 5)', NULL) AS result; + result +-------- + -2 +(1 row) + +SELECT test_bms_next_member(NULL, 5) AS result; + result +-------- + -2 +(1 row) + +SELECT test_bms_next_member(NULL, NULL) AS result; + result +-------- + -2 +(1 row) + +SELECT test_bms_nonempty_difference('(b 5)', NULL) AS result; + result +-------- + t +(1 row) + +SELECT test_bms_nonempty_difference(NULL, '(b 5)') AS result; + result +-------- + f +(1 row) + +SELECT test_bms_nonempty_difference(NULL, NULL) AS result; + result +-------- + f +(1 row) + +SELECT test_bms_overlap('(b 5)', NULL) AS result; + result +-------- + f +(1 row) + +SELECT test_bms_overlap(NULL, '(b 5)') AS result; + result +-------- + f +(1 row) + +SELECT test_bms_overlap(NULL, NULL) AS result; + result +-------- + f +(1 row) + +SELECT test_bms_overlap_list('(b 5)', NULL) AS result; + result +-------- + f +(1 row) + +SELECT test_bms_overlap_list(NULL, ARRAY[1,2,3]) AS result; + result +-------- + f +(1 row) + +SELECT test_bms_overlap_list(NULL, NULL) AS result; + result +-------- + f +(1 row) + +SELECT test_bms_prev_member('', 5) AS result; + result +-------- + -2 +(1 row) + +SELECT test_bms_prev_member('(b 5)', NULL) AS result; + result +-------- + -2 +(1 row) + +SELECT test_bms_prev_member(NULL, 5) AS result; + result +-------- + -2 +(1 row) + +SELECT test_bms_replace_members('(b 1 2 3)', NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_replace_members('(b 5)', NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_replace_members(NULL, '(b 5)') AS result; + result +-------- + (b 5) +(1 row) + +SELECT test_bms_replace_members(NULL, NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_singleton_member(NULL) AS result; + result +-------- + +(1 row) + +SELECT test_bms_subset_compare('(b 5)', NULL) AS result; + result +-------- + 2 +(1 row) + +SELECT test_bms_subset_compare(NULL, '(b 5)') AS result; + result +-------- + 1 +(1 row) + +SELECT test_bms_subset_compare(NULL, NULL) AS result; + result +-------- + 0 +(1 row) + +SELECT test_bms_union('(b 5)', NULL) AS result; + result +-------- + (b 5) +(1 row) + +SELECT test_bms_union(NULL, '(b 5)') AS result; + result +-------- + (b 5) +(1 row) + +SELECT test_bms_union(NULL, NULL) AS result; + result +-------- + +(1 row) + DROP EXTENSION test_bitmapset; diff --git a/src/test/modules/test_bitmapset/sql/test_bitmapset.sql b/src/test/modules/test_bitmapset/sql/test_bitmapset.sql index 2b2c72c876b..67e0f01ccb6 100644 --- a/src/test/modules/test_bitmapset/sql/test_bitmapset.sql +++ b/src/test/modules/test_bitmapset/sql/test_bitmapset.sql @@ -23,6 +23,8 @@ SELECT test_bms_replace_members('(b 1 2 3)', NULL) AS result; SELECT test_bms_replace_members('(b 1 2 3)', '(b 3 5 6)') AS result; SELECT test_bms_replace_members('(b 1 2 3)', '(b 3 5)') AS result; SELECT test_bms_replace_members('(b 1 2)', '(b 3 5 7)') AS result; +-- Force repalloc() with larger set +SELECT test_bms_replace_members('(b 1 2 3 4 5)', '(b 500 600)') AS result; -- bms_del_member() SELECT test_bms_del_member('(b)', -20); -- error @@ -34,15 +36,32 @@ SELECT test_bms_del_member('(b 1 2 3)', 2) AS result; SELECT test_bms_del_member(test_bms_del_member('(b 0 31 32 63 64)', 32), 63) AS result; -- Word boundary SELECT test_bms_del_member(test_bms_add_range('(b)', 30, 34), 32) AS result; +-- Force word count changes +SELECT test_bms_del_member('(b 1 200)', 200) AS result; +SELECT test_bms_del_member('(b 1 50 100 200)', 200) AS result; +SELECT test_bms_del_member('(b 1 50 100 200)', 100) AS result; + +-- bms_del_members() +SELECT test_bms_del_members('(b)', '(b 10)') AS result; +SELECT test_bms_del_members('(b 10)', '(b 10)') AS result; +SELECT test_bms_del_members('(b 10)', '(b 5)') AS result; +SELECT test_bms_del_members('(b 1 2 3)', '(b 2)') AS result; +SELECT test_bms_del_members('(b 5 100)', '(b 100)') AS result; +SELECT test_bms_del_members('(b 5 100 200)', '(b 200)') AS result; +SELECT test_bms_del_members('(b 1 2 100 200 300)', '(b 1 2)') AS result; +SELECT test_bms_del_members('(b 1 2 100 200 300)', '(b 200 300)') AS result; -- bms_join() SELECT test_bms_join('(b 1 3 5)', NULL) AS result; SELECT test_bms_join(NULL, '(b 2 4 6)') AS result; SELECT test_bms_join('(b 1 3 5)', '(b 2 4 6)') AS result; SELECT test_bms_join('(b 1 3 5)', '(b 1 4 5)') AS result; +-- Force word count changes +SELECT test_bms_join('(b 5)', '(b 100)') AS result; +SELECT test_bms_join('(b 1 2)', '(b 100 200 300)') AS result; -- bms_union() --- Overlapping sets. +-- Overlapping sets SELECT test_bms_union('(b 1 3 5)', '(b 3 5 7)') AS result; -- Union with NULL SELECT test_bms_union('(b 1 3 5)', '(b)') AS result; @@ -53,21 +72,27 @@ SELECT test_bms_union( test_bms_add_range('(b)', 0, 15), test_bms_add_range('(b)', 10, 20) ) AS result; +-- Union with varrying word counts +SELECT test_bms_union('(b 1 2)', '(b 100 300)') AS result; +SELECT test_bms_union('(b 100 300)', '(b 1 2)') AS result; -- bms_intersect() -- Overlapping sets SELECT test_bms_intersect('(b 1 3 5)', '(b 3 5 7)') AS result; -- Disjoint sets SELECT test_bms_intersect('(b 1 3 5)', '(b 2 4 6)') AS result; --- Intersect with empty. +-- Intersect with empty SELECT test_bms_intersect('(b 1 3 5)', '(b)') AS result; +-- Intersect with varrying word counts +SELECT test_bms_intersect('(b 1 300)', '(b 1 2 3 4 5)') AS result; +SELECT test_bms_intersect('(b 1 2 3 4 5)', '(b 1 300)') AS result; -- bms_int_members() -- Overlapping sets SELECT test_bms_int_members('(b 1 3 5)', '(b 3 5 7)') AS result; -- Disjoint sets SELECT test_bms_int_members('(b 1 3 5)', '(b 2 4 6)') AS result; --- Intersect with empty. +-- Intersect with empty SELECT test_bms_int_members('(b 1 3 5)', '(b)') AS result; -- Multiple members SELECT test_bms_int_members('(b 0 31 32 63 64)', '(b 31 32 64 65)') AS result; @@ -82,10 +107,13 @@ SELECT test_bms_difference('(b 1 3 5)', '(b 1 3 5)') AS result; -- Substraction to empty SELECT test_bms_difference('(b 42)', '(b 42)') AS result; -- Subtraction edge case -SELECT test_bms_difference( +SELECT length(test_bms_difference( test_bms_add_range('(b)', 0, 100), test_bms_add_range('(b)', 50, 150) - ) AS result; + )) AS result; +-- Difference with different word counts +SELECT test_bms_difference('(b 5 100)', '(b 5)') AS result; +SELECT test_bms_difference('(b 1 2 100 200)', '(b 1 2)') AS result; -- bms_is_member() SELECT test_bms_is_member('(b)', -5); -- error @@ -99,6 +127,10 @@ SELECT test_bms_member_index(NULL, 1) AS result; SELECT test_bms_member_index('(b 1 3 5)', 2) AS result; SELECT test_bms_member_index('(b 1 3 5)', 1) AS result; SELECT test_bms_member_index('(b 1 3 5)', 3) AS result; +-- Member index with various word positions +SELECT test_bms_member_index('(b 100 200)', 100) AS result; +SELECT test_bms_member_index('(b 100 200)', 200) AS result; +SELECT test_bms_member_index('(b 1 50 100 200)', 200) AS result; -- bms_num_members() SELECT test_bms_num_members('(b)') AS result; @@ -111,6 +143,9 @@ SELECT test_bms_equal('(b)', '(b 1 3 5)') AS result; SELECT test_bms_equal('(b 1 3 5)', '(b)') AS result; SELECT test_bms_equal('(b 1 3 5)', '(b 1 3 5)') AS result; SELECT test_bms_equal('(b 1 3 5)', '(b 2 4 6)') AS result; +-- Equal with different word counts +SELECT test_bms_equal('(b 5)', '(b 100)') AS result; +SELECT test_bms_equal('(b 5 10)', '(b 100 200 300)') AS result; -- bms_compare() SELECT test_bms_compare('(b)', '(b)') AS result; @@ -138,6 +173,9 @@ SELECT length(test_bms_add_range('(b)', 0, 1000)) AS result; -- Force reallocations SELECT length(test_bms_add_range('(b)', 0, 200)) AS result; SELECT length(test_bms_add_range('(b)', 1000, 1100)) AS result; +-- Force word count expansion +SELECT test_bms_add_range('(b 5)', 100, 105) AS result; +SELECT length(test_bms_add_range('(b 1 2)', 200, 250)) AS result; -- bms_membership() SELECT test_bms_membership('(b)') AS result; @@ -150,10 +188,12 @@ SELECT test_bms_is_empty('(b)') AS result; SELECT test_bms_is_empty('(b 1)') AS result; -- bms_singleton_member() +SELECT test_bms_singleton_member('(b)'); -- error SELECT test_bms_singleton_member('(b 1 2)'); -- error SELECT test_bms_singleton_member('(b 42)') AS result; -- bms_get_singleton_member() +SELECT test_bms_get_singleton_member('(b)', 1000); -- error -- Not a singleton, returns input default SELECT test_bms_get_singleton_member('(b 3 6)', 1000) AS result; -- Singletone, returns sole member @@ -176,6 +216,8 @@ SELECT test_bms_prev_member('(b 5 10 15 20)', 20) AS result; SELECT test_bms_prev_member('(b 5 10 15 20)', 5) AS result; -- Empty set SELECT test_bms_prev_member('(b)', 100) AS result; +-- Negative prevbit should result in highest possible bit in set +SELECT test_bms_prev_member('(b 0 63 64 127)', -1) AS result; -- bms_hash_value() SELECT test_bms_hash_value('(b)') = 0 AS result; @@ -194,22 +236,40 @@ SELECT test_bms_is_subset('(b 1 3 5)', '(b 1 3)') AS result; SELECT test_bms_is_subset('(b 1 3)', '(b 2 4)') AS result; SELECT test_bms_is_subset(test_bms_add_range(NULL, 0, 31), test_bms_add_range(NULL, 0, 63)) AS result; +-- Is subset with shorter word counts +SELECT test_bms_is_subset('(b 5 100)', '(b 5)') AS result; +SELECT test_bms_is_subset('(b 1 2 50 100)', '(b 1 2)') AS result; -- bms_subset_compare() -SELECT test_bms_subset_compare(NULL, NULL) AS result; -SELECT test_bms_subset_compare('(b 1 3)', NULL) AS result; -SELECT test_bms_subset_compare(NULL, '(b 1 3)') AS result; -SELECT test_bms_subset_compare('(b 1 3 5)', '(b 1 3)') AS result; -SELECT test_bms_subset_compare('(b 1 3)', '(b 1 3 5)') AS result; -SELECT test_bms_subset_compare('(b 1 3 5)', '(b 1 3 5)') AS result; -SELECT test_bms_subset_compare('(b 1 3 5)', '(b 2 4 6)') AS result; +SELECT test_bms_subset_compare(NULL, NULL); +SELECT test_bms_subset_compare(NULL, '(b 1 3)'); +SELECT test_bms_subset_compare('(b)', '(b)'); +SELECT test_bms_subset_compare('(b)', '(b 1)'); +SELECT test_bms_subset_compare('(b 1)', '(b)'); +SELECT test_bms_subset_compare('(b 1 3)', NULL); +SELECT test_bms_subset_compare('(b 1 3 5)', '(b 1 3 5)'); +SELECT test_bms_subset_compare('(b 1 3)', '(b 1 3 5)'); +SELECT test_bms_subset_compare('(b 1 3 5)', '(b 1 3)'); +SELECT test_bms_subset_compare('(b 1 2)', '(b 1 3)'); +SELECT test_bms_subset_compare('(b 1 2)', '(b 1 4)'); +SELECT test_bms_subset_compare('(b 1 3)', '(b 1 3 64)'); +SELECT test_bms_subset_compare('(b 1 3 64)', '(b 1 3)'); +SELECT test_bms_subset_compare('(b 1 3 64)', '(b 1 3 65)'); +SELECT test_bms_subset_compare('(b 1 3)', '(b 2 4)'); +SELECT test_bms_subset_compare('(b 1)', '(b 64)'); +SELECT test_bms_subset_compare('(b 0)', '(b 32)'); +SELECT test_bms_subset_compare('(b 0)', '(b 64)'); +SELECT test_bms_subset_compare('(b 64)', '(b 1)'); +SELECT test_bms_subset_compare('(b 1 2)', '(b 1 2 64)'); +SELECT test_bms_subset_compare('(b 64 200)', '(b 1 201)'); +SELECT test_bms_subset_compare('(b 1 64 65)', '(b 1 2 64)'); +SELECT test_bms_subset_compare('(b 2 64 128)', '(b 1 65)'); -- bms_copy() SELECT test_bms_copy(NULL) AS result; SELECT test_bms_copy('(b 1 3 5 7)') AS result; -- bms_add_members() -SELECT test_bms_add_member('(b)', 1000); -- error SELECT test_bms_add_members('(b 1 3)', '(b 5 7)') AS result; SELECT test_bms_add_members('(b 1 3 5)', '(b 2 5 7)') AS result; SELECT test_bms_add_members('(b 1 3 5)', '(b 100 200 300)') AS result; @@ -243,6 +303,9 @@ SELECT test_bms_overlap_list('(b 7 10)', ARRAY[6,7,8,9]) AS result; SELECT test_bms_overlap_list('(b 1 5)', ARRAY[6,7,8,9]) AS result; -- Empty list SELECT test_bms_overlap_list('(b 1)', ARRAY[]::integer[]) AS result; +-- Overlap list with negative numbers +SELECT test_bms_overlap_list('(b 5 10)', ARRAY[-1,5]) AS result; -- error +SELECT test_bms_overlap_list('(b 1 2 3)', ARRAY[-5,-1,0]) AS result; -- error -- bms_nonempty_difference() SELECT test_bms_nonempty_difference(NULL, '(b 1 3 5)') AS result; @@ -250,8 +313,92 @@ SELECT test_bms_nonempty_difference('(b 1 3 5)', NULL) AS result; SELECT test_bms_nonempty_difference('(b 1 3 5)', '(b 2 4 6)') AS result; SELECT test_bms_nonempty_difference('(b 1 3 5)', '(b 1 5)') AS result; SELECT test_bms_nonempty_difference('(b 1 3 5)', '(b 1 3 5)') AS result; +-- Difference with different word counts +SELECT test_bms_nonempty_difference('(b 5)', '(b 100)') AS result; +SELECT test_bms_nonempty_difference('(b 100)', '(b 5)') AS result; +SELECT test_bms_nonempty_difference('(b 1 2)', '(b 50 100)') AS result; -- random operations SELECT test_random_operations(-1, 10000, 81920, 0) > 0 AS result; +-- Cover the test API's corner cases such as when ARGISNULL, +-- or VARSIZE_ANY_EXHDR == 0, etc. + +SELECT test_bitmap_hash(NULL) AS result; +SELECT test_bitmap_match('(b 5)', NULL) AS result; +SELECT test_bitmap_match(NULL, '(b 5)') AS result; +SELECT test_bitmap_match(NULL, NULL) AS result; +SELECT test_bms_add_member('(b)', NULL) AS result; +SELECT test_bms_add_range('(b 5)', 5, NULL) AS result; +SELECT test_bms_add_range('(b 5)', NULL, 10) AS result; +SELECT test_bms_add_range('(b 5)', NULL, NULL) AS result; +SELECT test_bms_add_range(NULL, 5, 10) AS result; +SELECT test_bms_add_range(NULL, 10, 5) AS result; +SELECT test_bms_add_range(NULL, NULL, NULL) AS result; +SELECT test_bms_compare('(b 5)', NULL) AS result; +SELECT test_bms_compare(NULL, '(b 5)') AS result; +SELECT test_bms_compare(NULL, NULL) AS result; +SELECT test_bms_copy(NULL) AS result; +SELECT test_bms_del_member('(b 42)', 42) AS result; +SELECT test_bms_del_member('(b 5)', NULL) AS result; +SELECT test_bms_del_members('(b 5)', NULL) AS result; +SELECT test_bms_del_members(NULL, '(b 5)') AS result; +SELECT test_bms_difference('(b 5)', '(b 5 10)') AS result; +SELECT test_bms_difference('(b 5)', NULL) AS result; +SELECT test_bms_difference(NULL, '(b 5)') AS result; +SELECT test_bms_difference(NULL, NULL) AS result; +SELECT test_bms_equal('(b 5)', NULL) AS result; +SELECT test_bms_equal(NULL, '(b 5)') AS result; +SELECT test_bms_equal(NULL, NULL) AS result; +SELECT test_bms_get_singleton_member('', 1000) AS result; +SELECT test_bms_get_singleton_member(NULL, -1) AS result; +SELECT test_bms_hash_value(NULL) AS result; +SELECT test_bms_int_members('(b 1)', '(b 2)') AS result; +SELECT test_bms_int_members('(b 5)', NULL) AS result; +SELECT test_bms_int_members(NULL, '(b 5)') AS result; +SELECT test_bms_int_members(NULL, NULL) AS result; +SELECT test_bms_intersect('(b 1)', '(b 2)') AS result; +SELECT test_bms_intersect('(b 5)', NULL) AS result; +SELECT test_bms_intersect(NULL, '(b 5)') AS result; +SELECT test_bms_intersect(NULL, NULL) AS result; +SELECT test_bms_is_empty(NULL) AS result; +SELECT test_bms_is_member('(b 5)', NULL) AS result; +SELECT test_bms_is_subset('(b 5)', NULL) AS result; +SELECT test_bms_is_subset(NULL, '(b 5)') AS result; +SELECT test_bms_is_subset(NULL, NULL) AS result; +SELECT test_bms_join('(b 5)', NULL) AS result; +SELECT test_bms_join(NULL, '(b 5)') AS result; +SELECT test_bms_join(NULL, NULL) AS result; +SELECT test_bms_make_singleton(NULL) AS result; +SELECT test_bms_member_index('', 5) AS result; +SELECT test_bms_member_index(NULL, 5) AS result; +SELECT test_bms_membership(NULL) AS result; +SELECT test_bms_next_member('', 5) AS result; +SELECT test_bms_next_member('(b 5)', NULL) AS result; +SELECT test_bms_next_member(NULL, 5) AS result; +SELECT test_bms_next_member(NULL, NULL) AS result; +SELECT test_bms_nonempty_difference('(b 5)', NULL) AS result; +SELECT test_bms_nonempty_difference(NULL, '(b 5)') AS result; +SELECT test_bms_nonempty_difference(NULL, NULL) AS result; +SELECT test_bms_overlap('(b 5)', NULL) AS result; +SELECT test_bms_overlap(NULL, '(b 5)') AS result; +SELECT test_bms_overlap(NULL, NULL) AS result; +SELECT test_bms_overlap_list('(b 5)', NULL) AS result; +SELECT test_bms_overlap_list(NULL, ARRAY[1,2,3]) AS result; +SELECT test_bms_overlap_list(NULL, NULL) AS result; +SELECT test_bms_prev_member('', 5) AS result; +SELECT test_bms_prev_member('(b 5)', NULL) AS result; +SELECT test_bms_prev_member(NULL, 5) AS result; +SELECT test_bms_replace_members('(b 1 2 3)', NULL) AS result; +SELECT test_bms_replace_members('(b 5)', NULL) AS result; +SELECT test_bms_replace_members(NULL, '(b 5)') AS result; +SELECT test_bms_replace_members(NULL, NULL) AS result; +SELECT test_bms_singleton_member(NULL) AS result; +SELECT test_bms_subset_compare('(b 5)', NULL) AS result; +SELECT test_bms_subset_compare(NULL, '(b 5)') AS result; +SELECT test_bms_subset_compare(NULL, NULL) AS result; +SELECT test_bms_union('(b 5)', NULL) AS result; +SELECT test_bms_union(NULL, '(b 5)') AS result; +SELECT test_bms_union(NULL, NULL) AS result; + DROP EXTENSION test_bitmapset; diff --git a/src/test/modules/test_bitmapset/test_bitmapset--1.0.sql b/src/test/modules/test_bitmapset/test_bitmapset--1.0.sql index 95f5ee02e3f..b95c4d0dda5 100644 --- a/src/test/modules/test_bitmapset/test_bitmapset--1.0.sql +++ b/src/test/modules/test_bitmapset/test_bitmapset--1.0.sql @@ -112,6 +112,10 @@ CREATE FUNCTION test_bms_int_members(text, text) RETURNS text AS 'MODULE_PATHNAME' LANGUAGE C; +CREATE FUNCTION test_bms_del_members(text, text) +RETURNS text +AS 'MODULE_PATHNAME' LANGUAGE C; + CREATE FUNCTION test_bms_replace_members(text, text) RETURNS text AS 'MODULE_PATHNAME' LANGUAGE C; diff --git a/src/test/modules/test_bitmapset/test_bitmapset.c b/src/test/modules/test_bitmapset/test_bitmapset.c index 5bc4daa23f1..77b6c70af66 100644 --- a/src/test/modules/test_bitmapset/test_bitmapset.c +++ b/src/test/modules/test_bitmapset/test_bitmapset.c @@ -58,6 +58,7 @@ PG_FUNCTION_INFO_V1(test_bms_member_index); PG_FUNCTION_INFO_V1(test_bms_add_range); PG_FUNCTION_INFO_V1(test_bms_add_members); PG_FUNCTION_INFO_V1(test_bms_int_members); +PG_FUNCTION_INFO_V1(test_bms_del_members); PG_FUNCTION_INFO_V1(test_bms_replace_members); PG_FUNCTION_INFO_V1(test_bms_join); PG_FUNCTION_INFO_V1(test_bitmap_hash); @@ -111,9 +112,6 @@ test_bms_add_member(PG_FUNCTION_ARGS) if (bms) bms_free(bms); - if (result == NULL) - PG_RETURN_NULL(); - PG_RETURN_TEXT_P(result); } @@ -136,9 +134,6 @@ test_bms_add_members(PG_FUNCTION_ARGS) if (bms2) bms_free(bms2); - if (bms1 == NULL) - PG_RETURN_NULL(); - result = BITMAPSET_TO_TEXT(bms1); bms_free(bms1); @@ -161,12 +156,8 @@ test_bms_del_member(PG_FUNCTION_ARGS) member = PG_GETARG_INT32(1); bms = bms_del_member(bms, member); - if (bms == NULL || bms_is_empty(bms)) - { - if (bms) - bms_free(bms); + if (bms_is_empty(bms)) PG_RETURN_NULL(); - } result = BITMAPSET_TO_TEXT(bms); bms_free(bms); @@ -514,12 +505,10 @@ Datum test_bms_get_singleton_member(PG_FUNCTION_ARGS) { Bitmapset *bms = NULL; - int32 default_member = PG_GETARG_INT32(1); - int member; - bool success; + int member = - 1; if (PG_ARGISNULL(0)) - PG_RETURN_INT32(default_member); + PG_RETURN_INT32(member); bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0)); @@ -527,13 +516,10 @@ test_bms_get_singleton_member(PG_FUNCTION_ARGS) * bms_get_singleton_member returns bool and stores result in member * pointer */ - success = bms_get_singleton_member(bms, &member); + bms_get_singleton_member(bms, &member); bms_free(bms); - if (success) - PG_RETURN_INT32(member); - else - PG_RETURN_INT32(default_member); + PG_RETURN_INT32(member); } Datum @@ -609,11 +595,6 @@ test_bms_overlap_list(PG_FUNCTION_ARGS) array = PG_GETARG_ARRAYTYPE_P(1); - if (ARR_ELEMTYPE(array) != INT4OID) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("integer array expected"))); - deconstruct_array(array, INT4OID, sizeof(int32), true, 'i', &elem_datums, &elem_nulls, &elem_count); @@ -752,6 +733,37 @@ test_bms_int_members(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(result); } +Datum +test_bms_del_members(PG_FUNCTION_ARGS) +{ + Bitmapset *bms1 = NULL, + *bms2 = NULL; + Bitmapset *result_bms; + text *result; + + if (!PG_ARGISNULL(0)) + bms1 = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0)); + + if (!PG_ARGISNULL(1)) + bms2 = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(1)); + + /* IMPORTANT: bms_del_members modifies/frees the first argument */ + result_bms = bms_del_members(bms1, bms2); + + /* bms1 is now invalid, do not free it */ + + if (bms2) + bms_free(bms2); + + if (result_bms == NULL) + PG_RETURN_NULL(); + + result = BITMAPSET_TO_TEXT(result_bms); + bms_free(result_bms); + + PG_RETURN_TEXT_P(result); +} + Datum test_bms_replace_members(PG_FUNCTION_ARGS) { -- 2.49.0