Compare commits

..

5 Commits

Author SHA1 Message Date
Michael Paquier
684a745f55 pgstattuple: Improve reports generated for indexes (hash, gist, btree)
pgstattuple checks the state of the pages retrieved for gist and hash
using some check functions from each index AM, respectively
gistcheckpage() and _hash_checkpage().  When these are called, they
would fail when bumping on data that is found as incorrect (like opaque
area size not matching, or empty pages), contrary to btree that simply
discards these cases and continues to aggregate data.

Zero pages can happen after a crash, with these AMs being able to do an
internal cleanup when these are seen.  Also, sporadic failures are
annoying when doing for example a large-scale diagnostic query based on
pgstattuple with a join of pg_class, as it forces one to use tricks like
quals to discard hash or gist indexes, or use a PL wrapper able to catch
errors.

This commit changes the reports generated for btree, gist and hash to
be more user-friendly;
- When seeing an empty page, report it as free space.  This new rule
applies to gist and hash, and already applied to btree.
- For btree, a check based on the size of BTPageOpaqueData is added.
- For gist indexes, gistcheckpage() is not called anymore, replaced by a
check based on the size of GISTPageOpaqueData.
- For hash indexes, instead of _hash_getbuf_with_strategy(), use a
direct call to ReadBufferExtended(), coupled with a check based on
HashPageOpaqueData.  The opaque area size check was already used.
- Pages that do not match these criterias are discarded from the stats
reports generated.

There have been a couple of bug reports over the years that complained
about the current behavior for hash and gist, as being not that useful,
with nothing being done about it.  Hence this change is backpatched down
to v13.

Reported-by: Noah Misch <noah@leadboat.com>
Author: Nitin Motiani <nitinmotiani@google.com>
Reviewed-by: Dilip Kumar <dilipbalaut@gmail.com>
Discussion: https://postgr.es/m/CAH5HC95gT1J3dRYK4qEnaywG8RqjbwDdt04wuj8p39R=HukayA@mail.gmail.com
Backpatch-through: 13
2025-10-02 11:07:30 +09:00
Jacob Champion
fd726b8379 test_json_parser: Speed up 002_inline.pl
Some macOS machines are having trouble with 002_inline, which executes
the JSON parser test executables hundreds of times in a nested loop.
Both developer machines and buildfarm critters have shown excessive test
durations, upwards of 20 seconds.

Push the innermost loop of 002_inline, which iterates through differing
chunk sizes, down into the test executable. (I'd eventually like to push
all of the JSON unit tests down into C, but this is an easy win in the
short term.) Testers have reported a speedup between 4-9x.

Reported-by: Robert Haas <robertmhaas@gmail.com>
Suggested-by: Andres Freund <andres@anarazel.de>
Tested-by: Andrew Dunstan <andrew@dunslane.net>
Tested-by: Tom Lane <tgl@sss.pgh.pa.us>
Tested-by: Robert Haas <robertmhaas@gmail.com>
Discussion: https://postgr.es/m/CA%2BTgmobKoG%2BgKzH9qB7uE4MFo-z1hn7UngqAe9b0UqNbn3_XGQ%40mail.gmail.com
Backpatch-through: 17
2025-10-01 09:48:57 -07:00
Peter Eisentraut
3e908fb54f Fix compiler warnings around _CRT_glob
Newer compilers warned about

    extern int _CRT_glob = 0;

which is indeed a mysterious C construction, as it combines "extern"
and an initialization.  It turns out that according to the C standard,
the "extern" is ignored here, so we can remove it to resolve the
warnings.  But then we also need to add a real extern
declaration (without initializer) to satisfy
-Wmissing-variable-declarations.

(Note that this code is only active on MinGW.)

Discussion: https://www.postgresql.org/message-id/1053279b-da01-4eb4-b7a3-da6b5d8f73d1%40eisentraut.org
2025-10-01 17:13:52 +02:00
David Rowley
3a66158068 Minor fixups of test_bitmapset.c
The macro's comment had become outdated from a prior version and there's
now no longer a need for the do/while loop (or my misplaced semi-colon).

Author: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/CAApHDvr+P454SP_LDvB=bViPAbDQhV1Jmg5M55GEKz0d3z25NA@mail.gmail.com
2025-10-01 18:50:28 +13:00
Michael Paquier
9952f6c05a test_bitmapset: Simplify code of the module
Two macros are added in this module, to cut duplicated patterns:
- PG_ARG_GETBITMAPSET(), for input argument handling, with knowledge
about NULL.
- PG_RETURN_BITMAPSET_AS_TEXT(), that generates a text result from a
Bitmapset.

These changes limit the code so as the SQL functions are now mostly
wrappers of the equivalent C function.  Functions that use integer input
arguments still need some NULL handling, like bms_make_singleton().

A NULL input is translated to "<>", which is what nodeToString()
generates.  Some of the tests are able to generate this result.

Per discussion, the calls of bms_free() are removed.  These may be
justified if the functions are used in a rather long-lived memory
context, but let's keep the code minimal for now.  These calls used NULL
checks, which were also not necessary as NULL is an input authorized by
bms_free().

Some of the tests existed to cover behaviors related to the SQL
functions for NULL inputs.  Most of them are still relevant, as the
routines of bitmapset.c are able to handle such cases.

The coverage reports of bitmapset.c and test_bitmapset.c remain the
same after these changes, with 300 lines of C code removed.

Author: David Rowley <dgrowleyml@gmail.com>
Co-authored-by: Greg Burd <greg@burd.me>
Discussion: https://postgr.es/m/CAApHDvqghMnm_zgSNefto9oaEJ0S-3Cgb3gdsV7XvLC-hMS02Q@mail.gmail.com
2025-10-01 14:17:54 +09:00
9 changed files with 395 additions and 801 deletions

View File

@ -424,7 +424,7 @@ pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
/* fully empty page */ /* fully empty page */
stat->free_space += BLCKSZ; stat->free_space += BLCKSZ;
} }
else else if (PageGetSpecialSize(page) == MAXALIGN(sizeof(BTPageOpaqueData)))
{ {
BTPageOpaque opaque; BTPageOpaque opaque;
@ -458,10 +458,16 @@ pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
Buffer buf; Buffer buf;
Page page; Page page;
buf = _hash_getbuf_with_strategy(rel, blkno, HASH_READ, 0, bstrategy); buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
LockBuffer(buf, HASH_READ);
page = BufferGetPage(buf); page = BufferGetPage(buf);
if (PageGetSpecialSize(page) == MAXALIGN(sizeof(HashPageOpaqueData))) if (PageIsNew(page))
{
/* fully empty page */
stat->free_space += BLCKSZ;
}
else if (PageGetSpecialSize(page) == MAXALIGN(sizeof(HashPageOpaqueData)))
{ {
HashPageOpaque opaque; HashPageOpaque opaque;
@ -502,17 +508,23 @@ pgstat_gist_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy); buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
LockBuffer(buf, GIST_SHARE); LockBuffer(buf, GIST_SHARE);
gistcheckpage(rel, buf);
page = BufferGetPage(buf); page = BufferGetPage(buf);
if (PageIsNew(page))
if (GistPageIsLeaf(page))
{ {
pgstat_index_page(stat, page, FirstOffsetNumber, /* fully empty page */
PageGetMaxOffsetNumber(page)); stat->free_space += BLCKSZ;
} }
else else if (PageGetSpecialSize(page) == MAXALIGN(sizeof(GISTPageOpaqueData)))
{ {
/* root or node */ if (GistPageIsLeaf(page))
{
pgstat_index_page(stat, page, FirstOffsetNumber,
PageGetMaxOffsetNumber(page));
}
else
{
/* root or node */
}
} }
UnlockReleaseBuffer(buf); UnlockReleaseBuffer(buf);

View File

@ -46,7 +46,8 @@
/* Inhibit mingw CRT's auto-globbing of command line arguments */ /* Inhibit mingw CRT's auto-globbing of command line arguments */
#if defined(WIN32) && !defined(_MSC_VER) #if defined(WIN32) && !defined(_MSC_VER)
extern int _CRT_glob = 0; /* 0 turns off globbing; 1 turns it on */ extern int _CRT_glob;
int _CRT_glob = 0; /* 0 turns off globbing; 1 turns it on */
#endif #endif
/* /*

View File

@ -76,7 +76,7 @@ SELECT test_bms_replace_members(NULL, '(b 1 2 3)') AS result;
SELECT test_bms_replace_members('(b 1 2 3)', NULL) AS result; SELECT test_bms_replace_members('(b 1 2 3)', NULL) AS result;
result result
-------- --------
<>
(1 row) (1 row)
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 6)') AS result;
@ -104,44 +104,19 @@ SELECT test_bms_replace_members('(b 1 2 3 4 5)', '(b 500 600)') AS result;
(b 500 600) (b 500 600)
(1 row) (1 row)
-- Test module checks
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)
-- bms_del_member() -- bms_del_member()
SELECT test_bms_del_member('(b)', -20); -- error SELECT test_bms_del_member('(b)', -20); -- error
ERROR: negative bitmapset member not allowed ERROR: negative bitmapset member not allowed
SELECT test_bms_del_member('(b)', 10) AS result; SELECT test_bms_del_member('(b)', 10) AS result;
result result
-------- --------
<>
(1 row) (1 row)
SELECT test_bms_del_member('(b 10)', 10) AS result; SELECT test_bms_del_member('(b 10)', 10) AS result;
result result
-------- --------
<>
(1 row) (1 row)
SELECT test_bms_del_member('(b 10)', 5) AS result; SELECT test_bms_del_member('(b 10)', 5) AS result;
@ -190,12 +165,6 @@ SELECT test_bms_del_member('(b 1 50 100 200)', 100) AS result;
(1 row) (1 row)
-- Test module checks -- Test module checks
SELECT test_bms_del_member('(b 42)', 42) AS result;
result
--------
(1 row)
SELECT test_bms_del_member('(b 5)', NULL) AS result; SELECT test_bms_del_member('(b 5)', NULL) AS result;
result result
-------- --------
@ -206,13 +175,13 @@ SELECT test_bms_del_member('(b 5)', NULL) AS result;
SELECT test_bms_del_members('(b)', '(b 10)') AS result; SELECT test_bms_del_members('(b)', '(b 10)') AS result;
result result
-------- --------
<>
(1 row) (1 row)
SELECT test_bms_del_members('(b 10)', '(b 10)') AS result; SELECT test_bms_del_members('(b 10)', '(b 10)') AS result;
result result
-------- --------
<>
(1 row) (1 row)
SELECT test_bms_del_members('(b 10)', '(b 5)') AS result; SELECT test_bms_del_members('(b 10)', '(b 5)') AS result;
@ -252,7 +221,7 @@ SELECT test_bms_del_members('(b 1 2 100 200 300)', '(b 200 300)') AS result;
(b 1 2 100) (b 1 2 100)
(1 row) (1 row)
-- Test module checks -- NULL inputs
SELECT test_bms_del_members('(b 5)', NULL) AS result; SELECT test_bms_del_members('(b 5)', NULL) AS result;
result result
-------- --------
@ -262,7 +231,7 @@ SELECT test_bms_del_members('(b 5)', NULL) AS result;
SELECT test_bms_del_members(NULL, '(b 5)') AS result; SELECT test_bms_del_members(NULL, '(b 5)') AS result;
result result
-------- --------
<>
(1 row) (1 row)
-- bms_join() -- bms_join()
@ -303,7 +272,7 @@ SELECT test_bms_join('(b 1 2)', '(b 100 200 300)') AS result;
(b 1 2 100 200 300) (b 1 2 100 200 300)
(1 row) (1 row)
-- Test module checks -- NULL inputs
SELECT test_bms_join('(b 5)', NULL) AS result; SELECT test_bms_join('(b 5)', NULL) AS result;
result result
-------- --------
@ -319,7 +288,7 @@ SELECT test_bms_join(NULL, '(b 5)') AS result;
SELECT test_bms_join(NULL, NULL) AS result; SELECT test_bms_join(NULL, NULL) AS result;
result result
-------- --------
<>
(1 row) (1 row)
-- bms_union() -- bms_union()
@ -341,7 +310,7 @@ SELECT test_bms_union('(b 1 3 5)', '(b)') AS result;
SELECT test_bms_union('(b)', '(b)') AS result; SELECT test_bms_union('(b)', '(b)') AS result;
result result
-------- --------
<>
(1 row) (1 row)
-- Overlapping ranges -- Overlapping ranges
@ -354,7 +323,7 @@ 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) (b 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)
(1 row) (1 row)
-- Union with varrying word counts -- Union with varying word counts
SELECT test_bms_union('(b 1 2)', '(b 100 300)') AS result; SELECT test_bms_union('(b 1 2)', '(b 100 300)') AS result;
result result
----------------- -----------------
@ -367,7 +336,7 @@ SELECT test_bms_union('(b 100 300)', '(b 1 2)') AS result;
(b 1 2 100 300) (b 1 2 100 300)
(1 row) (1 row)
-- Test module checks -- NULL inputs
SELECT test_bms_union('(b 5)', NULL) AS result; SELECT test_bms_union('(b 5)', NULL) AS result;
result result
-------- --------
@ -383,7 +352,7 @@ SELECT test_bms_union(NULL, '(b 5)') AS result;
SELECT test_bms_union(NULL, NULL) AS result; SELECT test_bms_union(NULL, NULL) AS result;
result result
-------- --------
<>
(1 row) (1 row)
-- bms_intersect() -- bms_intersect()
@ -398,17 +367,17 @@ SELECT test_bms_intersect('(b 1 3 5)', '(b 3 5 7)') AS result;
SELECT test_bms_intersect('(b 1 3 5)', '(b 2 4 6)') AS result; SELECT test_bms_intersect('(b 1 3 5)', '(b 2 4 6)') AS result;
result result
-------- --------
<>
(1 row) (1 row)
-- Intersect with empty -- Intersect with empty
SELECT test_bms_intersect('(b 1 3 5)', '(b)') AS result; SELECT test_bms_intersect('(b 1 3 5)', '(b)') AS result;
result result
-------- --------
<>
(1 row) (1 row)
-- Intersect with varrying word counts -- Intersect with varying word counts
SELECT test_bms_intersect('(b 1 300)', '(b 1 2 3 4 5)') AS result; SELECT test_bms_intersect('(b 1 300)', '(b 1 2 3 4 5)') AS result;
result result
-------- --------
@ -421,29 +390,23 @@ SELECT test_bms_intersect('(b 1 2 3 4 5)', '(b 1 300)') AS result;
(b 1) (b 1)
(1 row) (1 row)
-- Test module checks -- NULL inputs
SELECT test_bms_intersect('(b 1)', '(b 2)') AS result;
result
--------
(1 row)
SELECT test_bms_intersect('(b 5)', NULL) AS result; SELECT test_bms_intersect('(b 5)', NULL) AS result;
result result
-------- --------
<>
(1 row) (1 row)
SELECT test_bms_intersect(NULL, '(b 5)') AS result; SELECT test_bms_intersect(NULL, '(b 5)') AS result;
result result
-------- --------
<>
(1 row) (1 row)
SELECT test_bms_intersect(NULL, NULL) AS result; SELECT test_bms_intersect(NULL, NULL) AS result;
result result
-------- --------
<>
(1 row) (1 row)
-- bms_int_members() -- bms_int_members()
@ -458,14 +421,14 @@ SELECT test_bms_int_members('(b 1 3 5)', '(b 3 5 7)') AS result;
SELECT test_bms_int_members('(b 1 3 5)', '(b 2 4 6)') AS result; SELECT test_bms_int_members('(b 1 3 5)', '(b 2 4 6)') AS result;
result result
-------- --------
<>
(1 row) (1 row)
-- Intersect with empty -- Intersect with empty
SELECT test_bms_int_members('(b 1 3 5)', '(b)') AS result; SELECT test_bms_int_members('(b 1 3 5)', '(b)') AS result;
result result
-------- --------
<>
(1 row) (1 row)
-- Multiple members -- Multiple members
@ -475,29 +438,23 @@ SELECT test_bms_int_members('(b 0 31 32 63 64)', '(b 31 32 64 65)') AS result;
(b 31 32 64) (b 31 32 64)
(1 row) (1 row)
-- Test module checks -- NULL inputs
SELECT test_bms_int_members('(b 1)', '(b 2)') AS result;
result
--------
(1 row)
SELECT test_bms_int_members('(b 5)', NULL) AS result; SELECT test_bms_int_members('(b 5)', NULL) AS result;
result result
-------- --------
<>
(1 row) (1 row)
SELECT test_bms_int_members(NULL, '(b 5)') AS result; SELECT test_bms_int_members(NULL, '(b 5)') AS result;
result result
-------- --------
<>
(1 row) (1 row)
SELECT test_bms_int_members(NULL, NULL) AS result; SELECT test_bms_int_members(NULL, NULL) AS result;
result result
-------- --------
<>
(1 row) (1 row)
-- bms_difference() -- bms_difference()
@ -519,14 +476,14 @@ SELECT test_bms_difference('(b 1 3 5)', '(b 2 4 6)') AS result;
SELECT test_bms_difference('(b 1 3 5)', '(b 1 3 5)') AS result; SELECT test_bms_difference('(b 1 3 5)', '(b 1 3 5)') AS result;
result result
-------- --------
<>
(1 row) (1 row)
-- Substraction to empty -- Substraction to empty
SELECT test_bms_difference('(b 42)', '(b 42)') AS result; SELECT test_bms_difference('(b 42)', '(b 42)') AS result;
result result
-------- --------
<>
(1 row) (1 row)
-- Subtraction edge case -- Subtraction edge case
@ -552,13 +509,7 @@ SELECT test_bms_difference('(b 1 2 100 200)', '(b 1 2)') AS result;
(b 100 200) (b 100 200)
(1 row) (1 row)
-- Test module checks -- NULL inputs
SELECT test_bms_difference('(b 5)', '(b 5 10)') AS result;
result
--------
(1 row)
SELECT test_bms_difference('(b 5)', NULL) AS result; SELECT test_bms_difference('(b 5)', NULL) AS result;
result result
-------- --------
@ -568,13 +519,13 @@ SELECT test_bms_difference('(b 5)', NULL) AS result;
SELECT test_bms_difference(NULL, '(b 5)') AS result; SELECT test_bms_difference(NULL, '(b 5)') AS result;
result result
-------- --------
<>
(1 row) (1 row)
SELECT test_bms_difference(NULL, NULL) AS result; SELECT test_bms_difference(NULL, NULL) AS result;
result result
-------- --------
<>
(1 row) (1 row)
-- bms_is_member() -- bms_is_member()
@ -608,7 +559,7 @@ SELECT test_bms_is_member('(b)', 1) AS result;
SELECT test_bms_is_member('(b 5)', NULL) AS result; SELECT test_bms_is_member('(b 5)', NULL) AS result;
result result
-------- --------
f
(1 row) (1 row)
-- bms_member_index() -- bms_member_index()
@ -655,17 +606,11 @@ SELECT test_bms_member_index('(b 1 50 100 200)', 200) AS result;
3 3
(1 row) (1 row)
-- Test module checks -- Test module check
SELECT test_bms_member_index('', 5) AS result; SELECT test_bms_member_index('(b 1 3 5)', NULL) AS result;
result result
-------- --------
-1
(1 row)
SELECT test_bms_member_index(NULL, 5) AS result;
result
--------
-1
(1 row) (1 row)
-- bms_num_members() -- bms_num_members()
@ -731,7 +676,7 @@ SELECT test_bms_equal('(b 5 10)', '(b 100 200 300)') AS result;
f f
(1 row) (1 row)
-- Test module checks -- NULL inputs
SELECT test_bms_equal('(b 5)', NULL) AS result; SELECT test_bms_equal('(b 5)', NULL) AS result;
result result
-------- --------
@ -796,7 +741,7 @@ SELECT test_bms_compare(
-1 -1
(1 row) (1 row)
-- Test module checks -- NULL inputs
SELECT test_bms_compare('(b 5)', NULL) AS result; SELECT test_bms_compare('(b 5)', NULL) AS result;
result result
-------- --------
@ -902,6 +847,7 @@ SELECT test_bms_add_range('(b 5)', NULL, NULL) AS result;
(1 row) (1 row)
-- NULL inputs
SELECT test_bms_add_range(NULL, 5, 10) AS result; SELECT test_bms_add_range(NULL, 5, 10) AS result;
result result
------------------ ------------------
@ -911,13 +857,7 @@ 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, 10, 5) AS result;
result result
-------- --------
<>
(1 row)
SELECT test_bms_add_range(NULL, NULL, NULL) AS result;
result
--------
(1 row) (1 row)
-- bms_membership() -- bms_membership()
@ -939,7 +879,7 @@ SELECT test_bms_membership('(b 1 2)') AS result;
2 2
(1 row) (1 row)
-- Test module check -- NULL input
SELECT test_bms_membership(NULL) AS result; SELECT test_bms_membership(NULL) AS result;
result result
-------- --------
@ -965,13 +905,6 @@ SELECT test_bms_is_empty('(b 1)') AS result;
f f
(1 row) (1 row)
-- Test module check
SELECT test_bms_is_empty(NULL) AS result;
result
--------
t
(1 row)
-- bms_singleton_member() -- bms_singleton_member()
SELECT test_bms_singleton_member('(b)'); -- error SELECT test_bms_singleton_member('(b)'); -- error
ERROR: bitmapset is empty ERROR: bitmapset is empty
@ -983,7 +916,7 @@ SELECT test_bms_singleton_member('(b 42)') AS result;
42 42
(1 row) (1 row)
-- Test module check -- NULL input
SELECT test_bms_singleton_member(NULL) AS result; SELECT test_bms_singleton_member(NULL) AS result;
result result
-------- --------
@ -991,39 +924,33 @@ SELECT test_bms_singleton_member(NULL) AS result;
(1 row) (1 row)
-- bms_get_singleton_member() -- bms_get_singleton_member()
SELECT test_bms_get_singleton_member('(b)', 1000); SELECT test_bms_get_singleton_member('(b)');
test_bms_get_singleton_member test_bms_get_singleton_member
------------------------------- -------------------------------
1000 -1
(1 row) (1 row)
-- Not a singleton, returns input default -- Try with an empty set
SELECT test_bms_get_singleton_member('(b 3 6)', 1000) AS result; SELECT test_bms_get_singleton_member(NULL) AS result;
result
--------
1000
(1 row)
-- Singletone, returns sole member
SELECT test_bms_get_singleton_member('(b 400)', 1000) AS result;
result
--------
400
(1 row)
-- Test module checks
SELECT test_bms_get_singleton_member('', 1000) AS result;
result
--------
1000
(1 row)
SELECT test_bms_get_singleton_member(NULL, -1) AS result;
result result
-------- --------
-1 -1
(1 row) (1 row)
-- Not a singleton, returns input default
SELECT test_bms_get_singleton_member('(b 3 6)') AS result;
result
--------
-1
(1 row)
-- Singletone, returns sole member
SELECT test_bms_get_singleton_member('(b 400)') AS result;
result
--------
400
(1 row)
-- bms_next_member() and bms_prev_member() -- bms_next_member() and bms_prev_member()
-- First member -- First member
SELECT test_bms_next_member('(b 5 10 15 20)', -1) AS result; SELECT test_bms_next_member('(b 5 10 15 20)', -1) AS result;
@ -1088,49 +1015,32 @@ SELECT test_bms_prev_member('(b 0 63 64 127)', -1) AS result;
127 127
(1 row) (1 row)
-- Test module checks -- NULL inputs
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; SELECT test_bms_next_member(NULL, 5) AS result;
result result
-------- --------
-2 -2
(1 row) (1 row)
SELECT test_bms_next_member(NULL, NULL) AS result;
result
--------
-2
(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; SELECT test_bms_prev_member(NULL, 5) AS result;
result result
-------- --------
-2 -2
(1 row) (1 row)
-- Test module check
SELECT test_bms_next_member('(b 5 10)', NULL) AS result;
result
--------
(1 row)
SELECT test_bms_prev_member('(b 5 10)', NULL) AS result;
result
--------
(1 row)
-- bms_hash_value() -- bms_hash_value()
SELECT test_bms_hash_value('(b)') = 0 AS result; SELECT test_bms_hash_value('(b)') = 0 AS result;
result result
@ -1150,7 +1060,7 @@ SELECT test_bms_hash_value('(b 1 3 5)') != test_bms_hash_value('(b 2 4 6)') AS r
t t
(1 row) (1 row)
-- Test module check -- NULL input
SELECT test_bms_hash_value(NULL) AS result; SELECT test_bms_hash_value(NULL) AS result;
result result
-------- --------
@ -1176,7 +1086,7 @@ SELECT test_bms_overlap('(b)', '(b 1 3 5)') AS result;
f f
(1 row) (1 row)
-- Test module checks -- NULL inputs
SELECT test_bms_overlap('(b 5)', NULL) AS result; SELECT test_bms_overlap('(b 5)', NULL) AS result;
result result
-------- --------
@ -1240,7 +1150,7 @@ SELECT test_bms_is_subset('(b 1 2 50 100)', '(b 1 2)') AS result;
f f
(1 row) (1 row)
-- Test module checks -- NULL inputs
SELECT test_bms_is_subset('(b 5)', NULL) AS result; SELECT test_bms_is_subset('(b 5)', NULL) AS result;
result result
-------- --------
@ -1398,30 +1308,11 @@ SELECT test_bms_subset_compare('(b 2 64 128)', '(b 1 65)') AS result;
3 3
(1 row) (1 row)
-- Test module checks
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)
-- bms_copy() -- bms_copy()
SELECT test_bms_copy(NULL) AS result; SELECT test_bms_copy(NULL) AS result;
result result
-------- --------
<>
(1 row) (1 row)
SELECT test_bms_copy('(b 1 3 5 7)') AS result; SELECT test_bms_copy('(b 1 3 5 7)') AS result;
@ -1430,13 +1321,6 @@ SELECT test_bms_copy('(b 1 3 5 7)') AS result;
(b 1 3 5 7) (b 1 3 5 7)
(1 row) (1 row)
-- Test module check
SELECT test_bms_copy(NULL) AS result;
result
--------
(1 row)
-- bms_add_members() -- bms_add_members()
SELECT test_bms_add_members('(b 1 3)', '(b 5 7)') AS result; SELECT test_bms_add_members('(b 1 3)', '(b 5 7)') AS result;
result result
@ -1547,7 +1431,7 @@ SELECT (test_bitmap_match('(b)', '(b)') = 0) =
t t
(1 row) (1 row)
-- Test module checks -- NULL inputs
SELECT test_bitmap_match('(b 5)', NULL) AS result; SELECT test_bitmap_match('(b 5)', NULL) AS result;
result result
-------- --------
@ -1609,7 +1493,7 @@ SELECT test_bms_overlap_list('(b 5 10)', ARRAY[-1,5]) AS result; -- error
ERROR: negative bitmapset member not allowed ERROR: negative bitmapset member not allowed
SELECT test_bms_overlap_list('(b 1 2 3)', ARRAY[-5,-1,0]) AS result; -- error SELECT test_bms_overlap_list('(b 1 2 3)', ARRAY[-5,-1,0]) AS result; -- error
ERROR: negative bitmapset member not allowed ERROR: negative bitmapset member not allowed
-- Test module checks -- NULL inputs
SELECT test_bms_overlap_list('(b 5)', NULL) AS result; SELECT test_bms_overlap_list('(b 5)', NULL) AS result;
result result
-------- --------
@ -1641,6 +1525,12 @@ SELECT test_bms_nonempty_difference('(b 1 3 5)', NULL) AS result;
t t
(1 row) (1 row)
SELECT test_bms_nonempty_difference(NULL, NULL) AS result;
result
--------
f
(1 row)
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 2 4 6)') AS result;
result result
-------- --------
@ -1678,25 +1568,6 @@ SELECT test_bms_nonempty_difference('(b 1 2)', '(b 50 100)') AS result;
t t
(1 row) (1 row)
-- Test module checks
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)
-- random operations -- random operations
SELECT test_random_operations(-1, 10000, 81920, 0) > 0 AS result; SELECT test_random_operations(-1, 10000, 81920, 0) > 0 AS result;
result result

View File

@ -29,11 +29,6 @@ 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; SELECT test_bms_replace_members('(b 1 2)', '(b 3 5 7)') AS result;
-- Force repalloc() with larger set -- Force repalloc() with larger set
SELECT test_bms_replace_members('(b 1 2 3 4 5)', '(b 500 600)') AS result; SELECT test_bms_replace_members('(b 1 2 3 4 5)', '(b 500 600)') AS result;
-- Test module checks
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;
-- bms_del_member() -- bms_del_member()
SELECT test_bms_del_member('(b)', -20); -- error SELECT test_bms_del_member('(b)', -20); -- error
@ -50,7 +45,6 @@ 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)', 200) AS result;
SELECT test_bms_del_member('(b 1 50 100 200)', 100) AS result; SELECT test_bms_del_member('(b 1 50 100 200)', 100) AS result;
-- Test module checks -- Test module checks
SELECT test_bms_del_member('(b 42)', 42) AS result;
SELECT test_bms_del_member('(b 5)', NULL) AS result; SELECT test_bms_del_member('(b 5)', NULL) AS result;
-- bms_del_members() -- bms_del_members()
@ -63,7 +57,7 @@ SELECT test_bms_del_members('(b 5 100 200)', '(b 200)') AS result;
-- Force word count changes -- Force word count changes
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 1 2)') AS result;
SELECT test_bms_del_members('(b 1 2 100 200 300)', '(b 200 300)') AS result; SELECT test_bms_del_members('(b 1 2 100 200 300)', '(b 200 300)') AS result;
-- Test module checks -- NULL inputs
SELECT test_bms_del_members('(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_del_members(NULL, '(b 5)') AS result;
@ -75,7 +69,7 @@ SELECT test_bms_join('(b 1 3 5)', '(b 1 4 5)') AS result;
-- Force word count changes -- Force word count changes
SELECT test_bms_join('(b 5)', '(b 100)') AS result; SELECT test_bms_join('(b 5)', '(b 100)') AS result;
SELECT test_bms_join('(b 1 2)', '(b 100 200 300)') AS result; SELECT test_bms_join('(b 1 2)', '(b 100 200 300)') AS result;
-- Test module checks -- NULL inputs
SELECT test_bms_join('(b 5)', 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, '(b 5)') AS result;
SELECT test_bms_join(NULL, NULL) AS result; SELECT test_bms_join(NULL, NULL) AS result;
@ -92,10 +86,10 @@ SELECT test_bms_union(
test_bms_add_range('(b)', 0, 15), test_bms_add_range('(b)', 0, 15),
test_bms_add_range('(b)', 10, 20) test_bms_add_range('(b)', 10, 20)
) AS result; ) AS result;
-- Union with varrying word counts -- Union with varying word counts
SELECT test_bms_union('(b 1 2)', '(b 100 300)') AS result; SELECT test_bms_union('(b 1 2)', '(b 100 300)') AS result;
SELECT test_bms_union('(b 100 300)', '(b 1 2)') AS result; SELECT test_bms_union('(b 100 300)', '(b 1 2)') AS result;
-- Test module checks -- NULL inputs
SELECT test_bms_union('(b 5)', 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, '(b 5)') AS result;
SELECT test_bms_union(NULL, NULL) AS result; SELECT test_bms_union(NULL, NULL) AS result;
@ -107,11 +101,10 @@ SELECT test_bms_intersect('(b 1 3 5)', '(b 3 5 7)') AS result;
SELECT test_bms_intersect('(b 1 3 5)', '(b 2 4 6)') AS result; 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; SELECT test_bms_intersect('(b 1 3 5)', '(b)') AS result;
-- Intersect with varrying word counts -- Intersect with varying word counts
SELECT test_bms_intersect('(b 1 300)', '(b 1 2 3 4 5)') AS result; 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; SELECT test_bms_intersect('(b 1 2 3 4 5)', '(b 1 300)') AS result;
-- Test module checks -- NULL inputs
SELECT test_bms_intersect('(b 1)', '(b 2)') AS result;
SELECT test_bms_intersect('(b 5)', NULL) 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, '(b 5)') AS result;
SELECT test_bms_intersect(NULL, NULL) AS result; SELECT test_bms_intersect(NULL, NULL) AS result;
@ -125,8 +118,7 @@ SELECT test_bms_int_members('(b 1 3 5)', '(b 2 4 6)') AS result;
SELECT test_bms_int_members('(b 1 3 5)', '(b)') AS result; SELECT test_bms_int_members('(b 1 3 5)', '(b)') AS result;
-- Multiple members -- Multiple members
SELECT test_bms_int_members('(b 0 31 32 63 64)', '(b 31 32 64 65)') AS result; SELECT test_bms_int_members('(b 0 31 32 63 64)', '(b 31 32 64 65)') AS result;
-- Test module checks -- NULL inputs
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('(b 5)', NULL) AS result;
SELECT test_bms_int_members(NULL, '(b 5)') AS result; SELECT test_bms_int_members(NULL, '(b 5)') AS result;
SELECT test_bms_int_members(NULL, NULL) AS result; SELECT test_bms_int_members(NULL, NULL) AS result;
@ -148,8 +140,7 @@ SELECT test_bms_difference(
-- Difference with different word counts -- Difference with different word counts
SELECT test_bms_difference('(b 5 100)', '(b 5)') AS result; 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; SELECT test_bms_difference('(b 1 2 100 200)', '(b 1 2)') AS result;
-- Test module checks -- NULL inputs
SELECT test_bms_difference('(b 5)', '(b 5 10)') AS result;
SELECT test_bms_difference('(b 5)', NULL) 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, '(b 5)') AS result;
SELECT test_bms_difference(NULL, NULL) AS result; SELECT test_bms_difference(NULL, NULL) AS result;
@ -172,9 +163,8 @@ SELECT test_bms_member_index('(b 1 3 5)', 3) AS result;
SELECT test_bms_member_index('(b 100 200)', 100) AS result; 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 100 200)', 200) AS result;
SELECT test_bms_member_index('(b 1 50 100 200)', 200) AS result; SELECT test_bms_member_index('(b 1 50 100 200)', 200) AS result;
-- Test module checks -- Test module check
SELECT test_bms_member_index('', 5) AS result; SELECT test_bms_member_index('(b 1 3 5)', NULL) AS result;
SELECT test_bms_member_index(NULL, 5) AS result;
-- bms_num_members() -- bms_num_members()
SELECT test_bms_num_members('(b)') AS result; SELECT test_bms_num_members('(b)') AS result;
@ -190,7 +180,7 @@ SELECT test_bms_equal('(b 1 3 5)', '(b 2 4 6)') AS result;
-- Equal with different word counts -- Equal with different word counts
SELECT test_bms_equal('(b 5)', '(b 100)') AS result; SELECT test_bms_equal('(b 5)', '(b 100)') AS result;
SELECT test_bms_equal('(b 5 10)', '(b 100 200 300)') AS result; SELECT test_bms_equal('(b 5 10)', '(b 100 200 300)') AS result;
-- Test module checks -- NULL inputs
SELECT test_bms_equal('(b 5)', 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, '(b 5)') AS result;
SELECT test_bms_equal(NULL, NULL) AS result; SELECT test_bms_equal(NULL, NULL) AS result;
@ -206,7 +196,7 @@ SELECT test_bms_compare(
test_bms_add_range('(b)', 0, 63), test_bms_add_range('(b)', 0, 63),
test_bms_add_range('(b)', 0, 64) test_bms_add_range('(b)', 0, 64)
) AS result; ) AS result;
-- Test module checks -- NULL inputs
SELECT test_bms_compare('(b 5)', 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, '(b 5)') AS result;
SELECT test_bms_compare(NULL, NULL) AS result; SELECT test_bms_compare(NULL, NULL) AS result;
@ -232,40 +222,37 @@ SELECT length(test_bms_add_range('(b 1 2)', 200, 250)) AS result;
SELECT test_bms_add_range('(b 5)', 5, 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, 10) AS result;
SELECT test_bms_add_range('(b 5)', NULL, NULL) AS result; SELECT test_bms_add_range('(b 5)', NULL, NULL) AS result;
-- NULL inputs
SELECT test_bms_add_range(NULL, 5, 10) 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, 10, 5) AS result;
SELECT test_bms_add_range(NULL, NULL, NULL) AS result;
-- bms_membership() -- bms_membership()
SELECT test_bms_membership('(b)') AS result; SELECT test_bms_membership('(b)') AS result;
SELECT test_bms_membership('(b 42)') AS result; SELECT test_bms_membership('(b 42)') AS result;
SELECT test_bms_membership('(b 1 2)') AS result; SELECT test_bms_membership('(b 1 2)') AS result;
-- Test module check -- NULL input
SELECT test_bms_membership(NULL) AS result; SELECT test_bms_membership(NULL) AS result;
-- bms_is_empty() -- bms_is_empty()
SELECT test_bms_is_empty(NULL) AS result; SELECT test_bms_is_empty(NULL) AS result;
SELECT test_bms_is_empty('(b)') AS result; SELECT test_bms_is_empty('(b)') AS result;
SELECT test_bms_is_empty('(b 1)') AS result; SELECT test_bms_is_empty('(b 1)') AS result;
-- Test module check
SELECT test_bms_is_empty(NULL) AS result;
-- bms_singleton_member() -- bms_singleton_member()
SELECT test_bms_singleton_member('(b)'); -- error SELECT test_bms_singleton_member('(b)'); -- error
SELECT test_bms_singleton_member('(b 1 2)'); -- error SELECT test_bms_singleton_member('(b 1 2)'); -- error
SELECT test_bms_singleton_member('(b 42)') AS result; SELECT test_bms_singleton_member('(b 42)') AS result;
-- Test module check -- NULL input
SELECT test_bms_singleton_member(NULL) AS result; SELECT test_bms_singleton_member(NULL) AS result;
-- bms_get_singleton_member() -- bms_get_singleton_member()
SELECT test_bms_get_singleton_member('(b)', 1000); SELECT test_bms_get_singleton_member('(b)');
-- Try with an empty set
SELECT test_bms_get_singleton_member(NULL) AS result;
-- Not a singleton, returns input default -- Not a singleton, returns input default
SELECT test_bms_get_singleton_member('(b 3 6)', 1000) AS result; SELECT test_bms_get_singleton_member('(b 3 6)') AS result;
-- Singletone, returns sole member -- Singletone, returns sole member
SELECT test_bms_get_singleton_member('(b 400)', 1000) AS result; SELECT test_bms_get_singleton_member('(b 400)') AS result;
-- Test module checks
SELECT test_bms_get_singleton_member('', 1000) AS result;
SELECT test_bms_get_singleton_member(NULL, -1) AS result;
-- bms_next_member() and bms_prev_member() -- bms_next_member() and bms_prev_member()
-- First member -- First member
@ -286,27 +273,25 @@ SELECT test_bms_prev_member('(b 5 10 15 20)', 5) AS result;
SELECT test_bms_prev_member('(b)', 100) AS result; SELECT test_bms_prev_member('(b)', 100) AS result;
-- Negative prevbit should result in highest possible bit in set -- Negative prevbit should result in highest possible bit in set
SELECT test_bms_prev_member('(b 0 63 64 127)', -1) AS result; SELECT test_bms_prev_member('(b 0 63 64 127)', -1) AS result;
-- Test module checks -- NULL inputs
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, 5) AS result;
SELECT test_bms_next_member(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_prev_member(NULL, 5) AS result;
-- Test module check
SELECT test_bms_next_member('(b 5 10)', NULL) AS result;
SELECT test_bms_prev_member('(b 5 10)', NULL) AS result;
-- bms_hash_value() -- bms_hash_value()
SELECT test_bms_hash_value('(b)') = 0 AS result; SELECT test_bms_hash_value('(b)') = 0 AS result;
SELECT test_bms_hash_value('(b 1 3 5)') = test_bms_hash_value('(b 1 3 5)') AS result; SELECT test_bms_hash_value('(b 1 3 5)') = test_bms_hash_value('(b 1 3 5)') AS result;
SELECT test_bms_hash_value('(b 1 3 5)') != test_bms_hash_value('(b 2 4 6)') AS result; SELECT test_bms_hash_value('(b 1 3 5)') != test_bms_hash_value('(b 2 4 6)') AS result;
-- Test module check -- NULL input
SELECT test_bms_hash_value(NULL) AS result; SELECT test_bms_hash_value(NULL) AS result;
-- bms_overlap() -- bms_overlap()
SELECT test_bms_overlap('(b 1 3 5)', '(b 3 5 7)') AS result; SELECT test_bms_overlap('(b 1 3 5)', '(b 3 5 7)') AS result;
SELECT test_bms_overlap('(b 1 3 5)', '(b 2 4 6)') AS result; SELECT test_bms_overlap('(b 1 3 5)', '(b 2 4 6)') AS result;
SELECT test_bms_overlap('(b)', '(b 1 3 5)') AS result; SELECT test_bms_overlap('(b)', '(b 1 3 5)') AS result;
-- Test module checks -- NULL inputs
SELECT test_bms_overlap('(b 5)', 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, '(b 5)') AS result;
SELECT test_bms_overlap(NULL, NULL) AS result; SELECT test_bms_overlap(NULL, NULL) AS result;
@ -321,7 +306,7 @@ SELECT test_bms_is_subset(test_bms_add_range(NULL, 0, 31),
-- Is subset with shorter word counts? -- Is subset with shorter word counts?
SELECT test_bms_is_subset('(b 5 100)', '(b 5)') AS result; 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; SELECT test_bms_is_subset('(b 1 2 50 100)', '(b 1 2)') AS result;
-- Test module checks -- NULL inputs
SELECT test_bms_is_subset('(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, '(b 5)') AS result;
SELECT test_bms_is_subset(NULL, NULL) AS result; SELECT test_bms_is_subset(NULL, NULL) AS result;
@ -350,16 +335,10 @@ SELECT test_bms_subset_compare('(b 1 2)', '(b 1 2 64)') AS result;
SELECT test_bms_subset_compare('(b 64 200)', '(b 1 201)') AS result; SELECT test_bms_subset_compare('(b 64 200)', '(b 1 201)') AS result;
SELECT test_bms_subset_compare('(b 1 64 65)', '(b 1 2 64)') AS result; SELECT test_bms_subset_compare('(b 1 64 65)', '(b 1 2 64)') AS result;
SELECT test_bms_subset_compare('(b 2 64 128)', '(b 1 65)') AS result; SELECT test_bms_subset_compare('(b 2 64 128)', '(b 1 65)') AS result;
-- Test module checks
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;
-- bms_copy() -- bms_copy()
SELECT test_bms_copy(NULL) AS result; SELECT test_bms_copy(NULL) AS result;
SELECT test_bms_copy('(b 1 3 5 7)') AS result; SELECT test_bms_copy('(b 1 3 5 7)') AS result;
-- Test module check
SELECT test_bms_copy(NULL) AS result;
-- bms_add_members() -- bms_add_members()
SELECT test_bms_add_members('(b 1 3)', '(b 5 7)') AS result; SELECT test_bms_add_members('(b 1 3)', '(b 5 7)') AS result;
@ -388,7 +367,7 @@ SELECT (test_bitmap_match('(b 1 3 5)', '(b 2 4 6)') = 0) =
test_bms_equal('(b 1 3 5)', '(b 2 4 6)') AS result; test_bms_equal('(b 1 3 5)', '(b 2 4 6)') AS result;
SELECT (test_bitmap_match('(b)', '(b)') = 0) = SELECT (test_bitmap_match('(b)', '(b)') = 0) =
test_bms_equal('(b)', '(b)') AS result; test_bms_equal('(b)', '(b)') AS result;
-- Test module checks -- NULL inputs
SELECT test_bitmap_match('(b 5)', 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, '(b 5)') AS result;
SELECT test_bitmap_match(NULL, NULL) AS result; SELECT test_bitmap_match(NULL, NULL) AS result;
@ -404,7 +383,7 @@ SELECT test_bms_overlap_list('(b 1)', ARRAY[]::integer[]) AS result;
-- Overlap list with negative numbers -- 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 5 10)', ARRAY[-1,5]) AS result; -- error
SELECT test_bms_overlap_list('(b 1 2 3)', ARRAY[-5,-1,0]) AS result; -- error SELECT test_bms_overlap_list('(b 1 2 3)', ARRAY[-5,-1,0]) AS result; -- error
-- Test module checks -- NULL inputs
SELECT test_bms_overlap_list('(b 5)', 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, ARRAY[1,2,3]) AS result;
SELECT test_bms_overlap_list(NULL, NULL) AS result; SELECT test_bms_overlap_list(NULL, NULL) AS result;
@ -412,6 +391,7 @@ SELECT test_bms_overlap_list(NULL, NULL) AS result;
-- bms_nonempty_difference() -- bms_nonempty_difference()
SELECT test_bms_nonempty_difference(NULL, '(b 1 3 5)') AS result; SELECT test_bms_nonempty_difference(NULL, '(b 1 3 5)') AS result;
SELECT test_bms_nonempty_difference('(b 1 3 5)', NULL) AS result; SELECT test_bms_nonempty_difference('(b 1 3 5)', NULL) AS result;
SELECT test_bms_nonempty_difference(NULL, 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 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 5)') AS result;
SELECT test_bms_nonempty_difference('(b 1 3 5)', '(b 1 3 5)') AS result; SELECT test_bms_nonempty_difference('(b 1 3 5)', '(b 1 3 5)') AS result;
@ -419,10 +399,6 @@ SELECT test_bms_nonempty_difference('(b 1 3 5)', '(b 1 3 5)') AS result;
SELECT test_bms_nonempty_difference('(b 5)', '(b 100)') AS result; 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 100)', '(b 5)') AS result;
SELECT test_bms_nonempty_difference('(b 1 2)', '(b 50 100)') AS result; SELECT test_bms_nonempty_difference('(b 1 2)', '(b 50 100)') AS result;
-- Test module checks
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;
-- random operations -- random operations
SELECT test_random_operations(-1, 10000, 81920, 0) > 0 AS result; SELECT test_random_operations(-1, 10000, 81920, 0) > 0 AS result;

View File

@ -68,7 +68,7 @@ CREATE FUNCTION test_bms_singleton_member(text)
RETURNS integer STRICT RETURNS integer STRICT
AS 'MODULE_PATHNAME' LANGUAGE C; AS 'MODULE_PATHNAME' LANGUAGE C;
CREATE FUNCTION test_bms_get_singleton_member(text, integer) CREATE FUNCTION test_bms_get_singleton_member(text)
RETURNS integer RETURNS integer
AS 'MODULE_PATHNAME' LANGUAGE C; AS 'MODULE_PATHNAME' LANGUAGE C;

View File

@ -26,7 +26,6 @@
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/timestamp.h" #include "utils/timestamp.h"
#include "varatt.h"
PG_MODULE_MAGIC; PG_MODULE_MAGIC;
@ -88,101 +87,99 @@ PG_FUNCTION_INFO_V1(test_random_operations);
#define BITMAPSET_TO_TEXT(bms) cstring_to_text(nodeToString(bms)) #define BITMAPSET_TO_TEXT(bms) cstring_to_text(nodeToString(bms))
#define TEXT_TO_BITMAPSET(str) ((Bitmapset *) stringToNode(text_to_cstring(str))) #define TEXT_TO_BITMAPSET(str) ((Bitmapset *) stringToNode(text_to_cstring(str)))
/*
* Helper macro to fetch text parameters as Bitmapsets. SQL-NULL means empty
* set.
*/
#define PG_ARG_GETBITMAPSET(n) \
(PG_ARGISNULL(n) ? NULL : TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(n)))
/*
* Helper macro to handle converting sets back to text, returning the
* resulting text representation of the set.
*/
#define PG_RETURN_BITMAPSET_AS_TEXT(bms) \
PG_RETURN_TEXT_P(BITMAPSET_TO_TEXT(bms))
/* /*
* Individual test functions for each bitmapset API function * Individual test functions for each bitmapset API function
*
* Primarily, we aim to keep these as close to simple wrapper functions as
* possible in order to publish the functions of bitmapset.c to the SQL layer
* with as little interference as possible. We opt to return SQL NULL in
* cases where the input given to the SQL function isn't valid to pass to the
* underlying bitmapset.c function. For example we cannot do much useful
* testing if someone calls test_bms_make_singleton(NULL) since
* bms_make_singleton() expects an integer argument.
*
* For function arguments which are to be converted to Bitmapsets, we accept
* SQL NULL as a valid argument to mean an empty set. Optionally callers may
* pass '(b)'.
*
* For the test functions which return a Bitmapset, these are converted back
* to text with result generated by nodeToString().
*/ */
Datum Datum
test_bms_add_member(PG_FUNCTION_ARGS) test_bms_add_member(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms;
int member; int member;
Bitmapset *bms = NULL;
text *result;
if (PG_ARGISNULL(1)) if (PG_ARGISNULL(1))
PG_RETURN_NULL(); PG_RETURN_NULL(); /* invalid input */
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
bms = PG_ARG_GETBITMAPSET(0);
member = PG_GETARG_INT32(1); member = PG_GETARG_INT32(1);
bms = bms_add_member(bms, member); bms = bms_add_member(bms, member);
result = BITMAPSET_TO_TEXT(bms);
if (bms) PG_RETURN_BITMAPSET_AS_TEXT(bms);
bms_free(bms);
PG_RETURN_TEXT_P(result);
} }
Datum Datum
test_bms_add_members(PG_FUNCTION_ARGS) test_bms_add_members(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
text *result;
if (!PG_ARGISNULL(0)) /* left input is recycled */
bms1 = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
if (!PG_ARGISNULL(1))
bms2 = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(1));
/* IMPORTANT: bms_add_members modifies/frees the first argument */
bms1 = bms_add_members(bms1, bms2); bms1 = bms_add_members(bms1, bms2);
if (bms2) PG_RETURN_BITMAPSET_AS_TEXT(bms1);
bms_free(bms2);
result = BITMAPSET_TO_TEXT(bms1);
bms_free(bms1);
PG_RETURN_TEXT_P(result);
} }
Datum Datum
test_bms_del_member(PG_FUNCTION_ARGS) test_bms_del_member(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms = NULL; Bitmapset *bms;
int32 member; int32 member;
text *result;
if (PG_ARGISNULL(1)) if (PG_ARGISNULL(1))
PG_RETURN_NULL(); PG_RETURN_NULL(); /* invalid input */
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
bms = PG_ARG_GETBITMAPSET(0);
member = PG_GETARG_INT32(1); member = PG_GETARG_INT32(1);
bms = bms_del_member(bms, member); bms = bms_del_member(bms, member);
if (bms_is_empty(bms)) PG_RETURN_BITMAPSET_AS_TEXT(bms);
PG_RETURN_NULL();
result = BITMAPSET_TO_TEXT(bms);
bms_free(bms);
PG_RETURN_TEXT_P(result);
} }
Datum Datum
test_bms_is_member(PG_FUNCTION_ARGS) test_bms_is_member(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms = NULL; Bitmapset *bms;
int32 member; int32 member;
bool result; bool result;
if (PG_ARGISNULL(1)) if (PG_ARGISNULL(1))
PG_RETURN_BOOL(false); PG_RETURN_NULL(); /* invalid input */
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
bms = PG_ARG_GETBITMAPSET(0);
member = PG_GETARG_INT32(1); member = PG_GETARG_INT32(1);
result = bms_is_member(member, bms);
if (bms) result = bms_is_member(member, bms);
bms_free(bms);
PG_RETURN_BOOL(result); PG_RETURN_BOOL(result);
} }
@ -190,150 +187,89 @@ test_bms_is_member(PG_FUNCTION_ARGS)
Datum Datum
test_bms_num_members(PG_FUNCTION_ARGS) test_bms_num_members(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms = NULL; Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
int result = 0; int result;
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
result = bms_num_members(bms); result = bms_num_members(bms);
if (bms)
bms_free(bms);
PG_RETURN_INT32(result); PG_RETURN_INT32(result);
} }
Datum Datum
test_bms_make_singleton(PG_FUNCTION_ARGS) test_bms_make_singleton(PG_FUNCTION_ARGS)
{ {
int32 member;
Bitmapset *bms; Bitmapset *bms;
text *result; int32 member;
if (PG_ARGISNULL(0)) if (PG_ARGISNULL(0))
PG_RETURN_NULL(); PG_RETURN_NULL(); /* invalid input */
member = PG_GETARG_INT32(0); member = PG_GETARG_INT32(0);
bms = bms_make_singleton(member); bms = bms_make_singleton(member);
result = BITMAPSET_TO_TEXT(bms); PG_RETURN_BITMAPSET_AS_TEXT(bms);
bms_free(bms);
PG_RETURN_TEXT_P(result);
} }
Datum Datum
test_bms_copy(PG_FUNCTION_ARGS) test_bms_copy(PG_FUNCTION_ARGS)
{ {
text *bms_data; Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms = NULL;
Bitmapset *copy_bms; Bitmapset *copy_bms;
text *result;
if (PG_ARGISNULL(0))
PG_RETURN_NULL();
bms_data = PG_GETARG_TEXT_PP(0);
bms = TEXT_TO_BITMAPSET(bms_data);
copy_bms = bms_copy(bms); copy_bms = bms_copy(bms);
result = BITMAPSET_TO_TEXT(copy_bms);
if (bms) PG_RETURN_BITMAPSET_AS_TEXT(copy_bms);
bms_free(bms);
if (copy_bms)
bms_free(copy_bms);
PG_RETURN_TEXT_P(result);
} }
Datum Datum
test_bms_equal(PG_FUNCTION_ARGS) test_bms_equal(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
bool result; bool 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));
result = bms_equal(bms1, bms2); result = bms_equal(bms1, bms2);
if (bms1)
bms_free(bms1);
if (bms2)
bms_free(bms2);
PG_RETURN_BOOL(result); PG_RETURN_BOOL(result);
} }
Datum Datum
test_bms_union(PG_FUNCTION_ARGS) test_bms_union(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
Bitmapset *result_bms; 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));
result_bms = bms_union(bms1, bms2); result_bms = bms_union(bms1, bms2);
if (bms1) PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
bms_free(bms1);
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 Datum
test_bms_membership(PG_FUNCTION_ARGS) test_bms_membership(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms = NULL; Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
BMS_Membership result; BMS_Membership result;
if (PG_ARGISNULL(0))
PG_RETURN_INT32(BMS_EMPTY_SET);
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
result = bms_membership(bms); result = bms_membership(bms);
if (bms)
bms_free(bms);
PG_RETURN_INT32((int32) result); PG_RETURN_INT32((int32) result);
} }
Datum Datum
test_bms_next_member(PG_FUNCTION_ARGS) test_bms_next_member(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms = NULL; Bitmapset *bms;
int32 prevmember; int32 prevmember;
int result; int result;
if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) if (PG_ARGISNULL(1))
PG_RETURN_INT32(-2); PG_RETURN_NULL(); /* invalid input */
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0)); bms = PG_ARG_GETBITMAPSET(0);
prevmember = PG_GETARG_INT32(1); prevmember = PG_GETARG_INT32(1);
result = bms_next_member(bms, prevmember);
if (bms) result = bms_next_member(bms, prevmember);
bms_free(bms);
PG_RETURN_INT32(result); PG_RETURN_INT32(result);
} }
@ -341,212 +277,115 @@ test_bms_next_member(PG_FUNCTION_ARGS)
Datum Datum
test_bms_intersect(PG_FUNCTION_ARGS) test_bms_intersect(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
Bitmapset *result_bms; 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));
result_bms = bms_intersect(bms1, bms2); result_bms = bms_intersect(bms1, bms2);
if (bms1) PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
bms_free(bms1);
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 Datum
test_bms_difference(PG_FUNCTION_ARGS) test_bms_difference(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
Bitmapset *result_bms; 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));
result_bms = bms_difference(bms1, bms2); result_bms = bms_difference(bms1, bms2);
if (bms1) PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
bms_free(bms1);
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 Datum
test_bms_compare(PG_FUNCTION_ARGS) test_bms_compare(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
int result; int 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));
result = bms_compare(bms1, bms2); result = bms_compare(bms1, bms2);
if (bms1)
bms_free(bms1);
if (bms2)
bms_free(bms2);
PG_RETURN_INT32(result); PG_RETURN_INT32(result);
} }
Datum Datum
test_bms_is_empty(PG_FUNCTION_ARGS) test_bms_is_empty(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms = NULL; Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
bool result; bool result;
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
result = bms_is_empty(bms); result = bms_is_empty(bms);
if (bms)
bms_free(bms);
PG_RETURN_BOOL(result); PG_RETURN_BOOL(result);
} }
Datum Datum
test_bms_is_subset(PG_FUNCTION_ARGS) test_bms_is_subset(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
bool result; bool 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));
result = bms_is_subset(bms1, bms2); result = bms_is_subset(bms1, bms2);
if (bms1)
bms_free(bms1);
if (bms2)
bms_free(bms2);
PG_RETURN_BOOL(result); PG_RETURN_BOOL(result);
} }
Datum Datum
test_bms_subset_compare(PG_FUNCTION_ARGS) test_bms_subset_compare(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
BMS_Comparison result; BMS_Comparison 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));
result = bms_subset_compare(bms1, bms2); result = bms_subset_compare(bms1, bms2);
if (bms1)
bms_free(bms1);
if (bms2)
bms_free(bms2);
PG_RETURN_INT32((int32) result); PG_RETURN_INT32((int32) result);
} }
Datum Datum
test_bms_singleton_member(PG_FUNCTION_ARGS) test_bms_singleton_member(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms = NULL; Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
int result; int result;
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
result = bms_singleton_member(bms); result = bms_singleton_member(bms);
if (bms)
bms_free(bms);
PG_RETURN_INT32(result); PG_RETURN_INT32(result);
} }
Datum Datum
test_bms_get_singleton_member(PG_FUNCTION_ARGS) test_bms_get_singleton_member(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms = NULL; Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
int32 default_member = PG_GETARG_INT32(1); int member;
bool success;
int member = -1;
if (PG_ARGISNULL(0))
PG_RETURN_INT32(default_member);
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
/* /*
* bms_get_singleton_member returns bool and stores result in member * Keep this simple. Return -1 when we detect the set is not a singleton
* pointer * set, otherwise return the singleton member.
*/ */
success = bms_get_singleton_member(bms, &member); if (!bms_get_singleton_member(bms, &member))
bms_free(bms); member = -1;
if (success) PG_RETURN_INT32(member);
PG_RETURN_INT32(member);
PG_RETURN_INT32(default_member);
} }
Datum Datum
test_bms_prev_member(PG_FUNCTION_ARGS) test_bms_prev_member(PG_FUNCTION_ARGS)
{ {
text *bms_data; Bitmapset *bms;
Bitmapset *bms = NULL;
int32 prevmember; int32 prevmember;
int result; int result;
if (PG_ARGISNULL(0)) if (PG_ARGISNULL(1))
PG_RETURN_INT32(-2); PG_RETURN_NULL(); /* invalid input */
bms_data = PG_GETARG_TEXT_PP(0); bms = PG_ARG_GETBITMAPSET(0);
prevmember = PG_GETARG_INT32(1); prevmember = PG_GETARG_INT32(1);
if (VARSIZE_ANY_EXHDR(bms_data) == 0)
PG_RETURN_INT32(-2);
bms = TEXT_TO_BITMAPSET(bms_data);
result = bms_prev_member(bms, prevmember); result = bms_prev_member(bms, prevmember);
bms_free(bms);
PG_RETURN_INT32(result); PG_RETURN_INT32(result);
} }
@ -554,75 +393,57 @@ test_bms_prev_member(PG_FUNCTION_ARGS)
Datum Datum
test_bms_overlap(PG_FUNCTION_ARGS) test_bms_overlap(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
bool result; bool 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));
result = bms_overlap(bms1, bms2); result = bms_overlap(bms1, bms2);
if (bms1)
bms_free(bms1);
if (bms2)
bms_free(bms2);
PG_RETURN_BOOL(result); PG_RETURN_BOOL(result);
} }
Datum Datum
test_bms_overlap_list(PG_FUNCTION_ARGS) test_bms_overlap_list(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms = NULL; Bitmapset *bms;
ArrayType *array; ArrayType *array;
List *int_list = NIL; List *int_list = NIL;
bool result; bool result;
Datum *elem_datums; Datum *elem_datums = NULL;
bool *elem_nulls; bool *elem_nulls = NULL;
int elem_count; int elem_count;
int i; int i;
if (PG_ARGISNULL(0)) bms = PG_ARG_GETBITMAPSET(0);
PG_RETURN_BOOL(false);
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0)); if (!PG_ARGISNULL(1))
if (PG_ARGISNULL(1))
{ {
if (bms) array = PG_GETARG_ARRAYTYPE_P(1);
bms_free(bms);
PG_RETURN_BOOL(false);
}
array = PG_GETARG_ARRAYTYPE_P(1); deconstruct_array(array,
INT4OID, sizeof(int32), true, 'i',
&elem_datums, &elem_nulls, &elem_count);
deconstruct_array(array, for (i = 0; i < elem_count; i++)
INT4OID, sizeof(int32), true, 'i',
&elem_datums, &elem_nulls, &elem_count);
for (i = 0; i < elem_count; i++)
{
if (!elem_nulls[i])
{ {
int32 member = DatumGetInt32(elem_datums[i]); if (!elem_nulls[i])
{
int32 member = DatumGetInt32(elem_datums[i]);
int_list = lappend_int(int_list, member); int_list = lappend_int(int_list, member);
}
} }
} }
result = bms_overlap_list(bms, int_list); result = bms_overlap_list(bms, int_list);
if (bms)
bms_free(bms);
list_free(int_list); list_free(int_list);
pfree(elem_datums); if (elem_datums)
pfree(elem_nulls); pfree(elem_datums);
if (elem_nulls)
pfree(elem_nulls);
PG_RETURN_BOOL(result); PG_RETURN_BOOL(result);
} }
@ -630,47 +451,29 @@ test_bms_overlap_list(PG_FUNCTION_ARGS)
Datum Datum
test_bms_nonempty_difference(PG_FUNCTION_ARGS) test_bms_nonempty_difference(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
bool result; bool 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));
result = bms_nonempty_difference(bms1, bms2); result = bms_nonempty_difference(bms1, bms2);
if (bms1)
bms_free(bms1);
if (bms2)
bms_free(bms2);
PG_RETURN_BOOL(result); PG_RETURN_BOOL(result);
} }
Datum Datum
test_bms_member_index(PG_FUNCTION_ARGS) test_bms_member_index(PG_FUNCTION_ARGS)
{ {
text *bms_data; Bitmapset *bms;
Bitmapset *bms = NULL;
int32 member; int32 member;
int result; int result;
if (PG_ARGISNULL(0)) if (PG_ARGISNULL(1))
PG_RETURN_INT32(-1); PG_RETURN_NULL(); /* invalid input */
bms_data = PG_GETARG_TEXT_PP(0); bms = PG_ARG_GETBITMAPSET(0);
member = PG_GETARG_INT32(1); member = PG_GETARG_INT32(1);
if (VARSIZE_ANY_EXHDR(bms_data) == 0)
PG_RETURN_INT32(-1);
bms = TEXT_TO_BITMAPSET(bms_data);
result = bms_member_index(bms, member); result = bms_member_index(bms, member);
bms_free(bms);
PG_RETURN_INT32(result); PG_RETURN_INT32(result);
} }
@ -678,191 +481,92 @@ test_bms_member_index(PG_FUNCTION_ARGS)
Datum Datum
test_bms_add_range(PG_FUNCTION_ARGS) test_bms_add_range(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms = NULL; Bitmapset *bms;
int32 lower, int32 lower,
upper; upper;
text *result;
if (PG_ARGISNULL(1) || PG_ARGISNULL(2)) if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
PG_RETURN_NULL(); PG_RETURN_NULL(); /* invalid input */
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
bms = PG_ARG_GETBITMAPSET(0);
lower = PG_GETARG_INT32(1); lower = PG_GETARG_INT32(1);
upper = PG_GETARG_INT32(2); upper = PG_GETARG_INT32(2);
/* Check for invalid range */
if (upper < lower)
{
if (bms)
bms_free(bms);
PG_RETURN_NULL();
}
bms = bms_add_range(bms, lower, upper); bms = bms_add_range(bms, lower, upper);
result = BITMAPSET_TO_TEXT(bms); PG_RETURN_BITMAPSET_AS_TEXT(bms);
if (bms)
bms_free(bms);
PG_RETURN_TEXT_P(result);
} }
Datum Datum
test_bms_int_members(PG_FUNCTION_ARGS) test_bms_int_members(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
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));
/* left input gets recycled */
bms1 = bms_int_members(bms1, bms2); bms1 = bms_int_members(bms1, bms2);
if (bms2) PG_RETURN_BITMAPSET_AS_TEXT(bms1);
bms_free(bms2);
if (bms1 == NULL)
PG_RETURN_NULL();
result = BITMAPSET_TO_TEXT(bms1);
if (bms1)
bms_free(bms1);
PG_RETURN_TEXT_P(result);
} }
Datum Datum
test_bms_del_members(PG_FUNCTION_ARGS) test_bms_del_members(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
Bitmapset *result_bms;
text *result;
if (!PG_ARGISNULL(0)) /* left input gets recycled */
bms1 = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0)); bms1 = bms_del_members(bms1, bms2);
if (!PG_ARGISNULL(1)) PG_RETURN_BITMAPSET_AS_TEXT(bms1);
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 Datum
test_bms_replace_members(PG_FUNCTION_ARGS) test_bms_replace_members(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
Bitmapset *result_bms;
text *result;
if (!PG_ARGISNULL(0)) /* left input gets recycled */
bms1 = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0)); bms1 = bms_replace_members(bms1, bms2);
if (!PG_ARGISNULL(1)) PG_RETURN_BITMAPSET_AS_TEXT(bms1);
bms2 = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(1));
/* IMPORTANT: bms_replace_members modifies/frees the first argument */
result_bms = bms_replace_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 Datum
test_bms_join(PG_FUNCTION_ARGS) test_bms_join(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
Bitmapset *result_bms; Bitmapset *result_bms;
text *result;
if (!PG_ARGISNULL(0)) /* either input can be recycled */
bms1 = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
if (!PG_ARGISNULL(1))
bms2 = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(1));
/* IMPORTANT: bms_join may recycle either input arguments */
result_bms = bms_join(bms1, bms2); result_bms = bms_join(bms1, bms2);
/* bms1 and bms2 may have been recycled! Do not free any of them. */ /* memory cleanup seems more tricky than it's worth here */
if (result_bms == NULL) PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
PG_RETURN_NULL();
result = BITMAPSET_TO_TEXT(result_bms);
bms_free(result_bms);
PG_RETURN_TEXT_P(result);
} }
Datum Datum
test_bms_hash_value(PG_FUNCTION_ARGS) test_bms_hash_value(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms = NULL; Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
uint32 hash_result; uint32 hash_result;
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
hash_result = bms_hash_value(bms); hash_result = bms_hash_value(bms);
if (bms)
bms_free(bms);
PG_RETURN_INT32(hash_result); PG_RETURN_INT32(hash_result);
} }
Datum Datum
test_bitmap_hash(PG_FUNCTION_ARGS) test_bitmap_hash(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms = NULL; Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms_ptr;
uint32 hash_result; uint32 hash_result;
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
bms_ptr = bms;
/* Call bitmap_hash */ /* Call bitmap_hash */
hash_result = bitmap_hash(&bms_ptr, sizeof(Bitmapset *)); hash_result = bitmap_hash(&bms, sizeof(Bitmapset *));
/* Clean up */
if (!PG_ARGISNULL(0) && bms_ptr)
bms_free(bms_ptr);
PG_RETURN_INT32(hash_result); PG_RETURN_INT32(hash_result);
} }
@ -870,30 +574,12 @@ test_bitmap_hash(PG_FUNCTION_ARGS)
Datum Datum
test_bitmap_match(PG_FUNCTION_ARGS) test_bitmap_match(PG_FUNCTION_ARGS)
{ {
Bitmapset *bms1 = NULL, Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
*bms2 = NULL; Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
Bitmapset *bms_ptr1,
*bms_ptr2;
int match_result; int match_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));
/* Set up pointers to the Bitmapsets */
bms_ptr1 = bms1;
bms_ptr2 = bms2;
/* Call bitmap_match with addresses of the Bitmapset pointers */ /* Call bitmap_match with addresses of the Bitmapset pointers */
match_result = bitmap_match(&bms_ptr1, &bms_ptr2, sizeof(Bitmapset *)); match_result = bitmap_match(&bms1, &bms2, sizeof(Bitmapset *));
/* Clean up */
if (bms1)
bms_free(bms1);
if (bms2)
bms_free(bms2);
PG_RETURN_INT32(match_result); PG_RETURN_INT32(match_result);
} }
@ -1031,8 +717,7 @@ test_random_operations(PG_FUNCTION_ARGS)
total_ops++; total_ops++;
} }
if (bms) bms_free(bms);
bms_free(bms);
PG_RETURN_INT32(total_ops); PG_RETURN_INT32(total_ops);
} }

View File

@ -6,10 +6,12 @@ This module contains two programs for testing the json parsers.
- `test_json_parser_incremental` is for testing the incremental parser, It - `test_json_parser_incremental` is for testing the incremental parser, It
reads in a file and passes it in very small chunks (default is 60 bytes at a reads in a file and passes it in very small chunks (default is 60 bytes at a
time) to the incremental parser. It's not meant to be a speed test but to time) to the incremental parser. It's not meant to be a speed test but to
test the accuracy of the incremental parser. There are two option arguments, test the accuracy of the incremental parser. The option "-c nn" specifies an
"-c nn" specifies an alternative chunk size, and "-s" specifies using alternative chunk size, "-r nn" runs a range of chunk sizes down to one byte
semantic routines. The semantic routines re-output the json, although not in on the same input (with output separated by null bytes), and "-s" specifies
a very pretty form. The required non-option argument is the input file name. using semantic routines. The semantic routines re-output the json, although
not in a very pretty form. The required non-option argument is the input file
name.
- `test_json_parser_perf` is for speed testing both the standard - `test_json_parser_perf` is for speed testing both the standard
recursive descent parser and the non-recursive incremental recursive descent parser and the non-recursive incremental
parser. If given the `-i` flag it uses the non-recursive parser, parser. If given the `-i` flag it uses the non-recursive parser,

View File

@ -33,23 +33,37 @@ sub test
print $fh "$json"; print $fh "$json";
close($fh); close($fh);
# The -r mode runs the parser in a loop, with output separated by nulls.
# Unpack that as a list of null-terminated ASCII strings (Z*) and check that
# each run produces the same result.
my ($all_stdout, $all_stderr) =
run_command([ @exe, "-r", $chunk, $fname ]);
my @stdout = unpack("(Z*)*", $all_stdout);
my @stderr = unpack("(Z*)*", $all_stderr);
is(scalar @stdout, $chunk, "$name: stdout has correct number of entries");
is(scalar @stderr, $chunk, "$name: stderr has correct number of entries");
my $i = 0;
foreach my $size (reverse(1 .. $chunk)) foreach my $size (reverse(1 .. $chunk))
{ {
my ($stdout, $stderr) = run_command([ @exe, "-c", $size, $fname ]);
if (defined($params{error})) if (defined($params{error}))
{ {
unlike($stdout, qr/SUCCESS/, unlike($stdout[$i], qr/SUCCESS/,
"$name, chunk size $size: test fails"); "$name, chunk size $size: test fails");
like($stderr, $params{error}, like($stderr[$i], $params{error},
"$name, chunk size $size: correct error output"); "$name, chunk size $size: correct error output");
} }
else else
{ {
like($stdout, qr/SUCCESS/, like($stdout[$i], qr/SUCCESS/,
"$name, chunk size $size: test succeeds"); "$name, chunk size $size: test succeeds");
is($stderr, "", "$name, chunk size $size: no error output"); is($stderr[$i], "", "$name, chunk size $size: no error output");
} }
$i++;
} }
} }

View File

@ -12,9 +12,14 @@
* the parser in very small chunks. In practice you would normally use * the parser in very small chunks. In practice you would normally use
* much larger chunks, but doing this makes it more likely that the * much larger chunks, but doing this makes it more likely that the
* full range of increment handling, especially in the lexer, is exercised. * full range of increment handling, especially in the lexer, is exercised.
*
* If the "-c SIZE" option is provided, that chunk size is used instead * If the "-c SIZE" option is provided, that chunk size is used instead
* of the default of 60. * of the default of 60.
* *
* If the "-r SIZE" option is provided, a range of chunk sizes from SIZE down to
* 1 are run sequentially. A null byte is printed to the streams after each
* iteration.
*
* If the -s flag is given, the program does semantic processing. This should * If the -s flag is given, the program does semantic processing. This should
* just mirror back the json, albeit with white space changes. * just mirror back the json, albeit with white space changes.
* *
@ -88,8 +93,8 @@ main(int argc, char **argv)
StringInfoData json; StringInfoData json;
int n_read; int n_read;
size_t chunk_size = DEFAULT_CHUNK_SIZE; size_t chunk_size = DEFAULT_CHUNK_SIZE;
bool run_chunk_ranges = false;
struct stat statbuf; struct stat statbuf;
off_t bytes_left;
const JsonSemAction *testsem = &nullSemAction; const JsonSemAction *testsem = &nullSemAction;
char *testfile; char *testfile;
int c; int c;
@ -102,11 +107,14 @@ main(int argc, char **argv)
if (!lex) if (!lex)
pg_fatal("out of memory"); pg_fatal("out of memory");
while ((c = getopt(argc, argv, "c:os")) != -1) while ((c = getopt(argc, argv, "r:c:os")) != -1)
{ {
switch (c) switch (c)
{ {
case 'c': /* chunksize */ case 'r': /* chunk range */
run_chunk_ranges = true;
/* fall through */
case 'c': /* chunk size */
chunk_size = strtou64(optarg, NULL, 10); chunk_size = strtou64(optarg, NULL, 10);
if (chunk_size > BUFSIZE) if (chunk_size > BUFSIZE)
pg_fatal("chunk size cannot exceed %d", BUFSIZE); pg_fatal("chunk size cannot exceed %d", BUFSIZE);
@ -135,8 +143,6 @@ main(int argc, char **argv)
exit(1); exit(1);
} }
makeJsonLexContextIncremental(lex, PG_UTF8, need_strings);
setJsonLexContextOwnsTokens(lex, lex_owns_tokens);
initStringInfo(&json); initStringInfo(&json);
if ((json_file = fopen(testfile, PG_BINARY_R)) == NULL) if ((json_file = fopen(testfile, PG_BINARY_R)) == NULL)
@ -145,61 +151,88 @@ main(int argc, char **argv)
if (fstat(fileno(json_file), &statbuf) != 0) if (fstat(fileno(json_file), &statbuf) != 0)
pg_fatal("error statting input: %m"); pg_fatal("error statting input: %m");
bytes_left = statbuf.st_size; do
for (;;)
{ {
/* We will break when there's nothing left to read */
if (bytes_left < chunk_size)
chunk_size = bytes_left;
n_read = fread(buff, 1, chunk_size, json_file);
if (n_read < chunk_size)
pg_fatal("error reading input file: %d", ferror(json_file));
appendBinaryStringInfo(&json, buff, n_read);
/* /*
* Append some trailing junk to the buffer passed to the parser. This * This outer loop only repeats in -r mode. Reset the parse state and
* helps us ensure that the parser does the right thing even if the * our position in the input file for the inner loop, which performs
* chunk isn't terminated with a '\0'. * the incremental parsing.
*/ */
appendStringInfoString(&json, "1+23 trailing junk"); off_t bytes_left = statbuf.st_size;
bytes_left -= n_read; size_t to_read = chunk_size;
if (bytes_left > 0)
makeJsonLexContextIncremental(lex, PG_UTF8, need_strings);
setJsonLexContextOwnsTokens(lex, lex_owns_tokens);
rewind(json_file);
resetStringInfo(&json);
for (;;)
{ {
result = pg_parse_json_incremental(lex, testsem, /* We will break when there's nothing left to read */
json.data, n_read,
false); if (bytes_left < to_read)
if (result != JSON_INCOMPLETE) to_read = bytes_left;
n_read = fread(buff, 1, to_read, json_file);
if (n_read < to_read)
pg_fatal("error reading input file: %d", ferror(json_file));
appendBinaryStringInfo(&json, buff, n_read);
/*
* Append some trailing junk to the buffer passed to the parser.
* This helps us ensure that the parser does the right thing even
* if the chunk isn't terminated with a '\0'.
*/
appendStringInfoString(&json, "1+23 trailing junk");
bytes_left -= n_read;
if (bytes_left > 0)
{ {
fprintf(stderr, "%s\n", json_errdetail(result, lex)); result = pg_parse_json_incremental(lex, testsem,
ret = 1; json.data, n_read,
goto cleanup; false);
if (result != JSON_INCOMPLETE)
{
fprintf(stderr, "%s\n", json_errdetail(result, lex));
ret = 1;
goto cleanup;
}
resetStringInfo(&json);
} }
resetStringInfo(&json); else
}
else
{
result = pg_parse_json_incremental(lex, testsem,
json.data, n_read,
true);
if (result != JSON_SUCCESS)
{ {
fprintf(stderr, "%s\n", json_errdetail(result, lex)); result = pg_parse_json_incremental(lex, testsem,
ret = 1; json.data, n_read,
goto cleanup; true);
if (result != JSON_SUCCESS)
{
fprintf(stderr, "%s\n", json_errdetail(result, lex));
ret = 1;
goto cleanup;
}
if (!need_strings)
printf("SUCCESS!\n");
break;
} }
if (!need_strings)
printf("SUCCESS!\n");
break;
} }
}
cleanup: cleanup:
freeJsonLexContext(lex);
/*
* In -r mode, separate output with nulls so that the calling test can
* split it up, decrement the chunk size, and loop back to the top.
* All other modes immediately fall out of the loop and exit.
*/
if (run_chunk_ranges)
{
fputc('\0', stdout);
fputc('\0', stderr);
}
} while (run_chunk_ranges && (--chunk_size > 0));
fclose(json_file); fclose(json_file);
freeJsonLexContext(lex);
free(json.data); free(json.data);
free(lex); free(lex);