PostgreSQL Source Code git master
Loading...
Searching...
No Matches
heaptuple.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * heaptuple.c
4 * This file contains heap tuple accessor and mutator routines, as well
5 * as various tuple utilities.
6 *
7 * Some notes about varlenas and this code:
8 *
9 * Before Postgres 8.3 varlenas always had a 4-byte length header, and
10 * therefore always needed 4-byte alignment (at least). This wasted space
11 * for short varlenas, for example CHAR(1) took 5 bytes and could need up to
12 * 3 additional padding bytes for alignment.
13 *
14 * Now, a short varlena (up to 126 data bytes) is reduced to a 1-byte header
15 * and we don't align it. To hide this from datatype-specific functions that
16 * don't want to deal with it, such a datum is considered "toasted" and will
17 * be expanded back to the normal 4-byte-header format by pg_detoast_datum.
18 * (In performance-critical code paths we can use pg_detoast_datum_packed
19 * and the appropriate access macros to avoid that overhead.) Note that this
20 * conversion is performed directly in heap_form_tuple, without invoking
21 * heaptoast.c.
22 *
23 * This change will break any code that assumes it needn't detoast values
24 * that have been put into a tuple but never sent to disk. Hopefully there
25 * are few such places.
26 *
27 * Varlenas still have alignment INT (or DOUBLE) in pg_type/pg_attribute, since
28 * that's the normal requirement for the untoasted format. But we ignore that
29 * for the 1-byte-header format. This means that the actual start position
30 * of a varlena datum may vary depending on which format it has. To determine
31 * what is stored, we have to require that alignment padding bytes be zero.
32 * (Postgres actually has always zeroed them, but now it's required!) Since
33 * the first byte of a 1-byte-header varlena can never be zero, we can examine
34 * the first byte after the previous datum to tell if it's a pad byte or the
35 * start of a 1-byte-header varlena.
36 *
37 * Note that while formerly we could rely on the first varlena column of a
38 * system catalog to be at the offset suggested by the C struct for the
39 * catalog, this is now risky: it's only safe if the preceding field is
40 * word-aligned, so that there will never be any padding.
41 *
42 * We don't pack varlenas whose attstorage is PLAIN, since the data type
43 * isn't expecting to have to detoast values. This is used in particular
44 * by oidvector and int2vector, which are used in the system catalogs
45 * and we'd like to still refer to them via C struct offsets.
46 *
47 *
48 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
49 * Portions Copyright (c) 1994, Regents of the University of California
50 *
51 *
52 * IDENTIFICATION
53 * src/backend/access/common/heaptuple.c
54 *
55 *-------------------------------------------------------------------------
56 */
57
58#include "postgres.h"
59
60#include "access/heaptoast.h"
61#include "access/sysattr.h"
63#include "common/hashfn.h"
64#include "utils/datum.h"
65#include "utils/expandeddatum.h"
66#include "utils/hsearch.h"
67#include "utils/memutils.h"
68
69
70/*
71 * Does att's datatype allow packing into the 1-byte-header varlena format?
72 * While functions that use TupleDescAttr() and assign attstorage =
73 * TYPSTORAGE_PLAIN cannot use packed varlena headers, functions that call
74 * TupleDescInitEntry() use typeForm->typstorage (TYPSTORAGE_EXTENDED) and
75 * can use packed varlena headers, e.g.:
76 * CREATE TABLE test(a VARCHAR(10000) STORAGE PLAIN);
77 * INSERT INTO test VALUES (repeat('A',10));
78 * This can be verified with pageinspect.
79 */
80#define ATT_IS_PACKABLE(att) \
81 ((att)->attlen == -1 && (att)->attstorage != TYPSTORAGE_PLAIN)
82/* Use this if it's already known varlena */
83#define VARLENA_ATT_IS_PACKABLE(att) \
84 ((att)->attstorage != TYPSTORAGE_PLAIN)
85
86/* FormData_pg_attribute.attstorage != TYPSTORAGE_PLAIN and an attlen of -1 */
87#define COMPACT_ATTR_IS_PACKABLE(att) \
88 ((att)->attlen == -1 && (att)->attispackable)
89
90/*
91 * Setup for caching pass-by-ref missing attributes in a way that survives
92 * tupleDesc destruction.
93 */
94
95typedef struct
96{
97 int len;
100
102
103static uint32
104missing_hash(const void *key, Size keysize)
105{
106 const missing_cache_key *entry = key;
107
108 return hash_bytes((const unsigned char *) DatumGetPointer(entry->value), entry->len);
109}
110
111static int
112missing_match(const void *key1, const void *key2, Size keysize)
113{
114 const missing_cache_key *entry1 = key1;
116
117 if (entry1->len != entry2->len)
118 return entry1->len > entry2->len ? 1 : -1;
119
120 return memcmp(DatumGetPointer(entry1->value),
121 DatumGetPointer(entry2->value),
122 entry1->len);
123}
124
125static void
127{
129
131 hash_ctl.entrysize = sizeof(missing_cache_key);
133 hash_ctl.hash = missing_hash;
134 hash_ctl.match = missing_match;
136 hash_create("Missing Values Cache",
137 32,
138 &hash_ctl,
140}
141
142/* ----------------------------------------------------------------
143 * misc support routines
144 * ----------------------------------------------------------------
145 */
146
147/*
148 * Return the missing value of an attribute, or NULL if there isn't one.
149 */
150Datum
152 int attnum, bool *isnull)
153{
155
157 Assert(attnum > 0);
158
160
161 if (att->atthasmissing)
162 {
164
165 Assert(tupleDesc->constr);
166 Assert(tupleDesc->constr->missing);
167
168 attrmiss = tupleDesc->constr->missing + (attnum - 1);
169
170 if (attrmiss->am_present)
171 {
173 missing_cache_key *entry;
174 bool found;
176
177 *isnull = false;
178
179 /* no need to cache by-value attributes */
180 if (att->attbyval)
181 return attrmiss->am_value;
182
183 /* set up cache if required */
184 if (missing_cache == NULL)
186
187 /* check if there's a cache entry */
188 Assert(att->attlen > 0 || att->attlen == -1);
189 if (att->attlen > 0)
190 key.len = att->attlen;
191 else
192 key.len = VARSIZE_ANY(DatumGetPointer(attrmiss->am_value));
193 key.value = attrmiss->am_value;
194
195 entry = hash_search(missing_cache, &key, HASH_ENTER, &found);
196
197 if (!found)
198 {
199 /* cache miss, so we need a non-transient copy of the datum */
201 entry->value =
202 datumCopy(attrmiss->am_value, false, att->attlen);
204 }
205
206 return entry->value;
207 }
208 }
209
210 *isnull = true;
211 return PointerGetDatum(NULL);
212}
213
214/*
215 * heap_compute_data_size
216 * Determine size of the data area of a tuple to be constructed
217 */
218Size
220 const Datum *values,
221 const bool *isnull)
222{
223 Size data_length = 0;
224 int i;
225 int numberOfAttributes = tupleDesc->natts;
226
227 for (i = 0; i < numberOfAttributes; i++)
228 {
229 Datum val;
231
232 if (isnull[i])
233 continue;
234
235 val = values[i];
237
240 {
241 /*
242 * we're anticipating converting to a short varlena header, so
243 * adjust length and don't count any alignment
244 */
246 }
247 else if (atti->attlen == -1 &&
249 {
250 /*
251 * we want to flatten the expanded value so that the constructed
252 * tuple doesn't depend on it
253 */
254 data_length = att_nominal_alignby(data_length, atti->attalignby);
255 data_length += EOH_get_flat_size(DatumGetEOHP(val));
256 }
257 else
258 {
259 data_length = att_datum_alignby(data_length, atti->attalignby,
260 atti->attlen, val);
261 data_length = att_addlength_datum(data_length, atti->attlen,
262 val);
263 }
264 }
265
266 return data_length;
267}
268
269/*
270 * Per-attribute helper for heap_fill_tuple and other routines building tuples.
271 *
272 * Fill in either a data value or a bit in the null bitmask
273 */
274static inline void
276 bits8 **bit,
277 int *bitmask,
278 char **dataP,
280 Datum datum,
281 bool isnull)
282{
283 Size data_length;
284 char *data = *dataP;
285
286 /*
287 * If we're building a null bitmap, set the appropriate bit for the
288 * current column value here.
289 */
290 if (bit != NULL)
291 {
292 if (*bitmask != HIGHBIT)
293 *bitmask <<= 1;
294 else
295 {
296 *bit += 1;
297 **bit = 0x0;
298 *bitmask = 1;
299 }
300
301 if (isnull)
302 {
304 return;
305 }
306
307 **bit |= *bitmask;
308 }
309
310 /*
311 * XXX we use the att_nominal_alignby macro on the pointer value itself,
312 * not on an offset. This is a bit of a hack.
313 */
314 if (att->attbyval)
315 {
316 /* pass-by-value */
317 data = (char *) att_nominal_alignby(data, att->attalignby);
318 store_att_byval(data, datum, att->attlen);
319 data_length = att->attlen;
320 }
321 else if (att->attlen == -1)
322 {
323 /* varlena */
324 Pointer val = DatumGetPointer(datum);
325
328 {
330 {
331 /*
332 * we want to flatten the expanded value so that the
333 * constructed tuple doesn't depend on it
334 */
336
337 data = (char *) att_nominal_alignby(data, att->attalignby);
338 data_length = EOH_get_flat_size(eoh);
339 EOH_flatten_into(eoh, data, data_length);
340 }
341 else
342 {
344 /* no alignment, since it's short by definition */
345 data_length = VARSIZE_EXTERNAL(val);
346 memcpy(data, val, data_length);
347 }
348 }
349 else if (VARATT_IS_SHORT(val))
350 {
351 /* no alignment for short varlenas */
352 data_length = VARSIZE_SHORT(val);
353 memcpy(data, val, data_length);
354 }
355 else if (att->attispackable && VARATT_CAN_MAKE_SHORT(val))
356 {
357 /* convert to short varlena -- no alignment */
358 data_length = VARATT_CONVERTED_SHORT_SIZE(val);
359 SET_VARSIZE_SHORT(data, data_length);
360 memcpy(data + 1, VARDATA(val), data_length - 1);
361 }
362 else
363 {
364 /* full 4-byte header varlena */
365 data = (char *) att_nominal_alignby(data, att->attalignby);
366 data_length = VARSIZE(val);
367 memcpy(data, val, data_length);
368 }
369 }
370 else if (att->attlen == -2)
371 {
372 /* cstring ... never needs alignment */
374 Assert(att->attalignby == sizeof(char));
375 data_length = strlen(DatumGetCString(datum)) + 1;
376 memcpy(data, DatumGetPointer(datum), data_length);
377 }
378 else
379 {
380 /* fixed-length pass-by-reference */
381 data = (char *) att_nominal_alignby(data, att->attalignby);
382 Assert(att->attlen > 0);
383 data_length = att->attlen;
384 memcpy(data, DatumGetPointer(datum), data_length);
385 }
386
387 data += data_length;
388 *dataP = data;
389}
390
391/*
392 * heap_fill_tuple
393 * Load data portion of a tuple from values/isnull arrays
394 *
395 * We also fill the null bitmap (if any) and set the infomask bits
396 * that reflect the tuple's data contents.
397 *
398 * NOTE: it is now REQUIRED that the caller have pre-zeroed the data area.
399 */
400void
402 const Datum *values, const bool *isnull,
403 char *data, Size data_size,
405{
406 bits8 *bitP;
407 int bitmask;
408 int i;
409 int numberOfAttributes = tupleDesc->natts;
410
411#ifdef USE_ASSERT_CHECKING
412 char *start = data;
413#endif
414
415 if (bit != NULL)
416 {
417 bitP = &bit[-1];
418 bitmask = HIGHBIT;
419 }
420 else
421 {
422 /* just to keep compiler quiet */
423 bitP = NULL;
424 bitmask = 0;
425 }
426
428
429 for (i = 0; i < numberOfAttributes; i++)
430 {
432
433 fill_val(attr,
434 bitP ? &bitP : NULL,
435 &bitmask,
436 &data,
437 infomask,
439 isnull ? isnull[i] : true);
440 }
441
442 Assert((data - start) == data_size);
443}
444
445
446/* ----------------------------------------------------------------
447 * heap tuple interface
448 * ----------------------------------------------------------------
449 */
450
451/* ----------------
452 * heap_attisnull - returns true iff tuple attribute is not present
453 * ----------------
454 */
455bool
457{
458 /*
459 * We allow a NULL tupledesc for relations not expected to have missing
460 * values, such as catalog relations and indexes.
461 */
463 if (attnum > (int) HeapTupleHeaderGetNatts(tup->t_data))
464 {
465 if (tupleDesc &&
466 TupleDescCompactAttr(tupleDesc, attnum - 1)->atthasmissing)
467 return false;
468 else
469 return true;
470 }
471
472 if (attnum > 0)
473 {
475 return false;
476 return att_isnull(attnum - 1, tup->t_data->t_bits);
477 }
478
479 switch (attnum)
480 {
487 /* these are never null */
488 break;
489
490 default:
491 elog(ERROR, "invalid attnum: %d", attnum);
492 }
493
494 return false;
495}
496
497/* ----------------
498 * nocachegetattr
499 *
500 * This only gets called from fastgetattr(), in cases where we
501 * can't use the attcacheoff and the value is not null.
502 *
503 * NOTE: if you need to change this code, see also heap_deform_tuple.
504 * Also see nocache_index_getattr, which is the same code for index
505 * tuples.
506 * ----------------
507 */
508Datum
510 int attnum,
512{
514 HeapTupleHeader td = tup->t_data;
515 char *tp; /* ptr to data part of tuple */
516 bits8 *bp = td->t_bits; /* ptr to null bitmap in tuple */
517 int off; /* current offset within data */
518 int startAttr;
519 int firstNullAttr;
520 int i;
522
523 /* Did someone forget to call TupleDescFinalize()? */
524 Assert(tupleDesc->firstNonCachedOffsetAttr >= 0);
525
526 attnum--;
527
528 /*
529 * To minimize the number of attributes we need to look at, start walking
530 * the tuple at the attribute with the highest attcacheoff prior to attnum
531 * or the first NULL attribute prior to attnum, whichever comes first.
532 */
533 if (hasnulls)
535 else
537
538 if (tupleDesc->firstNonCachedOffsetAttr > 0 && firstNullAttr > 0)
539 {
540 /*
541 * Try to start with the highest attribute with an attcacheoff that's
542 * prior to the one we're looking for, or with the attribute prior to
543 * the first NULL attribute, if there is one.
544 */
545 startAttr = Min(tupleDesc->firstNonCachedOffsetAttr - 1, firstNullAttr - 1);
547 }
548 else
549 {
550 /* Otherwise, start at the beginning... */
551 startAttr = 0;
552 off = 0;
553 }
554
555 tp = (char *) td + td->t_hoff;
556
557 /*
558 * Calculate 'off' up to the first NULL attr. We use two cheaper loops
559 * when the tuple has no variable-width columns. When variable-width
560 * columns exists, we use att_addlength_pointer() to move the offset
561 * beyond the current attribute.
562 */
564 {
565 for (i = startAttr; i < firstNullAttr; i++)
566 {
568
569 off = att_nominal_alignby(off, cattr->attalignby);
570 off += cattr->attlen;
571 }
572
573 for (; i < attnum; i++)
574 {
575 if (att_isnull(i, bp))
576 continue;
577
579
580 off = att_nominal_alignby(off, cattr->attalignby);
581 off += cattr->attlen;
582 }
583 }
584 else
585 {
586 for (i = startAttr; i < firstNullAttr; i++)
587 {
588 int attlen;
589
591 attlen = cattr->attlen;
592
593 /*
594 * cstrings don't exist in heap tuples. Use pg_assume to instruct
595 * the compiler not to emit the cstring-related code in
596 * att_addlength_pointer().
597 */
598 pg_assume(attlen > 0 || attlen == -1);
599
600 off = att_pointer_alignby(off,
601 cattr->attalignby,
602 attlen,
603 tp + off);
604 off = att_addlength_pointer(off, attlen, tp + off);
605 }
606
607 for (; i < attnum; i++)
608 {
609 int attlen;
610
611 if (att_isnull(i, bp))
612 continue;
613
615 attlen = cattr->attlen;
616
617 /* As above, heaptuples have no cstrings */
618 pg_assume(attlen > 0 || attlen == -1);
619
620 off = att_pointer_alignby(off, cattr->attalignby, attlen,
621 tp + off);
622 off = att_addlength_pointer(off, attlen, tp + off);
623 }
624 }
625
627 off = att_pointer_alignby(off,
628 cattr->attalignby,
629 cattr->attlen,
630 tp + off);
631
632 return fetchatt(cattr, tp + off);
633}
634
635/* ----------------
636 * heap_getsysattr
637 *
638 * Fetch the value of a system attribute for a tuple.
639 *
640 * This is a support routine for heap_getattr(). The function has already
641 * determined that the attnum refers to a system attribute.
642 * ----------------
643 */
644Datum
646{
647 Datum result;
648
649 Assert(tup);
650
651 /* Currently, no sys attribute ever reads as NULL. */
652 *isnull = false;
653
654 switch (attnum)
655 {
657 /* pass-by-reference datatype */
658 result = PointerGetDatum(&(tup->t_self));
659 break;
662 break;
665 break;
668
669 /*
670 * cmin and cmax are now both aliases for the same field, which
671 * can in fact also be a combo command id. XXX perhaps we should
672 * return the "real" cmin or cmax if possible, that is if we are
673 * inside the originating transaction?
674 */
676 break;
678 result = ObjectIdGetDatum(tup->t_tableOid);
679 break;
680 default:
681 elog(ERROR, "invalid attnum: %d", attnum);
682 result = 0; /* keep compiler quiet */
683 break;
684 }
685 return result;
686}
687
688/* ----------------
689 * heap_copytuple
690 *
691 * returns a copy of an entire tuple
692 *
693 * The HeapTuple struct, tuple header, and tuple data are all allocated
694 * as a single palloc() block.
695 * ----------------
696 */
699{
701
702 if (!HeapTupleIsValid(tuple) || tuple->t_data == NULL)
703 return NULL;
704
706 newTuple->t_len = tuple->t_len;
707 newTuple->t_self = tuple->t_self;
708 newTuple->t_tableOid = tuple->t_tableOid;
709 newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
710 memcpy(newTuple->t_data, tuple->t_data, tuple->t_len);
711 return newTuple;
712}
713
714/* ----------------
715 * heap_copytuple_with_tuple
716 *
717 * copy a tuple into a caller-supplied HeapTuple management struct
718 *
719 * Note that after calling this function, the "dest" HeapTuple will not be
720 * allocated as a single palloc() block (unlike with heap_copytuple()).
721 * ----------------
722 */
723void
725{
726 if (!HeapTupleIsValid(src) || src->t_data == NULL)
727 {
728 dest->t_data = NULL;
729 return;
730 }
731
732 dest->t_len = src->t_len;
733 dest->t_self = src->t_self;
734 dest->t_tableOid = src->t_tableOid;
735 dest->t_data = (HeapTupleHeader) palloc(src->t_len);
736 memcpy(dest->t_data, src->t_data, src->t_len);
737}
738
739/*
740 * Expand a tuple which has fewer attributes than required. For each attribute
741 * not present in the sourceTuple, if there is a missing value that will be
742 * used. Otherwise the attribute will be set to NULL.
743 *
744 * The source tuple must have fewer attributes than the required number.
745 *
746 * Only one of targetHeapTuple and targetMinimalTuple may be supplied. The
747 * other argument must be NULL.
748 */
749static void
754{
756 int attnum;
757 int firstmissingnum;
762 int natts = tupleDesc->natts;
763 int sourceNullLen;
764 int targetNullLen;
765 Size sourceDataLen = sourceTuple->t_len - sourceTHeader->t_hoff;
767 Size len;
768 int hoff;
770 int bitMask = 0;
771 char *targetData;
773
776
777 Assert(sourceNatts < natts);
778
780
782
783 if (tupleDesc->constr &&
784 tupleDesc->constr->missing)
785 {
786 /*
787 * If there are missing values we want to put them into the tuple.
788 * Before that we have to compute the extra length for the values
789 * array and the variable length data.
790 */
791 attrmiss = tupleDesc->constr->missing;
792
793 /*
794 * Find the first item in attrmiss for which we don't have a value in
795 * the source. We can ignore all the missing entries before that.
796 */
798 firstmissingnum < natts;
800 {
801 if (attrmiss[firstmissingnum].am_present)
802 break;
803 else
804 hasNulls = true;
805 }
806
807 /*
808 * Now walk the missing attributes. If there is a missing value make
809 * space for it. Otherwise, it's going to be NULL.
810 */
811 for (attnum = firstmissingnum;
812 attnum < natts;
813 attnum++)
814 {
815 if (attrmiss[attnum].am_present)
816 {
818
820 att->attalignby,
821 att->attlen,
822 attrmiss[attnum].am_value);
823
825 att->attlen,
826 attrmiss[attnum].am_value);
827 }
828 else
829 {
830 /* no missing value, so it must be null */
831 hasNulls = true;
832 }
833 }
834 } /* end if have missing values */
835 else
836 {
837 /*
838 * If there are no missing values at all then NULLS must be allowed,
839 * since some of the attributes are known to be absent.
840 */
841 hasNulls = true;
842 }
843
844 len = 0;
845
846 if (hasNulls)
847 {
848 targetNullLen = BITMAPLEN(natts);
850 }
851 else
852 targetNullLen = 0;
853
854 /*
855 * Allocate and zero the space needed. Note that the tuple body and
856 * HeapTupleData management structure are allocated in one chunk.
857 */
858 if (targetHeapTuple)
859 {
860 len += offsetof(HeapTupleHeaderData, t_bits);
861 hoff = len = MAXALIGN(len); /* align user data safely */
863
865 (*targetHeapTuple)->t_data
868 (*targetHeapTuple)->t_len = len;
869 (*targetHeapTuple)->t_tableOid = sourceTuple->t_tableOid;
870 (*targetHeapTuple)->t_self = sourceTuple->t_self;
871
872 targetTHeader->t_infomask = sourceTHeader->t_infomask;
873 targetTHeader->t_hoff = hoff;
878 /* We also make sure that t_ctid is invalid unless explicitly set */
880 if (targetNullLen > 0)
881 nullBits = (bits8 *) ((char *) (*targetHeapTuple)->t_data
882 + offsetof(HeapTupleHeaderData, t_bits));
883 targetData = (char *) (*targetHeapTuple)->t_data + hoff;
884 infoMask = &(targetTHeader->t_infomask);
885 }
886 else
887 {
889 hoff = len = MAXALIGN(len); /* align user data safely */
891
893 (*targetMinimalTuple)->t_len = len;
894 (*targetMinimalTuple)->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
895 (*targetMinimalTuple)->t_infomask = sourceTHeader->t_infomask;
896 /* Same macro works for MinimalTuples */
898 if (targetNullLen > 0)
899 nullBits = (bits8 *) ((char *) *targetMinimalTuple
900 + offsetof(MinimalTupleData, t_bits));
901 targetData = (char *) *targetMinimalTuple + hoff;
902 infoMask = &((*targetMinimalTuple)->t_infomask);
903 }
904
905 if (targetNullLen > 0)
906 {
907 if (sourceNullLen > 0)
908 {
909 /* if bitmap pre-existed copy in - all is set */
911 ((char *) sourceTHeader)
912 + offsetof(HeapTupleHeaderData, t_bits),
914 nullBits += sourceNullLen - 1;
915 }
916 else
917 {
919 /* Set NOT NULL for all existing attributes */
921
922 nullBits += sourceNullLen - 1;
923
924 if (sourceNatts & 0x07)
925 {
926 /* build the mask (inverted!) */
927 bitMask = 0xff << (sourceNatts & 0x07);
928 /* Voila */
930 }
931 }
932
933 bitMask = (1 << ((sourceNatts - 1) & 0x07));
934 } /* End if have null bitmap */
935
937 ((char *) sourceTuple->t_data) + sourceTHeader->t_hoff,
939
941
942 /* Now fill in the missing values */
943 for (attnum = sourceNatts; attnum < natts; attnum++)
944 {
946
947 if (attrmiss && attrmiss[attnum].am_present)
948 {
949 fill_val(attr,
951 &bitMask,
952 &targetData,
953 infoMask,
954 attrmiss[attnum].am_value,
955 false);
956 }
957 else
958 {
959 fill_val(attr,
960 &nullBits,
961 &bitMask,
962 &targetData,
963 infoMask,
964 (Datum) 0,
965 true);
966 }
967 } /* end loop over missing attributes */
968}
969
970/*
971 * Fill in the missing values for a minimal HeapTuple
972 */
981
982/*
983 * Fill in the missing values for an ordinary HeapTuple
984 */
993
994/* ----------------
995 * heap_copy_tuple_as_datum
996 *
997 * copy a tuple as a composite-type Datum
998 * ----------------
999 */
1000Datum
1002{
1003 HeapTupleHeader td;
1004
1005 /*
1006 * If the tuple contains any external TOAST pointers, we have to inline
1007 * those fields to meet the conventions for composite-type Datums.
1008 */
1009 if (HeapTupleHasExternal(tuple))
1011 tuple->t_len,
1012 tupleDesc);
1013
1014 /*
1015 * Fast path for easy case: just make a palloc'd copy and insert the
1016 * correct composite-Datum header fields (since those may not be set if
1017 * the given tuple came from disk, rather than from heap_form_tuple).
1018 */
1019 td = (HeapTupleHeader) palloc(tuple->t_len);
1020 memcpy(td, tuple->t_data, tuple->t_len);
1021
1023 HeapTupleHeaderSetTypeId(td, tupleDesc->tdtypeid);
1024 HeapTupleHeaderSetTypMod(td, tupleDesc->tdtypmod);
1025
1026 return PointerGetDatum(td);
1027}
1028
1029/*
1030 * heap_form_tuple
1031 * construct a tuple from the given values[] and isnull[] arrays,
1032 * which are of the length indicated by tupleDescriptor->natts
1033 *
1034 * The result is allocated in the current memory context.
1035 */
1038 const Datum *values,
1039 const bool *isnull)
1040{
1041 HeapTuple tuple; /* return tuple */
1042 HeapTupleHeader td; /* tuple data */
1043 Size len,
1044 data_len;
1045 int hoff;
1046 bool hasnull = false;
1048 int i;
1049
1051 ereport(ERROR,
1053 errmsg("number of columns (%d) exceeds limit (%d)",
1055
1056 /*
1057 * Check for nulls
1058 */
1059 for (i = 0; i < numberOfAttributes; i++)
1060 {
1061 if (isnull[i])
1062 {
1063 hasnull = true;
1064 break;
1065 }
1066 }
1067
1068 /*
1069 * Determine total space needed
1070 */
1071 len = offsetof(HeapTupleHeaderData, t_bits);
1072
1073 if (hasnull)
1075
1076 hoff = len = MAXALIGN(len); /* align user data safely */
1077
1078 data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
1079
1080 len += data_len;
1081
1082 /*
1083 * Allocate and zero the space needed. Note that the tuple body and
1084 * HeapTupleData management structure are allocated in one chunk.
1085 */
1086 tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
1087 tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
1088
1089 /*
1090 * And fill in the information. Note we fill the Datum fields even though
1091 * this tuple may never become a Datum. This lets HeapTupleHeaderGetDatum
1092 * identify the tuple type if needed.
1093 */
1094 tuple->t_len = len;
1095 ItemPointerSetInvalid(&(tuple->t_self));
1096 tuple->t_tableOid = InvalidOid;
1097
1101 /* We also make sure that t_ctid is invalid unless explicitly set */
1103
1105 td->t_hoff = hoff;
1106
1108 values,
1109 isnull,
1110 (char *) td + hoff,
1111 data_len,
1112 &td->t_infomask,
1113 (hasnull ? td->t_bits : NULL));
1114
1115 return tuple;
1116}
1117
1118/*
1119 * heap_modify_tuple
1120 * form a new tuple from an old tuple and a set of replacement values.
1121 *
1122 * The replValues, replIsnull, and doReplace arrays must be of the length
1123 * indicated by tupleDesc->natts. The new tuple is constructed using the data
1124 * from replValues/replIsnull at columns where doReplace is true, and using
1125 * the data from the old tuple at columns where doReplace is false.
1126 *
1127 * The result is allocated in the current memory context.
1128 */
1132 const Datum *replValues,
1133 const bool *replIsnull,
1134 const bool *doReplace)
1135{
1136 int numberOfAttributes = tupleDesc->natts;
1137 int attoff;
1138 Datum *values;
1139 bool *isnull;
1141
1142 /*
1143 * allocate and fill values and isnull arrays from either the tuple or the
1144 * repl information, as appropriate.
1145 *
1146 * NOTE: it's debatable whether to use heap_deform_tuple() here or just
1147 * heap_getattr() only the non-replaced columns. The latter could win if
1148 * there are many replaced columns and few non-replaced ones. However,
1149 * heap_deform_tuple costs only O(N) while the heap_getattr way would cost
1150 * O(N^2) if there are many non-replaced columns, so it seems better to
1151 * err on the side of linear cost.
1152 */
1154 isnull = palloc_array(bool, numberOfAttributes);
1155
1156 heap_deform_tuple(tuple, tupleDesc, values, isnull);
1157
1158 for (attoff = 0; attoff < numberOfAttributes; attoff++)
1159 {
1160 if (doReplace[attoff])
1161 {
1163 isnull[attoff] = replIsnull[attoff];
1164 }
1165 }
1166
1167 /*
1168 * create a new tuple from the values and isnull arrays
1169 */
1171
1172 pfree(values);
1173 pfree(isnull);
1174
1175 /*
1176 * copy the identification info of the old tuple: t_ctid, t_self
1177 */
1178 newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
1179 newTuple->t_self = tuple->t_self;
1180 newTuple->t_tableOid = tuple->t_tableOid;
1181
1182 return newTuple;
1183}
1184
1185/*
1186 * heap_modify_tuple_by_cols
1187 * form a new tuple from an old tuple and a set of replacement values.
1188 *
1189 * This is like heap_modify_tuple, except that instead of specifying which
1190 * column(s) to replace by a boolean map, an array of target column numbers
1191 * is used. This is often more convenient when a fixed number of columns
1192 * are to be replaced. The replCols, replValues, and replIsnull arrays must
1193 * be of length nCols. Target column numbers are indexed from 1.
1194 *
1195 * The result is allocated in the current memory context.
1196 */
1200 int nCols,
1201 const int *replCols,
1202 const Datum *replValues,
1203 const bool *replIsnull)
1204{
1205 int numberOfAttributes = tupleDesc->natts;
1206 Datum *values;
1207 bool *isnull;
1209 int i;
1210
1211 /*
1212 * allocate and fill values and isnull arrays from the tuple, then replace
1213 * selected columns from the input arrays.
1214 */
1216 isnull = palloc_array(bool, numberOfAttributes);
1217
1218 heap_deform_tuple(tuple, tupleDesc, values, isnull);
1219
1220 for (i = 0; i < nCols; i++)
1221 {
1222 int attnum = replCols[i];
1223
1225 elog(ERROR, "invalid column number %d", attnum);
1226 values[attnum - 1] = replValues[i];
1227 isnull[attnum - 1] = replIsnull[i];
1228 }
1229
1230 /*
1231 * create a new tuple from the values and isnull arrays
1232 */
1234
1235 pfree(values);
1236 pfree(isnull);
1237
1238 /*
1239 * copy the identification info of the old tuple: t_ctid, t_self
1240 */
1241 newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
1242 newTuple->t_self = tuple->t_self;
1243 newTuple->t_tableOid = tuple->t_tableOid;
1244
1245 return newTuple;
1246}
1247
1248/*
1249 * heap_deform_tuple
1250 * Given a tuple, extract data into values/isnull arrays; this is
1251 * the inverse of heap_form_tuple.
1252 *
1253 * Storage for the values/isnull arrays is provided by the caller;
1254 * it should be sized according to tupleDesc->natts not
1255 * HeapTupleHeaderGetNatts(tuple->t_data).
1256 *
1257 * Note that for pass-by-reference datatypes, the pointer placed
1258 * in the Datum will point into the given tuple.
1259 *
1260 * When all or most of a tuple's fields need to be extracted,
1261 * this routine will be significantly quicker than a loop around
1262 * heap_getattr; the loop will become O(N^2) as soon as any
1263 * noncacheable attribute offsets are involved.
1264 */
1265void
1267 Datum *values, bool *isnull)
1268{
1269 HeapTupleHeader tup = tuple->t_data;
1271 bool hasnulls = HeapTupleHasNulls(tuple);
1272 int tdesc_natts = tupleDesc->natts;
1273 int natts; /* number of atts to extract */
1274 int attnum;
1275 char *tp; /* ptr to tuple data */
1276 uint32 off; /* offset in tuple data */
1277 bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
1279 int firstNullAttr;
1280
1282
1283 /* Did someone forget to call TupleDescFinalize()? */
1284 Assert(tupleDesc->firstNonCachedOffsetAttr >= 0);
1285
1286 /*
1287 * In inheritance situations, it is possible that the given tuple actually
1288 * has more fields than the caller is expecting. Don't run off the end of
1289 * the caller's arrays.
1290 */
1291 natts = Min(natts, tdesc_natts);
1292 firstNonCacheOffsetAttr = Min(tupleDesc->firstNonCachedOffsetAttr, natts);
1293
1294 if (hasnulls)
1295 {
1297
1298 /*
1299 * XXX: it'd be nice to use populate_isnull_array() here, but that
1300 * requires that the isnull array's size is rounded up to the next
1301 * multiple of 8. Doing that would require adjusting many locations
1302 * that allocate the array.
1303 */
1305 }
1306 else
1307 firstNullAttr = natts;
1308
1309 tp = (char *) tup + tup->t_hoff;
1310 attnum = 0;
1311
1313 {
1314#ifdef USE_ASSERT_CHECKING
1315 /* In Assert enabled builds, verify attcacheoff is correct */
1316 int offcheck = 0;
1317#endif
1318 do
1319 {
1320 isnull[attnum] = false;
1322 off = cattr->attcacheoff;
1323
1324#ifdef USE_ASSERT_CHECKING
1326 Assert(offcheck == cattr->attcacheoff);
1327 offcheck += cattr->attlen;
1328#endif
1329
1330 values[attnum] = fetch_att_noerr(tp + off,
1331 cattr->attbyval,
1332 cattr->attlen);
1333 } while (++attnum < firstNonCacheOffsetAttr);
1334 off += cattr->attlen;
1335 }
1336 else
1337 off = 0;
1338
1339 for (; attnum < firstNullAttr; attnum++)
1340 {
1341 isnull[attnum] = false;
1344 &off,
1345 cattr->attbyval,
1346 cattr->attlen,
1347 cattr->attalignby);
1348 }
1349
1350 for (; attnum < natts; attnum++)
1351 {
1353
1354 if (att_isnull(attnum, bp))
1355 {
1356 values[attnum] = (Datum) 0;
1357 isnull[attnum] = true;
1358 continue;
1359 }
1360
1361 isnull[attnum] = false;
1363
1364 /* align 'off', fetch the attr's value, and increment off beyond it */
1366 &off,
1367 cattr->attbyval,
1368 cattr->attlen,
1369 cattr->attalignby);
1370 }
1371
1372 /*
1373 * If tuple doesn't have all the atts indicated by tupleDesc, read the
1374 * rest as nulls or missing values as appropriate.
1375 */
1376 for (; attnum < tdesc_natts; attnum++)
1378}
1379
1380/*
1381 * heap_freetuple
1382 */
1383void
1385{
1386 pfree(htup);
1387}
1388
1389
1390/*
1391 * heap_form_minimal_tuple
1392 * construct a MinimalTuple from the given values[] and isnull[] arrays,
1393 * which are of the length indicated by tupleDescriptor->natts
1394 *
1395 * This is exactly like heap_form_tuple() except that the result is a
1396 * "minimal" tuple lacking a HeapTupleData header as well as room for system
1397 * columns.
1398 *
1399 * The result is allocated in the current memory context.
1400 */
1403 const Datum *values,
1404 const bool *isnull,
1405 Size extra)
1406{
1407 MinimalTuple tuple; /* return tuple */
1408 char *mem;
1409 Size len,
1410 data_len;
1411 int hoff;
1412 bool hasnull = false;
1414 int i;
1415
1416 Assert(extra == MAXALIGN(extra));
1417
1419 ereport(ERROR,
1421 errmsg("number of columns (%d) exceeds limit (%d)",
1423
1424 /*
1425 * Check for nulls
1426 */
1427 for (i = 0; i < numberOfAttributes; i++)
1428 {
1429 if (isnull[i])
1430 {
1431 hasnull = true;
1432 break;
1433 }
1434 }
1435
1436 /*
1437 * Determine total space needed
1438 */
1440
1441 if (hasnull)
1443
1444 hoff = len = MAXALIGN(len); /* align user data safely */
1445
1446 data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
1447
1448 len += data_len;
1449
1450 /*
1451 * Allocate and zero the space needed.
1452 */
1453 mem = palloc0(len + extra);
1454 tuple = (MinimalTuple) (mem + extra);
1455
1456 /*
1457 * And fill in the information.
1458 */
1459 tuple->t_len = len;
1461 tuple->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
1462
1464 values,
1465 isnull,
1466 (char *) tuple + hoff,
1467 data_len,
1468 &tuple->t_infomask,
1469 (hasnull ? tuple->t_bits : NULL));
1470
1471 return tuple;
1472}
1473
1474/*
1475 * heap_free_minimal_tuple
1476 */
1477void
1482
1483/*
1484 * heap_copy_minimal_tuple
1485 * copy a MinimalTuple
1486 *
1487 * The result is allocated in the current memory context.
1488 */
1491{
1492 MinimalTuple result;
1493 char *mem;
1494
1495 Assert(extra == MAXALIGN(extra));
1496 mem = palloc(mtup->t_len + extra);
1497 memset(mem, 0, extra);
1498 result = (MinimalTuple) (mem + extra);
1499 memcpy(result, mtup, mtup->t_len);
1500 return result;
1501}
1502
1503/*
1504 * heap_tuple_from_minimal_tuple
1505 * create a HeapTuple by copying from a MinimalTuple;
1506 * system columns are filled with zeroes
1507 *
1508 * The result is allocated in the current memory context.
1509 * The HeapTuple struct, tuple header, and tuple data are all allocated
1510 * as a single palloc() block.
1511 */
1514{
1515 HeapTuple result;
1517
1518 result = (HeapTuple) palloc(HEAPTUPLESIZE + len);
1519 result->t_len = len;
1520 ItemPointerSetInvalid(&(result->t_self));
1521 result->t_tableOid = InvalidOid;
1522 result->t_data = (HeapTupleHeader) ((char *) result + HEAPTUPLESIZE);
1523 memcpy((char *) result->t_data + MINIMAL_TUPLE_OFFSET, mtup, mtup->t_len);
1524 memset(result->t_data, 0, offsetof(HeapTupleHeaderData, t_infomask2));
1525 return result;
1526}
1527
1528/*
1529 * minimal_tuple_from_heap_tuple
1530 * create a MinimalTuple by copying from a HeapTuple
1531 *
1532 * The result is allocated in the current memory context.
1533 */
1536{
1537 MinimalTuple result;
1538 char *mem;
1539 uint32 len;
1540
1541 Assert(extra == MAXALIGN(extra));
1543 len = htup->t_len - MINIMAL_TUPLE_OFFSET;
1544 mem = palloc(len + extra);
1545 memset(mem, 0, extra);
1546 result = (MinimalTuple) (mem + extra);
1547 memcpy(result, (char *) htup->t_data + MINIMAL_TUPLE_OFFSET, len);
1548
1549 result->t_len = len;
1550 return result;
1551}
1552
1553/*
1554 * This mainly exists so JIT can inline the definition, but it's also
1555 * sometimes useful in debugging sessions.
1556 */
1557size_t
1559{
1560 return VARSIZE_ANY(p);
1561}
static Datum values[MAXATTR]
Definition bootstrap.c:188
#define Min(x, y)
Definition c.h:1093
#define MAXALIGN(LEN)
Definition c.h:898
#define Assert(condition)
Definition c.h:945
uint8 bits8
Definition c.h:625
uint16_t uint16
Definition c.h:617
#define pg_assume(expr)
Definition c.h:417
uint32_t uint32
Definition c.h:618
void * Pointer
Definition c.h:609
#define HIGHBIT
Definition c.h:1245
size_t Size
Definition c.h:691
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition datum.c:132
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:358
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
ExpandedObjectHeader * DatumGetEOHP(Datum d)
void EOH_flatten_into(ExpandedObjectHeader *eohptr, void *result, Size allocated_size)
Size EOH_get_flat_size(ExpandedObjectHeader *eohptr)
#define palloc_array(type, count)
Definition fe_memutils.h:76
uint32 hash_bytes(const unsigned char *k, int keylen)
Definition hashfn.c:146
return str start
Datum toast_flatten_tuple_to_datum(HeapTupleHeader tup, uint32 tup_len, TupleDesc tupleDesc)
Definition heaptoast.c:449
Size heap_compute_data_size(TupleDesc tupleDesc, const Datum *values, const bool *isnull)
Definition heaptuple.c:219
static uint32 missing_hash(const void *key, Size keysize)
Definition heaptuple.c:104
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1130
void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest)
Definition heaptuple.c:724
HeapTuple heap_copytuple(HeapTuple tuple)
Definition heaptuple.c:698
size_t varsize_any(void *p)
Definition heaptuple.c:1558
MinimalTuple heap_copy_minimal_tuple(MinimalTuple mtup, Size extra)
Definition heaptuple.c:1490
Datum heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition heaptuple.c:645
MinimalTuple heap_form_minimal_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull, Size extra)
Definition heaptuple.c:1402
HeapTuple heap_modify_tuple_by_cols(HeapTuple tuple, TupleDesc tupleDesc, int nCols, const int *replCols, const Datum *replValues, const bool *replIsnull)
Definition heaptuple.c:1198
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1037
void heap_free_minimal_tuple(MinimalTuple mtup)
Definition heaptuple.c:1478
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition heaptuple.c:456
Datum nocachegetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition heaptuple.c:509
Datum getmissingattr(TupleDesc tupleDesc, int attnum, bool *isnull)
Definition heaptuple.c:151
MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup, Size extra)
Definition heaptuple.c:1535
HeapTuple heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
Definition heaptuple.c:986
static void fill_val(CompactAttribute *att, bits8 **bit, int *bitmask, char **dataP, uint16 *infomask, Datum datum, bool isnull)
Definition heaptuple.c:275
void heap_fill_tuple(TupleDesc tupleDesc, const Datum *values, const bool *isnull, char *data, Size data_size, uint16 *infomask, bits8 *bit)
Definition heaptuple.c:401
#define COMPACT_ATTR_IS_PACKABLE(att)
Definition heaptuple.c:87
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition heaptuple.c:1266
static void init_missing_cache(void)
Definition heaptuple.c:126
static int missing_match(const void *key1, const void *key2, Size keysize)
Definition heaptuple.c:112
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition heaptuple.c:1001
static HTAB * missing_cache
Definition heaptuple.c:101
static void expand_tuple(HeapTuple *targetHeapTuple, MinimalTuple *targetMinimalTuple, HeapTuple sourceTuple, TupleDesc tupleDesc)
Definition heaptuple.c:750
HeapTuple heap_tuple_from_minimal_tuple(MinimalTuple mtup)
Definition heaptuple.c:1513
MinimalTuple minimal_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
Definition heaptuple.c:974
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1384
@ HASH_ENTER
Definition hsearch.h:114
#define HASH_CONTEXT
Definition hsearch.h:102
#define HASH_ELEM
Definition hsearch.h:95
#define HASH_COMPARE
Definition hsearch.h:99
#define HASH_FUNCTION
Definition hsearch.h:98
#define HEAPTUPLESIZE
Definition htup.h:73
HeapTupleData * HeapTuple
Definition htup.h:71
MinimalTupleData * MinimalTuple
Definition htup.h:27
HeapTupleHeaderData * HeapTupleHeader
Definition htup.h:23
#define HeapTupleIsValid(tuple)
Definition htup.h:78
#define HEAP_HASVARWIDTH
#define MINIMAL_TUPLE_OFFSET
#define HeapTupleHeaderGetNatts(tup)
static void HeapTupleHeaderSetTypMod(HeapTupleHeaderData *tup, int32 typmod)
static bool HeapTupleHasNulls(const HeapTupleData *tuple)
#define HEAP_HASNULL
static int BITMAPLEN(int NATTS)
static bool HeapTupleHasExternal(const HeapTupleData *tuple)
#define SizeofMinimalTupleHeader
static void HeapTupleHeaderSetTypeId(HeapTupleHeaderData *tup, Oid datum_typeid)
static CommandId HeapTupleHeaderGetRawCommandId(const HeapTupleHeaderData *tup)
static TransactionId HeapTupleHeaderGetRawXmax(const HeapTupleHeaderData *tup)
#define MaxTupleAttributeNumber
static bool HeapTupleNoNulls(const HeapTupleData *tuple)
#define HEAP_HASEXTERNAL
static void HeapTupleHeaderSetDatumLength(HeapTupleHeaderData *tup, uint32 len)
static TransactionId HeapTupleHeaderGetRawXmin(const HeapTupleHeaderData *tup)
#define HeapTupleHeaderSetNatts(tup, natts)
static bool HeapTupleHasVarWidth(const HeapTupleData *tuple)
long val
Definition informix.c:689
int i
Definition isn.c:77
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition itemptr.h:184
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc0(Size size)
Definition mcxt.c:1417
MemoryContext TopMemoryContext
Definition mcxt.c:166
void * palloc(Size size)
Definition mcxt.c:1387
static char * errmsg
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
int16 attnum
int16 attlen
const void size_t len
const void * data
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
static Datum TransactionIdGetDatum(TransactionId X)
Definition postgres.h:292
static Datum CommandIdGetDatum(CommandId X)
Definition postgres.h:322
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
static char * DatumGetCString(Datum X)
Definition postgres.h:355
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
#define InvalidOid
static int fb(int x)
int16 attcacheoff
Definition tupdesc.h:70
Size keysize
Definition hsearch.h:75
ItemPointerData t_self
Definition htup.h:65
uint32 t_len
Definition htup.h:64
HeapTupleHeader t_data
Definition htup.h:68
Oid t_tableOid
Definition htup.h:66
ItemPointerData t_ctid
bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]
bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]
#define MinTransactionIdAttributeNumber
Definition sysattr.h:22
#define MaxCommandIdAttributeNumber
Definition sysattr.h:25
#define MaxTransactionIdAttributeNumber
Definition sysattr.h:24
#define TableOidAttributeNumber
Definition sysattr.h:26
#define SelfItemPointerAttributeNumber
Definition sysattr.h:21
#define MinCommandIdAttributeNumber
Definition sysattr.h:23
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:193
#define att_nominal_alignby(cur_offset, attalignby)
Definition tupmacs.h:411
static int first_null_attr(const bits8 *bits, int natts)
Definition tupmacs.h:244
#define att_datum_alignby(cur_offset, attalignby, attlen, attdatum)
Definition tupmacs.h:352
static bool att_isnull(int ATT, const bits8 *BITS)
Definition tupmacs.h:28
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition tupmacs.h:431
static Datum align_fetch_then_add(const char *tupptr, uint32 *off, bool attbyval, int attlen, uint8 attalignby)
Definition tupmacs.h:172
#define att_pointer_alignby(cur_offset, attalignby, attlen, attptr)
Definition tupmacs.h:383
#define fetchatt(A, T)
Definition tupmacs.h:102
static Datum fetch_att_noerr(const void *T, bool attbyval, int attlen)
Definition tupmacs.h:137
#define att_addlength_datum(cur_offset, attlen, attdatum)
Definition tupmacs.h:419
static void store_att_byval(void *T, Datum newdatum, int attlen)
Definition tupmacs.h:457
static bool VARATT_IS_SHORT(const void *PTR)
Definition varatt.h:403
static Size VARSIZE_ANY(const void *PTR)
Definition varatt.h:460
static bool VARATT_CAN_MAKE_SHORT(const void *PTR)
Definition varatt.h:417
static bool VARATT_IS_EXTERNAL(const void *PTR)
Definition varatt.h:354
static Size VARSIZE(const void *PTR)
Definition varatt.h:298
static char * VARDATA(const void *PTR)
Definition varatt.h:305
static Size VARATT_CONVERTED_SHORT_SIZE(const void *PTR)
Definition varatt.h:425
static Size VARSIZE_EXTERNAL(const void *PTR)
Definition varatt.h:333
static bool VARATT_IS_EXTERNAL_EXPANDED(const void *PTR)
Definition varatt.h:389
static void SET_VARSIZE_SHORT(void *PTR, Size len)
Definition varatt.h:439
static Size VARSIZE_SHORT(const void *PTR)
Definition varatt.h:312
Datum bit(PG_FUNCTION_ARGS)
Definition varbit.c:391