PostgreSQL Source Code  git master
heaptoast.c File Reference
#include "postgres.h"
#include "access/detoast.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/heaptoast.h"
#include "access/toast_helper.h"
#include "access/toast_internals.h"
#include "utils/fmgroids.h"
Include dependency graph for heaptoast.c:

Go to the source code of this file.

Functions

void heap_toast_delete (Relation rel, HeapTuple oldtup, bool is_speculative)
 
HeapTuple heap_toast_insert_or_update (Relation rel, HeapTuple newtup, HeapTuple oldtup, int options)
 
HeapTuple toast_flatten_tuple (HeapTuple tup, TupleDesc tupleDesc)
 
Datum toast_flatten_tuple_to_datum (HeapTupleHeader tup, uint32 tup_len, TupleDesc tupleDesc)
 
HeapTuple toast_build_flattened_tuple (TupleDesc tupleDesc, Datum *values, bool *isnull)
 
void heap_fetch_toast_slice (Relation toastrel, Oid valueid, int32 attrsize, int32 sliceoffset, int32 slicelength, struct varlena *result)
 

Function Documentation

◆ heap_fetch_toast_slice()

void heap_fetch_toast_slice ( Relation  toastrel,
Oid  valueid,
int32  attrsize,
int32  sliceoffset,
int32  slicelength,
struct varlena result 
)

Definition at line 621 of file heaptoast.c.

References AccessShareLock, Assert, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTLessEqualStrategyNumber, DatumGetInt32, DatumGetPointer, elog, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg_internal(), ERROR, fastgetattr, ForwardScanDirection, init_toast_snapshot(), Int32GetDatum, ObjectIdGetDatum, RelationData::rd_att, RelationGetRelationName, ScanKeyInit(), systable_beginscan_ordered(), systable_endscan_ordered(), systable_getnext_ordered(), toast_close_indexes(), TOAST_MAX_CHUNK_SIZE, toast_open_indexes(), VARATT_IS_EXTENDED, VARATT_IS_SHORT, VARDATA, VARDATA_SHORT, VARHDRSZ, VARHDRSZ_SHORT, VARSIZE, and VARSIZE_SHORT.

Referenced by SampleHeapTupleVisible().

624 {
625  Relation *toastidxs;
626  ScanKeyData toastkey[3];
627  TupleDesc toasttupDesc = toastrel->rd_att;
628  int nscankeys;
629  SysScanDesc toastscan;
630  HeapTuple ttup;
631  int32 expectedchunk;
632  int32 totalchunks = ((attrsize - 1) / TOAST_MAX_CHUNK_SIZE) + 1;
633  int startchunk;
634  int endchunk;
635  int num_indexes;
636  int validIndex;
637  SnapshotData SnapshotToast;
638 
639  /* Look for the valid index of toast relation */
640  validIndex = toast_open_indexes(toastrel,
642  &toastidxs,
643  &num_indexes);
644 
645  startchunk = sliceoffset / TOAST_MAX_CHUNK_SIZE;
646  endchunk = (sliceoffset + slicelength - 1) / TOAST_MAX_CHUNK_SIZE;
647  Assert(endchunk <= totalchunks);
648 
649  /* Set up a scan key to fetch from the index. */
650  ScanKeyInit(&toastkey[0],
651  (AttrNumber) 1,
652  BTEqualStrategyNumber, F_OIDEQ,
653  ObjectIdGetDatum(valueid));
654 
655  /*
656  * No additional condition if fetching all chunks. Otherwise, use an
657  * equality condition for one chunk, and a range condition otherwise.
658  */
659  if (startchunk == 0 && endchunk == totalchunks - 1)
660  nscankeys = 1;
661  else if (startchunk == endchunk)
662  {
663  ScanKeyInit(&toastkey[1],
664  (AttrNumber) 2,
665  BTEqualStrategyNumber, F_INT4EQ,
666  Int32GetDatum(startchunk));
667  nscankeys = 2;
668  }
669  else
670  {
671  ScanKeyInit(&toastkey[1],
672  (AttrNumber) 2,
674  Int32GetDatum(startchunk));
675  ScanKeyInit(&toastkey[2],
676  (AttrNumber) 2,
677  BTLessEqualStrategyNumber, F_INT4LE,
678  Int32GetDatum(endchunk));
679  nscankeys = 3;
680  }
681 
682  /* Prepare for scan */
683  init_toast_snapshot(&SnapshotToast);
684  toastscan = systable_beginscan_ordered(toastrel, toastidxs[validIndex],
685  &SnapshotToast, nscankeys, toastkey);
686 
687  /*
688  * Read the chunks by index
689  *
690  * The index is on (valueid, chunkidx) so they will come in order
691  */
692  expectedchunk = startchunk;
693  while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
694  {
695  int32 curchunk;
696  Pointer chunk;
697  bool isnull;
698  char *chunkdata;
699  int32 chunksize;
700  int32 expected_size;
701  int32 chcpystrt;
702  int32 chcpyend;
703 
704  /*
705  * Have a chunk, extract the sequence number and the data
706  */
707  curchunk = DatumGetInt32(fastgetattr(ttup, 2, toasttupDesc, &isnull));
708  Assert(!isnull);
709  chunk = DatumGetPointer(fastgetattr(ttup, 3, toasttupDesc, &isnull));
710  Assert(!isnull);
711  if (!VARATT_IS_EXTENDED(chunk))
712  {
713  chunksize = VARSIZE(chunk) - VARHDRSZ;
714  chunkdata = VARDATA(chunk);
715  }
716  else if (VARATT_IS_SHORT(chunk))
717  {
718  /* could happen due to heap_form_tuple doing its thing */
719  chunksize = VARSIZE_SHORT(chunk) - VARHDRSZ_SHORT;
720  chunkdata = VARDATA_SHORT(chunk);
721  }
722  else
723  {
724  /* should never happen */
725  elog(ERROR, "found toasted toast chunk for toast value %u in %s",
726  valueid, RelationGetRelationName(toastrel));
727  chunksize = 0; /* keep compiler quiet */
728  chunkdata = NULL;
729  }
730 
731  /*
732  * Some checks on the data we've found
733  */
734  if (curchunk != expectedchunk)
735  ereport(ERROR,
737  errmsg_internal("unexpected chunk number %d (expected %d) for toast value %u in %s",
738  curchunk, expectedchunk, valueid,
739  RelationGetRelationName(toastrel))));
740  if (curchunk > endchunk)
741  ereport(ERROR,
743  errmsg_internal("unexpected chunk number %d (out of range %d..%d) for toast value %u in %s",
744  curchunk,
745  startchunk, endchunk, valueid,
746  RelationGetRelationName(toastrel))));
747  expected_size = curchunk < totalchunks - 1 ? TOAST_MAX_CHUNK_SIZE
748  : attrsize - ((totalchunks - 1) * TOAST_MAX_CHUNK_SIZE);
749  if (chunksize != expected_size)
750  ereport(ERROR,
752  errmsg_internal("unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s",
753  chunksize, expected_size,
754  curchunk, totalchunks, valueid,
755  RelationGetRelationName(toastrel))));
756 
757  /*
758  * Copy the data into proper place in our result
759  */
760  chcpystrt = 0;
761  chcpyend = chunksize - 1;
762  if (curchunk == startchunk)
763  chcpystrt = sliceoffset % TOAST_MAX_CHUNK_SIZE;
764  if (curchunk == endchunk)
765  chcpyend = (sliceoffset + slicelength - 1) % TOAST_MAX_CHUNK_SIZE;
766 
767  memcpy(VARDATA(result) +
768  (curchunk * TOAST_MAX_CHUNK_SIZE - sliceoffset) + chcpystrt,
769  chunkdata + chcpystrt,
770  (chcpyend - chcpystrt) + 1);
771 
772  expectedchunk++;
773  }
774 
775  /*
776  * Final checks that we successfully fetched the datum
777  */
778  if (expectedchunk != (endchunk + 1))
779  ereport(ERROR,
781  errmsg_internal("missing chunk number %d for toast value %u in %s",
782  expectedchunk, valueid,
783  RelationGetRelationName(toastrel))));
784 
785  /* End scan and close indexes. */
786  systable_endscan_ordered(toastscan);
787  toast_close_indexes(toastidxs, num_indexes, AccessShareLock);
788 }
#define VARDATA(PTR)
Definition: postgres.h:302
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:712
#define TOAST_MAX_CHUNK_SIZE
Definition: heaptoast.h:84
#define DatumGetInt32(X)
Definition: postgres.h:472
#define VARHDRSZ_SHORT
Definition: postgres.h:268
#define VARSIZE(PTR)
Definition: postgres.h:303
void init_toast_snapshot(Snapshot toast_snapshot)
#define VARHDRSZ
Definition: c.h:561
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:608
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
Definition: genam.c:630
signed int int32
Definition: c.h:355
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
char * Pointer
Definition: c.h:344
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define VARATT_IS_SHORT(PTR)
Definition: postgres.h:326
void toast_close_indexes(Relation *toastidxs, int num_indexes, LOCKMODE lock)
#define RelationGetRelationName(relation)
Definition: rel.h:462
#define ereport(elevel, rest)
Definition: elog.h:141
#define VARSIZE_SHORT(PTR)
Definition: postgres.h:305
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:45
int toast_open_indexes(Relation toastrel, LOCKMODE lock, Relation **toastidxs, int *num_indexes)
void systable_endscan_ordered(SysScanDesc sysscan)
Definition: genam.c:649
TupleDesc rd_att
Definition: rel.h:85
int errmsg_internal(const char *fmt,...)
Definition: elog.c:909
#define Assert(condition)
Definition: c.h:738
#define VARATT_IS_EXTENDED(PTR)
Definition: postgres.h:327
#define DatumGetPointer(X)
Definition: postgres.h:549
#define VARDATA_SHORT(PTR)
Definition: postgres.h:306
#define Int32GetDatum(X)
Definition: postgres.h:479
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:565
#define elog(elevel,...)
Definition: elog.h:228
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
int16 AttrNumber
Definition: attnum.h:21
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32

◆ heap_toast_delete()

void heap_toast_delete ( Relation  rel,
HeapTuple  oldtup,
bool  is_speculative 
)

Definition at line 43 of file heaptoast.c.

References Assert, heap_deform_tuple(), MaxHeapAttributeNumber, TupleDescData::natts, RelationData::rd_att, RelationData::rd_rel, and toast_delete_external().

Referenced by heap_abort_speculative(), and heap_delete().

44 {
45  TupleDesc tupleDesc;
46  Datum toast_values[MaxHeapAttributeNumber];
47  bool toast_isnull[MaxHeapAttributeNumber];
48 
49  /*
50  * We should only ever be called for tuples of plain relations or
51  * materialized views --- recursing on a toast rel is bad news.
52  */
53  Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
54  rel->rd_rel->relkind == RELKIND_MATVIEW);
55 
56  /*
57  * Get the tuple descriptor and break down the tuple into fields.
58  *
59  * NOTE: it's debatable whether to use heap_deform_tuple() here or just
60  * heap_getattr() only the varlena columns. The latter could win if there
61  * are few varlena columns and many non-varlena ones. However,
62  * heap_deform_tuple costs only O(N) while the heap_getattr way would cost
63  * O(N^2) if there are many varlena columns, so it seems better to err on
64  * the side of linear cost. (We won't even be here unless there's at
65  * least one varlena column, by the way.)
66  */
67  tupleDesc = rel->rd_att;
68 
69  Assert(tupleDesc->natts <= MaxHeapAttributeNumber);
70  heap_deform_tuple(oldtup, tupleDesc, toast_values, toast_isnull);
71 
72  /* Do the real work. */
73  toast_delete_external(rel, toast_values, toast_isnull, is_speculative);
74 }
Form_pg_class rd_rel
Definition: rel.h:84
void toast_delete_external(Relation rel, Datum *values, bool *isnull, bool is_speculative)
Definition: toast_helper.c:312
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:85
#define MaxHeapAttributeNumber
Definition: htup_details.h:47
#define Assert(condition)
Definition: c.h:738
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1249

◆ heap_toast_insert_or_update()

HeapTuple heap_toast_insert_or_update ( Relation  rel,
HeapTuple  newtup,
HeapTuple  oldtup,
int  options 
)

Definition at line 96 of file heaptoast.c.

References Assert, attstorage, BITMAPLEN, heap_compute_data_size(), heap_deform_tuple(), heap_fill_tuple(), HEAP_INSERT_SPECULATIVE, HeapTupleHeaderSetNatts, HEAPTUPLESIZE, InvalidOid, MAXALIGN, MaxHeapAttributeNumber, TupleDescData::natts, palloc0(), RelationData::rd_att, RelationData::rd_rel, RelationGetToastTupleTarget, SizeofHeapTupleHeader, HeapTupleHeaderData::t_bits, HeapTupleData::t_data, HeapTupleHeaderData::t_hoff, HeapTupleHeaderData::t_infomask, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, ToastAttrInfo::tai_colflags, TOAST_HAS_NULLS, TOAST_NEEDS_CHANGE, toast_tuple_cleanup(), toast_tuple_externalize(), toast_tuple_find_biggest_attribute(), toast_tuple_init(), TOAST_TUPLE_TARGET, TOAST_TUPLE_TARGET_MAIN, toast_tuple_try_compression(), TOASTCOL_INCOMPRESSIBLE, ToastTupleContext::ttc_attr, ToastTupleContext::ttc_flags, ToastTupleContext::ttc_isnull, ToastTupleContext::ttc_oldisnull, ToastTupleContext::ttc_oldvalues, ToastTupleContext::ttc_rel, ToastTupleContext::ttc_values, and TupleDescAttr.

Referenced by heap_prepare_insert(), heap_update(), and raw_heap_insert().

98 {
99  HeapTuple result_tuple;
100  TupleDesc tupleDesc;
101  int numAttrs;
102 
103  Size maxDataLen;
104  Size hoff;
105 
106  bool toast_isnull[MaxHeapAttributeNumber];
107  bool toast_oldisnull[MaxHeapAttributeNumber];
108  Datum toast_values[MaxHeapAttributeNumber];
109  Datum toast_oldvalues[MaxHeapAttributeNumber];
111  ToastTupleContext ttc;
112 
113  /*
114  * Ignore the INSERT_SPECULATIVE option. Speculative insertions/super
115  * deletions just normally insert/delete the toast values. It seems
116  * easiest to deal with that here, instead on, potentially, multiple
117  * callers.
118  */
120 
121  /*
122  * We should only ever be called for tuples of plain relations or
123  * materialized views --- recursing on a toast rel is bad news.
124  */
125  Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
126  rel->rd_rel->relkind == RELKIND_MATVIEW);
127 
128  /*
129  * Get the tuple descriptor and break down the tuple(s) into fields.
130  */
131  tupleDesc = rel->rd_att;
132  numAttrs = tupleDesc->natts;
133 
134  Assert(numAttrs <= MaxHeapAttributeNumber);
135  heap_deform_tuple(newtup, tupleDesc, toast_values, toast_isnull);
136  if (oldtup != NULL)
137  heap_deform_tuple(oldtup, tupleDesc, toast_oldvalues, toast_oldisnull);
138 
139  /* ----------
140  * Prepare for toasting
141  * ----------
142  */
143  ttc.ttc_rel = rel;
144  ttc.ttc_values = toast_values;
145  ttc.ttc_isnull = toast_isnull;
146  if (oldtup == NULL)
147  {
148  ttc.ttc_oldvalues = NULL;
149  ttc.ttc_oldisnull = NULL;
150  }
151  else
152  {
153  ttc.ttc_oldvalues = toast_oldvalues;
154  ttc.ttc_oldisnull = toast_oldisnull;
155  }
156  ttc.ttc_attr = toast_attr;
157  toast_tuple_init(&ttc);
158 
159  /* ----------
160  * Compress and/or save external until data fits into target length
161  *
162  * 1: Inline compress attributes with attstorage 'x', and store very
163  * large attributes with attstorage 'x' or 'e' external immediately
164  * 2: Store attributes with attstorage 'x' or 'e' external
165  * 3: Inline compress attributes with attstorage 'm'
166  * 4: Store attributes with attstorage 'm' external
167  * ----------
168  */
169 
170  /* compute header overhead --- this should match heap_form_tuple() */
171  hoff = SizeofHeapTupleHeader;
172  if ((ttc.ttc_flags & TOAST_HAS_NULLS) != 0)
173  hoff += BITMAPLEN(numAttrs);
174  hoff = MAXALIGN(hoff);
175  /* now convert to a limit on the tuple data size */
176  maxDataLen = RelationGetToastTupleTarget(rel, TOAST_TUPLE_TARGET) - hoff;
177 
178  /*
179  * Look for attributes with attstorage 'x' to compress. Also find large
180  * attributes with attstorage 'x' or 'e', and store them external.
181  */
182  while (heap_compute_data_size(tupleDesc,
183  toast_values, toast_isnull) > maxDataLen)
184  {
185  int biggest_attno;
186 
187  biggest_attno = toast_tuple_find_biggest_attribute(&ttc, true, false);
188  if (biggest_attno < 0)
189  break;
190 
191  /*
192  * Attempt to compress it inline, if it has attstorage 'x'
193  */
194  if (TupleDescAttr(tupleDesc, biggest_attno)->attstorage == 'x')
195  toast_tuple_try_compression(&ttc, biggest_attno);
196  else
197  {
198  /* has attstorage 'e', ignore on subsequent compression passes */
199  toast_attr[biggest_attno].tai_colflags |= TOASTCOL_INCOMPRESSIBLE;
200  }
201 
202  /*
203  * If this value is by itself more than maxDataLen (after compression
204  * if any), push it out to the toast table immediately, if possible.
205  * This avoids uselessly compressing other fields in the common case
206  * where we have one long field and several short ones.
207  *
208  * XXX maybe the threshold should be less than maxDataLen?
209  */
210  if (toast_attr[biggest_attno].tai_size > maxDataLen &&
211  rel->rd_rel->reltoastrelid != InvalidOid)
212  toast_tuple_externalize(&ttc, biggest_attno, options);
213  }
214 
215  /*
216  * Second we look for attributes of attstorage 'x' or 'e' that are still
217  * inline, and make them external. But skip this if there's no toast
218  * table to push them to.
219  */
220  while (heap_compute_data_size(tupleDesc,
221  toast_values, toast_isnull) > maxDataLen &&
222  rel->rd_rel->reltoastrelid != InvalidOid)
223  {
224  int biggest_attno;
225 
226  biggest_attno = toast_tuple_find_biggest_attribute(&ttc, false, false);
227  if (biggest_attno < 0)
228  break;
229  toast_tuple_externalize(&ttc, biggest_attno, options);
230  }
231 
232  /*
233  * Round 3 - this time we take attributes with storage 'm' into
234  * compression
235  */
236  while (heap_compute_data_size(tupleDesc,
237  toast_values, toast_isnull) > maxDataLen)
238  {
239  int biggest_attno;
240 
241  biggest_attno = toast_tuple_find_biggest_attribute(&ttc, true, true);
242  if (biggest_attno < 0)
243  break;
244 
245  toast_tuple_try_compression(&ttc, biggest_attno);
246  }
247 
248  /*
249  * Finally we store attributes of type 'm' externally. At this point we
250  * increase the target tuple size, so that 'm' attributes aren't stored
251  * externally unless really necessary.
252  */
253  maxDataLen = TOAST_TUPLE_TARGET_MAIN - hoff;
254 
255  while (heap_compute_data_size(tupleDesc,
256  toast_values, toast_isnull) > maxDataLen &&
257  rel->rd_rel->reltoastrelid != InvalidOid)
258  {
259  int biggest_attno;
260 
261  biggest_attno = toast_tuple_find_biggest_attribute(&ttc, false, true);
262  if (biggest_attno < 0)
263  break;
264 
265  toast_tuple_externalize(&ttc, biggest_attno, options);
266  }
267 
268  /*
269  * In the case we toasted any values, we need to build a new heap tuple
270  * with the changed values.
271  */
272  if ((ttc.ttc_flags & TOAST_NEEDS_CHANGE) != 0)
273  {
274  HeapTupleHeader olddata = newtup->t_data;
275  HeapTupleHeader new_data;
276  int32 new_header_len;
277  int32 new_data_len;
278  int32 new_tuple_len;
279 
280  /*
281  * Calculate the new size of the tuple.
282  *
283  * Note: we used to assume here that the old tuple's t_hoff must equal
284  * the new_header_len value, but that was incorrect. The old tuple
285  * might have a smaller-than-current natts, if there's been an ALTER
286  * TABLE ADD COLUMN since it was stored; and that would lead to a
287  * different conclusion about the size of the null bitmap, or even
288  * whether there needs to be one at all.
289  */
290  new_header_len = SizeofHeapTupleHeader;
291  if ((ttc.ttc_flags & TOAST_HAS_NULLS) != 0)
292  new_header_len += BITMAPLEN(numAttrs);
293  new_header_len = MAXALIGN(new_header_len);
294  new_data_len = heap_compute_data_size(tupleDesc,
295  toast_values, toast_isnull);
296  new_tuple_len = new_header_len + new_data_len;
297 
298  /*
299  * Allocate and zero the space needed, and fill HeapTupleData fields.
300  */
301  result_tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + new_tuple_len);
302  result_tuple->t_len = new_tuple_len;
303  result_tuple->t_self = newtup->t_self;
304  result_tuple->t_tableOid = newtup->t_tableOid;
305  new_data = (HeapTupleHeader) ((char *) result_tuple + HEAPTUPLESIZE);
306  result_tuple->t_data = new_data;
307 
308  /*
309  * Copy the existing tuple header, but adjust natts and t_hoff.
310  */
311  memcpy(new_data, olddata, SizeofHeapTupleHeader);
312  HeapTupleHeaderSetNatts(new_data, numAttrs);
313  new_data->t_hoff = new_header_len;
314 
315  /* Copy over the data, and fill the null bitmap if needed */
316  heap_fill_tuple(tupleDesc,
317  toast_values,
318  toast_isnull,
319  (char *) new_data + new_header_len,
320  new_data_len,
321  &(new_data->t_infomask),
322  ((ttc.ttc_flags & TOAST_HAS_NULLS) != 0) ?
323  new_data->t_bits : NULL);
324  }
325  else
326  result_tuple = newtup;
327 
328  toast_tuple_cleanup(&ttc);
329 
330  return result_tuple;
331 }
void heap_fill_tuple(TupleDesc tupleDesc, Datum *values, bool *isnull, char *data, Size data_size, uint16 *infomask, bits8 *bit)
Definition: heaptuple.c:304
#define SizeofHeapTupleHeader
Definition: htup_details.h:184
HeapTupleData * HeapTuple
Definition: htup.h:71
char attstorage
Definition: pg_attribute.h:123
bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]
Definition: htup_details.h:177
#define TOASTCOL_INCOMPRESSIBLE
Definition: toast_helper.h:101
uint8 tai_colflags
Definition: toast_helper.h:34
void toast_tuple_try_compression(ToastTupleContext *ttc, int attribute)
Definition: toast_helper.c:223
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define BITMAPLEN(NATTS)
Definition: htup_details.h:547
Form_pg_class rd_rel
Definition: rel.h:84
#define HEAP_INSERT_SPECULATIVE
Definition: heapam.h:38
signed int int32
Definition: c.h:355
#define TOAST_TUPLE_TARGET
Definition: heaptoast.h:50
#define TOAST_NEEDS_CHANGE
Definition: toast_helper.h:80
HeapTupleHeader t_data
Definition: htup.h:68
ItemPointerData t_self
Definition: htup.h:65
void toast_tuple_cleanup(ToastTupleContext *ttc)
Definition: toast_helper.c:269
uint32 t_len
Definition: htup.h:64
int toast_tuple_find_biggest_attribute(ToastTupleContext *ttc, bool for_compression, bool check_main)
Definition: toast_helper.c:178
Oid t_tableOid
Definition: htup.h:66
#define TOAST_TUPLE_TARGET_MAIN
Definition: heaptoast.h:61
#define TOAST_HAS_NULLS
Definition: toast_helper.h:79
void * palloc0(Size size)
Definition: mcxt.c:980
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:85
#define InvalidOid
Definition: postgres_ext.h:36
Datum * ttc_oldvalues
Definition: toast_helper.h:51
#define MaxHeapAttributeNumber
Definition: htup_details.h:47
#define Assert(condition)
Definition: c.h:738
#define HeapTupleHeaderSetNatts(tup, natts)
Definition: htup_details.h:534
size_t Size
Definition: c.h:466
#define RelationGetToastTupleTarget(relation, defaulttarg)
Definition: rel.h:289
#define MAXALIGN(LEN)
Definition: c.h:691
Size heap_compute_data_size(TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:119
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1249
#define HEAPTUPLESIZE
Definition: htup.h:73
ToastAttrInfo * ttc_attr
Definition: toast_helper.h:61
void toast_tuple_init(ToastTupleContext *ttc)
Definition: toast_helper.c:39
void toast_tuple_externalize(ToastTupleContext *ttc, int attribute, int options)
Definition: toast_helper.c:250

◆ toast_build_flattened_tuple()

HeapTuple toast_build_flattened_tuple ( TupleDesc  tupleDesc,
Datum values,
bool isnull 
)

Definition at line 558 of file heaptoast.c.

References Assert, attlen, DatumGetPointer, detoast_external_attr(), heap_form_tuple(), i, MaxTupleAttributeNumber, TupleDescData::natts, pfree(), PointerGetDatum, TupleDescAttr, and VARATT_IS_EXTERNAL.

Referenced by ExecEvalWholeRowVar().

561 {
562  HeapTuple new_tuple;
563  int numAttrs = tupleDesc->natts;
564  int num_to_free;
565  int i;
566  Datum new_values[MaxTupleAttributeNumber];
567  Pointer freeable_values[MaxTupleAttributeNumber];
568 
569  /*
570  * We can pass the caller's isnull array directly to heap_form_tuple, but
571  * we potentially need to modify the values array.
572  */
573  Assert(numAttrs <= MaxTupleAttributeNumber);
574  memcpy(new_values, values, numAttrs * sizeof(Datum));
575 
576  num_to_free = 0;
577  for (i = 0; i < numAttrs; i++)
578  {
579  /*
580  * Look at non-null varlena attributes
581  */
582  if (!isnull[i] && TupleDescAttr(tupleDesc, i)->attlen == -1)
583  {
584  struct varlena *new_value;
585 
586  new_value = (struct varlena *) DatumGetPointer(new_values[i]);
587  if (VARATT_IS_EXTERNAL(new_value))
588  {
589  new_value = detoast_external_attr(new_value);
590  new_values[i] = PointerGetDatum(new_value);
591  freeable_values[num_to_free++] = (Pointer) new_value;
592  }
593  }
594  }
595 
596  /*
597  * Form the reconfigured tuple.
598  */
599  new_tuple = heap_form_tuple(tupleDesc, new_values, isnull);
600 
601  /*
602  * Free allocated temp values
603  */
604  for (i = 0; i < num_to_free; i++)
605  pfree(freeable_values[i]);
606 
607  return new_tuple;
608 }
#define MaxTupleAttributeNumber
Definition: htup_details.h:33
#define PointerGetDatum(X)
Definition: postgres.h:556
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
struct varlena * detoast_external_attr(struct varlena *attr)
Definition: detoast.c:44
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
#define VARATT_IS_EXTERNAL(PTR)
Definition: postgres.h:313
void pfree(void *pointer)
Definition: mcxt.c:1056
char * Pointer
Definition: c.h:344
int16 attlen
Definition: pg_attribute.h:64
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:738
#define DatumGetPointer(X)
Definition: postgres.h:549
static Datum values[MAXATTR]
Definition: bootstrap.c:167
int i
Definition: c.h:555

◆ toast_flatten_tuple()

HeapTuple toast_flatten_tuple ( HeapTuple  tup,
TupleDesc  tupleDesc 
)

Definition at line 345 of file heaptoast.c.

References Assert, attlen, DatumGetPointer, detoast_external_attr(), HEAP2_XACT_MASK, heap_deform_tuple(), heap_form_tuple(), HEAP_XACT_MASK, i, MaxTupleAttributeNumber, TupleDescData::natts, pfree(), PointerGetDatum, HeapTupleHeaderData::t_choice, HeapTupleHeaderData::t_ctid, HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleHeaderData::t_infomask2, HeapTupleData::t_self, HeapTupleData::t_tableOid, TupleDescAttr, and VARATT_IS_EXTERNAL.

Referenced by CatalogCacheCreateEntry(), expanded_record_set_tuple(), and ExtractReplicaIdentity().

346 {
347  HeapTuple new_tuple;
348  int numAttrs = tupleDesc->natts;
349  int i;
350  Datum toast_values[MaxTupleAttributeNumber];
351  bool toast_isnull[MaxTupleAttributeNumber];
352  bool toast_free[MaxTupleAttributeNumber];
353 
354  /*
355  * Break down the tuple into fields.
356  */
357  Assert(numAttrs <= MaxTupleAttributeNumber);
358  heap_deform_tuple(tup, tupleDesc, toast_values, toast_isnull);
359 
360  memset(toast_free, 0, numAttrs * sizeof(bool));
361 
362  for (i = 0; i < numAttrs; i++)
363  {
364  /*
365  * Look at non-null varlena attributes
366  */
367  if (!toast_isnull[i] && TupleDescAttr(tupleDesc, i)->attlen == -1)
368  {
369  struct varlena *new_value;
370 
371  new_value = (struct varlena *) DatumGetPointer(toast_values[i]);
372  if (VARATT_IS_EXTERNAL(new_value))
373  {
374  new_value = detoast_external_attr(new_value);
375  toast_values[i] = PointerGetDatum(new_value);
376  toast_free[i] = true;
377  }
378  }
379  }
380 
381  /*
382  * Form the reconfigured tuple.
383  */
384  new_tuple = heap_form_tuple(tupleDesc, toast_values, toast_isnull);
385 
386  /*
387  * Be sure to copy the tuple's identity fields. We also make a point of
388  * copying visibility info, just in case anybody looks at those fields in
389  * a syscache entry.
390  */
391  new_tuple->t_self = tup->t_self;
392  new_tuple->t_tableOid = tup->t_tableOid;
393 
394  new_tuple->t_data->t_choice = tup->t_data->t_choice;
395  new_tuple->t_data->t_ctid = tup->t_data->t_ctid;
396  new_tuple->t_data->t_infomask &= ~HEAP_XACT_MASK;
397  new_tuple->t_data->t_infomask |=
399  new_tuple->t_data->t_infomask2 &= ~HEAP2_XACT_MASK;
400  new_tuple->t_data->t_infomask2 |=
402 
403  /*
404  * Free allocated temp values
405  */
406  for (i = 0; i < numAttrs; i++)
407  if (toast_free[i])
408  pfree(DatumGetPointer(toast_values[i]));
409 
410  return new_tuple;
411 }
union HeapTupleHeaderData::@45 t_choice
#define MaxTupleAttributeNumber
Definition: htup_details.h:33
#define PointerGetDatum(X)
Definition: postgres.h:556
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
struct varlena * detoast_external_attr(struct varlena *attr)
Definition: detoast.c:44
#define HEAP2_XACT_MASK
Definition: htup_details.h:283
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
HeapTupleHeader t_data
Definition: htup.h:68
#define VARATT_IS_EXTERNAL(PTR)
Definition: postgres.h:313
void pfree(void *pointer)
Definition: mcxt.c:1056
ItemPointerData t_ctid
Definition: htup_details.h:160
ItemPointerData t_self
Definition: htup.h:65
Oid t_tableOid
Definition: htup.h:66
int16 attlen
Definition: pg_attribute.h:64
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:738
#define DatumGetPointer(X)
Definition: postgres.h:549
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1249
int i
Definition: c.h:555
#define HEAP_XACT_MASK
Definition: htup_details.h:218

◆ toast_flatten_tuple_to_datum()

Datum toast_flatten_tuple_to_datum ( HeapTupleHeader  tup,
uint32  tup_len,
TupleDesc  tupleDesc 
)

Definition at line 444 of file heaptoast.c.

References Assert, attlen, BITMAPLEN, DatumGetPointer, detoast_attr(), heap_compute_data_size(), heap_deform_tuple(), heap_fill_tuple(), HeapTupleHeaderSetDatumLength, HeapTupleHeaderSetNatts, HeapTupleHeaderSetTypeId, HeapTupleHeaderSetTypMod, i, InvalidOid, ItemPointerSetInvalid, MAXALIGN, MaxTupleAttributeNumber, TupleDescData::natts, palloc0(), pfree(), PointerGetDatum, SizeofHeapTupleHeader, HeapTupleHeaderData::t_bits, HeapTupleData::t_data, HeapTupleHeaderData::t_hoff, HeapTupleHeaderData::t_infomask, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, TupleDescData::tdtypeid, TupleDescData::tdtypmod, TupleDescAttr, VARATT_IS_COMPRESSED, and VARATT_IS_EXTERNAL.

Referenced by heap_copy_tuple_as_datum(), and HeapTupleHeaderGetDatum().

447 {
448  HeapTupleHeader new_data;
449  int32 new_header_len;
450  int32 new_data_len;
451  int32 new_tuple_len;
452  HeapTupleData tmptup;
453  int numAttrs = tupleDesc->natts;
454  int i;
455  bool has_nulls = false;
456  Datum toast_values[MaxTupleAttributeNumber];
457  bool toast_isnull[MaxTupleAttributeNumber];
458  bool toast_free[MaxTupleAttributeNumber];
459 
460  /* Build a temporary HeapTuple control structure */
461  tmptup.t_len = tup_len;
462  ItemPointerSetInvalid(&(tmptup.t_self));
463  tmptup.t_tableOid = InvalidOid;
464  tmptup.t_data = tup;
465 
466  /*
467  * Break down the tuple into fields.
468  */
469  Assert(numAttrs <= MaxTupleAttributeNumber);
470  heap_deform_tuple(&tmptup, tupleDesc, toast_values, toast_isnull);
471 
472  memset(toast_free, 0, numAttrs * sizeof(bool));
473 
474  for (i = 0; i < numAttrs; i++)
475  {
476  /*
477  * Look at non-null varlena attributes
478  */
479  if (toast_isnull[i])
480  has_nulls = true;
481  else if (TupleDescAttr(tupleDesc, i)->attlen == -1)
482  {
483  struct varlena *new_value;
484 
485  new_value = (struct varlena *) DatumGetPointer(toast_values[i]);
486  if (VARATT_IS_EXTERNAL(new_value) ||
487  VARATT_IS_COMPRESSED(new_value))
488  {
489  new_value = detoast_attr(new_value);
490  toast_values[i] = PointerGetDatum(new_value);
491  toast_free[i] = true;
492  }
493  }
494  }
495 
496  /*
497  * Calculate the new size of the tuple.
498  *
499  * This should match the reconstruction code in
500  * heap_toast_insert_or_update.
501  */
502  new_header_len = SizeofHeapTupleHeader;
503  if (has_nulls)
504  new_header_len += BITMAPLEN(numAttrs);
505  new_header_len = MAXALIGN(new_header_len);
506  new_data_len = heap_compute_data_size(tupleDesc,
507  toast_values, toast_isnull);
508  new_tuple_len = new_header_len + new_data_len;
509 
510  new_data = (HeapTupleHeader) palloc0(new_tuple_len);
511 
512  /*
513  * Copy the existing tuple header, but adjust natts and t_hoff.
514  */
515  memcpy(new_data, tup, SizeofHeapTupleHeader);
516  HeapTupleHeaderSetNatts(new_data, numAttrs);
517  new_data->t_hoff = new_header_len;
518 
519  /* Set the composite-Datum header fields correctly */
520  HeapTupleHeaderSetDatumLength(new_data, new_tuple_len);
521  HeapTupleHeaderSetTypeId(new_data, tupleDesc->tdtypeid);
522  HeapTupleHeaderSetTypMod(new_data, tupleDesc->tdtypmod);
523 
524  /* Copy over the data, and fill the null bitmap if needed */
525  heap_fill_tuple(tupleDesc,
526  toast_values,
527  toast_isnull,
528  (char *) new_data + new_header_len,
529  new_data_len,
530  &(new_data->t_infomask),
531  has_nulls ? new_data->t_bits : NULL);
532 
533  /*
534  * Free allocated temp values
535  */
536  for (i = 0; i < numAttrs; i++)
537  if (toast_free[i])
538  pfree(DatumGetPointer(toast_values[i]));
539 
540  return PointerGetDatum(new_data);
541 }
#define VARATT_IS_COMPRESSED(PTR)
Definition: postgres.h:312
void heap_fill_tuple(TupleDesc tupleDesc, Datum *values, bool *isnull, char *data, Size data_size, uint16 *infomask, bits8 *bit)
Definition: heaptuple.c:304
#define SizeofHeapTupleHeader
Definition: htup_details.h:184
#define HeapTupleHeaderSetTypeId(tup, typeid)
Definition: htup_details.h:463
bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]
Definition: htup_details.h:177
#define MaxTupleAttributeNumber
Definition: htup_details.h:33
#define PointerGetDatum(X)
Definition: postgres.h:556
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define BITMAPLEN(NATTS)
Definition: htup_details.h:547
signed int int32
Definition: c.h:355
#define HeapTupleHeaderSetDatumLength(tup, len)
Definition: htup_details.h:455
HeapTupleHeader t_data
Definition: htup.h:68
#define VARATT_IS_EXTERNAL(PTR)
Definition: postgres.h:313
struct varlena * detoast_attr(struct varlena *attr)
Definition: detoast.c:115
void pfree(void *pointer)
Definition: mcxt.c:1056
int32 tdtypmod
Definition: tupdesc.h:83
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
Oid t_tableOid
Definition: htup.h:66
int16 attlen
Definition: pg_attribute.h:64
void * palloc0(Size size)
Definition: mcxt.c:980
uintptr_t Datum
Definition: postgres.h:367
#define HeapTupleHeaderSetTypMod(tup, typmod)
Definition: htup_details.h:473
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:738
#define HeapTupleHeaderSetNatts(tup, natts)
Definition: htup_details.h:534
#define MAXALIGN(LEN)
Definition: c.h:691
Size heap_compute_data_size(TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:119
#define DatumGetPointer(X)
Definition: postgres.h:549
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1249
Oid tdtypeid
Definition: tupdesc.h:82
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
int i
Definition: c.h:555