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