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