1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * itup.h |
4 | * POSTGRES index tuple definitions. |
5 | * |
6 | * |
7 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
8 | * Portions Copyright (c) 1994, Regents of the University of California |
9 | * |
10 | * src/include/access/itup.h |
11 | * |
12 | *------------------------------------------------------------------------- |
13 | */ |
14 | #ifndef ITUP_H |
15 | #define ITUP_H |
16 | |
17 | #include "access/tupdesc.h" |
18 | #include "access/tupmacs.h" |
19 | #include "storage/bufpage.h" |
20 | #include "storage/itemptr.h" |
21 | |
22 | /* |
23 | * Index tuple header structure |
24 | * |
25 | * All index tuples start with IndexTupleData. If the HasNulls bit is set, |
26 | * this is followed by an IndexAttributeBitMapData. The index attribute |
27 | * values follow, beginning at a MAXALIGN boundary. |
28 | * |
29 | * Note that the space allocated for the bitmap does not vary with the number |
30 | * of attributes; that is because we don't have room to store the number of |
31 | * attributes in the header. Given the MAXALIGN constraint there's no space |
32 | * savings to be had anyway, for usual values of INDEX_MAX_KEYS. |
33 | */ |
34 | |
35 | typedef struct IndexTupleData |
36 | { |
37 | ItemPointerData t_tid; /* reference TID to heap tuple */ |
38 | |
39 | /* --------------- |
40 | * t_info is laid out in the following fashion: |
41 | * |
42 | * 15th (high) bit: has nulls |
43 | * 14th bit: has var-width attributes |
44 | * 13th bit: AM-defined meaning |
45 | * 12-0 bit: size of tuple |
46 | * --------------- |
47 | */ |
48 | |
49 | unsigned short t_info; /* various info about tuple */ |
50 | |
51 | } IndexTupleData; /* MORE DATA FOLLOWS AT END OF STRUCT */ |
52 | |
53 | typedef IndexTupleData *IndexTuple; |
54 | |
55 | typedef struct IndexAttributeBitMapData |
56 | { |
57 | bits8 bits[(INDEX_MAX_KEYS + 8 - 1) / 8]; |
58 | } IndexAttributeBitMapData; |
59 | |
60 | typedef IndexAttributeBitMapData * IndexAttributeBitMap; |
61 | |
62 | /* |
63 | * t_info manipulation macros |
64 | */ |
65 | #define INDEX_SIZE_MASK 0x1FFF |
66 | #define INDEX_AM_RESERVED_BIT 0x2000 /* reserved for index-AM specific |
67 | * usage */ |
68 | #define INDEX_VAR_MASK 0x4000 |
69 | #define INDEX_NULL_MASK 0x8000 |
70 | |
71 | #define IndexTupleSize(itup) ((Size) ((itup)->t_info & INDEX_SIZE_MASK)) |
72 | #define IndexTupleHasNulls(itup) ((((IndexTuple) (itup))->t_info & INDEX_NULL_MASK)) |
73 | #define IndexTupleHasVarwidths(itup) ((((IndexTuple) (itup))->t_info & INDEX_VAR_MASK)) |
74 | |
75 | |
76 | /* |
77 | * Takes an infomask as argument (primarily because this needs to be usable |
78 | * at index_form_tuple time so enough space is allocated). |
79 | */ |
80 | #define IndexInfoFindDataOffset(t_info) \ |
81 | ( \ |
82 | (!((t_info) & INDEX_NULL_MASK)) ? \ |
83 | ( \ |
84 | (Size)MAXALIGN(sizeof(IndexTupleData)) \ |
85 | ) \ |
86 | : \ |
87 | ( \ |
88 | (Size)MAXALIGN(sizeof(IndexTupleData) + sizeof(IndexAttributeBitMapData)) \ |
89 | ) \ |
90 | ) |
91 | |
92 | /* ---------------- |
93 | * index_getattr |
94 | * |
95 | * This gets called many times, so we macro the cacheable and NULL |
96 | * lookups, and call nocache_index_getattr() for the rest. |
97 | * |
98 | * ---------------- |
99 | */ |
100 | #define index_getattr(tup, attnum, tupleDesc, isnull) \ |
101 | ( \ |
102 | AssertMacro(PointerIsValid(isnull) && (attnum) > 0), \ |
103 | *(isnull) = false, \ |
104 | !IndexTupleHasNulls(tup) ? \ |
105 | ( \ |
106 | TupleDescAttr((tupleDesc), (attnum)-1)->attcacheoff >= 0 ? \ |
107 | ( \ |
108 | fetchatt(TupleDescAttr((tupleDesc), (attnum)-1), \ |
109 | (char *) (tup) + IndexInfoFindDataOffset((tup)->t_info) \ |
110 | + TupleDescAttr((tupleDesc), (attnum)-1)->attcacheoff) \ |
111 | ) \ |
112 | : \ |
113 | nocache_index_getattr((tup), (attnum), (tupleDesc)) \ |
114 | ) \ |
115 | : \ |
116 | ( \ |
117 | (att_isnull((attnum)-1, (char *)(tup) + sizeof(IndexTupleData))) ? \ |
118 | ( \ |
119 | *(isnull) = true, \ |
120 | (Datum)NULL \ |
121 | ) \ |
122 | : \ |
123 | ( \ |
124 | nocache_index_getattr((tup), (attnum), (tupleDesc)) \ |
125 | ) \ |
126 | ) \ |
127 | ) |
128 | |
129 | /* |
130 | * MaxIndexTuplesPerPage is an upper bound on the number of tuples that can |
131 | * fit on one index page. An index tuple must have either data or a null |
132 | * bitmap, so we can safely assume it's at least 1 byte bigger than a bare |
133 | * IndexTupleData struct. We arrive at the divisor because each tuple |
134 | * must be maxaligned, and it must have an associated line pointer. |
135 | * |
136 | * To be index-type-independent, this does not account for any special space |
137 | * on the page, and is thus conservative. |
138 | * |
139 | * Note: in btree non-leaf pages, the first tuple has no key (it's implicitly |
140 | * minus infinity), thus breaking the "at least 1 byte bigger" assumption. |
141 | * On such a page, N tuples could take one MAXALIGN quantum less space than |
142 | * estimated here, seemingly allowing one more tuple than estimated here. |
143 | * But such a page always has at least MAXALIGN special space, so we're safe. |
144 | */ |
145 | #define MaxIndexTuplesPerPage \ |
146 | ((int) ((BLCKSZ - SizeOfPageHeaderData) / \ |
147 | (MAXALIGN(sizeof(IndexTupleData) + 1) + sizeof(ItemIdData)))) |
148 | |
149 | |
150 | /* routines in indextuple.c */ |
151 | extern IndexTuple index_form_tuple(TupleDesc tupleDescriptor, |
152 | Datum *values, bool *isnull); |
153 | extern Datum nocache_index_getattr(IndexTuple tup, int attnum, |
154 | TupleDesc tupleDesc); |
155 | extern void index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor, |
156 | Datum *values, bool *isnull); |
157 | extern IndexTuple CopyIndexTuple(IndexTuple source); |
158 | extern IndexTuple index_truncate_tuple(TupleDesc sourceDescriptor, |
159 | IndexTuple source, int leavenatts); |
160 | |
161 | #endif /* ITUP_H */ |
162 | |