1
/*-------------------------------------------------------------------------
4
* Tuple macros used by both index tuples and heap tuples.
7
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
8
* Portions Copyright (c) 1994, Regents of the University of California
12
*-------------------------------------------------------------------------
19
* check to see if the ATT'th bit of an array of 8-bit bytes is set.
21
#define att_isnull(ATT, BITS) (!((BITS)[(ATT) >> 3] & (1 << ((ATT) & 0x07))))
24
* Given a Form_pg_attribute and a pointer into a tuple's data area,
25
* return the correct value or pointer.
27
* We return a Datum value in all cases. If the attribute has "byval" false,
28
* we return the same pointer into the tuple data area that we're passed.
29
* Otherwise, we return the correct number of bytes fetched from the data
30
* area and extended to Datum form.
32
* On machines where Datum is 8 bytes, we support fetching 8-byte byval
33
* attributes; otherwise, only 1, 2, and 4-byte values are supported.
35
* Note that T must already be properly aligned for this to work correctly.
37
#define fetchatt(A,T) fetch_att(T, (A)->attbyval, (A)->attlen)
40
* Same, but work from byval/len parameters rather than Form_pg_attribute.
44
#define fetch_att(T,attbyval,attlen) \
48
(attlen) == (int) sizeof(Datum) ? \
52
(attlen) == (int) sizeof(int32) ? \
53
Int32GetDatum(*((int32 *)(T))) \
56
(attlen) == (int) sizeof(int16) ? \
57
Int16GetDatum(*((int16 *)(T))) \
60
AssertMacro((attlen) == 1), \
61
CharGetDatum(*((char *)(T))) \
67
PointerGetDatum((char *) (T)) \
69
#else /* SIZEOF_DATUM != 8 */
71
#define fetch_att(T,attbyval,attlen) \
75
(attlen) == (int) sizeof(int32) ? \
76
Int32GetDatum(*((int32 *)(T))) \
79
(attlen) == (int) sizeof(int16) ? \
80
Int16GetDatum(*((int16 *)(T))) \
83
AssertMacro((attlen) == 1), \
84
CharGetDatum(*((char *)(T))) \
89
PointerGetDatum((char *) (T)) \
91
#endif /* SIZEOF_DATUM == 8 */
94
* att_align_datum aligns the given offset as needed for a datum of alignment
95
* requirement attalign and typlen attlen. attdatum is the Datum variable
96
* we intend to pack into a tuple (it's only accessed if we are dealing with
97
* a varlena type). Note that this assumes the Datum will be stored as-is;
98
* callers that are intending to convert non-short varlena datums to short
99
* format have to account for that themselves.
101
#define att_align_datum(cur_offset, attalign, attlen, attdatum) \
103
((attlen) == -1 && VARATT_IS_SHORT(DatumGetPointer(attdatum))) ? (long) (cur_offset) : \
104
att_align_nominal(cur_offset, attalign) \
108
* att_align_pointer performs the same calculation as att_align_datum,
109
* but is used when walking a tuple. attptr is the current actual data
110
* pointer; when accessing a varlena field we have to "peek" to see if we
111
* are looking at a pad byte or the first byte of a 1-byte-header datum.
112
* (A zero byte must be either a pad byte, or the first byte of a correctly
113
* aligned 4-byte length word; in either case we can align safely. A non-zero
114
* byte must be either a 1-byte length word, or the first byte of a correctly
115
* aligned 4-byte length word; in either case we need not align.)
117
* Note: some callers pass a "char *" pointer for cur_offset. This is
118
* a bit of a hack but works OK on all known platforms. It ought to be
119
* cleaned up someday, though.
121
#define att_align_pointer(cur_offset, attalign, attlen, attptr) \
123
((attlen) == -1 && VARATT_NOT_PAD_BYTE(attptr)) ? (long) (cur_offset) : \
124
att_align_nominal(cur_offset, attalign) \
128
* att_align_nominal aligns the given offset as needed for a datum of alignment
129
* requirement attalign, ignoring any consideration of packed varlena datums.
130
* There are three main use cases for using this macro directly:
131
* * we know that the att in question is not varlena (attlen != -1);
132
* in this case it is cheaper than the above macros and just as good.
133
* * we need to estimate alignment padding cost abstractly, ie without
134
* reference to a real tuple. We must assume the worst case that
135
* all varlenas are aligned.
136
* * within arrays, we unconditionally align varlenas (XXX this should be
137
* revisited, probably).
139
* The attalign cases are tested in what is hopefully something like their
140
* frequency of occurrence.
142
#define att_align_nominal(cur_offset, attalign) \
144
((attalign) == 'i') ? INTALIGN(cur_offset) : \
145
(((attalign) == 'c') ? (long) (cur_offset) : \
146
(((attalign) == 'd') ? DOUBLEALIGN(cur_offset) : \
148
AssertMacro((attalign) == 's'), \
149
SHORTALIGN(cur_offset) \
154
* att_addlength_datum increments the given offset by the space needed for
155
* the given Datum variable. attdatum is only accessed if we are dealing
156
* with a variable-length attribute.
158
#define att_addlength_datum(cur_offset, attlen, attdatum) \
159
att_addlength_pointer(cur_offset, attlen, DatumGetPointer(attdatum))
162
* att_addlength_pointer performs the same calculation as att_addlength_datum,
163
* but is used when walking a tuple --- attptr is the pointer to the field
166
* Note: some callers pass a "char *" pointer for cur_offset. This is
167
* actually perfectly OK, but probably should be cleaned up along with
168
* the same practice for att_align_pointer.
170
#define att_addlength_pointer(cur_offset, attlen, attptr) \
174
(cur_offset) + (attlen) \
176
: (((attlen) == -1) ? \
178
(cur_offset) + VARSIZE_ANY(attptr) \
182
AssertMacro((attlen) == -2), \
183
(cur_offset) + (strlen((char *) (attptr)) + 1) \
188
* store_att_byval is a partial inverse of fetch_att: store a given Datum
189
* value into a tuple data area at the specified address. However, it only
190
* handles the byval case, because in typical usage the caller needs to
191
* distinguish by-val and by-ref cases anyway, and so a do-it-all macro
192
* wouldn't be convenient.
194
#if SIZEOF_DATUM == 8
196
#define store_att_byval(T,newdatum,attlen) \
201
*(char *) (T) = DatumGetChar(newdatum); \
203
case sizeof(int16): \
204
*(int16 *) (T) = DatumGetInt16(newdatum); \
206
case sizeof(int32): \
207
*(int32 *) (T) = DatumGetInt32(newdatum); \
209
case sizeof(Datum): \
210
*(Datum *) (T) = (newdatum); \
213
elog(ERROR, "unsupported byval length: %d", \
218
#else /* SIZEOF_DATUM != 8 */
220
#define store_att_byval(T,newdatum,attlen) \
225
*(char *) (T) = DatumGetChar(newdatum); \
227
case sizeof(int16): \
228
*(int16 *) (T) = DatumGetInt16(newdatum); \
230
case sizeof(int32): \
231
*(int32 *) (T) = DatumGetInt32(newdatum); \
234
elog(ERROR, "unsupported byval length: %d", \
239
#endif /* SIZEOF_DATUM == 8 */