1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * tupmacs.h |
4 | * Tuple macros used by both index tuples and heap tuples. |
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/tupmacs.h |
11 | * |
12 | *------------------------------------------------------------------------- |
13 | */ |
14 | #ifndef TUPMACS_H |
15 | #define TUPMACS_H |
16 | |
17 | |
18 | /* |
19 | * Check a tuple's null bitmap to determine whether the attribute is null. |
20 | * Note that a 0 in the null bitmap indicates a null, while 1 indicates |
21 | * non-null. |
22 | */ |
23 | #define att_isnull(ATT, BITS) (!((BITS)[(ATT) >> 3] & (1 << ((ATT) & 0x07)))) |
24 | |
25 | /* |
26 | * Given a Form_pg_attribute and a pointer into a tuple's data area, |
27 | * return the correct value or pointer. |
28 | * |
29 | * We return a Datum value in all cases. If the attribute has "byval" false, |
30 | * we return the same pointer into the tuple data area that we're passed. |
31 | * Otherwise, we return the correct number of bytes fetched from the data |
32 | * area and extended to Datum form. |
33 | * |
34 | * On machines where Datum is 8 bytes, we support fetching 8-byte byval |
35 | * attributes; otherwise, only 1, 2, and 4-byte values are supported. |
36 | * |
37 | * Note that T must already be properly aligned for this to work correctly. |
38 | */ |
39 | #define fetchatt(A,T) fetch_att(T, (A)->attbyval, (A)->attlen) |
40 | |
41 | /* |
42 | * Same, but work from byval/len parameters rather than Form_pg_attribute. |
43 | */ |
44 | #if SIZEOF_DATUM == 8 |
45 | |
46 | #define fetch_att(T,attbyval,attlen) \ |
47 | ( \ |
48 | (attbyval) ? \ |
49 | ( \ |
50 | (attlen) == (int) sizeof(Datum) ? \ |
51 | *((Datum *)(T)) \ |
52 | : \ |
53 | ( \ |
54 | (attlen) == (int) sizeof(int32) ? \ |
55 | Int32GetDatum(*((int32 *)(T))) \ |
56 | : \ |
57 | ( \ |
58 | (attlen) == (int) sizeof(int16) ? \ |
59 | Int16GetDatum(*((int16 *)(T))) \ |
60 | : \ |
61 | ( \ |
62 | AssertMacro((attlen) == 1), \ |
63 | CharGetDatum(*((char *)(T))) \ |
64 | ) \ |
65 | ) \ |
66 | ) \ |
67 | ) \ |
68 | : \ |
69 | PointerGetDatum((char *) (T)) \ |
70 | ) |
71 | #else /* SIZEOF_DATUM != 8 */ |
72 | |
73 | #define fetch_att(T,attbyval,attlen) \ |
74 | ( \ |
75 | (attbyval) ? \ |
76 | ( \ |
77 | (attlen) == (int) sizeof(int32) ? \ |
78 | Int32GetDatum(*((int32 *)(T))) \ |
79 | : \ |
80 | ( \ |
81 | (attlen) == (int) sizeof(int16) ? \ |
82 | Int16GetDatum(*((int16 *)(T))) \ |
83 | : \ |
84 | ( \ |
85 | AssertMacro((attlen) == 1), \ |
86 | CharGetDatum(*((char *)(T))) \ |
87 | ) \ |
88 | ) \ |
89 | ) \ |
90 | : \ |
91 | PointerGetDatum((char *) (T)) \ |
92 | ) |
93 | #endif /* SIZEOF_DATUM == 8 */ |
94 | |
95 | /* |
96 | * att_align_datum aligns the given offset as needed for a datum of alignment |
97 | * requirement attalign and typlen attlen. attdatum is the Datum variable |
98 | * we intend to pack into a tuple (it's only accessed if we are dealing with |
99 | * a varlena type). Note that this assumes the Datum will be stored as-is; |
100 | * callers that are intending to convert non-short varlena datums to short |
101 | * format have to account for that themselves. |
102 | */ |
103 | #define att_align_datum(cur_offset, attalign, attlen, attdatum) \ |
104 | ( \ |
105 | ((attlen) == -1 && VARATT_IS_SHORT(DatumGetPointer(attdatum))) ? \ |
106 | (uintptr_t) (cur_offset) : \ |
107 | att_align_nominal(cur_offset, attalign) \ |
108 | ) |
109 | |
110 | /* |
111 | * att_align_pointer performs the same calculation as att_align_datum, |
112 | * but is used when walking a tuple. attptr is the current actual data |
113 | * pointer; when accessing a varlena field we have to "peek" to see if we |
114 | * are looking at a pad byte or the first byte of a 1-byte-header datum. |
115 | * (A zero byte must be either a pad byte, or the first byte of a correctly |
116 | * aligned 4-byte length word; in either case we can align safely. A non-zero |
117 | * byte must be either a 1-byte length word, or the first byte of a correctly |
118 | * aligned 4-byte length word; in either case we need not align.) |
119 | * |
120 | * Note: some callers pass a "char *" pointer for cur_offset. This is |
121 | * a bit of a hack but should work all right as long as uintptr_t is the |
122 | * correct width. |
123 | */ |
124 | #define att_align_pointer(cur_offset, attalign, attlen, attptr) \ |
125 | ( \ |
126 | ((attlen) == -1 && VARATT_NOT_PAD_BYTE(attptr)) ? \ |
127 | (uintptr_t) (cur_offset) : \ |
128 | att_align_nominal(cur_offset, attalign) \ |
129 | ) |
130 | |
131 | /* |
132 | * att_align_nominal aligns the given offset as needed for a datum of alignment |
133 | * requirement attalign, ignoring any consideration of packed varlena datums. |
134 | * There are three main use cases for using this macro directly: |
135 | * * we know that the att in question is not varlena (attlen != -1); |
136 | * in this case it is cheaper than the above macros and just as good. |
137 | * * we need to estimate alignment padding cost abstractly, ie without |
138 | * reference to a real tuple. We must assume the worst case that |
139 | * all varlenas are aligned. |
140 | * * within arrays, we unconditionally align varlenas (XXX this should be |
141 | * revisited, probably). |
142 | * |
143 | * The attalign cases are tested in what is hopefully something like their |
144 | * frequency of occurrence. |
145 | */ |
146 | #define att_align_nominal(cur_offset, attalign) \ |
147 | ( \ |
148 | ((attalign) == 'i') ? INTALIGN(cur_offset) : \ |
149 | (((attalign) == 'c') ? (uintptr_t) (cur_offset) : \ |
150 | (((attalign) == 'd') ? DOUBLEALIGN(cur_offset) : \ |
151 | ( \ |
152 | AssertMacro((attalign) == 's'), \ |
153 | SHORTALIGN(cur_offset) \ |
154 | ))) \ |
155 | ) |
156 | |
157 | /* |
158 | * att_addlength_datum increments the given offset by the space needed for |
159 | * the given Datum variable. attdatum is only accessed if we are dealing |
160 | * with a variable-length attribute. |
161 | */ |
162 | #define att_addlength_datum(cur_offset, attlen, attdatum) \ |
163 | att_addlength_pointer(cur_offset, attlen, DatumGetPointer(attdatum)) |
164 | |
165 | /* |
166 | * att_addlength_pointer performs the same calculation as att_addlength_datum, |
167 | * but is used when walking a tuple --- attptr is the pointer to the field |
168 | * within the tuple. |
169 | * |
170 | * Note: some callers pass a "char *" pointer for cur_offset. This is |
171 | * actually perfectly OK, but probably should be cleaned up along with |
172 | * the same practice for att_align_pointer. |
173 | */ |
174 | #define att_addlength_pointer(cur_offset, attlen, attptr) \ |
175 | ( \ |
176 | ((attlen) > 0) ? \ |
177 | ( \ |
178 | (cur_offset) + (attlen) \ |
179 | ) \ |
180 | : (((attlen) == -1) ? \ |
181 | ( \ |
182 | (cur_offset) + VARSIZE_ANY(attptr) \ |
183 | ) \ |
184 | : \ |
185 | ( \ |
186 | AssertMacro((attlen) == -2), \ |
187 | (cur_offset) + (strlen((char *) (attptr)) + 1) \ |
188 | )) \ |
189 | ) |
190 | |
191 | /* |
192 | * store_att_byval is a partial inverse of fetch_att: store a given Datum |
193 | * value into a tuple data area at the specified address. However, it only |
194 | * handles the byval case, because in typical usage the caller needs to |
195 | * distinguish by-val and by-ref cases anyway, and so a do-it-all macro |
196 | * wouldn't be convenient. |
197 | */ |
198 | #if SIZEOF_DATUM == 8 |
199 | |
200 | #define store_att_byval(T,newdatum,attlen) \ |
201 | do { \ |
202 | switch (attlen) \ |
203 | { \ |
204 | case sizeof(char): \ |
205 | *(char *) (T) = DatumGetChar(newdatum); \ |
206 | break; \ |
207 | case sizeof(int16): \ |
208 | *(int16 *) (T) = DatumGetInt16(newdatum); \ |
209 | break; \ |
210 | case sizeof(int32): \ |
211 | *(int32 *) (T) = DatumGetInt32(newdatum); \ |
212 | break; \ |
213 | case sizeof(Datum): \ |
214 | *(Datum *) (T) = (newdatum); \ |
215 | break; \ |
216 | default: \ |
217 | elog(ERROR, "unsupported byval length: %d", \ |
218 | (int) (attlen)); \ |
219 | break; \ |
220 | } \ |
221 | } while (0) |
222 | #else /* SIZEOF_DATUM != 8 */ |
223 | |
224 | #define store_att_byval(T,newdatum,attlen) \ |
225 | do { \ |
226 | switch (attlen) \ |
227 | { \ |
228 | case sizeof(char): \ |
229 | *(char *) (T) = DatumGetChar(newdatum); \ |
230 | break; \ |
231 | case sizeof(int16): \ |
232 | *(int16 *) (T) = DatumGetInt16(newdatum); \ |
233 | break; \ |
234 | case sizeof(int32): \ |
235 | *(int32 *) (T) = DatumGetInt32(newdatum); \ |
236 | break; \ |
237 | default: \ |
238 | elog(ERROR, "unsupported byval length: %d", \ |
239 | (int) (attlen)); \ |
240 | break; \ |
241 | } \ |
242 | } while (0) |
243 | #endif /* SIZEOF_DATUM == 8 */ |
244 | |
245 | #endif |
246 | |