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