1 /*-------------------------------------------------------------------------
2  *
3  * itemptr.c
4  *	  POSTGRES disk item pointer code.
5  *
6  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/storage/page/itemptr.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "storage/itemptr.h"
18 
19 
20 /*
21  * ItemPointerEquals
22  *	Returns true if both item pointers point to the same item,
23  *	 otherwise returns false.
24  *
25  * Note:
26  *	Asserts that the disk item pointers are both valid!
27  */
28 bool
ItemPointerEquals(ItemPointer pointer1,ItemPointer pointer2)29 ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
30 {
31 	/*
32 	 * We really want ItemPointerData to be exactly 6 bytes.  This is rather a
33 	 * random place to check, but there is no better place.
34 	 */
35 	StaticAssertStmt(sizeof(ItemPointerData) == 3 * sizeof(uint16),
36 					 "ItemPointerData struct is improperly padded");
37 
38 	if (ItemPointerGetBlockNumber(pointer1) ==
39 		ItemPointerGetBlockNumber(pointer2) &&
40 		ItemPointerGetOffsetNumber(pointer1) ==
41 		ItemPointerGetOffsetNumber(pointer2))
42 		return true;
43 	else
44 		return false;
45 }
46 
47 /*
48  * ItemPointerCompare
49  *		Generic btree-style comparison for item pointers.
50  */
51 int32
ItemPointerCompare(ItemPointer arg1,ItemPointer arg2)52 ItemPointerCompare(ItemPointer arg1, ItemPointer arg2)
53 {
54 	/*
55 	 * Use ItemPointerGet{Offset,Block}NumberNoCheck to avoid asserting
56 	 * ip_posid != 0, which may not be true for a user-supplied TID.
57 	 */
58 	BlockNumber b1 = ItemPointerGetBlockNumberNoCheck(arg1);
59 	BlockNumber b2 = ItemPointerGetBlockNumberNoCheck(arg2);
60 
61 	if (b1 < b2)
62 		return -1;
63 	else if (b1 > b2)
64 		return 1;
65 	else if (ItemPointerGetOffsetNumberNoCheck(arg1) <
66 			 ItemPointerGetOffsetNumberNoCheck(arg2))
67 		return -1;
68 	else if (ItemPointerGetOffsetNumberNoCheck(arg1) >
69 			 ItemPointerGetOffsetNumberNoCheck(arg2))
70 		return 1;
71 	else
72 		return 0;
73 }
74 
75 /*
76  * ItemPointerInc
77  *		Increment 'pointer' by 1 only paying attention to the ItemPointer's
78  *		type's range limits and not MaxOffsetNumber and FirstOffsetNumber.
79  *		This may result in 'pointer' becoming !OffsetNumberIsValid.
80  *
81  * If the pointer is already the maximum possible values permitted by the
82  * range of the ItemPointer's types, then do nothing.
83  */
84 void
ItemPointerInc(ItemPointer pointer)85 ItemPointerInc(ItemPointer pointer)
86 {
87 	BlockNumber blk = ItemPointerGetBlockNumberNoCheck(pointer);
88 	OffsetNumber off = ItemPointerGetOffsetNumberNoCheck(pointer);
89 
90 	if (off == PG_UINT16_MAX)
91 	{
92 		if (blk != InvalidBlockNumber)
93 		{
94 			off = 0;
95 			blk++;
96 		}
97 	}
98 	else
99 		off++;
100 
101 	ItemPointerSet(pointer, blk, off);
102 }
103 
104 /*
105  * ItemPointerDec
106  *		Decrement 'pointer' by 1 only paying attention to the ItemPointer's
107  *		type's range limits and not MaxOffsetNumber and FirstOffsetNumber.
108  *		This may result in 'pointer' becoming !OffsetNumberIsValid.
109  *
110  * If the pointer is already the minimum possible values permitted by the
111  * range of the ItemPointer's types, then do nothing.  This does rely on
112  * FirstOffsetNumber being 1 rather than 0.
113  */
114 void
ItemPointerDec(ItemPointer pointer)115 ItemPointerDec(ItemPointer pointer)
116 {
117 	BlockNumber blk = ItemPointerGetBlockNumberNoCheck(pointer);
118 	OffsetNumber off = ItemPointerGetOffsetNumberNoCheck(pointer);
119 
120 	if (off == 0)
121 	{
122 		if (blk != 0)
123 		{
124 			off = PG_UINT16_MAX;
125 			blk--;
126 		}
127 	}
128 	else
129 		off--;
130 
131 	ItemPointerSet(pointer, blk, off);
132 }
133