PostgreSQL Source Code  git master
heaptoast.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * heaptoast.c
4  * Heap-specific definitions for external and compressed storage
5  * of variable size attributes.
6  *
7  * Copyright (c) 2000-2019, PostgreSQL Global Development Group
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/access/heap/heaptoast.c
12  *
13  *
14  * INTERFACE ROUTINES
15  * heap_toast_insert_or_update -
16  * Try to make a given tuple fit into one page by compressing
17  * or moving off attributes
18  *
19  * heap_toast_delete -
20  * Reclaim toast storage when a tuple is deleted
21  *
22  *-------------------------------------------------------------------------
23  */
24 
25 #include "postgres.h"
26 
27 #include "access/detoast.h"
28 #include "access/heapam.h"
29 #include "access/heaptoast.h"
30 #include "access/toast_helper.h"
31 #include "access/toast_internals.h"
32 
33 
34 /* ----------
35  * heap_toast_delete -
36  *
37  * Cascaded delete toast-entries on DELETE
38  * ----------
39  */
40 void
41 heap_toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative)
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 }
73 
74 
75 /* ----------
76  * heap_toast_insert_or_update -
77  *
78  * Delete no-longer-used toast-entries and create new ones to
79  * make the new tuple fit on INSERT or UPDATE
80  *
81  * Inputs:
82  * newtup: the candidate new tuple to be inserted
83  * oldtup: the old row version for UPDATE, or NULL for INSERT
84  * options: options to be passed to heap_insert() for toast rows
85  * Result:
86  * either newtup if no toasting is needed, or a palloc'd modified tuple
87  * that is what should actually get stored
88  *
89  * NOTE: neither newtup nor oldtup will be modified. This is a change
90  * from the pre-8.1 API of this routine.
91  * ----------
92  */
95  int options)
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  */
117  options &= ~HEAP_INSERT_SPECULATIVE;
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 }
330 
331 
332 /* ----------
333  * toast_flatten_tuple -
334  *
335  * "Flatten" a tuple to contain no out-of-line toasted fields.
336  * (This does not eliminate compressed or short-header datums.)
337  *
338  * Note: we expect the caller already checked HeapTupleHasExternal(tup),
339  * so there is no need for a short-circuit path.
340  * ----------
341  */
342 HeapTuple
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 }
410 
411 
412 /* ----------
413  * toast_flatten_tuple_to_datum -
414  *
415  * "Flatten" a tuple containing out-of-line toasted fields into a Datum.
416  * The result is always palloc'd in the current memory context.
417  *
418  * We have a general rule that Datums of container types (rows, arrays,
419  * ranges, etc) must not contain any external TOAST pointers. Without
420  * this rule, we'd have to look inside each Datum when preparing a tuple
421  * for storage, which would be expensive and would fail to extend cleanly
422  * to new sorts of container types.
423  *
424  * However, we don't want to say that tuples represented as HeapTuples
425  * can't contain toasted fields, so instead this routine should be called
426  * when such a HeapTuple is being converted into a Datum.
427  *
428  * While we're at it, we decompress any compressed fields too. This is not
429  * necessary for correctness, but reflects an expectation that compression
430  * will be more effective if applied to the whole tuple not individual
431  * fields. We are not so concerned about that that we want to deconstruct
432  * and reconstruct tuples just to get rid of compressed fields, however.
433  * So callers typically won't call this unless they see that the tuple has
434  * at least one external field.
435  *
436  * On the other hand, in-line short-header varlena fields are left alone.
437  * If we "untoasted" them here, they'd just get changed back to short-header
438  * format anyway within heap_fill_tuple.
439  * ----------
440  */
441 Datum
443  uint32 tup_len,
444  TupleDesc tupleDesc)
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 }
540 
541 
542 /* ----------
543  * toast_build_flattened_tuple -
544  *
545  * Build a tuple containing no out-of-line toasted fields.
546  * (This does not eliminate compressed or short-header datums.)
547  *
548  * This is essentially just like heap_form_tuple, except that it will
549  * expand any external-data pointers beforehand.
550  *
551  * It's not very clear whether it would be preferable to decompress
552  * in-line compressed datums while at it. For now, we don't.
553  * ----------
554  */
555 HeapTuple
557  Datum *values,
558  bool *isnull)
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 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
union HeapTupleHeaderData::@45 t_choice
HeapTupleData * HeapTuple
Definition: htup.h:71
char attstorage
Definition: pg_attribute.h:123
#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 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
#define PointerGetDatum(X)
Definition: postgres.h:556
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#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
#define BITMAPLEN(NATTS)
Definition: htup_details.h:547
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
Form_pg_class rd_rel
Definition: rel.h:83
#define HEAP_INSERT_SPECULATIVE
Definition: heapam.h:36
signed int int32
Definition: c.h:347
#define TOAST_TUPLE_TARGET
Definition: heaptoast.h:50
#define HeapTupleHeaderSetDatumLength(tup, len)
Definition: htup_details.h:455
#define TOAST_NEEDS_CHANGE
Definition: toast_helper.h:80
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
char * Pointer
Definition: c.h:336
int32 tdtypmod
Definition: tupdesc.h:83
ItemPointerData t_ctid
Definition: htup_details.h:160
ItemPointerData t_self
Definition: htup.h:65
void heap_toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative)
Definition: heaptoast.c:41
HeapTuple toast_flatten_tuple(HeapTuple tup, TupleDesc tupleDesc)
Definition: heaptoast.c:343
void toast_tuple_cleanup(ToastTupleContext *ttc)
Definition: toast_helper.c:269
uint32 t_len
Definition: htup.h:64
HeapTuple toast_build_flattened_tuple(TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptoast.c:556
int toast_tuple_find_biggest_attribute(ToastTupleContext *ttc, bool for_compression, bool check_main)
Definition: toast_helper.c:178
unsigned int uint32
Definition: c.h:359
Oid t_tableOid
Definition: htup.h:66
#define TOAST_TUPLE_TARGET_MAIN
Definition: heaptoast.h:61
void toast_delete_external(Relation rel, Datum *values, bool *isnull, bool is_speculative)
Definition: toast_helper.c:312
#define TOAST_HAS_NULLS
Definition: toast_helper.h:79
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
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
Datum toast_flatten_tuple_to_datum(HeapTupleHeader tup, uint32 tup_len, TupleDesc tupleDesc)
Definition: heaptoast.c:442
#define Assert(condition)
Definition: c.h:739
#define HeapTupleHeaderSetNatts(tup, natts)
Definition: htup_details.h:534
size_t Size
Definition: c.h:467
#define RelationGetToastTupleTarget(relation, defaulttarg)
Definition: rel.h:283
#define MAXALIGN(LEN)
Definition: c.h:692
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
static Datum values[MAXATTR]
Definition: bootstrap.c:167
Oid tdtypeid
Definition: tupdesc.h:82
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
#define HEAPTUPLESIZE
Definition: htup.h:73
int i
Definition: c.h:556
#define HEAP_XACT_MASK
Definition: htup_details.h:218
HeapTuple heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, int options)
Definition: heaptoast.c:94
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