| 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 | |