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