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-2026, 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 : /* FormData_pg_attribute.attstorage != TYPSTORAGE_PLAIN and an attlen of -1 */
87 : #define COMPACT_ATTR_IS_PACKABLE(att) \
88 : ((att)->attlen == -1 && (att)->attispackable)
89 :
90 : /*
91 : * Setup for caching pass-by-ref missing attributes in a way that survives
92 : * tupleDesc destruction.
93 : */
94 :
95 : typedef struct
96 : {
97 : int len;
98 : Datum value;
99 : } missing_cache_key;
100 :
101 : static HTAB *missing_cache = NULL;
102 :
103 : static uint32
104 0 : missing_hash(const void *key, Size keysize)
105 : {
106 0 : const missing_cache_key *entry = key;
107 :
108 0 : return hash_bytes((const unsigned char *) DatumGetPointer(entry->value), entry->len);
109 : }
110 :
111 : static int
112 0 : missing_match(const void *key1, const void *key2, Size keysize)
113 : {
114 0 : const missing_cache_key *entry1 = key1;
115 0 : const missing_cache_key *entry2 = key2;
116 :
117 0 : if (entry1->len != entry2->len)
118 0 : return entry1->len > entry2->len ? 1 : -1;
119 :
120 0 : return memcmp(DatumGetPointer(entry1->value),
121 0 : DatumGetPointer(entry2->value),
122 0 : entry1->len);
123 : }
124 :
125 : static void
126 0 : init_missing_cache(void)
127 : {
128 : HASHCTL hash_ctl;
129 :
130 0 : hash_ctl.keysize = sizeof(missing_cache_key);
131 0 : hash_ctl.entrysize = sizeof(missing_cache_key);
132 0 : hash_ctl.hcxt = TopMemoryContext;
133 0 : hash_ctl.hash = missing_hash;
134 0 : hash_ctl.match = missing_match;
135 0 : missing_cache =
136 0 : hash_create("Missing Values Cache",
137 : 32,
138 : &hash_ctl,
139 : HASH_ELEM | HASH_CONTEXT | HASH_FUNCTION | HASH_COMPARE);
140 0 : }
141 :
142 : /* ----------------------------------------------------------------
143 : * misc support routines
144 : * ----------------------------------------------------------------
145 : */
146 :
147 : /*
148 : * Return the missing value of an attribute, or NULL if there isn't one.
149 : */
150 : Datum
151 233 : getmissingattr(TupleDesc tupleDesc,
152 : int attnum, bool *isnull)
153 : {
154 : CompactAttribute *att;
155 :
156 : Assert(attnum <= tupleDesc->natts);
157 : Assert(attnum > 0);
158 :
159 233 : att = TupleDescCompactAttr(tupleDesc, attnum - 1);
160 :
161 233 : if (att->atthasmissing)
162 : {
163 : AttrMissing *attrmiss;
164 :
165 : Assert(tupleDesc->constr);
166 : Assert(tupleDesc->constr->missing);
167 :
168 36 : attrmiss = tupleDesc->constr->missing + (attnum - 1);
169 :
170 36 : if (attrmiss->am_present)
171 : {
172 : missing_cache_key key;
173 : missing_cache_key *entry;
174 : bool found;
175 : MemoryContext oldctx;
176 :
177 36 : *isnull = false;
178 :
179 : /* no need to cache by-value attributes */
180 36 : if (att->attbyval)
181 36 : return attrmiss->am_value;
182 :
183 : /* set up cache if required */
184 0 : if (missing_cache == NULL)
185 0 : init_missing_cache();
186 :
187 : /* check if there's a cache entry */
188 : Assert(att->attlen > 0 || att->attlen == -1);
189 0 : if (att->attlen > 0)
190 0 : key.len = att->attlen;
191 : else
192 0 : key.len = VARSIZE_ANY(DatumGetPointer(attrmiss->am_value));
193 0 : key.value = attrmiss->am_value;
194 :
195 0 : entry = hash_search(missing_cache, &key, HASH_ENTER, &found);
196 :
197 0 : if (!found)
198 : {
199 : /* cache miss, so we need a non-transient copy of the datum */
200 0 : oldctx = MemoryContextSwitchTo(TopMemoryContext);
201 0 : entry->value =
202 0 : datumCopy(attrmiss->am_value, false, att->attlen);
203 0 : MemoryContextSwitchTo(oldctx);
204 : }
205 :
206 0 : return entry->value;
207 : }
208 : }
209 :
210 197 : *isnull = true;
211 197 : return PointerGetDatum(NULL);
212 : }
213 :
214 : /*
215 : * heap_compute_data_size
216 : * Determine size of the data area of a tuple to be constructed
217 : */
218 : Size
219 81516730 : heap_compute_data_size(TupleDesc tupleDesc,
220 : const Datum *values,
221 : const bool *isnull)
222 : {
223 81516730 : Size data_length = 0;
224 : int i;
225 81516730 : int numberOfAttributes = tupleDesc->natts;
226 :
227 275624265 : for (i = 0; i < numberOfAttributes; i++)
228 : {
229 : Datum val;
230 : CompactAttribute *atti;
231 :
232 194107535 : if (isnull[i])
233 16240779 : continue;
234 :
235 177866756 : val = values[i];
236 177866756 : atti = TupleDescCompactAttr(tupleDesc, i);
237 :
238 200484148 : if (COMPACT_ATTR_IS_PACKABLE(atti) &&
239 22617392 : VARATT_CAN_MAKE_SHORT(DatumGetPointer(val)))
240 : {
241 : /*
242 : * we're anticipating converting to a short varlena header, so
243 : * adjust length and don't count any alignment
244 : */
245 17288692 : data_length += VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val));
246 : }
247 167067479 : else if (atti->attlen == -1 &&
248 6489415 : VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
249 : {
250 : /*
251 : * we want to flatten the expanded value so that the constructed
252 : * tuple doesn't depend on it
253 : */
254 1855 : data_length = att_nominal_alignby(data_length, atti->attalignby);
255 1855 : data_length += EOH_get_flat_size(DatumGetEOHP(val));
256 : }
257 : else
258 : {
259 160576209 : data_length = att_datum_alignby(data_length, atti->attalignby,
260 : atti->attlen, val);
261 160576209 : data_length = att_addlength_datum(data_length, atti->attlen,
262 : val);
263 : }
264 : }
265 :
266 81516730 : return data_length;
267 : }
268 :
269 : /*
270 : * Per-attribute helper for heap_fill_tuple and other routines building tuples.
271 : *
272 : * Fill in either a data value or a bit in the null bitmask
273 : */
274 : static inline void
275 179661816 : fill_val(CompactAttribute *att,
276 : uint8 **bit,
277 : int *bitmask,
278 : char **dataP,
279 : uint16 *infomask,
280 : Datum datum,
281 : bool isnull)
282 : {
283 : Size data_length;
284 179661816 : char *data = *dataP;
285 :
286 : /*
287 : * If we're building a null bitmap, set the appropriate bit for the
288 : * current column value here.
289 : */
290 179661816 : if (bit != NULL)
291 : {
292 60816889 : if (*bitmask != HIGHBIT)
293 50477264 : *bitmask <<= 1;
294 : else
295 : {
296 10339625 : *bit += 1;
297 10339625 : **bit = 0x0;
298 10339625 : *bitmask = 1;
299 : }
300 :
301 60816889 : if (isnull)
302 : {
303 16095687 : *infomask |= HEAP_HASNULL;
304 16095687 : return;
305 : }
306 :
307 44721202 : **bit |= *bitmask;
308 : }
309 :
310 : /*
311 : * XXX we use the att_nominal_alignby macro on the pointer value itself,
312 : * not on an offset. This is a bit of a hack.
313 : */
314 163566129 : if (att->attbyval)
315 : {
316 : /* pass-by-value */
317 124484271 : data = (char *) att_nominal_alignby(data, att->attalignby);
318 124484271 : store_att_byval(data, datum, att->attlen);
319 124484271 : data_length = att->attlen;
320 : }
321 39081858 : else if (att->attlen == -1)
322 : {
323 : /* varlena */
324 22753631 : Pointer val = DatumGetPointer(datum);
325 :
326 22753631 : *infomask |= HEAP_HASVARWIDTH;
327 22753631 : if (VARATT_IS_EXTERNAL(val))
328 : {
329 15520 : if (VARATT_IS_EXTERNAL_EXPANDED(val))
330 : {
331 : /*
332 : * we want to flatten the expanded value so that the
333 : * constructed tuple doesn't depend on it
334 : */
335 1855 : ExpandedObjectHeader *eoh = DatumGetEOHP(datum);
336 :
337 1855 : data = (char *) att_nominal_alignby(data, att->attalignby);
338 1855 : data_length = EOH_get_flat_size(eoh);
339 1855 : EOH_flatten_into(eoh, data, data_length);
340 : }
341 : else
342 : {
343 13665 : *infomask |= HEAP_HASEXTERNAL;
344 : /* no alignment, since it's short by definition */
345 13665 : data_length = VARSIZE_EXTERNAL(val);
346 13665 : memcpy(data, val, data_length);
347 : }
348 : }
349 22738111 : else if (VARATT_IS_SHORT(val))
350 : {
351 : /* no alignment for short varlenas */
352 4244604 : data_length = VARSIZE_SHORT(val);
353 4244604 : memcpy(data, val, data_length);
354 : }
355 18493507 : else if (att->attispackable && VARATT_CAN_MAKE_SHORT(val))
356 : {
357 : /* convert to short varlena -- no alignment */
358 16672921 : data_length = VARATT_CONVERTED_SHORT_SIZE(val);
359 16672921 : SET_VARSIZE_SHORT(data, data_length);
360 16672921 : memcpy(data + 1, VARDATA(val), data_length - 1);
361 : }
362 : else
363 : {
364 : /* full 4-byte header varlena */
365 1820586 : data = (char *) att_nominal_alignby(data, att->attalignby);
366 1820586 : data_length = VARSIZE(val);
367 1820586 : memcpy(data, val, data_length);
368 : }
369 : }
370 16328227 : else if (att->attlen == -2)
371 : {
372 : /* cstring ... never needs alignment */
373 1551897 : *infomask |= HEAP_HASVARWIDTH;
374 : Assert(att->attalignby == sizeof(char));
375 1551897 : data_length = strlen(DatumGetCString(datum)) + 1;
376 1551897 : memcpy(data, DatumGetPointer(datum), data_length);
377 : }
378 : else
379 : {
380 : /* fixed-length pass-by-reference */
381 14776330 : data = (char *) att_nominal_alignby(data, att->attalignby);
382 : Assert(att->attlen > 0);
383 14776330 : data_length = att->attlen;
384 14776330 : memcpy(data, DatumGetPointer(datum), data_length);
385 : }
386 :
387 163566129 : data += data_length;
388 163566129 : *dataP = data;
389 : }
390 :
391 : /*
392 : * heap_fill_tuple
393 : * Load data portion of a tuple from values/isnull arrays
394 : *
395 : * We also fill the null bitmap (if any) and set the infomask bits
396 : * that reflect the tuple's data contents.
397 : *
398 : * NOTE: it is now REQUIRED that the caller have pre-zeroed the data area.
399 : */
400 : void
401 68414025 : heap_fill_tuple(TupleDesc tupleDesc,
402 : const Datum *values, const bool *isnull,
403 : char *data, Size data_size,
404 : uint16 *infomask, uint8 *bit)
405 : {
406 : uint8 *bitP;
407 : int bitmask;
408 : int i;
409 68414025 : int numberOfAttributes = tupleDesc->natts;
410 :
411 : #ifdef USE_ASSERT_CHECKING
412 : char *start = data;
413 : #endif
414 :
415 68414025 : if (bit != NULL)
416 : {
417 4284532 : bitP = &bit[-1];
418 4284532 : bitmask = HIGHBIT;
419 : }
420 : else
421 : {
422 : /* just to keep compiler quiet */
423 64129493 : bitP = NULL;
424 64129493 : bitmask = 0;
425 : }
426 :
427 68414025 : *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTERNAL);
428 :
429 248075841 : for (i = 0; i < numberOfAttributes; i++)
430 : {
431 179661816 : CompactAttribute *attr = TupleDescCompactAttr(tupleDesc, i);
432 :
433 538985448 : fill_val(attr,
434 179661816 : bitP ? &bitP : NULL,
435 : &bitmask,
436 : &data,
437 : infomask,
438 179661816 : values ? values[i] : PointerGetDatum(NULL),
439 179661816 : isnull ? isnull[i] : true);
440 : }
441 :
442 : Assert((data - start) == data_size);
443 68414025 : }
444 :
445 :
446 : /* ----------------------------------------------------------------
447 : * heap tuple interface
448 : * ----------------------------------------------------------------
449 : */
450 :
451 : /* ----------------
452 : * heap_attisnull - returns true iff tuple attribute is not present
453 : * ----------------
454 : */
455 : bool
456 6709689 : heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
457 : {
458 : /*
459 : * We allow a NULL tupledesc for relations not expected to have missing
460 : * values, such as catalog relations and indexes.
461 : */
462 : Assert(!tupleDesc || attnum <= tupleDesc->natts);
463 6709689 : if (attnum > (int) HeapTupleHeaderGetNatts(tup->t_data))
464 : {
465 0 : if (tupleDesc &&
466 0 : TupleDescCompactAttr(tupleDesc, attnum - 1)->atthasmissing)
467 0 : return false;
468 : else
469 0 : return true;
470 : }
471 :
472 6709689 : if (attnum > 0)
473 : {
474 6709689 : if (HeapTupleNoNulls(tup))
475 1974 : return false;
476 6707715 : return att_isnull(attnum - 1, tup->t_data->t_bits);
477 : }
478 :
479 0 : switch (attnum)
480 : {
481 0 : case TableOidAttributeNumber:
482 : case SelfItemPointerAttributeNumber:
483 : case MinTransactionIdAttributeNumber:
484 : case MinCommandIdAttributeNumber:
485 : case MaxTransactionIdAttributeNumber:
486 : case MaxCommandIdAttributeNumber:
487 : /* these are never null */
488 0 : break;
489 :
490 0 : default:
491 0 : elog(ERROR, "invalid attnum: %d", attnum);
492 : }
493 :
494 0 : return false;
495 : }
496 :
497 : /* ----------------
498 : * nocachegetattr
499 : *
500 : * This only gets called from fastgetattr(), in cases where we
501 : * can't use the attcacheoff and the value is not null.
502 : *
503 : * NOTE: if you need to change this code, see also heap_deform_tuple.
504 : * Also see nocache_index_getattr, which is the same code for index
505 : * tuples.
506 : * ----------------
507 : */
508 : Datum
509 141982118 : nocachegetattr(HeapTuple tup,
510 : int attnum,
511 : TupleDesc tupleDesc)
512 : {
513 : CompactAttribute *cattr;
514 141982118 : HeapTupleHeader td = tup->t_data;
515 : char *tp; /* ptr to data part of tuple */
516 141982118 : uint8 *bp = td->t_bits; /* ptr to null bitmap in tuple */
517 : int off; /* current offset within data */
518 : int startAttr;
519 : int firstNullAttr;
520 : int i;
521 141982118 : bool hasnulls = HeapTupleHasNulls(tup);
522 :
523 : /* Did someone forget to call TupleDescFinalize()? */
524 : Assert(tupleDesc->firstNonCachedOffsetAttr >= 0);
525 :
526 141982118 : attnum--;
527 :
528 : /*
529 : * To minimize the number of attributes we need to look at, start walking
530 : * the tuple at the attribute with the highest attcacheoff prior to attnum
531 : * or the first NULL attribute prior to attnum, whichever comes first.
532 : */
533 141982118 : if (hasnulls)
534 100432657 : firstNullAttr = first_null_attr(bp, attnum);
535 : else
536 41549461 : firstNullAttr = attnum;
537 :
538 141982118 : if (tupleDesc->firstNonCachedOffsetAttr > 0 && firstNullAttr > 0)
539 : {
540 : /*
541 : * Try to start with the highest attribute with an attcacheoff that's
542 : * prior to the one we're looking for, or with the attribute prior to
543 : * the first NULL attribute, if there is one.
544 : */
545 48196815 : startAttr = Min(tupleDesc->firstNonCachedOffsetAttr - 1, firstNullAttr - 1);
546 48196815 : off = TupleDescCompactAttr(tupleDesc, startAttr)->attcacheoff;
547 : }
548 : else
549 : {
550 : /* Otherwise, start at the beginning... */
551 93785303 : startAttr = 0;
552 93785303 : off = 0;
553 : }
554 :
555 141982118 : tp = (char *) td + td->t_hoff;
556 :
557 : /*
558 : * Calculate 'off' up to the first NULL attr. We use two cheaper loops
559 : * when the tuple has no variable-width columns. When variable-width
560 : * columns exists, we use att_addlength_pointer() to move the offset
561 : * beyond the current attribute.
562 : */
563 141982118 : if (!HeapTupleHasVarWidth(tup))
564 : {
565 95401527 : for (i = startAttr; i < firstNullAttr; i++)
566 : {
567 23462270 : cattr = TupleDescCompactAttr(tupleDesc, i);
568 :
569 23462270 : off = att_nominal_alignby(off, cattr->attalignby);
570 23462270 : off += cattr->attlen;
571 : }
572 :
573 76005610 : for (; i < attnum; i++)
574 : {
575 4066353 : if (att_isnull(i, bp))
576 3321402 : continue;
577 :
578 744951 : cattr = TupleDescCompactAttr(tupleDesc, i);
579 :
580 744951 : off = att_nominal_alignby(off, cattr->attalignby);
581 744951 : off += cattr->attlen;
582 : }
583 : }
584 : else
585 : {
586 177097361 : for (i = startAttr; i < firstNullAttr; i++)
587 : {
588 : int attlen;
589 :
590 107054500 : cattr = TupleDescCompactAttr(tupleDesc, i);
591 107054500 : attlen = cattr->attlen;
592 107054500 : off = att_pointer_alignby(off,
593 : cattr->attalignby,
594 : attlen,
595 : tp + off);
596 107054500 : off = att_addlength_pointer(off, attlen, tp + off);
597 : }
598 :
599 81938655 : for (; i < attnum; i++)
600 : {
601 : int attlen;
602 :
603 11895794 : if (att_isnull(i, bp))
604 8321348 : continue;
605 :
606 3574446 : cattr = TupleDescCompactAttr(tupleDesc, i);
607 3574446 : attlen = cattr->attlen;
608 3574446 : off = att_pointer_alignby(off, cattr->attalignby, attlen,
609 : tp + off);
610 3574446 : off = att_addlength_pointer(off, attlen, tp + off);
611 : }
612 : }
613 :
614 141982118 : cattr = TupleDescCompactAttr(tupleDesc, attnum);
615 141982118 : off = att_pointer_alignby(off,
616 : cattr->attalignby,
617 : cattr->attlen,
618 : tp + off);
619 :
620 141982118 : return fetchatt(cattr, tp + off);
621 : }
622 :
623 : /* ----------------
624 : * heap_getsysattr
625 : *
626 : * Fetch the value of a system attribute for a tuple.
627 : *
628 : * This is a support routine for heap_getattr(). The function has already
629 : * determined that the attnum refers to a system attribute.
630 : * ----------------
631 : */
632 : Datum
633 72813 : heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
634 : {
635 : Datum result;
636 :
637 : Assert(tup);
638 :
639 : /* Currently, no sys attribute ever reads as NULL. */
640 72813 : *isnull = false;
641 :
642 72813 : switch (attnum)
643 : {
644 2 : case SelfItemPointerAttributeNumber:
645 : /* pass-by-reference datatype */
646 2 : result = PointerGetDatum(&(tup->t_self));
647 2 : break;
648 72566 : case MinTransactionIdAttributeNumber:
649 72566 : result = TransactionIdGetDatum(HeapTupleHeaderGetRawXmin(tup->t_data));
650 72566 : break;
651 119 : case MaxTransactionIdAttributeNumber:
652 119 : result = TransactionIdGetDatum(HeapTupleHeaderGetRawXmax(tup->t_data));
653 119 : break;
654 124 : case MinCommandIdAttributeNumber:
655 : case MaxCommandIdAttributeNumber:
656 :
657 : /*
658 : * cmin and cmax are now both aliases for the same field, which
659 : * can in fact also be a combo command id. XXX perhaps we should
660 : * return the "real" cmin or cmax if possible, that is if we are
661 : * inside the originating transaction?
662 : */
663 124 : result = CommandIdGetDatum(HeapTupleHeaderGetRawCommandId(tup->t_data));
664 124 : break;
665 2 : case TableOidAttributeNumber:
666 2 : result = ObjectIdGetDatum(tup->t_tableOid);
667 2 : break;
668 0 : default:
669 0 : elog(ERROR, "invalid attnum: %d", attnum);
670 : result = 0; /* keep compiler quiet */
671 : break;
672 : }
673 72813 : return result;
674 : }
675 :
676 : /* ----------------
677 : * heap_copytuple
678 : *
679 : * returns a copy of an entire tuple
680 : *
681 : * The HeapTuple struct, tuple header, and tuple data are all allocated
682 : * as a single palloc() block.
683 : * ----------------
684 : */
685 : HeapTuple
686 10706382 : heap_copytuple(HeapTuple tuple)
687 : {
688 : HeapTuple newTuple;
689 :
690 10706382 : if (!HeapTupleIsValid(tuple) || tuple->t_data == NULL)
691 0 : return NULL;
692 :
693 10706382 : newTuple = (HeapTuple) palloc(HEAPTUPLESIZE + tuple->t_len);
694 10706382 : newTuple->t_len = tuple->t_len;
695 10706382 : newTuple->t_self = tuple->t_self;
696 10706382 : newTuple->t_tableOid = tuple->t_tableOid;
697 10706382 : newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
698 10706382 : memcpy(newTuple->t_data, tuple->t_data, tuple->t_len);
699 10706382 : return newTuple;
700 : }
701 :
702 : /* ----------------
703 : * heap_copytuple_with_tuple
704 : *
705 : * copy a tuple into a caller-supplied HeapTuple management struct
706 : *
707 : * Note that after calling this function, the "dest" HeapTuple will not be
708 : * allocated as a single palloc() block (unlike with heap_copytuple()).
709 : * ----------------
710 : */
711 : void
712 0 : heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest)
713 : {
714 0 : if (!HeapTupleIsValid(src) || src->t_data == NULL)
715 : {
716 0 : dest->t_data = NULL;
717 0 : return;
718 : }
719 :
720 0 : dest->t_len = src->t_len;
721 0 : dest->t_self = src->t_self;
722 0 : dest->t_tableOid = src->t_tableOid;
723 0 : dest->t_data = (HeapTupleHeader) palloc(src->t_len);
724 0 : memcpy(dest->t_data, src->t_data, src->t_len);
725 : }
726 :
727 : /*
728 : * Expand a tuple which has fewer attributes than required. For each attribute
729 : * not present in the sourceTuple, if there is a missing value that will be
730 : * used. Otherwise the attribute will be set to NULL.
731 : *
732 : * The source tuple must have fewer attributes than the required number.
733 : *
734 : * Only one of targetHeapTuple and targetMinimalTuple may be supplied. The
735 : * other argument must be NULL.
736 : */
737 : static void
738 0 : expand_tuple(HeapTuple *targetHeapTuple,
739 : MinimalTuple *targetMinimalTuple,
740 : HeapTuple sourceTuple,
741 : TupleDesc tupleDesc)
742 : {
743 0 : AttrMissing *attrmiss = NULL;
744 : int attnum;
745 : int firstmissingnum;
746 0 : bool hasNulls = HeapTupleHasNulls(sourceTuple);
747 : HeapTupleHeader targetTHeader;
748 0 : HeapTupleHeader sourceTHeader = sourceTuple->t_data;
749 0 : int sourceNatts = HeapTupleHeaderGetNatts(sourceTHeader);
750 0 : int natts = tupleDesc->natts;
751 : int sourceNullLen;
752 : int targetNullLen;
753 0 : Size sourceDataLen = sourceTuple->t_len - sourceTHeader->t_hoff;
754 : Size targetDataLen;
755 : Size len;
756 : int hoff;
757 0 : uint8 *nullBits = NULL;
758 0 : int bitMask = 0;
759 : char *targetData;
760 : uint16 *infoMask;
761 :
762 : Assert((targetHeapTuple && !targetMinimalTuple)
763 : || (!targetHeapTuple && targetMinimalTuple));
764 :
765 : Assert(sourceNatts < natts);
766 :
767 0 : sourceNullLen = (hasNulls ? BITMAPLEN(sourceNatts) : 0);
768 :
769 0 : targetDataLen = sourceDataLen;
770 :
771 0 : if (tupleDesc->constr &&
772 0 : tupleDesc->constr->missing)
773 : {
774 : /*
775 : * If there are missing values we want to put them into the tuple.
776 : * Before that we have to compute the extra length for the values
777 : * array and the variable length data.
778 : */
779 0 : attrmiss = tupleDesc->constr->missing;
780 :
781 : /*
782 : * Find the first item in attrmiss for which we don't have a value in
783 : * the source. We can ignore all the missing entries before that.
784 : */
785 0 : for (firstmissingnum = sourceNatts;
786 0 : firstmissingnum < natts;
787 0 : firstmissingnum++)
788 : {
789 0 : if (attrmiss[firstmissingnum].am_present)
790 0 : break;
791 : else
792 0 : hasNulls = true;
793 : }
794 :
795 : /*
796 : * Now walk the missing attributes. If there is a missing value make
797 : * space for it. Otherwise, it's going to be NULL.
798 : */
799 0 : for (attnum = firstmissingnum;
800 0 : attnum < natts;
801 0 : attnum++)
802 : {
803 0 : if (attrmiss[attnum].am_present)
804 : {
805 0 : CompactAttribute *att = TupleDescCompactAttr(tupleDesc, attnum);
806 :
807 0 : targetDataLen = att_datum_alignby(targetDataLen,
808 : att->attalignby,
809 : att->attlen,
810 : attrmiss[attnum].am_value);
811 :
812 0 : targetDataLen = att_addlength_datum(targetDataLen,
813 : att->attlen,
814 : attrmiss[attnum].am_value);
815 : }
816 : else
817 : {
818 : /* no missing value, so it must be null */
819 0 : hasNulls = true;
820 : }
821 : }
822 : } /* end if have missing values */
823 : else
824 : {
825 : /*
826 : * If there are no missing values at all then NULLS must be allowed,
827 : * since some of the attributes are known to be absent.
828 : */
829 0 : hasNulls = true;
830 : }
831 :
832 0 : len = 0;
833 :
834 0 : if (hasNulls)
835 : {
836 0 : targetNullLen = BITMAPLEN(natts);
837 0 : len += targetNullLen;
838 : }
839 : else
840 0 : targetNullLen = 0;
841 :
842 : /*
843 : * Allocate and zero the space needed. Note that the tuple body and
844 : * HeapTupleData management structure are allocated in one chunk.
845 : */
846 0 : if (targetHeapTuple)
847 : {
848 0 : len += offsetof(HeapTupleHeaderData, t_bits);
849 0 : hoff = len = MAXALIGN(len); /* align user data safely */
850 0 : len += targetDataLen;
851 :
852 0 : *targetHeapTuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
853 0 : (*targetHeapTuple)->t_data
854 0 : = targetTHeader
855 0 : = (HeapTupleHeader) ((char *) *targetHeapTuple + HEAPTUPLESIZE);
856 0 : (*targetHeapTuple)->t_len = len;
857 0 : (*targetHeapTuple)->t_tableOid = sourceTuple->t_tableOid;
858 0 : (*targetHeapTuple)->t_self = sourceTuple->t_self;
859 :
860 0 : targetTHeader->t_infomask = sourceTHeader->t_infomask;
861 0 : targetTHeader->t_hoff = hoff;
862 0 : HeapTupleHeaderSetNatts(targetTHeader, natts);
863 0 : HeapTupleHeaderSetDatumLength(targetTHeader, len);
864 0 : HeapTupleHeaderSetTypeId(targetTHeader, tupleDesc->tdtypeid);
865 0 : HeapTupleHeaderSetTypMod(targetTHeader, tupleDesc->tdtypmod);
866 : /* We also make sure that t_ctid is invalid unless explicitly set */
867 0 : ItemPointerSetInvalid(&(targetTHeader->t_ctid));
868 0 : if (targetNullLen > 0)
869 0 : nullBits = (uint8 *) ((char *) (*targetHeapTuple)->t_data
870 : + offsetof(HeapTupleHeaderData, t_bits));
871 0 : targetData = (char *) (*targetHeapTuple)->t_data + hoff;
872 0 : infoMask = &(targetTHeader->t_infomask);
873 : }
874 : else
875 : {
876 0 : len += SizeofMinimalTupleHeader;
877 0 : hoff = len = MAXALIGN(len); /* align user data safely */
878 0 : len += targetDataLen;
879 :
880 0 : *targetMinimalTuple = (MinimalTuple) palloc0(len);
881 0 : (*targetMinimalTuple)->t_len = len;
882 0 : (*targetMinimalTuple)->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
883 0 : (*targetMinimalTuple)->t_infomask = sourceTHeader->t_infomask;
884 : /* Same macro works for MinimalTuples */
885 0 : HeapTupleHeaderSetNatts(*targetMinimalTuple, natts);
886 0 : if (targetNullLen > 0)
887 0 : nullBits = (uint8 *) ((char *) *targetMinimalTuple
888 0 : + offsetof(MinimalTupleData, t_bits));
889 0 : targetData = (char *) *targetMinimalTuple + hoff;
890 0 : infoMask = &((*targetMinimalTuple)->t_infomask);
891 : }
892 :
893 0 : if (targetNullLen > 0)
894 : {
895 0 : if (sourceNullLen > 0)
896 : {
897 : /* if bitmap pre-existed copy in - all is set */
898 0 : memcpy(nullBits,
899 : ((char *) sourceTHeader)
900 : + offsetof(HeapTupleHeaderData, t_bits),
901 : sourceNullLen);
902 0 : nullBits += sourceNullLen - 1;
903 : }
904 : else
905 : {
906 0 : sourceNullLen = BITMAPLEN(sourceNatts);
907 : /* Set NOT NULL for all existing attributes */
908 0 : memset(nullBits, 0xff, sourceNullLen);
909 :
910 0 : nullBits += sourceNullLen - 1;
911 :
912 0 : if (sourceNatts & 0x07)
913 : {
914 : /* build the mask (inverted!) */
915 0 : bitMask = 0xff << (sourceNatts & 0x07);
916 : /* Voila */
917 0 : *nullBits = ~bitMask;
918 : }
919 : }
920 :
921 0 : bitMask = (1 << ((sourceNatts - 1) & 0x07));
922 : } /* End if have null bitmap */
923 :
924 0 : memcpy(targetData,
925 0 : ((char *) sourceTuple->t_data) + sourceTHeader->t_hoff,
926 : sourceDataLen);
927 :
928 0 : targetData += sourceDataLen;
929 :
930 : /* Now fill in the missing values */
931 0 : for (attnum = sourceNatts; attnum < natts; attnum++)
932 : {
933 0 : CompactAttribute *attr = TupleDescCompactAttr(tupleDesc, attnum);
934 :
935 0 : if (attrmiss && attrmiss[attnum].am_present)
936 : {
937 0 : fill_val(attr,
938 0 : nullBits ? &nullBits : NULL,
939 : &bitMask,
940 : &targetData,
941 : infoMask,
942 0 : attrmiss[attnum].am_value,
943 : false);
944 : }
945 : else
946 : {
947 0 : fill_val(attr,
948 : &nullBits,
949 : &bitMask,
950 : &targetData,
951 : infoMask,
952 : (Datum) 0,
953 : true);
954 : }
955 : } /* end loop over missing attributes */
956 0 : }
957 :
958 : /*
959 : * Fill in the missing values for a minimal HeapTuple
960 : */
961 : MinimalTuple
962 0 : minimal_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
963 : {
964 : MinimalTuple minimalTuple;
965 :
966 0 : expand_tuple(NULL, &minimalTuple, sourceTuple, tupleDesc);
967 0 : return minimalTuple;
968 : }
969 :
970 : /*
971 : * Fill in the missing values for an ordinary HeapTuple
972 : */
973 : HeapTuple
974 0 : heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
975 : {
976 : HeapTuple heapTuple;
977 :
978 0 : expand_tuple(&heapTuple, NULL, sourceTuple, tupleDesc);
979 0 : return heapTuple;
980 : }
981 :
982 : /* ----------------
983 : * heap_copy_tuple_as_datum
984 : *
985 : * copy a tuple as a composite-type Datum
986 : * ----------------
987 : */
988 : Datum
989 52136 : heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
990 : {
991 : HeapTupleHeader td;
992 :
993 : /*
994 : * If the tuple contains any external TOAST pointers, we have to inline
995 : * those fields to meet the conventions for composite-type Datums.
996 : */
997 52136 : if (HeapTupleHasExternal(tuple))
998 0 : return toast_flatten_tuple_to_datum(tuple->t_data,
999 : tuple->t_len,
1000 : tupleDesc);
1001 :
1002 : /*
1003 : * Fast path for easy case: just make a palloc'd copy and insert the
1004 : * correct composite-Datum header fields (since those may not be set if
1005 : * the given tuple came from disk, rather than from heap_form_tuple).
1006 : */
1007 52136 : td = (HeapTupleHeader) palloc(tuple->t_len);
1008 52136 : memcpy(td, tuple->t_data, tuple->t_len);
1009 :
1010 52136 : HeapTupleHeaderSetDatumLength(td, tuple->t_len);
1011 52136 : HeapTupleHeaderSetTypeId(td, tupleDesc->tdtypeid);
1012 52136 : HeapTupleHeaderSetTypMod(td, tupleDesc->tdtypmod);
1013 :
1014 52136 : return PointerGetDatum(td);
1015 : }
1016 :
1017 : /*
1018 : * heap_form_tuple
1019 : * construct a tuple from the given values[] and isnull[] arrays,
1020 : * which are of the length indicated by tupleDescriptor->natts
1021 : *
1022 : * The result is allocated in the current memory context.
1023 : */
1024 : HeapTuple
1025 18570532 : heap_form_tuple(TupleDesc tupleDescriptor,
1026 : const Datum *values,
1027 : const bool *isnull)
1028 : {
1029 : HeapTuple tuple; /* return tuple */
1030 : HeapTupleHeader td; /* tuple data */
1031 : Size len,
1032 : data_len;
1033 : int hoff;
1034 18570532 : bool hasnull = false;
1035 18570532 : int numberOfAttributes = tupleDescriptor->natts;
1036 : int i;
1037 :
1038 18570532 : if (numberOfAttributes > MaxTupleAttributeNumber)
1039 0 : ereport(ERROR,
1040 : (errcode(ERRCODE_TOO_MANY_COLUMNS),
1041 : errmsg("number of columns (%d) exceeds limit (%d)",
1042 : numberOfAttributes, MaxTupleAttributeNumber)));
1043 :
1044 : /*
1045 : * Check for nulls
1046 : */
1047 83342051 : for (i = 0; i < numberOfAttributes; i++)
1048 : {
1049 68459205 : if (isnull[i])
1050 : {
1051 3687686 : hasnull = true;
1052 3687686 : break;
1053 : }
1054 : }
1055 :
1056 : /*
1057 : * Determine total space needed
1058 : */
1059 18570532 : len = offsetof(HeapTupleHeaderData, t_bits);
1060 :
1061 18570532 : if (hasnull)
1062 3687686 : len += BITMAPLEN(numberOfAttributes);
1063 :
1064 18570532 : hoff = len = MAXALIGN(len); /* align user data safely */
1065 :
1066 18570532 : data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
1067 :
1068 18570532 : len += data_len;
1069 :
1070 : /*
1071 : * Allocate and zero the space needed. Note that the tuple body and
1072 : * HeapTupleData management structure are allocated in one chunk.
1073 : */
1074 18570532 : tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
1075 18570532 : tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
1076 :
1077 : /*
1078 : * And fill in the information. Note we fill the Datum fields even though
1079 : * this tuple may never become a Datum. This lets HeapTupleHeaderGetDatum
1080 : * identify the tuple type if needed.
1081 : */
1082 18570532 : tuple->t_len = len;
1083 18570532 : ItemPointerSetInvalid(&(tuple->t_self));
1084 18570532 : tuple->t_tableOid = InvalidOid;
1085 :
1086 18570532 : HeapTupleHeaderSetDatumLength(td, len);
1087 18570532 : HeapTupleHeaderSetTypeId(td, tupleDescriptor->tdtypeid);
1088 18570532 : HeapTupleHeaderSetTypMod(td, tupleDescriptor->tdtypmod);
1089 : /* We also make sure that t_ctid is invalid unless explicitly set */
1090 18570532 : ItemPointerSetInvalid(&(td->t_ctid));
1091 :
1092 18570532 : HeapTupleHeaderSetNatts(td, numberOfAttributes);
1093 18570532 : td->t_hoff = hoff;
1094 :
1095 18570532 : heap_fill_tuple(tupleDescriptor,
1096 : values,
1097 : isnull,
1098 : (char *) td + hoff,
1099 : data_len,
1100 : &td->t_infomask,
1101 : (hasnull ? td->t_bits : NULL));
1102 :
1103 18570532 : return tuple;
1104 : }
1105 :
1106 : /*
1107 : * heap_modify_tuple
1108 : * form a new tuple from an old tuple and a set of replacement values.
1109 : *
1110 : * The replValues, replIsnull, and doReplace arrays must be of the length
1111 : * indicated by tupleDesc->natts. The new tuple is constructed using the data
1112 : * from replValues/replIsnull at columns where doReplace is true, and using
1113 : * the data from the old tuple at columns where doReplace is false.
1114 : *
1115 : * The result is allocated in the current memory context.
1116 : */
1117 : HeapTuple
1118 60030 : heap_modify_tuple(HeapTuple tuple,
1119 : TupleDesc tupleDesc,
1120 : const Datum *replValues,
1121 : const bool *replIsnull,
1122 : const bool *doReplace)
1123 : {
1124 60030 : int numberOfAttributes = tupleDesc->natts;
1125 : int attoff;
1126 : Datum *values;
1127 : bool *isnull;
1128 : HeapTuple newTuple;
1129 :
1130 : /*
1131 : * allocate and fill values and isnull arrays from either the tuple or the
1132 : * repl information, as appropriate.
1133 : *
1134 : * NOTE: it's debatable whether to use heap_deform_tuple() here or just
1135 : * heap_getattr() only the non-replaced columns. The latter could win if
1136 : * there are many replaced columns and few non-replaced ones. However,
1137 : * heap_deform_tuple costs only O(N) while the heap_getattr way would cost
1138 : * O(N^2) if there are many non-replaced columns, so it seems better to
1139 : * err on the side of linear cost.
1140 : */
1141 60030 : values = palloc_array(Datum, numberOfAttributes);
1142 60030 : isnull = palloc_array(bool, numberOfAttributes);
1143 :
1144 60030 : heap_deform_tuple(tuple, tupleDesc, values, isnull);
1145 :
1146 1819299 : for (attoff = 0; attoff < numberOfAttributes; attoff++)
1147 : {
1148 1759269 : if (doReplace[attoff])
1149 : {
1150 815923 : values[attoff] = replValues[attoff];
1151 815923 : isnull[attoff] = replIsnull[attoff];
1152 : }
1153 : }
1154 :
1155 : /*
1156 : * create a new tuple from the values and isnull arrays
1157 : */
1158 60030 : newTuple = heap_form_tuple(tupleDesc, values, isnull);
1159 :
1160 60030 : pfree(values);
1161 60030 : pfree(isnull);
1162 :
1163 : /*
1164 : * copy the identification info of the old tuple: t_ctid, t_self
1165 : */
1166 60030 : newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
1167 60030 : newTuple->t_self = tuple->t_self;
1168 60030 : newTuple->t_tableOid = tuple->t_tableOid;
1169 :
1170 60030 : return newTuple;
1171 : }
1172 :
1173 : /*
1174 : * heap_modify_tuple_by_cols
1175 : * form a new tuple from an old tuple and a set of replacement values.
1176 : *
1177 : * This is like heap_modify_tuple, except that instead of specifying which
1178 : * column(s) to replace by a boolean map, an array of target column numbers
1179 : * is used. This is often more convenient when a fixed number of columns
1180 : * are to be replaced. The replCols, replValues, and replIsnull arrays must
1181 : * be of length nCols. Target column numbers are indexed from 1.
1182 : *
1183 : * The result is allocated in the current memory context.
1184 : */
1185 : HeapTuple
1186 719 : heap_modify_tuple_by_cols(HeapTuple tuple,
1187 : TupleDesc tupleDesc,
1188 : int nCols,
1189 : const int *replCols,
1190 : const Datum *replValues,
1191 : const bool *replIsnull)
1192 : {
1193 719 : int numberOfAttributes = tupleDesc->natts;
1194 : Datum *values;
1195 : bool *isnull;
1196 : HeapTuple newTuple;
1197 : int i;
1198 :
1199 : /*
1200 : * allocate and fill values and isnull arrays from the tuple, then replace
1201 : * selected columns from the input arrays.
1202 : */
1203 719 : values = palloc_array(Datum, numberOfAttributes);
1204 719 : isnull = palloc_array(bool, numberOfAttributes);
1205 :
1206 719 : heap_deform_tuple(tuple, tupleDesc, values, isnull);
1207 :
1208 2091 : for (i = 0; i < nCols; i++)
1209 : {
1210 1372 : int attnum = replCols[i];
1211 :
1212 1372 : if (attnum <= 0 || attnum > numberOfAttributes)
1213 0 : elog(ERROR, "invalid column number %d", attnum);
1214 1372 : values[attnum - 1] = replValues[i];
1215 1372 : isnull[attnum - 1] = replIsnull[i];
1216 : }
1217 :
1218 : /*
1219 : * create a new tuple from the values and isnull arrays
1220 : */
1221 719 : newTuple = heap_form_tuple(tupleDesc, values, isnull);
1222 :
1223 719 : pfree(values);
1224 719 : pfree(isnull);
1225 :
1226 : /*
1227 : * copy the identification info of the old tuple: t_ctid, t_self
1228 : */
1229 719 : newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
1230 719 : newTuple->t_self = tuple->t_self;
1231 719 : newTuple->t_tableOid = tuple->t_tableOid;
1232 :
1233 719 : return newTuple;
1234 : }
1235 :
1236 : /*
1237 : * heap_deform_tuple
1238 : * Given a tuple, extract data into values/isnull arrays; this is
1239 : * the inverse of heap_form_tuple.
1240 : *
1241 : * Storage for the values/isnull arrays is provided by the caller;
1242 : * it should be sized according to tupleDesc->natts not
1243 : * HeapTupleHeaderGetNatts(tuple->t_data).
1244 : *
1245 : * Note that for pass-by-reference datatypes, the pointer placed
1246 : * in the Datum will point into the given tuple.
1247 : *
1248 : * When all or most of a tuple's fields need to be extracted,
1249 : * this routine will be significantly quicker than a loop around
1250 : * heap_getattr; the loop will become O(N^2) as soon as any
1251 : * noncacheable attribute offsets are involved.
1252 : */
1253 : void
1254 3171120 : heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
1255 : Datum *values, bool *isnull)
1256 : {
1257 3171120 : HeapTupleHeader tup = tuple->t_data;
1258 : CompactAttribute *cattr;
1259 3171120 : bool hasnulls = HeapTupleHasNulls(tuple);
1260 3171120 : int tdesc_natts = tupleDesc->natts;
1261 : int natts; /* number of atts to extract */
1262 : int attnum;
1263 : char *tp; /* ptr to tuple data */
1264 : uint32 off; /* offset in tuple data */
1265 3171120 : uint8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
1266 : int firstNonCacheOffsetAttr;
1267 : int firstNullAttr;
1268 :
1269 3171120 : natts = HeapTupleHeaderGetNatts(tup);
1270 :
1271 : /* Did someone forget to call TupleDescFinalize()? */
1272 : Assert(tupleDesc->firstNonCachedOffsetAttr >= 0);
1273 :
1274 : /*
1275 : * In inheritance situations, it is possible that the given tuple actually
1276 : * has more fields than the caller is expecting. Don't run off the end of
1277 : * the caller's arrays.
1278 : */
1279 3171120 : natts = Min(natts, tdesc_natts);
1280 3171120 : firstNonCacheOffsetAttr = Min(tupleDesc->firstNonCachedOffsetAttr, natts);
1281 :
1282 3171120 : if (hasnulls)
1283 : {
1284 120414 : firstNullAttr = first_null_attr(bp, natts);
1285 :
1286 : /*
1287 : * XXX: it'd be nice to use populate_isnull_array() here, but that
1288 : * requires that the isnull array's size is rounded up to the next
1289 : * multiple of 8. Doing that would require adjusting many locations
1290 : * that allocate the array.
1291 : */
1292 120414 : firstNonCacheOffsetAttr = Min(firstNonCacheOffsetAttr, firstNullAttr);
1293 : }
1294 : else
1295 3050706 : firstNullAttr = natts;
1296 :
1297 3171120 : tp = (char *) tup + tup->t_hoff;
1298 3171120 : attnum = 0;
1299 :
1300 3171120 : if (firstNonCacheOffsetAttr > 0)
1301 : {
1302 : #ifdef USE_ASSERT_CHECKING
1303 : /* In Assert enabled builds, verify attcacheoff is correct */
1304 : int offcheck = 0;
1305 : #endif
1306 : do
1307 : {
1308 4343565 : isnull[attnum] = false;
1309 4343565 : cattr = TupleDescCompactAttr(tupleDesc, attnum);
1310 4343565 : off = cattr->attcacheoff;
1311 :
1312 : #ifdef USE_ASSERT_CHECKING
1313 : offcheck = att_nominal_alignby(offcheck, cattr->attalignby);
1314 : Assert(offcheck == cattr->attcacheoff);
1315 : offcheck += cattr->attlen;
1316 : #endif
1317 :
1318 8687130 : values[attnum] = fetch_att_noerr(tp + off,
1319 4343565 : cattr->attbyval,
1320 4343565 : cattr->attlen);
1321 4343565 : } while (++attnum < firstNonCacheOffsetAttr);
1322 2576248 : off += cattr->attlen;
1323 : }
1324 : else
1325 594872 : off = 0;
1326 :
1327 4881932 : for (; attnum < firstNullAttr; attnum++)
1328 : {
1329 1710812 : isnull[attnum] = false;
1330 1710812 : cattr = TupleDescCompactAttr(tupleDesc, attnum);
1331 1710812 : values[attnum] = align_fetch_then_add(tp,
1332 : &off,
1333 1710812 : cattr->attbyval,
1334 1710812 : cattr->attlen,
1335 1710812 : cattr->attalignby);
1336 : }
1337 :
1338 3700037 : for (; attnum < natts; attnum++)
1339 : {
1340 : Assert(hasnulls);
1341 :
1342 528917 : if (att_isnull(attnum, bp))
1343 : {
1344 418302 : values[attnum] = (Datum) 0;
1345 418302 : isnull[attnum] = true;
1346 418302 : continue;
1347 : }
1348 :
1349 110615 : isnull[attnum] = false;
1350 110615 : cattr = TupleDescCompactAttr(tupleDesc, attnum);
1351 :
1352 : /* align 'off', fetch the attr's value, and increment off beyond it */
1353 110615 : values[attnum] = align_fetch_then_add(tp,
1354 : &off,
1355 110615 : cattr->attbyval,
1356 110615 : cattr->attlen,
1357 110615 : cattr->attalignby);
1358 : }
1359 :
1360 : /*
1361 : * If tuple doesn't have all the atts indicated by tupleDesc, read the
1362 : * rest as nulls or missing values as appropriate.
1363 : */
1364 3171132 : for (; attnum < tdesc_natts; attnum++)
1365 12 : values[attnum] = getmissingattr(tupleDesc, attnum + 1, &isnull[attnum]);
1366 3171120 : }
1367 :
1368 : /*
1369 : * heap_freetuple
1370 : */
1371 : void
1372 15515835 : heap_freetuple(HeapTuple htup)
1373 : {
1374 15515835 : pfree(htup);
1375 15515835 : }
1376 :
1377 :
1378 : /*
1379 : * heap_form_minimal_tuple
1380 : * construct a MinimalTuple from the given values[] and isnull[] arrays,
1381 : * which are of the length indicated by tupleDescriptor->natts
1382 : *
1383 : * This is exactly like heap_form_tuple() except that the result is a
1384 : * "minimal" tuple lacking a HeapTupleData header as well as room for system
1385 : * columns.
1386 : *
1387 : * The result is allocated in the current memory context.
1388 : */
1389 : MinimalTuple
1390 32257885 : heap_form_minimal_tuple(TupleDesc tupleDescriptor,
1391 : const Datum *values,
1392 : const bool *isnull,
1393 : Size extra)
1394 : {
1395 : MinimalTuple tuple; /* return tuple */
1396 : char *mem;
1397 : Size len,
1398 : data_len;
1399 : int hoff;
1400 32257885 : bool hasnull = false;
1401 32257885 : int numberOfAttributes = tupleDescriptor->natts;
1402 : int i;
1403 :
1404 : Assert(extra == MAXALIGN(extra));
1405 :
1406 32257885 : if (numberOfAttributes > MaxTupleAttributeNumber)
1407 0 : ereport(ERROR,
1408 : (errcode(ERRCODE_TOO_MANY_COLUMNS),
1409 : errmsg("number of columns (%d) exceeds limit (%d)",
1410 : numberOfAttributes, MaxTupleAttributeNumber)));
1411 :
1412 : /*
1413 : * Check for nulls
1414 : */
1415 93429615 : for (i = 0; i < numberOfAttributes; i++)
1416 : {
1417 61686203 : if (isnull[i])
1418 : {
1419 514473 : hasnull = true;
1420 514473 : break;
1421 : }
1422 : }
1423 :
1424 : /*
1425 : * Determine total space needed
1426 : */
1427 32257885 : len = SizeofMinimalTupleHeader;
1428 :
1429 32257885 : if (hasnull)
1430 514473 : len += BITMAPLEN(numberOfAttributes);
1431 :
1432 32257885 : hoff = len = MAXALIGN(len); /* align user data safely */
1433 :
1434 32257885 : data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
1435 :
1436 32257885 : len += data_len;
1437 :
1438 : /*
1439 : * Allocate and zero the space needed.
1440 : */
1441 32257885 : mem = palloc0(len + extra);
1442 32257885 : tuple = (MinimalTuple) (mem + extra);
1443 :
1444 : /*
1445 : * And fill in the information.
1446 : */
1447 32257885 : tuple->t_len = len;
1448 32257885 : HeapTupleHeaderSetNatts(tuple, numberOfAttributes);
1449 32257885 : tuple->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
1450 :
1451 32257885 : heap_fill_tuple(tupleDescriptor,
1452 : values,
1453 : isnull,
1454 : (char *) tuple + hoff,
1455 : data_len,
1456 : &tuple->t_infomask,
1457 : (hasnull ? tuple->t_bits : NULL));
1458 :
1459 32257885 : return tuple;
1460 : }
1461 :
1462 : /*
1463 : * heap_free_minimal_tuple
1464 : */
1465 : void
1466 22870999 : heap_free_minimal_tuple(MinimalTuple mtup)
1467 : {
1468 22870999 : pfree(mtup);
1469 22870999 : }
1470 :
1471 : /*
1472 : * heap_copy_minimal_tuple
1473 : * copy a MinimalTuple
1474 : *
1475 : * The result is allocated in the current memory context.
1476 : */
1477 : MinimalTuple
1478 3248423 : heap_copy_minimal_tuple(MinimalTuple mtup, Size extra)
1479 : {
1480 : MinimalTuple result;
1481 : char *mem;
1482 :
1483 : Assert(extra == MAXALIGN(extra));
1484 3248423 : mem = palloc(mtup->t_len + extra);
1485 3248423 : memset(mem, 0, extra);
1486 3248423 : result = (MinimalTuple) (mem + extra);
1487 3248423 : memcpy(result, mtup, mtup->t_len);
1488 3248423 : return result;
1489 : }
1490 :
1491 : /*
1492 : * heap_tuple_from_minimal_tuple
1493 : * create a HeapTuple by copying from a MinimalTuple;
1494 : * system columns are filled with zeroes
1495 : *
1496 : * The result is allocated in the current memory context.
1497 : * The HeapTuple struct, tuple header, and tuple data are all allocated
1498 : * as a single palloc() block.
1499 : */
1500 : HeapTuple
1501 491810 : heap_tuple_from_minimal_tuple(MinimalTuple mtup)
1502 : {
1503 : HeapTuple result;
1504 491810 : uint32 len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
1505 :
1506 491810 : result = (HeapTuple) palloc(HEAPTUPLESIZE + len);
1507 491810 : result->t_len = len;
1508 491810 : ItemPointerSetInvalid(&(result->t_self));
1509 491810 : result->t_tableOid = InvalidOid;
1510 491810 : result->t_data = (HeapTupleHeader) ((char *) result + HEAPTUPLESIZE);
1511 491810 : memcpy((char *) result->t_data + MINIMAL_TUPLE_OFFSET, mtup, mtup->t_len);
1512 491810 : memset(result->t_data, 0, offsetof(HeapTupleHeaderData, t_infomask2));
1513 491810 : return result;
1514 : }
1515 :
1516 : /*
1517 : * minimal_tuple_from_heap_tuple
1518 : * create a MinimalTuple by copying from a HeapTuple
1519 : *
1520 : * The result is allocated in the current memory context.
1521 : */
1522 : MinimalTuple
1523 2997332 : minimal_tuple_from_heap_tuple(HeapTuple htup, Size extra)
1524 : {
1525 : MinimalTuple result;
1526 : char *mem;
1527 : uint32 len;
1528 :
1529 : Assert(extra == MAXALIGN(extra));
1530 : Assert(htup->t_len > MINIMAL_TUPLE_OFFSET);
1531 2997332 : len = htup->t_len - MINIMAL_TUPLE_OFFSET;
1532 2997332 : mem = palloc(len + extra);
1533 2997332 : memset(mem, 0, extra);
1534 2997332 : result = (MinimalTuple) (mem + extra);
1535 2997332 : memcpy(result, (char *) htup->t_data + MINIMAL_TUPLE_OFFSET, len);
1536 :
1537 2997332 : result->t_len = len;
1538 2997332 : return result;
1539 : }
1540 :
1541 : /*
1542 : * This mainly exists so JIT can inline the definition, but it's also
1543 : * sometimes useful in debugging sessions.
1544 : */
1545 : size_t
1546 0 : varsize_any(void *p)
1547 : {
1548 0 : return VARSIZE_ANY(p);
1549 : }
|