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-2024, 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 #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 indicates
23  * non-null.
24  */
25 static inline bool
26 att_isnull(int ATT, const bits8 *BITS)
27 {
28  return !(BITS[ATT >> 3] & (1 << (ATT & 0x07)));
29 }
30 
31 #ifndef FRONTEND
32 /*
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 data
39  * area and extended to Datum form.
40  *
41  * On machines where Datum is 8 bytes, we support fetching 8-byte byval
42  * 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  */
51 static inline Datum
52 fetch_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 == 8
65  case sizeof(Datum):
66  return *((const Datum *) T);
67 #endif
68  default:
69  elog(ERROR, "unsupported byval length: %d", attlen);
70  return 0;
71  }
72  }
73  else
74  return PointerGetDatum(T);
75 }
76 #endif /* FRONTEND */
77 
78 /*
79  * att_align_datum aligns the given offset as needed for a datum of alignment
80  * requirement attalign and typlen attlen. attdatum is the Datum variable
81  * we intend to pack into a tuple (it's only accessed if we are dealing with
82  * 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 short
84  * 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 data
96  * pointer; when accessing a varlena field we have to "peek" to see if we
97  * 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 correctly
99  * aligned 4-byte length word; in either case we can align safely. A non-zero
100  * byte must be either a 1-byte length word, or the first byte of a correctly
101  * 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 is
104  * a bit of a hack but should work all right as long as uintptr_t is the
105  * 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 alignment
116  * 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 without
121  * reference to a real tuple. We must assume the worst case that
122  * all varlenas are aligned.
123  * * within arrays and multiranges, we unconditionally align varlenas (XXX this
124  * should be revisited, probably).
125  *
126  * The attalign cases are tested in what is hopefully something like their
127  * 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 for
142  * the given Datum variable. attdatum is only accessed if we are dealing
143  * 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 field
151  * within the tuple.
152  *
153  * Note: some callers pass a "char *" pointer for cur_offset. This is
154  * actually perfectly OK, but probably should be cleaned up along with
155  * 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 FRONTEND
175 /*
176  * store_att_byval is a partial inverse of fetch_att: store a given Datum
177  * value into a tuple data area at the specified address. However, it only
178  * handles the byval case, because in typical usage the caller needs to
179  * distinguish by-val and by-ref cases anyway, and so a do-it-all function
180  * wouldn't be convenient.
181  */
182 static inline void
183 store_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 == 8
197  case sizeof(Datum):
198  *(Datum *) T = newdatum;
199  break;
200 #endif
201  default:
202  elog(ERROR, "unsupported byval length: %d", attlen);
203  }
204 }
205 #endif /* FRONTEND */
206 
207 #endif /* TUPMACS_H */
signed short int16
Definition: c.h:480
signed int int32
Definition: c.h:481
uint8 bits8
Definition: c.h:500
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
static const uint32 T[65]
Definition: md5.c:119
bool attbyval
Definition: pg_attribute.h:103
int16 attlen
Definition: pg_attribute.h:59
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
static char DatumGetChar(Datum X)
Definition: postgres.h:112
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
static int16 DatumGetInt16(Datum X)
Definition: postgres.h:162
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:202
static Datum CharGetDatum(char X)
Definition: postgres.h:122
static bool att_isnull(int ATT, const bits8 *BITS)
Definition: tupmacs.h:26
static Datum fetch_att(const void *T, bool attbyval, int attlen)
Definition: tupmacs.h:52
static void store_att_byval(void *T, Datum newdatum, int attlen)
Definition: tupmacs.h:183