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 */
stat->free_space += BLCKSZ;
}
else
else if (PageGetSpecialSize(page) == MAXALIGN(sizeof(BTPageOpaqueData)))
{
BTPageOpaque opaque;
@ -458,10 +458,16 @@ pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
Buffer buf;
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);
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;
@ -502,17 +508,23 @@ pgstat_gist_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
LockBuffer(buf, GIST_SHARE);
gistcheckpage(rel, buf);
page = BufferGetPage(buf);
if (GistPageIsLeaf(page))
if (PageIsNew(page))
{
pgstat_index_page(stat, page, FirstOffsetNumber,
PageGetMaxOffsetNumber(page));
/* fully empty 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);

View File

@ -46,7 +46,8 @@
/* Inhibit mingw CRT's auto-globbing of command line arguments */
#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
/*

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;
result
--------
<>
(1 row)
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)
(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()
SELECT test_bms_del_member('(b)', -20); -- error
ERROR: negative bitmapset member not allowed
SELECT test_bms_del_member('(b)', 10) AS result;
result
--------
<>
(1 row)
SELECT test_bms_del_member('(b 10)', 10) AS result;
result
--------
<>
(1 row)
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)
-- 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;
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;
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;
@ -252,7 +221,7 @@ SELECT test_bms_del_members('(b 1 2 100 200 300)', '(b 200 300)') AS result;
(b 1 2 100)
(1 row)
-- Test module checks
-- NULL inputs
SELECT test_bms_del_members('(b 5)', NULL) AS 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;
result
--------
<>
(1 row)
-- 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)
(1 row)
-- Test module checks
-- NULL inputs
SELECT test_bms_join('(b 5)', NULL) AS result;
result
--------
@ -319,7 +288,7 @@ SELECT test_bms_join(NULL, '(b 5)') AS result;
SELECT test_bms_join(NULL, NULL) AS result;
result
--------
<>
(1 row)
-- 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;
result
--------
<>
(1 row)
-- 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)
(1 row)
-- Union with varrying word counts
-- Union with varying word counts
SELECT test_bms_union('(b 1 2)', '(b 100 300)') AS result;
result
-----------------
@ -367,7 +336,7 @@ SELECT test_bms_union('(b 100 300)', '(b 1 2)') AS result;
(b 1 2 100 300)
(1 row)
-- Test module checks
-- NULL inputs
SELECT test_bms_union('(b 5)', NULL) AS result;
result
--------
@ -383,7 +352,7 @@ SELECT test_bms_union(NULL, '(b 5)') AS result;
SELECT test_bms_union(NULL, NULL) AS result;
result
--------
<>
(1 row)
-- 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;
result
--------
<>
(1 row)
-- Intersect with empty
SELECT test_bms_intersect('(b 1 3 5)', '(b)') AS result;
result
--------
<>
(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;
result
--------
@ -421,29 +390,23 @@ SELECT test_bms_intersect('(b 1 2 3 4 5)', '(b 1 300)') AS result;
(b 1)
(1 row)
-- Test module checks
SELECT test_bms_intersect('(b 1)', '(b 2)') AS result;
result
--------
(1 row)
-- NULL inputs
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)
-- 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;
result
--------
<>
(1 row)
-- Intersect with empty
SELECT test_bms_int_members('(b 1 3 5)', '(b)') AS result;
result
--------
<>
(1 row)
-- 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)
(1 row)
-- Test module checks
SELECT test_bms_int_members('(b 1)', '(b 2)') AS result;
result
--------
(1 row)
-- NULL inputs
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)
-- 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;
result
--------
<>
(1 row)
-- Substraction to empty
SELECT test_bms_difference('(b 42)', '(b 42)') AS result;
result
--------
<>
(1 row)
-- Subtraction edge case
@ -552,13 +509,7 @@ SELECT test_bms_difference('(b 1 2 100 200)', '(b 1 2)') AS result;
(b 100 200)
(1 row)
-- Test module checks
SELECT test_bms_difference('(b 5)', '(b 5 10)') AS result;
result
--------
(1 row)
-- NULL inputs
SELECT test_bms_difference('(b 5)', NULL) AS result;
result
--------
@ -568,13 +519,13 @@ SELECT test_bms_difference('(b 5)', NULL) AS result;
SELECT test_bms_difference(NULL, '(b 5)') AS result;
result
--------
<>
(1 row)
SELECT test_bms_difference(NULL, NULL) AS result;
result
--------
<>
(1 row)
-- 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;
result
--------
f
(1 row)
-- bms_member_index()
@ -655,17 +606,11 @@ SELECT test_bms_member_index('(b 1 50 100 200)', 200) AS result;
3
(1 row)
-- Test module checks
SELECT test_bms_member_index('', 5) AS result;
-- Test module check
SELECT test_bms_member_index('(b 1 3 5)', NULL) AS result;
result
--------
-1
(1 row)
SELECT test_bms_member_index(NULL, 5) AS result;
result
--------
-1
(1 row)
-- bms_num_members()
@ -731,7 +676,7 @@ SELECT test_bms_equal('(b 5 10)', '(b 100 200 300)') AS result;
f
(1 row)
-- Test module checks
-- NULL inputs
SELECT test_bms_equal('(b 5)', NULL) AS result;
result
--------
@ -796,7 +741,7 @@ SELECT test_bms_compare(
-1
(1 row)
-- Test module checks
-- NULL inputs
SELECT test_bms_compare('(b 5)', NULL) AS result;
result
--------
@ -902,6 +847,7 @@ SELECT test_bms_add_range('(b 5)', NULL, NULL) AS result;
(1 row)
-- NULL inputs
SELECT test_bms_add_range(NULL, 5, 10) AS 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;
result
--------
(1 row)
SELECT test_bms_add_range(NULL, NULL, NULL) AS result;
result
--------
<>
(1 row)
-- bms_membership()
@ -939,7 +879,7 @@ SELECT test_bms_membership('(b 1 2)') AS result;
2
(1 row)
-- Test module check
-- NULL input
SELECT test_bms_membership(NULL) AS result;
result
--------
@ -965,13 +905,6 @@ SELECT test_bms_is_empty('(b 1)') AS result;
f
(1 row)
-- Test module check
SELECT test_bms_is_empty(NULL) AS result;
result
--------
t
(1 row)
-- bms_singleton_member()
SELECT test_bms_singleton_member('(b)'); -- error
ERROR: bitmapset is empty
@ -983,7 +916,7 @@ SELECT test_bms_singleton_member('(b 42)') AS result;
42
(1 row)
-- Test module check
-- NULL input
SELECT test_bms_singleton_member(NULL) AS result;
result
--------
@ -991,39 +924,33 @@ SELECT test_bms_singleton_member(NULL) AS result;
(1 row)
-- bms_get_singleton_member()
SELECT test_bms_get_singleton_member('(b)', 1000);
SELECT test_bms_get_singleton_member('(b)');
test_bms_get_singleton_member
-------------------------------
1000
-1
(1 row)
-- Not a singleton, returns input default
SELECT test_bms_get_singleton_member('(b 3 6)', 1000) 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;
-- Try with an empty set
SELECT test_bms_get_singleton_member(NULL) AS result;
result
--------
-1
(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()
-- First member
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
(1 row)
-- Test module checks
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)
-- NULL inputs
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_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)
-- 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()
SELECT test_bms_hash_value('(b)') = 0 AS 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
(1 row)
-- Test module check
-- NULL input
SELECT test_bms_hash_value(NULL) AS result;
result
--------
@ -1176,7 +1086,7 @@ SELECT test_bms_overlap('(b)', '(b 1 3 5)') AS result;
f
(1 row)
-- Test module checks
-- NULL inputs
SELECT test_bms_overlap('(b 5)', NULL) AS result;
result
--------
@ -1240,7 +1150,7 @@ SELECT test_bms_is_subset('(b 1 2 50 100)', '(b 1 2)') AS result;
f
(1 row)
-- Test module checks
-- NULL inputs
SELECT test_bms_is_subset('(b 5)', NULL) AS result;
result
--------
@ -1398,30 +1308,11 @@ SELECT test_bms_subset_compare('(b 2 64 128)', '(b 1 65)') AS result;
3
(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()
SELECT test_bms_copy(NULL) AS result;
result
--------
<>
(1 row)
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)
(1 row)
-- Test module check
SELECT test_bms_copy(NULL) AS result;
result
--------
(1 row)
-- bms_add_members()
SELECT test_bms_add_members('(b 1 3)', '(b 5 7)') AS result;
result
@ -1547,7 +1431,7 @@ SELECT (test_bitmap_match('(b)', '(b)') = 0) =
t
(1 row)
-- Test module checks
-- NULL inputs
SELECT test_bitmap_match('(b 5)', NULL) AS 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
SELECT test_bms_overlap_list('(b 1 2 3)', ARRAY[-5,-1,0]) AS result; -- error
ERROR: negative bitmapset member not allowed
-- Test module checks
-- NULL inputs
SELECT test_bms_overlap_list('(b 5)', NULL) AS result;
result
--------
@ -1641,6 +1525,12 @@ SELECT test_bms_nonempty_difference('(b 1 3 5)', NULL) AS result;
t
(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;
result
--------
@ -1678,25 +1568,6 @@ SELECT test_bms_nonempty_difference('(b 1 2)', '(b 50 100)') AS result;
t
(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
SELECT test_random_operations(-1, 10000, 81920, 0) > 0 AS 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;
-- Force repalloc() with larger set
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()
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)', 100) AS result;
-- Test module checks
SELECT test_bms_del_member('(b 42)', 42) AS result;
SELECT test_bms_del_member('(b 5)', NULL) AS result;
-- bms_del_members()
@ -63,7 +57,7 @@ SELECT test_bms_del_members('(b 5 100 200)', '(b 200)') AS result;
-- 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 200 300)') AS result;
-- Test module checks
-- NULL inputs
SELECT test_bms_del_members('(b 5)', NULL) 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
SELECT test_bms_join('(b 5)', '(b 100)') 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(NULL, '(b 5)') 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)', 10, 20)
) 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 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(NULL, '(b 5)') 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;
-- Intersect with empty
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 2 3 4 5)', '(b 1 300)') AS result;
-- Test module checks
SELECT test_bms_intersect('(b 1)', '(b 2)') AS result;
-- NULL inputs
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;
@ -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;
-- Multiple members
SELECT test_bms_int_members('(b 0 31 32 63 64)', '(b 31 32 64 65)') AS result;
-- Test module checks
SELECT test_bms_int_members('(b 1)', '(b 2)') AS result;
-- NULL inputs
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;
@ -148,8 +140,7 @@ SELECT test_bms_difference(
-- 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;
-- Test module checks
SELECT test_bms_difference('(b 5)', '(b 5 10)') AS result;
-- NULL inputs
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;
@ -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)', 200) AS result;
SELECT test_bms_member_index('(b 1 50 100 200)', 200) AS result;
-- Test module checks
SELECT test_bms_member_index('', 5) AS result;
SELECT test_bms_member_index(NULL, 5) AS result;
-- Test module check
SELECT test_bms_member_index('(b 1 3 5)', NULL) AS result;
-- bms_num_members()
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
SELECT test_bms_equal('(b 5)', '(b 100)') 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(NULL, '(b 5)') 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, 64)
) AS result;
-- Test module checks
-- NULL inputs
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;
@ -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)', NULL, 10) 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, 10, 5) AS result;
SELECT test_bms_add_range(NULL, NULL, NULL) AS result;
-- bms_membership()
SELECT test_bms_membership('(b)') AS result;
SELECT test_bms_membership('(b 42)') AS result;
SELECT test_bms_membership('(b 1 2)') AS result;
-- Test module check
-- NULL input
SELECT test_bms_membership(NULL) AS result;
-- bms_is_empty()
SELECT test_bms_is_empty(NULL) AS result;
SELECT test_bms_is_empty('(b)') 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()
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;
-- Test module check
-- NULL input
SELECT test_bms_singleton_member(NULL) AS result;
-- 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
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
SELECT test_bms_get_singleton_member('(b 400)', 1000) AS result;
-- Test module checks
SELECT test_bms_get_singleton_member('', 1000) AS result;
SELECT test_bms_get_singleton_member(NULL, -1) AS result;
SELECT test_bms_get_singleton_member('(b 400)') AS result;
-- bms_next_member() and bms_prev_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;
-- Negative prevbit should result in highest possible bit in set
SELECT test_bms_prev_member('(b 0 63 64 127)', -1) AS result;
-- Test module checks
SELECT test_bms_next_member('', 5) AS result;
SELECT test_bms_next_member('(b 5)', NULL) AS result;
-- NULL inputs
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;
-- 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()
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 2 4 6)') AS result;
-- Test module check
-- NULL input
SELECT test_bms_hash_value(NULL) AS result;
-- 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 2 4 6)') 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(NULL, '(b 5)') 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?
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;
-- Test module checks
-- NULL inputs
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;
@ -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 1 64 65)', '(b 1 2 64)') 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()
SELECT test_bms_copy(NULL) 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()
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;
SELECT (test_bitmap_match('(b)', '(b)') = 0) =
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(NULL, '(b 5)') 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
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
-- Test module checks
-- NULL inputs
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;
@ -412,6 +391,7 @@ SELECT test_bms_overlap_list(NULL, NULL) AS result;
-- bms_nonempty_difference()
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(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 1 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 100)', '(b 5)') 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
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
AS 'MODULE_PATHNAME' LANGUAGE C;
CREATE FUNCTION test_bms_get_singleton_member(text, integer)
CREATE FUNCTION test_bms_get_singleton_member(text)
RETURNS integer
AS 'MODULE_PATHNAME' LANGUAGE C;

View File

@ -26,7 +26,6 @@
#include "nodes/pg_list.h"
#include "utils/builtins.h"
#include "utils/timestamp.h"
#include "varatt.h"
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 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
*
* 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
test_bms_add_member(PG_FUNCTION_ARGS)
{
Bitmapset *bms;
int member;
Bitmapset *bms = NULL;
text *result;
if (PG_ARGISNULL(1))
PG_RETURN_NULL();
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
PG_RETURN_NULL(); /* invalid input */
bms = PG_ARG_GETBITMAPSET(0);
member = PG_GETARG_INT32(1);
bms = bms_add_member(bms, member);
result = BITMAPSET_TO_TEXT(bms);
if (bms)
bms_free(bms);
PG_RETURN_TEXT_P(result);
PG_RETURN_BITMAPSET_AS_TEXT(bms);
}
Datum
test_bms_add_members(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
text *result;
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
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_add_members modifies/frees the first argument */
/* left input is recycled */
bms1 = bms_add_members(bms1, bms2);
if (bms2)
bms_free(bms2);
result = BITMAPSET_TO_TEXT(bms1);
bms_free(bms1);
PG_RETURN_TEXT_P(result);
PG_RETURN_BITMAPSET_AS_TEXT(bms1);
}
Datum
test_bms_del_member(PG_FUNCTION_ARGS)
{
Bitmapset *bms = NULL;
Bitmapset *bms;
int32 member;
text *result;
if (PG_ARGISNULL(1))
PG_RETURN_NULL();
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
PG_RETURN_NULL(); /* invalid input */
bms = PG_ARG_GETBITMAPSET(0);
member = PG_GETARG_INT32(1);
bms = bms_del_member(bms, member);
if (bms_is_empty(bms))
PG_RETURN_NULL();
result = BITMAPSET_TO_TEXT(bms);
bms_free(bms);
PG_RETURN_TEXT_P(result);
PG_RETURN_BITMAPSET_AS_TEXT(bms);
}
Datum
test_bms_is_member(PG_FUNCTION_ARGS)
{
Bitmapset *bms = NULL;
Bitmapset *bms;
int32 member;
bool result;
if (PG_ARGISNULL(1))
PG_RETURN_BOOL(false);
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
PG_RETURN_NULL(); /* invalid input */
bms = PG_ARG_GETBITMAPSET(0);
member = PG_GETARG_INT32(1);
result = bms_is_member(member, bms);
if (bms)
bms_free(bms);
result = bms_is_member(member, bms);
PG_RETURN_BOOL(result);
}
@ -190,150 +187,89 @@ test_bms_is_member(PG_FUNCTION_ARGS)
Datum
test_bms_num_members(PG_FUNCTION_ARGS)
{
Bitmapset *bms = NULL;
int result = 0;
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
int result;
result = bms_num_members(bms);
if (bms)
bms_free(bms);
PG_RETURN_INT32(result);
}
Datum
test_bms_make_singleton(PG_FUNCTION_ARGS)
{
int32 member;
Bitmapset *bms;
text *result;
int32 member;
if (PG_ARGISNULL(0))
PG_RETURN_NULL();
PG_RETURN_NULL(); /* invalid input */
member = PG_GETARG_INT32(0);
bms = bms_make_singleton(member);
result = BITMAPSET_TO_TEXT(bms);
bms_free(bms);
PG_RETURN_TEXT_P(result);
PG_RETURN_BITMAPSET_AS_TEXT(bms);
}
Datum
test_bms_copy(PG_FUNCTION_ARGS)
{
text *bms_data;
Bitmapset *bms = NULL;
Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
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);
result = BITMAPSET_TO_TEXT(copy_bms);
if (bms)
bms_free(bms);
if (copy_bms)
bms_free(copy_bms);
PG_RETURN_TEXT_P(result);
PG_RETURN_BITMAPSET_AS_TEXT(copy_bms);
}
Datum
test_bms_equal(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
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);
if (bms1)
bms_free(bms1);
if (bms2)
bms_free(bms2);
PG_RETURN_BOOL(result);
}
Datum
test_bms_union(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
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);
if (bms1)
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);
PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
}
Datum
test_bms_membership(PG_FUNCTION_ARGS)
{
Bitmapset *bms = NULL;
Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
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);
if (bms)
bms_free(bms);
PG_RETURN_INT32((int32) result);
}
Datum
test_bms_next_member(PG_FUNCTION_ARGS)
{
Bitmapset *bms = NULL;
Bitmapset *bms;
int32 prevmember;
int result;
if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
PG_RETURN_INT32(-2);
if (PG_ARGISNULL(1))
PG_RETURN_NULL(); /* invalid input */
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
bms = PG_ARG_GETBITMAPSET(0);
prevmember = PG_GETARG_INT32(1);
result = bms_next_member(bms, prevmember);
if (bms)
bms_free(bms);
result = bms_next_member(bms, prevmember);
PG_RETURN_INT32(result);
}
@ -341,212 +277,115 @@ test_bms_next_member(PG_FUNCTION_ARGS)
Datum
test_bms_intersect(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
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);
if (bms1)
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);
PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
}
Datum
test_bms_difference(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
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);
if (bms1)
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);
PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
}
Datum
test_bms_compare(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
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);
if (bms1)
bms_free(bms1);
if (bms2)
bms_free(bms2);
PG_RETURN_INT32(result);
}
Datum
test_bms_is_empty(PG_FUNCTION_ARGS)
{
Bitmapset *bms = NULL;
Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
bool result;
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
result = bms_is_empty(bms);
if (bms)
bms_free(bms);
PG_RETURN_BOOL(result);
}
Datum
test_bms_is_subset(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
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);
if (bms1)
bms_free(bms1);
if (bms2)
bms_free(bms2);
PG_RETURN_BOOL(result);
}
Datum
test_bms_subset_compare(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
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);
if (bms1)
bms_free(bms1);
if (bms2)
bms_free(bms2);
PG_RETURN_INT32((int32) result);
}
Datum
test_bms_singleton_member(PG_FUNCTION_ARGS)
{
Bitmapset *bms = NULL;
Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
int result;
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
result = bms_singleton_member(bms);
if (bms)
bms_free(bms);
PG_RETURN_INT32(result);
}
Datum
test_bms_get_singleton_member(PG_FUNCTION_ARGS)
{
Bitmapset *bms = NULL;
int32 default_member = PG_GETARG_INT32(1);
bool success;
int member = -1;
if (PG_ARGISNULL(0))
PG_RETURN_INT32(default_member);
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
int member;
/*
* bms_get_singleton_member returns bool and stores result in member
* pointer
* Keep this simple. Return -1 when we detect the set is not a singleton
* set, otherwise return the singleton member.
*/
success = bms_get_singleton_member(bms, &member);
bms_free(bms);
if (!bms_get_singleton_member(bms, &member))
member = -1;
if (success)
PG_RETURN_INT32(member);
PG_RETURN_INT32(default_member);
PG_RETURN_INT32(member);
}
Datum
test_bms_prev_member(PG_FUNCTION_ARGS)
{
text *bms_data;
Bitmapset *bms = NULL;
Bitmapset *bms;
int32 prevmember;
int result;
if (PG_ARGISNULL(0))
PG_RETURN_INT32(-2);
if (PG_ARGISNULL(1))
PG_RETURN_NULL(); /* invalid input */
bms_data = PG_GETARG_TEXT_PP(0);
bms = PG_ARG_GETBITMAPSET(0);
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);
bms_free(bms);
PG_RETURN_INT32(result);
}
@ -554,75 +393,57 @@ test_bms_prev_member(PG_FUNCTION_ARGS)
Datum
test_bms_overlap(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
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);
if (bms1)
bms_free(bms1);
if (bms2)
bms_free(bms2);
PG_RETURN_BOOL(result);
}
Datum
test_bms_overlap_list(PG_FUNCTION_ARGS)
{
Bitmapset *bms = NULL;
Bitmapset *bms;
ArrayType *array;
List *int_list = NIL;
bool result;
Datum *elem_datums;
bool *elem_nulls;
Datum *elem_datums = NULL;
bool *elem_nulls = NULL;
int elem_count;
int i;
if (PG_ARGISNULL(0))
PG_RETURN_BOOL(false);
bms = PG_ARG_GETBITMAPSET(0);
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
if (PG_ARGISNULL(1))
if (!PG_ARGISNULL(1))
{
if (bms)
bms_free(bms);
PG_RETURN_BOOL(false);
}
array = PG_GETARG_ARRAYTYPE_P(1);
array = PG_GETARG_ARRAYTYPE_P(1);
deconstruct_array(array,
INT4OID, sizeof(int32), true, 'i',
&elem_datums, &elem_nulls, &elem_count);
deconstruct_array(array,
INT4OID, sizeof(int32), true, 'i',
&elem_datums, &elem_nulls, &elem_count);
for (i = 0; i < elem_count; i++)
{
if (!elem_nulls[i])
for (i = 0; i < elem_count; 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);
if (bms)
bms_free(bms);
list_free(int_list);
pfree(elem_datums);
pfree(elem_nulls);
if (elem_datums)
pfree(elem_datums);
if (elem_nulls)
pfree(elem_nulls);
PG_RETURN_BOOL(result);
}
@ -630,47 +451,29 @@ test_bms_overlap_list(PG_FUNCTION_ARGS)
Datum
test_bms_nonempty_difference(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
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);
if (bms1)
bms_free(bms1);
if (bms2)
bms_free(bms2);
PG_RETURN_BOOL(result);
}
Datum
test_bms_member_index(PG_FUNCTION_ARGS)
{
text *bms_data;
Bitmapset *bms = NULL;
Bitmapset *bms;
int32 member;
int result;
if (PG_ARGISNULL(0))
PG_RETURN_INT32(-1);
if (PG_ARGISNULL(1))
PG_RETURN_NULL(); /* invalid input */
bms_data = PG_GETARG_TEXT_PP(0);
bms = PG_ARG_GETBITMAPSET(0);
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);
bms_free(bms);
PG_RETURN_INT32(result);
}
@ -678,191 +481,92 @@ test_bms_member_index(PG_FUNCTION_ARGS)
Datum
test_bms_add_range(PG_FUNCTION_ARGS)
{
Bitmapset *bms = NULL;
Bitmapset *bms;
int32 lower,
upper;
text *result;
if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
PG_RETURN_NULL();
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
PG_RETURN_NULL(); /* invalid input */
bms = PG_ARG_GETBITMAPSET(0);
lower = PG_GETARG_INT32(1);
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);
result = BITMAPSET_TO_TEXT(bms);
if (bms)
bms_free(bms);
PG_RETURN_TEXT_P(result);
PG_RETURN_BITMAPSET_AS_TEXT(bms);
}
Datum
test_bms_int_members(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
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));
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
/* left input gets recycled */
bms1 = bms_int_members(bms1, bms2);
if (bms2)
bms_free(bms2);
if (bms1 == NULL)
PG_RETURN_NULL();
result = BITMAPSET_TO_TEXT(bms1);
if (bms1)
bms_free(bms1);
PG_RETURN_TEXT_P(result);
PG_RETURN_BITMAPSET_AS_TEXT(bms1);
}
Datum
test_bms_del_members(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
Bitmapset *result_bms;
text *result;
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
if (!PG_ARGISNULL(0))
bms1 = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
/* left input gets recycled */
bms1 = bms_del_members(bms1, bms2);
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);
PG_RETURN_BITMAPSET_AS_TEXT(bms1);
}
Datum
test_bms_replace_members(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
Bitmapset *result_bms;
text *result;
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
if (!PG_ARGISNULL(0))
bms1 = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
/* left input gets recycled */
bms1 = bms_replace_members(bms1, bms2);
if (!PG_ARGISNULL(1))
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);
PG_RETURN_BITMAPSET_AS_TEXT(bms1);
}
Datum
test_bms_join(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
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_join may recycle either input arguments */
/* either input can be recycled */
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_NULL();
result = BITMAPSET_TO_TEXT(result_bms);
bms_free(result_bms);
PG_RETURN_TEXT_P(result);
PG_RETURN_BITMAPSET_AS_TEXT(result_bms);
}
Datum
test_bms_hash_value(PG_FUNCTION_ARGS)
{
Bitmapset *bms = NULL;
Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
uint32 hash_result;
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
hash_result = bms_hash_value(bms);
if (bms)
bms_free(bms);
PG_RETURN_INT32(hash_result);
}
Datum
test_bitmap_hash(PG_FUNCTION_ARGS)
{
Bitmapset *bms = NULL;
Bitmapset *bms_ptr;
Bitmapset *bms = PG_ARG_GETBITMAPSET(0);
uint32 hash_result;
if (!PG_ARGISNULL(0))
bms = TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(0));
bms_ptr = bms;
/* Call bitmap_hash */
hash_result = bitmap_hash(&bms_ptr, sizeof(Bitmapset *));
/* Clean up */
if (!PG_ARGISNULL(0) && bms_ptr)
bms_free(bms_ptr);
hash_result = bitmap_hash(&bms, sizeof(Bitmapset *));
PG_RETURN_INT32(hash_result);
}
@ -870,30 +574,12 @@ test_bitmap_hash(PG_FUNCTION_ARGS)
Datum
test_bitmap_match(PG_FUNCTION_ARGS)
{
Bitmapset *bms1 = NULL,
*bms2 = NULL;
Bitmapset *bms_ptr1,
*bms_ptr2;
Bitmapset *bms1 = PG_ARG_GETBITMAPSET(0);
Bitmapset *bms2 = PG_ARG_GETBITMAPSET(1);
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 */
match_result = bitmap_match(&bms_ptr1, &bms_ptr2, sizeof(Bitmapset *));
/* Clean up */
if (bms1)
bms_free(bms1);
if (bms2)
bms_free(bms2);
match_result = bitmap_match(&bms1, &bms2, sizeof(Bitmapset *));
PG_RETURN_INT32(match_result);
}
@ -1031,8 +717,7 @@ test_random_operations(PG_FUNCTION_ARGS)
total_ops++;
}
if (bms)
bms_free(bms);
bms_free(bms);
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
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
test the accuracy of the incremental parser. There are two option arguments,
"-c nn" specifies an alternative chunk size, and "-s" specifies 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 the accuracy of the incremental parser. The option "-c nn" specifies an
alternative chunk size, "-r nn" runs a range of chunk sizes down to one byte
on the same input (with output separated by null bytes), and "-s" specifies
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
recursive descent parser and the non-recursive incremental
parser. If given the `-i` flag it uses the non-recursive parser,

View File

@ -33,23 +33,37 @@ sub test
print $fh "$json";
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))
{
my ($stdout, $stderr) = run_command([ @exe, "-c", $size, $fname ]);
if (defined($params{error}))
{
unlike($stdout, qr/SUCCESS/,
unlike($stdout[$i], qr/SUCCESS/,
"$name, chunk size $size: test fails");
like($stderr, $params{error},
like($stderr[$i], $params{error},
"$name, chunk size $size: correct error output");
}
else
{
like($stdout, qr/SUCCESS/,
like($stdout[$i], qr/SUCCESS/,
"$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
* much larger chunks, but doing this makes it more likely that the
* full range of increment handling, especially in the lexer, is exercised.
*
* If the "-c SIZE" option is provided, that chunk size is used instead
* 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
* just mirror back the json, albeit with white space changes.
*
@ -88,8 +93,8 @@ main(int argc, char **argv)
StringInfoData json;
int n_read;
size_t chunk_size = DEFAULT_CHUNK_SIZE;
bool run_chunk_ranges = false;
struct stat statbuf;
off_t bytes_left;
const JsonSemAction *testsem = &nullSemAction;
char *testfile;
int c;
@ -102,11 +107,14 @@ main(int argc, char **argv)
if (!lex)
pg_fatal("out of memory");
while ((c = getopt(argc, argv, "c:os")) != -1)
while ((c = getopt(argc, argv, "r:c:os")) != -1)
{
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);
if (chunk_size > BUFSIZE)
pg_fatal("chunk size cannot exceed %d", BUFSIZE);
@ -135,8 +143,6 @@ main(int argc, char **argv)
exit(1);
}
makeJsonLexContextIncremental(lex, PG_UTF8, need_strings);
setJsonLexContextOwnsTokens(lex, lex_owns_tokens);
initStringInfo(&json);
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)
pg_fatal("error statting input: %m");
bytes_left = statbuf.st_size;
for (;;)
do
{
/* 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
* helps us ensure that the parser does the right thing even if the
* chunk isn't terminated with a '\0'.
* This outer loop only repeats in -r mode. Reset the parse state and
* our position in the input file for the inner loop, which performs
* the incremental parsing.
*/
appendStringInfoString(&json, "1+23 trailing junk");
bytes_left -= n_read;
if (bytes_left > 0)
off_t bytes_left = statbuf.st_size;
size_t to_read = chunk_size;
makeJsonLexContextIncremental(lex, PG_UTF8, need_strings);
setJsonLexContextOwnsTokens(lex, lex_owns_tokens);
rewind(json_file);
resetStringInfo(&json);
for (;;)
{
result = pg_parse_json_incremental(lex, testsem,
json.data, n_read,
false);
if (result != JSON_INCOMPLETE)
/* We will break when there's nothing left to read */
if (bytes_left < to_read)
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));
ret = 1;
goto cleanup;
result = pg_parse_json_incremental(lex, testsem,
json.data, n_read,
false);
if (result != JSON_INCOMPLETE)
{
fprintf(stderr, "%s\n", json_errdetail(result, lex));
ret = 1;
goto cleanup;
}
resetStringInfo(&json);
}
resetStringInfo(&json);
}
else
{
result = pg_parse_json_incremental(lex, testsem,
json.data, n_read,
true);
if (result != JSON_SUCCESS)
else
{
fprintf(stderr, "%s\n", json_errdetail(result, lex));
ret = 1;
goto cleanup;
result = pg_parse_json_incremental(lex, testsem,
json.data, n_read,
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:
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);
freeJsonLexContext(lex);
free(json.data);
free(lex);