1 /*-------------------------------------------------------------------------
4 * This file contains heap tuple accessor and mutator routines, as well
5 * as various tuple utilities.
7 * NOTE: there is massive duplication of code in this module to
8 * support both the convention that a null is marked by a bool TRUE,
9 * and the convention that a null is marked by a char 'n'. The latter
10 * convention is deprecated but it'll probably be a long time before
11 * we can get rid of it entirely.
14 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
15 * Portions Copyright (c) 1994, Regents of the University of California
19 * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.101 2005/10/19 18:18:32 tgl Exp $
21 *-------------------------------------------------------------------------
26 #include "access/heapam.h"
27 #include "access/tuptoaster.h"
28 #include "catalog/pg_type.h"
29 #include "executor/tuptable.h"
30 #include "utils/typcache.h"
33 /* ----------------------------------------------------------------
34 * misc support routines
35 * ----------------------------------------------------------------
39 * heap_compute_data_size
40 * Determine size of the data area of a tuple to be constructed
43 heap_compute_data_size(TupleDesc tupleDesc,
49 int numberOfAttributes = tupleDesc->natts;
50 Form_pg_attribute *att = tupleDesc->attrs;
52 for (i = 0; i < numberOfAttributes; i++)
57 data_length = att_align(data_length, att[i]->attalign);
58 data_length = att_addlength(data_length, att[i]->attlen, values[i]);
67 * Determine size of the data area of a tuple to be constructed
69 * OLD API with char 'n'/' ' convention for indicating nulls
73 ComputeDataSize(TupleDesc tupleDesc,
79 int numberOfAttributes = tupleDesc->natts;
80 Form_pg_attribute *att = tupleDesc->attrs;
82 for (i = 0; i < numberOfAttributes; i++)
87 data_length = att_align(data_length, att[i]->attalign);
88 data_length = att_addlength(data_length, att[i]->attlen, values[i]);
96 * Load data portion of a tuple from values/isnull arrays
98 * We also fill the null bitmap (if any) and set the infomask bits
99 * that reflect the tuple's data contents.
102 heap_fill_tuple(TupleDesc tupleDesc,
103 Datum *values, bool *isnull,
104 char *data, uint16 *infomask, bits8 *bit)
109 int numberOfAttributes = tupleDesc->natts;
110 Form_pg_attribute *att = tupleDesc->attrs;
119 /* just to keep compiler quiet */
124 *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTENDED);
126 for (i = 0; i < numberOfAttributes; i++)
132 if (bitmask != CSIGNBIT)
143 *infomask |= HEAP_HASNULL;
150 /* XXX we are aligning the pointer itself, not the offset */
151 data = (char *) att_align((long) data, att[i]->attalign);
153 if (att[i]->attbyval)
156 store_att_byval(data, values[i], att[i]->attlen);
157 data_length = att[i]->attlen;
159 else if (att[i]->attlen == -1)
162 *infomask |= HEAP_HASVARWIDTH;
163 if (VARATT_IS_EXTERNAL(values[i]))
164 *infomask |= HEAP_HASEXTERNAL;
165 if (VARATT_IS_COMPRESSED(values[i]))
166 *infomask |= HEAP_HASCOMPRESSED;
167 data_length = VARATT_SIZE(DatumGetPointer(values[i]));
168 memcpy(data, DatumGetPointer(values[i]), data_length);
170 else if (att[i]->attlen == -2)
173 *infomask |= HEAP_HASVARWIDTH;
174 data_length = strlen(DatumGetCString(values[i])) + 1;
175 memcpy(data, DatumGetPointer(values[i]), data_length);
179 /* fixed-length pass-by-reference */
180 Assert(att[i]->attlen > 0);
181 data_length = att[i]->attlen;
182 memcpy(data, DatumGetPointer(values[i]), data_length);
192 * Load data portion of a tuple from values/nulls arrays
194 * OLD API with char 'n'/' ' convention for indicating nulls
208 int numberOfAttributes = tupleDesc->natts;
209 Form_pg_attribute *att = tupleDesc->attrs;
218 /* just to keep compiler quiet */
223 *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTENDED);
225 for (i = 0; i < numberOfAttributes; i++)
231 if (bitmask != CSIGNBIT)
242 *infomask |= HEAP_HASNULL;
249 /* XXX we are aligning the pointer itself, not the offset */
250 data = (char *) att_align((long) data, att[i]->attalign);
252 if (att[i]->attbyval)
255 store_att_byval(data, values[i], att[i]->attlen);
256 data_length = att[i]->attlen;
258 else if (att[i]->attlen == -1)
261 *infomask |= HEAP_HASVARWIDTH;
262 if (VARATT_IS_EXTERNAL(values[i]))
263 *infomask |= HEAP_HASEXTERNAL;
264 if (VARATT_IS_COMPRESSED(values[i]))
265 *infomask |= HEAP_HASCOMPRESSED;
266 data_length = VARATT_SIZE(DatumGetPointer(values[i]));
267 memcpy(data, DatumGetPointer(values[i]), data_length);
269 else if (att[i]->attlen == -2)
272 *infomask |= HEAP_HASVARWIDTH;
273 data_length = strlen(DatumGetCString(values[i])) + 1;
274 memcpy(data, DatumGetPointer(values[i]), data_length);
278 /* fixed-length pass-by-reference */
279 Assert(att[i]->attlen > 0);
280 data_length = att[i]->attlen;
281 memcpy(data, DatumGetPointer(values[i]), data_length);
288 /* ----------------------------------------------------------------
289 * heap tuple interface
290 * ----------------------------------------------------------------
294 * heap_attisnull - returns TRUE iff tuple attribute is not present
298 heap_attisnull(HeapTuple tup, int attnum)
300 if (attnum > (int) tup->t_data->t_natts)
305 if (HeapTupleNoNulls(tup))
307 return att_isnull(attnum - 1, tup->t_data->t_bits);
312 case TableOidAttributeNumber:
313 case SelfItemPointerAttributeNumber:
314 case ObjectIdAttributeNumber:
315 case MinTransactionIdAttributeNumber:
316 case MinCommandIdAttributeNumber:
317 case MaxTransactionIdAttributeNumber:
318 case MaxCommandIdAttributeNumber:
319 /* these are never null */
323 elog(ERROR, "invalid attnum: %d", attnum);
332 * This only gets called from fastgetattr() macro, in cases where
333 * we can't use a cacheoffset and the value is not null.
335 * This caches attribute offsets in the attribute descriptor.
337 * An alternate way to speed things up would be to cache offsets
338 * with the tuple, but that seems more difficult unless you take
339 * the storage hit of actually putting those offsets into the
340 * tuple you send to disk. Yuck.
342 * This scheme will be slightly slower than that, but should
343 * perform well for queries which hit large #'s of tuples. After
344 * you cache the offsets once, examining all the other tuples using
345 * the same attribute descriptor will go much quicker. -cim 5/4/91
347 * NOTE: if you need to change this code, see also heap_deform_tuple.
351 nocachegetattr(HeapTuple tuple,
356 HeapTupleHeader tup = tuple->t_data;
357 Form_pg_attribute *att = tupleDesc->attrs;
358 char *tp; /* ptr to att in tuple */
359 bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
360 bool slow = false; /* do we have to walk nulls? */
362 (void) isnull; /* not used */
364 /* This is handled in the macro */
376 * 1: No nulls and no variable-width attributes.
377 * 2: Has a null or a var-width AFTER att.
378 * 3: Has nulls or var-widths BEFORE att.
382 if (HeapTupleNoNulls(tuple))
385 /* This is handled in the macro */
386 if (att[attnum]->attcacheoff != -1)
388 return fetchatt(att[attnum],
389 (char *) tup + tup->t_hoff +
390 att[attnum]->attcacheoff);
397 * there's a null somewhere in the tuple
399 * check to see if desired att is null
403 /* This is handled in the macro */
404 if (att_isnull(attnum, bp))
413 * Now check to see if any preceding bits are null...
416 int byte = attnum >> 3;
417 int finalbit = attnum & 0x07;
419 /* check for nulls "before" final bit of last byte */
420 if ((~bp[byte]) & ((1 << finalbit) - 1))
424 /* check for nulls in any "earlier" bytes */
427 for (i = 0; i < byte; i++)
439 tp = (char *) tup + tup->t_hoff;
442 * now check for any non-fixed length attrs before our attribute
446 if (att[attnum]->attcacheoff != -1)
448 return fetchatt(att[attnum],
449 tp + att[attnum]->attcacheoff);
451 else if (HeapTupleHasVarWidth(tuple))
456 * In for(), we test <= and not < because we want to see if we can
457 * go past it in initializing offsets.
459 for (j = 0; j <= attnum; j++)
461 if (att[j]->attlen <= 0)
471 * If slow is false, and we got here, we know that we have a tuple with no
472 * nulls or var-widths before the target attribute. If possible, we also
473 * want to initialize the remainder of the attribute cached offset values.
481 * need to set cache for some atts
484 att[0]->attcacheoff = 0;
486 while (j < attnum && att[j]->attcacheoff > 0)
489 off = att[j - 1]->attcacheoff + att[j - 1]->attlen;
491 for (; j <= attnum ||
492 /* Can we compute more? We will probably need them */
494 att[j]->attcacheoff == -1 &&
495 (HeapTupleNoNulls(tuple) || !att_isnull(j, bp)) &&
496 (HeapTupleAllFixed(tuple) || att[j]->attlen > 0)); j++)
498 off = att_align(off, att[j]->attalign);
500 att[j]->attcacheoff = off;
502 off = att_addlength(off, att[j]->attlen, tp + off);
505 return fetchatt(att[attnum], tp + att[attnum]->attcacheoff);
509 bool usecache = true;
514 * Now we know that we have to walk the tuple CAREFULLY.
516 * Note - This loop is a little tricky. For each non-null attribute, we
517 * have to first account for alignment padding before the attr, then
518 * advance over the attr based on its length. Nulls have no storage
519 * and no alignment padding either. We can use/set attcacheoff until
520 * we pass either a null or a var-width attribute.
523 for (i = 0; i < attnum; i++)
525 if (HeapTupleHasNulls(tuple) && att_isnull(i, bp))
531 /* If we know the next offset, we can skip the alignment calc */
532 if (usecache && att[i]->attcacheoff != -1)
533 off = att[i]->attcacheoff;
536 off = att_align(off, att[i]->attalign);
539 att[i]->attcacheoff = off;
542 off = att_addlength(off, att[i]->attlen, tp + off);
544 if (usecache && att[i]->attlen <= 0)
548 off = att_align(off, att[attnum]->attalign);
550 return fetchatt(att[attnum], tp + off);
557 * Fetch the value of a system attribute for a tuple.
559 * This is a support routine for the heap_getattr macro. The macro
560 * has already determined that the attnum refers to a system attribute.
564 heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
570 /* Currently, no sys attribute ever reads as NULL. */
576 case SelfItemPointerAttributeNumber:
577 /* pass-by-reference datatype */
578 result = PointerGetDatum(&(tup->t_self));
580 case ObjectIdAttributeNumber:
581 result = ObjectIdGetDatum(HeapTupleGetOid(tup));
583 case MinTransactionIdAttributeNumber:
584 result = TransactionIdGetDatum(HeapTupleHeaderGetXmin(tup->t_data));
586 case MinCommandIdAttributeNumber:
587 result = CommandIdGetDatum(HeapTupleHeaderGetCmin(tup->t_data));
589 case MaxTransactionIdAttributeNumber:
590 result = TransactionIdGetDatum(HeapTupleHeaderGetXmax(tup->t_data));
592 case MaxCommandIdAttributeNumber:
593 result = CommandIdGetDatum(HeapTupleHeaderGetCmax(tup->t_data));
595 case TableOidAttributeNumber:
596 result = ObjectIdGetDatum(tup->t_tableOid);
600 * If the attribute number is 0, then we are supposed to return
601 * the entire tuple as a row-type Datum. (Using zero for this
602 * purpose is unclean since it risks confusion with "invalid attr"
603 * result codes, but it's not worth changing now.)
605 * We have to make a copy of the tuple so we can safely insert the
606 * Datum overhead fields, which are not set in on-disk tuples.
608 * It's possible that the passed tupleDesc is a record type that
609 * hasn't been "blessed" yet, so cover that case.
611 case InvalidAttrNumber:
613 HeapTupleHeader dtup;
615 if (tupleDesc->tdtypeid == RECORDOID &&
616 tupleDesc->tdtypmod < 0)
617 assign_record_type_typmod(tupleDesc);
619 dtup = (HeapTupleHeader) palloc(tup->t_len);
620 memcpy((char *) dtup, (char *) tup->t_data, tup->t_len);
622 HeapTupleHeaderSetDatumLength(dtup, tup->t_len);
623 HeapTupleHeaderSetTypeId(dtup, tupleDesc->tdtypeid);
624 HeapTupleHeaderSetTypMod(dtup, tupleDesc->tdtypmod);
626 result = PointerGetDatum(dtup);
631 elog(ERROR, "invalid attnum: %d", attnum);
632 result = 0; /* keep compiler quiet */
641 * returns a copy of an entire tuple
643 * The HeapTuple struct, tuple header, and tuple data are all allocated
644 * as a single palloc() block.
648 heap_copytuple(HeapTuple tuple)
652 if (!HeapTupleIsValid(tuple) || tuple->t_data == NULL)
655 newTuple = (HeapTuple) palloc(HEAPTUPLESIZE + tuple->t_len);
656 newTuple->t_len = tuple->t_len;
657 newTuple->t_self = tuple->t_self;
658 newTuple->t_tableOid = tuple->t_tableOid;
659 newTuple->t_datamcxt = CurrentMemoryContext;
660 newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
661 memcpy((char *) newTuple->t_data, (char *) tuple->t_data, tuple->t_len);
666 * heap_copytuple_with_tuple
668 * copy a tuple into a caller-supplied HeapTuple management struct
672 heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest)
674 if (!HeapTupleIsValid(src) || src->t_data == NULL)
680 dest->t_len = src->t_len;
681 dest->t_self = src->t_self;
682 dest->t_tableOid = src->t_tableOid;
683 dest->t_datamcxt = CurrentMemoryContext;
684 dest->t_data = (HeapTupleHeader) palloc(src->t_len);
685 memcpy((char *) dest->t_data, (char *) src->t_data, src->t_len);
690 * construct a tuple from the given values[] and isnull[] arrays,
691 * which are of the length indicated by tupleDescriptor->natts
693 * The result is allocated in the current memory context.
696 heap_form_tuple(TupleDesc tupleDescriptor,
700 HeapTuple tuple; /* return tuple */
701 HeapTupleHeader td; /* tuple data */
704 bool hasnull = false;
705 Form_pg_attribute *att = tupleDescriptor->attrs;
706 int numberOfAttributes = tupleDescriptor->natts;
709 if (numberOfAttributes > MaxTupleAttributeNumber)
711 (errcode(ERRCODE_TOO_MANY_COLUMNS),
712 errmsg("number of columns (%d) exceeds limit (%d)",
713 numberOfAttributes, MaxTupleAttributeNumber)));
716 * Check for nulls and embedded tuples; expand any toasted attributes in
717 * embedded tuples. This preserves the invariant that toasting can only
720 * We can skip calling toast_flatten_tuple_attribute() if the attribute
721 * couldn't possibly be of composite type. All composite datums are
722 * varlena and have alignment 'd'; furthermore they aren't arrays. Also,
723 * if an attribute is already toasted, it must have been sent to disk
724 * already and so cannot contain toasted attributes.
726 for (i = 0; i < numberOfAttributes; i++)
730 else if (att[i]->attlen == -1 &&
731 att[i]->attalign == 'd' &&
732 att[i]->attndims == 0 &&
733 !VARATT_IS_EXTENDED(values[i]))
735 values[i] = toast_flatten_tuple_attribute(values[i],
742 * Determine total space needed
744 len = offsetof(HeapTupleHeaderData, t_bits);
747 len += BITMAPLEN(numberOfAttributes);
749 if (tupleDescriptor->tdhasoid)
752 hoff = len = MAXALIGN(len); /* align user data safely */
754 len += heap_compute_data_size(tupleDescriptor, values, isnull);
757 * Allocate and zero the space needed. Note that the tuple body and
758 * HeapTupleData management structure are allocated in one chunk.
760 tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
761 tuple->t_datamcxt = CurrentMemoryContext;
762 tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
765 * And fill in the information. Note we fill the Datum fields even though
766 * this tuple may never become a Datum.
769 ItemPointerSetInvalid(&(tuple->t_self));
770 tuple->t_tableOid = InvalidOid;
772 HeapTupleHeaderSetDatumLength(td, len);
773 HeapTupleHeaderSetTypeId(td, tupleDescriptor->tdtypeid);
774 HeapTupleHeaderSetTypMod(td, tupleDescriptor->tdtypmod);
776 td->t_natts = numberOfAttributes;
779 if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
780 td->t_infomask = HEAP_HASOID;
782 heap_fill_tuple(tupleDescriptor,
787 (hasnull ? td->t_bits : NULL));
795 * construct a tuple from the given values[] and nulls[] arrays
797 * Null attributes are indicated by a 'n' in the appropriate byte
798 * of nulls[]. Non-null attributes are indicated by a ' ' (space).
800 * OLD API with char 'n'/' ' convention for indicating nulls
804 heap_formtuple(TupleDesc tupleDescriptor,
808 HeapTuple tuple; /* return tuple */
809 HeapTupleHeader td; /* tuple data */
812 bool hasnull = false;
813 Form_pg_attribute *att = tupleDescriptor->attrs;
814 int numberOfAttributes = tupleDescriptor->natts;
817 if (numberOfAttributes > MaxTupleAttributeNumber)
819 (errcode(ERRCODE_TOO_MANY_COLUMNS),
820 errmsg("number of columns (%d) exceeds limit (%d)",
821 numberOfAttributes, MaxTupleAttributeNumber)));
824 * Check for nulls and embedded tuples; expand any toasted attributes in
825 * embedded tuples. This preserves the invariant that toasting can only
828 * We can skip calling toast_flatten_tuple_attribute() if the attribute
829 * couldn't possibly be of composite type. All composite datums are
830 * varlena and have alignment 'd'; furthermore they aren't arrays. Also,
831 * if an attribute is already toasted, it must have been sent to disk
832 * already and so cannot contain toasted attributes.
834 for (i = 0; i < numberOfAttributes; i++)
838 else if (att[i]->attlen == -1 &&
839 att[i]->attalign == 'd' &&
840 att[i]->attndims == 0 &&
841 !VARATT_IS_EXTENDED(values[i]))
843 values[i] = toast_flatten_tuple_attribute(values[i],
850 * Determine total space needed
852 len = offsetof(HeapTupleHeaderData, t_bits);
855 len += BITMAPLEN(numberOfAttributes);
857 if (tupleDescriptor->tdhasoid)
860 hoff = len = MAXALIGN(len); /* align user data safely */
862 len += ComputeDataSize(tupleDescriptor, values, nulls);
865 * Allocate and zero the space needed. Note that the tuple body and
866 * HeapTupleData management structure are allocated in one chunk.
868 tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
869 tuple->t_datamcxt = CurrentMemoryContext;
870 tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
873 * And fill in the information. Note we fill the Datum fields even though
874 * this tuple may never become a Datum.
877 ItemPointerSetInvalid(&(tuple->t_self));
878 tuple->t_tableOid = InvalidOid;
880 HeapTupleHeaderSetDatumLength(td, len);
881 HeapTupleHeaderSetTypeId(td, tupleDescriptor->tdtypeid);
882 HeapTupleHeaderSetTypMod(td, tupleDescriptor->tdtypmod);
884 td->t_natts = numberOfAttributes;
887 if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
888 td->t_infomask = HEAP_HASOID;
890 DataFill((char *) td + hoff,
895 (hasnull ? td->t_bits : NULL));
902 * form a new tuple from an old tuple and a set of replacement values.
904 * The replValues, replIsnull, and doReplace arrays must be of the length
905 * indicated by tupleDesc->natts. The new tuple is constructed using the data
906 * from replValues/replIsnull at columns where doReplace is true, and using
907 * the data from the old tuple at columns where doReplace is false.
909 * The result is allocated in the current memory context.
912 heap_modify_tuple(HeapTuple tuple,
918 int numberOfAttributes = tupleDesc->natts;
925 * allocate and fill values and isnull arrays from either the tuple or the
926 * repl information, as appropriate.
928 * NOTE: it's debatable whether to use heap_deform_tuple() here or just
929 * heap_getattr() only the non-replaced colums. The latter could win if
930 * there are many replaced columns and few non-replaced ones. However,
931 * heap_deform_tuple costs only O(N) while the heap_getattr way would cost
932 * O(N^2) if there are many non-replaced columns, so it seems better to
933 * err on the side of linear cost.
935 values = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
936 isnull = (bool *) palloc(numberOfAttributes * sizeof(bool));
938 heap_deform_tuple(tuple, tupleDesc, values, isnull);
940 for (attoff = 0; attoff < numberOfAttributes; attoff++)
942 if (doReplace[attoff])
944 values[attoff] = replValues[attoff];
945 isnull[attoff] = replIsnull[attoff];
950 * create a new tuple from the values and isnull arrays
952 newTuple = heap_form_tuple(tupleDesc, values, isnull);
958 * copy the identification info of the old tuple: t_ctid, t_self, and OID
961 newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
962 newTuple->t_self = tuple->t_self;
963 newTuple->t_tableOid = tuple->t_tableOid;
964 if (tupleDesc->tdhasoid)
965 HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
973 * forms a new tuple from an old tuple and a set of replacement values.
974 * returns a new palloc'ed tuple.
976 * OLD API with char 'n'/' ' convention for indicating nulls, and
977 * char 'r'/' ' convention for indicating whether to replace columns.
981 heap_modifytuple(HeapTuple tuple,
987 int numberOfAttributes = tupleDesc->natts;
994 * allocate and fill values and nulls arrays from either the tuple or the
995 * repl information, as appropriate.
997 * NOTE: it's debatable whether to use heap_deformtuple() here or just
998 * heap_getattr() only the non-replaced colums. The latter could win if
999 * there are many replaced columns and few non-replaced ones. However,
1000 * heap_deformtuple costs only O(N) while the heap_getattr way would cost
1001 * O(N^2) if there are many non-replaced columns, so it seems better to
1002 * err on the side of linear cost.
1004 values = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
1005 nulls = (char *) palloc(numberOfAttributes * sizeof(char));
1007 heap_deformtuple(tuple, tupleDesc, values, nulls);
1009 for (attoff = 0; attoff < numberOfAttributes; attoff++)
1011 if (replActions[attoff] == 'r')
1013 values[attoff] = replValues[attoff];
1014 nulls[attoff] = replNulls[attoff];
1016 else if (replActions[attoff] != ' ')
1017 elog(ERROR, "unrecognized replace flag: %d",
1018 (int) replActions[attoff]);
1022 * create a new tuple from the values and nulls arrays
1024 newTuple = heap_formtuple(tupleDesc, values, nulls);
1030 * copy the identification info of the old tuple: t_ctid, t_self, and OID
1033 newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
1034 newTuple->t_self = tuple->t_self;
1035 newTuple->t_tableOid = tuple->t_tableOid;
1036 if (tupleDesc->tdhasoid)
1037 HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
1044 * Given a tuple, extract data into values/isnull arrays; this is
1045 * the inverse of heap_form_tuple.
1047 * Storage for the values/isnull arrays is provided by the caller;
1048 * it should be sized according to tupleDesc->natts not tuple->t_natts.
1050 * Note that for pass-by-reference datatypes, the pointer placed
1051 * in the Datum will point into the given tuple.
1053 * When all or most of a tuple's fields need to be extracted,
1054 * this routine will be significantly quicker than a loop around
1055 * heap_getattr; the loop will become O(N^2) as soon as any
1056 * noncacheable attribute offsets are involved.
1059 heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
1060 Datum *values, bool *isnull)
1062 HeapTupleHeader tup = tuple->t_data;
1063 bool hasnulls = HeapTupleHasNulls(tuple);
1064 Form_pg_attribute *att = tupleDesc->attrs;
1065 int tdesc_natts = tupleDesc->natts;
1066 int natts; /* number of atts to extract */
1068 char *tp; /* ptr to tuple data */
1069 long off; /* offset in tuple data */
1070 bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
1071 bool slow = false; /* can we use/set attcacheoff? */
1073 natts = tup->t_natts;
1076 * In inheritance situations, it is possible that the given tuple actually
1077 * has more fields than the caller is expecting. Don't run off the end of
1078 * the caller's arrays.
1080 natts = Min(natts, tdesc_natts);
1082 tp = (char *) tup + tup->t_hoff;
1086 for (attnum = 0; attnum < natts; attnum++)
1088 Form_pg_attribute thisatt = att[attnum];
1090 if (hasnulls && att_isnull(attnum, bp))
1092 values[attnum] = (Datum) 0;
1093 isnull[attnum] = true;
1094 slow = true; /* can't use attcacheoff anymore */
1098 isnull[attnum] = false;
1100 if (!slow && thisatt->attcacheoff >= 0)
1101 off = thisatt->attcacheoff;
1104 off = att_align(off, thisatt->attalign);
1107 thisatt->attcacheoff = off;
1110 values[attnum] = fetchatt(thisatt, tp + off);
1112 off = att_addlength(off, thisatt->attlen, tp + off);
1114 if (thisatt->attlen <= 0)
1115 slow = true; /* can't use attcacheoff anymore */
1119 * If tuple doesn't have all the atts indicated by tupleDesc, read the
1122 for (; attnum < tdesc_natts; attnum++)
1124 values[attnum] = (Datum) 0;
1125 isnull[attnum] = true;
1132 * Given a tuple, extract data into values/nulls arrays; this is
1133 * the inverse of heap_formtuple.
1135 * Storage for the values/nulls arrays is provided by the caller;
1136 * it should be sized according to tupleDesc->natts not tuple->t_natts.
1138 * Note that for pass-by-reference datatypes, the pointer placed
1139 * in the Datum will point into the given tuple.
1141 * When all or most of a tuple's fields need to be extracted,
1142 * this routine will be significantly quicker than a loop around
1143 * heap_getattr; the loop will become O(N^2) as soon as any
1144 * noncacheable attribute offsets are involved.
1146 * OLD API with char 'n'/' ' convention for indicating nulls
1150 heap_deformtuple(HeapTuple tuple,
1151 TupleDesc tupleDesc,
1155 HeapTupleHeader tup = tuple->t_data;
1156 bool hasnulls = HeapTupleHasNulls(tuple);
1157 Form_pg_attribute *att = tupleDesc->attrs;
1158 int tdesc_natts = tupleDesc->natts;
1159 int natts; /* number of atts to extract */
1161 char *tp; /* ptr to tuple data */
1162 long off; /* offset in tuple data */
1163 bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
1164 bool slow = false; /* can we use/set attcacheoff? */
1166 natts = tup->t_natts;
1169 * In inheritance situations, it is possible that the given tuple actually
1170 * has more fields than the caller is expecting. Don't run off the end of
1171 * the caller's arrays.
1173 natts = Min(natts, tdesc_natts);
1175 tp = (char *) tup + tup->t_hoff;
1179 for (attnum = 0; attnum < natts; attnum++)
1181 Form_pg_attribute thisatt = att[attnum];
1183 if (hasnulls && att_isnull(attnum, bp))
1185 values[attnum] = (Datum) 0;
1186 nulls[attnum] = 'n';
1187 slow = true; /* can't use attcacheoff anymore */
1191 nulls[attnum] = ' ';
1193 if (!slow && thisatt->attcacheoff >= 0)
1194 off = thisatt->attcacheoff;
1197 off = att_align(off, thisatt->attalign);
1200 thisatt->attcacheoff = off;
1203 values[attnum] = fetchatt(thisatt, tp + off);
1205 off = att_addlength(off, thisatt->attlen, tp + off);
1207 if (thisatt->attlen <= 0)
1208 slow = true; /* can't use attcacheoff anymore */
1212 * If tuple doesn't have all the atts indicated by tupleDesc, read the
1215 for (; attnum < tdesc_natts; attnum++)
1217 values[attnum] = (Datum) 0;
1218 nulls[attnum] = 'n';
1224 * Given a TupleTableSlot, extract data from the slot's physical tuple
1225 * into its Datum/isnull arrays. Data is extracted up through the
1226 * natts'th column (caller must ensure this is a legal column number).
1228 * This is essentially an incremental version of heap_deform_tuple:
1229 * on each call we extract attributes up to the one needed, without
1230 * re-computing information about previously extracted attributes.
1231 * slot->tts_nvalid is the number of attributes already extracted.
1234 slot_deform_tuple(TupleTableSlot *slot, int natts)
1236 HeapTuple tuple = slot->tts_tuple;
1237 TupleDesc tupleDesc = slot->tts_tupleDescriptor;
1238 Datum *values = slot->tts_values;
1239 bool *isnull = slot->tts_isnull;
1240 HeapTupleHeader tup = tuple->t_data;
1241 bool hasnulls = HeapTupleHasNulls(tuple);
1242 Form_pg_attribute *att = tupleDesc->attrs;
1244 char *tp; /* ptr to tuple data */
1245 long off; /* offset in tuple data */
1246 bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
1247 bool slow; /* can we use/set attcacheoff? */
1250 * Check whether the first call for this tuple, and initialize or restore
1253 attnum = slot->tts_nvalid;
1256 /* Start from the first attribute */
1262 /* Restore state from previous execution */
1263 off = slot->tts_off;
1264 slow = slot->tts_slow;
1267 tp = (char *) tup + tup->t_hoff;
1269 for (; attnum < natts; attnum++)
1271 Form_pg_attribute thisatt = att[attnum];
1273 if (hasnulls && att_isnull(attnum, bp))
1275 values[attnum] = (Datum) 0;
1276 isnull[attnum] = true;
1277 slow = true; /* can't use attcacheoff anymore */
1281 isnull[attnum] = false;
1283 if (!slow && thisatt->attcacheoff >= 0)
1284 off = thisatt->attcacheoff;
1287 off = att_align(off, thisatt->attalign);
1290 thisatt->attcacheoff = off;
1293 values[attnum] = fetchatt(thisatt, tp + off);
1295 off = att_addlength(off, thisatt->attlen, tp + off);
1297 if (thisatt->attlen <= 0)
1298 slow = true; /* can't use attcacheoff anymore */
1302 * Save state for next execution
1304 slot->tts_nvalid = attnum;
1305 slot->tts_off = off;
1306 slot->tts_slow = slow;
1311 * This function fetches an attribute of the slot's current tuple.
1312 * It is functionally equivalent to heap_getattr, but fetches of
1313 * multiple attributes of the same tuple will be optimized better,
1314 * because we avoid O(N^2) behavior from multiple calls of
1315 * nocachegetattr(), even when attcacheoff isn't usable.
1317 * A difference from raw heap_getattr is that attnums beyond the
1318 * slot's tupdesc's last attribute will be considered NULL even
1319 * when the physical tuple is longer than the tupdesc.
1322 slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
1324 HeapTuple tuple = slot->tts_tuple;
1325 TupleDesc tupleDesc = slot->tts_tupleDescriptor;
1326 HeapTupleHeader tup;
1329 * system attributes are handled by heap_getsysattr
1333 if (tuple == NULL) /* internal error */
1334 elog(ERROR, "cannot extract system attribute from virtual tuple");
1335 return heap_getsysattr(tuple, attnum, tupleDesc, isnull);
1339 * fast path if desired attribute already cached
1341 if (attnum <= slot->tts_nvalid)
1343 *isnull = slot->tts_isnull[attnum - 1];
1344 return slot->tts_values[attnum - 1];
1348 * return NULL if attnum is out of range according to the tupdesc
1350 if (attnum > tupleDesc->natts)
1357 * otherwise we had better have a physical tuple (tts_nvalid should equal
1358 * natts in all virtual-tuple cases)
1360 if (tuple == NULL) /* internal error */
1361 elog(ERROR, "cannot extract attribute from empty tuple slot");
1364 * return NULL if attnum is out of range according to the tuple
1366 * (We have to check this separately because of various inheritance and
1367 * table-alteration scenarios: the tuple could be either longer or shorter
1368 * than the tupdesc.)
1370 tup = tuple->t_data;
1371 if (attnum > tup->t_natts)
1378 * check if target attribute is null: no point in groveling through tuple
1380 if (HeapTupleHasNulls(tuple) && att_isnull(attnum - 1, tup->t_bits))
1387 * If the attribute's column has been dropped, we force a NULL result.
1388 * This case should not happen in normal use, but it could happen if we
1389 * are executing a plan cached before the column was dropped.
1391 if (tupleDesc->attrs[attnum - 1]->attisdropped)
1398 * Extract the attribute, along with any preceding attributes.
1400 slot_deform_tuple(slot, attnum);
1403 * The result is acquired from tts_values array.
1405 *isnull = slot->tts_isnull[attnum - 1];
1406 return slot->tts_values[attnum - 1];
1411 * This function forces all the entries of the slot's Datum/isnull
1412 * arrays to be valid. The caller may then extract data directly
1413 * from those arrays instead of using slot_getattr.
1416 slot_getallattrs(TupleTableSlot *slot)
1418 int tdesc_natts = slot->tts_tupleDescriptor->natts;
1422 /* Quick out if we have 'em all already */
1423 if (slot->tts_nvalid == tdesc_natts)
1427 * otherwise we had better have a physical tuple (tts_nvalid should equal
1428 * natts in all virtual-tuple cases)
1430 tuple = slot->tts_tuple;
1431 if (tuple == NULL) /* internal error */
1432 elog(ERROR, "cannot extract attribute from empty tuple slot");
1435 * load up any slots available from physical tuple
1437 attnum = tuple->t_data->t_natts;
1438 attnum = Min(attnum, tdesc_natts);
1440 slot_deform_tuple(slot, attnum);
1443 * If tuple doesn't have all the atts indicated by tupleDesc, read the
1446 for (; attnum < tdesc_natts; attnum++)
1448 slot->tts_values[attnum] = (Datum) 0;
1449 slot->tts_isnull[attnum] = true;
1451 slot->tts_nvalid = tdesc_natts;
1456 * This function forces the entries of the slot's Datum/isnull
1457 * arrays to be valid at least up through the attnum'th entry.
1460 slot_getsomeattrs(TupleTableSlot *slot, int attnum)
1465 /* Quick out if we have 'em all already */
1466 if (slot->tts_nvalid >= attnum)
1469 /* Check for caller error */
1470 if (attnum <= 0 || attnum > slot->tts_tupleDescriptor->natts)
1471 elog(ERROR, "invalid attribute number %d", attnum);
1474 * otherwise we had better have a physical tuple (tts_nvalid should equal
1475 * natts in all virtual-tuple cases)
1477 tuple = slot->tts_tuple;
1478 if (tuple == NULL) /* internal error */
1479 elog(ERROR, "cannot extract attribute from empty tuple slot");
1482 * load up any slots available from physical tuple
1484 attno = tuple->t_data->t_natts;
1485 attno = Min(attno, attnum);
1487 slot_deform_tuple(slot, attno);
1490 * If tuple doesn't have all the atts indicated by tupleDesc, read the
1493 for (; attno < attnum; attno++)
1495 slot->tts_values[attno] = (Datum) 0;
1496 slot->tts_isnull[attno] = true;
1498 slot->tts_nvalid = attnum;
1503 * Detect whether an attribute of the slot is null, without
1504 * actually fetching it.
1507 slot_attisnull(TupleTableSlot *slot, int attnum)
1509 HeapTuple tuple = slot->tts_tuple;
1510 TupleDesc tupleDesc = slot->tts_tupleDescriptor;
1513 * system attributes are handled by heap_attisnull
1517 if (tuple == NULL) /* internal error */
1518 elog(ERROR, "cannot extract system attribute from virtual tuple");
1519 return heap_attisnull(tuple, attnum);
1523 * fast path if desired attribute already cached
1525 if (attnum <= slot->tts_nvalid)
1526 return slot->tts_isnull[attnum - 1];
1529 * return NULL if attnum is out of range according to the tupdesc
1531 if (attnum > tupleDesc->natts)
1535 * otherwise we had better have a physical tuple (tts_nvalid should equal
1536 * natts in all virtual-tuple cases)
1538 if (tuple == NULL) /* internal error */
1539 elog(ERROR, "cannot extract attribute from empty tuple slot");
1541 /* and let the tuple tell it */
1542 return heap_attisnull(tuple, attnum);
1550 heap_freetuple(HeapTuple htup)
1552 if (htup->t_data != NULL)
1553 if (htup->t_datamcxt != NULL && (char *) (htup->t_data) !=
1554 ((char *) htup + HEAPTUPLESIZE))
1555 pfree(htup->t_data);
1564 * This routine forms a HeapTuple by copying the given structure (tuple
1565 * data) and adding a generic header. Note that the tuple data is
1566 * presumed to contain no null fields and no varlena fields.
1568 * This routine is really only useful for certain system tables that are
1569 * known to be fixed-width and null-free. It is used in some places for
1570 * pg_class, but that is a gross hack (it only works because relacl can
1571 * be omitted from the tuple entirely in those places).
1575 heap_addheader(int natts, /* max domain index */
1576 bool withoid, /* reserve space for oid */
1577 Size structlen, /* its length */
1578 void *structure) /* pointer to the struct */
1585 AssertArg(natts > 0);
1587 /* header needs no null bitmap */
1588 hoff = offsetof(HeapTupleHeaderData, t_bits);
1590 hoff += sizeof(Oid);
1591 hoff = MAXALIGN(hoff);
1592 len = hoff + structlen;
1594 tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
1595 tuple->t_datamcxt = CurrentMemoryContext;
1596 tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
1599 ItemPointerSetInvalid(&(tuple->t_self));
1600 tuple->t_tableOid = InvalidOid;
1602 /* we don't bother to fill the Datum fields */
1604 td->t_natts = natts;
1607 if (withoid) /* else leave infomask = 0 */
1608 td->t_infomask = HEAP_HASOID;
1610 memcpy((char *) td + hoff, structure, structlen);