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