1 /*--------------------------------------------------------------------------
2 *
3 * test_ginpostinglist.c
4 * Test varbyte-encoding in ginpostinglist.c
5 *
6 * Copyright (c) 2019-2020, PostgreSQL Global Development Group
7 *
8 * IDENTIFICATION
9 * src/test/modules/test_ginpostinglist/test_ginpostinglist.c
10 *
11 * -------------------------------------------------------------------------
12 */
13 #include "postgres.h"
14
15 #include "access/gin_private.h"
16 #include "access/ginblock.h"
17 #include "access/htup_details.h"
18 #include "fmgr.h"
19
20 PG_MODULE_MAGIC;
21
22 PG_FUNCTION_INFO_V1(test_ginpostinglist);
23
24 /*
25 * Encodes a pair of TIDs, and decodes it back. The first TID is always
26 * (0, 1), the second one is formed from the blk/off arguments. The 'maxsize'
27 * argument is passed to ginCompressPostingList(); it can be used to test the
28 * overflow checks.
29 *
30 * The reason that we test a pair, instead of just a single TID, is that
31 * the GinPostingList stores the first TID as is, and the varbyte-encoding
32 * is only used for the deltas between TIDs. So testing a single TID would
33 * not exercise the varbyte encoding at all.
34 *
35 * This function prints NOTICEs to describe what is tested, and how large the
36 * resulting GinPostingList is. Any incorrect results, e.g. if the encode +
37 * decode round trip doesn't return the original input, are reported as
38 * ERRORs.
39 */
40 static void
test_itemptr_pair(BlockNumber blk,OffsetNumber off,int maxsize)41 test_itemptr_pair(BlockNumber blk, OffsetNumber off, int maxsize)
42 {
43 ItemPointerData orig_itemptrs[2];
44 ItemPointer decoded_itemptrs;
45 GinPostingList *pl;
46 int nwritten;
47 int ndecoded;
48
49 elog(NOTICE, "testing with (%u, %d), (%u, %d), max %d bytes",
50 0, 1, blk, off, maxsize);
51 ItemPointerSet(&orig_itemptrs[0], 0, 1);
52 ItemPointerSet(&orig_itemptrs[1], blk, off);
53
54 /* Encode, and decode it back */
55 pl = ginCompressPostingList(orig_itemptrs, 2, maxsize, &nwritten);
56 elog(NOTICE, "encoded %d item pointers to %zu bytes",
57 nwritten, SizeOfGinPostingList(pl));
58
59 if (SizeOfGinPostingList(pl) > maxsize)
60 elog(ERROR, "overflow: result was %zu bytes, max %d",
61 SizeOfGinPostingList(pl), maxsize);
62
63 decoded_itemptrs = ginPostingListDecode(pl, &ndecoded);
64 if (nwritten != ndecoded)
65 elog(NOTICE, "encoded %d itemptrs, %d came back", nwritten, ndecoded);
66
67 /* Check the result */
68 if (!ItemPointerEquals(&orig_itemptrs[0], &decoded_itemptrs[0]))
69 elog(ERROR, "mismatch on first itemptr: (%u, %d) vs (%u, %d)",
70 0, 1,
71 ItemPointerGetBlockNumber(&decoded_itemptrs[0]),
72 ItemPointerGetOffsetNumber(&decoded_itemptrs[0]));
73
74 if (ndecoded == 2 &&
75 !ItemPointerEquals(&orig_itemptrs[0], &decoded_itemptrs[0]))
76 {
77 elog(ERROR, "mismatch on second itemptr: (%u, %d) vs (%u, %d)",
78 0, 1,
79 ItemPointerGetBlockNumber(&decoded_itemptrs[0]),
80 ItemPointerGetOffsetNumber(&decoded_itemptrs[0]));
81 }
82 }
83
84 /*
85 * SQL-callable entry point to perform all tests.
86 */
87 Datum
test_ginpostinglist(PG_FUNCTION_ARGS)88 test_ginpostinglist(PG_FUNCTION_ARGS)
89 {
90 test_itemptr_pair(0, 2, 14);
91 test_itemptr_pair(0, MaxHeapTuplesPerPage, 14);
92 test_itemptr_pair(MaxBlockNumber, MaxHeapTuplesPerPage, 14);
93 test_itemptr_pair(MaxBlockNumber, MaxHeapTuplesPerPage, 16);
94
95 PG_RETURN_VOID();
96 }
97