PostgreSQL Source Code  git master
heaptoast.c File Reference
#include "postgres.h"
#include "access/detoast.h"
#include "access/heapam.h"
#include "access/heaptoast.h"
#include "access/toast_helper.h"
#include "access/toast_internals.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)
 

Function Documentation

◆ heap_toast_delete()

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

Definition at line 41 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().

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

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

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

◆ toast_flatten_tuple()

HeapTuple toast_flatten_tuple ( HeapTuple  tup,
TupleDesc  tupleDesc 
)

Definition at line 343 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().

344 {
345  HeapTuple new_tuple;
346  int numAttrs = tupleDesc->natts;
347  int i;
348  Datum toast_values[MaxTupleAttributeNumber];
349  bool toast_isnull[MaxTupleAttributeNumber];
350  bool toast_free[MaxTupleAttributeNumber];
351 
352  /*
353  * Break down the tuple into fields.
354  */
355  Assert(numAttrs <= MaxTupleAttributeNumber);
356  heap_deform_tuple(tup, tupleDesc, toast_values, toast_isnull);
357 
358  memset(toast_free, 0, numAttrs * sizeof(bool));
359 
360  for (i = 0; i < numAttrs; i++)
361  {
362  /*
363  * Look at non-null varlena attributes
364  */
365  if (!toast_isnull[i] && TupleDescAttr(tupleDesc, i)->attlen == -1)
366  {
367  struct varlena *new_value;
368 
369  new_value = (struct varlena *) DatumGetPointer(toast_values[i]);
370  if (VARATT_IS_EXTERNAL(new_value))
371  {
372  new_value = detoast_external_attr(new_value);
373  toast_values[i] = PointerGetDatum(new_value);
374  toast_free[i] = true;
375  }
376  }
377  }
378 
379  /*
380  * Form the reconfigured tuple.
381  */
382  new_tuple = heap_form_tuple(tupleDesc, toast_values, toast_isnull);
383 
384  /*
385  * Be sure to copy the tuple's identity fields. We also make a point of
386  * copying visibility info, just in case anybody looks at those fields in
387  * a syscache entry.
388  */
389  new_tuple->t_self = tup->t_self;
390  new_tuple->t_tableOid = tup->t_tableOid;
391 
392  new_tuple->t_data->t_choice = tup->t_data->t_choice;
393  new_tuple->t_data->t_ctid = tup->t_data->t_ctid;
394  new_tuple->t_data->t_infomask &= ~HEAP_XACT_MASK;
395  new_tuple->t_data->t_infomask |=
397  new_tuple->t_data->t_infomask2 &= ~HEAP2_XACT_MASK;
398  new_tuple->t_data->t_infomask2 |=
400 
401  /*
402  * Free allocated temp values
403  */
404  for (i = 0; i < numAttrs; i++)
405  if (toast_free[i])
406  pfree(DatumGetPointer(toast_values[i]));
407 
408  return new_tuple;
409 }
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:45
#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:732
#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:549
#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 442 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().

445 {
446  HeapTupleHeader new_data;
447  int32 new_header_len;
448  int32 new_data_len;
449  int32 new_tuple_len;
450  HeapTupleData tmptup;
451  int numAttrs = tupleDesc->natts;
452  int i;
453  bool has_nulls = false;
454  Datum toast_values[MaxTupleAttributeNumber];
455  bool toast_isnull[MaxTupleAttributeNumber];
456  bool toast_free[MaxTupleAttributeNumber];
457 
458  /* Build a temporary HeapTuple control structure */
459  tmptup.t_len = tup_len;
460  ItemPointerSetInvalid(&(tmptup.t_self));
461  tmptup.t_tableOid = InvalidOid;
462  tmptup.t_data = tup;
463 
464  /*
465  * Break down the tuple into fields.
466  */
467  Assert(numAttrs <= MaxTupleAttributeNumber);
468  heap_deform_tuple(&tmptup, tupleDesc, toast_values, toast_isnull);
469 
470  memset(toast_free, 0, numAttrs * sizeof(bool));
471 
472  for (i = 0; i < numAttrs; i++)
473  {
474  /*
475  * Look at non-null varlena attributes
476  */
477  if (toast_isnull[i])
478  has_nulls = true;
479  else if (TupleDescAttr(tupleDesc, i)->attlen == -1)
480  {
481  struct varlena *new_value;
482 
483  new_value = (struct varlena *) DatumGetPointer(toast_values[i]);
484  if (VARATT_IS_EXTERNAL(new_value) ||
485  VARATT_IS_COMPRESSED(new_value))
486  {
487  new_value = detoast_attr(new_value);
488  toast_values[i] = PointerGetDatum(new_value);
489  toast_free[i] = true;
490  }
491  }
492  }
493 
494  /*
495  * Calculate the new size of the tuple.
496  *
497  * This should match the reconstruction code in
498  * heap_toast_insert_or_update.
499  */
500  new_header_len = SizeofHeapTupleHeader;
501  if (has_nulls)
502  new_header_len += BITMAPLEN(numAttrs);
503  new_header_len = MAXALIGN(new_header_len);
504  new_data_len = heap_compute_data_size(tupleDesc,
505  toast_values, toast_isnull);
506  new_tuple_len = new_header_len + new_data_len;
507 
508  new_data = (HeapTupleHeader) palloc0(new_tuple_len);
509 
510  /*
511  * Copy the existing tuple header, but adjust natts and t_hoff.
512  */
513  memcpy(new_data, tup, SizeofHeapTupleHeader);
514  HeapTupleHeaderSetNatts(new_data, numAttrs);
515  new_data->t_hoff = new_header_len;
516 
517  /* Set the composite-Datum header fields correctly */
518  HeapTupleHeaderSetDatumLength(new_data, new_tuple_len);
519  HeapTupleHeaderSetTypeId(new_data, tupleDesc->tdtypeid);
520  HeapTupleHeaderSetTypMod(new_data, tupleDesc->tdtypmod);
521 
522  /* Copy over the data, and fill the null bitmap if needed */
523  heap_fill_tuple(tupleDesc,
524  toast_values,
525  toast_isnull,
526  (char *) new_data + new_header_len,
527  new_data_len,
528  &(new_data->t_infomask),
529  has_nulls ? new_data->t_bits : NULL);
530 
531  /*
532  * Free allocated temp values
533  */
534  for (i = 0; i < numAttrs; i++)
535  if (toast_free[i])
536  pfree(DatumGetPointer(toast_values[i]));
537 
538  return PointerGetDatum(new_data);
539 }
#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:346
#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:116
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:732
#define HeapTupleHeaderSetNatts(tup, natts)
Definition: htup_details.h:534
#define MAXALIGN(LEN)
Definition: c.h:685
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:549