Line data Source code
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-2017, 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/tuptoaster.h"
62 : #include "executor/tuptable.h"
63 : #include "utils/expandeddatum.h"
64 :
65 :
66 : /* Does att's datatype allow packing into the 1-byte-header varlena format? */
67 : #define ATT_IS_PACKABLE(att) \
68 : ((att)->attlen == -1 && (att)->attstorage != 'p')
69 : /* Use this if it's already known varlena */
70 : #define VARLENA_ATT_IS_PACKABLE(att) \
71 : ((att)->attstorage != 'p')
72 :
73 :
74 : /* ----------------------------------------------------------------
75 : * misc support routines
76 : * ----------------------------------------------------------------
77 : */
78 :
79 :
80 : /*
81 : * heap_compute_data_size
82 : * Determine size of the data area of a tuple to be constructed
83 : */
84 : Size
85 3378443 : heap_compute_data_size(TupleDesc tupleDesc,
86 : Datum *values,
87 : bool *isnull)
88 : {
89 3378443 : Size data_length = 0;
90 : int i;
91 3378443 : int numberOfAttributes = tupleDesc->natts;
92 :
93 12234221 : for (i = 0; i < numberOfAttributes; i++)
94 : {
95 : Datum val;
96 : Form_pg_attribute atti;
97 :
98 8855778 : if (isnull[i])
99 1305633 : continue;
100 :
101 7550145 : val = values[i];
102 7550145 : atti = TupleDescAttr(tupleDesc, i);
103 :
104 8312387 : if (ATT_IS_PACKABLE(atti) &&
105 1284122 : VARATT_CAN_MAKE_SHORT(DatumGetPointer(val)))
106 : {
107 : /*
108 : * we're anticipating converting to a short varlena header, so
109 : * adjust length and don't count any alignment
110 : */
111 502825 : data_length += VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val));
112 : }
113 7400759 : else if (atti->attlen == -1 &&
114 354556 : VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
115 : {
116 : /*
117 : * we want to flatten the expanded value so that the constructed
118 : * tuple doesn't depend on it
119 : */
120 385 : data_length = att_align_nominal(data_length, atti->attalign);
121 385 : data_length += EOH_get_flat_size(DatumGetEOHP(val));
122 : }
123 : else
124 : {
125 7046935 : data_length = att_align_datum(data_length, atti->attalign,
126 : atti->attlen, val);
127 7046935 : data_length = att_addlength_datum(data_length, atti->attlen,
128 : val);
129 : }
130 : }
131 :
132 3378443 : return data_length;
133 : }
134 :
135 : /*
136 : * heap_fill_tuple
137 : * Load data portion of a tuple from values/isnull arrays
138 : *
139 : * We also fill the null bitmap (if any) and set the infomask bits
140 : * that reflect the tuple's data contents.
141 : *
142 : * NOTE: it is now REQUIRED that the caller have pre-zeroed the data area.
143 : */
144 : void
145 3368987 : heap_fill_tuple(TupleDesc tupleDesc,
146 : Datum *values, bool *isnull,
147 : char *data, Size data_size,
148 : uint16 *infomask, bits8 *bit)
149 : {
150 : bits8 *bitP;
151 : int bitmask;
152 : int i;
153 3368987 : int numberOfAttributes = tupleDesc->natts;
154 :
155 : #ifdef USE_ASSERT_CHECKING
156 3368987 : char *start = data;
157 : #endif
158 :
159 3368987 : if (bit != NULL)
160 : {
161 194034 : bitP = &bit[-1];
162 194034 : bitmask = HIGHBIT;
163 : }
164 : else
165 : {
166 : /* just to keep compiler quiet */
167 3174953 : bitP = NULL;
168 3174953 : bitmask = 0;
169 : }
170 :
171 3368987 : *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTERNAL);
172 :
173 12179511 : for (i = 0; i < numberOfAttributes; i++)
174 : {
175 8810524 : Form_pg_attribute att = TupleDescAttr(tupleDesc, i);
176 : Size data_length;
177 :
178 8810524 : if (bit != NULL)
179 : {
180 2703620 : if (bitmask != HIGHBIT)
181 2304492 : bitmask <<= 1;
182 : else
183 : {
184 399128 : bitP += 1;
185 399128 : *bitP = 0x0;
186 399128 : bitmask = 1;
187 : }
188 :
189 2703620 : if (isnull[i])
190 : {
191 1303400 : *infomask |= HEAP_HASNULL;
192 1303400 : continue;
193 : }
194 :
195 1400220 : *bitP |= bitmask;
196 : }
197 :
198 : /*
199 : * XXX we use the att_align macros on the pointer value itself, not on
200 : * an offset. This is a bit of a hack.
201 : */
202 :
203 7507124 : if (att->attbyval)
204 : {
205 : /* pass-by-value */
206 5653219 : data = (char *) att_align_nominal(data, att->attalign);
207 5653219 : store_att_byval(data, values[i], att->attlen);
208 5653219 : data_length = att->attlen;
209 : }
210 1853905 : else if (att->attlen == -1)
211 : {
212 : /* varlena */
213 843438 : Pointer val = DatumGetPointer(values[i]);
214 :
215 843438 : *infomask |= HEAP_HASVARWIDTH;
216 843438 : if (VARATT_IS_EXTERNAL(val))
217 : {
218 585 : if (VARATT_IS_EXTERNAL_EXPANDED(val))
219 385 : {
220 : /*
221 : * we want to flatten the expanded value so that the
222 : * constructed tuple doesn't depend on it
223 : */
224 385 : ExpandedObjectHeader *eoh = DatumGetEOHP(values[i]);
225 :
226 385 : data = (char *) att_align_nominal(data,
227 : att->attalign);
228 385 : data_length = EOH_get_flat_size(eoh);
229 385 : EOH_flatten_into(eoh, data, data_length);
230 : }
231 : else
232 : {
233 200 : *infomask |= HEAP_HASEXTERNAL;
234 : /* no alignment, since it's short by definition */
235 200 : data_length = VARSIZE_EXTERNAL(val);
236 200 : memcpy(data, val, data_length);
237 : }
238 : }
239 842853 : else if (VARATT_IS_SHORT(val))
240 : {
241 : /* no alignment for short varlenas */
242 226712 : data_length = VARSIZE_SHORT(val);
243 226712 : memcpy(data, val, data_length);
244 : }
245 1138270 : else if (VARLENA_ATT_IS_PACKABLE(att) &&
246 1041816 : VARATT_CAN_MAKE_SHORT(val))
247 : {
248 : /* convert to short varlena -- no alignment */
249 502825 : data_length = VARATT_CONVERTED_SHORT_SIZE(val);
250 502825 : SET_VARSIZE_SHORT(data, data_length);
251 502825 : memcpy(data + 1, VARDATA(val), data_length - 1);
252 : }
253 : else
254 : {
255 : /* full 4-byte header varlena */
256 113316 : data = (char *) att_align_nominal(data,
257 : att->attalign);
258 113316 : data_length = VARSIZE(val);
259 113316 : memcpy(data, val, data_length);
260 : }
261 : }
262 1010467 : else if (att->attlen == -2)
263 : {
264 : /* cstring ... never needs alignment */
265 59419 : *infomask |= HEAP_HASVARWIDTH;
266 59419 : Assert(att->attalign == 'c');
267 59419 : data_length = strlen(DatumGetCString(values[i])) + 1;
268 59419 : memcpy(data, DatumGetPointer(values[i]), data_length);
269 : }
270 : else
271 : {
272 : /* fixed-length pass-by-reference */
273 951048 : data = (char *) att_align_nominal(data, att->attalign);
274 951048 : Assert(att->attlen > 0);
275 951048 : data_length = att->attlen;
276 951048 : memcpy(data, DatumGetPointer(values[i]), data_length);
277 : }
278 :
279 7507124 : data += data_length;
280 : }
281 :
282 3368987 : Assert((data - start) == data_size);
283 3368987 : }
284 :
285 :
286 : /* ----------------------------------------------------------------
287 : * heap tuple interface
288 : * ----------------------------------------------------------------
289 : */
290 :
291 : /* ----------------
292 : * heap_attisnull - returns TRUE iff tuple attribute is not present
293 : * ----------------
294 : */
295 : bool
296 375429 : heap_attisnull(HeapTuple tup, int attnum)
297 : {
298 375429 : if (attnum > (int) HeapTupleHeaderGetNatts(tup->t_data))
299 1 : return true;
300 :
301 375428 : if (attnum > 0)
302 : {
303 375428 : if (HeapTupleNoNulls(tup))
304 83140 : return false;
305 292288 : return att_isnull(attnum - 1, tup->t_data->t_bits);
306 : }
307 :
308 0 : switch (attnum)
309 : {
310 : case TableOidAttributeNumber:
311 : case SelfItemPointerAttributeNumber:
312 : case ObjectIdAttributeNumber:
313 : case MinTransactionIdAttributeNumber:
314 : case MinCommandIdAttributeNumber:
315 : case MaxTransactionIdAttributeNumber:
316 : case MaxCommandIdAttributeNumber:
317 : /* these are never null */
318 0 : break;
319 :
320 : default:
321 0 : elog(ERROR, "invalid attnum: %d", attnum);
322 : }
323 :
324 0 : return false;
325 : }
326 :
327 : /* ----------------
328 : * nocachegetattr
329 : *
330 : * This only gets called from fastgetattr() macro, in cases where
331 : * we can't use a cacheoffset and the value is not null.
332 : *
333 : * This caches attribute offsets in the attribute descriptor.
334 : *
335 : * An alternative way to speed things up would be to cache offsets
336 : * with the tuple, but that seems more difficult unless you take
337 : * the storage hit of actually putting those offsets into the
338 : * tuple you send to disk. Yuck.
339 : *
340 : * This scheme will be slightly slower than that, but should
341 : * perform well for queries which hit large #'s of tuples. After
342 : * you cache the offsets once, examining all the other tuples using
343 : * the same attribute descriptor will go much quicker. -cim 5/4/91
344 : *
345 : * NOTE: if you need to change this code, see also heap_deform_tuple.
346 : * Also see nocache_index_getattr, which is the same code for index
347 : * tuples.
348 : * ----------------
349 : */
350 : Datum
351 3860262 : nocachegetattr(HeapTuple tuple,
352 : int attnum,
353 : TupleDesc tupleDesc)
354 : {
355 3860262 : HeapTupleHeader tup = tuple->t_data;
356 : char *tp; /* ptr to data part of tuple */
357 3860262 : bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
358 3860262 : bool slow = false; /* do we have to walk attrs? */
359 : int off; /* current offset within data */
360 :
361 : /* ----------------
362 : * Three cases:
363 : *
364 : * 1: No nulls and no variable-width attributes.
365 : * 2: Has a null or a var-width AFTER att.
366 : * 3: Has nulls or var-widths BEFORE att.
367 : * ----------------
368 : */
369 :
370 3860262 : attnum--;
371 :
372 3860262 : if (!HeapTupleNoNulls(tuple))
373 : {
374 : /*
375 : * there's a null somewhere in the tuple
376 : *
377 : * check to see if any preceding bits are null...
378 : */
379 3749316 : int byte = attnum >> 3;
380 3749316 : int finalbit = attnum & 0x07;
381 :
382 : /* check for nulls "before" final bit of last byte */
383 3749316 : if ((~bp[byte]) & ((1 << finalbit) - 1))
384 1912807 : slow = true;
385 : else
386 : {
387 : /* check for nulls in any "earlier" bytes */
388 : int i;
389 :
390 2225921 : for (i = 0; i < byte; i++)
391 : {
392 390436 : if (bp[i] != 0xFF)
393 : {
394 1024 : slow = true;
395 1024 : break;
396 : }
397 : }
398 : }
399 : }
400 :
401 3860262 : tp = (char *) tup + tup->t_hoff;
402 :
403 3860262 : if (!slow)
404 : {
405 : Form_pg_attribute att;
406 :
407 : /*
408 : * If we get here, there are no nulls up to and including the target
409 : * attribute. If we have a cached offset, we can use it.
410 : */
411 1946431 : att = TupleDescAttr(tupleDesc, attnum);
412 1946431 : if (att->attcacheoff >= 0)
413 1785639 : return fetchatt(att, tp + att->attcacheoff);
414 :
415 : /*
416 : * Otherwise, check for non-fixed-length attrs up to and including
417 : * target. If there aren't any, it's safe to cheaply initialize the
418 : * cached offsets for these attrs.
419 : */
420 160792 : if (HeapTupleHasVarWidth(tuple))
421 : {
422 : int j;
423 :
424 840434 : for (j = 0; j <= attnum; j++)
425 : {
426 839315 : if (TupleDescAttr(tupleDesc, j)->attlen <= 0)
427 : {
428 155128 : slow = true;
429 155128 : break;
430 : }
431 : }
432 : }
433 : }
434 :
435 2074623 : if (!slow)
436 : {
437 5664 : int natts = tupleDesc->natts;
438 5664 : int j = 1;
439 :
440 : /*
441 : * If we get here, we have a tuple with no nulls or var-widths up to
442 : * and including the target attribute, so we can use the cached offset
443 : * ... only we don't have it yet, or we'd not have got here. Since
444 : * it's cheap to compute offsets for fixed-width columns, we take the
445 : * opportunity to initialize the cached offsets for *all* the leading
446 : * fixed-width columns, in hope of avoiding future visits to this
447 : * routine.
448 : */
449 5664 : TupleDescAttr(tupleDesc, 0)->attcacheoff = 0;
450 :
451 : /* we might have set some offsets in the slow path previously */
452 11367 : while (j < natts && TupleDescAttr(tupleDesc, j)->attcacheoff > 0)
453 39 : j++;
454 :
455 11328 : off = TupleDescAttr(tupleDesc, j - 1)->attcacheoff +
456 5664 : TupleDescAttr(tupleDesc, j - 1)->attlen;
457 :
458 33030 : for (; j < natts; j++)
459 : {
460 29187 : Form_pg_attribute att = TupleDescAttr(tupleDesc, j);
461 :
462 29187 : if (att->attlen <= 0)
463 1821 : break;
464 :
465 27366 : off = att_align_nominal(off, att->attalign);
466 :
467 27366 : att->attcacheoff = off;
468 :
469 27366 : off += att->attlen;
470 : }
471 :
472 5664 : Assert(j > attnum);
473 :
474 5664 : off = TupleDescAttr(tupleDesc, attnum)->attcacheoff;
475 : }
476 : else
477 : {
478 2068959 : bool usecache = true;
479 : int i;
480 :
481 : /*
482 : * Now we know that we have to walk the tuple CAREFULLY. But we still
483 : * might be able to cache some offsets for next time.
484 : *
485 : * Note - This loop is a little tricky. For each non-null attribute,
486 : * we have to first account for alignment padding before the attr,
487 : * then advance over the attr based on its length. Nulls have no
488 : * storage and no alignment padding either. We can use/set
489 : * attcacheoff until we reach either a null or a var-width attribute.
490 : */
491 2068959 : off = 0;
492 10277856 : for (i = 0;; i++) /* loop exit is at "break" */
493 : {
494 10277856 : Form_pg_attribute att = TupleDescAttr(tupleDesc, i);
495 :
496 10277856 : if (HeapTupleHasNulls(tuple) && att_isnull(i, bp))
497 : {
498 2897712 : usecache = false;
499 2897712 : continue; /* this cannot be the target att */
500 : }
501 :
502 : /* If we know the next offset, we can skip the rest */
503 7380144 : if (usecache && att->attcacheoff >= 0)
504 3221044 : off = att->attcacheoff;
505 4159100 : else if (att->attlen == -1)
506 : {
507 : /*
508 : * We can only cache the offset for a varlena attribute if the
509 : * offset is already suitably aligned, so that there would be
510 : * no pad bytes in any case: then the offset will be valid for
511 : * either an aligned or unaligned value.
512 : */
513 574451 : if (usecache &&
514 11608 : off == att_align_nominal(off, att->attalign))
515 4000 : att->attcacheoff = off;
516 : else
517 : {
518 558843 : off = att_align_pointer(off, att->attalign, -1,
519 : tp + off);
520 558843 : usecache = false;
521 : }
522 : }
523 : else
524 : {
525 : /* not varlena, so safe to use att_align_nominal */
526 3596257 : off = att_align_nominal(off, att->attalign);
527 :
528 3596257 : if (usecache)
529 16252 : att->attcacheoff = off;
530 : }
531 :
532 7380144 : if (i == attnum)
533 2068959 : break;
534 :
535 5311185 : off = att_addlength_pointer(off, att->attlen, tp + off);
536 :
537 5311185 : if (usecache && att->attlen <= 0)
538 1972943 : usecache = false;
539 8208897 : }
540 : }
541 :
542 2074623 : return fetchatt(TupleDescAttr(tupleDesc, attnum), tp + off);
543 : }
544 :
545 : /* ----------------
546 : * heap_getsysattr
547 : *
548 : * Fetch the value of a system attribute for a tuple.
549 : *
550 : * This is a support routine for the heap_getattr macro. The macro
551 : * has already determined that the attnum refers to a system attribute.
552 : * ----------------
553 : */
554 : Datum
555 2256895 : heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
556 : {
557 : Datum result;
558 :
559 2256895 : Assert(tup);
560 :
561 : /* Currently, no sys attribute ever reads as NULL. */
562 2256895 : *isnull = false;
563 :
564 2256895 : switch (attnum)
565 : {
566 : case SelfItemPointerAttributeNumber:
567 : /* pass-by-reference datatype */
568 165600 : result = PointerGetDatum(&(tup->t_self));
569 165600 : break;
570 : case ObjectIdAttributeNumber:
571 2073339 : result = ObjectIdGetDatum(HeapTupleGetOid(tup));
572 2073339 : break;
573 : case MinTransactionIdAttributeNumber:
574 6 : result = TransactionIdGetDatum(HeapTupleHeaderGetRawXmin(tup->t_data));
575 6 : break;
576 : case MaxTransactionIdAttributeNumber:
577 0 : result = TransactionIdGetDatum(HeapTupleHeaderGetRawXmax(tup->t_data));
578 0 : break;
579 : case MinCommandIdAttributeNumber:
580 : case MaxCommandIdAttributeNumber:
581 :
582 : /*
583 : * cmin and cmax are now both aliases for the same field, which
584 : * can in fact also be a combo command id. XXX perhaps we should
585 : * return the "real" cmin or cmax if possible, that is if we are
586 : * inside the originating transaction?
587 : */
588 31 : result = CommandIdGetDatum(HeapTupleHeaderGetRawCommandId(tup->t_data));
589 31 : break;
590 : case TableOidAttributeNumber:
591 17919 : result = ObjectIdGetDatum(tup->t_tableOid);
592 17919 : break;
593 : default:
594 0 : elog(ERROR, "invalid attnum: %d", attnum);
595 : result = 0; /* keep compiler quiet */
596 : break;
597 : }
598 2256895 : return result;
599 : }
600 :
601 : /* ----------------
602 : * heap_copytuple
603 : *
604 : * returns a copy of an entire tuple
605 : *
606 : * The HeapTuple struct, tuple header, and tuple data are all allocated
607 : * as a single palloc() block.
608 : * ----------------
609 : */
610 : HeapTuple
611 523810 : heap_copytuple(HeapTuple tuple)
612 : {
613 : HeapTuple newTuple;
614 :
615 523810 : if (!HeapTupleIsValid(tuple) || tuple->t_data == NULL)
616 0 : return NULL;
617 :
618 523810 : newTuple = (HeapTuple) palloc(HEAPTUPLESIZE + tuple->t_len);
619 523810 : newTuple->t_len = tuple->t_len;
620 523810 : newTuple->t_self = tuple->t_self;
621 523810 : newTuple->t_tableOid = tuple->t_tableOid;
622 523810 : newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
623 523810 : memcpy((char *) newTuple->t_data, (char *) tuple->t_data, tuple->t_len);
624 523810 : return newTuple;
625 : }
626 :
627 : /* ----------------
628 : * heap_copytuple_with_tuple
629 : *
630 : * copy a tuple into a caller-supplied HeapTuple management struct
631 : *
632 : * Note that after calling this function, the "dest" HeapTuple will not be
633 : * allocated as a single palloc() block (unlike with heap_copytuple()).
634 : * ----------------
635 : */
636 : void
637 153951 : heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest)
638 : {
639 153951 : if (!HeapTupleIsValid(src) || src->t_data == NULL)
640 : {
641 0 : dest->t_data = NULL;
642 153951 : return;
643 : }
644 :
645 153951 : dest->t_len = src->t_len;
646 153951 : dest->t_self = src->t_self;
647 153951 : dest->t_tableOid = src->t_tableOid;
648 153951 : dest->t_data = (HeapTupleHeader) palloc(src->t_len);
649 153951 : memcpy((char *) dest->t_data, (char *) src->t_data, src->t_len);
650 : }
651 :
652 : /* ----------------
653 : * heap_copy_tuple_as_datum
654 : *
655 : * copy a tuple as a composite-type Datum
656 : * ----------------
657 : */
658 : Datum
659 9970 : heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
660 : {
661 : HeapTupleHeader td;
662 :
663 : /*
664 : * If the tuple contains any external TOAST pointers, we have to inline
665 : * those fields to meet the conventions for composite-type Datums.
666 : */
667 9970 : if (HeapTupleHasExternal(tuple))
668 8 : return toast_flatten_tuple_to_datum(tuple->t_data,
669 : tuple->t_len,
670 : tupleDesc);
671 :
672 : /*
673 : * Fast path for easy case: just make a palloc'd copy and insert the
674 : * correct composite-Datum header fields (since those may not be set if
675 : * the given tuple came from disk, rather than from heap_form_tuple).
676 : */
677 9962 : td = (HeapTupleHeader) palloc(tuple->t_len);
678 9962 : memcpy((char *) td, (char *) tuple->t_data, tuple->t_len);
679 :
680 9962 : HeapTupleHeaderSetDatumLength(td, tuple->t_len);
681 9962 : HeapTupleHeaderSetTypeId(td, tupleDesc->tdtypeid);
682 9962 : HeapTupleHeaderSetTypMod(td, tupleDesc->tdtypmod);
683 :
684 9962 : return PointerGetDatum(td);
685 : }
686 :
687 : /*
688 : * heap_form_tuple
689 : * construct a tuple from the given values[] and isnull[] arrays,
690 : * which are of the length indicated by tupleDescriptor->natts
691 : *
692 : * The result is allocated in the current memory context.
693 : */
694 : HeapTuple
695 999378 : heap_form_tuple(TupleDesc tupleDescriptor,
696 : Datum *values,
697 : bool *isnull)
698 : {
699 : HeapTuple tuple; /* return tuple */
700 : HeapTupleHeader td; /* tuple data */
701 : Size len,
702 : data_len;
703 : int hoff;
704 999378 : bool hasnull = false;
705 999378 : int numberOfAttributes = tupleDescriptor->natts;
706 : int i;
707 :
708 999378 : if (numberOfAttributes > MaxTupleAttributeNumber)
709 0 : ereport(ERROR,
710 : (errcode(ERRCODE_TOO_MANY_COLUMNS),
711 : errmsg("number of columns (%d) exceeds limit (%d)",
712 : numberOfAttributes, MaxTupleAttributeNumber)));
713 :
714 : /*
715 : * Check for nulls
716 : */
717 4569604 : for (i = 0; i < numberOfAttributes; i++)
718 : {
719 3759662 : if (isnull[i])
720 : {
721 189436 : hasnull = true;
722 189436 : break;
723 : }
724 : }
725 :
726 : /*
727 : * Determine total space needed
728 : */
729 999378 : len = offsetof(HeapTupleHeaderData, t_bits);
730 :
731 999378 : if (hasnull)
732 189436 : len += BITMAPLEN(numberOfAttributes);
733 :
734 999378 : if (tupleDescriptor->tdhasoid)
735 86624 : len += sizeof(Oid);
736 :
737 999378 : hoff = len = MAXALIGN(len); /* align user data safely */
738 :
739 999378 : data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
740 :
741 999378 : len += data_len;
742 :
743 : /*
744 : * Allocate and zero the space needed. Note that the tuple body and
745 : * HeapTupleData management structure are allocated in one chunk.
746 : */
747 999378 : tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
748 999378 : tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
749 :
750 : /*
751 : * And fill in the information. Note we fill the Datum fields even though
752 : * this tuple may never become a Datum. This lets HeapTupleHeaderGetDatum
753 : * identify the tuple type if needed.
754 : */
755 999378 : tuple->t_len = len;
756 999378 : ItemPointerSetInvalid(&(tuple->t_self));
757 999378 : tuple->t_tableOid = InvalidOid;
758 :
759 999378 : HeapTupleHeaderSetDatumLength(td, len);
760 999378 : HeapTupleHeaderSetTypeId(td, tupleDescriptor->tdtypeid);
761 999378 : HeapTupleHeaderSetTypMod(td, tupleDescriptor->tdtypmod);
762 : /* We also make sure that t_ctid is invalid unless explicitly set */
763 999378 : ItemPointerSetInvalid(&(td->t_ctid));
764 :
765 999378 : HeapTupleHeaderSetNatts(td, numberOfAttributes);
766 999378 : td->t_hoff = hoff;
767 :
768 999378 : if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
769 86624 : td->t_infomask = HEAP_HASOID;
770 :
771 999378 : heap_fill_tuple(tupleDescriptor,
772 : values,
773 : isnull,
774 : (char *) td + hoff,
775 : data_len,
776 : &td->t_infomask,
777 : (hasnull ? td->t_bits : NULL));
778 :
779 999378 : return tuple;
780 : }
781 :
782 : /*
783 : * heap_modify_tuple
784 : * form a new tuple from an old tuple and a set of replacement values.
785 : *
786 : * The replValues, replIsnull, and doReplace arrays must be of the length
787 : * indicated by tupleDesc->natts. The new tuple is constructed using the data
788 : * from replValues/replIsnull at columns where doReplace is true, and using
789 : * the data from the old tuple at columns where doReplace is false.
790 : *
791 : * The result is allocated in the current memory context.
792 : */
793 : HeapTuple
794 1458 : heap_modify_tuple(HeapTuple tuple,
795 : TupleDesc tupleDesc,
796 : Datum *replValues,
797 : bool *replIsnull,
798 : bool *doReplace)
799 : {
800 1458 : int numberOfAttributes = tupleDesc->natts;
801 : int attoff;
802 : Datum *values;
803 : bool *isnull;
804 : HeapTuple newTuple;
805 :
806 : /*
807 : * allocate and fill values and isnull arrays from either the tuple or the
808 : * repl information, as appropriate.
809 : *
810 : * NOTE: it's debatable whether to use heap_deform_tuple() here or just
811 : * heap_getattr() only the non-replaced columns. The latter could win if
812 : * there are many replaced columns and few non-replaced ones. However,
813 : * heap_deform_tuple costs only O(N) while the heap_getattr way would cost
814 : * O(N^2) if there are many non-replaced columns, so it seems better to
815 : * err on the side of linear cost.
816 : */
817 1458 : values = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
818 1458 : isnull = (bool *) palloc(numberOfAttributes * sizeof(bool));
819 :
820 1458 : heap_deform_tuple(tuple, tupleDesc, values, isnull);
821 :
822 36321 : for (attoff = 0; attoff < numberOfAttributes; attoff++)
823 : {
824 34863 : if (doReplace[attoff])
825 : {
826 13360 : values[attoff] = replValues[attoff];
827 13360 : isnull[attoff] = replIsnull[attoff];
828 : }
829 : }
830 :
831 : /*
832 : * create a new tuple from the values and isnull arrays
833 : */
834 1458 : newTuple = heap_form_tuple(tupleDesc, values, isnull);
835 :
836 1458 : pfree(values);
837 1458 : pfree(isnull);
838 :
839 : /*
840 : * copy the identification info of the old tuple: t_ctid, t_self, and OID
841 : * (if any)
842 : */
843 1458 : newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
844 1458 : newTuple->t_self = tuple->t_self;
845 1458 : newTuple->t_tableOid = tuple->t_tableOid;
846 1458 : if (tupleDesc->tdhasoid)
847 1010 : HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
848 :
849 1458 : return newTuple;
850 : }
851 :
852 : /*
853 : * heap_modify_tuple_by_cols
854 : * form a new tuple from an old tuple and a set of replacement values.
855 : *
856 : * This is like heap_modify_tuple, except that instead of specifying which
857 : * column(s) to replace by a boolean map, an array of target column numbers
858 : * is used. This is often more convenient when a fixed number of columns
859 : * are to be replaced. The replCols, replValues, and replIsnull arrays must
860 : * be of length nCols. Target column numbers are indexed from 1.
861 : *
862 : * The result is allocated in the current memory context.
863 : */
864 : HeapTuple
865 92 : heap_modify_tuple_by_cols(HeapTuple tuple,
866 : TupleDesc tupleDesc,
867 : int nCols,
868 : int *replCols,
869 : Datum *replValues,
870 : bool *replIsnull)
871 : {
872 92 : int numberOfAttributes = tupleDesc->natts;
873 : Datum *values;
874 : bool *isnull;
875 : HeapTuple newTuple;
876 : int i;
877 :
878 : /*
879 : * allocate and fill values and isnull arrays from the tuple, then replace
880 : * selected columns from the input arrays.
881 : */
882 92 : values = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
883 92 : isnull = (bool *) palloc(numberOfAttributes * sizeof(bool));
884 :
885 92 : heap_deform_tuple(tuple, tupleDesc, values, isnull);
886 :
887 184 : for (i = 0; i < nCols; i++)
888 : {
889 92 : int attnum = replCols[i];
890 :
891 92 : if (attnum <= 0 || attnum > numberOfAttributes)
892 0 : elog(ERROR, "invalid column number %d", attnum);
893 92 : values[attnum - 1] = replValues[i];
894 92 : isnull[attnum - 1] = replIsnull[i];
895 : }
896 :
897 : /*
898 : * create a new tuple from the values and isnull arrays
899 : */
900 92 : newTuple = heap_form_tuple(tupleDesc, values, isnull);
901 :
902 92 : pfree(values);
903 92 : pfree(isnull);
904 :
905 : /*
906 : * copy the identification info of the old tuple: t_ctid, t_self, and OID
907 : * (if any)
908 : */
909 92 : newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
910 92 : newTuple->t_self = tuple->t_self;
911 92 : newTuple->t_tableOid = tuple->t_tableOid;
912 92 : if (tupleDesc->tdhasoid)
913 25 : HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
914 :
915 92 : return newTuple;
916 : }
917 :
918 : /*
919 : * heap_deform_tuple
920 : * Given a tuple, extract data into values/isnull arrays; this is
921 : * the inverse of heap_form_tuple.
922 : *
923 : * Storage for the values/isnull arrays is provided by the caller;
924 : * it should be sized according to tupleDesc->natts not
925 : * HeapTupleHeaderGetNatts(tuple->t_data).
926 : *
927 : * Note that for pass-by-reference datatypes, the pointer placed
928 : * in the Datum will point into the given tuple.
929 : *
930 : * When all or most of a tuple's fields need to be extracted,
931 : * this routine will be significantly quicker than a loop around
932 : * heap_getattr; the loop will become O(N^2) as soon as any
933 : * noncacheable attribute offsets are involved.
934 : */
935 : void
936 36216 : heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
937 : Datum *values, bool *isnull)
938 : {
939 36216 : HeapTupleHeader tup = tuple->t_data;
940 36216 : bool hasnulls = HeapTupleHasNulls(tuple);
941 36216 : int tdesc_natts = tupleDesc->natts;
942 : int natts; /* number of atts to extract */
943 : int attnum;
944 : char *tp; /* ptr to tuple data */
945 : long off; /* offset in tuple data */
946 36216 : bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
947 36216 : bool slow = false; /* can we use/set attcacheoff? */
948 :
949 36216 : natts = HeapTupleHeaderGetNatts(tup);
950 :
951 : /*
952 : * In inheritance situations, it is possible that the given tuple actually
953 : * has more fields than the caller is expecting. Don't run off the end of
954 : * the caller's arrays.
955 : */
956 36216 : natts = Min(natts, tdesc_natts);
957 :
958 36216 : tp = (char *) tup + tup->t_hoff;
959 :
960 36216 : off = 0;
961 :
962 501408 : for (attnum = 0; attnum < natts; attnum++)
963 : {
964 465192 : Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
965 :
966 465192 : if (hasnulls && att_isnull(attnum, bp))
967 : {
968 24645 : values[attnum] = (Datum) 0;
969 24645 : isnull[attnum] = true;
970 24645 : slow = true; /* can't use attcacheoff anymore */
971 24645 : continue;
972 : }
973 :
974 440547 : isnull[attnum] = false;
975 :
976 440547 : if (!slow && thisatt->attcacheoff >= 0)
977 419573 : off = thisatt->attcacheoff;
978 20974 : else if (thisatt->attlen == -1)
979 : {
980 : /*
981 : * We can only cache the offset for a varlena attribute if the
982 : * offset is already suitably aligned, so that there would be no
983 : * pad bytes in any case: then the offset will be valid for either
984 : * an aligned or unaligned value.
985 : */
986 9225 : if (!slow &&
987 649 : off == att_align_nominal(off, thisatt->attalign))
988 107 : thisatt->attcacheoff = off;
989 : else
990 : {
991 8469 : off = att_align_pointer(off, thisatt->attalign, -1,
992 : tp + off);
993 8469 : slow = true;
994 : }
995 : }
996 : else
997 : {
998 : /* not varlena, so safe to use att_align_nominal */
999 12398 : off = att_align_nominal(off, thisatt->attalign);
1000 :
1001 12398 : if (!slow)
1002 1716 : thisatt->attcacheoff = off;
1003 : }
1004 :
1005 440547 : values[attnum] = fetchatt(thisatt, tp + off);
1006 :
1007 440547 : off = att_addlength_pointer(off, thisatt->attlen, tp + off);
1008 :
1009 440547 : if (thisatt->attlen <= 0)
1010 16835 : slow = true; /* can't use attcacheoff anymore */
1011 : }
1012 :
1013 : /*
1014 : * If tuple doesn't have all the atts indicated by tupleDesc, read the
1015 : * rest as null
1016 : */
1017 36220 : for (; attnum < tdesc_natts; attnum++)
1018 : {
1019 4 : values[attnum] = (Datum) 0;
1020 4 : isnull[attnum] = true;
1021 : }
1022 36216 : }
1023 :
1024 : /*
1025 : * slot_deform_tuple
1026 : * Given a TupleTableSlot, extract data from the slot's physical tuple
1027 : * into its Datum/isnull arrays. Data is extracted up through the
1028 : * natts'th column (caller must ensure this is a legal column number).
1029 : *
1030 : * This is essentially an incremental version of heap_deform_tuple:
1031 : * on each call we extract attributes up to the one needed, without
1032 : * re-computing information about previously extracted attributes.
1033 : * slot->tts_nvalid is the number of attributes already extracted.
1034 : */
1035 : static void
1036 5626272 : slot_deform_tuple(TupleTableSlot *slot, int natts)
1037 : {
1038 5626272 : HeapTuple tuple = slot->tts_tuple;
1039 5626272 : TupleDesc tupleDesc = slot->tts_tupleDescriptor;
1040 5626272 : Datum *values = slot->tts_values;
1041 5626272 : bool *isnull = slot->tts_isnull;
1042 5626272 : HeapTupleHeader tup = tuple->t_data;
1043 5626272 : bool hasnulls = HeapTupleHasNulls(tuple);
1044 : int attnum;
1045 : char *tp; /* ptr to tuple data */
1046 : long off; /* offset in tuple data */
1047 5626272 : bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
1048 : bool slow; /* can we use/set attcacheoff? */
1049 :
1050 : /*
1051 : * Check whether the first call for this tuple, and initialize or restore
1052 : * loop state.
1053 : */
1054 5626272 : attnum = slot->tts_nvalid;
1055 5626272 : if (attnum == 0)
1056 : {
1057 : /* Start from the first attribute */
1058 4967053 : off = 0;
1059 4967053 : slow = false;
1060 : }
1061 : else
1062 : {
1063 : /* Restore state from previous execution */
1064 659219 : off = slot->tts_off;
1065 659219 : slow = slot->tts_slow;
1066 : }
1067 :
1068 5626272 : tp = (char *) tup + tup->t_hoff;
1069 :
1070 29005822 : for (; attnum < natts; attnum++)
1071 : {
1072 23379550 : Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
1073 :
1074 23379550 : if (hasnulls && att_isnull(attnum, bp))
1075 : {
1076 663804 : values[attnum] = (Datum) 0;
1077 663804 : isnull[attnum] = true;
1078 663804 : slow = true; /* can't use attcacheoff anymore */
1079 663804 : continue;
1080 : }
1081 :
1082 22715746 : isnull[attnum] = false;
1083 :
1084 22715746 : if (!slow && thisatt->attcacheoff >= 0)
1085 21518058 : off = thisatt->attcacheoff;
1086 1197688 : else if (thisatt->attlen == -1)
1087 : {
1088 : /*
1089 : * We can only cache the offset for a varlena attribute if the
1090 : * offset is already suitably aligned, so that there would be no
1091 : * pad bytes in any case: then the offset will be valid for either
1092 : * an aligned or unaligned value.
1093 : */
1094 405671 : if (!slow &&
1095 7039 : off == att_align_nominal(off, thisatt->attalign))
1096 3330 : thisatt->attcacheoff = off;
1097 : else
1098 : {
1099 395302 : off = att_align_pointer(off, thisatt->attalign, -1,
1100 : tp + off);
1101 395302 : slow = true;
1102 : }
1103 : }
1104 : else
1105 : {
1106 : /* not varlena, so safe to use att_align_nominal */
1107 799056 : off = att_align_nominal(off, thisatt->attalign);
1108 :
1109 799056 : if (!slow)
1110 17379 : thisatt->attcacheoff = off;
1111 : }
1112 :
1113 22715746 : values[attnum] = fetchatt(thisatt, tp + off);
1114 :
1115 22715746 : off = att_addlength_pointer(off, thisatt->attlen, tp + off);
1116 :
1117 22715746 : if (thisatt->attlen <= 0)
1118 1477422 : slow = true; /* can't use attcacheoff anymore */
1119 : }
1120 :
1121 : /*
1122 : * Save state for next execution
1123 : */
1124 5626272 : slot->tts_nvalid = attnum;
1125 5626272 : slot->tts_off = off;
1126 5626272 : slot->tts_slow = slow;
1127 5626272 : }
1128 :
1129 : /*
1130 : * slot_getattr
1131 : * This function fetches an attribute of the slot's current tuple.
1132 : * It is functionally equivalent to heap_getattr, but fetches of
1133 : * multiple attributes of the same tuple will be optimized better,
1134 : * because we avoid O(N^2) behavior from multiple calls of
1135 : * nocachegetattr(), even when attcacheoff isn't usable.
1136 : *
1137 : * A difference from raw heap_getattr is that attnums beyond the
1138 : * slot's tupdesc's last attribute will be considered NULL even
1139 : * when the physical tuple is longer than the tupdesc.
1140 : */
1141 : Datum
1142 4945049 : slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
1143 : {
1144 4945049 : HeapTuple tuple = slot->tts_tuple;
1145 4945049 : TupleDesc tupleDesc = slot->tts_tupleDescriptor;
1146 : HeapTupleHeader tup;
1147 :
1148 : /*
1149 : * system attributes are handled by heap_getsysattr
1150 : */
1151 4945049 : if (attnum <= 0)
1152 : {
1153 20336 : if (tuple == NULL) /* internal error */
1154 0 : elog(ERROR, "cannot extract system attribute from virtual tuple");
1155 20336 : if (tuple == &(slot->tts_minhdr)) /* internal error */
1156 0 : elog(ERROR, "cannot extract system attribute from minimal tuple");
1157 20336 : return heap_getsysattr(tuple, attnum, tupleDesc, isnull);
1158 : }
1159 :
1160 : /*
1161 : * fast path if desired attribute already cached
1162 : */
1163 4924713 : if (attnum <= slot->tts_nvalid)
1164 : {
1165 2680666 : *isnull = slot->tts_isnull[attnum - 1];
1166 2680666 : return slot->tts_values[attnum - 1];
1167 : }
1168 :
1169 : /*
1170 : * return NULL if attnum is out of range according to the tupdesc
1171 : */
1172 2244047 : if (attnum > tupleDesc->natts)
1173 : {
1174 0 : *isnull = true;
1175 0 : return (Datum) 0;
1176 : }
1177 :
1178 : /*
1179 : * otherwise we had better have a physical tuple (tts_nvalid should equal
1180 : * natts in all virtual-tuple cases)
1181 : */
1182 2244047 : if (tuple == NULL) /* internal error */
1183 0 : elog(ERROR, "cannot extract attribute from empty tuple slot");
1184 :
1185 : /*
1186 : * return NULL if attnum is out of range according to the tuple
1187 : *
1188 : * (We have to check this separately because of various inheritance and
1189 : * table-alteration scenarios: the tuple could be either longer or shorter
1190 : * than the tupdesc.)
1191 : */
1192 2244047 : tup = tuple->t_data;
1193 2244047 : if (attnum > HeapTupleHeaderGetNatts(tup))
1194 : {
1195 1 : *isnull = true;
1196 1 : return (Datum) 0;
1197 : }
1198 :
1199 : /*
1200 : * check if target attribute is null: no point in groveling through tuple
1201 : */
1202 2244046 : if (HeapTupleHasNulls(tuple) && att_isnull(attnum - 1, tup->t_bits))
1203 : {
1204 3639 : *isnull = true;
1205 3639 : return (Datum) 0;
1206 : }
1207 :
1208 : /*
1209 : * If the attribute's column has been dropped, we force a NULL result.
1210 : * This case should not happen in normal use, but it could happen if we
1211 : * are executing a plan cached before the column was dropped.
1212 : */
1213 2240407 : if (TupleDescAttr(tupleDesc, attnum - 1)->attisdropped)
1214 : {
1215 0 : *isnull = true;
1216 0 : return (Datum) 0;
1217 : }
1218 :
1219 : /*
1220 : * Extract the attribute, along with any preceding attributes.
1221 : */
1222 2240407 : slot_deform_tuple(slot, attnum);
1223 :
1224 : /*
1225 : * The result is acquired from tts_values array.
1226 : */
1227 2240407 : *isnull = slot->tts_isnull[attnum - 1];
1228 2240407 : return slot->tts_values[attnum - 1];
1229 : }
1230 :
1231 : /*
1232 : * slot_getallattrs
1233 : * This function forces all the entries of the slot's Datum/isnull
1234 : * arrays to be valid. The caller may then extract data directly
1235 : * from those arrays instead of using slot_getattr.
1236 : */
1237 : void
1238 73459 : slot_getallattrs(TupleTableSlot *slot)
1239 : {
1240 73459 : int tdesc_natts = slot->tts_tupleDescriptor->natts;
1241 : int attnum;
1242 : HeapTuple tuple;
1243 :
1244 : /* Quick out if we have 'em all already */
1245 73459 : if (slot->tts_nvalid == tdesc_natts)
1246 123229 : return;
1247 :
1248 : /*
1249 : * otherwise we had better have a physical tuple (tts_nvalid should equal
1250 : * natts in all virtual-tuple cases)
1251 : */
1252 23689 : tuple = slot->tts_tuple;
1253 23689 : if (tuple == NULL) /* internal error */
1254 0 : elog(ERROR, "cannot extract attribute from empty tuple slot");
1255 :
1256 : /*
1257 : * load up any slots available from physical tuple
1258 : */
1259 23689 : attnum = HeapTupleHeaderGetNatts(tuple->t_data);
1260 23689 : attnum = Min(attnum, tdesc_natts);
1261 :
1262 23689 : slot_deform_tuple(slot, attnum);
1263 :
1264 : /*
1265 : * If tuple doesn't have all the atts indicated by tupleDesc, read the
1266 : * rest as null
1267 : */
1268 23699 : for (; attnum < tdesc_natts; attnum++)
1269 : {
1270 10 : slot->tts_values[attnum] = (Datum) 0;
1271 10 : slot->tts_isnull[attnum] = true;
1272 : }
1273 23689 : slot->tts_nvalid = tdesc_natts;
1274 : }
1275 :
1276 : /*
1277 : * slot_getsomeattrs
1278 : * This function forces the entries of the slot's Datum/isnull
1279 : * arrays to be valid at least up through the attnum'th entry.
1280 : */
1281 : void
1282 4636820 : slot_getsomeattrs(TupleTableSlot *slot, int attnum)
1283 : {
1284 : HeapTuple tuple;
1285 : int attno;
1286 :
1287 : /* Quick out if we have 'em all already */
1288 4636820 : if (slot->tts_nvalid >= attnum)
1289 5911464 : return;
1290 :
1291 : /* Check for caller error */
1292 3362176 : if (attnum <= 0 || attnum > slot->tts_tupleDescriptor->natts)
1293 0 : elog(ERROR, "invalid attribute number %d", attnum);
1294 :
1295 : /*
1296 : * otherwise we had better have a physical tuple (tts_nvalid should equal
1297 : * natts in all virtual-tuple cases)
1298 : */
1299 3362176 : tuple = slot->tts_tuple;
1300 3362176 : if (tuple == NULL) /* internal error */
1301 0 : elog(ERROR, "cannot extract attribute from empty tuple slot");
1302 :
1303 : /*
1304 : * load up any slots available from physical tuple
1305 : */
1306 3362176 : attno = HeapTupleHeaderGetNatts(tuple->t_data);
1307 3362176 : attno = Min(attno, attnum);
1308 :
1309 3362176 : slot_deform_tuple(slot, attno);
1310 :
1311 : /*
1312 : * If tuple doesn't have all the atts indicated by tupleDesc, read the
1313 : * rest as null
1314 : */
1315 3362272 : for (; attno < attnum; attno++)
1316 : {
1317 96 : slot->tts_values[attno] = (Datum) 0;
1318 96 : slot->tts_isnull[attno] = true;
1319 : }
1320 3362176 : slot->tts_nvalid = attnum;
1321 : }
1322 :
1323 : /*
1324 : * slot_attisnull
1325 : * Detect whether an attribute of the slot is null, without
1326 : * actually fetching it.
1327 : */
1328 : bool
1329 205983 : slot_attisnull(TupleTableSlot *slot, int attnum)
1330 : {
1331 205983 : HeapTuple tuple = slot->tts_tuple;
1332 205983 : TupleDesc tupleDesc = slot->tts_tupleDescriptor;
1333 :
1334 : /*
1335 : * system attributes are handled by heap_attisnull
1336 : */
1337 205983 : if (attnum <= 0)
1338 : {
1339 0 : if (tuple == NULL) /* internal error */
1340 0 : elog(ERROR, "cannot extract system attribute from virtual tuple");
1341 0 : if (tuple == &(slot->tts_minhdr)) /* internal error */
1342 0 : elog(ERROR, "cannot extract system attribute from minimal tuple");
1343 0 : return heap_attisnull(tuple, attnum);
1344 : }
1345 :
1346 : /*
1347 : * fast path if desired attribute already cached
1348 : */
1349 205983 : if (attnum <= slot->tts_nvalid)
1350 98449 : return slot->tts_isnull[attnum - 1];
1351 :
1352 : /*
1353 : * return NULL if attnum is out of range according to the tupdesc
1354 : */
1355 107534 : if (attnum > tupleDesc->natts)
1356 0 : return true;
1357 :
1358 : /*
1359 : * otherwise we had better have a physical tuple (tts_nvalid should equal
1360 : * natts in all virtual-tuple cases)
1361 : */
1362 107534 : if (tuple == NULL) /* internal error */
1363 0 : elog(ERROR, "cannot extract attribute from empty tuple slot");
1364 :
1365 : /* and let the tuple tell it */
1366 107534 : return heap_attisnull(tuple, attnum);
1367 : }
1368 :
1369 : /*
1370 : * heap_freetuple
1371 : */
1372 : void
1373 858629 : heap_freetuple(HeapTuple htup)
1374 : {
1375 858629 : pfree(htup);
1376 858629 : }
1377 :
1378 :
1379 : /*
1380 : * heap_form_minimal_tuple
1381 : * construct a MinimalTuple from the given values[] and isnull[] arrays,
1382 : * which are of the length indicated by tupleDescriptor->natts
1383 : *
1384 : * This is exactly like heap_form_tuple() except that the result is a
1385 : * "minimal" tuple lacking a HeapTupleData header as well as room for system
1386 : * columns.
1387 : *
1388 : * The result is allocated in the current memory context.
1389 : */
1390 : MinimalTuple
1391 1319935 : heap_form_minimal_tuple(TupleDesc tupleDescriptor,
1392 : Datum *values,
1393 : bool *isnull)
1394 : {
1395 : MinimalTuple tuple; /* return tuple */
1396 : Size len,
1397 : data_len;
1398 : int hoff;
1399 1319935 : bool hasnull = false;
1400 1319935 : int numberOfAttributes = tupleDescriptor->natts;
1401 : int i;
1402 :
1403 1319935 : if (numberOfAttributes > MaxTupleAttributeNumber)
1404 0 : ereport(ERROR,
1405 : (errcode(ERRCODE_TOO_MANY_COLUMNS),
1406 : errmsg("number of columns (%d) exceeds limit (%d)",
1407 : numberOfAttributes, MaxTupleAttributeNumber)));
1408 :
1409 : /*
1410 : * Check for nulls
1411 : */
1412 3599200 : for (i = 0; i < numberOfAttributes; i++)
1413 : {
1414 2281249 : if (isnull[i])
1415 : {
1416 1984 : hasnull = true;
1417 1984 : break;
1418 : }
1419 : }
1420 :
1421 : /*
1422 : * Determine total space needed
1423 : */
1424 1319935 : len = SizeofMinimalTupleHeader;
1425 :
1426 1319935 : if (hasnull)
1427 1984 : len += BITMAPLEN(numberOfAttributes);
1428 :
1429 1319935 : if (tupleDescriptor->tdhasoid)
1430 0 : len += sizeof(Oid);
1431 :
1432 1319935 : hoff = len = MAXALIGN(len); /* align user data safely */
1433 :
1434 1319935 : data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
1435 :
1436 1319935 : len += data_len;
1437 :
1438 : /*
1439 : * Allocate and zero the space needed.
1440 : */
1441 1319935 : tuple = (MinimalTuple) palloc0(len);
1442 :
1443 : /*
1444 : * And fill in the information.
1445 : */
1446 1319935 : tuple->t_len = len;
1447 1319935 : HeapTupleHeaderSetNatts(tuple, numberOfAttributes);
1448 1319935 : tuple->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
1449 :
1450 1319935 : if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
1451 0 : tuple->t_infomask = HEAP_HASOID;
1452 :
1453 1319935 : heap_fill_tuple(tupleDescriptor,
1454 : values,
1455 : isnull,
1456 : (char *) tuple + hoff,
1457 : data_len,
1458 : &tuple->t_infomask,
1459 : (hasnull ? tuple->t_bits : NULL));
1460 :
1461 1319935 : return tuple;
1462 : }
1463 :
1464 : /*
1465 : * heap_free_minimal_tuple
1466 : */
1467 : void
1468 760839 : heap_free_minimal_tuple(MinimalTuple mtup)
1469 : {
1470 760839 : pfree(mtup);
1471 760839 : }
1472 :
1473 : /*
1474 : * heap_copy_minimal_tuple
1475 : * copy a MinimalTuple
1476 : *
1477 : * The result is allocated in the current memory context.
1478 : */
1479 : MinimalTuple
1480 173134 : heap_copy_minimal_tuple(MinimalTuple mtup)
1481 : {
1482 : MinimalTuple result;
1483 :
1484 173134 : result = (MinimalTuple) palloc(mtup->t_len);
1485 173134 : memcpy(result, mtup, mtup->t_len);
1486 173134 : return result;
1487 : }
1488 :
1489 : /*
1490 : * heap_tuple_from_minimal_tuple
1491 : * create a HeapTuple by copying from a MinimalTuple;
1492 : * system columns are filled with zeroes
1493 : *
1494 : * The result is allocated in the current memory context.
1495 : * The HeapTuple struct, tuple header, and tuple data are all allocated
1496 : * as a single palloc() block.
1497 : */
1498 : HeapTuple
1499 62898 : heap_tuple_from_minimal_tuple(MinimalTuple mtup)
1500 : {
1501 : HeapTuple result;
1502 62898 : uint32 len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
1503 :
1504 62898 : result = (HeapTuple) palloc(HEAPTUPLESIZE + len);
1505 62898 : result->t_len = len;
1506 62898 : ItemPointerSetInvalid(&(result->t_self));
1507 62898 : result->t_tableOid = InvalidOid;
1508 62898 : result->t_data = (HeapTupleHeader) ((char *) result + HEAPTUPLESIZE);
1509 62898 : memcpy((char *) result->t_data + MINIMAL_TUPLE_OFFSET, mtup, mtup->t_len);
1510 62898 : memset(result->t_data, 0, offsetof(HeapTupleHeaderData, t_infomask2));
1511 62898 : return result;
1512 : }
1513 :
1514 : /*
1515 : * minimal_tuple_from_heap_tuple
1516 : * create a MinimalTuple by copying from a HeapTuple
1517 : *
1518 : * The result is allocated in the current memory context.
1519 : */
1520 : MinimalTuple
1521 61111 : minimal_tuple_from_heap_tuple(HeapTuple htup)
1522 : {
1523 : MinimalTuple result;
1524 : uint32 len;
1525 :
1526 61111 : Assert(htup->t_len > MINIMAL_TUPLE_OFFSET);
1527 61111 : len = htup->t_len - MINIMAL_TUPLE_OFFSET;
1528 61111 : result = (MinimalTuple) palloc(len);
1529 61111 : memcpy(result, (char *) htup->t_data + MINIMAL_TUPLE_OFFSET, len);
1530 61111 : result->t_len = len;
1531 61111 : return result;
1532 : }
|