Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * varatt.h
4 : : * variable-length datatypes (TOAST support)
5 : : *
6 : : *
7 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 : : * Portions Copyright (c) 1995, Regents of the University of California
9 : : *
10 : : * src/include/varatt.h
11 : : *
12 : : *-------------------------------------------------------------------------
13 : : */
14 : :
15 : : #ifndef VARATT_H
16 : : #define VARATT_H
17 : :
18 : : /*
19 : : * struct varatt_external is a traditional "TOAST pointer", that is, the
20 : : * information needed to fetch a Datum stored out-of-line in a TOAST table.
21 : : * The data is compressed if and only if the external size stored in
22 : : * va_extinfo is less than va_rawsize - VARHDRSZ.
23 : : *
24 : : * This struct must not contain any padding, because we sometimes compare
25 : : * these pointers using memcmp.
26 : : *
27 : : * Note that this information is stored unaligned within actual tuples, so
28 : : * you need to memcpy from the tuple into a local struct variable before
29 : : * you can look at these fields! (The reason we use memcmp is to avoid
30 : : * having to do that just to detect equality of two TOAST pointers...)
31 : : */
32 : : typedef struct varatt_external
33 : : {
34 : : int32 va_rawsize; /* Original data size (includes header) */
35 : : uint32 va_extinfo; /* External saved size (without header) and
36 : : * compression method */
37 : : Oid va_valueid; /* Unique ID of value within TOAST table */
38 : : Oid va_toastrelid; /* RelID of TOAST table containing it */
39 : : } varatt_external;
40 : :
41 : : /*
42 : : * These macros define the "saved size" portion of va_extinfo. Its remaining
43 : : * two high-order bits identify the compression method.
44 : : */
45 : : #define VARLENA_EXTSIZE_BITS 30
46 : : #define VARLENA_EXTSIZE_MASK ((1U << VARLENA_EXTSIZE_BITS) - 1)
47 : :
48 : : /*
49 : : * struct varatt_indirect is a "TOAST pointer" representing an out-of-line
50 : : * Datum that's stored in memory, not in an external toast relation.
51 : : * The creator of such a Datum is entirely responsible that the referenced
52 : : * storage survives for as long as referencing pointer Datums can exist.
53 : : *
54 : : * Note that just as for struct varatt_external, this struct is stored
55 : : * unaligned within any containing tuple.
56 : : */
57 : : typedef struct varatt_indirect
58 : : {
59 : : struct varlena *pointer; /* Pointer to in-memory varlena */
60 : : } varatt_indirect;
61 : :
62 : : /*
63 : : * struct varatt_expanded is a "TOAST pointer" representing an out-of-line
64 : : * Datum that is stored in memory, in some type-specific, not necessarily
65 : : * physically contiguous format that is convenient for computation not
66 : : * storage. APIs for this, in particular the definition of struct
67 : : * ExpandedObjectHeader, are in src/include/utils/expandeddatum.h.
68 : : *
69 : : * Note that just as for struct varatt_external, this struct is stored
70 : : * unaligned within any containing tuple.
71 : : */
72 : : typedef struct ExpandedObjectHeader ExpandedObjectHeader;
73 : :
74 : : typedef struct varatt_expanded
75 : : {
76 : : ExpandedObjectHeader *eohptr;
77 : : } varatt_expanded;
78 : :
79 : : /*
80 : : * Type tag for the various sorts of "TOAST pointer" datums. The peculiar
81 : : * value for VARTAG_ONDISK comes from a requirement for on-disk compatibility
82 : : * with a previous notion that the tag field was the pointer datum's length.
83 : : */
84 : : typedef enum vartag_external
85 : : {
86 : : VARTAG_INDIRECT = 1,
87 : : VARTAG_EXPANDED_RO = 2,
88 : : VARTAG_EXPANDED_RW = 3,
89 : : VARTAG_ONDISK = 18
90 : : } vartag_external;
91 : :
92 : : /* Is a TOAST pointer either type of expanded-object pointer? */
93 : : /* this test relies on the specific tag values above */
94 : : static inline bool
32 peter@eisentraut.org 95 :GNC 286969 : VARTAG_IS_EXPANDED(vartag_external tag)
96 : : {
97 : 286969 : return ((tag & ~1) == VARTAG_EXPANDED_RO);
98 : : }
99 : :
100 : : /* Size of the data part of a "TOAST pointer" datum */
101 : : static inline Size
102 : 149868 : VARTAG_SIZE(vartag_external tag)
103 : : {
104 [ + + ]: 149868 : if (tag == VARTAG_INDIRECT)
105 : 1007 : return sizeof(varatt_indirect);
106 [ - + ]: 148861 : else if (VARTAG_IS_EXPANDED(tag))
32 peter@eisentraut.org 107 :UNC 0 : return sizeof(varatt_expanded);
32 peter@eisentraut.org 108 [ + - ]:GNC 148861 : else if (tag == VARTAG_ONDISK)
109 : 148861 : return sizeof(varatt_external);
110 : : else
111 : : {
32 peter@eisentraut.org 112 :UNC 0 : Assert(false);
113 : : return 0;
114 : : }
115 : : }
116 : :
117 : : /*
118 : : * These structs describe the header of a varlena object that may have been
119 : : * TOASTed. Generally, don't reference these structs directly, but use the
120 : : * functions and macros below.
121 : : *
122 : : * We use separate structs for the aligned and unaligned cases because the
123 : : * compiler might otherwise think it could generate code that assumes
124 : : * alignment while touching fields of a 1-byte-header varlena.
125 : : */
126 : : typedef union
127 : : {
128 : : struct /* Normal varlena (4-byte length) */
129 : : {
130 : : uint32 va_header;
131 : : char va_data[FLEXIBLE_ARRAY_MEMBER];
132 : : } va_4byte;
133 : : struct /* Compressed-in-line format */
134 : : {
135 : : uint32 va_header;
136 : : uint32 va_tcinfo; /* Original data size (excludes header) and
137 : : * compression method; see va_extinfo */
138 : : char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Compressed data */
139 : : } va_compressed;
140 : : } varattrib_4b;
141 : :
142 : : typedef struct
143 : : {
144 : : uint8 va_header;
145 : : char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Data begins here */
146 : : } varattrib_1b;
147 : :
148 : : /* TOAST pointers are a subset of varattrib_1b with an identifying tag byte */
149 : : typedef struct
150 : : {
151 : : uint8 va_header; /* Always 0x80 or 0x01 */
152 : : uint8 va_tag; /* Type of datum */
153 : : char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Type-specific data */
154 : : } varattrib_1b_e;
155 : :
156 : : /*
157 : : * Bit layouts for varlena headers on big-endian machines:
158 : : *
159 : : * 00xxxxxx 4-byte length word, aligned, uncompressed data (up to 1G)
160 : : * 01xxxxxx 4-byte length word, aligned, *compressed* data (up to 1G)
161 : : * 10000000 1-byte length word, unaligned, TOAST pointer
162 : : * 1xxxxxxx 1-byte length word, unaligned, uncompressed data (up to 126b)
163 : : *
164 : : * Bit layouts for varlena headers on little-endian machines:
165 : : *
166 : : * xxxxxx00 4-byte length word, aligned, uncompressed data (up to 1G)
167 : : * xxxxxx10 4-byte length word, aligned, *compressed* data (up to 1G)
168 : : * 00000001 1-byte length word, unaligned, TOAST pointer
169 : : * xxxxxxx1 1-byte length word, unaligned, uncompressed data (up to 126b)
170 : : *
171 : : * The "xxx" bits are the length field (which includes itself in all cases).
172 : : * In the big-endian case we mask to extract the length, in the little-endian
173 : : * case we shift. Note that in both cases the flag bits are in the physically
174 : : * first byte. Also, it is not possible for a 1-byte length word to be zero;
175 : : * this lets us disambiguate alignment padding bytes from the start of an
176 : : * unaligned datum. (We now *require* pad bytes to be filled with zero!)
177 : : *
178 : : * In TOAST pointers the va_tag field (see varattrib_1b_e) is used to discern
179 : : * the specific type and length of the pointer datum.
180 : : */
181 : :
182 : : /*
183 : : * Endian-dependent macros. These are considered internal --- use the
184 : : * external functions below instead of using these directly. All of these
185 : : * expect an argument that is a pointer, not a Datum. Some of them have
186 : : * multiple-evaluation hazards, too.
187 : : *
188 : : * Note: IS_1B is true for external toast records but VARSIZE_1B will return 0
189 : : * for such records. Hence you should usually check for IS_EXTERNAL before
190 : : * checking for IS_1B.
191 : : */
192 : :
193 : : #ifdef WORDS_BIGENDIAN
194 : :
195 : : #define VARATT_IS_4B(PTR) \
196 : : ((((varattrib_1b *) (PTR))->va_header & 0x80) == 0x00)
197 : : #define VARATT_IS_4B_U(PTR) \
198 : : ((((varattrib_1b *) (PTR))->va_header & 0xC0) == 0x00)
199 : : #define VARATT_IS_4B_C(PTR) \
200 : : ((((varattrib_1b *) (PTR))->va_header & 0xC0) == 0x40)
201 : : #define VARATT_IS_1B(PTR) \
202 : : ((((varattrib_1b *) (PTR))->va_header & 0x80) == 0x80)
203 : : #define VARATT_IS_1B_E(PTR) \
204 : : ((((varattrib_1b *) (PTR))->va_header) == 0x80)
205 : : #define VARATT_NOT_PAD_BYTE(PTR) \
206 : : (*((uint8 *) (PTR)) != 0)
207 : :
208 : : /* VARSIZE_4B() should only be used on known-aligned data */
209 : : #define VARSIZE_4B(PTR) \
210 : : (((varattrib_4b *) (PTR))->va_4byte.va_header & 0x3FFFFFFF)
211 : : #define VARSIZE_1B(PTR) \
212 : : (((varattrib_1b *) (PTR))->va_header & 0x7F)
213 : : #define VARTAG_1B_E(PTR) \
214 : : ((vartag_external) ((varattrib_1b_e *) (PTR))->va_tag)
215 : :
216 : : #define SET_VARSIZE_4B(PTR,len) \
217 : : (((varattrib_4b *) (PTR))->va_4byte.va_header = (len) & 0x3FFFFFFF)
218 : : #define SET_VARSIZE_4B_C(PTR,len) \
219 : : (((varattrib_4b *) (PTR))->va_4byte.va_header = ((len) & 0x3FFFFFFF) | 0x40000000)
220 : : #define SET_VARSIZE_1B(PTR,len) \
221 : : (((varattrib_1b *) (PTR))->va_header = (len) | 0x80)
222 : : #define SET_VARTAG_1B_E(PTR,tag) \
223 : : (((varattrib_1b_e *) (PTR))->va_header = 0x80, \
224 : : ((varattrib_1b_e *) (PTR))->va_tag = (tag))
225 : :
226 : : #else /* !WORDS_BIGENDIAN */
227 : :
228 : : #define VARATT_IS_4B(PTR) \
229 : : ((((varattrib_1b *) (PTR))->va_header & 0x01) == 0x00)
230 : : #define VARATT_IS_4B_U(PTR) \
231 : : ((((varattrib_1b *) (PTR))->va_header & 0x03) == 0x00)
232 : : #define VARATT_IS_4B_C(PTR) \
233 : : ((((varattrib_1b *) (PTR))->va_header & 0x03) == 0x02)
234 : : #define VARATT_IS_1B(PTR) \
235 : : ((((varattrib_1b *) (PTR))->va_header & 0x01) == 0x01)
236 : : #define VARATT_IS_1B_E(PTR) \
237 : : ((((varattrib_1b *) (PTR))->va_header) == 0x01)
238 : : #define VARATT_NOT_PAD_BYTE(PTR) \
239 : : (*((uint8 *) (PTR)) != 0)
240 : :
241 : : /* VARSIZE_4B() should only be used on known-aligned data */
242 : : #define VARSIZE_4B(PTR) \
243 : : ((((varattrib_4b *) (PTR))->va_4byte.va_header >> 2) & 0x3FFFFFFF)
244 : : #define VARSIZE_1B(PTR) \
245 : : ((((varattrib_1b *) (PTR))->va_header >> 1) & 0x7F)
246 : : #define VARTAG_1B_E(PTR) \
247 : : ((vartag_external) ((varattrib_1b_e *) (PTR))->va_tag)
248 : :
249 : : #define SET_VARSIZE_4B(PTR,len) \
250 : : (((varattrib_4b *) (PTR))->va_4byte.va_header = (((uint32) (len)) << 2))
251 : : #define SET_VARSIZE_4B_C(PTR,len) \
252 : : (((varattrib_4b *) (PTR))->va_4byte.va_header = (((uint32) (len)) << 2) | 0x02)
253 : : #define SET_VARSIZE_1B(PTR,len) \
254 : : (((varattrib_1b *) (PTR))->va_header = (((uint8) (len)) << 1) | 0x01)
255 : : #define SET_VARTAG_1B_E(PTR,tag) \
256 : : (((varattrib_1b_e *) (PTR))->va_header = 0x01, \
257 : : ((varattrib_1b_e *) (PTR))->va_tag = (tag))
258 : :
259 : : #endif /* WORDS_BIGENDIAN */
260 : :
261 : : #define VARDATA_4B(PTR) (((varattrib_4b *) (PTR))->va_4byte.va_data)
262 : : #define VARDATA_4B_C(PTR) (((varattrib_4b *) (PTR))->va_compressed.va_data)
263 : : #define VARDATA_1B(PTR) (((varattrib_1b *) (PTR))->va_data)
264 : : #define VARDATA_1B_E(PTR) (((varattrib_1b_e *) (PTR))->va_data)
265 : :
266 : : /*
267 : : * Externally visible TOAST functions and macros begin here. All of these
268 : : * were originally macros, accounting for the upper-case naming.
269 : : *
270 : : * Most of these functions accept a pointer to a value of a toastable data
271 : : * type. The caller's variable might be declared "text *" or the like,
272 : : * so we use "void *" here. Callers that are working with a Datum variable
273 : : * must apply DatumGetPointer before calling these functions.
274 : : */
275 : :
276 : : #define VARHDRSZ_EXTERNAL offsetof(varattrib_1b_e, va_data)
277 : : #define VARHDRSZ_COMPRESSED offsetof(varattrib_4b, va_compressed.va_data)
278 : : #define VARHDRSZ_SHORT offsetof(varattrib_1b, va_data)
279 : : #define VARATT_SHORT_MAX 0x7F
280 : :
281 : : /*
282 : : * In consumers oblivious to data alignment, call PG_DETOAST_DATUM_PACKED(),
283 : : * VARDATA_ANY(), VARSIZE_ANY() and VARSIZE_ANY_EXHDR(). Elsewhere, call
284 : : * PG_DETOAST_DATUM(), VARDATA() and VARSIZE(). Directly fetching an int16,
285 : : * int32 or wider field in the struct representing the datum layout requires
286 : : * aligned data. memcpy() is alignment-oblivious, as are most operations on
287 : : * datatypes, such as text, whose layout struct contains only char fields.
288 : : *
289 : : * Code assembling a new datum should call VARDATA() and SET_VARSIZE().
290 : : * (Datums begin life untoasted.)
291 : : *
292 : : * Other functions here should usually be used only by tuple assembly/disassembly
293 : : * code and code that specifically wants to work with still-toasted Datums.
294 : : */
295 : :
296 : : /* Size of a known-not-toasted varlena datum, including header */
297 : : static inline Size
32 peter@eisentraut.org 298 :GNC 103158816 : VARSIZE(const void *PTR)
299 : : {
300 : 103158816 : return VARSIZE_4B(PTR);
301 : : }
302 : :
303 : : /* Start of data area of a known-not-toasted varlena datum */
304 : : static inline char *
305 : 53027029 : VARDATA(const void *PTR)
306 : : {
307 : 53027029 : return VARDATA_4B(PTR);
308 : : }
309 : :
310 : : /* Size of a known-short-header varlena datum, including header */
311 : : static inline Size
312 : 30926612 : VARSIZE_SHORT(const void *PTR)
313 : : {
314 : 30926612 : return VARSIZE_1B(PTR);
315 : : }
316 : :
317 : : /* Start of data area of a known-short-header varlena datum */
318 : : static inline char *
319 : 19986099 : VARDATA_SHORT(const void *PTR)
320 : : {
321 : 19986099 : return VARDATA_1B(PTR);
322 : : }
323 : :
324 : : /* Type tag of a "TOAST pointer" datum */
325 : : static inline vartag_external
326 : 394380 : VARTAG_EXTERNAL(const void *PTR)
327 : : {
328 : 394380 : return VARTAG_1B_E(PTR);
329 : : }
330 : :
331 : : /* Size of a "TOAST pointer" datum, including header */
332 : : static inline Size
333 : 149868 : VARSIZE_EXTERNAL(const void *PTR)
334 : : {
335 : 149868 : return VARHDRSZ_EXTERNAL + VARTAG_SIZE(VARTAG_EXTERNAL(PTR));
336 : : }
337 : :
338 : : /* Start of data area of a "TOAST pointer" datum */
339 : : static inline char *
340 : 172281 : VARDATA_EXTERNAL(const void *PTR)
341 : : {
342 : 172281 : return VARDATA_1B_E(PTR);
343 : : }
344 : :
345 : : /* Is varlena datum in inline-compressed format? */
346 : : static inline bool
347 : 148130227 : VARATT_IS_COMPRESSED(const void *PTR)
348 : : {
349 : 148130227 : return VARATT_IS_4B_C(PTR);
350 : : }
351 : :
352 : : /* Is varlena datum a "TOAST pointer" datum? */
353 : : static inline bool
354 : 257292425 : VARATT_IS_EXTERNAL(const void *PTR)
355 : : {
356 : 257292425 : return VARATT_IS_1B_E(PTR);
357 : : }
358 : :
359 : : /* Is varlena datum a pointer to on-disk toasted data? */
360 : : static inline bool
361 : 32293897 : VARATT_IS_EXTERNAL_ONDISK(const void *PTR)
362 : : {
363 [ + + + + ]: 32293897 : return VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) == VARTAG_ONDISK;
364 : : }
365 : :
366 : : /* Is varlena datum an indirect pointer? */
367 : : static inline bool
368 : 32036172 : VARATT_IS_EXTERNAL_INDIRECT(const void *PTR)
369 : : {
370 [ + + + + ]: 32036172 : return VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) == VARTAG_INDIRECT;
371 : : }
372 : :
373 : : /* Is varlena datum a read-only pointer to an expanded object? */
374 : : static inline bool
375 : 16875 : VARATT_IS_EXTERNAL_EXPANDED_RO(const void *PTR)
376 : : {
377 [ + + + - ]: 16875 : return VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) == VARTAG_EXPANDED_RO;
378 : : }
379 : :
380 : : /* Is varlena datum a read-write pointer to an expanded object? */
381 : : static inline bool
382 : 4604719 : VARATT_IS_EXTERNAL_EXPANDED_RW(const void *PTR)
383 : : {
384 [ + + + + ]: 4604719 : return VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) == VARTAG_EXPANDED_RW;
385 : : }
386 : :
387 : : /* Is varlena datum either type of pointer to an expanded object? */
388 : : static inline bool
389 : 52009875 : VARATT_IS_EXTERNAL_EXPANDED(const void *PTR)
390 : : {
391 [ + + + + ]: 52009875 : return VARATT_IS_EXTERNAL(PTR) && VARTAG_IS_EXPANDED(VARTAG_EXTERNAL(PTR));
392 : : }
393 : :
394 : : /* Is varlena datum a "TOAST pointer", but not for an expanded object? */
395 : : static inline bool
396 : 21782 : VARATT_IS_EXTERNAL_NON_EXPANDED(const void *PTR)
397 : : {
398 [ + + + + ]: 21782 : return VARATT_IS_EXTERNAL(PTR) && !VARTAG_IS_EXPANDED(VARTAG_EXTERNAL(PTR));
399 : : }
400 : :
401 : : /* Is varlena datum a short-header datum? */
402 : : static inline bool
403 : 55219688 : VARATT_IS_SHORT(const void *PTR)
404 : : {
405 : 55219688 : return VARATT_IS_1B(PTR);
406 : : }
407 : :
408 : : /* Is varlena datum not in traditional (4-byte-header, uncompressed) format? */
409 : : static inline bool
410 : 64998719 : VARATT_IS_EXTENDED(const void *PTR)
411 : : {
412 : 64998719 : return !VARATT_IS_4B_U(PTR);
413 : : }
414 : :
415 : : /* Is varlena datum short enough to convert to short-header format? */
416 : : static inline bool
417 : 31904348 : VARATT_CAN_MAKE_SHORT(const void *PTR)
418 : : {
419 [ + + ]: 60281884 : return VARATT_IS_4B_U(PTR) &&
420 [ + + ]: 28377536 : (VARSIZE(PTR) - VARHDRSZ + VARHDRSZ_SHORT) <= VARATT_SHORT_MAX;
421 : : }
422 : :
423 : : /* Size that datum will have in short-header format, including header */
424 : : static inline Size
425 : 27216367 : VARATT_CONVERTED_SHORT_SIZE(const void *PTR)
426 : : {
427 : 27216367 : return VARSIZE(PTR) - VARHDRSZ + VARHDRSZ_SHORT;
428 : : }
429 : :
430 : : /* Set the size (including header) of a 4-byte-header varlena datum */
431 : : static inline void
432 : 62543299 : SET_VARSIZE(void *PTR, Size len)
433 : : {
434 : 62543299 : SET_VARSIZE_4B(PTR, len);
435 : 62543299 : }
436 : :
437 : : /* Set the size (including header) of a short-header varlena datum */
438 : : static inline void
439 : 13523841 : SET_VARSIZE_SHORT(void *PTR, Size len)
440 : : {
441 : 13523841 : SET_VARSIZE_1B(PTR, len);
442 : 13523841 : }
443 : :
444 : : /* Set the size (including header) of an inline-compressed varlena datum */
445 : : static inline void
446 : 30568 : SET_VARSIZE_COMPRESSED(void *PTR, Size len)
447 : : {
448 : 30568 : SET_VARSIZE_4B_C(PTR, len);
449 : 30568 : }
450 : :
451 : : /* Set the type tag of a "TOAST pointer" datum */
452 : : static inline void
453 : 62392 : SET_VARTAG_EXTERNAL(void *PTR, vartag_external tag)
454 : : {
455 : 62392 : SET_VARTAG_1B_E(PTR, tag);
456 : 62392 : }
457 : :
458 : : /* Size of a varlena datum of any format, including header */
459 : : static inline Size
460 : 87537073 : VARSIZE_ANY(const void *PTR)
461 : : {
462 [ + + ]: 87537073 : if (VARATT_IS_1B_E(PTR))
463 : 82214 : return VARSIZE_EXTERNAL(PTR);
464 [ + + ]: 87454859 : else if (VARATT_IS_1B(PTR))
465 : 62836286 : return VARSIZE_1B(PTR);
466 : : else
467 : 24618573 : return VARSIZE_4B(PTR);
468 : : }
469 : :
470 : : /* Size of a varlena datum of any format, excluding header */
471 : : static inline Size
472 : 110777157 : VARSIZE_ANY_EXHDR(const void *PTR)
473 : : {
474 [ - + ]: 110777157 : if (VARATT_IS_1B_E(PTR))
32 peter@eisentraut.org 475 :UNC 0 : return VARSIZE_EXTERNAL(PTR) - VARHDRSZ_EXTERNAL;
32 peter@eisentraut.org 476 [ + + ]:GNC 110777157 : else if (VARATT_IS_1B(PTR))
477 : 11590046 : return VARSIZE_1B(PTR) - VARHDRSZ_SHORT;
478 : : else
479 : 99187111 : return VARSIZE_4B(PTR) - VARHDRSZ;
480 : : }
481 : :
482 : : /* Start of data area of a plain or short-header varlena datum */
483 : : /* caution: this will not work on an external or compressed-in-line Datum */
484 : : /* caution: this will return a possibly unaligned pointer */
485 : : static inline char *
486 : 115264629 : VARDATA_ANY(const void *PTR)
487 : : {
488 [ + + ]: 115264629 : return VARATT_IS_1B(PTR) ? VARDATA_1B(PTR) : VARDATA_4B(PTR);
489 : : }
490 : :
491 : : /* Decompressed size of a compressed-in-line varlena datum */
492 : : static inline Size
493 : 161049 : VARDATA_COMPRESSED_GET_EXTSIZE(const void *PTR)
494 : : {
495 : 161049 : return ((varattrib_4b *) PTR)->va_compressed.va_tcinfo & VARLENA_EXTSIZE_MASK;
496 : : }
497 : :
498 : : /* Compression method of a compressed-in-line varlena datum */
499 : : static inline uint32
500 : 10333 : VARDATA_COMPRESSED_GET_COMPRESS_METHOD(const void *PTR)
501 : : {
502 : 10333 : return ((varattrib_4b *) PTR)->va_compressed.va_tcinfo >> VARLENA_EXTSIZE_BITS;
503 : : }
504 : :
505 : : /* Same for external Datums; but note argument is a struct varatt_external */
506 : : static inline Size
507 : 66441 : VARATT_EXTERNAL_GET_EXTSIZE(struct varatt_external toast_pointer)
508 : : {
509 : 66441 : return toast_pointer.va_extinfo & VARLENA_EXTSIZE_MASK;
510 : : }
511 : :
512 : : static inline uint32
513 : 27 : VARATT_EXTERNAL_GET_COMPRESS_METHOD(struct varatt_external toast_pointer)
514 : : {
515 : 27 : return toast_pointer.va_extinfo >> VARLENA_EXTSIZE_BITS;
516 : : }
517 : :
518 : : /* Set size and compress method of an externally-stored varlena datum */
519 : : /* This has to remain a macro; beware multiple evaluations! */
520 : : #define VARATT_EXTERNAL_SET_SIZE_AND_COMPRESS_METHOD(toast_pointer, len, cm) \
521 : : do { \
522 : : Assert((cm) == TOAST_PGLZ_COMPRESSION_ID || \
523 : : (cm) == TOAST_LZ4_COMPRESSION_ID); \
524 : : ((toast_pointer).va_extinfo = \
525 : : (len) | ((uint32) (cm) << VARLENA_EXTSIZE_BITS)); \
526 : : } while (0)
527 : :
528 : : /*
529 : : * Testing whether an externally-stored value is compressed now requires
530 : : * comparing size stored in va_extinfo (the actual length of the external data)
531 : : * to rawsize (the original uncompressed datum's size). The latter includes
532 : : * VARHDRSZ overhead, the former doesn't. We never use compression unless it
533 : : * actually saves space, so we expect either equality or less-than.
534 : : */
535 : : static inline bool
536 : 43258 : VARATT_EXTERNAL_IS_COMPRESSED(struct varatt_external toast_pointer)
537 : : {
538 : 43258 : return VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer) <
539 : 43258 : (Size) (toast_pointer.va_rawsize - VARHDRSZ);
540 : : }
541 : :
542 : : #endif
|