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 : * heaptoast.c.
22 : *
23 : * This change will break any code that assumes it needn't detoast values
24 : * that have been put into a tuple but never sent to disk. Hopefully there
25 : * are few such places.
26 : *
27 : * Varlenas still have alignment INT (or DOUBLE) in pg_type/pg_attribute, since
28 : * that's the normal requirement for the untoasted format. But we ignore that
29 : * for the 1-byte-header format. This means that the actual start position
30 : * of a varlena datum may vary depending on which format it has. To determine
31 : * what is stored, we have to require that alignment padding bytes be zero.
32 : * (Postgres actually has always zeroed them, but now it's required!) Since
33 : * the first byte of a 1-byte-header varlena can never be zero, we can examine
34 : * the first byte after the previous datum to tell if it's a pad byte or the
35 : * start of a 1-byte-header varlena.
36 : *
37 : * Note that while formerly we could rely on the first varlena column of a
38 : * system catalog to be at the offset suggested by the C struct for the
39 : * catalog, this is now risky: it's only safe if the preceding field is
40 : * word-aligned, so that there will never be any padding.
41 : *
42 : * We don't pack varlenas whose attstorage is PLAIN, since the data type
43 : * isn't expecting to have to detoast values. This is used in particular
44 : * by oidvector and int2vector, which are used in the system catalogs
45 : * and we'd like to still refer to them via C struct offsets.
46 : *
47 : *
48 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
49 : * Portions Copyright (c) 1994, Regents of the University of California
50 : *
51 : *
52 : * IDENTIFICATION
53 : * src/backend/access/common/heaptuple.c
54 : *
55 : *-------------------------------------------------------------------------
56 : */
57 :
58 : #include "postgres.h"
59 :
60 : #include "access/heaptoast.h"
61 : #include "access/sysattr.h"
62 : #include "access/tupdesc_details.h"
63 : #include "common/hashfn.h"
64 : #include "utils/datum.h"
65 : #include "utils/expandeddatum.h"
66 : #include "utils/hsearch.h"
67 : #include "utils/memutils.h"
68 :
69 :
70 : /*
71 : * Does att's datatype allow packing into the 1-byte-header varlena format?
72 : * While functions that use TupleDescAttr() and assign attstorage =
73 : * TYPSTORAGE_PLAIN cannot use packed varlena headers, functions that call
74 : * TupleDescInitEntry() use typeForm->typstorage (TYPSTORAGE_EXTENDED) and
75 : * can use packed varlena headers, e.g.:
76 : * CREATE TABLE test(a VARCHAR(10000) STORAGE PLAIN);
77 : * INSERT INTO test VALUES (repeat('A',10));
78 : * This can be verified with pageinspect.
79 : */
80 : #define ATT_IS_PACKABLE(att) \
81 : ((att)->attlen == -1 && (att)->attstorage != TYPSTORAGE_PLAIN)
82 : /* Use this if it's already known varlena */
83 : #define VARLENA_ATT_IS_PACKABLE(att) \
84 : ((att)->attstorage != TYPSTORAGE_PLAIN)
85 :
86 : /*
87 : * Setup for caching pass-by-ref missing attributes in a way that survives
88 : * tupleDesc destruction.
89 : */
90 :
91 : typedef struct
92 : {
93 : int len;
94 : Datum value;
95 : } missing_cache_key;
96 :
97 : static HTAB *missing_cache = NULL;
98 :
99 : static uint32
100 0 : missing_hash(const void *key, Size keysize)
101 : {
102 0 : const missing_cache_key *entry = (missing_cache_key *) key;
103 :
104 0 : return hash_bytes((const unsigned char *) entry->value, entry->len);
105 : }
106 :
107 : static int
108 0 : missing_match(const void *key1, const void *key2, Size keysize)
109 : {
110 0 : const missing_cache_key *entry1 = (missing_cache_key *) key1;
111 0 : const missing_cache_key *entry2 = (missing_cache_key *) key2;
112 :
113 0 : if (entry1->len != entry2->len)
114 0 : return entry1->len > entry2->len ? 1 : -1;
115 :
116 0 : return memcmp(DatumGetPointer(entry1->value),
117 0 : DatumGetPointer(entry2->value),
118 0 : entry1->len);
119 : }
120 :
121 : static void
122 0 : init_missing_cache()
123 : {
124 : HASHCTL hash_ctl;
125 :
126 0 : hash_ctl.keysize = sizeof(missing_cache_key);
127 0 : hash_ctl.entrysize = sizeof(missing_cache_key);
128 0 : hash_ctl.hcxt = TopMemoryContext;
129 0 : hash_ctl.hash = missing_hash;
130 0 : hash_ctl.match = missing_match;
131 0 : missing_cache =
132 0 : hash_create("Missing Values Cache",
133 : 32,
134 : &hash_ctl,
135 : HASH_ELEM | HASH_CONTEXT | HASH_FUNCTION | HASH_COMPARE);
136 0 : }
137 :
138 : /* ----------------------------------------------------------------
139 : * misc support routines
140 : * ----------------------------------------------------------------
141 : */
142 :
143 : /*
144 : * Return the missing value of an attribute, or NULL if there isn't one.
145 : */
146 : Datum
147 356 : getmissingattr(TupleDesc tupleDesc,
148 : int attnum, bool *isnull)
149 : {
150 : Form_pg_attribute att;
151 :
152 : Assert(attnum <= tupleDesc->natts);
153 : Assert(attnum > 0);
154 :
155 356 : att = TupleDescAttr(tupleDesc, attnum - 1);
156 :
157 356 : if (att->atthasmissing)
158 : {
159 : AttrMissing *attrmiss;
160 :
161 : Assert(tupleDesc->constr);
162 : Assert(tupleDesc->constr->missing);
163 :
164 54 : attrmiss = tupleDesc->constr->missing + (attnum - 1);
165 :
166 54 : if (attrmiss->am_present)
167 : {
168 : missing_cache_key key;
169 : missing_cache_key *entry;
170 : bool found;
171 : MemoryContext oldctx;
172 :
173 54 : *isnull = false;
174 :
175 : /* no need to cache by-value attributes */
176 54 : if (att->attbyval)
177 54 : return attrmiss->am_value;
178 :
179 : /* set up cache if required */
180 0 : if (missing_cache == NULL)
181 0 : init_missing_cache();
182 :
183 : /* check if there's a cache entry */
184 : Assert(att->attlen > 0 || att->attlen == -1);
185 0 : if (att->attlen > 0)
186 0 : key.len = att->attlen;
187 : else
188 0 : key.len = VARSIZE_ANY(attrmiss->am_value);
189 0 : key.value = attrmiss->am_value;
190 :
191 0 : entry = hash_search(missing_cache, &key, HASH_ENTER, &found);
192 :
193 0 : if (!found)
194 : {
195 : /* cache miss, so we need a non-transient copy of the datum */
196 0 : oldctx = MemoryContextSwitchTo(TopMemoryContext);
197 0 : entry->value =
198 0 : datumCopy(attrmiss->am_value, false, att->attlen);
199 0 : MemoryContextSwitchTo(oldctx);
200 : }
201 :
202 0 : return entry->value;
203 : }
204 : }
205 :
206 302 : *isnull = true;
207 302 : return PointerGetDatum(NULL);
208 : }
209 :
210 : /*
211 : * heap_compute_data_size
212 : * Determine size of the data area of a tuple to be constructed
213 : */
214 : Size
215 112031982 : heap_compute_data_size(TupleDesc tupleDesc,
216 : const Datum *values,
217 : const bool *isnull)
218 : {
219 112031982 : Size data_length = 0;
220 : int i;
221 112031982 : int numberOfAttributes = tupleDesc->natts;
222 :
223 385882096 : for (i = 0; i < numberOfAttributes; i++)
224 : {
225 : Datum val;
226 : Form_pg_attribute atti;
227 :
228 273850114 : if (isnull[i])
229 24280386 : continue;
230 :
231 249569728 : val = values[i];
232 249569728 : atti = TupleDescAttr(tupleDesc, i);
233 :
234 249569728 : if (ATT_IS_PACKABLE(atti) &&
235 33506090 : VARATT_CAN_MAKE_SHORT(DatumGetPointer(val)))
236 : {
237 : /*
238 : * we're anticipating converting to a short varlena header, so
239 : * adjust length and don't count any alignment
240 : */
241 25981272 : data_length += VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val));
242 : }
243 223588456 : else if (atti->attlen == -1 &&
244 9376634 : VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
245 : {
246 : /*
247 : * we want to flatten the expanded value so that the constructed
248 : * tuple doesn't depend on it
249 : */
250 2966 : data_length = att_align_nominal(data_length, atti->attalign);
251 2966 : data_length += EOH_get_flat_size(DatumGetEOHP(val));
252 : }
253 : else
254 : {
255 223585490 : data_length = att_align_datum(data_length, atti->attalign,
256 : atti->attlen, val);
257 223585490 : data_length = att_addlength_datum(data_length, atti->attlen,
258 : val);
259 : }
260 : }
261 :
262 112031982 : return data_length;
263 : }
264 :
265 : /*
266 : * Per-attribute helper for heap_fill_tuple and other routines building tuples.
267 : *
268 : * Fill in either a data value or a bit in the null bitmask
269 : */
270 : static inline void
271 252401970 : fill_val(Form_pg_attribute att,
272 : bits8 **bit,
273 : int *bitmask,
274 : char **dataP,
275 : uint16 *infomask,
276 : Datum datum,
277 : bool isnull)
278 : {
279 : Size data_length;
280 252401970 : char *data = *dataP;
281 :
282 : /*
283 : * If we're building a null bitmap, set the appropriate bit for the
284 : * current column value here.
285 : */
286 252401970 : if (bit != NULL)
287 : {
288 89956680 : if (*bitmask != HIGHBIT)
289 74454844 : *bitmask <<= 1;
290 : else
291 : {
292 15501836 : *bit += 1;
293 15501836 : **bit = 0x0;
294 15501836 : *bitmask = 1;
295 : }
296 :
297 89956680 : if (isnull)
298 : {
299 24098800 : *infomask |= HEAP_HASNULL;
300 24098800 : return;
301 : }
302 :
303 65857880 : **bit |= *bitmask;
304 : }
305 :
306 : /*
307 : * XXX we use the att_align macros on the pointer value itself, not on an
308 : * offset. This is a bit of a hack.
309 : */
310 228303170 : if (att->attbyval)
311 : {
312 : /* pass-by-value */
313 169685866 : data = (char *) att_align_nominal(data, att->attalign);
314 169685866 : store_att_byval(data, datum, att->attlen);
315 169685866 : data_length = att->attlen;
316 : }
317 58617304 : else if (att->attlen == -1)
318 : {
319 : /* varlena */
320 33837748 : Pointer val = DatumGetPointer(datum);
321 :
322 33837748 : *infomask |= HEAP_HASVARWIDTH;
323 33837748 : if (VARATT_IS_EXTERNAL(val))
324 : {
325 19538 : if (VARATT_IS_EXTERNAL_EXPANDED(val))
326 2966 : {
327 : /*
328 : * we want to flatten the expanded value so that the
329 : * constructed tuple doesn't depend on it
330 : */
331 2966 : ExpandedObjectHeader *eoh = DatumGetEOHP(datum);
332 :
333 2966 : data = (char *) att_align_nominal(data,
334 : att->attalign);
335 2966 : data_length = EOH_get_flat_size(eoh);
336 2966 : EOH_flatten_into(eoh, data, data_length);
337 : }
338 : else
339 : {
340 16572 : *infomask |= HEAP_HASEXTERNAL;
341 : /* no alignment, since it's short by definition */
342 16572 : data_length = VARSIZE_EXTERNAL(val);
343 16572 : memcpy(data, val, data_length);
344 : }
345 : }
346 33818210 : else if (VARATT_IS_SHORT(val))
347 : {
348 : /* no alignment for short varlenas */
349 6182680 : data_length = VARSIZE_SHORT(val);
350 6182680 : memcpy(data, val, data_length);
351 : }
352 27635530 : else if (VARLENA_ATT_IS_PACKABLE(att) &&
353 25793256 : VARATT_CAN_MAKE_SHORT(val))
354 : {
355 : /* convert to short varlena -- no alignment */
356 25051116 : data_length = VARATT_CONVERTED_SHORT_SIZE(val);
357 25051116 : SET_VARSIZE_SHORT(data, data_length);
358 25051116 : memcpy(data + 1, VARDATA(val), data_length - 1);
359 : }
360 : else
361 : {
362 : /* full 4-byte header varlena */
363 2584414 : data = (char *) att_align_nominal(data,
364 : att->attalign);
365 2584414 : data_length = VARSIZE(val);
366 2584414 : memcpy(data, val, data_length);
367 : }
368 : }
369 24779556 : else if (att->attlen == -2)
370 : {
371 : /* cstring ... never needs alignment */
372 2335082 : *infomask |= HEAP_HASVARWIDTH;
373 : Assert(att->attalign == TYPALIGN_CHAR);
374 2335082 : data_length = strlen(DatumGetCString(datum)) + 1;
375 2335082 : memcpy(data, DatumGetPointer(datum), data_length);
376 : }
377 : else
378 : {
379 : /* fixed-length pass-by-reference */
380 22444474 : data = (char *) att_align_nominal(data, att->attalign);
381 : Assert(att->attlen > 0);
382 22444474 : data_length = att->attlen;
383 22444474 : memcpy(data, DatumGetPointer(datum), data_length);
384 : }
385 :
386 228303170 : data += data_length;
387 228303170 : *dataP = data;
388 : }
389 :
390 : /*
391 : * heap_fill_tuple
392 : * Load data portion of a tuple from values/isnull arrays
393 : *
394 : * We also fill the null bitmap (if any) and set the infomask bits
395 : * that reflect the tuple's data contents.
396 : *
397 : * NOTE: it is now REQUIRED that the caller have pre-zeroed the data area.
398 : */
399 : void
400 92386852 : heap_fill_tuple(TupleDesc tupleDesc,
401 : const Datum *values, const bool *isnull,
402 : char *data, Size data_size,
403 : uint16 *infomask, bits8 *bit)
404 : {
405 : bits8 *bitP;
406 : int bitmask;
407 : int i;
408 92386852 : int numberOfAttributes = tupleDesc->natts;
409 :
410 : #ifdef USE_ASSERT_CHECKING
411 : char *start = data;
412 : #endif
413 :
414 92386852 : if (bit != NULL)
415 : {
416 6757528 : bitP = &bit[-1];
417 6757528 : bitmask = HIGHBIT;
418 : }
419 : else
420 : {
421 : /* just to keep compiler quiet */
422 85629324 : bitP = NULL;
423 85629324 : bitmask = 0;
424 : }
425 :
426 92386852 : *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTERNAL);
427 :
428 344788822 : for (i = 0; i < numberOfAttributes; i++)
429 : {
430 252401970 : Form_pg_attribute attr = TupleDescAttr(tupleDesc, i);
431 :
432 504803940 : fill_val(attr,
433 252401970 : bitP ? &bitP : NULL,
434 : &bitmask,
435 : &data,
436 : infomask,
437 252401970 : values ? values[i] : PointerGetDatum(NULL),
438 252401970 : isnull ? isnull[i] : true);
439 : }
440 :
441 : Assert((data - start) == data_size);
442 92386852 : }
443 :
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 8852740 : heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
456 : {
457 : /*
458 : * We allow a NULL tupledesc for relations not expected to have missing
459 : * values, such as catalog relations and indexes.
460 : */
461 : Assert(!tupleDesc || attnum <= tupleDesc->natts);
462 8852740 : if (attnum > (int) HeapTupleHeaderGetNatts(tup->t_data))
463 : {
464 0 : if (tupleDesc && TupleDescAttr(tupleDesc, attnum - 1)->atthasmissing)
465 0 : return false;
466 : else
467 0 : return true;
468 : }
469 :
470 8852740 : if (attnum > 0)
471 : {
472 8852740 : if (HeapTupleNoNulls(tup))
473 2956 : return false;
474 8849784 : return att_isnull(attnum - 1, tup->t_data->t_bits);
475 : }
476 :
477 0 : switch (attnum)
478 : {
479 0 : case TableOidAttributeNumber:
480 : case SelfItemPointerAttributeNumber:
481 : case MinTransactionIdAttributeNumber:
482 : case MinCommandIdAttributeNumber:
483 : case MaxTransactionIdAttributeNumber:
484 : case MaxCommandIdAttributeNumber:
485 : /* these are never null */
486 0 : break;
487 :
488 0 : default:
489 0 : elog(ERROR, "invalid attnum: %d", attnum);
490 : }
491 :
492 0 : return false;
493 : }
494 :
495 : /* ----------------
496 : * nocachegetattr
497 : *
498 : * This only gets called from fastgetattr(), in cases where we
499 : * can't use a cacheoffset and the value is not null.
500 : *
501 : * This caches attribute offsets in the attribute descriptor.
502 : *
503 : * An alternative way to speed things up would be to cache offsets
504 : * with the tuple, but that seems more difficult unless you take
505 : * the storage hit of actually putting those offsets into the
506 : * tuple you send to disk. Yuck.
507 : *
508 : * This scheme will be slightly slower than that, but should
509 : * perform well for queries which hit large #'s of tuples. After
510 : * you cache the offsets once, examining all the other tuples using
511 : * the same attribute descriptor will go much quicker. -cim 5/4/91
512 : *
513 : * NOTE: if you need to change this code, see also heap_deform_tuple.
514 : * Also see nocache_index_getattr, which is the same code for index
515 : * tuples.
516 : * ----------------
517 : */
518 : Datum
519 172466280 : nocachegetattr(HeapTuple tup,
520 : int attnum,
521 : TupleDesc tupleDesc)
522 : {
523 172466280 : HeapTupleHeader td = tup->t_data;
524 : char *tp; /* ptr to data part of tuple */
525 172466280 : bits8 *bp = td->t_bits; /* ptr to null bitmap in tuple */
526 172466280 : bool slow = false; /* do we have to walk attrs? */
527 : int off; /* current offset within data */
528 :
529 : /* ----------------
530 : * Three cases:
531 : *
532 : * 1: No nulls and no variable-width attributes.
533 : * 2: Has a null or a var-width AFTER att.
534 : * 3: Has nulls or var-widths BEFORE att.
535 : * ----------------
536 : */
537 :
538 172466280 : attnum--;
539 :
540 172466280 : if (!HeapTupleNoNulls(tup))
541 : {
542 : /*
543 : * there's a null somewhere in the tuple
544 : *
545 : * check to see if any preceding bits are null...
546 : */
547 130310280 : int byte = attnum >> 3;
548 130310280 : int finalbit = attnum & 0x07;
549 :
550 : /* check for nulls "before" final bit of last byte */
551 130310280 : if ((~bp[byte]) & ((1 << finalbit) - 1))
552 5547290 : slow = true;
553 : else
554 : {
555 : /* check for nulls in any "earlier" bytes */
556 : int i;
557 :
558 161999944 : for (i = 0; i < byte; i++)
559 : {
560 37871284 : if (bp[i] != 0xFF)
561 : {
562 634330 : slow = true;
563 634330 : break;
564 : }
565 : }
566 : }
567 : }
568 :
569 172466280 : tp = (char *) td + td->t_hoff;
570 :
571 172466280 : if (!slow)
572 : {
573 : Form_pg_attribute att;
574 :
575 : /*
576 : * If we get here, there are no nulls up to and including the target
577 : * attribute. If we have a cached offset, we can use it.
578 : */
579 166284660 : att = TupleDescAttr(tupleDesc, attnum);
580 166284660 : if (att->attcacheoff >= 0)
581 120357174 : return fetchatt(att, tp + att->attcacheoff);
582 :
583 : /*
584 : * Otherwise, check for non-fixed-length attrs up to and including
585 : * target. If there aren't any, it's safe to cheaply initialize the
586 : * cached offsets for these attrs.
587 : */
588 45927486 : if (HeapTupleHasVarWidth(tup))
589 : {
590 : int j;
591 :
592 101670836 : for (j = 0; j <= attnum; j++)
593 : {
594 101593270 : if (TupleDescAttr(tupleDesc, j)->attlen <= 0)
595 : {
596 45716840 : slow = true;
597 45716840 : break;
598 : }
599 : }
600 : }
601 : }
602 :
603 52109106 : if (!slow)
604 : {
605 210646 : int natts = tupleDesc->natts;
606 210646 : int j = 1;
607 :
608 : /*
609 : * If we get here, we have a tuple with no nulls or var-widths up to
610 : * and including the target attribute, so we can use the cached offset
611 : * ... only we don't have it yet, or we'd not have got here. Since
612 : * it's cheap to compute offsets for fixed-width columns, we take the
613 : * opportunity to initialize the cached offsets for *all* the leading
614 : * fixed-width columns, in hope of avoiding future visits to this
615 : * routine.
616 : */
617 210646 : TupleDescAttr(tupleDesc, 0)->attcacheoff = 0;
618 :
619 : /* we might have set some offsets in the slow path previously */
620 214274 : while (j < natts && TupleDescAttr(tupleDesc, j)->attcacheoff > 0)
621 3628 : j++;
622 :
623 210646 : off = TupleDescAttr(tupleDesc, j - 1)->attcacheoff +
624 210646 : TupleDescAttr(tupleDesc, j - 1)->attlen;
625 :
626 2130604 : for (; j < natts; j++)
627 : {
628 2026526 : Form_pg_attribute att = TupleDescAttr(tupleDesc, j);
629 :
630 2026526 : if (att->attlen <= 0)
631 106568 : break;
632 :
633 1919958 : off = att_align_nominal(off, att->attalign);
634 :
635 1919958 : att->attcacheoff = off;
636 :
637 1919958 : off += att->attlen;
638 : }
639 :
640 : Assert(j > attnum);
641 :
642 210646 : off = TupleDescAttr(tupleDesc, attnum)->attcacheoff;
643 : }
644 : else
645 : {
646 51898460 : bool usecache = true;
647 : int i;
648 :
649 : /*
650 : * Now we know that we have to walk the tuple CAREFULLY. But we still
651 : * might be able to cache some offsets for next time.
652 : *
653 : * Note - This loop is a little tricky. For each non-null attribute,
654 : * we have to first account for alignment padding before the attr,
655 : * then advance over the attr based on its length. Nulls have no
656 : * storage and no alignment padding either. We can use/set
657 : * attcacheoff until we reach either a null or a var-width attribute.
658 : */
659 51898460 : off = 0;
660 51898460 : for (i = 0;; i++) /* loop exit is at "break" */
661 216404102 : {
662 268302562 : Form_pg_attribute att = TupleDescAttr(tupleDesc, i);
663 :
664 268302562 : if (HeapTupleHasNulls(tup) && att_isnull(i, bp))
665 : {
666 17083342 : usecache = false;
667 17083342 : continue; /* this cannot be the target att */
668 : }
669 :
670 : /* If we know the next offset, we can skip the rest */
671 251219220 : if (usecache && att->attcacheoff >= 0)
672 142161858 : off = att->attcacheoff;
673 109057362 : else if (att->attlen == -1)
674 : {
675 : /*
676 : * We can only cache the offset for a varlena attribute if the
677 : * offset is already suitably aligned, so that there would be
678 : * no pad bytes in any case: then the offset will be valid for
679 : * either an aligned or unaligned value.
680 : */
681 20981464 : if (usecache &&
682 2264408 : off == att_align_nominal(off, att->attalign))
683 94958 : att->attcacheoff = off;
684 : else
685 : {
686 18622098 : off = att_align_pointer(off, att->attalign, -1,
687 : tp + off);
688 18622098 : usecache = false;
689 : }
690 : }
691 : else
692 : {
693 : /* not varlena, so safe to use att_align_nominal */
694 90340306 : off = att_align_nominal(off, att->attalign);
695 :
696 90340306 : if (usecache)
697 964606 : att->attcacheoff = off;
698 : }
699 :
700 251219220 : if (i == attnum)
701 51898460 : break;
702 :
703 199320760 : off = att_addlength_pointer(off, att->attlen, tp + off);
704 :
705 199320760 : if (usecache && att->attlen <= 0)
706 47043934 : usecache = false;
707 : }
708 : }
709 :
710 52109106 : return fetchatt(TupleDescAttr(tupleDesc, attnum), tp + off);
711 : }
712 :
713 : /* ----------------
714 : * heap_getsysattr
715 : *
716 : * Fetch the value of a system attribute for a tuple.
717 : *
718 : * This is a support routine for heap_getattr(). The function has already
719 : * determined that the attnum refers to a system attribute.
720 : * ----------------
721 : */
722 : Datum
723 144868 : heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
724 : {
725 : Datum result;
726 :
727 : Assert(tup);
728 :
729 : /* Currently, no sys attribute ever reads as NULL. */
730 144868 : *isnull = false;
731 :
732 144868 : switch (attnum)
733 : {
734 4 : case SelfItemPointerAttributeNumber:
735 : /* pass-by-reference datatype */
736 4 : result = PointerGetDatum(&(tup->t_self));
737 4 : break;
738 144644 : case MinTransactionIdAttributeNumber:
739 144644 : result = TransactionIdGetDatum(HeapTupleHeaderGetRawXmin(tup->t_data));
740 144644 : break;
741 30 : case MaxTransactionIdAttributeNumber:
742 30 : result = TransactionIdGetDatum(HeapTupleHeaderGetRawXmax(tup->t_data));
743 30 : break;
744 186 : case MinCommandIdAttributeNumber:
745 : case MaxCommandIdAttributeNumber:
746 :
747 : /*
748 : * cmin and cmax are now both aliases for the same field, which
749 : * can in fact also be a combo command id. XXX perhaps we should
750 : * return the "real" cmin or cmax if possible, that is if we are
751 : * inside the originating transaction?
752 : */
753 186 : result = CommandIdGetDatum(HeapTupleHeaderGetRawCommandId(tup->t_data));
754 186 : break;
755 4 : case TableOidAttributeNumber:
756 4 : result = ObjectIdGetDatum(tup->t_tableOid);
757 4 : break;
758 0 : default:
759 0 : elog(ERROR, "invalid attnum: %d", attnum);
760 : result = 0; /* keep compiler quiet */
761 : break;
762 : }
763 144868 : return result;
764 : }
765 :
766 : /* ----------------
767 : * heap_copytuple
768 : *
769 : * returns a copy of an entire tuple
770 : *
771 : * The HeapTuple struct, tuple header, and tuple data are all allocated
772 : * as a single palloc() block.
773 : * ----------------
774 : */
775 : HeapTuple
776 12532886 : heap_copytuple(HeapTuple tuple)
777 : {
778 : HeapTuple newTuple;
779 :
780 12532886 : if (!HeapTupleIsValid(tuple) || tuple->t_data == NULL)
781 0 : return NULL;
782 :
783 12532886 : newTuple = (HeapTuple) palloc(HEAPTUPLESIZE + tuple->t_len);
784 12532886 : newTuple->t_len = tuple->t_len;
785 12532886 : newTuple->t_self = tuple->t_self;
786 12532886 : newTuple->t_tableOid = tuple->t_tableOid;
787 12532886 : newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
788 12532886 : memcpy((char *) newTuple->t_data, (char *) tuple->t_data, tuple->t_len);
789 12532886 : return newTuple;
790 : }
791 :
792 : /* ----------------
793 : * heap_copytuple_with_tuple
794 : *
795 : * copy a tuple into a caller-supplied HeapTuple management struct
796 : *
797 : * Note that after calling this function, the "dest" HeapTuple will not be
798 : * allocated as a single palloc() block (unlike with heap_copytuple()).
799 : * ----------------
800 : */
801 : void
802 0 : heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest)
803 : {
804 0 : if (!HeapTupleIsValid(src) || src->t_data == NULL)
805 : {
806 0 : dest->t_data = NULL;
807 0 : return;
808 : }
809 :
810 0 : dest->t_len = src->t_len;
811 0 : dest->t_self = src->t_self;
812 0 : dest->t_tableOid = src->t_tableOid;
813 0 : dest->t_data = (HeapTupleHeader) palloc(src->t_len);
814 0 : memcpy((char *) dest->t_data, (char *) src->t_data, src->t_len);
815 : }
816 :
817 : /*
818 : * Expand a tuple which has fewer attributes than required. For each attribute
819 : * not present in the sourceTuple, if there is a missing value that will be
820 : * used. Otherwise the attribute will be set to NULL.
821 : *
822 : * The source tuple must have fewer attributes than the required number.
823 : *
824 : * Only one of targetHeapTuple and targetMinimalTuple may be supplied. The
825 : * other argument must be NULL.
826 : */
827 : static void
828 0 : expand_tuple(HeapTuple *targetHeapTuple,
829 : MinimalTuple *targetMinimalTuple,
830 : HeapTuple sourceTuple,
831 : TupleDesc tupleDesc)
832 : {
833 0 : AttrMissing *attrmiss = NULL;
834 : int attnum;
835 : int firstmissingnum;
836 0 : bool hasNulls = HeapTupleHasNulls(sourceTuple);
837 : HeapTupleHeader targetTHeader;
838 0 : HeapTupleHeader sourceTHeader = sourceTuple->t_data;
839 0 : int sourceNatts = HeapTupleHeaderGetNatts(sourceTHeader);
840 0 : int natts = tupleDesc->natts;
841 : int sourceNullLen;
842 : int targetNullLen;
843 0 : Size sourceDataLen = sourceTuple->t_len - sourceTHeader->t_hoff;
844 : Size targetDataLen;
845 : Size len;
846 : int hoff;
847 0 : bits8 *nullBits = NULL;
848 0 : int bitMask = 0;
849 : char *targetData;
850 : uint16 *infoMask;
851 :
852 : Assert((targetHeapTuple && !targetMinimalTuple)
853 : || (!targetHeapTuple && targetMinimalTuple));
854 :
855 : Assert(sourceNatts < natts);
856 :
857 0 : sourceNullLen = (hasNulls ? BITMAPLEN(sourceNatts) : 0);
858 :
859 0 : targetDataLen = sourceDataLen;
860 :
861 0 : if (tupleDesc->constr &&
862 0 : tupleDesc->constr->missing)
863 : {
864 : /*
865 : * If there are missing values we want to put them into the tuple.
866 : * Before that we have to compute the extra length for the values
867 : * array and the variable length data.
868 : */
869 0 : attrmiss = tupleDesc->constr->missing;
870 :
871 : /*
872 : * Find the first item in attrmiss for which we don't have a value in
873 : * the source. We can ignore all the missing entries before that.
874 : */
875 0 : for (firstmissingnum = sourceNatts;
876 : firstmissingnum < natts;
877 0 : firstmissingnum++)
878 : {
879 0 : if (attrmiss[firstmissingnum].am_present)
880 0 : break;
881 : else
882 0 : hasNulls = true;
883 : }
884 :
885 : /*
886 : * Now walk the missing attributes. If there is a missing value make
887 : * space for it. Otherwise, it's going to be NULL.
888 : */
889 0 : for (attnum = firstmissingnum;
890 : attnum < natts;
891 0 : attnum++)
892 : {
893 0 : if (attrmiss[attnum].am_present)
894 : {
895 0 : Form_pg_attribute att = TupleDescAttr(tupleDesc, attnum);
896 :
897 0 : targetDataLen = att_align_datum(targetDataLen,
898 : att->attalign,
899 : att->attlen,
900 : attrmiss[attnum].am_value);
901 :
902 0 : targetDataLen = att_addlength_pointer(targetDataLen,
903 : att->attlen,
904 : attrmiss[attnum].am_value);
905 : }
906 : else
907 : {
908 : /* no missing value, so it must be null */
909 0 : hasNulls = true;
910 : }
911 : }
912 : } /* end if have missing values */
913 : else
914 : {
915 : /*
916 : * If there are no missing values at all then NULLS must be allowed,
917 : * since some of the attributes are known to be absent.
918 : */
919 0 : hasNulls = true;
920 : }
921 :
922 0 : len = 0;
923 :
924 0 : if (hasNulls)
925 : {
926 0 : targetNullLen = BITMAPLEN(natts);
927 0 : len += targetNullLen;
928 : }
929 : else
930 0 : targetNullLen = 0;
931 :
932 : /*
933 : * Allocate and zero the space needed. Note that the tuple body and
934 : * HeapTupleData management structure are allocated in one chunk.
935 : */
936 0 : if (targetHeapTuple)
937 : {
938 0 : len += offsetof(HeapTupleHeaderData, t_bits);
939 0 : hoff = len = MAXALIGN(len); /* align user data safely */
940 0 : len += targetDataLen;
941 :
942 0 : *targetHeapTuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
943 0 : (*targetHeapTuple)->t_data
944 0 : = targetTHeader
945 0 : = (HeapTupleHeader) ((char *) *targetHeapTuple + HEAPTUPLESIZE);
946 0 : (*targetHeapTuple)->t_len = len;
947 0 : (*targetHeapTuple)->t_tableOid = sourceTuple->t_tableOid;
948 0 : (*targetHeapTuple)->t_self = sourceTuple->t_self;
949 :
950 0 : targetTHeader->t_infomask = sourceTHeader->t_infomask;
951 0 : targetTHeader->t_hoff = hoff;
952 0 : HeapTupleHeaderSetNatts(targetTHeader, natts);
953 0 : HeapTupleHeaderSetDatumLength(targetTHeader, len);
954 0 : HeapTupleHeaderSetTypeId(targetTHeader, tupleDesc->tdtypeid);
955 0 : HeapTupleHeaderSetTypMod(targetTHeader, tupleDesc->tdtypmod);
956 : /* We also make sure that t_ctid is invalid unless explicitly set */
957 0 : ItemPointerSetInvalid(&(targetTHeader->t_ctid));
958 0 : if (targetNullLen > 0)
959 0 : nullBits = (bits8 *) ((char *) (*targetHeapTuple)->t_data
960 : + offsetof(HeapTupleHeaderData, t_bits));
961 0 : targetData = (char *) (*targetHeapTuple)->t_data + hoff;
962 0 : infoMask = &(targetTHeader->t_infomask);
963 : }
964 : else
965 : {
966 0 : len += SizeofMinimalTupleHeader;
967 0 : hoff = len = MAXALIGN(len); /* align user data safely */
968 0 : len += targetDataLen;
969 :
970 0 : *targetMinimalTuple = (MinimalTuple) palloc0(len);
971 0 : (*targetMinimalTuple)->t_len = len;
972 0 : (*targetMinimalTuple)->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
973 0 : (*targetMinimalTuple)->t_infomask = sourceTHeader->t_infomask;
974 : /* Same macro works for MinimalTuples */
975 0 : HeapTupleHeaderSetNatts(*targetMinimalTuple, natts);
976 0 : if (targetNullLen > 0)
977 0 : nullBits = (bits8 *) ((char *) *targetMinimalTuple
978 0 : + offsetof(MinimalTupleData, t_bits));
979 0 : targetData = (char *) *targetMinimalTuple + hoff;
980 0 : infoMask = &((*targetMinimalTuple)->t_infomask);
981 : }
982 :
983 0 : if (targetNullLen > 0)
984 : {
985 0 : if (sourceNullLen > 0)
986 : {
987 : /* if bitmap pre-existed copy in - all is set */
988 0 : memcpy(nullBits,
989 : ((char *) sourceTHeader)
990 : + offsetof(HeapTupleHeaderData, t_bits),
991 : sourceNullLen);
992 0 : nullBits += sourceNullLen - 1;
993 : }
994 : else
995 : {
996 0 : sourceNullLen = BITMAPLEN(sourceNatts);
997 : /* Set NOT NULL for all existing attributes */
998 0 : memset(nullBits, 0xff, sourceNullLen);
999 :
1000 0 : nullBits += sourceNullLen - 1;
1001 :
1002 0 : if (sourceNatts & 0x07)
1003 : {
1004 : /* build the mask (inverted!) */
1005 0 : bitMask = 0xff << (sourceNatts & 0x07);
1006 : /* Voila */
1007 0 : *nullBits = ~bitMask;
1008 : }
1009 : }
1010 :
1011 0 : bitMask = (1 << ((sourceNatts - 1) & 0x07));
1012 : } /* End if have null bitmap */
1013 :
1014 0 : memcpy(targetData,
1015 0 : ((char *) sourceTuple->t_data) + sourceTHeader->t_hoff,
1016 : sourceDataLen);
1017 :
1018 0 : targetData += sourceDataLen;
1019 :
1020 : /* Now fill in the missing values */
1021 0 : for (attnum = sourceNatts; attnum < natts; attnum++)
1022 : {
1023 :
1024 0 : Form_pg_attribute attr = TupleDescAttr(tupleDesc, attnum);
1025 :
1026 0 : if (attrmiss && attrmiss[attnum].am_present)
1027 : {
1028 0 : fill_val(attr,
1029 0 : nullBits ? &nullBits : NULL,
1030 : &bitMask,
1031 : &targetData,
1032 : infoMask,
1033 0 : attrmiss[attnum].am_value,
1034 : false);
1035 : }
1036 : else
1037 : {
1038 0 : fill_val(attr,
1039 : &nullBits,
1040 : &bitMask,
1041 : &targetData,
1042 : infoMask,
1043 : (Datum) 0,
1044 : true);
1045 : }
1046 : } /* end loop over missing attributes */
1047 0 : }
1048 :
1049 : /*
1050 : * Fill in the missing values for a minimal HeapTuple
1051 : */
1052 : MinimalTuple
1053 0 : minimal_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
1054 : {
1055 : MinimalTuple minimalTuple;
1056 :
1057 0 : expand_tuple(NULL, &minimalTuple, sourceTuple, tupleDesc);
1058 0 : return minimalTuple;
1059 : }
1060 :
1061 : /*
1062 : * Fill in the missing values for an ordinary HeapTuple
1063 : */
1064 : HeapTuple
1065 0 : heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
1066 : {
1067 : HeapTuple heapTuple;
1068 :
1069 0 : expand_tuple(&heapTuple, NULL, sourceTuple, tupleDesc);
1070 0 : return heapTuple;
1071 : }
1072 :
1073 : /* ----------------
1074 : * heap_copy_tuple_as_datum
1075 : *
1076 : * copy a tuple as a composite-type Datum
1077 : * ----------------
1078 : */
1079 : Datum
1080 78986 : heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
1081 : {
1082 : HeapTupleHeader td;
1083 :
1084 : /*
1085 : * If the tuple contains any external TOAST pointers, we have to inline
1086 : * those fields to meet the conventions for composite-type Datums.
1087 : */
1088 78986 : if (HeapTupleHasExternal(tuple))
1089 0 : return toast_flatten_tuple_to_datum(tuple->t_data,
1090 : tuple->t_len,
1091 : tupleDesc);
1092 :
1093 : /*
1094 : * Fast path for easy case: just make a palloc'd copy and insert the
1095 : * correct composite-Datum header fields (since those may not be set if
1096 : * the given tuple came from disk, rather than from heap_form_tuple).
1097 : */
1098 78986 : td = (HeapTupleHeader) palloc(tuple->t_len);
1099 78986 : memcpy((char *) td, (char *) tuple->t_data, tuple->t_len);
1100 :
1101 78986 : HeapTupleHeaderSetDatumLength(td, tuple->t_len);
1102 78986 : HeapTupleHeaderSetTypeId(td, tupleDesc->tdtypeid);
1103 78986 : HeapTupleHeaderSetTypMod(td, tupleDesc->tdtypmod);
1104 :
1105 78986 : return PointerGetDatum(td);
1106 : }
1107 :
1108 : /*
1109 : * heap_form_tuple
1110 : * construct a tuple from the given values[] and isnull[] arrays,
1111 : * which are of the length indicated by tupleDescriptor->natts
1112 : *
1113 : * The result is allocated in the current memory context.
1114 : */
1115 : HeapTuple
1116 23248340 : heap_form_tuple(TupleDesc tupleDescriptor,
1117 : const Datum *values,
1118 : const bool *isnull)
1119 : {
1120 : HeapTuple tuple; /* return tuple */
1121 : HeapTupleHeader td; /* tuple data */
1122 : Size len,
1123 : data_len;
1124 : int hoff;
1125 23248340 : bool hasnull = false;
1126 23248340 : int numberOfAttributes = tupleDescriptor->natts;
1127 : int i;
1128 :
1129 23248340 : if (numberOfAttributes > MaxTupleAttributeNumber)
1130 0 : ereport(ERROR,
1131 : (errcode(ERRCODE_TOO_MANY_COLUMNS),
1132 : errmsg("number of columns (%d) exceeds limit (%d)",
1133 : numberOfAttributes, MaxTupleAttributeNumber)));
1134 :
1135 : /*
1136 : * Check for nulls
1137 : */
1138 116036818 : for (i = 0; i < numberOfAttributes; i++)
1139 : {
1140 98804924 : if (isnull[i])
1141 : {
1142 6016446 : hasnull = true;
1143 6016446 : break;
1144 : }
1145 : }
1146 :
1147 : /*
1148 : * Determine total space needed
1149 : */
1150 23248340 : len = offsetof(HeapTupleHeaderData, t_bits);
1151 :
1152 23248340 : if (hasnull)
1153 6016446 : len += BITMAPLEN(numberOfAttributes);
1154 :
1155 23248340 : hoff = len = MAXALIGN(len); /* align user data safely */
1156 :
1157 23248340 : data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
1158 :
1159 23248340 : len += data_len;
1160 :
1161 : /*
1162 : * Allocate and zero the space needed. Note that the tuple body and
1163 : * HeapTupleData management structure are allocated in one chunk.
1164 : */
1165 23248340 : tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
1166 23248340 : tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
1167 :
1168 : /*
1169 : * And fill in the information. Note we fill the Datum fields even though
1170 : * this tuple may never become a Datum. This lets HeapTupleHeaderGetDatum
1171 : * identify the tuple type if needed.
1172 : */
1173 23248340 : tuple->t_len = len;
1174 23248340 : ItemPointerSetInvalid(&(tuple->t_self));
1175 23248340 : tuple->t_tableOid = InvalidOid;
1176 :
1177 23248340 : HeapTupleHeaderSetDatumLength(td, len);
1178 23248340 : HeapTupleHeaderSetTypeId(td, tupleDescriptor->tdtypeid);
1179 23248340 : HeapTupleHeaderSetTypMod(td, tupleDescriptor->tdtypmod);
1180 : /* We also make sure that t_ctid is invalid unless explicitly set */
1181 23248340 : ItemPointerSetInvalid(&(td->t_ctid));
1182 :
1183 23248340 : HeapTupleHeaderSetNatts(td, numberOfAttributes);
1184 23248340 : td->t_hoff = hoff;
1185 :
1186 23248340 : heap_fill_tuple(tupleDescriptor,
1187 : values,
1188 : isnull,
1189 : (char *) td + hoff,
1190 : data_len,
1191 : &td->t_infomask,
1192 : (hasnull ? td->t_bits : NULL));
1193 :
1194 23248340 : return tuple;
1195 : }
1196 :
1197 : /*
1198 : * heap_modify_tuple
1199 : * form a new tuple from an old tuple and a set of replacement values.
1200 : *
1201 : * The replValues, replIsnull, and doReplace arrays must be of the length
1202 : * indicated by tupleDesc->natts. The new tuple is constructed using the data
1203 : * from replValues/replIsnull at columns where doReplace is true, and using
1204 : * the data from the old tuple at columns where doReplace is false.
1205 : *
1206 : * The result is allocated in the current memory context.
1207 : */
1208 : HeapTuple
1209 89306 : heap_modify_tuple(HeapTuple tuple,
1210 : TupleDesc tupleDesc,
1211 : const Datum *replValues,
1212 : const bool *replIsnull,
1213 : const bool *doReplace)
1214 : {
1215 89306 : int numberOfAttributes = tupleDesc->natts;
1216 : int attoff;
1217 : Datum *values;
1218 : bool *isnull;
1219 : HeapTuple newTuple;
1220 :
1221 : /*
1222 : * allocate and fill values and isnull arrays from either the tuple or the
1223 : * repl information, as appropriate.
1224 : *
1225 : * NOTE: it's debatable whether to use heap_deform_tuple() here or just
1226 : * heap_getattr() only the non-replaced columns. The latter could win if
1227 : * there are many replaced columns and few non-replaced ones. However,
1228 : * heap_deform_tuple costs only O(N) while the heap_getattr way would cost
1229 : * O(N^2) if there are many non-replaced columns, so it seems better to
1230 : * err on the side of linear cost.
1231 : */
1232 89306 : values = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
1233 89306 : isnull = (bool *) palloc(numberOfAttributes * sizeof(bool));
1234 :
1235 89306 : heap_deform_tuple(tuple, tupleDesc, values, isnull);
1236 :
1237 2685952 : for (attoff = 0; attoff < numberOfAttributes; attoff++)
1238 : {
1239 2596646 : if (doReplace[attoff])
1240 : {
1241 1152272 : values[attoff] = replValues[attoff];
1242 1152272 : isnull[attoff] = replIsnull[attoff];
1243 : }
1244 : }
1245 :
1246 : /*
1247 : * create a new tuple from the values and isnull arrays
1248 : */
1249 89306 : newTuple = heap_form_tuple(tupleDesc, values, isnull);
1250 :
1251 89306 : pfree(values);
1252 89306 : pfree(isnull);
1253 :
1254 : /*
1255 : * copy the identification info of the old tuple: t_ctid, t_self
1256 : */
1257 89306 : newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
1258 89306 : newTuple->t_self = tuple->t_self;
1259 89306 : newTuple->t_tableOid = tuple->t_tableOid;
1260 :
1261 89306 : return newTuple;
1262 : }
1263 :
1264 : /*
1265 : * heap_modify_tuple_by_cols
1266 : * form a new tuple from an old tuple and a set of replacement values.
1267 : *
1268 : * This is like heap_modify_tuple, except that instead of specifying which
1269 : * column(s) to replace by a boolean map, an array of target column numbers
1270 : * is used. This is often more convenient when a fixed number of columns
1271 : * are to be replaced. The replCols, replValues, and replIsnull arrays must
1272 : * be of length nCols. Target column numbers are indexed from 1.
1273 : *
1274 : * The result is allocated in the current memory context.
1275 : */
1276 : HeapTuple
1277 102 : heap_modify_tuple_by_cols(HeapTuple tuple,
1278 : TupleDesc tupleDesc,
1279 : int nCols,
1280 : const int *replCols,
1281 : const Datum *replValues,
1282 : const bool *replIsnull)
1283 : {
1284 102 : int numberOfAttributes = tupleDesc->natts;
1285 : Datum *values;
1286 : bool *isnull;
1287 : HeapTuple newTuple;
1288 : int i;
1289 :
1290 : /*
1291 : * allocate and fill values and isnull arrays from the tuple, then replace
1292 : * selected columns from the input arrays.
1293 : */
1294 102 : values = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
1295 102 : isnull = (bool *) palloc(numberOfAttributes * sizeof(bool));
1296 :
1297 102 : heap_deform_tuple(tuple, tupleDesc, values, isnull);
1298 :
1299 252 : for (i = 0; i < nCols; i++)
1300 : {
1301 150 : int attnum = replCols[i];
1302 :
1303 150 : if (attnum <= 0 || attnum > numberOfAttributes)
1304 0 : elog(ERROR, "invalid column number %d", attnum);
1305 150 : values[attnum - 1] = replValues[i];
1306 150 : isnull[attnum - 1] = replIsnull[i];
1307 : }
1308 :
1309 : /*
1310 : * create a new tuple from the values and isnull arrays
1311 : */
1312 102 : newTuple = heap_form_tuple(tupleDesc, values, isnull);
1313 :
1314 102 : pfree(values);
1315 102 : pfree(isnull);
1316 :
1317 : /*
1318 : * copy the identification info of the old tuple: t_ctid, t_self
1319 : */
1320 102 : newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
1321 102 : newTuple->t_self = tuple->t_self;
1322 102 : newTuple->t_tableOid = tuple->t_tableOid;
1323 :
1324 102 : return newTuple;
1325 : }
1326 :
1327 : /*
1328 : * heap_deform_tuple
1329 : * Given a tuple, extract data into values/isnull arrays; this is
1330 : * the inverse of heap_form_tuple.
1331 : *
1332 : * Storage for the values/isnull arrays is provided by the caller;
1333 : * it should be sized according to tupleDesc->natts not
1334 : * HeapTupleHeaderGetNatts(tuple->t_data).
1335 : *
1336 : * Note that for pass-by-reference datatypes, the pointer placed
1337 : * in the Datum will point into the given tuple.
1338 : *
1339 : * When all or most of a tuple's fields need to be extracted,
1340 : * this routine will be significantly quicker than a loop around
1341 : * heap_getattr; the loop will become O(N^2) as soon as any
1342 : * noncacheable attribute offsets are involved.
1343 : */
1344 : void
1345 5523044 : heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
1346 : Datum *values, bool *isnull)
1347 : {
1348 5523044 : HeapTupleHeader tup = tuple->t_data;
1349 5523044 : bool hasnulls = HeapTupleHasNulls(tuple);
1350 5523044 : int tdesc_natts = tupleDesc->natts;
1351 : int natts; /* number of atts to extract */
1352 : int attnum;
1353 : char *tp; /* ptr to tuple data */
1354 : uint32 off; /* offset in tuple data */
1355 5523044 : bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
1356 5523044 : bool slow = false; /* can we use/set attcacheoff? */
1357 :
1358 5523044 : natts = HeapTupleHeaderGetNatts(tup);
1359 :
1360 : /*
1361 : * In inheritance situations, it is possible that the given tuple actually
1362 : * has more fields than the caller is expecting. Don't run off the end of
1363 : * the caller's arrays.
1364 : */
1365 5523044 : natts = Min(natts, tdesc_natts);
1366 :
1367 5523044 : tp = (char *) tup + tup->t_hoff;
1368 :
1369 5523044 : off = 0;
1370 :
1371 20797216 : for (attnum = 0; attnum < natts; attnum++)
1372 : {
1373 15274172 : Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
1374 :
1375 15274172 : if (hasnulls && att_isnull(attnum, bp))
1376 : {
1377 941436 : values[attnum] = (Datum) 0;
1378 941436 : isnull[attnum] = true;
1379 941436 : slow = true; /* can't use attcacheoff anymore */
1380 941436 : continue;
1381 : }
1382 :
1383 14332736 : isnull[attnum] = false;
1384 :
1385 14332736 : if (!slow && thisatt->attcacheoff >= 0)
1386 13545486 : off = thisatt->attcacheoff;
1387 787250 : else if (thisatt->attlen == -1)
1388 : {
1389 : /*
1390 : * We can only cache the offset for a varlena attribute if the
1391 : * offset is already suitably aligned, so that there would be no
1392 : * pad bytes in any case: then the offset will be valid for either
1393 : * an aligned or unaligned value.
1394 : */
1395 456594 : if (!slow &&
1396 84094 : off == att_align_nominal(off, thisatt->attalign))
1397 47040 : thisatt->attcacheoff = off;
1398 : else
1399 : {
1400 325460 : off = att_align_pointer(off, thisatt->attalign, -1,
1401 : tp + off);
1402 325460 : slow = true;
1403 : }
1404 : }
1405 : else
1406 : {
1407 : /* not varlena, so safe to use att_align_nominal */
1408 414750 : off = att_align_nominal(off, thisatt->attalign);
1409 :
1410 414750 : if (!slow)
1411 71798 : thisatt->attcacheoff = off;
1412 : }
1413 :
1414 14332736 : values[attnum] = fetchatt(thisatt, tp + off);
1415 :
1416 14332736 : off = att_addlength_pointer(off, thisatt->attlen, tp + off);
1417 :
1418 14332736 : if (thisatt->attlen <= 0)
1419 2538362 : slow = true; /* can't use attcacheoff anymore */
1420 : }
1421 :
1422 : /*
1423 : * If tuple doesn't have all the atts indicated by tupleDesc, read the
1424 : * rest as nulls or missing values as appropriate.
1425 : */
1426 5523068 : for (; attnum < tdesc_natts; attnum++)
1427 24 : values[attnum] = getmissingattr(tupleDesc, attnum + 1, &isnull[attnum]);
1428 5523044 : }
1429 :
1430 : /*
1431 : * heap_freetuple
1432 : */
1433 : void
1434 19859674 : heap_freetuple(HeapTuple htup)
1435 : {
1436 19859674 : pfree(htup);
1437 19859674 : }
1438 :
1439 :
1440 : /*
1441 : * heap_form_minimal_tuple
1442 : * construct a MinimalTuple from the given values[] and isnull[] arrays,
1443 : * which are of the length indicated by tupleDescriptor->natts
1444 : *
1445 : * This is exactly like heap_form_tuple() except that the result is a
1446 : * "minimal" tuple lacking a HeapTupleData header as well as room for system
1447 : * columns.
1448 : *
1449 : * The result is allocated in the current memory context.
1450 : */
1451 : MinimalTuple
1452 42658562 : heap_form_minimal_tuple(TupleDesc tupleDescriptor,
1453 : const Datum *values,
1454 : const bool *isnull)
1455 : {
1456 : MinimalTuple tuple; /* return tuple */
1457 : Size len,
1458 : data_len;
1459 : int hoff;
1460 42658562 : bool hasnull = false;
1461 42658562 : int numberOfAttributes = tupleDescriptor->natts;
1462 : int i;
1463 :
1464 42658562 : if (numberOfAttributes > MaxTupleAttributeNumber)
1465 0 : ereport(ERROR,
1466 : (errcode(ERRCODE_TOO_MANY_COLUMNS),
1467 : errmsg("number of columns (%d) exceeds limit (%d)",
1468 : numberOfAttributes, MaxTupleAttributeNumber)));
1469 :
1470 : /*
1471 : * Check for nulls
1472 : */
1473 120455518 : for (i = 0; i < numberOfAttributes; i++)
1474 : {
1475 78385408 : if (isnull[i])
1476 : {
1477 588452 : hasnull = true;
1478 588452 : break;
1479 : }
1480 : }
1481 :
1482 : /*
1483 : * Determine total space needed
1484 : */
1485 42658562 : len = SizeofMinimalTupleHeader;
1486 :
1487 42658562 : if (hasnull)
1488 588452 : len += BITMAPLEN(numberOfAttributes);
1489 :
1490 42658562 : hoff = len = MAXALIGN(len); /* align user data safely */
1491 :
1492 42658562 : data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
1493 :
1494 42658562 : len += data_len;
1495 :
1496 : /*
1497 : * Allocate and zero the space needed.
1498 : */
1499 42658562 : tuple = (MinimalTuple) palloc0(len);
1500 :
1501 : /*
1502 : * And fill in the information.
1503 : */
1504 42658562 : tuple->t_len = len;
1505 42658562 : HeapTupleHeaderSetNatts(tuple, numberOfAttributes);
1506 42658562 : tuple->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
1507 :
1508 42658562 : heap_fill_tuple(tupleDescriptor,
1509 : values,
1510 : isnull,
1511 : (char *) tuple + hoff,
1512 : data_len,
1513 : &tuple->t_infomask,
1514 : (hasnull ? tuple->t_bits : NULL));
1515 :
1516 42658562 : return tuple;
1517 : }
1518 :
1519 : /*
1520 : * heap_free_minimal_tuple
1521 : */
1522 : void
1523 30212510 : heap_free_minimal_tuple(MinimalTuple mtup)
1524 : {
1525 30212510 : pfree(mtup);
1526 30212510 : }
1527 :
1528 : /*
1529 : * heap_copy_minimal_tuple
1530 : * copy a MinimalTuple
1531 : *
1532 : * The result is allocated in the current memory context.
1533 : */
1534 : MinimalTuple
1535 4428506 : heap_copy_minimal_tuple(MinimalTuple mtup)
1536 : {
1537 : MinimalTuple result;
1538 :
1539 4428506 : result = (MinimalTuple) palloc(mtup->t_len);
1540 4428506 : memcpy(result, mtup, mtup->t_len);
1541 4428506 : return result;
1542 : }
1543 :
1544 : /*
1545 : * heap_tuple_from_minimal_tuple
1546 : * create a HeapTuple by copying from a MinimalTuple;
1547 : * system columns are filled with zeroes
1548 : *
1549 : * The result is allocated in the current memory context.
1550 : * The HeapTuple struct, tuple header, and tuple data are all allocated
1551 : * as a single palloc() block.
1552 : */
1553 : HeapTuple
1554 877504 : heap_tuple_from_minimal_tuple(MinimalTuple mtup)
1555 : {
1556 : HeapTuple result;
1557 877504 : uint32 len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
1558 :
1559 877504 : result = (HeapTuple) palloc(HEAPTUPLESIZE + len);
1560 877504 : result->t_len = len;
1561 877504 : ItemPointerSetInvalid(&(result->t_self));
1562 877504 : result->t_tableOid = InvalidOid;
1563 877504 : result->t_data = (HeapTupleHeader) ((char *) result + HEAPTUPLESIZE);
1564 877504 : memcpy((char *) result->t_data + MINIMAL_TUPLE_OFFSET, mtup, mtup->t_len);
1565 877504 : memset(result->t_data, 0, offsetof(HeapTupleHeaderData, t_infomask2));
1566 877504 : return result;
1567 : }
1568 :
1569 : /*
1570 : * minimal_tuple_from_heap_tuple
1571 : * create a MinimalTuple by copying from a HeapTuple
1572 : *
1573 : * The result is allocated in the current memory context.
1574 : */
1575 : MinimalTuple
1576 3982980 : minimal_tuple_from_heap_tuple(HeapTuple htup)
1577 : {
1578 : MinimalTuple result;
1579 : uint32 len;
1580 :
1581 : Assert(htup->t_len > MINIMAL_TUPLE_OFFSET);
1582 3982980 : len = htup->t_len - MINIMAL_TUPLE_OFFSET;
1583 3982980 : result = (MinimalTuple) palloc(len);
1584 3982980 : memcpy(result, (char *) htup->t_data + MINIMAL_TUPLE_OFFSET, len);
1585 3982980 : result->t_len = len;
1586 3982980 : return result;
1587 : }
1588 :
1589 : /*
1590 : * This mainly exists so JIT can inline the definition, but it's also
1591 : * sometimes useful in debugging sessions.
1592 : */
1593 : size_t
1594 324468 : varsize_any(void *p)
1595 : {
1596 324468 : return VARSIZE_ANY(p);
1597 : }
|