Header And Logo

PostgreSQL
| The world's most advanced open source database.

tupmacs.h

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * tupmacs.h
00004  *    Tuple macros used by both index tuples and heap tuples.
00005  *
00006  *
00007  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00008  * Portions Copyright (c) 1994, Regents of the University of California
00009  *
00010  * src/include/access/tupmacs.h
00011  *
00012  *-------------------------------------------------------------------------
00013  */
00014 #ifndef TUPMACS_H
00015 #define TUPMACS_H
00016 
00017 
00018 /*
00019  * check to see if the ATT'th bit of an array of 8-bit bytes is set.
00020  */
00021 #define att_isnull(ATT, BITS) (!((BITS)[(ATT) >> 3] & (1 << ((ATT) & 0x07))))
00022 
00023 /*
00024  * Given a Form_pg_attribute and a pointer into a tuple's data area,
00025  * return the correct value or pointer.
00026  *
00027  * We return a Datum value in all cases.  If the attribute has "byval" false,
00028  * we return the same pointer into the tuple data area that we're passed.
00029  * Otherwise, we return the correct number of bytes fetched from the data
00030  * area and extended to Datum form.
00031  *
00032  * On machines where Datum is 8 bytes, we support fetching 8-byte byval
00033  * attributes; otherwise, only 1, 2, and 4-byte values are supported.
00034  *
00035  * Note that T must already be properly aligned for this to work correctly.
00036  */
00037 #define fetchatt(A,T) fetch_att(T, (A)->attbyval, (A)->attlen)
00038 
00039 /*
00040  * Same, but work from byval/len parameters rather than Form_pg_attribute.
00041  */
00042 #if SIZEOF_DATUM == 8
00043 
00044 #define fetch_att(T,attbyval,attlen) \
00045 ( \
00046     (attbyval) ? \
00047     ( \
00048         (attlen) == (int) sizeof(Datum) ? \
00049             *((Datum *)(T)) \
00050         : \
00051       ( \
00052         (attlen) == (int) sizeof(int32) ? \
00053             Int32GetDatum(*((int32 *)(T))) \
00054         : \
00055         ( \
00056             (attlen) == (int) sizeof(int16) ? \
00057                 Int16GetDatum(*((int16 *)(T))) \
00058             : \
00059             ( \
00060                 AssertMacro((attlen) == 1), \
00061                 CharGetDatum(*((char *)(T))) \
00062             ) \
00063         ) \
00064       ) \
00065     ) \
00066     : \
00067     PointerGetDatum((char *) (T)) \
00068 )
00069 #else                           /* SIZEOF_DATUM != 8 */
00070 
00071 #define fetch_att(T,attbyval,attlen) \
00072 ( \
00073     (attbyval) ? \
00074     ( \
00075         (attlen) == (int) sizeof(int32) ? \
00076             Int32GetDatum(*((int32 *)(T))) \
00077         : \
00078         ( \
00079             (attlen) == (int) sizeof(int16) ? \
00080                 Int16GetDatum(*((int16 *)(T))) \
00081             : \
00082             ( \
00083                 AssertMacro((attlen) == 1), \
00084                 CharGetDatum(*((char *)(T))) \
00085             ) \
00086         ) \
00087     ) \
00088     : \
00089     PointerGetDatum((char *) (T)) \
00090 )
00091 #endif   /* SIZEOF_DATUM == 8 */
00092 
00093 /*
00094  * att_align_datum aligns the given offset as needed for a datum of alignment
00095  * requirement attalign and typlen attlen.  attdatum is the Datum variable
00096  * we intend to pack into a tuple (it's only accessed if we are dealing with
00097  * a varlena type).  Note that this assumes the Datum will be stored as-is;
00098  * callers that are intending to convert non-short varlena datums to short
00099  * format have to account for that themselves.
00100  */
00101 #define att_align_datum(cur_offset, attalign, attlen, attdatum) \
00102 ( \
00103     ((attlen) == -1 && VARATT_IS_SHORT(DatumGetPointer(attdatum))) ? \
00104     (intptr_t) (cur_offset) : \
00105     att_align_nominal(cur_offset, attalign) \
00106 )
00107 
00108 /*
00109  * att_align_pointer performs the same calculation as att_align_datum,
00110  * but is used when walking a tuple.  attptr is the current actual data
00111  * pointer; when accessing a varlena field we have to "peek" to see if we
00112  * are looking at a pad byte or the first byte of a 1-byte-header datum.
00113  * (A zero byte must be either a pad byte, or the first byte of a correctly
00114  * aligned 4-byte length word; in either case we can align safely.  A non-zero
00115  * byte must be either a 1-byte length word, or the first byte of a correctly
00116  * aligned 4-byte length word; in either case we need not align.)
00117  *
00118  * Note: some callers pass a "char *" pointer for cur_offset.  This is
00119  * a bit of a hack but should work all right as long as intptr_t is the
00120  * correct width.
00121  */
00122 #define att_align_pointer(cur_offset, attalign, attlen, attptr) \
00123 ( \
00124     ((attlen) == -1 && VARATT_NOT_PAD_BYTE(attptr)) ? \
00125     (intptr_t) (cur_offset) : \
00126     att_align_nominal(cur_offset, attalign) \
00127 )
00128 
00129 /*
00130  * att_align_nominal aligns the given offset as needed for a datum of alignment
00131  * requirement attalign, ignoring any consideration of packed varlena datums.
00132  * There are three main use cases for using this macro directly:
00133  *  * we know that the att in question is not varlena (attlen != -1);
00134  *    in this case it is cheaper than the above macros and just as good.
00135  *  * we need to estimate alignment padding cost abstractly, ie without
00136  *    reference to a real tuple.  We must assume the worst case that
00137  *    all varlenas are aligned.
00138  *  * within arrays, we unconditionally align varlenas (XXX this should be
00139  *    revisited, probably).
00140  *
00141  * The attalign cases are tested in what is hopefully something like their
00142  * frequency of occurrence.
00143  */
00144 #define att_align_nominal(cur_offset, attalign) \
00145 ( \
00146     ((attalign) == 'i') ? INTALIGN(cur_offset) : \
00147      (((attalign) == 'c') ? (intptr_t) (cur_offset) : \
00148       (((attalign) == 'd') ? DOUBLEALIGN(cur_offset) : \
00149        ( \
00150             AssertMacro((attalign) == 's'), \
00151             SHORTALIGN(cur_offset) \
00152        ))) \
00153 )
00154 
00155 /*
00156  * att_addlength_datum increments the given offset by the space needed for
00157  * the given Datum variable.  attdatum is only accessed if we are dealing
00158  * with a variable-length attribute.
00159  */
00160 #define att_addlength_datum(cur_offset, attlen, attdatum) \
00161     att_addlength_pointer(cur_offset, attlen, DatumGetPointer(attdatum))
00162 
00163 /*
00164  * att_addlength_pointer performs the same calculation as att_addlength_datum,
00165  * but is used when walking a tuple --- attptr is the pointer to the field
00166  * within the tuple.
00167  *
00168  * Note: some callers pass a "char *" pointer for cur_offset.  This is
00169  * actually perfectly OK, but probably should be cleaned up along with
00170  * the same practice for att_align_pointer.
00171  */
00172 #define att_addlength_pointer(cur_offset, attlen, attptr) \
00173 ( \
00174     ((attlen) > 0) ? \
00175     ( \
00176         (cur_offset) + (attlen) \
00177     ) \
00178     : (((attlen) == -1) ? \
00179     ( \
00180         (cur_offset) + VARSIZE_ANY(attptr) \
00181     ) \
00182     : \
00183     ( \
00184         AssertMacro((attlen) == -2), \
00185         (cur_offset) + (strlen((char *) (attptr)) + 1) \
00186     )) \
00187 )
00188 
00189 /*
00190  * store_att_byval is a partial inverse of fetch_att: store a given Datum
00191  * value into a tuple data area at the specified address.  However, it only
00192  * handles the byval case, because in typical usage the caller needs to
00193  * distinguish by-val and by-ref cases anyway, and so a do-it-all macro
00194  * wouldn't be convenient.
00195  */
00196 #if SIZEOF_DATUM == 8
00197 
00198 #define store_att_byval(T,newdatum,attlen) \
00199     do { \
00200         switch (attlen) \
00201         { \
00202             case sizeof(char): \
00203                 *(char *) (T) = DatumGetChar(newdatum); \
00204                 break; \
00205             case sizeof(int16): \
00206                 *(int16 *) (T) = DatumGetInt16(newdatum); \
00207                 break; \
00208             case sizeof(int32): \
00209                 *(int32 *) (T) = DatumGetInt32(newdatum); \
00210                 break; \
00211             case sizeof(Datum): \
00212                 *(Datum *) (T) = (newdatum); \
00213                 break; \
00214             default: \
00215                 elog(ERROR, "unsupported byval length: %d", \
00216                      (int) (attlen)); \
00217                 break; \
00218         } \
00219     } while (0)
00220 #else                           /* SIZEOF_DATUM != 8 */
00221 
00222 #define store_att_byval(T,newdatum,attlen) \
00223     do { \
00224         switch (attlen) \
00225         { \
00226             case sizeof(char): \
00227                 *(char *) (T) = DatumGetChar(newdatum); \
00228                 break; \
00229             case sizeof(int16): \
00230                 *(int16 *) (T) = DatumGetInt16(newdatum); \
00231                 break; \
00232             case sizeof(int32): \
00233                 *(int32 *) (T) = DatumGetInt32(newdatum); \
00234                 break; \
00235             default: \
00236                 elog(ERROR, "unsupported byval length: %d", \
00237                      (int) (attlen)); \
00238                 break; \
00239         } \
00240     } while (0)
00241 #endif   /* SIZEOF_DATUM == 8 */
00242 
00243 #endif