PostgreSQL Source Code  git master
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  * tuptoaster.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 'i' (or 'd') 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 'p', 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-2018, 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/sysattr.h"
61 #include "access/tupdesc_details.h"
62 #include "access/tuptoaster.h"
63 #include "executor/tuptable.h"
64 #include "utils/expandeddatum.h"
65 
66 
67 /* Does att's datatype allow packing into the 1-byte-header varlena format? */
68 #define ATT_IS_PACKABLE(att) \
69  ((att)->attlen == -1 && (att)->attstorage != 'p')
70 /* Use this if it's already known varlena */
71 #define VARLENA_ATT_IS_PACKABLE(att) \
72  ((att)->attstorage != 'p')
73 
74 
75 /* ----------------------------------------------------------------
76  * misc support routines
77  * ----------------------------------------------------------------
78  */
79 
80 /*
81  * Return the missing value of an attribute, or NULL if there isn't one.
82  */
83 static Datum
85  int attnum, bool *isnull)
86 {
88 
89  Assert(attnum <= tupleDesc->natts);
90  Assert(attnum > 0);
91 
92  att = TupleDescAttr(tupleDesc, attnum - 1);
93 
94  if (att->atthasmissing)
95  {
96  AttrMissing *attrmiss;
97 
98  Assert(tupleDesc->constr);
99  Assert(tupleDesc->constr->missing);
100 
101  attrmiss = tupleDesc->constr->missing + (attnum - 1);
102 
103  if (attrmiss->ammissingPresent)
104  {
105  *isnull = false;
106  return attrmiss->ammissing;
107  }
108  }
109 
110  *isnull = true;
111  return PointerGetDatum(NULL);
112 }
113 
114 /*
115  * Fill in missing values for a TupleTableSlot.
116  *
117  * This is only exposed because it's needed for JIT compiled tuple
118  * deforming. That exception aside, there should be no callers outside of this
119  * file.
120  */
121 void
122 slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum)
123 {
124  AttrMissing *attrmiss = NULL;
125  int missattnum;
126 
127  if (slot->tts_tupleDescriptor->constr)
128  attrmiss = slot->tts_tupleDescriptor->constr->missing;
129 
130  if (!attrmiss)
131  {
132  /* no missing values array at all, so just fill everything in as NULL */
133  memset(slot->tts_values + startAttNum, 0,
134  (lastAttNum - startAttNum) * sizeof(Datum));
135  memset(slot->tts_isnull + startAttNum, 1,
136  (lastAttNum - startAttNum) * sizeof(bool));
137  }
138  else
139  {
140  /* if there is a missing values array we must process them one by one */
141  for (missattnum = startAttNum;
142  missattnum < lastAttNum;
143  missattnum++)
144  {
145  slot->tts_values[missattnum] = attrmiss[missattnum].ammissing;
146  slot->tts_isnull[missattnum] =
147  !attrmiss[missattnum].ammissingPresent;
148  }
149  }
150 }
151 
152 /*
153  * heap_compute_data_size
154  * Determine size of the data area of a tuple to be constructed
155  */
156 Size
158  Datum *values,
159  bool *isnull)
160 {
161  Size data_length = 0;
162  int i;
163  int numberOfAttributes = tupleDesc->natts;
164 
165  for (i = 0; i < numberOfAttributes; i++)
166  {
167  Datum val;
168  Form_pg_attribute atti;
169 
170  if (isnull[i])
171  continue;
172 
173  val = values[i];
174  atti = TupleDescAttr(tupleDesc, i);
175 
176  if (ATT_IS_PACKABLE(atti) &&
178  {
179  /*
180  * we're anticipating converting to a short varlena header, so
181  * adjust length and don't count any alignment
182  */
183  data_length += VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val));
184  }
185  else if (atti->attlen == -1 &&
187  {
188  /*
189  * we want to flatten the expanded value so that the constructed
190  * tuple doesn't depend on it
191  */
192  data_length = att_align_nominal(data_length, atti->attalign);
193  data_length += EOH_get_flat_size(DatumGetEOHP(val));
194  }
195  else
196  {
197  data_length = att_align_datum(data_length, atti->attalign,
198  atti->attlen, val);
199  data_length = att_addlength_datum(data_length, atti->attlen,
200  val);
201  }
202  }
203 
204  return data_length;
205 }
206 
207 /*
208  * Per-attribute helper for heap_fill_tuple and other routines building tuples.
209  *
210  * Fill in either a data value or a bit in the null bitmask
211  */
212 static inline void
214  bits8 **bit,
215  int *bitmask,
216  char **dataP,
217  uint16 *infomask,
218  Datum datum,
219  bool isnull)
220 {
221  Size data_length;
222  char *data = *dataP;
223 
224  /*
225  * If we're building a null bitmap, set the appropriate bit for the
226  * current column value here.
227  */
228  if (bit != NULL)
229  {
230  if (*bitmask != HIGHBIT)
231  *bitmask <<= 1;
232  else
233  {
234  *bit += 1;
235  **bit = 0x0;
236  *bitmask = 1;
237  }
238 
239  if (isnull)
240  {
241  *infomask |= HEAP_HASNULL;
242  return;
243  }
244 
245  **bit |= *bitmask;
246  }
247 
248  /*
249  * XXX we use the att_align macros on the pointer value itself, not on an
250  * offset. This is a bit of a hack.
251  */
252  if (att->attbyval)
253  {
254  /* pass-by-value */
255  data = (char *) att_align_nominal(data, att->attalign);
256  store_att_byval(data, datum, att->attlen);
257  data_length = att->attlen;
258  }
259  else if (att->attlen == -1)
260  {
261  /* varlena */
262  Pointer val = DatumGetPointer(datum);
263 
264  *infomask |= HEAP_HASVARWIDTH;
265  if (VARATT_IS_EXTERNAL(val))
266  {
268  {
269  /*
270  * we want to flatten the expanded value so that the
271  * constructed tuple doesn't depend on it
272  */
273  ExpandedObjectHeader *eoh = DatumGetEOHP(datum);
274 
275  data = (char *) att_align_nominal(data,
276  att->attalign);
277  data_length = EOH_get_flat_size(eoh);
278  EOH_flatten_into(eoh, data, data_length);
279  }
280  else
281  {
282  *infomask |= HEAP_HASEXTERNAL;
283  /* no alignment, since it's short by definition */
284  data_length = VARSIZE_EXTERNAL(val);
285  memcpy(data, val, data_length);
286  }
287  }
288  else if (VARATT_IS_SHORT(val))
289  {
290  /* no alignment for short varlenas */
291  data_length = VARSIZE_SHORT(val);
292  memcpy(data, val, data_length);
293  }
294  else if (VARLENA_ATT_IS_PACKABLE(att) &&
296  {
297  /* convert to short varlena -- no alignment */
298  data_length = VARATT_CONVERTED_SHORT_SIZE(val);
299  SET_VARSIZE_SHORT(data, data_length);
300  memcpy(data + 1, VARDATA(val), data_length - 1);
301  }
302  else
303  {
304  /* full 4-byte header varlena */
305  data = (char *) att_align_nominal(data,
306  att->attalign);
307  data_length = VARSIZE(val);
308  memcpy(data, val, data_length);
309  }
310  }
311  else if (att->attlen == -2)
312  {
313  /* cstring ... never needs alignment */
314  *infomask |= HEAP_HASVARWIDTH;
315  Assert(att->attalign == 'c');
316  data_length = strlen(DatumGetCString(datum)) + 1;
317  memcpy(data, DatumGetPointer(datum), data_length);
318  }
319  else
320  {
321  /* fixed-length pass-by-reference */
322  data = (char *) att_align_nominal(data, att->attalign);
323  Assert(att->attlen > 0);
324  data_length = att->attlen;
325  memcpy(data, DatumGetPointer(datum), data_length);
326  }
327 
328  data += data_length;
329  *dataP = data;
330 }
331 
332 /*
333  * heap_fill_tuple
334  * Load data portion of a tuple from values/isnull arrays
335  *
336  * We also fill the null bitmap (if any) and set the infomask bits
337  * that reflect the tuple's data contents.
338  *
339  * NOTE: it is now REQUIRED that the caller have pre-zeroed the data area.
340  */
341 void
343  Datum *values, bool *isnull,
344  char *data, Size data_size,
345  uint16 *infomask, bits8 *bit)
346 {
347  bits8 *bitP;
348  int bitmask;
349  int i;
350  int numberOfAttributes = tupleDesc->natts;
351 
352 #ifdef USE_ASSERT_CHECKING
353  char *start = data;
354 #endif
355 
356  if (bit != NULL)
357  {
358  bitP = &bit[-1];
359  bitmask = HIGHBIT;
360  }
361  else
362  {
363  /* just to keep compiler quiet */
364  bitP = NULL;
365  bitmask = 0;
366  }
367 
368  *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTERNAL);
369 
370  for (i = 0; i < numberOfAttributes; i++)
371  {
372  Form_pg_attribute attr = TupleDescAttr(tupleDesc, i);
373 
374  fill_val(attr,
375  bitP ? &bitP : NULL,
376  &bitmask,
377  &data,
378  infomask,
379  values ? values[i] : PointerGetDatum(NULL),
380  isnull ? isnull[i] : true);
381  }
382 
383  Assert((data - start) == data_size);
384 }
385 
386 
387 /* ----------------------------------------------------------------
388  * heap tuple interface
389  * ----------------------------------------------------------------
390  */
391 
392 /* ----------------
393  * heap_attisnull - returns true iff tuple attribute is not present
394  * ----------------
395  */
396 bool
398 {
399  /*
400  * We allow a NULL tupledesc for relations not expected to have missing
401  * values, such as catalog relations and indexes.
402  */
403  Assert(!tupleDesc || attnum <= tupleDesc->natts);
404  if (attnum > (int) HeapTupleHeaderGetNatts(tup->t_data))
405  {
406  if (tupleDesc && TupleDescAttr(tupleDesc, attnum - 1)->atthasmissing)
407  return false;
408  else
409  return true;
410  }
411 
412  if (attnum > 0)
413  {
414  if (HeapTupleNoNulls(tup))
415  return false;
416  return att_isnull(attnum - 1, tup->t_data->t_bits);
417  }
418 
419  switch (attnum)
420  {
428  /* these are never null */
429  break;
430 
431  default:
432  elog(ERROR, "invalid attnum: %d", attnum);
433  }
434 
435  return false;
436 }
437 
438 /* ----------------
439  * nocachegetattr
440  *
441  * This only gets called from fastgetattr() macro, in cases where
442  * we can't use a cacheoffset and the value is not null.
443  *
444  * This caches attribute offsets in the attribute descriptor.
445  *
446  * An alternative way to speed things up would be to cache offsets
447  * with the tuple, but that seems more difficult unless you take
448  * the storage hit of actually putting those offsets into the
449  * tuple you send to disk. Yuck.
450  *
451  * This scheme will be slightly slower than that, but should
452  * perform well for queries which hit large #'s of tuples. After
453  * you cache the offsets once, examining all the other tuples using
454  * the same attribute descriptor will go much quicker. -cim 5/4/91
455  *
456  * NOTE: if you need to change this code, see also heap_deform_tuple.
457  * Also see nocache_index_getattr, which is the same code for index
458  * tuples.
459  * ----------------
460  */
461 Datum
463  int attnum,
465 {
466  HeapTupleHeader tup = tuple->t_data;
467  char *tp; /* ptr to data part of tuple */
468  bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
469  bool slow = false; /* do we have to walk attrs? */
470  int off; /* current offset within data */
471 
472  /* ----------------
473  * Three cases:
474  *
475  * 1: No nulls and no variable-width attributes.
476  * 2: Has a null or a var-width AFTER att.
477  * 3: Has nulls or var-widths BEFORE att.
478  * ----------------
479  */
480 
481  attnum--;
482 
483  if (!HeapTupleNoNulls(tuple))
484  {
485  /*
486  * there's a null somewhere in the tuple
487  *
488  * check to see if any preceding bits are null...
489  */
490  int byte = attnum >> 3;
491  int finalbit = attnum & 0x07;
492 
493  /* check for nulls "before" final bit of last byte */
494  if ((~bp[byte]) & ((1 << finalbit) - 1))
495  slow = true;
496  else
497  {
498  /* check for nulls in any "earlier" bytes */
499  int i;
500 
501  for (i = 0; i < byte; i++)
502  {
503  if (bp[i] != 0xFF)
504  {
505  slow = true;
506  break;
507  }
508  }
509  }
510  }
511 
512  tp = (char *) tup + tup->t_hoff;
513 
514  if (!slow)
515  {
516  Form_pg_attribute att;
517 
518  /*
519  * If we get here, there are no nulls up to and including the target
520  * attribute. If we have a cached offset, we can use it.
521  */
522  att = TupleDescAttr(tupleDesc, attnum);
523  if (att->attcacheoff >= 0)
524  return fetchatt(att, tp + att->attcacheoff);
525 
526  /*
527  * Otherwise, check for non-fixed-length attrs up to and including
528  * target. If there aren't any, it's safe to cheaply initialize the
529  * cached offsets for these attrs.
530  */
531  if (HeapTupleHasVarWidth(tuple))
532  {
533  int j;
534 
535  for (j = 0; j <= attnum; j++)
536  {
537  if (TupleDescAttr(tupleDesc, j)->attlen <= 0)
538  {
539  slow = true;
540  break;
541  }
542  }
543  }
544  }
545 
546  if (!slow)
547  {
548  int natts = tupleDesc->natts;
549  int j = 1;
550 
551  /*
552  * If we get here, we have a tuple with no nulls or var-widths up to
553  * and including the target attribute, so we can use the cached offset
554  * ... only we don't have it yet, or we'd not have got here. Since
555  * it's cheap to compute offsets for fixed-width columns, we take the
556  * opportunity to initialize the cached offsets for *all* the leading
557  * fixed-width columns, in hope of avoiding future visits to this
558  * routine.
559  */
560  TupleDescAttr(tupleDesc, 0)->attcacheoff = 0;
561 
562  /* we might have set some offsets in the slow path previously */
563  while (j < natts && TupleDescAttr(tupleDesc, j)->attcacheoff > 0)
564  j++;
565 
566  off = TupleDescAttr(tupleDesc, j - 1)->attcacheoff +
567  TupleDescAttr(tupleDesc, j - 1)->attlen;
568 
569  for (; j < natts; j++)
570  {
571  Form_pg_attribute att = TupleDescAttr(tupleDesc, j);
572 
573  if (att->attlen <= 0)
574  break;
575 
576  off = att_align_nominal(off, att->attalign);
577 
578  att->attcacheoff = off;
579 
580  off += att->attlen;
581  }
582 
583  Assert(j > attnum);
584 
585  off = TupleDescAttr(tupleDesc, attnum)->attcacheoff;
586  }
587  else
588  {
589  bool usecache = true;
590  int i;
591 
592  /*
593  * Now we know that we have to walk the tuple CAREFULLY. But we still
594  * might be able to cache some offsets for next time.
595  *
596  * Note - This loop is a little tricky. For each non-null attribute,
597  * we have to first account for alignment padding before the attr,
598  * then advance over the attr based on its length. Nulls have no
599  * storage and no alignment padding either. We can use/set
600  * attcacheoff until we reach either a null or a var-width attribute.
601  */
602  off = 0;
603  for (i = 0;; i++) /* loop exit is at "break" */
604  {
605  Form_pg_attribute att = TupleDescAttr(tupleDesc, i);
606 
607  if (HeapTupleHasNulls(tuple) && att_isnull(i, bp))
608  {
609  usecache = false;
610  continue; /* this cannot be the target att */
611  }
612 
613  /* If we know the next offset, we can skip the rest */
614  if (usecache && att->attcacheoff >= 0)
615  off = att->attcacheoff;
616  else if (att->attlen == -1)
617  {
618  /*
619  * We can only cache the offset for a varlena attribute if the
620  * offset is already suitably aligned, so that there would be
621  * no pad bytes in any case: then the offset will be valid for
622  * either an aligned or unaligned value.
623  */
624  if (usecache &&
625  off == att_align_nominal(off, att->attalign))
626  att->attcacheoff = off;
627  else
628  {
629  off = att_align_pointer(off, att->attalign, -1,
630  tp + off);
631  usecache = false;
632  }
633  }
634  else
635  {
636  /* not varlena, so safe to use att_align_nominal */
637  off = att_align_nominal(off, att->attalign);
638 
639  if (usecache)
640  att->attcacheoff = off;
641  }
642 
643  if (i == attnum)
644  break;
645 
646  off = att_addlength_pointer(off, att->attlen, tp + off);
647 
648  if (usecache && att->attlen <= 0)
649  usecache = false;
650  }
651  }
652 
653  return fetchatt(TupleDescAttr(tupleDesc, attnum), tp + off);
654 }
655 
656 /* ----------------
657  * heap_getsysattr
658  *
659  * Fetch the value of a system attribute for a tuple.
660  *
661  * This is a support routine for the heap_getattr macro. The macro
662  * has already determined that the attnum refers to a system attribute.
663  * ----------------
664  */
665 Datum
667 {
668  Datum result;
669 
670  Assert(tup);
671 
672  /* Currently, no sys attribute ever reads as NULL. */
673  *isnull = false;
674 
675  switch (attnum)
676  {
678  /* pass-by-reference datatype */
679  result = PointerGetDatum(&(tup->t_self));
680  break;
682  result = ObjectIdGetDatum(HeapTupleGetOid(tup));
683  break;
686  break;
689  break;
692 
693  /*
694  * cmin and cmax are now both aliases for the same field, which
695  * can in fact also be a combo command id. XXX perhaps we should
696  * return the "real" cmin or cmax if possible, that is if we are
697  * inside the originating transaction?
698  */
700  break;
702  result = ObjectIdGetDatum(tup->t_tableOid);
703  break;
704  default:
705  elog(ERROR, "invalid attnum: %d", attnum);
706  result = 0; /* keep compiler quiet */
707  break;
708  }
709  return result;
710 }
711 
712 /* ----------------
713  * heap_copytuple
714  *
715  * returns a copy of an entire tuple
716  *
717  * The HeapTuple struct, tuple header, and tuple data are all allocated
718  * as a single palloc() block.
719  * ----------------
720  */
721 HeapTuple
723 {
724  HeapTuple newTuple;
725 
726  if (!HeapTupleIsValid(tuple) || tuple->t_data == NULL)
727  return NULL;
728 
729  newTuple = (HeapTuple) palloc(HEAPTUPLESIZE + tuple->t_len);
730  newTuple->t_len = tuple->t_len;
731  newTuple->t_self = tuple->t_self;
732  newTuple->t_tableOid = tuple->t_tableOid;
733  newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
734  memcpy((char *) newTuple->t_data, (char *) tuple->t_data, tuple->t_len);
735  return newTuple;
736 }
737 
738 /* ----------------
739  * heap_copytuple_with_tuple
740  *
741  * copy a tuple into a caller-supplied HeapTuple management struct
742  *
743  * Note that after calling this function, the "dest" HeapTuple will not be
744  * allocated as a single palloc() block (unlike with heap_copytuple()).
745  * ----------------
746  */
747 void
749 {
750  if (!HeapTupleIsValid(src) || src->t_data == NULL)
751  {
752  dest->t_data = NULL;
753  return;
754  }
755 
756  dest->t_len = src->t_len;
757  dest->t_self = src->t_self;
758  dest->t_tableOid = src->t_tableOid;
759  dest->t_data = (HeapTupleHeader) palloc(src->t_len);
760  memcpy((char *) dest->t_data, (char *) src->t_data, src->t_len);
761 }
762 
763 /*
764  * Expand a tuple which has less attributes than required. For each attribute
765  * not present in the sourceTuple, if there is a missing value that will be
766  * used. Otherwise the attribute will be set to NULL.
767  *
768  * The source tuple must have less attributes than the required number.
769  *
770  * Only one of targetHeapTuple and targetMinimalTuple may be supplied. The
771  * other argument must be NULL.
772  */
773 static void
774 expand_tuple(HeapTuple *targetHeapTuple,
775  MinimalTuple *targetMinimalTuple,
776  HeapTuple sourceTuple,
778 {
779  AttrMissing *attrmiss = NULL;
780  int attnum;
781  int firstmissingnum = 0;
782  bool hasNulls = HeapTupleHasNulls(sourceTuple);
783  HeapTupleHeader targetTHeader;
784  HeapTupleHeader sourceTHeader = sourceTuple->t_data;
785  int sourceNatts = HeapTupleHeaderGetNatts(sourceTHeader);
786  int natts = tupleDesc->natts;
787  int sourceNullLen;
788  int targetNullLen;
789  Size sourceDataLen = sourceTuple->t_len - sourceTHeader->t_hoff;
790  Size targetDataLen;
791  Size len;
792  int hoff;
793  bits8 *nullBits = NULL;
794  int bitMask = 0;
795  char *targetData;
796  uint16 *infoMask;
797 
798  Assert((targetHeapTuple && !targetMinimalTuple)
799  || (!targetHeapTuple && targetMinimalTuple));
800 
801  Assert(sourceNatts < natts);
802 
803  sourceNullLen = (hasNulls ? BITMAPLEN(sourceNatts) : 0);
804 
805  targetDataLen = sourceDataLen;
806 
807  if (tupleDesc->constr &&
808  tupleDesc->constr->missing)
809  {
810  /*
811  * If there are missing values we want to put them into the tuple.
812  * Before that we have to compute the extra length for the values
813  * array and the variable length data.
814  */
815  attrmiss = tupleDesc->constr->missing;
816 
817  /*
818  * Find the first item in attrmiss for which we don't have a value in
819  * the source. We can ignore all the missing entries before that.
820  */
821  for (firstmissingnum = sourceNatts;
822  firstmissingnum < natts;
823  firstmissingnum++)
824  {
825  if (attrmiss[firstmissingnum].ammissingPresent)
826  break;
827  }
828 
829  /*
830  * If there are no more missing values everything else must be NULL
831  */
832  if (firstmissingnum >= natts)
833  {
834  hasNulls = true;
835  }
836  else
837  {
838 
839  /*
840  * Now walk the missing attributes. If there is a missing value
841  * make space for it. Otherwise, it's going to be NULL.
842  */
843  for (attnum = firstmissingnum;
844  attnum < natts;
845  attnum++)
846  {
847  if (attrmiss[attnum].ammissingPresent)
848  {
849  Form_pg_attribute att = TupleDescAttr(tupleDesc, attnum);
850 
851  targetDataLen = att_align_datum(targetDataLen,
852  att->attalign,
853  att->attlen,
854  attrmiss[attnum].ammissing);
855 
856  targetDataLen = att_addlength_pointer(targetDataLen,
857  att->attlen,
858  attrmiss[attnum].ammissing);
859  }
860  else
861  {
862  /* no missing value, so it must be null */
863  hasNulls = true;
864  }
865  }
866  }
867  } /* end if have missing values */
868  else
869  {
870  /*
871  * If there are no missing values at all then NULLS must be allowed,
872  * since some of the attributes are known to be absent.
873  */
874  hasNulls = true;
875  }
876 
877  len = 0;
878 
879  if (hasNulls)
880  {
881  targetNullLen = BITMAPLEN(natts);
882  len += targetNullLen;
883  }
884  else
885  targetNullLen = 0;
886 
887  if (tupleDesc->tdhasoid)
888  len += sizeof(Oid);
889 
890  /*
891  * Allocate and zero the space needed. Note that the tuple body and
892  * HeapTupleData management structure are allocated in one chunk.
893  */
894  if (targetHeapTuple)
895  {
896  len += offsetof(HeapTupleHeaderData, t_bits);
897  hoff = len = MAXALIGN(len); /* align user data safely */
898  len += targetDataLen;
899 
900  *targetHeapTuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
901  (*targetHeapTuple)->t_data
902  = targetTHeader
903  = (HeapTupleHeader) ((char *) *targetHeapTuple + HEAPTUPLESIZE);
904  (*targetHeapTuple)->t_len = len;
905  (*targetHeapTuple)->t_tableOid = sourceTuple->t_tableOid;
906  ItemPointerSetInvalid(&((*targetHeapTuple)->t_self));
907 
908  targetTHeader->t_infomask = sourceTHeader->t_infomask;
909  targetTHeader->t_hoff = hoff;
910  HeapTupleHeaderSetNatts(targetTHeader, natts);
911  HeapTupleHeaderSetDatumLength(targetTHeader, len);
912  HeapTupleHeaderSetTypeId(targetTHeader, tupleDesc->tdtypeid);
913  HeapTupleHeaderSetTypMod(targetTHeader, tupleDesc->tdtypmod);
914  /* We also make sure that t_ctid is invalid unless explicitly set */
915  ItemPointerSetInvalid(&(targetTHeader->t_ctid));
916  if (targetNullLen > 0)
917  nullBits = (bits8 *) ((char *) (*targetHeapTuple)->t_data
918  + offsetof(HeapTupleHeaderData, t_bits));
919  targetData = (char *) (*targetHeapTuple)->t_data + hoff;
920  infoMask = &(targetTHeader->t_infomask);
921  }
922  else
923  {
925  hoff = len = MAXALIGN(len); /* align user data safely */
926  len += targetDataLen;
927 
928  *targetMinimalTuple = (MinimalTuple) palloc0(len);
929  (*targetMinimalTuple)->t_len = len;
930  (*targetMinimalTuple)->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
931  (*targetMinimalTuple)->t_infomask = sourceTHeader->t_infomask;
932  /* Same macro works for MinimalTuples */
933  HeapTupleHeaderSetNatts(*targetMinimalTuple, natts);
934  if (targetNullLen > 0)
935  nullBits = (bits8 *) ((char *) *targetMinimalTuple
936  + offsetof(MinimalTupleData, t_bits));
937  targetData = (char *) *targetMinimalTuple + hoff;
938  infoMask = &((*targetMinimalTuple)->t_infomask);
939  }
940 
941  if (targetNullLen > 0)
942  {
943  if (sourceNullLen > 0)
944  {
945  /* if bitmap pre-existed copy in - all is set */
946  memcpy(nullBits,
947  ((char *) sourceTHeader)
948  + offsetof(HeapTupleHeaderData, t_bits),
949  sourceNullLen);
950  nullBits += sourceNullLen - 1;
951  }
952  else
953  {
954  sourceNullLen = BITMAPLEN(sourceNatts);
955  /* Set NOT NULL for all existing attributes */
956  memset(nullBits, 0xff, sourceNullLen);
957 
958  nullBits += sourceNullLen - 1;
959 
960  if (sourceNatts & 0x07)
961  {
962  /* build the mask (inverted!) */
963  bitMask = 0xff << (sourceNatts & 0x07);
964  /* Voila */
965  *nullBits = ~bitMask;
966  }
967  }
968 
969  bitMask = (1 << ((sourceNatts - 1) & 0x07));
970  } /* End if have null bitmap */
971 
972  memcpy(targetData,
973  ((char *) sourceTuple->t_data) + sourceTHeader->t_hoff,
974  sourceDataLen);
975 
976  targetData += sourceDataLen;
977 
978  /* Now fill in the missing values */
979  for (attnum = sourceNatts; attnum < natts; attnum++)
980  {
981 
982  Form_pg_attribute attr = TupleDescAttr(tupleDesc, attnum);
983 
984  if (attrmiss && attrmiss[attnum].ammissingPresent)
985  {
986  fill_val(attr,
987  nullBits ? &nullBits : NULL,
988  &bitMask,
989  &targetData,
990  infoMask,
991  attrmiss[attnum].ammissing,
992  false);
993  }
994  else
995  {
996  fill_val(attr,
997  &nullBits,
998  &bitMask,
999  &targetData,
1000  infoMask,
1001  (Datum) 0,
1002  true);
1003  }
1004  } /* end loop over missing attributes */
1005 }
1006 
1007 /*
1008  * Fill in the missing values for a minimal HeapTuple
1009  */
1012 {
1013  MinimalTuple minimalTuple;
1014 
1015  expand_tuple(NULL, &minimalTuple, sourceTuple, tupleDesc);
1016  return minimalTuple;
1017 }
1018 
1019 /*
1020  * Fill in the missing values for an ordinary HeapTuple
1021  */
1022 HeapTuple
1024 {
1025  HeapTuple heapTuple;
1026 
1027  expand_tuple(&heapTuple, NULL, sourceTuple, tupleDesc);
1028  return heapTuple;
1029 }
1030 
1031 /* ----------------
1032  * heap_copy_tuple_as_datum
1033  *
1034  * copy a tuple as a composite-type Datum
1035  * ----------------
1036  */
1037 Datum
1039 {
1040  HeapTupleHeader td;
1041 
1042  /*
1043  * If the tuple contains any external TOAST pointers, we have to inline
1044  * those fields to meet the conventions for composite-type Datums.
1045  */
1046  if (HeapTupleHasExternal(tuple))
1047  return toast_flatten_tuple_to_datum(tuple->t_data,
1048  tuple->t_len,
1049  tupleDesc);
1050 
1051  /*
1052  * Fast path for easy case: just make a palloc'd copy and insert the
1053  * correct composite-Datum header fields (since those may not be set if
1054  * the given tuple came from disk, rather than from heap_form_tuple).
1055  */
1056  td = (HeapTupleHeader) palloc(tuple->t_len);
1057  memcpy((char *) td, (char *) tuple->t_data, tuple->t_len);
1058 
1060  HeapTupleHeaderSetTypeId(td, tupleDesc->tdtypeid);
1061  HeapTupleHeaderSetTypMod(td, tupleDesc->tdtypmod);
1062 
1063  return PointerGetDatum(td);
1064 }
1065 
1066 /*
1067  * heap_form_tuple
1068  * construct a tuple from the given values[] and isnull[] arrays,
1069  * which are of the length indicated by tupleDescriptor->natts
1070  *
1071  * The result is allocated in the current memory context.
1072  */
1073 HeapTuple
1074 heap_form_tuple(TupleDesc tupleDescriptor,
1075  Datum *values,
1076  bool *isnull)
1077 {
1078  HeapTuple tuple; /* return tuple */
1079  HeapTupleHeader td; /* tuple data */
1080  Size len,
1081  data_len;
1082  int hoff;
1083  bool hasnull = false;
1084  int numberOfAttributes = tupleDescriptor->natts;
1085  int i;
1086 
1087  if (numberOfAttributes > MaxTupleAttributeNumber)
1088  ereport(ERROR,
1089  (errcode(ERRCODE_TOO_MANY_COLUMNS),
1090  errmsg("number of columns (%d) exceeds limit (%d)",
1091  numberOfAttributes, MaxTupleAttributeNumber)));
1092 
1093  /*
1094  * Check for nulls
1095  */
1096  for (i = 0; i < numberOfAttributes; i++)
1097  {
1098  if (isnull[i])
1099  {
1100  hasnull = true;
1101  break;
1102  }
1103  }
1104 
1105  /*
1106  * Determine total space needed
1107  */
1108  len = offsetof(HeapTupleHeaderData, t_bits);
1109 
1110  if (hasnull)
1111  len += BITMAPLEN(numberOfAttributes);
1112 
1113  if (tupleDescriptor->tdhasoid)
1114  len += sizeof(Oid);
1115 
1116  hoff = len = MAXALIGN(len); /* align user data safely */
1117 
1118  data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
1119 
1120  len += data_len;
1121 
1122  /*
1123  * Allocate and zero the space needed. Note that the tuple body and
1124  * HeapTupleData management structure are allocated in one chunk.
1125  */
1126  tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
1127  tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
1128 
1129  /*
1130  * And fill in the information. Note we fill the Datum fields even though
1131  * this tuple may never become a Datum. This lets HeapTupleHeaderGetDatum
1132  * identify the tuple type if needed.
1133  */
1134  tuple->t_len = len;
1135  ItemPointerSetInvalid(&(tuple->t_self));
1136  tuple->t_tableOid = InvalidOid;
1137 
1139  HeapTupleHeaderSetTypeId(td, tupleDescriptor->tdtypeid);
1140  HeapTupleHeaderSetTypMod(td, tupleDescriptor->tdtypmod);
1141  /* We also make sure that t_ctid is invalid unless explicitly set */
1142  ItemPointerSetInvalid(&(td->t_ctid));
1143 
1144  HeapTupleHeaderSetNatts(td, numberOfAttributes);
1145  td->t_hoff = hoff;
1146 
1147  if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
1148  td->t_infomask = HEAP_HASOID;
1149 
1150  heap_fill_tuple(tupleDescriptor,
1151  values,
1152  isnull,
1153  (char *) td + hoff,
1154  data_len,
1155  &td->t_infomask,
1156  (hasnull ? td->t_bits : NULL));
1157 
1158  return tuple;
1159 }
1160 
1161 /*
1162  * heap_modify_tuple
1163  * form a new tuple from an old tuple and a set of replacement values.
1164  *
1165  * The replValues, replIsnull, and doReplace arrays must be of the length
1166  * indicated by tupleDesc->natts. The new tuple is constructed using the data
1167  * from replValues/replIsnull at columns where doReplace is true, and using
1168  * the data from the old tuple at columns where doReplace is false.
1169  *
1170  * The result is allocated in the current memory context.
1171  */
1172 HeapTuple
1175  Datum *replValues,
1176  bool *replIsnull,
1177  bool *doReplace)
1178 {
1179  int numberOfAttributes = tupleDesc->natts;
1180  int attoff;
1181  Datum *values;
1182  bool *isnull;
1183  HeapTuple newTuple;
1184 
1185  /*
1186  * allocate and fill values and isnull arrays from either the tuple or the
1187  * repl information, as appropriate.
1188  *
1189  * NOTE: it's debatable whether to use heap_deform_tuple() here or just
1190  * heap_getattr() only the non-replaced columns. The latter could win if
1191  * there are many replaced columns and few non-replaced ones. However,
1192  * heap_deform_tuple costs only O(N) while the heap_getattr way would cost
1193  * O(N^2) if there are many non-replaced columns, so it seems better to
1194  * err on the side of linear cost.
1195  */
1196  values = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
1197  isnull = (bool *) palloc(numberOfAttributes * sizeof(bool));
1198 
1199  heap_deform_tuple(tuple, tupleDesc, values, isnull);
1200 
1201  for (attoff = 0; attoff < numberOfAttributes; attoff++)
1202  {
1203  if (doReplace[attoff])
1204  {
1205  values[attoff] = replValues[attoff];
1206  isnull[attoff] = replIsnull[attoff];
1207  }
1208  }
1209 
1210  /*
1211  * create a new tuple from the values and isnull arrays
1212  */
1213  newTuple = heap_form_tuple(tupleDesc, values, isnull);
1214 
1215  pfree(values);
1216  pfree(isnull);
1217 
1218  /*
1219  * copy the identification info of the old tuple: t_ctid, t_self, and OID
1220  * (if any)
1221  */
1222  newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
1223  newTuple->t_self = tuple->t_self;
1224  newTuple->t_tableOid = tuple->t_tableOid;
1225  if (tupleDesc->tdhasoid)
1226  HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
1227 
1228  return newTuple;
1229 }
1230 
1231 /*
1232  * heap_modify_tuple_by_cols
1233  * form a new tuple from an old tuple and a set of replacement values.
1234  *
1235  * This is like heap_modify_tuple, except that instead of specifying which
1236  * column(s) to replace by a boolean map, an array of target column numbers
1237  * is used. This is often more convenient when a fixed number of columns
1238  * are to be replaced. The replCols, replValues, and replIsnull arrays must
1239  * be of length nCols. Target column numbers are indexed from 1.
1240  *
1241  * The result is allocated in the current memory context.
1242  */
1243 HeapTuple
1246  int nCols,
1247  int *replCols,
1248  Datum *replValues,
1249  bool *replIsnull)
1250 {
1251  int numberOfAttributes = tupleDesc->natts;
1252  Datum *values;
1253  bool *isnull;
1254  HeapTuple newTuple;
1255  int i;
1256 
1257  /*
1258  * allocate and fill values and isnull arrays from the tuple, then replace
1259  * selected columns from the input arrays.
1260  */
1261  values = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
1262  isnull = (bool *) palloc(numberOfAttributes * sizeof(bool));
1263 
1264  heap_deform_tuple(tuple, tupleDesc, values, isnull);
1265 
1266  for (i = 0; i < nCols; i++)
1267  {
1268  int attnum = replCols[i];
1269 
1270  if (attnum <= 0 || attnum > numberOfAttributes)
1271  elog(ERROR, "invalid column number %d", attnum);
1272  values[attnum - 1] = replValues[i];
1273  isnull[attnum - 1] = replIsnull[i];
1274  }
1275 
1276  /*
1277  * create a new tuple from the values and isnull arrays
1278  */
1279  newTuple = heap_form_tuple(tupleDesc, values, isnull);
1280 
1281  pfree(values);
1282  pfree(isnull);
1283 
1284  /*
1285  * copy the identification info of the old tuple: t_ctid, t_self, and OID
1286  * (if any)
1287  */
1288  newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
1289  newTuple->t_self = tuple->t_self;
1290  newTuple->t_tableOid = tuple->t_tableOid;
1291  if (tupleDesc->tdhasoid)
1292  HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
1293 
1294  return newTuple;
1295 }
1296 
1297 /*
1298  * heap_deform_tuple
1299  * Given a tuple, extract data into values/isnull arrays; this is
1300  * the inverse of heap_form_tuple.
1301  *
1302  * Storage for the values/isnull arrays is provided by the caller;
1303  * it should be sized according to tupleDesc->natts not
1304  * HeapTupleHeaderGetNatts(tuple->t_data).
1305  *
1306  * Note that for pass-by-reference datatypes, the pointer placed
1307  * in the Datum will point into the given tuple.
1308  *
1309  * When all or most of a tuple's fields need to be extracted,
1310  * this routine will be significantly quicker than a loop around
1311  * heap_getattr; the loop will become O(N^2) as soon as any
1312  * noncacheable attribute offsets are involved.
1313  */
1314 void
1316  Datum *values, bool *isnull)
1317 {
1318  HeapTupleHeader tup = tuple->t_data;
1319  bool hasnulls = HeapTupleHasNulls(tuple);
1320  int tdesc_natts = tupleDesc->natts;
1321  int natts; /* number of atts to extract */
1322  int attnum;
1323  char *tp; /* ptr to tuple data */
1324  uint32 off; /* offset in tuple data */
1325  bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
1326  bool slow = false; /* can we use/set attcacheoff? */
1327 
1328  natts = HeapTupleHeaderGetNatts(tup);
1329 
1330  /*
1331  * In inheritance situations, it is possible that the given tuple actually
1332  * has more fields than the caller is expecting. Don't run off the end of
1333  * the caller's arrays.
1334  */
1335  natts = Min(natts, tdesc_natts);
1336 
1337  tp = (char *) tup + tup->t_hoff;
1338 
1339  off = 0;
1340 
1341  for (attnum = 0; attnum < natts; attnum++)
1342  {
1343  Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
1344 
1345  if (hasnulls && att_isnull(attnum, bp))
1346  {
1347  values[attnum] = (Datum) 0;
1348  isnull[attnum] = true;
1349  slow = true; /* can't use attcacheoff anymore */
1350  continue;
1351  }
1352 
1353  isnull[attnum] = false;
1354 
1355  if (!slow && thisatt->attcacheoff >= 0)
1356  off = thisatt->attcacheoff;
1357  else if (thisatt->attlen == -1)
1358  {
1359  /*
1360  * We can only cache the offset for a varlena attribute if the
1361  * offset is already suitably aligned, so that there would be no
1362  * pad bytes in any case: then the offset will be valid for either
1363  * an aligned or unaligned value.
1364  */
1365  if (!slow &&
1366  off == att_align_nominal(off, thisatt->attalign))
1367  thisatt->attcacheoff = off;
1368  else
1369  {
1370  off = att_align_pointer(off, thisatt->attalign, -1,
1371  tp + off);
1372  slow = true;
1373  }
1374  }
1375  else
1376  {
1377  /* not varlena, so safe to use att_align_nominal */
1378  off = att_align_nominal(off, thisatt->attalign);
1379 
1380  if (!slow)
1381  thisatt->attcacheoff = off;
1382  }
1383 
1384  values[attnum] = fetchatt(thisatt, tp + off);
1385 
1386  off = att_addlength_pointer(off, thisatt->attlen, tp + off);
1387 
1388  if (thisatt->attlen <= 0)
1389  slow = true; /* can't use attcacheoff anymore */
1390  }
1391 
1392  /*
1393  * If tuple doesn't have all the atts indicated by tupleDesc, read the
1394  * rest as nulls or missing values as appropriate.
1395  */
1396  for (; attnum < tdesc_natts; attnum++)
1397  values[attnum] = getmissingattr(tupleDesc, attnum + 1, &isnull[attnum]);
1398 }
1399 
1400 /*
1401  * slot_deform_tuple
1402  * Given a TupleTableSlot, extract data from the slot's physical tuple
1403  * into its Datum/isnull arrays. Data is extracted up through the
1404  * natts'th column (caller must ensure this is a legal column number).
1405  *
1406  * This is essentially an incremental version of heap_deform_tuple:
1407  * on each call we extract attributes up to the one needed, without
1408  * re-computing information about previously extracted attributes.
1409  * slot->tts_nvalid is the number of attributes already extracted.
1410  */
1411 static void
1413 {
1414  HeapTuple tuple = slot->tts_tuple;
1416  Datum *values = slot->tts_values;
1417  bool *isnull = slot->tts_isnull;
1418  HeapTupleHeader tup = tuple->t_data;
1419  bool hasnulls = HeapTupleHasNulls(tuple);
1420  int attnum;
1421  char *tp; /* ptr to tuple data */
1422  uint32 off; /* offset in tuple data */
1423  bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
1424  bool slow; /* can we use/set attcacheoff? */
1425 
1426  /*
1427  * Check whether the first call for this tuple, and initialize or restore
1428  * loop state.
1429  */
1430  attnum = slot->tts_nvalid;
1431  if (attnum == 0)
1432  {
1433  /* Start from the first attribute */
1434  off = 0;
1435  slow = false;
1436  }
1437  else
1438  {
1439  /* Restore state from previous execution */
1440  off = slot->tts_off;
1441  slow = slot->tts_slow;
1442  }
1443 
1444  tp = (char *) tup + tup->t_hoff;
1445 
1446  for (; attnum < natts; attnum++)
1447  {
1448  Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
1449 
1450  if (hasnulls && att_isnull(attnum, bp))
1451  {
1452  values[attnum] = (Datum) 0;
1453  isnull[attnum] = true;
1454  slow = true; /* can't use attcacheoff anymore */
1455  continue;
1456  }
1457 
1458  isnull[attnum] = false;
1459 
1460  if (!slow && thisatt->attcacheoff >= 0)
1461  off = thisatt->attcacheoff;
1462  else if (thisatt->attlen == -1)
1463  {
1464  /*
1465  * We can only cache the offset for a varlena attribute if the
1466  * offset is already suitably aligned, so that there would be no
1467  * pad bytes in any case: then the offset will be valid for either
1468  * an aligned or unaligned value.
1469  */
1470  if (!slow &&
1471  off == att_align_nominal(off, thisatt->attalign))
1472  thisatt->attcacheoff = off;
1473  else
1474  {
1475  off = att_align_pointer(off, thisatt->attalign, -1,
1476  tp + off);
1477  slow = true;
1478  }
1479  }
1480  else
1481  {
1482  /* not varlena, so safe to use att_align_nominal */
1483  off = att_align_nominal(off, thisatt->attalign);
1484 
1485  if (!slow)
1486  thisatt->attcacheoff = off;
1487  }
1488 
1489  values[attnum] = fetchatt(thisatt, tp + off);
1490 
1491  off = att_addlength_pointer(off, thisatt->attlen, tp + off);
1492 
1493  if (thisatt->attlen <= 0)
1494  slow = true; /* can't use attcacheoff anymore */
1495  }
1496 
1497  /*
1498  * Save state for next execution
1499  */
1500  slot->tts_nvalid = attnum;
1501  slot->tts_off = off;
1502  slot->tts_slow = slow;
1503 }
1504 
1505 /*
1506  * slot_getattr
1507  * This function fetches an attribute of the slot's current tuple.
1508  * It is functionally equivalent to heap_getattr, but fetches of
1509  * multiple attributes of the same tuple will be optimized better,
1510  * because we avoid O(N^2) behavior from multiple calls of
1511  * nocachegetattr(), even when attcacheoff isn't usable.
1512  *
1513  * A difference from raw heap_getattr is that attnums beyond the
1514  * slot's tupdesc's last attribute will be considered NULL even
1515  * when the physical tuple is longer than the tupdesc.
1516  */
1517 Datum
1518 slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
1519 {
1520  HeapTuple tuple = slot->tts_tuple;
1522  HeapTupleHeader tup;
1523 
1524  /*
1525  * system attributes are handled by heap_getsysattr
1526  */
1527  if (attnum <= 0)
1528  {
1529  if (tuple == NULL) /* internal error */
1530  elog(ERROR, "cannot extract system attribute from virtual tuple");
1531  if (tuple == &(slot->tts_minhdr)) /* internal error */
1532  elog(ERROR, "cannot extract system attribute from minimal tuple");
1533  return heap_getsysattr(tuple, attnum, tupleDesc, isnull);
1534  }
1535 
1536  /*
1537  * fast path if desired attribute already cached
1538  */
1539  if (attnum <= slot->tts_nvalid)
1540  {
1541  *isnull = slot->tts_isnull[attnum - 1];
1542  return slot->tts_values[attnum - 1];
1543  }
1544 
1545  /*
1546  * return NULL if attnum is out of range according to the tupdesc
1547  */
1548  if (attnum > tupleDesc->natts)
1549  {
1550  *isnull = true;
1551  return (Datum) 0;
1552  }
1553 
1554  /*
1555  * otherwise we had better have a physical tuple (tts_nvalid should equal
1556  * natts in all virtual-tuple cases)
1557  */
1558  if (tuple == NULL) /* internal error */
1559  elog(ERROR, "cannot extract attribute from empty tuple slot");
1560 
1561  /*
1562  * return NULL or missing value if attnum is out of range according to the
1563  * tuple
1564  *
1565  * (We have to check this separately because of various inheritance and
1566  * table-alteration scenarios: the tuple could be either longer or shorter
1567  * than the tupdesc.)
1568  */
1569  tup = tuple->t_data;
1570  if (attnum > HeapTupleHeaderGetNatts(tup))
1571  return getmissingattr(slot->tts_tupleDescriptor, attnum, isnull);
1572 
1573  /*
1574  * check if target attribute is null: no point in groveling through tuple
1575  */
1576  if (HeapTupleHasNulls(tuple) && att_isnull(attnum - 1, tup->t_bits))
1577  {
1578  *isnull = true;
1579  return (Datum) 0;
1580  }
1581 
1582  /*
1583  * If the attribute's column has been dropped, we force a NULL result.
1584  * This case should not happen in normal use, but it could happen if we
1585  * are executing a plan cached before the column was dropped.
1586  */
1587  if (TupleDescAttr(tupleDesc, attnum - 1)->attisdropped)
1588  {
1589  *isnull = true;
1590  return (Datum) 0;
1591  }
1592 
1593  /*
1594  * Extract the attribute, along with any preceding attributes.
1595  */
1596  slot_deform_tuple(slot, attnum);
1597 
1598  /*
1599  * The result is acquired from tts_values array.
1600  */
1601  *isnull = slot->tts_isnull[attnum - 1];
1602  return slot->tts_values[attnum - 1];
1603 }
1604 
1605 /*
1606  * slot_getallattrs
1607  * This function forces all the entries of the slot's Datum/isnull
1608  * arrays to be valid. The caller may then extract data directly
1609  * from those arrays instead of using slot_getattr.
1610  */
1611 void
1613 {
1614  int tdesc_natts = slot->tts_tupleDescriptor->natts;
1615  int attnum;
1616  HeapTuple tuple;
1617 
1618  /* Quick out if we have 'em all already */
1619  if (slot->tts_nvalid == tdesc_natts)
1620  return;
1621 
1622  /*
1623  * otherwise we had better have a physical tuple (tts_nvalid should equal
1624  * natts in all virtual-tuple cases)
1625  */
1626  tuple = slot->tts_tuple;
1627  if (tuple == NULL) /* internal error */
1628  elog(ERROR, "cannot extract attribute from empty tuple slot");
1629 
1630  /*
1631  * load up any slots available from physical tuple
1632  */
1633  attnum = HeapTupleHeaderGetNatts(tuple->t_data);
1634  attnum = Min(attnum, tdesc_natts);
1635 
1636  slot_deform_tuple(slot, attnum);
1637 
1638  attnum = slot->tts_nvalid;
1639 
1640  /*
1641  * If tuple doesn't have all the atts indicated by tupleDesc, read the
1642  * rest as NULLS or missing values.
1643  */
1644  if (attnum < tdesc_natts)
1645  slot_getmissingattrs(slot, attnum, tdesc_natts);
1646 
1647  slot->tts_nvalid = tdesc_natts;
1648 }
1649 
1650 /*
1651  * slot_getsomeattrs
1652  * This function forces the entries of the slot's Datum/isnull
1653  * arrays to be valid at least up through the attnum'th entry.
1654  */
1655 void
1657 {
1658  HeapTuple tuple;
1659  int attno;
1660 
1661  /* Quick out if we have 'em all already */
1662  if (slot->tts_nvalid >= attnum)
1663  return;
1664 
1665  /* Check for caller error */
1666  if (attnum <= 0 || attnum > slot->tts_tupleDescriptor->natts)
1667  elog(ERROR, "invalid attribute number %d", attnum);
1668 
1669  /*
1670  * otherwise we had better have a physical tuple (tts_nvalid should equal
1671  * natts in all virtual-tuple cases)
1672  */
1673  tuple = slot->tts_tuple;
1674  if (tuple == NULL) /* internal error */
1675  elog(ERROR, "cannot extract attribute from empty tuple slot");
1676 
1677  /*
1678  * load up any slots available from physical tuple
1679  */
1680  attno = HeapTupleHeaderGetNatts(tuple->t_data);
1681  attno = Min(attno, attnum);
1682 
1683  slot_deform_tuple(slot, attno);
1684 
1685  attno = slot->tts_nvalid;
1686 
1687  /*
1688  * If tuple doesn't have all the atts indicated by attnum, read the
1689  * rest as NULLs or missing values
1690  */
1691  if (attno < attnum)
1692  slot_getmissingattrs(slot, attno, attnum);
1693 
1694  slot->tts_nvalid = attnum;
1695 }
1696 
1697 /*
1698  * slot_attisnull
1699  * Detect whether an attribute of the slot is null, without
1700  * actually fetching it.
1701  */
1702 bool
1704 {
1705  HeapTuple tuple = slot->tts_tuple;
1707 
1708  /*
1709  * system attributes are handled by heap_attisnull
1710  */
1711  if (attnum <= 0)
1712  {
1713  if (tuple == NULL) /* internal error */
1714  elog(ERROR, "cannot extract system attribute from virtual tuple");
1715  if (tuple == &(slot->tts_minhdr)) /* internal error */
1716  elog(ERROR, "cannot extract system attribute from minimal tuple");
1717  return heap_attisnull(tuple, attnum, tupleDesc);
1718  }
1719 
1720  /*
1721  * fast path if desired attribute already cached
1722  */
1723  if (attnum <= slot->tts_nvalid)
1724  return slot->tts_isnull[attnum - 1];
1725 
1726  /*
1727  * return NULL if attnum is out of range according to the tupdesc
1728  */
1729  if (attnum > tupleDesc->natts)
1730  return true;
1731 
1732  /*
1733  * otherwise we had better have a physical tuple (tts_nvalid should equal
1734  * natts in all virtual-tuple cases)
1735  */
1736  if (tuple == NULL) /* internal error */
1737  elog(ERROR, "cannot extract attribute from empty tuple slot");
1738 
1739  /* and let the tuple tell it */
1740  return heap_attisnull(tuple, attnum, tupleDesc);
1741 }
1742 
1743 /*
1744  * slot_getsysattr
1745  * This function fetches a system attribute of the slot's current tuple.
1746  * Unlike slot_getattr, if the slot does not contain system attributes,
1747  * this will return false (with a NULL attribute value) instead of
1748  * throwing an error.
1749  */
1750 bool
1752  Datum *value, bool *isnull)
1753 {
1754  HeapTuple tuple = slot->tts_tuple;
1755 
1756  Assert(attnum < 0); /* else caller error */
1757  if (tuple == NULL ||
1758  tuple == &(slot->tts_minhdr))
1759  {
1760  /* No physical tuple, or minimal tuple, so fail */
1761  *value = (Datum) 0;
1762  *isnull = true;
1763  return false;
1764  }
1765  *value = heap_getsysattr(tuple, attnum, slot->tts_tupleDescriptor, isnull);
1766  return true;
1767 }
1768 
1769 /*
1770  * heap_freetuple
1771  */
1772 void
1774 {
1775  pfree(htup);
1776 }
1777 
1778 
1779 /*
1780  * heap_form_minimal_tuple
1781  * construct a MinimalTuple from the given values[] and isnull[] arrays,
1782  * which are of the length indicated by tupleDescriptor->natts
1783  *
1784  * This is exactly like heap_form_tuple() except that the result is a
1785  * "minimal" tuple lacking a HeapTupleData header as well as room for system
1786  * columns.
1787  *
1788  * The result is allocated in the current memory context.
1789  */
1792  Datum *values,
1793  bool *isnull)
1794 {
1795  MinimalTuple tuple; /* return tuple */
1796  Size len,
1797  data_len;
1798  int hoff;
1799  bool hasnull = false;
1800  int numberOfAttributes = tupleDescriptor->natts;
1801  int i;
1802 
1803  if (numberOfAttributes > MaxTupleAttributeNumber)
1804  ereport(ERROR,
1805  (errcode(ERRCODE_TOO_MANY_COLUMNS),
1806  errmsg("number of columns (%d) exceeds limit (%d)",
1807  numberOfAttributes, MaxTupleAttributeNumber)));
1808 
1809  /*
1810  * Check for nulls
1811  */
1812  for (i = 0; i < numberOfAttributes; i++)
1813  {
1814  if (isnull[i])
1815  {
1816  hasnull = true;
1817  break;
1818  }
1819  }
1820 
1821  /*
1822  * Determine total space needed
1823  */
1825 
1826  if (hasnull)
1827  len += BITMAPLEN(numberOfAttributes);
1828 
1829  if (tupleDescriptor->tdhasoid)
1830  len += sizeof(Oid);
1831 
1832  hoff = len = MAXALIGN(len); /* align user data safely */
1833 
1834  data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
1835 
1836  len += data_len;
1837 
1838  /*
1839  * Allocate and zero the space needed.
1840  */
1841  tuple = (MinimalTuple) palloc0(len);
1842 
1843  /*
1844  * And fill in the information.
1845  */
1846  tuple->t_len = len;
1847  HeapTupleHeaderSetNatts(tuple, numberOfAttributes);
1848  tuple->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
1849 
1850  if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
1851  tuple->t_infomask = HEAP_HASOID;
1852 
1853  heap_fill_tuple(tupleDescriptor,
1854  values,
1855  isnull,
1856  (char *) tuple + hoff,
1857  data_len,
1858  &tuple->t_infomask,
1859  (hasnull ? tuple->t_bits : NULL));
1860 
1861  return tuple;
1862 }
1863 
1864 /*
1865  * heap_free_minimal_tuple
1866  */
1867 void
1869 {
1870  pfree(mtup);
1871 }
1872 
1873 /*
1874  * heap_copy_minimal_tuple
1875  * copy a MinimalTuple
1876  *
1877  * The result is allocated in the current memory context.
1878  */
1881 {
1882  MinimalTuple result;
1883 
1884  result = (MinimalTuple) palloc(mtup->t_len);
1885  memcpy(result, mtup, mtup->t_len);
1886  return result;
1887 }
1888 
1889 /*
1890  * heap_tuple_from_minimal_tuple
1891  * create a HeapTuple by copying from a MinimalTuple;
1892  * system columns are filled with zeroes
1893  *
1894  * The result is allocated in the current memory context.
1895  * The HeapTuple struct, tuple header, and tuple data are all allocated
1896  * as a single palloc() block.
1897  */
1898 HeapTuple
1900 {
1901  HeapTuple result;
1902  uint32 len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
1903 
1904  result = (HeapTuple) palloc(HEAPTUPLESIZE + len);
1905  result->t_len = len;
1906  ItemPointerSetInvalid(&(result->t_self));
1907  result->t_tableOid = InvalidOid;
1908  result->t_data = (HeapTupleHeader) ((char *) result + HEAPTUPLESIZE);
1909  memcpy((char *) result->t_data + MINIMAL_TUPLE_OFFSET, mtup, mtup->t_len);
1910  memset(result->t_data, 0, offsetof(HeapTupleHeaderData, t_infomask2));
1911  return result;
1912 }
1913 
1914 /*
1915  * minimal_tuple_from_heap_tuple
1916  * create a MinimalTuple by copying from a HeapTuple
1917  *
1918  * The result is allocated in the current memory context.
1919  */
1922 {
1923  MinimalTuple result;
1924  uint32 len;
1925 
1927  len = htup->t_len - MINIMAL_TUPLE_OFFSET;
1928  result = (MinimalTuple) palloc(len);
1929  memcpy(result, (char *) htup->t_data + MINIMAL_TUPLE_OFFSET, len);
1930  result->t_len = len;
1931  return result;
1932 }
1933 
1934 /*
1935  * This mainly exists so JIT can inline the definition, but it's also
1936  * sometimes useful in debugging sessions.
1937  */
1938 size_t
1939 varsize_any(void *p)
1940 {
1941  return VARSIZE_ANY(p);
1942 }
#define HeapTupleHasVarWidth(tuple)
Definition: htup_details.h:685
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:722
#define SET_VARSIZE_SHORT(PTR, len)
Definition: postgres.h:328
void heap_fill_tuple(TupleDesc tupleDesc, Datum *values, bool *isnull, char *data, Size data_size, uint16 *infomask, bits8 *bit)
Definition: heaptuple.c:342
HeapTupleData * HeapTuple
Definition: htup.h:71
Oid tdtypeid
Definition: tupdesc.h:83
#define HeapTupleHeaderSetTypeId(tup, typeid)
Definition: htup_details.h:467
#define VARDATA(PTR)
Definition: postgres.h:302
bool tdhasoid
Definition: tupdesc.h:85
#define att_align_nominal(cur_offset, attalign)
Definition: tupmacs.h:144
#define VARATT_IS_EXTERNAL_EXPANDED(PTR)
Definition: postgres.h:322
bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]
Definition: htup_details.h:174
#define MaxTupleAttributeNumber
Definition: htup_details.h:33
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
#define VARSIZE(PTR)
Definition: postgres.h:303
#define att_isnull(ATT, BITS)
Definition: tupmacs.h:21
#define PointerGetDatum(X)
Definition: postgres.h:539
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
#define Min(x, y)
Definition: c.h:857
MissingPtr missing
Definition: tupdesc.h:43
bool slot_getsysattr(TupleTableSlot *slot, int attnum, Datum *value, bool *isnull)
Definition: heaptuple.c:1751
int errcode(int sqlerrcode)
Definition: elog.c:575
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:397
Datum * tts_values
Definition: tuptable.h:130
#define BITMAPLEN(NATTS)
Definition: htup_details.h:565
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1074
#define MinCommandIdAttributeNumber
Definition: sysattr.h:24
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
MinimalTuple heap_copy_minimal_tuple(MinimalTuple mtup)
Definition: heaptuple.c:1880
int natts
Definition: tupdesc.h:82
bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]
Definition: htup_details.h:660
bool ammissingPresent
#define fetchatt(A, T)
Definition: tupmacs.h:37
int32 tdtypmod
Definition: tupdesc.h:84
#define HeapTupleHeaderSetDatumLength(tup, len)
Definition: htup_details.h:459
#define att_align_datum(cur_offset, attalign, attlen, attdatum)
Definition: tupmacs.h:101
HeapTupleHeader t_data
Definition: htup.h:68
#define HeapTupleSetOid(tuple, oid)
Definition: htup_details.h:715
void slot_getsomeattrs(TupleTableSlot *slot, int attnum)
Definition: heaptuple.c:1656
#define VARATT_IS_EXTERNAL(PTR)
Definition: postgres.h:313
#define HeapTupleHeaderGetRawXmax(tup)
Definition: htup_details.h:380
unsigned short uint16
Definition: c.h:324
void pfree(void *pointer)
Definition: mcxt.c:1031
char * Pointer
Definition: c.h:302
static void fill_val(Form_pg_attribute att, bits8 **bit, int *bitmask, char **dataP, uint16 *infomask, Datum datum, bool isnull)
Definition: heaptuple.c:213
#define HEAP_HASNULL
Definition: htup_details.h:186
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
Datum heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: heaptuple.c:666
#define DatumGetCString(X)
Definition: postgres.h:549
#define VARATT_IS_SHORT(PTR)
Definition: postgres.h:324
HeapTupleData tts_minhdr
Definition: tuptable.h:134
void heap_free_minimal_tuple(MinimalTuple mtup)
Definition: heaptuple.c:1868
#define HeapTupleHeaderGetNatts(tup)
Definition: htup_details.h:549
ItemPointerData t_ctid
Definition: htup_details.h:157
#define VARATT_CAN_MAKE_SHORT(PTR)
Definition: postgres.h:270
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
#define HeapTupleHasNulls(tuple)
Definition: htup_details.h:679
Datum toast_flatten_tuple_to_datum(HeapTupleHeader tup, uint32 tup_len, TupleDesc tupleDesc)
Definition: tuptoaster.c:1187
MinimalTuple minimal_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
Definition: heaptuple.c:1011
bool * tts_isnull
Definition: tuptable.h:132
MinimalTupleData * MinimalTuple
Definition: htup.h:27
HeapTuple heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
Definition: heaptuple.c:1023
#define TableOidAttributeNumber
Definition: sysattr.h:27
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
unsigned int uint32
Definition: c.h:325
Oid t_tableOid
Definition: htup.h:66
Size EOH_get_flat_size(ExpandedObjectHeader *eohptr)
Definition: expandeddatum.c:75
static Datum getmissingattr(TupleDesc tupleDesc, int attnum, bool *isnull)
Definition: heaptuple.c:84
#define HEAP_HASVARWIDTH
Definition: htup_details.h:187
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition: tupmacs.h:172
#define ereport(elevel, rest)
Definition: elog.h:122
void slot_getallattrs(TupleTableSlot *slot)
Definition: heaptuple.c:1612
#define HeapTupleNoNulls(tuple)
Definition: htup_details.h:682
#define HIGHBIT
Definition: c.h:993
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition: heaptuple.c:1038
#define VARSIZE_SHORT(PTR)
Definition: postgres.h:305
#define byte(x, n)
Definition: rijndael.c:68
#define MaxCommandIdAttributeNumber
Definition: sysattr.h:26
#define MaxTransactionIdAttributeNumber
Definition: sysattr.h:25
MinimalTuple heap_form_minimal_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1791
int16 attlen
Definition: pg_attribute.h:64
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
#define VARATT_CONVERTED_SHORT_SIZE(PTR)
Definition: postgres.h:273
#define SizeofMinimalTupleHeader
Definition: htup_details.h:667
HeapTuple heap_tuple_from_minimal_tuple(MinimalTuple mtup)
Definition: heaptuple.c:1899
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
#define store_att_byval(T, newdatum, attlen)
Definition: tupmacs.h:222
uint8 bits8
Definition: c.h:332
#define TransactionIdGetDatum(X)
Definition: postgres.h:504
void slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum)
Definition: heaptuple.c:122
#define VARLENA_ATT_IS_PACKABLE(att)
Definition: heaptuple.c:71
void * palloc0(Size size)
Definition: mcxt.c:955
uintptr_t Datum
Definition: postgres.h:365
void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest)
Definition: heaptuple.c:748
#define HeapTupleHeaderSetTypMod(tup, typmod)
Definition: htup_details.h:477
void EOH_flatten_into(ExpandedObjectHeader *eohptr, void *result, Size allocated_size)
Definition: expandeddatum.c:81
#define att_align_pointer(cur_offset, attalign, attlen, attptr)
Definition: tupmacs.h:122
static struct @131 value
#define VARSIZE_ANY(PTR)
Definition: postgres.h:333
#define InvalidOid
Definition: postgres_ext.h:36
int16 attnum
Definition: pg_attribute.h:79
bool slot_attisnull(TupleTableSlot *slot, int attnum)
Definition: heaptuple.c:1703
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
Datum bit(PG_FUNCTION_ARGS)
Definition: varbit.c:362
#define Assert(condition)
Definition: c.h:699
#define HeapTupleHeaderSetNatts(tup, natts)
Definition: htup_details.h:552
TupleConstr * constr
Definition: tupdesc.h:87
size_t Size
Definition: c.h:433
#define MAXALIGN(LEN)
Definition: c.h:652
#define HeapTupleHeaderGetRawXmin(tup)
Definition: htup_details.h:313
#define MINIMAL_TUPLE_OFFSET
Definition: htup_details.h:637
Size heap_compute_data_size(TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:157
HeapTuple heap_modify_tuple_by_cols(HeapTuple tuple, TupleDesc tupleDesc, int nCols, int *replCols, Datum *replValues, bool *replIsnull)
Definition: heaptuple.c:1244
#define DatumGetPointer(X)
Definition: postgres.h:532
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1315
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define HeapTupleHeaderGetRawCommandId(tup)
Definition: htup_details.h:396
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:150
#define att_addlength_datum(cur_offset, attlen, attdatum)
Definition: tupmacs.h:160
MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup)
Definition: heaptuple.c:1921
#define HeapTupleHasExternal(tuple)
Definition: htup_details.h:691
#define ATT_IS_PACKABLE(att)
Definition: heaptuple.c:68
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define HEAPTUPLESIZE
Definition: htup.h:73
int i
#define HEAP_HASOID
Definition: htup_details.h:189
Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: heaptuple.c:1518
#define HEAP_HASEXTERNAL
Definition: htup_details.h:188
#define CommandIdGetDatum(X)
Definition: postgres.h:525
HeapTuple tts_tuple
Definition: tuptable.h:122
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1173
#define MinTransactionIdAttributeNumber
Definition: sysattr.h:23
uint32 tts_off
Definition: tuptable.h:136
size_t varsize_any(void *p)
Definition: heaptuple.c:1939
long val
Definition: informix.c:689
static void slot_deform_tuple(TupleTableSlot *slot, int natts)
Definition: heaptuple.c:1412
#define offsetof(type, field)
Definition: c.h:622
#define VARSIZE_EXTERNAL(PTR)
Definition: postgres.h:309
static void expand_tuple(HeapTuple *targetHeapTuple, MinimalTuple *targetMinimalTuple, HeapTuple sourceTuple, TupleDesc tupleDesc)
Definition: heaptuple.c:774
Datum nocachegetattr(HeapTuple tuple, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:462