codekingpro/portable-devtools
114k
1/*-------------------------------------------------------------------------2 *3 * tupmacs.h4 * Tuple macros used by both index tuples and heap tuples.5 *6 *7 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group8 * Portions Copyright (c) 1994, Regents of the University of California9 *10 * src/include/access/tupmacs.h11 *12 *-------------------------------------------------------------------------13 */14#ifndef TUPMACS_H15#define TUPMACS_H16 17#include "catalog/pg_type_d.h" /* for TYPALIGN macros */18 19 20/*21 * Check a tuple's null bitmap to determine whether the attribute is null.22 * Note that a 0 in the null bitmap indicates a null, while 1 indicates23 * non-null.24 */25static inline bool26att_isnull(int ATT, const bits8 *BITS)27{28 return !(BITS[ATT >> 3] & (1 << (ATT & 0x07)));29}30 31#ifndef FRONTEND32/*33 * Given a Form_pg_attribute and a pointer into a tuple's data area,34 * return the correct value or pointer.35 *36 * We return a Datum value in all cases. If the attribute has "byval" false,37 * we return the same pointer into the tuple data area that we're passed.38 * Otherwise, we return the correct number of bytes fetched from the data39 * area and extended to Datum form.40 *41 * On machines where Datum is 8 bytes, we support fetching 8-byte byval42 * attributes; otherwise, only 1, 2, and 4-byte values are supported.43 *44 * Note that T must already be properly aligned for this to work correctly.45 */46#define fetchatt(A,T) fetch_att(T, (A)->attbyval, (A)->attlen)47 48/*49 * Same, but work from byval/len parameters rather than Form_pg_attribute.50 */51static inline Datum52fetch_att(const void *T, bool attbyval, int attlen)53{54 if (attbyval)55 {56 switch (attlen)57 {58 case sizeof(char):59 return CharGetDatum(*((const char *) T));60 case sizeof(int16):61 return Int16GetDatum(*((const int16 *) T));62 case sizeof(int32):63 return Int32GetDatum(*((const int32 *) T));64#if SIZEOF_DATUM == 865 case sizeof(Datum):66 return *((const Datum *) T);67#endif68 default:69 elog(ERROR, "unsupported byval length: %d", attlen);70 return 0;71 }72 }73 else74 return PointerGetDatum(T);75}76#endif /* FRONTEND */77 78/*79 * att_align_datum aligns the given offset as needed for a datum of alignment80 * requirement attalign and typlen attlen. attdatum is the Datum variable81 * we intend to pack into a tuple (it's only accessed if we are dealing with82 * a varlena type). Note that this assumes the Datum will be stored as-is;83 * callers that are intending to convert non-short varlena datums to short84 * format have to account for that themselves.85 */86#define att_align_datum(cur_offset, attalign, attlen, attdatum) \87( \88 ((attlen) == -1 && VARATT_IS_SHORT(DatumGetPointer(attdatum))) ? \89 (uintptr_t) (cur_offset) : \90 att_align_nominal(cur_offset, attalign) \91)92 93/*94 * att_align_pointer performs the same calculation as att_align_datum,95 * but is used when walking a tuple. attptr is the current actual data96 * pointer; when accessing a varlena field we have to "peek" to see if we97 * are looking at a pad byte or the first byte of a 1-byte-header datum.98 * (A zero byte must be either a pad byte, or the first byte of a correctly99 * aligned 4-byte length word; in either case we can align safely. A non-zero100 * byte must be either a 1-byte length word, or the first byte of a correctly101 * aligned 4-byte length word; in either case we need not align.)102 *103 * Note: some callers pass a "char *" pointer for cur_offset. This is104 * a bit of a hack but should work all right as long as uintptr_t is the105 * correct width.106 */107#define att_align_pointer(cur_offset, attalign, attlen, attptr) \108( \109 ((attlen) == -1 && VARATT_NOT_PAD_BYTE(attptr)) ? \110 (uintptr_t) (cur_offset) : \111 att_align_nominal(cur_offset, attalign) \112)113 114/*115 * att_align_nominal aligns the given offset as needed for a datum of alignment116 * requirement attalign, ignoring any consideration of packed varlena datums.117 * There are three main use cases for using this macro directly:118 * * we know that the att in question is not varlena (attlen != -1);119 * in this case it is cheaper than the above macros and just as good.120 * * we need to estimate alignment padding cost abstractly, ie without121 * reference to a real tuple. We must assume the worst case that122 * all varlenas are aligned.123 * * within arrays and multiranges, we unconditionally align varlenas (XXX this124 * should be revisited, probably).125 *126 * The attalign cases are tested in what is hopefully something like their127 * frequency of occurrence.128 */129#define att_align_nominal(cur_offset, attalign) \130( \131 ((attalign) == TYPALIGN_INT) ? INTALIGN(cur_offset) : \132 (((attalign) == TYPALIGN_CHAR) ? (uintptr_t) (cur_offset) : \133 (((attalign) == TYPALIGN_DOUBLE) ? DOUBLEALIGN(cur_offset) : \134 ( \135 AssertMacro((attalign) == TYPALIGN_SHORT), \136 SHORTALIGN(cur_offset) \137 ))) \138)139 140/*141 * att_addlength_datum increments the given offset by the space needed for142 * the given Datum variable. attdatum is only accessed if we are dealing143 * with a variable-length attribute.144 */145#define att_addlength_datum(cur_offset, attlen, attdatum) \146 att_addlength_pointer(cur_offset, attlen, DatumGetPointer(attdatum))147 148/*149 * att_addlength_pointer performs the same calculation as att_addlength_datum,150 * but is used when walking a tuple --- attptr is the pointer to the field151 * within the tuple.152 *153 * Note: some callers pass a "char *" pointer for cur_offset. This is154 * actually perfectly OK, but probably should be cleaned up along with155 * the same practice for att_align_pointer.156 */157#define att_addlength_pointer(cur_offset, attlen, attptr) \158( \159 ((attlen) > 0) ? \160 ( \161 (cur_offset) + (attlen) \162 ) \163 : (((attlen) == -1) ? \164 ( \165 (cur_offset) + VARSIZE_ANY(attptr) \166 ) \167 : \168 ( \169 AssertMacro((attlen) == -2), \170 (cur_offset) + (strlen((char *) (attptr)) + 1) \171 )) \172)173 174#ifndef FRONTEND175/*176 * store_att_byval is a partial inverse of fetch_att: store a given Datum177 * value into a tuple data area at the specified address. However, it only178 * handles the byval case, because in typical usage the caller needs to179 * distinguish by-val and by-ref cases anyway, and so a do-it-all function180 * wouldn't be convenient.181 */182static inline void183store_att_byval(void *T, Datum newdatum, int attlen)184{185 switch (attlen)186 {187 case sizeof(char):188 *(char *) T = DatumGetChar(newdatum);189 break;190 case sizeof(int16):191 *(int16 *) T = DatumGetInt16(newdatum);192 break;193 case sizeof(int32):194 *(int32 *) T = DatumGetInt32(newdatum);195 break;196#if SIZEOF_DATUM == 8197 case sizeof(Datum):198 *(Datum *) T = newdatum;199 break;200#endif201 default:202 elog(ERROR, "unsupported byval length: %d", attlen);203 }204}205#endif /* FRONTEND */206 207#endif /* TUPMACS_H */208 