PostgreSQL Source Code  git master
tupmacs.h
Go to the documentation of this file.
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