PostgreSQL Source Code  git master
tuptoaster.c File Reference
#include "postgres.h"
#include <unistd.h>
#include <fcntl.h>
#include "access/genam.h"
#include "access/heapam.h"
#include "access/tuptoaster.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "common/pg_lzcompress.h"
#include "miscadmin.h"
#include "utils/expandeddatum.h"
#include "utils/fmgroids.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/typcache.h"
Include dependency graph for tuptoaster.c:

Go to the source code of this file.

Data Structures

struct  toast_compress_header
 

Macros

#define TOAST_COMPRESS_HDRSZ   ((int32) sizeof(toast_compress_header))
 
#define TOAST_COMPRESS_RAWSIZE(ptr)   (((toast_compress_header *) (ptr))->rawsize)
 
#define TOAST_COMPRESS_RAWDATA(ptr)   (((char *) (ptr)) + TOAST_COMPRESS_HDRSZ)
 
#define TOAST_COMPRESS_SET_RAWSIZE(ptr, len)   (((toast_compress_header *) (ptr))->rawsize = (len))
 

Typedefs

typedef struct toast_compress_header toast_compress_header
 

Functions

static void toast_delete_datum (Relation rel, Datum value, bool is_speculative)
 
static Datum toast_save_datum (Relation rel, Datum value, struct varlena *oldexternal, int options)
 
static bool toastrel_valueid_exists (Relation toastrel, Oid valueid)
 
static bool toastid_valueid_exists (Oid toastrelid, Oid valueid)
 
static struct varlenatoast_fetch_datum (struct varlena *attr)
 
static struct varlenatoast_fetch_datum_slice (struct varlena *attr, int32 sliceoffset, int32 length)
 
static struct varlenatoast_decompress_datum (struct varlena *attr)
 
static struct varlenatoast_decompress_datum_slice (struct varlena *attr, int32 slicelength)
 
static int toast_open_indexes (Relation toastrel, LOCKMODE lock, Relation **toastidxs, int *num_indexes)
 
static void toast_close_indexes (Relation *toastidxs, int num_indexes, LOCKMODE lock)
 
static void init_toast_snapshot (Snapshot toast_snapshot)
 
struct varlenaheap_tuple_fetch_attr (struct varlena *attr)
 
struct varlenaheap_tuple_untoast_attr (struct varlena *attr)
 
struct varlenaheap_tuple_untoast_attr_slice (struct varlena *attr, int32 sliceoffset, int32 slicelength)
 
Size toast_raw_datum_size (Datum value)
 
Size toast_datum_size (Datum value)
 
void toast_delete (Relation rel, HeapTuple oldtup, bool is_speculative)
 
HeapTuple 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)
 
Datum toast_compress_datum (Datum value)
 
Oid toast_get_valid_index (Oid toastoid, LOCKMODE lock)
 

Macro Definition Documentation

◆ TOAST_COMPRESS_HDRSZ

#define TOAST_COMPRESS_HDRSZ   ((int32) sizeof(toast_compress_header))

◆ TOAST_COMPRESS_RAWDATA

#define TOAST_COMPRESS_RAWDATA (   ptr)    (((char *) (ptr)) + TOAST_COMPRESS_HDRSZ)

◆ TOAST_COMPRESS_RAWSIZE

#define TOAST_COMPRESS_RAWSIZE (   ptr)    (((toast_compress_header *) (ptr))->rawsize)

Definition at line 63 of file tuptoaster.c.

Referenced by toast_decompress_datum().

◆ TOAST_COMPRESS_SET_RAWSIZE

#define TOAST_COMPRESS_SET_RAWSIZE (   ptr,
  len 
)    (((toast_compress_header *) (ptr))->rawsize = (len))

Definition at line 66 of file tuptoaster.c.

Referenced by toast_compress_datum().

Typedef Documentation

◆ toast_compress_header

Function Documentation

◆ heap_tuple_fetch_attr()

struct varlena* heap_tuple_fetch_attr ( struct varlena attr)

Definition at line 101 of file tuptoaster.c.

References Assert, DatumGetEOHP(), EOH_flatten_into(), EOH_get_flat_size(), heap_tuple_fetch_attr(), palloc(), varatt_indirect::pointer, PointerGetDatum, toast_fetch_datum(), VARATT_EXTERNAL_GET_POINTER, VARATT_IS_EXTERNAL, VARATT_IS_EXTERNAL_EXPANDED, VARATT_IS_EXTERNAL_INDIRECT, VARATT_IS_EXTERNAL_ONDISK, and VARSIZE_ANY.

Referenced by assign_simple_var(), expanded_record_set_field_internal(), expanded_record_set_fields(), heap_tuple_fetch_attr(), heap_tuple_untoast_attr(), heap_tuple_untoast_attr_slice(), index_form_tuple(), make_tuple_indirect(), toast_build_flattened_tuple(), toast_flatten_tuple(), toast_insert_or_update(), and tstoreReceiveSlot_detoast().

102 {
103  struct varlena *result;
104 
105  if (VARATT_IS_EXTERNAL_ONDISK(attr))
106  {
107  /*
108  * This is an external stored plain value
109  */
110  result = toast_fetch_datum(attr);
111  }
112  else if (VARATT_IS_EXTERNAL_INDIRECT(attr))
113  {
114  /*
115  * This is an indirect pointer --- dereference it
116  */
117  struct varatt_indirect redirect;
118 
119  VARATT_EXTERNAL_GET_POINTER(redirect, attr);
120  attr = (struct varlena *) redirect.pointer;
121 
122  /* nested indirect Datums aren't allowed */
124 
125  /* recurse if value is still external in some other way */
126  if (VARATT_IS_EXTERNAL(attr))
127  return heap_tuple_fetch_attr(attr);
128 
129  /*
130  * Copy into the caller's memory context, in case caller tries to
131  * pfree the result.
132  */
133  result = (struct varlena *) palloc(VARSIZE_ANY(attr));
134  memcpy(result, attr, VARSIZE_ANY(attr));
135  }
136  else if (VARATT_IS_EXTERNAL_EXPANDED(attr))
137  {
138  /*
139  * This is an expanded-object pointer --- get flat format
140  */
142  Size resultsize;
143 
144  eoh = DatumGetEOHP(PointerGetDatum(attr));
145  resultsize = EOH_get_flat_size(eoh);
146  result = (struct varlena *) palloc(resultsize);
147  EOH_flatten_into(eoh, (void *) result, resultsize);
148  }
149  else
150  {
151  /*
152  * This is a plain value inside of the main tuple - why am I called?
153  */
154  result = attr;
155  }
156 
157  return result;
158 }
#define VARATT_IS_EXTERNAL_ONDISK(PTR)
Definition: postgres.h:314
#define VARATT_IS_EXTERNAL_EXPANDED(PTR)
Definition: postgres.h:322
#define PointerGetDatum(X)
Definition: postgres.h:556
struct varlena * heap_tuple_fetch_attr(struct varlena *attr)
Definition: tuptoaster.c:101
#define VARATT_IS_EXTERNAL(PTR)
Definition: postgres.h:313
#define VARATT_IS_EXTERNAL_INDIRECT(PTR)
Definition: postgres.h:316
Size EOH_get_flat_size(ExpandedObjectHeader *eohptr)
Definition: expandeddatum.c:75
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
void EOH_flatten_into(ExpandedObjectHeader *eohptr, void *result, Size allocated_size)
Definition: expandeddatum.c:81
#define VARSIZE_ANY(PTR)
Definition: postgres.h:335
#define Assert(condition)
Definition: c.h:732
#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr)
Definition: tuptoaster.h:121
static struct varlena * toast_fetch_datum(struct varlena *attr)
Definition: tuptoaster.c:1865
size_t Size
Definition: c.h:466
void * palloc(Size size)
Definition: mcxt.c:924
Definition: c.h:549

◆ heap_tuple_untoast_attr()

struct varlena* heap_tuple_untoast_attr ( struct varlena attr)

Definition at line 172 of file tuptoaster.c.

References Assert, heap_tuple_fetch_attr(), heap_tuple_untoast_attr(), palloc(), pfree(), varatt_indirect::pointer, SET_VARSIZE, toast_decompress_datum(), toast_fetch_datum(), VARATT_EXTERNAL_GET_POINTER, VARATT_IS_COMPRESSED, VARATT_IS_EXTENDED, VARATT_IS_EXTERNAL_EXPANDED, VARATT_IS_EXTERNAL_INDIRECT, VARATT_IS_EXTERNAL_ONDISK, VARATT_IS_SHORT, VARDATA, VARDATA_SHORT, VARHDRSZ, VARHDRSZ_SHORT, VARSIZE_ANY, and VARSIZE_SHORT.

Referenced by getdatafield(), heap_tuple_untoast_attr(), pg_detoast_datum(), pg_detoast_datum_copy(), pg_detoast_datum_packed(), toast_flatten_tuple_to_datum(), and toast_insert_or_update().

173 {
174  if (VARATT_IS_EXTERNAL_ONDISK(attr))
175  {
176  /*
177  * This is an externally stored datum --- fetch it back from there
178  */
179  attr = toast_fetch_datum(attr);
180  /* If it's compressed, decompress it */
181  if (VARATT_IS_COMPRESSED(attr))
182  {
183  struct varlena *tmp = attr;
184 
185  attr = toast_decompress_datum(tmp);
186  pfree(tmp);
187  }
188  }
189  else if (VARATT_IS_EXTERNAL_INDIRECT(attr))
190  {
191  /*
192  * This is an indirect pointer --- dereference it
193  */
194  struct varatt_indirect redirect;
195 
196  VARATT_EXTERNAL_GET_POINTER(redirect, attr);
197  attr = (struct varlena *) redirect.pointer;
198 
199  /* nested indirect Datums aren't allowed */
201 
202  /* recurse in case value is still extended in some other way */
203  attr = heap_tuple_untoast_attr(attr);
204 
205  /* if it isn't, we'd better copy it */
206  if (attr == (struct varlena *) redirect.pointer)
207  {
208  struct varlena *result;
209 
210  result = (struct varlena *) palloc(VARSIZE_ANY(attr));
211  memcpy(result, attr, VARSIZE_ANY(attr));
212  attr = result;
213  }
214  }
215  else if (VARATT_IS_EXTERNAL_EXPANDED(attr))
216  {
217  /*
218  * This is an expanded-object pointer --- get flat format
219  */
220  attr = heap_tuple_fetch_attr(attr);
221  /* flatteners are not allowed to produce compressed/short output */
222  Assert(!VARATT_IS_EXTENDED(attr));
223  }
224  else if (VARATT_IS_COMPRESSED(attr))
225  {
226  /*
227  * This is a compressed value inside of the main tuple
228  */
229  attr = toast_decompress_datum(attr);
230  }
231  else if (VARATT_IS_SHORT(attr))
232  {
233  /*
234  * This is a short-header varlena --- convert to 4-byte header format
235  */
236  Size data_size = VARSIZE_SHORT(attr) - VARHDRSZ_SHORT;
237  Size new_size = data_size + VARHDRSZ;
238  struct varlena *new_attr;
239 
240  new_attr = (struct varlena *) palloc(new_size);
241  SET_VARSIZE(new_attr, new_size);
242  memcpy(VARDATA(new_attr), VARDATA_SHORT(attr), data_size);
243  attr = new_attr;
244  }
245 
246  return attr;
247 }
#define VARATT_IS_EXTERNAL_ONDISK(PTR)
Definition: postgres.h:314
#define VARATT_IS_COMPRESSED(PTR)
Definition: postgres.h:312
#define VARDATA(PTR)
Definition: postgres.h:302
#define VARATT_IS_EXTERNAL_EXPANDED(PTR)
Definition: postgres.h:322
#define VARHDRSZ_SHORT
Definition: postgres.h:268
struct varlena * heap_tuple_fetch_attr(struct varlena *attr)
Definition: tuptoaster.c:101
#define VARHDRSZ
Definition: c.h:555
struct varlena * heap_tuple_untoast_attr(struct varlena *attr)
Definition: tuptoaster.c:172
void pfree(void *pointer)
Definition: mcxt.c:1031
#define VARATT_IS_EXTERNAL_INDIRECT(PTR)
Definition: postgres.h:316
#define VARATT_IS_SHORT(PTR)
Definition: postgres.h:326
#define VARSIZE_SHORT(PTR)
Definition: postgres.h:305
#define VARSIZE_ANY(PTR)
Definition: postgres.h:335
#define Assert(condition)
Definition: c.h:732
#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr)
Definition: tuptoaster.h:121
static struct varlena * toast_fetch_datum(struct varlena *attr)
Definition: tuptoaster.c:1865
size_t Size
Definition: c.h:466
static struct varlena * toast_decompress_datum(struct varlena *attr)
Definition: tuptoaster.c:2277
#define VARATT_IS_EXTENDED(PTR)
Definition: postgres.h:327
#define VARDATA_SHORT(PTR)
Definition: postgres.h:306
void * palloc(Size size)
Definition: mcxt.c:924
Definition: c.h:549
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329

◆ heap_tuple_untoast_attr_slice()

struct varlena* heap_tuple_untoast_attr_slice ( struct varlena attr,
int32  sliceoffset,
int32  slicelength 
)

Definition at line 258 of file tuptoaster.c.

References Assert, heap_tuple_fetch_attr(), heap_tuple_untoast_attr_slice(), palloc(), pfree(), varatt_indirect::pointer, SET_VARSIZE, toast_decompress_datum(), toast_decompress_datum_slice(), toast_fetch_datum(), toast_fetch_datum_slice(), VARATT_EXTERNAL_GET_POINTER, VARATT_EXTERNAL_IS_COMPRESSED, VARATT_IS_COMPRESSED, VARATT_IS_EXTERNAL, VARATT_IS_EXTERNAL_EXPANDED, VARATT_IS_EXTERNAL_INDIRECT, VARATT_IS_EXTERNAL_ONDISK, VARATT_IS_SHORT, VARDATA, VARDATA_SHORT, VARHDRSZ, VARHDRSZ_SHORT, VARSIZE, and VARSIZE_SHORT.

Referenced by heap_tuple_untoast_attr_slice(), and pg_detoast_datum_slice().

260 {
261  struct varlena *preslice;
262  struct varlena *result;
263  char *attrdata;
264  int32 attrsize;
265 
266  if (VARATT_IS_EXTERNAL_ONDISK(attr))
267  {
268  struct varatt_external toast_pointer;
269 
270  VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
271 
272  /* fast path for non-compressed external datums */
273  if (!VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer))
274  return toast_fetch_datum_slice(attr, sliceoffset, slicelength);
275 
276  /* fetch it back (compressed marker will get set automatically) */
277  preslice = toast_fetch_datum(attr);
278  }
279  else if (VARATT_IS_EXTERNAL_INDIRECT(attr))
280  {
281  struct varatt_indirect redirect;
282 
283  VARATT_EXTERNAL_GET_POINTER(redirect, attr);
284 
285  /* nested indirect Datums aren't allowed */
286  Assert(!VARATT_IS_EXTERNAL_INDIRECT(redirect.pointer));
287 
288  return heap_tuple_untoast_attr_slice(redirect.pointer,
289  sliceoffset, slicelength);
290  }
291  else if (VARATT_IS_EXTERNAL_EXPANDED(attr))
292  {
293  /* pass it off to heap_tuple_fetch_attr to flatten */
294  preslice = heap_tuple_fetch_attr(attr);
295  }
296  else
297  preslice = attr;
298 
299  Assert(!VARATT_IS_EXTERNAL(preslice));
300 
301  if (VARATT_IS_COMPRESSED(preslice))
302  {
303  struct varlena *tmp = preslice;
304 
305  /* Decompress enough to encompass the slice and the offset */
306  if (slicelength > 0 && sliceoffset >= 0)
307  preslice = toast_decompress_datum_slice(tmp, slicelength + sliceoffset);
308  else
309  preslice = toast_decompress_datum(tmp);
310 
311  if (tmp != attr)
312  pfree(tmp);
313  }
314 
315  if (VARATT_IS_SHORT(preslice))
316  {
317  attrdata = VARDATA_SHORT(preslice);
318  attrsize = VARSIZE_SHORT(preslice) - VARHDRSZ_SHORT;
319  }
320  else
321  {
322  attrdata = VARDATA(preslice);
323  attrsize = VARSIZE(preslice) - VARHDRSZ;
324  }
325 
326  /* slicing of datum for compressed cases and plain value */
327 
328  if (sliceoffset >= attrsize)
329  {
330  sliceoffset = 0;
331  slicelength = 0;
332  }
333 
334  if (((sliceoffset + slicelength) > attrsize) || slicelength < 0)
335  slicelength = attrsize - sliceoffset;
336 
337  result = (struct varlena *) palloc(slicelength + VARHDRSZ);
338  SET_VARSIZE(result, slicelength + VARHDRSZ);
339 
340  memcpy(VARDATA(result), attrdata + sliceoffset, slicelength);
341 
342  if (preslice != attr)
343  pfree(preslice);
344 
345  return result;
346 }
#define VARATT_IS_EXTERNAL_ONDISK(PTR)
Definition: postgres.h:314
static struct varlena * toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, int32 length)
Definition: tuptoaster.c:2048
#define VARATT_IS_COMPRESSED(PTR)
Definition: postgres.h:312
#define VARDATA(PTR)
Definition: postgres.h:302
#define VARATT_IS_EXTERNAL_EXPANDED(PTR)
Definition: postgres.h:322
#define VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer)
Definition: tuptoaster.h:111
#define VARHDRSZ_SHORT
Definition: postgres.h:268
#define VARSIZE(PTR)
Definition: postgres.h:303
struct varlena * heap_tuple_fetch_attr(struct varlena *attr)
Definition: tuptoaster.c:101
#define VARHDRSZ
Definition: c.h:555
signed int int32
Definition: c.h:346
#define VARATT_IS_EXTERNAL(PTR)
Definition: postgres.h:313
void pfree(void *pointer)
Definition: mcxt.c:1031
#define VARATT_IS_EXTERNAL_INDIRECT(PTR)
Definition: postgres.h:316
#define VARATT_IS_SHORT(PTR)
Definition: postgres.h:326
static struct varlena * toast_decompress_datum_slice(struct varlena *attr, int32 slicelength)
Definition: tuptoaster.c:2305
#define VARSIZE_SHORT(PTR)
Definition: postgres.h:305
struct varlena * heap_tuple_untoast_attr_slice(struct varlena *attr, int32 sliceoffset, int32 slicelength)
Definition: tuptoaster.c:258
#define Assert(condition)
Definition: c.h:732
#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr)
Definition: tuptoaster.h:121
static struct varlena * toast_fetch_datum(struct varlena *attr)
Definition: tuptoaster.c:1865
static struct varlena * toast_decompress_datum(struct varlena *attr)
Definition: tuptoaster.c:2277
#define VARDATA_SHORT(PTR)
Definition: postgres.h:306
void * palloc(Size size)
Definition: mcxt.c:924
Definition: c.h:549
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329

◆ init_toast_snapshot()

static void init_toast_snapshot ( Snapshot  toast_snapshot)
static

Definition at line 2413 of file tuptoaster.c.

References elog, ERROR, GetOldestSnapshot(), InitToastSnapshot, SnapshotData::lsn, and SnapshotData::whenTaken.

Referenced by toast_delete_datum(), toast_fetch_datum(), and toast_fetch_datum_slice().

2414 {
2415  Snapshot snapshot = GetOldestSnapshot();
2416 
2417  if (snapshot == NULL)
2418  elog(ERROR, "no known snapshots");
2419 
2420  InitToastSnapshot(*toast_snapshot, snapshot->lsn, snapshot->whenTaken);
2421 }
XLogRecPtr lsn
Definition: snapshot.h:203
#define ERROR
Definition: elog.h:43
Snapshot GetOldestSnapshot(void)
Definition: snapmgr.c:413
#define elog(elevel,...)
Definition: elog.h:226
TimestampTz whenTaken
Definition: snapshot.h:202
#define InitToastSnapshot(snapshotdata, l, w)
Definition: snapmgr.h:92

◆ toast_build_flattened_tuple()

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

Definition at line 1295 of file tuptoaster.c.

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

Referenced by ExecEvalWholeRowVar().

1298 {
1299  HeapTuple new_tuple;
1300  int numAttrs = tupleDesc->natts;
1301  int num_to_free;
1302  int i;
1303  Datum new_values[MaxTupleAttributeNumber];
1304  Pointer freeable_values[MaxTupleAttributeNumber];
1305 
1306  /*
1307  * We can pass the caller's isnull array directly to heap_form_tuple, but
1308  * we potentially need to modify the values array.
1309  */
1310  Assert(numAttrs <= MaxTupleAttributeNumber);
1311  memcpy(new_values, values, numAttrs * sizeof(Datum));
1312 
1313  num_to_free = 0;
1314  for (i = 0; i < numAttrs; i++)
1315  {
1316  /*
1317  * Look at non-null varlena attributes
1318  */
1319  if (!isnull[i] && TupleDescAttr(tupleDesc, i)->attlen == -1)
1320  {
1321  struct varlena *new_value;
1322 
1323  new_value = (struct varlena *) DatumGetPointer(new_values[i]);
1324  if (VARATT_IS_EXTERNAL(new_value))
1325  {
1326  new_value = heap_tuple_fetch_attr(new_value);
1327  new_values[i] = PointerGetDatum(new_value);
1328  freeable_values[num_to_free++] = (Pointer) new_value;
1329  }
1330  }
1331  }
1332 
1333  /*
1334  * Form the reconfigured tuple.
1335  */
1336  new_tuple = heap_form_tuple(tupleDesc, new_values, isnull);
1337 
1338  /*
1339  * Free allocated temp values
1340  */
1341  for (i = 0; i < num_to_free; i++)
1342  pfree(freeable_values[i]);
1343 
1344  return new_tuple;
1345 }
#define MaxTupleAttributeNumber
Definition: htup_details.h:33
#define PointerGetDatum(X)
Definition: postgres.h:556
struct varlena * heap_tuple_fetch_attr(struct varlena *attr)
Definition: tuptoaster.c:101
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
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:1031
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_close_indexes()

static void toast_close_indexes ( Relation toastidxs,
int  num_indexes,
LOCKMODE  lock 
)
static

Definition at line 2394 of file tuptoaster.c.

References i, index_close(), and pfree().

Referenced by toast_delete_datum(), toast_fetch_datum(), toast_fetch_datum_slice(), toast_get_valid_index(), toast_save_datum(), and toastrel_valueid_exists().

2395 {
2396  int i;
2397 
2398  /* Close relations and clean up things */
2399  for (i = 0; i < num_indexes; i++)
2400  index_close(toastidxs[i], lock);
2401  pfree(toastidxs);
2402 }
void pfree(void *pointer)
Definition: mcxt.c:1031
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:152
int i

◆ toast_compress_datum()

Datum toast_compress_datum ( Datum  value)

Definition at line 1362 of file tuptoaster.c.

References Assert, DatumGetPointer, PGLZ_Strategy::max_input_size, palloc(), pfree(), pglz_compress(), PGLZ_MAX_OUTPUT, PGLZ_strategy_default, PointerGetDatum, SET_VARSIZE_COMPRESSED, TOAST_COMPRESS_HDRSZ, TOAST_COMPRESS_RAWDATA, TOAST_COMPRESS_SET_RAWSIZE, VARATT_IS_COMPRESSED, VARATT_IS_EXTERNAL, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

Referenced by index_form_tuple(), and toast_insert_or_update().

1363 {
1364  struct varlena *tmp;
1366  int32 len;
1367 
1370 
1371  /*
1372  * No point in wasting a palloc cycle if value size is out of the allowed
1373  * range for compression
1374  */
1375  if (valsize < PGLZ_strategy_default->min_input_size ||
1377  return PointerGetDatum(NULL);
1378 
1379  tmp = (struct varlena *) palloc(PGLZ_MAX_OUTPUT(valsize) +
1381 
1382  /*
1383  * We recheck the actual size even if pglz_compress() reports success,
1384  * because it might be satisfied with having saved as little as one byte
1385  * in the compressed data --- which could turn into a net loss once you
1386  * consider header and alignment padding. Worst case, the compressed
1387  * format might require three padding bytes (plus header, which is
1388  * included in VARSIZE(tmp)), whereas the uncompressed format would take
1389  * only one header byte and no padding if the value is short enough. So
1390  * we insist on a savings of more than 2 bytes to ensure we have a gain.
1391  */
1393  valsize,
1396  if (len >= 0 &&
1397  len + TOAST_COMPRESS_HDRSZ < valsize - 2)
1398  {
1399  TOAST_COMPRESS_SET_RAWSIZE(tmp, valsize);
1401  /* successful compression */
1402  return PointerGetDatum(tmp);
1403  }
1404  else
1405  {
1406  /* incompressible data */
1407  pfree(tmp);
1408  return PointerGetDatum(NULL);
1409  }
1410 }
#define VARATT_IS_COMPRESSED(PTR)
Definition: postgres.h:312
#define VARDATA_ANY(PTR)
Definition: postgres.h:348
#define TOAST_COMPRESS_HDRSZ
Definition: tuptoaster.c:62
#define PointerGetDatum(X)
Definition: postgres.h:556
static struct @144 value
signed int int32
Definition: c.h:346
#define TOAST_COMPRESS_SET_RAWSIZE(ptr, len)
Definition: tuptoaster.c:66
#define VARATT_IS_EXTERNAL(PTR)
Definition: postgres.h:313
void pfree(void *pointer)
Definition: mcxt.c:1031
int32 pglz_compress(const char *source, int32 slen, char *dest, const PGLZ_Strategy *strategy)
#define PGLZ_MAX_OUTPUT(_dlen)
Definition: pg_lzcompress.h:21
#define Assert(condition)
Definition: c.h:732
int32 max_input_size
Definition: pg_lzcompress.h:60
#define DatumGetPointer(X)
Definition: postgres.h:549
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:341
void * palloc(Size size)
Definition: mcxt.c:924
#define TOAST_COMPRESS_RAWDATA(ptr)
Definition: tuptoaster.c:64
#define SET_VARSIZE_COMPRESSED(PTR, len)
Definition: postgres.h:331
Definition: c.h:549
const PGLZ_Strategy *const PGLZ_strategy_default

◆ toast_datum_size()

Size toast_datum_size ( Datum  value)

Definition at line 413 of file tuptoaster.c.

References Assert, DatumGetEOHP(), DatumGetPointer, EOH_get_flat_size(), varatt_indirect::pointer, PointerGetDatum, toast_datum_size(), varatt_external::va_extsize, VARATT_EXTERNAL_GET_POINTER, VARATT_IS_EXTERNAL_EXPANDED, VARATT_IS_EXTERNAL_INDIRECT, VARATT_IS_EXTERNAL_ONDISK, VARATT_IS_SHORT, VARSIZE, and VARSIZE_SHORT.

Referenced by pg_column_size(), and toast_datum_size().

414 {
415  struct varlena *attr = (struct varlena *) DatumGetPointer(value);
416  Size result;
417 
418  if (VARATT_IS_EXTERNAL_ONDISK(attr))
419  {
420  /*
421  * Attribute is stored externally - return the extsize whether
422  * compressed or not. We do not count the size of the toast pointer
423  * ... should we?
424  */
425  struct varatt_external toast_pointer;
426 
427  VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
428  result = toast_pointer.va_extsize;
429  }
430  else if (VARATT_IS_EXTERNAL_INDIRECT(attr))
431  {
432  struct varatt_indirect toast_pointer;
433 
434  VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
435 
436  /* nested indirect Datums aren't allowed */
438 
439  return toast_datum_size(PointerGetDatum(toast_pointer.pointer));
440  }
441  else if (VARATT_IS_EXTERNAL_EXPANDED(attr))
442  {
444  }
445  else if (VARATT_IS_SHORT(attr))
446  {
447  result = VARSIZE_SHORT(attr);
448  }
449  else
450  {
451  /*
452  * Attribute is stored inline either compressed or not, just calculate
453  * the size of the datum in either case.
454  */
455  result = VARSIZE(attr);
456  }
457  return result;
458 }
#define VARATT_IS_EXTERNAL_ONDISK(PTR)
Definition: postgres.h:314
#define VARATT_IS_EXTERNAL_EXPANDED(PTR)
Definition: postgres.h:322
#define VARSIZE(PTR)
Definition: postgres.h:303
#define PointerGetDatum(X)
Definition: postgres.h:556
static struct @144 value
#define VARATT_IS_EXTERNAL_INDIRECT(PTR)
Definition: postgres.h:316
#define VARATT_IS_SHORT(PTR)
Definition: postgres.h:326
Size toast_datum_size(Datum value)
Definition: tuptoaster.c:413
Size EOH_get_flat_size(ExpandedObjectHeader *eohptr)
Definition: expandeddatum.c:75
#define VARSIZE_SHORT(PTR)
Definition: postgres.h:305
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
#define Assert(condition)
Definition: c.h:732
#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr)
Definition: tuptoaster.h:121
size_t Size
Definition: c.h:466
#define DatumGetPointer(X)
Definition: postgres.h:549
Definition: c.h:549

◆ toast_decompress_datum()

static struct varlena * toast_decompress_datum ( struct varlena attr)
static

Definition at line 2277 of file tuptoaster.c.

References Assert, elog, ERROR, palloc(), pglz_decompress(), SET_VARSIZE, TOAST_COMPRESS_HDRSZ, TOAST_COMPRESS_RAWDATA, TOAST_COMPRESS_RAWSIZE, VARATT_IS_COMPRESSED, VARDATA, VARHDRSZ, and VARSIZE.

Referenced by heap_tuple_untoast_attr(), and heap_tuple_untoast_attr_slice().

2278 {
2279  struct varlena *result;
2280 
2282 
2283  result = (struct varlena *)
2285  SET_VARSIZE(result, TOAST_COMPRESS_RAWSIZE(attr) + VARHDRSZ);
2286 
2288  VARSIZE(attr) - TOAST_COMPRESS_HDRSZ,
2289  VARDATA(result),
2290  TOAST_COMPRESS_RAWSIZE(attr), true) < 0)
2291  elog(ERROR, "compressed data is corrupted");
2292 
2293  return result;
2294 }
#define VARATT_IS_COMPRESSED(PTR)
Definition: postgres.h:312
#define VARDATA(PTR)
Definition: postgres.h:302
#define TOAST_COMPRESS_RAWSIZE(ptr)
Definition: tuptoaster.c:63
#define TOAST_COMPRESS_HDRSZ
Definition: tuptoaster.c:62
#define VARSIZE(PTR)
Definition: postgres.h:303
#define VARHDRSZ
Definition: c.h:555
int32 pglz_decompress(const char *source, int32 slen, char *dest, int32 rawsize, bool check_complete)
#define ERROR
Definition: elog.h:43
#define Assert(condition)
Definition: c.h:732
void * palloc(Size size)
Definition: mcxt.c:924
#define elog(elevel,...)
Definition: elog.h:226
#define TOAST_COMPRESS_RAWDATA(ptr)
Definition: tuptoaster.c:64
Definition: c.h:549
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329

◆ toast_decompress_datum_slice()

static struct varlena * toast_decompress_datum_slice ( struct varlena attr,
int32  slicelength 
)
static

Definition at line 2305 of file tuptoaster.c.

References Assert, elog, ERROR, palloc(), pglz_decompress(), toast_compress_header::rawsize, SET_VARSIZE, TOAST_COMPRESS_HDRSZ, TOAST_COMPRESS_RAWDATA, VARATT_IS_COMPRESSED, VARDATA, VARHDRSZ, and VARSIZE.

Referenced by heap_tuple_untoast_attr_slice().

2306 {
2307  struct varlena *result;
2308  int32 rawsize;
2309 
2311 
2312  result = (struct varlena *) palloc(slicelength + VARHDRSZ);
2313 
2314  rawsize = pglz_decompress(TOAST_COMPRESS_RAWDATA(attr),
2315  VARSIZE(attr) - TOAST_COMPRESS_HDRSZ,
2316  VARDATA(result),
2317  slicelength, false);
2318  if (rawsize < 0)
2319  elog(ERROR, "compressed data is corrupted");
2320 
2321  SET_VARSIZE(result, rawsize + VARHDRSZ);
2322  return result;
2323 }
#define VARATT_IS_COMPRESSED(PTR)
Definition: postgres.h:312
#define VARDATA(PTR)
Definition: postgres.h:302
#define TOAST_COMPRESS_HDRSZ
Definition: tuptoaster.c:62
#define VARSIZE(PTR)
Definition: postgres.h:303
#define VARHDRSZ
Definition: c.h:555
int32 pglz_decompress(const char *source, int32 slen, char *dest, int32 rawsize, bool check_complete)
signed int int32
Definition: c.h:346
#define ERROR
Definition: elog.h:43
#define Assert(condition)
Definition: c.h:732
void * palloc(Size size)
Definition: mcxt.c:924
#define elog(elevel,...)
Definition: elog.h:226
#define TOAST_COMPRESS_RAWDATA(ptr)
Definition: tuptoaster.c:64
Definition: c.h:549
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329

◆ toast_delete()

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

Definition at line 468 of file tuptoaster.c.

References Assert, attlen, heap_deform_tuple(), i, MaxHeapAttributeNumber, TupleDescData::natts, PointerGetDatum, RelationData::rd_att, RelationData::rd_rel, toast_delete_datum(), TupleDescAttr, value, and VARATT_IS_EXTERNAL_ONDISK.

Referenced by heap_abort_speculative(), and heap_delete().

469 {
470  TupleDesc tupleDesc;
471  int numAttrs;
472  int i;
473  Datum toast_values[MaxHeapAttributeNumber];
474  bool toast_isnull[MaxHeapAttributeNumber];
475 
476  /*
477  * We should only ever be called for tuples of plain relations or
478  * materialized views --- recursing on a toast rel is bad news.
479  */
480  Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
481  rel->rd_rel->relkind == RELKIND_MATVIEW);
482 
483  /*
484  * Get the tuple descriptor and break down the tuple into fields.
485  *
486  * NOTE: it's debatable whether to use heap_deform_tuple() here or just
487  * heap_getattr() only the varlena columns. The latter could win if there
488  * are few varlena columns and many non-varlena ones. However,
489  * heap_deform_tuple costs only O(N) while the heap_getattr way would cost
490  * O(N^2) if there are many varlena columns, so it seems better to err on
491  * the side of linear cost. (We won't even be here unless there's at
492  * least one varlena column, by the way.)
493  */
494  tupleDesc = rel->rd_att;
495  numAttrs = tupleDesc->natts;
496 
497  Assert(numAttrs <= MaxHeapAttributeNumber);
498  heap_deform_tuple(oldtup, tupleDesc, toast_values, toast_isnull);
499 
500  /*
501  * Check for external stored attributes and delete them from the secondary
502  * relation.
503  */
504  for (i = 0; i < numAttrs; i++)
505  {
506  if (TupleDescAttr(tupleDesc, i)->attlen == -1)
507  {
508  Datum value = toast_values[i];
509 
510  if (toast_isnull[i])
511  continue;
513  toast_delete_datum(rel, value, is_speculative);
514  }
515  }
516 }
#define VARATT_IS_EXTERNAL_ONDISK(PTR)
Definition: postgres.h:314
#define PointerGetDatum(X)
Definition: postgres.h:556
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static struct @144 value
Form_pg_class rd_rel
Definition: rel.h:83
int16 attlen
Definition: pg_attribute.h:64
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
static void toast_delete_datum(Relation rel, Datum value, bool is_speculative)
Definition: tuptoaster.c:1719
int i

◆ toast_delete_datum()

static void toast_delete_datum ( Relation  rel,
Datum  value,
bool  is_speculative 
)
static

Definition at line 1719 of file tuptoaster.c.

References BTEqualStrategyNumber, DatumGetPointer, ForwardScanDirection, heap_abort_speculative(), init_toast_snapshot(), ObjectIdGetDatum, RowExclusiveLock, ScanKeyInit(), simple_heap_delete(), systable_beginscan_ordered(), systable_endscan_ordered(), systable_getnext_ordered(), HeapTupleData::t_self, table_close(), table_open(), toast_close_indexes(), toast_open_indexes(), varatt_external::va_toastrelid, varatt_external::va_valueid, VARATT_EXTERNAL_GET_POINTER, and VARATT_IS_EXTERNAL_ONDISK.

Referenced by toast_delete(), and toast_insert_or_update().

1720 {
1721  struct varlena *attr = (struct varlena *) DatumGetPointer(value);
1722  struct varatt_external toast_pointer;
1723  Relation toastrel;
1724  Relation *toastidxs;
1725  ScanKeyData toastkey;
1726  SysScanDesc toastscan;
1727  HeapTuple toasttup;
1728  int num_indexes;
1729  int validIndex;
1730  SnapshotData SnapshotToast;
1731 
1732  if (!VARATT_IS_EXTERNAL_ONDISK(attr))
1733  return;
1734 
1735  /* Must copy to access aligned fields */
1736  VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
1737 
1738  /*
1739  * Open the toast relation and its indexes
1740  */
1741  toastrel = table_open(toast_pointer.va_toastrelid, RowExclusiveLock);
1742 
1743  /* Fetch valid relation used for process */
1744  validIndex = toast_open_indexes(toastrel,
1746  &toastidxs,
1747  &num_indexes);
1748 
1749  /*
1750  * Setup a scan key to find chunks with matching va_valueid
1751  */
1752  ScanKeyInit(&toastkey,
1753  (AttrNumber) 1,
1754  BTEqualStrategyNumber, F_OIDEQ,
1755  ObjectIdGetDatum(toast_pointer.va_valueid));
1756 
1757  /*
1758  * Find all the chunks. (We don't actually care whether we see them in
1759  * sequence or not, but since we've already locked the index we might as
1760  * well use systable_beginscan_ordered.)
1761  */
1762  init_toast_snapshot(&SnapshotToast);
1763  toastscan = systable_beginscan_ordered(toastrel, toastidxs[validIndex],
1764  &SnapshotToast, 1, &toastkey);
1765  while ((toasttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
1766  {
1767  /*
1768  * Have a chunk, delete it
1769  */
1770  if (is_speculative)
1771  heap_abort_speculative(toastrel, &toasttup->t_self);
1772  else
1773  simple_heap_delete(toastrel, &toasttup->t_self);
1774  }
1775 
1776  /*
1777  * End scan and close relations
1778  */
1779  systable_endscan_ordered(toastscan);
1780  toast_close_indexes(toastidxs, num_indexes, RowExclusiveLock);
1781  table_close(toastrel, RowExclusiveLock);
1782 }
#define VARATT_IS_EXTERNAL_ONDISK(PTR)
Definition: postgres.h:314
void heap_abort_speculative(Relation relation, ItemPointer tid)
Definition: heapam.c:5566
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
static int toast_open_indexes(Relation toastrel, LOCKMODE lock, Relation **toastidxs, int *num_indexes)
Definition: tuptoaster.c:2335
static void init_toast_snapshot(Snapshot toast_snapshot)
Definition: tuptoaster.c:2413
static struct @144 value
static void toast_close_indexes(Relation *toastidxs, int num_indexes, LOCKMODE lock)
Definition: tuptoaster.c:2394
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
Definition: genam.c:630
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
void systable_endscan_ordered(SysScanDesc sysscan)
Definition: genam.c:649
#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr)
Definition: tuptoaster.h:121
void simple_heap_delete(Relation relation, ItemPointer tid)
Definition: heapam.c:2847
#define DatumGetPointer(X)
Definition: postgres.h:549
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:565
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Definition: c.h:549
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
int16 AttrNumber
Definition: attnum.h:21
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ toast_fetch_datum()

static struct varlena * toast_fetch_datum ( struct varlena attr)
static

Definition at line 1865 of file tuptoaster.c.

References AccessShareLock, Assert, BTEqualStrategyNumber, DatumGetInt32, DatumGetPointer, elog, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg_internal(), ERROR, fastgetattr, ForwardScanDirection, init_toast_snapshot(), ObjectIdGetDatum, palloc(), RelationData::rd_att, RelationGetRelationName, ScanKeyInit(), SET_VARSIZE, SET_VARSIZE_COMPRESSED, systable_beginscan_ordered(), systable_endscan_ordered(), systable_getnext_ordered(), table_close(), table_open(), toast_close_indexes(), TOAST_MAX_CHUNK_SIZE, toast_open_indexes(), varatt_external::va_extsize, varatt_external::va_toastrelid, varatt_external::va_valueid, VARATT_EXTERNAL_GET_POINTER, VARATT_EXTERNAL_IS_COMPRESSED, VARATT_IS_EXTENDED, VARATT_IS_EXTERNAL_ONDISK, VARATT_IS_SHORT, VARDATA, VARDATA_SHORT, VARHDRSZ, VARHDRSZ_SHORT, VARSIZE, and VARSIZE_SHORT.

Referenced by heap_tuple_fetch_attr(), heap_tuple_untoast_attr(), and heap_tuple_untoast_attr_slice().

1866 {
1867  Relation toastrel;
1868  Relation *toastidxs;
1869  ScanKeyData toastkey;
1870  SysScanDesc toastscan;
1871  HeapTuple ttup;
1872  TupleDesc toasttupDesc;
1873  struct varlena *result;
1874  struct varatt_external toast_pointer;
1875  int32 ressize;
1876  int32 residx,
1877  nextidx;
1878  int32 numchunks;
1879  Pointer chunk;
1880  bool isnull;
1881  char *chunkdata;
1882  int32 chunksize;
1883  int num_indexes;
1884  int validIndex;
1885  SnapshotData SnapshotToast;
1886 
1887  if (!VARATT_IS_EXTERNAL_ONDISK(attr))
1888  elog(ERROR, "toast_fetch_datum shouldn't be called for non-ondisk datums");
1889 
1890  /* Must copy to access aligned fields */
1891  VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
1892 
1893  ressize = toast_pointer.va_extsize;
1894  numchunks = ((ressize - 1) / TOAST_MAX_CHUNK_SIZE) + 1;
1895 
1896  result = (struct varlena *) palloc(ressize + VARHDRSZ);
1897 
1898  if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer))
1899  SET_VARSIZE_COMPRESSED(result, ressize + VARHDRSZ);
1900  else
1901  SET_VARSIZE(result, ressize + VARHDRSZ);
1902 
1903  /*
1904  * Open the toast relation and its indexes
1905  */
1906  toastrel = table_open(toast_pointer.va_toastrelid, AccessShareLock);
1907  toasttupDesc = toastrel->rd_att;
1908 
1909  /* Look for the valid index of the toast relation */
1910  validIndex = toast_open_indexes(toastrel,
1912  &toastidxs,
1913  &num_indexes);
1914 
1915  /*
1916  * Setup a scan key to fetch from the index by va_valueid
1917  */
1918  ScanKeyInit(&toastkey,
1919  (AttrNumber) 1,
1920  BTEqualStrategyNumber, F_OIDEQ,
1921  ObjectIdGetDatum(toast_pointer.va_valueid));
1922 
1923  /*
1924  * Read the chunks by index
1925  *
1926  * Note that because the index is actually on (valueid, chunkidx) we will
1927  * see the chunks in chunkidx order, even though we didn't explicitly ask
1928  * for it.
1929  */
1930  nextidx = 0;
1931 
1932  init_toast_snapshot(&SnapshotToast);
1933  toastscan = systable_beginscan_ordered(toastrel, toastidxs[validIndex],
1934  &SnapshotToast, 1, &toastkey);
1935  while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
1936  {
1937  /*
1938  * Have a chunk, extract the sequence number and the data
1939  */
1940  residx = DatumGetInt32(fastgetattr(ttup, 2, toasttupDesc, &isnull));
1941  Assert(!isnull);
1942  chunk = DatumGetPointer(fastgetattr(ttup, 3, toasttupDesc, &isnull));
1943  Assert(!isnull);
1944  if (!VARATT_IS_EXTENDED(chunk))
1945  {
1946  chunksize = VARSIZE(chunk) - VARHDRSZ;
1947  chunkdata = VARDATA(chunk);
1948  }
1949  else if (VARATT_IS_SHORT(chunk))
1950  {
1951  /* could happen due to heap_form_tuple doing its thing */
1952  chunksize = VARSIZE_SHORT(chunk) - VARHDRSZ_SHORT;
1953  chunkdata = VARDATA_SHORT(chunk);
1954  }
1955  else
1956  {
1957  /* should never happen */
1958  elog(ERROR, "found toasted toast chunk for toast value %u in %s",
1959  toast_pointer.va_valueid,
1960  RelationGetRelationName(toastrel));
1961  chunksize = 0; /* keep compiler quiet */
1962  chunkdata = NULL;
1963  }
1964 
1965  /*
1966  * Some checks on the data we've found
1967  */
1968  if (residx != nextidx)
1969  ereport(ERROR,
1971  errmsg_internal("unexpected chunk number %d (expected %d) for toast value %u in %s",
1972  residx, nextidx,
1973  toast_pointer.va_valueid,
1974  RelationGetRelationName(toastrel))));
1975  if (residx < numchunks - 1)
1976  {
1977  if (chunksize != TOAST_MAX_CHUNK_SIZE)
1978  ereport(ERROR,
1980  errmsg_internal("unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s",
1981  chunksize, (int) TOAST_MAX_CHUNK_SIZE,
1982  residx, numchunks,
1983  toast_pointer.va_valueid,
1984  RelationGetRelationName(toastrel))));
1985  }
1986  else if (residx == numchunks - 1)
1987  {
1988  if ((residx * TOAST_MAX_CHUNK_SIZE + chunksize) != ressize)
1989  ereport(ERROR,
1991  errmsg_internal("unexpected chunk size %d (expected %d) in final chunk %d for toast value %u in %s",
1992  chunksize,
1993  (int) (ressize - residx * TOAST_MAX_CHUNK_SIZE),
1994  residx,
1995  toast_pointer.va_valueid,
1996  RelationGetRelationName(toastrel))));
1997  }
1998  else
1999  ereport(ERROR,
2001  errmsg_internal("unexpected chunk number %d (out of range %d..%d) for toast value %u in %s",
2002  residx,
2003  0, numchunks - 1,
2004  toast_pointer.va_valueid,
2005  RelationGetRelationName(toastrel))));
2006 
2007  /*
2008  * Copy the data into proper place in our result
2009  */
2010  memcpy(VARDATA(result) + residx * TOAST_MAX_CHUNK_SIZE,
2011  chunkdata,
2012  chunksize);
2013 
2014  nextidx++;
2015  }
2016 
2017  /*
2018  * Final checks that we successfully fetched the datum
2019  */
2020  if (nextidx != numchunks)
2021  ereport(ERROR,
2023  errmsg_internal("missing chunk number %d for toast value %u in %s",
2024  nextidx,
2025  toast_pointer.va_valueid,
2026  RelationGetRelationName(toastrel))));
2027 
2028  /*
2029  * End scan and close relations
2030  */
2031  systable_endscan_ordered(toastscan);
2032  toast_close_indexes(toastidxs, num_indexes, AccessShareLock);
2033  table_close(toastrel, AccessShareLock);
2034 
2035  return result;
2036 }
#define VARATT_IS_EXTERNAL_ONDISK(PTR)
Definition: postgres.h:314
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define VARDATA(PTR)
Definition: postgres.h:302
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:712
static int toast_open_indexes(Relation toastrel, LOCKMODE lock, Relation **toastidxs, int *num_indexes)
Definition: tuptoaster.c:2335
#define DatumGetInt32(X)
Definition: postgres.h:472
#define VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer)
Definition: tuptoaster.h:111
#define VARHDRSZ_SHORT
Definition: postgres.h:268
#define VARSIZE(PTR)
Definition: postgres.h:303
#define VARHDRSZ
Definition: c.h:555
static void init_toast_snapshot(Snapshot toast_snapshot)
Definition: tuptoaster.c:2413
static void toast_close_indexes(Relation *toastidxs, int num_indexes, LOCKMODE lock)
Definition: tuptoaster.c:2394
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:570
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
Definition: genam.c:630
signed int int32
Definition: c.h:346
char * Pointer
Definition: c.h:335
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define VARATT_IS_SHORT(PTR)
Definition: postgres.h:326
#define RelationGetRelationName(relation)
Definition: rel.h:450
#define ereport(elevel, rest)
Definition: elog.h:141
#define VARSIZE_SHORT(PTR)
Definition: postgres.h:305
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:44
#define TOAST_MAX_CHUNK_SIZE
Definition: tuptoaster.h:91
void systable_endscan_ordered(SysScanDesc sysscan)
Definition: genam.c:649
TupleDesc rd_att
Definition: rel.h:84
int errmsg_internal(const char *fmt,...)
Definition: elog.c:814
#define Assert(condition)
Definition: c.h:732
#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr)
Definition: tuptoaster.h:121
#define VARATT_IS_EXTENDED(PTR)
Definition: postgres.h:327
#define DatumGetPointer(X)
Definition: postgres.h:549
#define VARDATA_SHORT(PTR)
Definition: postgres.h:306
void * palloc(Size size)
Definition: mcxt.c:924
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:565
#define elog(elevel,...)
Definition: elog.h:226
#define SET_VARSIZE_COMPRESSED(PTR, len)
Definition: postgres.h:331
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Definition: c.h:549
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
int16 AttrNumber
Definition: attnum.h:21
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ toast_fetch_datum_slice()

static struct varlena * toast_fetch_datum_slice ( struct varlena attr,
int32  sliceoffset,
int32  length 
)
static

Definition at line 2048 of file tuptoaster.c.

References AccessShareLock, Assert, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTLessEqualStrategyNumber, DatumGetInt32, DatumGetPointer, elog, ERROR, fastgetattr, ForwardScanDirection, init_toast_snapshot(), Int32GetDatum, ObjectIdGetDatum, palloc(), RelationData::rd_att, RelationGetRelationName, ScanKeyInit(), SET_VARSIZE, systable_beginscan_ordered(), systable_endscan_ordered(), systable_getnext_ordered(), table_close(), table_open(), toast_close_indexes(), TOAST_MAX_CHUNK_SIZE, toast_open_indexes(), varatt_external::va_extsize, varatt_external::va_toastrelid, varatt_external::va_valueid, VARATT_EXTERNAL_GET_POINTER, VARATT_EXTERNAL_IS_COMPRESSED, VARATT_IS_EXTENDED, VARATT_IS_EXTERNAL_ONDISK, VARATT_IS_SHORT, VARDATA, VARDATA_SHORT, VARHDRSZ, VARHDRSZ_SHORT, VARSIZE, and VARSIZE_SHORT.

Referenced by heap_tuple_untoast_attr_slice().

2049 {
2050  Relation toastrel;
2051  Relation *toastidxs;
2052  ScanKeyData toastkey[3];
2053  int nscankeys;
2054  SysScanDesc toastscan;
2055  HeapTuple ttup;
2056  TupleDesc toasttupDesc;
2057  struct varlena *result;
2058  struct varatt_external toast_pointer;
2059  int32 attrsize;
2060  int32 residx;
2061  int32 nextidx;
2062  int numchunks;
2063  int startchunk;
2064  int endchunk;
2065  int32 startoffset;
2066  int32 endoffset;
2067  int totalchunks;
2068  Pointer chunk;
2069  bool isnull;
2070  char *chunkdata;
2071  int32 chunksize;
2072  int32 chcpystrt;
2073  int32 chcpyend;
2074  int num_indexes;
2075  int validIndex;
2076  SnapshotData SnapshotToast;
2077 
2078  if (!VARATT_IS_EXTERNAL_ONDISK(attr))
2079  elog(ERROR, "toast_fetch_datum_slice shouldn't be called for non-ondisk datums");
2080 
2081  /* Must copy to access aligned fields */
2082  VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
2083 
2084  /*
2085  * It's nonsense to fetch slices of a compressed datum -- this isn't lo_*
2086  * we can't return a compressed datum which is meaningful to toast later
2087  */
2088  Assert(!VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer));
2089 
2090  attrsize = toast_pointer.va_extsize;
2091  totalchunks = ((attrsize - 1) / TOAST_MAX_CHUNK_SIZE) + 1;
2092 
2093  if (sliceoffset >= attrsize)
2094  {
2095  sliceoffset = 0;
2096  length = 0;
2097  }
2098 
2099  if (((sliceoffset + length) > attrsize) || length < 0)
2100  length = attrsize - sliceoffset;
2101 
2102  result = (struct varlena *) palloc(length + VARHDRSZ);
2103 
2104  SET_VARSIZE(result, length + VARHDRSZ);
2105 
2106  if (length == 0)
2107  return result; /* Can save a lot of work at this point! */
2108 
2109  startchunk = sliceoffset / TOAST_MAX_CHUNK_SIZE;
2110  endchunk = (sliceoffset + length - 1) / TOAST_MAX_CHUNK_SIZE;
2111  numchunks = (endchunk - startchunk) + 1;
2112 
2113  startoffset = sliceoffset % TOAST_MAX_CHUNK_SIZE;
2114  endoffset = (sliceoffset + length - 1) % TOAST_MAX_CHUNK_SIZE;
2115 
2116  /*
2117  * Open the toast relation and its indexes
2118  */
2119  toastrel = table_open(toast_pointer.va_toastrelid, AccessShareLock);
2120  toasttupDesc = toastrel->rd_att;
2121 
2122  /* Look for the valid index of toast relation */
2123  validIndex = toast_open_indexes(toastrel,
2125  &toastidxs,
2126  &num_indexes);
2127 
2128  /*
2129  * Setup a scan key to fetch from the index. This is either two keys or
2130  * three depending on the number of chunks.
2131  */
2132  ScanKeyInit(&toastkey[0],
2133  (AttrNumber) 1,
2134  BTEqualStrategyNumber, F_OIDEQ,
2135  ObjectIdGetDatum(toast_pointer.va_valueid));
2136 
2137  /*
2138  * Use equality condition for one chunk, a range condition otherwise:
2139  */
2140  if (numchunks == 1)
2141  {
2142  ScanKeyInit(&toastkey[1],
2143  (AttrNumber) 2,
2144  BTEqualStrategyNumber, F_INT4EQ,
2145  Int32GetDatum(startchunk));
2146  nscankeys = 2;
2147  }
2148  else
2149  {
2150  ScanKeyInit(&toastkey[1],
2151  (AttrNumber) 2,
2152  BTGreaterEqualStrategyNumber, F_INT4GE,
2153  Int32GetDatum(startchunk));
2154  ScanKeyInit(&toastkey[2],
2155  (AttrNumber) 2,
2156  BTLessEqualStrategyNumber, F_INT4LE,
2157  Int32GetDatum(endchunk));
2158  nscankeys = 3;
2159  }
2160 
2161  /*
2162  * Read the chunks by index
2163  *
2164  * The index is on (valueid, chunkidx) so they will come in order
2165  */
2166  init_toast_snapshot(&SnapshotToast);
2167  nextidx = startchunk;
2168  toastscan = systable_beginscan_ordered(toastrel, toastidxs[validIndex],
2169  &SnapshotToast, nscankeys, toastkey);
2170  while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
2171  {
2172  /*
2173  * Have a chunk, extract the sequence number and the data
2174  */
2175  residx = DatumGetInt32(fastgetattr(ttup, 2, toasttupDesc, &isnull));
2176  Assert(!isnull);
2177  chunk = DatumGetPointer(fastgetattr(ttup, 3, toasttupDesc, &isnull));
2178  Assert(!isnull);
2179  if (!VARATT_IS_EXTENDED(chunk))
2180  {
2181  chunksize = VARSIZE(chunk) - VARHDRSZ;
2182  chunkdata = VARDATA(chunk);
2183  }
2184  else if (VARATT_IS_SHORT(chunk))
2185  {
2186  /* could happen due to heap_form_tuple doing its thing */
2187  chunksize = VARSIZE_SHORT(chunk) - VARHDRSZ_SHORT;
2188  chunkdata = VARDATA_SHORT(chunk);
2189  }
2190  else
2191  {
2192  /* should never happen */
2193  elog(ERROR, "found toasted toast chunk for toast value %u in %s",
2194  toast_pointer.va_valueid,
2195  RelationGetRelationName(toastrel));
2196  chunksize = 0; /* keep compiler quiet */
2197  chunkdata = NULL;
2198  }
2199 
2200  /*
2201  * Some checks on the data we've found
2202  */
2203  if ((residx != nextidx) || (residx > endchunk) || (residx < startchunk))
2204  elog(ERROR, "unexpected chunk number %d (expected %d) for toast value %u in %s",
2205  residx, nextidx,
2206  toast_pointer.va_valueid,
2207  RelationGetRelationName(toastrel));
2208  if (residx < totalchunks - 1)
2209  {
2210  if (chunksize != TOAST_MAX_CHUNK_SIZE)
2211  elog(ERROR, "unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s when fetching slice",
2212  chunksize, (int) TOAST_MAX_CHUNK_SIZE,
2213  residx, totalchunks,
2214  toast_pointer.va_valueid,
2215  RelationGetRelationName(toastrel));
2216  }
2217  else if (residx == totalchunks - 1)
2218  {
2219  if ((residx * TOAST_MAX_CHUNK_SIZE + chunksize) != attrsize)
2220  elog(ERROR, "unexpected chunk size %d (expected %d) in final chunk %d for toast value %u in %s when fetching slice",
2221  chunksize,
2222  (int) (attrsize - residx * TOAST_MAX_CHUNK_SIZE),
2223  residx,
2224  toast_pointer.va_valueid,
2225  RelationGetRelationName(toastrel));
2226  }
2227  else
2228  elog(ERROR, "unexpected chunk number %d (out of range %d..%d) for toast value %u in %s",
2229  residx,
2230  0, totalchunks - 1,
2231  toast_pointer.va_valueid,
2232  RelationGetRelationName(toastrel));
2233 
2234  /*
2235  * Copy the data into proper place in our result
2236  */
2237  chcpystrt = 0;
2238  chcpyend = chunksize - 1;
2239  if (residx == startchunk)
2240  chcpystrt = startoffset;
2241  if (residx == endchunk)
2242  chcpyend = endoffset;
2243 
2244  memcpy(VARDATA(result) +
2245  (residx * TOAST_MAX_CHUNK_SIZE - sliceoffset) + chcpystrt,
2246  chunkdata + chcpystrt,
2247  (chcpyend - chcpystrt) + 1);
2248 
2249  nextidx++;
2250  }
2251 
2252  /*
2253  * Final checks that we successfully fetched the datum
2254  */
2255  if (nextidx != (endchunk + 1))
2256  elog(ERROR, "missing chunk number %d for toast value %u in %s",
2257  nextidx,
2258  toast_pointer.va_valueid,
2259  RelationGetRelationName(toastrel));
2260 
2261  /*
2262  * End scan and close relations
2263  */
2264  systable_endscan_ordered(toastscan);
2265  toast_close_indexes(toastidxs, num_indexes, AccessShareLock);
2266  table_close(toastrel, AccessShareLock);
2267 
2268  return result;
2269 }
#define VARATT_IS_EXTERNAL_ONDISK(PTR)
Definition: postgres.h:314
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define VARDATA(PTR)
Definition: postgres.h:302
#define fastgetattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:712
static int toast_open_indexes(Relation toastrel, LOCKMODE lock, Relation **toastidxs, int *num_indexes)
Definition: tuptoaster.c:2335
#define DatumGetInt32(X)
Definition: postgres.h:472
#define VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer)
Definition: tuptoaster.h:111
#define VARHDRSZ_SHORT
Definition: postgres.h:268
#define VARSIZE(PTR)
Definition: postgres.h:303
#define VARHDRSZ
Definition: c.h:555
static void init_toast_snapshot(Snapshot toast_snapshot)
Definition: tuptoaster.c:2413
static void toast_close_indexes(Relation *toastidxs, int num_indexes, LOCKMODE lock)
Definition: tuptoaster.c:2394
#define AccessShareLock
Definition: lockdefs.h:36
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
Definition: genam.c:630
signed int int32
Definition: c.h:346
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
char * Pointer
Definition: c.h:335
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define VARATT_IS_SHORT(PTR)
Definition: postgres.h:326
#define RelationGetRelationName(relation)
Definition: rel.h:450
#define VARSIZE_SHORT(PTR)
Definition: postgres.h:305
#define TOAST_MAX_CHUNK_SIZE
Definition: tuptoaster.h:91
void systable_endscan_ordered(SysScanDesc sysscan)
Definition: genam.c:649
TupleDesc rd_att
Definition: rel.h:84
#define Assert(condition)
Definition: c.h:732
#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr)
Definition: tuptoaster.h:121
#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
void * palloc(Size size)
Definition: mcxt.c:924
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:565
#define elog(elevel,...)
Definition: elog.h:226
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Definition: c.h:549
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
int16 AttrNumber
Definition: attnum.h:21
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32

◆ toast_flatten_tuple()

HeapTuple toast_flatten_tuple ( HeapTuple  tup,
TupleDesc  tupleDesc 
)

Definition at line 1083 of file tuptoaster.c.

References Assert, attlen, DatumGetPointer, HEAP2_XACT_MASK, heap_deform_tuple(), heap_form_tuple(), heap_tuple_fetch_attr(), 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().

1084 {
1085  HeapTuple new_tuple;
1086  int numAttrs = tupleDesc->natts;
1087  int i;
1088  Datum toast_values[MaxTupleAttributeNumber];
1089  bool toast_isnull[MaxTupleAttributeNumber];
1090  bool toast_free[MaxTupleAttributeNumber];
1091 
1092  /*
1093  * Break down the tuple into fields.
1094  */
1095  Assert(numAttrs <= MaxTupleAttributeNumber);
1096  heap_deform_tuple(tup, tupleDesc, toast_values, toast_isnull);
1097 
1098  memset(toast_free, 0, numAttrs * sizeof(bool));
1099 
1100  for (i = 0; i < numAttrs; i++)
1101  {
1102  /*
1103  * Look at non-null varlena attributes
1104  */
1105  if (!toast_isnull[i] && TupleDescAttr(tupleDesc, i)->attlen == -1)
1106  {
1107  struct varlena *new_value;
1108 
1109  new_value = (struct varlena *) DatumGetPointer(toast_values[i]);
1110  if (VARATT_IS_EXTERNAL(new_value))
1111  {
1112  new_value = heap_tuple_fetch_attr(new_value);
1113  toast_values[i] = PointerGetDatum(new_value);
1114  toast_free[i] = true;
1115  }
1116  }
1117  }
1118 
1119  /*
1120  * Form the reconfigured tuple.
1121  */
1122  new_tuple = heap_form_tuple(tupleDesc, toast_values, toast_isnull);
1123 
1124  /*
1125  * Be sure to copy the tuple's identity fields. We also make a point of
1126  * copying visibility info, just in case anybody looks at those fields in
1127  * a syscache entry.
1128  */
1129  new_tuple->t_self = tup->t_self;
1130  new_tuple->t_tableOid = tup->t_tableOid;
1131 
1132  new_tuple->t_data->t_choice = tup->t_data->t_choice;
1133  new_tuple->t_data->t_ctid = tup->t_data->t_ctid;
1134  new_tuple->t_data->t_infomask &= ~HEAP_XACT_MASK;
1135  new_tuple->t_data->t_infomask |=
1137  new_tuple->t_data->t_infomask2 &= ~HEAP2_XACT_MASK;
1138  new_tuple->t_data->t_infomask2 |=
1140 
1141  /*
1142  * Free allocated temp values
1143  */
1144  for (i = 0; i < numAttrs; i++)
1145  if (toast_free[i])
1146  pfree(DatumGetPointer(toast_values[i]));
1147 
1148  return new_tuple;
1149 }
union HeapTupleHeaderData::@45 t_choice
#define MaxTupleAttributeNumber
Definition: htup_details.h:33
#define PointerGetDatum(X)
Definition: postgres.h:556
struct varlena * heap_tuple_fetch_attr(struct varlena *attr)
Definition: tuptoaster.c:101
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#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:1031
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 1182 of file tuptoaster.c.

References Assert, attlen, BITMAPLEN, DatumGetPointer, heap_compute_data_size(), heap_deform_tuple(), heap_fill_tuple(), heap_tuple_untoast_attr(), 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().

1185 {
1186  HeapTupleHeader new_data;
1187  int32 new_header_len;
1188  int32 new_data_len;
1189  int32 new_tuple_len;
1190  HeapTupleData tmptup;
1191  int numAttrs = tupleDesc->natts;
1192  int i;
1193  bool has_nulls = false;
1194  Datum toast_values[MaxTupleAttributeNumber];
1195  bool toast_isnull[MaxTupleAttributeNumber];
1196  bool toast_free[MaxTupleAttributeNumber];
1197 
1198  /* Build a temporary HeapTuple control structure */
1199  tmptup.t_len = tup_len;
1200  ItemPointerSetInvalid(&(tmptup.t_self));
1201  tmptup.t_tableOid = InvalidOid;
1202  tmptup.t_data = tup;
1203 
1204  /*
1205  * Break down the tuple into fields.
1206  */
1207  Assert(numAttrs <= MaxTupleAttributeNumber);
1208  heap_deform_tuple(&tmptup, tupleDesc, toast_values, toast_isnull);
1209 
1210  memset(toast_free, 0, numAttrs * sizeof(bool));
1211 
1212  for (i = 0; i < numAttrs; i++)
1213  {
1214  /*
1215  * Look at non-null varlena attributes
1216  */
1217  if (toast_isnull[i])
1218  has_nulls = true;
1219  else if (TupleDescAttr(tupleDesc, i)->attlen == -1)
1220  {
1221  struct varlena *new_value;
1222 
1223  new_value = (struct varlena *) DatumGetPointer(toast_values[i]);
1224  if (VARATT_IS_EXTERNAL(new_value) ||
1225  VARATT_IS_COMPRESSED(new_value))
1226  {
1227  new_value = heap_tuple_untoast_attr(new_value);
1228  toast_values[i] = PointerGetDatum(new_value);
1229  toast_free[i] = true;
1230  }
1231  }
1232  }
1233 
1234  /*
1235  * Calculate the new size of the tuple.
1236  *
1237  * This should match the reconstruction code in toast_insert_or_update.
1238  */
1239  new_header_len = SizeofHeapTupleHeader;
1240  if (has_nulls)
1241  new_header_len += BITMAPLEN(numAttrs);
1242  new_header_len = MAXALIGN(new_header_len);
1243  new_data_len = heap_compute_data_size(tupleDesc,
1244  toast_values, toast_isnull);
1245  new_tuple_len = new_header_len + new_data_len;
1246 
1247  new_data = (HeapTupleHeader) palloc0(new_tuple_len);
1248 
1249  /*
1250  * Copy the existing tuple header, but adjust natts and t_hoff.
1251  */
1252  memcpy(new_data, tup, SizeofHeapTupleHeader);
1253  HeapTupleHeaderSetNatts(new_data, numAttrs);
1254  new_data->t_hoff = new_header_len;
1255 
1256  /* Set the composite-Datum header fields correctly */
1257  HeapTupleHeaderSetDatumLength(new_data, new_tuple_len);
1258  HeapTupleHeaderSetTypeId(new_data, tupleDesc->tdtypeid);
1259  HeapTupleHeaderSetTypMod(new_data, tupleDesc->tdtypmod);
1260 
1261  /* Copy over the data, and fill the null bitmap if needed */
1262  heap_fill_tuple(tupleDesc,
1263  toast_values,
1264  toast_isnull,
1265  (char *) new_data + new_header_len,
1266  new_data_len,
1267  &(new_data->t_infomask),
1268  has_nulls ? new_data->t_bits : NULL);
1269 
1270  /*
1271  * Free allocated temp values
1272  */
1273  for (i = 0; i < numAttrs; i++)
1274  if (toast_free[i])
1275  pfree(DatumGetPointer(toast_values[i]));
1276 
1277  return PointerGetDatum(new_data);
1278 }
#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
struct varlena * heap_tuple_untoast_attr(struct varlena *attr)
Definition: tuptoaster.c:172
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
void pfree(void *pointer)
Definition: mcxt.c:1031
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:955
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

◆ toast_get_valid_index()

Oid toast_get_valid_index ( Oid  toastoid,
LOCKMODE  lock 
)

Definition at line 1420 of file tuptoaster.c.

References RelationGetRelid, table_close(), table_open(), toast_close_indexes(), and toast_open_indexes().

Referenced by finish_heap_swap(), and swap_relation_files().

1421 {
1422  int num_indexes;
1423  int validIndex;
1424  Oid validIndexOid;
1425  Relation *toastidxs;
1426  Relation toastrel;
1427 
1428  /* Open the toast relation */
1429  toastrel = table_open(toastoid, lock);
1430 
1431  /* Look for the valid index of the toast relation */
1432  validIndex = toast_open_indexes(toastrel,
1433  lock,
1434  &toastidxs,
1435  &num_indexes);
1436  validIndexOid = RelationGetRelid(toastidxs[validIndex]);
1437 
1438  /* Close the toast relation and all its indexes */
1439  toast_close_indexes(toastidxs, num_indexes, lock);
1440  table_close(toastrel, lock);
1441 
1442  return validIndexOid;
1443 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
static int toast_open_indexes(Relation toastrel, LOCKMODE lock, Relation **toastidxs, int *num_indexes)
Definition: tuptoaster.c:2335
static void toast_close_indexes(Relation *toastidxs, int num_indexes, LOCKMODE lock)
Definition: tuptoaster.c:2394
unsigned int Oid
Definition: postgres_ext.h:31
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:416

◆ toast_insert_or_update()

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

Definition at line 538 of file tuptoaster.c.

References Assert, attstorage, BITMAPLEN, DatumGetPointer, heap_compute_data_size(), heap_deform_tuple(), heap_fill_tuple(), HEAP_INSERT_SPECULATIVE, heap_tuple_fetch_attr(), heap_tuple_untoast_attr(), HeapTupleHeaderSetNatts, HEAPTUPLESIZE, i, InvalidOid, MAXALIGN, MaxHeapAttributeNumber, TupleDescData::natts, palloc0(), pfree(), PointerGetDatum, 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, toast_compress_datum(), toast_delete_datum(), TOAST_POINTER_SIZE, toast_save_datum(), TOAST_TUPLE_TARGET, TOAST_TUPLE_TARGET_MAIN, TupleDescAttr, VARATT_IS_COMPRESSED, VARATT_IS_EXTERNAL, VARATT_IS_EXTERNAL_ONDISK, VARSIZE, VARSIZE_ANY, and VARSIZE_EXTERNAL.

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

540 {
541  HeapTuple result_tuple;
542  TupleDesc tupleDesc;
543  int numAttrs;
544  int i;
545 
546  bool need_change = false;
547  bool need_free = false;
548  bool need_delold = false;
549  bool has_nulls = false;
550 
551  Size maxDataLen;
552  Size hoff;
553 
554  char toast_action[MaxHeapAttributeNumber];
555  bool toast_isnull[MaxHeapAttributeNumber];
556  bool toast_oldisnull[MaxHeapAttributeNumber];
557  Datum toast_values[MaxHeapAttributeNumber];
558  Datum toast_oldvalues[MaxHeapAttributeNumber];
559  struct varlena *toast_oldexternal[MaxHeapAttributeNumber];
560  int32 toast_sizes[MaxHeapAttributeNumber];
561  bool toast_free[MaxHeapAttributeNumber];
562  bool toast_delold[MaxHeapAttributeNumber];
563 
564  /*
565  * Ignore the INSERT_SPECULATIVE option. Speculative insertions/super
566  * deletions just normally insert/delete the toast values. It seems
567  * easiest to deal with that here, instead on, potentially, multiple
568  * callers.
569  */
571 
572  /*
573  * We should only ever be called for tuples of plain relations or
574  * materialized views --- recursing on a toast rel is bad news.
575  */
576  Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
577  rel->rd_rel->relkind == RELKIND_MATVIEW);
578 
579  /*
580  * Get the tuple descriptor and break down the tuple(s) into fields.
581  */
582  tupleDesc = rel->rd_att;
583  numAttrs = tupleDesc->natts;
584 
585  Assert(numAttrs <= MaxHeapAttributeNumber);
586  heap_deform_tuple(newtup, tupleDesc, toast_values, toast_isnull);
587  if (oldtup != NULL)
588  heap_deform_tuple(oldtup, tupleDesc, toast_oldvalues, toast_oldisnull);
589 
590  /* ----------
591  * Then collect information about the values given
592  *
593  * NOTE: toast_action[i] can have these values:
594  * ' ' default handling
595  * 'p' already processed --- don't touch it
596  * 'x' incompressible, but OK to move off
597  *
598  * NOTE: toast_sizes[i] is only made valid for varlena attributes with
599  * toast_action[i] different from 'p'.
600  * ----------
601  */
602  memset(toast_action, ' ', numAttrs * sizeof(char));
603  memset(toast_oldexternal, 0, numAttrs * sizeof(struct varlena *));
604  memset(toast_free, 0, numAttrs * sizeof(bool));
605  memset(toast_delold, 0, numAttrs * sizeof(bool));
606 
607  for (i = 0; i < numAttrs; i++)
608  {
609  Form_pg_attribute att = TupleDescAttr(tupleDesc, i);
610  struct varlena *old_value;
611  struct varlena *new_value;
612 
613  if (oldtup != NULL)
614  {
615  /*
616  * For UPDATE get the old and new values of this attribute
617  */
618  old_value = (struct varlena *) DatumGetPointer(toast_oldvalues[i]);
619  new_value = (struct varlena *) DatumGetPointer(toast_values[i]);
620 
621  /*
622  * If the old value is stored on disk, check if it has changed so
623  * we have to delete it later.
624  */
625  if (att->attlen == -1 && !toast_oldisnull[i] &&
626  VARATT_IS_EXTERNAL_ONDISK(old_value))
627  {
628  if (toast_isnull[i] || !VARATT_IS_EXTERNAL_ONDISK(new_value) ||
629  memcmp((char *) old_value, (char *) new_value,
630  VARSIZE_EXTERNAL(old_value)) != 0)
631  {
632  /*
633  * The old external stored value isn't needed any more
634  * after the update
635  */
636  toast_delold[i] = true;
637  need_delold = true;
638  }
639  else
640  {
641  /*
642  * This attribute isn't changed by this update so we reuse
643  * the original reference to the old value in the new
644  * tuple.
645  */
646  toast_action[i] = 'p';
647  continue;
648  }
649  }
650  }
651  else
652  {
653  /*
654  * For INSERT simply get the new value
655  */
656  new_value = (struct varlena *) DatumGetPointer(toast_values[i]);
657  }
658 
659  /*
660  * Handle NULL attributes
661  */
662  if (toast_isnull[i])
663  {
664  toast_action[i] = 'p';
665  has_nulls = true;
666  continue;
667  }
668 
669  /*
670  * Now look at varlena attributes
671  */
672  if (att->attlen == -1)
673  {
674  /*
675  * If the table's attribute says PLAIN always, force it so.
676  */
677  if (att->attstorage == 'p')
678  toast_action[i] = 'p';
679 
680  /*
681  * We took care of UPDATE above, so any external value we find
682  * still in the tuple must be someone else's that we cannot reuse
683  * (this includes the case of an out-of-line in-memory datum).
684  * Fetch it back (without decompression, unless we are forcing
685  * PLAIN storage). If necessary, we'll push it out as a new
686  * external value below.
687  */
688  if (VARATT_IS_EXTERNAL(new_value))
689  {
690  toast_oldexternal[i] = new_value;
691  if (att->attstorage == 'p')
692  new_value = heap_tuple_untoast_attr(new_value);
693  else
694  new_value = heap_tuple_fetch_attr(new_value);
695  toast_values[i] = PointerGetDatum(new_value);
696  toast_free[i] = true;
697  need_change = true;
698  need_free = true;
699  }
700 
701  /*
702  * Remember the size of this attribute
703  */
704  toast_sizes[i] = VARSIZE_ANY(new_value);
705  }
706  else
707  {
708  /*
709  * Not a varlena attribute, plain storage always
710  */
711  toast_action[i] = 'p';
712  }
713  }
714 
715  /* ----------
716  * Compress and/or save external until data fits into target length
717  *
718  * 1: Inline compress attributes with attstorage 'x', and store very
719  * large attributes with attstorage 'x' or 'e' external immediately
720  * 2: Store attributes with attstorage 'x' or 'e' external
721  * 3: Inline compress attributes with attstorage 'm'
722  * 4: Store attributes with attstorage 'm' external
723  * ----------
724  */
725 
726  /* compute header overhead --- this should match heap_form_tuple() */
727  hoff = SizeofHeapTupleHeader;
728  if (has_nulls)
729  hoff += BITMAPLEN(numAttrs);
730  hoff = MAXALIGN(hoff);
731  /* now convert to a limit on the tuple data size */
732  maxDataLen = RelationGetToastTupleTarget(rel, TOAST_TUPLE_TARGET) - hoff;
733 
734  /*
735  * Look for attributes with attstorage 'x' to compress. Also find large
736  * attributes with attstorage 'x' or 'e', and store them external.
737  */
738  while (heap_compute_data_size(tupleDesc,
739  toast_values, toast_isnull) > maxDataLen)
740  {
741  int biggest_attno = -1;
742  int32 biggest_size = MAXALIGN(TOAST_POINTER_SIZE);
743  Datum old_value;
744  Datum new_value;
745 
746  /*
747  * Search for the biggest yet unprocessed internal attribute
748  */
749  for (i = 0; i < numAttrs; i++)
750  {
751  Form_pg_attribute att = TupleDescAttr(tupleDesc, i);
752 
753  if (toast_action[i] != ' ')
754  continue;
755  if (VARATT_IS_EXTERNAL(DatumGetPointer(toast_values[i])))
756  continue; /* can't happen, toast_action would be 'p' */
757  if (VARATT_IS_COMPRESSED(DatumGetPointer(toast_values[i])))
758  continue;
759  if (att->attstorage != 'x' && att->attstorage != 'e')
760  continue;
761  if (toast_sizes[i] > biggest_size)
762  {
763  biggest_attno = i;
764  biggest_size = toast_sizes[i];
765  }
766  }
767 
768  if (biggest_attno < 0)
769  break;
770 
771  /*
772  * Attempt to compress it inline, if it has attstorage 'x'
773  */
774  i = biggest_attno;
775  if (TupleDescAttr(tupleDesc, i)->attstorage == 'x')
776  {
777  old_value = toast_values[i];
778  new_value = toast_compress_datum(old_value);
779 
780  if (DatumGetPointer(new_value) != NULL)
781  {
782  /* successful compression */
783  if (toast_free[i])
784  pfree(DatumGetPointer(old_value));
785  toast_values[i] = new_value;
786  toast_free[i] = true;
787  toast_sizes[i] = VARSIZE(DatumGetPointer(toast_values[i]));
788  need_change = true;
789  need_free = true;
790  }
791  else
792  {
793  /* incompressible, ignore on subsequent compression passes */
794  toast_action[i] = 'x';
795  }
796  }
797  else
798  {
799  /* has attstorage 'e', ignore on subsequent compression passes */
800  toast_action[i] = 'x';
801  }
802 
803  /*
804  * If this value is by itself more than maxDataLen (after compression
805  * if any), push it out to the toast table immediately, if possible.
806  * This avoids uselessly compressing other fields in the common case
807  * where we have one long field and several short ones.
808  *
809  * XXX maybe the threshold should be less than maxDataLen?
810  */
811  if (toast_sizes[i] > maxDataLen &&
812  rel->rd_rel->reltoastrelid != InvalidOid)
813  {
814  old_value = toast_values[i];
815  toast_action[i] = 'p';
816  toast_values[i] = toast_save_datum(rel, toast_values[i],
817  toast_oldexternal[i], options);
818  if (toast_free[i])
819  pfree(DatumGetPointer(old_value));
820  toast_free[i] = true;
821  need_change = true;
822  need_free = true;
823  }
824  }
825 
826  /*
827  * Second we look for attributes of attstorage 'x' or 'e' that are still
828  * inline. But skip this if there's no toast table to push them to.
829  */
830  while (heap_compute_data_size(tupleDesc,
831  toast_values, toast_isnull) > maxDataLen &&
832  rel->rd_rel->reltoastrelid != InvalidOid)
833  {
834  int biggest_attno = -1;
835  int32 biggest_size = MAXALIGN(TOAST_POINTER_SIZE);
836  Datum old_value;
837 
838  /*------
839  * Search for the biggest yet inlined attribute with
840  * attstorage equals 'x' or 'e'
841  *------
842  */
843  for (i = 0; i < numAttrs; i++)
844  {
845  Form_pg_attribute att = TupleDescAttr(tupleDesc, i);
846 
847  if (toast_action[i] == 'p')
848  continue;
849  if (VARATT_IS_EXTERNAL(DatumGetPointer(toast_values[i])))
850  continue; /* can't happen, toast_action would be 'p' */
851  if (att->attstorage != 'x' && att->attstorage != 'e')
852  continue;
853  if (toast_sizes[i] > biggest_size)
854  {
855  biggest_attno = i;
856  biggest_size = toast_sizes[i];
857  }
858  }
859 
860  if (biggest_attno < 0)
861  break;
862 
863  /*
864  * Store this external
865  */
866  i = biggest_attno;
867  old_value = toast_values[i];
868  toast_action[i] = 'p';
869  toast_values[i] = toast_save_datum(rel, toast_values[i],
870  toast_oldexternal[i], options);
871  if (toast_free[i])
872  pfree(DatumGetPointer(old_value));
873  toast_free[i] = true;
874 
875  need_change = true;
876  need_free = true;
877  }
878 
879  /*
880  * Round 3 - this time we take attributes with storage 'm' into
881  * compression
882  */
883  while (heap_compute_data_size(tupleDesc,
884  toast_values, toast_isnull) > maxDataLen)
885  {
886  int biggest_attno = -1;
887  int32 biggest_size = MAXALIGN(TOAST_POINTER_SIZE);
888  Datum old_value;
889  Datum new_value;
890 
891  /*
892  * Search for the biggest yet uncompressed internal attribute
893  */
894  for (i = 0; i < numAttrs; i++)
895  {
896  if (toast_action[i] != ' ')
897  continue;
898  if (VARATT_IS_EXTERNAL(DatumGetPointer(toast_values[i])))
899  continue; /* can't happen, toast_action would be 'p' */
900  if (VARATT_IS_COMPRESSED(DatumGetPointer(toast_values[i])))
901  continue;
902  if (TupleDescAttr(tupleDesc, i)->attstorage != 'm')
903  continue;
904  if (toast_sizes[i] > biggest_size)
905  {
906  biggest_attno = i;
907  biggest_size = toast_sizes[i];
908  }
909  }
910 
911  if (biggest_attno < 0)
912  break;
913 
914  /*
915  * Attempt to compress it inline
916  */
917  i = biggest_attno;
918  old_value = toast_values[i];
919  new_value = toast_compress_datum(old_value);
920 
921  if (DatumGetPointer(new_value) != NULL)
922  {
923  /* successful compression */
924  if (toast_free[i])
925  pfree(DatumGetPointer(old_value));
926  toast_values[i] = new_value;
927  toast_free[i] = true;
928  toast_sizes[i] = VARSIZE(DatumGetPointer(toast_values[i]));
929  need_change = true;
930  need_free = true;
931  }
932  else
933  {
934  /* incompressible, ignore on subsequent compression passes */
935  toast_action[i] = 'x';
936  }
937  }
938 
939  /*
940  * Finally we store attributes of type 'm' externally. At this point we
941  * increase the target tuple size, so that 'm' attributes aren't stored
942  * externally unless really necessary.
943  */
944  maxDataLen = TOAST_TUPLE_TARGET_MAIN - hoff;
945 
946  while (heap_compute_data_size(tupleDesc,
947  toast_values, toast_isnull) > maxDataLen &&
948  rel->rd_rel->reltoastrelid != InvalidOid)
949  {
950  int biggest_attno = -1;
951  int32 biggest_size = MAXALIGN(TOAST_POINTER_SIZE);
952  Datum old_value;
953 
954  /*--------
955  * Search for the biggest yet inlined attribute with
956  * attstorage = 'm'
957  *--------
958  */
959  for (i = 0; i < numAttrs; i++)
960  {
961  if (toast_action[i] == 'p')
962  continue;
963  if (VARATT_IS_EXTERNAL(DatumGetPointer(toast_values[i])))
964  continue; /* can't happen, toast_action would be 'p' */
965  if (TupleDescAttr(tupleDesc, i)->attstorage != 'm')
966  continue;
967  if (toast_sizes[i] > biggest_size)
968  {
969  biggest_attno = i;
970  biggest_size = toast_sizes[i];
971  }
972  }
973 
974  if (biggest_attno < 0)
975  break;
976 
977  /*
978  * Store this external
979  */
980  i = biggest_attno;
981  old_value = toast_values[i];
982  toast_action[i] = 'p';
983  toast_values[i] = toast_save_datum(rel, toast_values[i],
984  toast_oldexternal[i], options);
985  if (toast_free[i])
986  pfree(DatumGetPointer(old_value));
987  toast_free[i] = true;
988 
989  need_change = true;
990  need_free = true;
991  }
992 
993  /*
994  * In the case we toasted any values, we need to build a new heap tuple
995  * with the changed values.
996  */
997  if (need_change)
998  {
999  HeapTupleHeader olddata = newtup->t_data;
1000  HeapTupleHeader new_data;
1001  int32 new_header_len;
1002  int32 new_data_len;
1003  int32 new_tuple_len;
1004 
1005  /*
1006  * Calculate the new size of the tuple.
1007  *
1008  * Note: we used to assume here that the old tuple's t_hoff must equal
1009  * the new_header_len value, but that was incorrect. The old tuple
1010  * might have a smaller-than-current natts, if there's been an ALTER
1011  * TABLE ADD COLUMN since it was stored; and that would lead to a
1012  * different conclusion about the size of the null bitmap, or even
1013  * whether there needs to be one at all.
1014  */
1015  new_header_len = SizeofHeapTupleHeader;
1016  if (has_nulls)
1017  new_header_len += BITMAPLEN(numAttrs);
1018  new_header_len = MAXALIGN(new_header_len);
1019  new_data_len = heap_compute_data_size(tupleDesc,
1020  toast_values, toast_isnull);
1021  new_tuple_len = new_header_len + new_data_len;
1022 
1023  /*
1024  * Allocate and zero the space needed, and fill HeapTupleData fields.
1025  */
1026  result_tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + new_tuple_len);
1027  result_tuple->t_len = new_tuple_len;
1028  result_tuple->t_self = newtup->t_self;
1029  result_tuple->t_tableOid = newtup->t_tableOid;
1030  new_data = (HeapTupleHeader) ((char *) result_tuple + HEAPTUPLESIZE);
1031  result_tuple->t_data = new_data;
1032 
1033  /*
1034  * Copy the existing tuple header, but adjust natts and t_hoff.
1035  */
1036  memcpy(new_data, olddata, SizeofHeapTupleHeader);
1037  HeapTupleHeaderSetNatts(new_data, numAttrs);
1038  new_data->t_hoff = new_header_len;
1039 
1040  /* Copy over the data, and fill the null bitmap if needed */
1041  heap_fill_tuple(tupleDesc,
1042  toast_values,
1043  toast_isnull,
1044  (char *) new_data + new_header_len,
1045  new_data_len,
1046  &(new_data->t_infomask),
1047  has_nulls ? new_data->t_bits : NULL);
1048  }
1049  else
1050  result_tuple = newtup;
1051 
1052  /*
1053  * Free allocated temp values
1054  */
1055  if (need_free)
1056  for (i = 0; i < numAttrs; i++)
1057  if (toast_free[i])
1058  pfree(DatumGetPointer(toast_values[i]));
1059 
1060  /*
1061  * Delete external values from the old tuple
1062  */
1063  if (need_delold)
1064  for (i = 0; i < numAttrs; i++)
1065  if (toast_delold[i])
1066  toast_delete_datum(rel, toast_oldvalues[i], false);
1067 
1068  return result_tuple;
1069 }
#define VARATT_IS_EXTERNAL_ONDISK(PTR)
Definition: postgres.h:314
#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
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 VARSIZE(PTR)
Definition: postgres.h:303
#define PointerGetDatum(X)
Definition: postgres.h:556
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
struct varlena * heap_tuple_fetch_attr(struct varlena *attr)
Definition: tuptoaster.c:101
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define TOAST_TUPLE_TARGET_MAIN
Definition: tuptoaster.h:68
#define BITMAPLEN(NATTS)
Definition: htup_details.h:547
static Datum toast_save_datum(Relation rel, Datum value, struct varlena *oldexternal, int options)
Definition: tuptoaster.c:1459
struct varlena * heap_tuple_untoast_attr(struct varlena *attr)
Definition: tuptoaster.c:172
Form_pg_class rd_rel
Definition: rel.h:83
#define HEAP_INSERT_SPECULATIVE
Definition: heapam.h:36
signed int int32
Definition: c.h:346
HeapTupleHeader t_data
Definition: htup.h:68
#define VARATT_IS_EXTERNAL(PTR)
Definition: postgres.h:313
void pfree(void *pointer)
Definition: mcxt.c:1031
Datum toast_compress_datum(Datum value)
Definition: tuptoaster.c:1362
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
Oid t_tableOid
Definition: htup.h:66
void * palloc0(Size size)
Definition: mcxt.c:955
#define TOAST_POINTER_SIZE
Definition: tuptoaster.h:99
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:84
#define VARSIZE_ANY(PTR)
Definition: postgres.h:335
#define InvalidOid
Definition: postgres_ext.h:36
#define MaxHeapAttributeNumber
Definition: htup_details.h:47
#define Assert(condition)
Definition: c.h:732
#define HeapTupleHeaderSetNatts(tup, natts)
Definition: htup_details.h:534
#define TOAST_TUPLE_TARGET
Definition: tuptoaster.h:57
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
#define DatumGetPointer(X)
Definition: postgres.h:549
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1249
static void toast_delete_datum(Relation rel, Datum value, bool is_speculative)
Definition: tuptoaster.c:1719
#define HEAPTUPLESIZE
Definition: htup.h:73
int i
Definition: c.h:549
#define VARSIZE_EXTERNAL(PTR)
Definition: postgres.h:309

◆ toast_open_indexes()

static int toast_open_indexes ( Relation  toastrel,
LOCKMODE  lock,
Relation **  toastidxs,
int *  num_indexes 
)
static

Definition at line 2335 of file tuptoaster.c.

References Assert, elog, ERROR, i, index_open(), lfirst_oid, list_free(), list_length(), NIL, palloc(), RelationData::rd_index, RelationGetIndexList(), and RelationGetRelid.

Referenced by toast_delete_datum(), toast_fetch_datum(), toast_fetch_datum_slice(), toast_get_valid_index(), toast_save_datum(), and toastrel_valueid_exists().

2339 {
2340  int i = 0;
2341  int res = 0;
2342  bool found = false;
2343  List *indexlist;
2344  ListCell *lc;
2345 
2346  /* Get index list of the toast relation */
2347  indexlist = RelationGetIndexList(toastrel);
2348  Assert(indexlist != NIL);
2349 
2350  *num_indexes = list_length(indexlist);
2351 
2352  /* Open all the index relations */
2353  *toastidxs = (Relation *) palloc(*num_indexes * sizeof(Relation));
2354  foreach(lc, indexlist)
2355  (*toastidxs)[i++] = index_open(lfirst_oid(lc), lock);
2356 
2357  /* Fetch the first valid index in list */
2358  for (i = 0; i < *num_indexes; i++)
2359  {
2360  Relation toastidx = (*toastidxs)[i];
2361 
2362  if (toastidx->rd_index->indisvalid)
2363  {
2364  res = i;
2365  found = true;
2366  break;
2367  }
2368  }
2369 
2370  /*
2371  * Free index list, not necessary anymore as relations are opened and a
2372  * valid index has been found.
2373  */
2374  list_free(indexlist);
2375 
2376  /*
2377  * The toast relation should have one valid index, so something is going
2378  * wrong if there is nothing.
2379  */
2380  if (!found)
2381  elog(ERROR, "no valid index found for toast relation with Oid %u",
2382  RelationGetRelid(toastrel));
2383 
2384  return res;
2385 }
#define NIL
Definition: pg_list.h:65
Form_pg_index rd_index
Definition: rel.h:143
#define ERROR
Definition: elog.h:43
#define Assert(condition)
Definition: c.h:732
static int list_length(const List *l)
Definition: pg_list.h:169
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4348
void * palloc(Size size)
Definition: mcxt.c:924
void list_free(List *list)
Definition: list.c:1373
#define elog(elevel,...)
Definition: elog.h:226
int i
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:416
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:126
#define lfirst_oid(lc)
Definition: pg_list.h:192

◆ toast_raw_datum_size()

Size toast_raw_datum_size ( Datum  value)

Definition at line 357 of file tuptoaster.c.

References Assert, DatumGetEOHP(), DatumGetPointer, EOH_get_flat_size(), varatt_indirect::pointer, PointerGetDatum, toast_raw_datum_size(), varatt_external::va_rawsize, VARATT_EXTERNAL_GET_POINTER, VARATT_IS_COMPRESSED, VARATT_IS_EXTERNAL_EXPANDED, VARATT_IS_EXTERNAL_INDIRECT, VARATT_IS_EXTERNAL_ONDISK, VARATT_IS_SHORT, VARHDRSZ, VARHDRSZ_SHORT, VARRAWSIZE_4B_C, VARSIZE, and VARSIZE_SHORT.

Referenced by bpcharoctetlen(), build_sorted_items(), byteaeq(), byteane(), byteaoctetlen(), compute_array_stats(), compute_distinct_stats(), compute_scalar_stats(), datum_image_eq(), record_image_cmp(), text_length(), text_starts_with(), texteq(), textne(), textoctetlen(), and toast_raw_datum_size().

358 {
359  struct varlena *attr = (struct varlena *) DatumGetPointer(value);
360  Size result;
361 
362  if (VARATT_IS_EXTERNAL_ONDISK(attr))
363  {
364  /* va_rawsize is the size of the original datum -- including header */
365  struct varatt_external toast_pointer;
366 
367  VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
368  result = toast_pointer.va_rawsize;
369  }
370  else if (VARATT_IS_EXTERNAL_INDIRECT(attr))
371  {
372  struct varatt_indirect toast_pointer;
373 
374  VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
375 
376  /* nested indirect Datums aren't allowed */
377  Assert(!VARATT_IS_EXTERNAL_INDIRECT(toast_pointer.pointer));
378 
379  return toast_raw_datum_size(PointerGetDatum(toast_pointer.pointer));
380  }
381  else if (VARATT_IS_EXTERNAL_EXPANDED(attr))
382  {
384  }
385  else if (VARATT_IS_COMPRESSED(attr))
386  {
387  /* here, va_rawsize is just the payload size */
388  result = VARRAWSIZE_4B_C(attr) + VARHDRSZ;
389  }
390  else if (VARATT_IS_SHORT(attr))
391  {
392  /*
393  * we have to normalize the header length to VARHDRSZ or else the
394  * callers of this function will be confused.
395  */
396  result = VARSIZE_SHORT(attr) - VARHDRSZ_SHORT + VARHDRSZ;
397  }
398  else
399  {
400  /* plain untoasted datum */
401  result = VARSIZE(attr);
402  }
403  return result;
404 }
#define VARATT_IS_EXTERNAL_ONDISK(PTR)
Definition: postgres.h:314
#define VARATT_IS_COMPRESSED(PTR)
Definition: postgres.h:312
#define VARATT_IS_EXTERNAL_EXPANDED(PTR)
Definition: postgres.h:322
#define VARHDRSZ_SHORT
Definition: postgres.h:268
#define VARSIZE(PTR)
Definition: postgres.h:303
#define PointerGetDatum(X)
Definition: postgres.h:556
#define VARHDRSZ
Definition: c.h:555
static struct @144 value
Size toast_raw_datum_size(Datum value)
Definition: tuptoaster.c:357
#define VARATT_IS_EXTERNAL_INDIRECT(PTR)
Definition: postgres.h:316
#define VARATT_IS_SHORT(PTR)
Definition: postgres.h:326
Size EOH_get_flat_size(ExpandedObjectHeader *eohptr)
Definition: expandeddatum.c:75
#define VARSIZE_SHORT(PTR)
Definition: postgres.h:305
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
#define VARRAWSIZE_4B_C(PTR)
Definition: postgres.h:283
#define Assert(condition)
Definition: c.h:732
#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr)
Definition: tuptoaster.h:121
size_t Size
Definition: c.h:466
#define DatumGetPointer(X)
Definition: postgres.h:549
Definition: c.h:549

◆ toast_save_datum()

static Datum toast_save_datum ( Relation  rel,
Datum  value,
struct varlena oldexternal,
int  options 
)
static

Definition at line 1459 of file tuptoaster.c.

References Assert, CHECK_FOR_INTERRUPTS, DatumGetPointer, GetCurrentCommandId(), GetNewOidWithIndex(), heap_form_tuple(), heap_freetuple(), heap_insert(), i, index_insert(), Int32GetDatum, InvalidOid, Min, ObjectIdGetDatum, OidIsValid, palloc(), PointerGetDatum, RelationData::rd_att, RelationData::rd_index, RelationData::rd_rel, RelationData::rd_toastoid, RelationGetRelid, RowExclusiveLock, SET_VARSIZE, SET_VARTAG_EXTERNAL, HeapTupleData::t_self, table_close(), table_open(), toast_close_indexes(), TOAST_MAX_CHUNK_SIZE, toast_open_indexes(), TOAST_POINTER_SIZE, toastid_valueid_exists(), toastrel_valueid_exists(), UNIQUE_CHECK_NO, UNIQUE_CHECK_YES, varatt_external::va_extsize, varatt_external::va_rawsize, varatt_external::va_toastrelid, varatt_external::va_valueid, VARATT_EXTERNAL_GET_POINTER, VARATT_EXTERNAL_IS_COMPRESSED, VARATT_IS_COMPRESSED, VARATT_IS_EXTERNAL, VARATT_IS_EXTERNAL_ONDISK, VARATT_IS_SHORT, VARDATA, VARDATA_EXTERNAL, VARDATA_SHORT, VARHDRSZ, VARHDRSZ_SHORT, VARRAWSIZE_4B_C, VARSIZE, VARSIZE_SHORT, and VARTAG_ONDISK.

Referenced by toast_insert_or_update().

1461 {
1462  Relation toastrel;
1463  Relation *toastidxs;
1464  HeapTuple toasttup;
1465  TupleDesc toasttupDesc;
1466  Datum t_values[3];
1467  bool t_isnull[3];
1468  CommandId mycid = GetCurrentCommandId(true);
1469  struct varlena *result;
1470  struct varatt_external toast_pointer;
1471  union
1472  {
1473  struct varlena hdr;
1474  /* this is to make the union big enough for a chunk: */
1475  char data[TOAST_MAX_CHUNK_SIZE + VARHDRSZ];
1476  /* ensure union is aligned well enough: */
1477  int32 align_it;
1478  } chunk_data;
1479  int32 chunk_size;
1480  int32 chunk_seq = 0;
1481  char *data_p;
1482  int32 data_todo;
1483  Pointer dval = DatumGetPointer(value);
1484  int num_indexes;
1485  int validIndex;
1486 
1488 
1489  /*
1490  * Open the toast relation and its indexes. We can use the index to check
1491  * uniqueness of the OID we assign to the toasted item, even though it has
1492  * additional columns besides OID.
1493  */
1494  toastrel = table_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
1495  toasttupDesc = toastrel->rd_att;
1496 
1497  /* Open all the toast indexes and look for the valid one */
1498  validIndex = toast_open_indexes(toastrel,
1500  &toastidxs,
1501  &num_indexes);
1502 
1503  /*
1504  * Get the data pointer and length, and compute va_rawsize and va_extsize.
1505  *
1506  * va_rawsize is the size of the equivalent fully uncompressed datum, so
1507  * we have to adjust for short headers.
1508  *
1509  * va_extsize is the actual size of the data payload in the toast records.
1510  */
1511  if (VARATT_IS_SHORT(dval))
1512  {
1513  data_p = VARDATA_SHORT(dval);
1514  data_todo = VARSIZE_SHORT(dval) - VARHDRSZ_SHORT;
1515  toast_pointer.va_rawsize = data_todo + VARHDRSZ; /* as if not short */
1516  toast_pointer.va_extsize = data_todo;
1517  }
1518  else if (VARATT_IS_COMPRESSED(dval))
1519  {
1520  data_p = VARDATA(dval);
1521  data_todo = VARSIZE(dval) - VARHDRSZ;
1522  /* rawsize in a compressed datum is just the size of the payload */
1523  toast_pointer.va_rawsize = VARRAWSIZE_4B_C(dval) + VARHDRSZ;
1524  toast_pointer.va_extsize = data_todo;
1525  /* Assert that the numbers look like it's compressed */
1526  Assert(VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer));
1527  }
1528  else
1529  {
1530  data_p = VARDATA(dval);
1531  data_todo = VARSIZE(dval) - VARHDRSZ;
1532  toast_pointer.va_rawsize = VARSIZE(dval);
1533  toast_pointer.va_extsize = data_todo;
1534  }
1535 
1536  /*
1537  * Insert the correct table OID into the result TOAST pointer.
1538  *
1539  * Normally this is the actual OID of the target toast table, but during
1540  * table-rewriting operations such as CLUSTER, we have to insert the OID
1541  * of the table's real permanent toast table instead. rd_toastoid is set
1542  * if we have to substitute such an OID.
1543  */
1544  if (OidIsValid(rel->rd_toastoid))
1545  toast_pointer.va_toastrelid = rel->rd_toastoid;
1546  else
1547  toast_pointer.va_toastrelid = RelationGetRelid(toastrel);
1548 
1549  /*
1550  * Choose an OID to use as the value ID for this toast value.
1551  *
1552  * Normally we just choose an unused OID within the toast table. But
1553  * during table-rewriting operations where we are preserving an existing
1554  * toast table OID, we want to preserve toast value OIDs too. So, if
1555  * rd_toastoid is set and we had a prior external value from that same
1556  * toast table, re-use its value ID. If we didn't have a prior external
1557  * value (which is a corner case, but possible if the table's attstorage
1558  * options have been changed), we have to pick a value ID that doesn't
1559  * conflict with either new or existing toast value OIDs.
1560  */
1561  if (!OidIsValid(rel->rd_toastoid))
1562  {
1563  /* normal case: just choose an unused OID */
1564  toast_pointer.va_valueid =
1565  GetNewOidWithIndex(toastrel,
1566  RelationGetRelid(toastidxs[validIndex]),
1567  (AttrNumber) 1);
1568  }
1569  else
1570  {
1571  /* rewrite case: check to see if value was in old toast table */
1572  toast_pointer.va_valueid = InvalidOid;
1573  if (oldexternal != NULL)
1574  {
1575  struct varatt_external old_toast_pointer;
1576 
1577  Assert(VARATT_IS_EXTERNAL_ONDISK(oldexternal));
1578  /* Must copy to access aligned fields */
1579  VARATT_EXTERNAL_GET_POINTER(old_toast_pointer, oldexternal);
1580  if (old_toast_pointer.va_toastrelid == rel->rd_toastoid)
1581  {
1582  /* This value came from the old toast table; reuse its OID */
1583  toast_pointer.va_valueid = old_toast_pointer.va_valueid;
1584 
1585  /*
1586  * There is a corner case here: the table rewrite might have
1587  * to copy both live and recently-dead versions of a row, and
1588  * those versions could easily reference the same toast value.
1589  * When we copy the second or later version of such a row,
1590  * reusing the OID will mean we select an OID that's already
1591  * in the new toast table. Check for that, and if so, just
1592  * fall through without writing the data again.
1593  *
1594  * While annoying and ugly-looking, this is a good thing
1595  * because it ensures that we wind up with only one copy of
1596  * the toast value when there is only one copy in the old
1597  * toast table. Before we detected this case, we'd have made
1598  * multiple copies, wasting space; and what's worse, the
1599  * copies belonging to already-deleted heap tuples would not
1600  * be reclaimed by VACUUM.
1601  */
1602  if (toastrel_valueid_exists(toastrel,
1603  toast_pointer.va_valueid))
1604  {
1605  /* Match, so short-circuit the data storage loop below */
1606  data_todo = 0;
1607  }
1608  }
1609  }
1610  if (toast_pointer.va_valueid == InvalidOid)
1611  {
1612  /*
1613  * new value; must choose an OID that doesn't conflict in either
1614  * old or new toast table
1615  */
1616  do
1617  {
1618  toast_pointer.va_valueid =
1619  GetNewOidWithIndex(toastrel,
1620  RelationGetRelid(toastidxs[validIndex]),
1621  (AttrNumber) 1);
1622  } while (toastid_valueid_exists(rel->rd_toastoid,
1623  toast_pointer.va_valueid));
1624  }
1625  }
1626 
1627  /*
1628  * Initialize constant parts of the tuple data
1629  */
1630  t_values[0] = ObjectIdGetDatum(toast_pointer.va_valueid);
1631  t_values[2] = PointerGetDatum(&chunk_data);
1632  t_isnull[0] = false;
1633  t_isnull[1] = false;
1634  t_isnull[2] = false;
1635 
1636  /*
1637  * Split up the item into chunks
1638  */
1639  while (data_todo > 0)
1640  {
1641  int i;
1642 
1644 
1645  /*
1646  * Calculate the size of this chunk
1647  */
1648  chunk_size = Min(TOAST_MAX_CHUNK_SIZE, data_todo);
1649 
1650  /*
1651  * Build a tuple and store it
1652  */
1653  t_values[1] = Int32GetDatum(chunk_seq++);
1654  SET_VARSIZE(&chunk_data, chunk_size + VARHDRSZ);
1655  memcpy(VARDATA(&chunk_data), data_p, chunk_size);
1656  toasttup = heap_form_tuple(toasttupDesc, t_values, t_isnull);
1657 
1658  heap_insert(toastrel, toasttup, mycid, options, NULL);
1659 
1660  /*
1661  * Create the index entry. We cheat a little here by not using
1662  * FormIndexDatum: this relies on the knowledge that the index columns
1663  * are the same as the initial columns of the table for all the
1664  * indexes. We also cheat by not providing an IndexInfo: this is okay
1665  * for now because btree doesn't need one, but we might have to be
1666  * more honest someday.
1667  *
1668  * Note also that there had better not be any user-created index on
1669  * the TOAST table, since we don't bother to update anything else.
1670  */
1671  for (i = 0; i < num_indexes; i++)
1672  {
1673  /* Only index relations marked as ready can be updated */
1674  if (toastidxs[i]->rd_index->indisready)
1675  index_insert(toastidxs[i], t_values, t_isnull,
1676  &(toasttup->t_self),
1677  toastrel,
1678  toastidxs[i]->rd_index->indisunique ?
1680  NULL);
1681  }
1682 
1683  /*
1684  * Free memory
1685  */
1686  heap_freetuple(toasttup);
1687 
1688  /*
1689  * Move on to next chunk
1690  */
1691  data_todo -= chunk_size;
1692  data_p += chunk_size;
1693  }
1694 
1695  /*
1696  * Done - close toast relation and its indexes
1697  */
1698  toast_close_indexes(toastidxs, num_indexes, RowExclusiveLock);
1699  table_close(toastrel, RowExclusiveLock);
1700 
1701  /*
1702  * Create the TOAST pointer value that we'll return
1703  */
1704  result = (struct varlena *) palloc(TOAST_POINTER_SIZE);
1706  memcpy(VARDATA_EXTERNAL(result), &toast_pointer, sizeof(toast_pointer));
1707 
1708  return PointerGetDatum(result);
1709 }
void heap_insert(Relation relation, HeapTuple tup, CommandId cid, int options, BulkInsertState bistate)
Definition: heapam.c:1868
uint32 CommandId
Definition: c.h:521
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:323
#define VARATT_IS_EXTERNAL_ONDISK(PTR)
Definition: postgres.h:314
#define VARATT_IS_COMPRESSED(PTR)
Definition: postgres.h:312
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define VARDATA(PTR)
Definition: postgres.h:302
static int toast_open_indexes(Relation toastrel, LOCKMODE lock, Relation **toastidxs, int *num_indexes)
Definition: tuptoaster.c:2335
#define VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer)
Definition: tuptoaster.h:111
#define VARHDRSZ_SHORT
Definition: postgres.h:268
#define VARSIZE(PTR)
Definition: postgres.h:303
#define PointerGetDatum(X)
Definition: postgres.h:556
#define VARHDRSZ
Definition: c.h:555
static bool toastrel_valueid_exists(Relation toastrel, Oid valueid)
Definition: tuptoaster.c:1794
#define Min(x, y)
Definition: c.h:904
static struct @144 value
static void toast_close_indexes(Relation *toastidxs, int num_indexes, LOCKMODE lock)
Definition: tuptoaster.c:2394
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
Form_pg_class rd_rel
Definition: rel.h:83
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define OidIsValid(objectId)
Definition: c.h:638
#define VARDATA_EXTERNAL(PTR)
Definition: postgres.h:310
signed int int32
Definition: c.h:346
#define VARATT_IS_EXTERNAL(PTR)
Definition: postgres.h:313
Form_pg_index rd_index
Definition: rel.h:143
char * Pointer
Definition: c.h:335
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define VARATT_IS_SHORT(PTR)
Definition: postgres.h:326
ItemPointerData t_self
Definition: htup.h:65
#define SET_VARTAG_EXTERNAL(PTR, tag)
Definition: postgres.h:333
Oid rd_toastoid
Definition: rel.h:201
#define RowExclusiveLock
Definition: lockdefs.h:38
#define VARSIZE_SHORT(PTR)
Definition: postgres.h:305
#define VARRAWSIZE_4B_C(PTR)
Definition: postgres.h:283
#define TOAST_MAX_CHUNK_SIZE
Definition: tuptoaster.h:91
#define TOAST_POINTER_SIZE
Definition: tuptoaster.h:99
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:84
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:732
#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr)
Definition: tuptoaster.h:121
static bool toastid_valueid_exists(Oid toastrelid, Oid valueid)
Definition: tuptoaster.c:1842
#define DatumGetPointer(X)
Definition: postgres.h:549
#define VARDATA_SHORT(PTR)
Definition: postgres.h:306
#define Int32GetDatum(X)
Definition: postgres.h:479
void * palloc(Size size)
Definition: mcxt.c:924
int i
Definition: c.h:549
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:746
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:416
bool index_insert(Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, IndexUniqueCheck checkUnique, IndexInfo *indexInfo)
Definition: indexam.c:170

◆ toastid_valueid_exists()

static bool toastid_valueid_exists ( Oid  toastrelid,
Oid  valueid 
)
static

Definition at line 1842 of file tuptoaster.c.

References AccessShareLock, table_close(), table_open(), and toastrel_valueid_exists().

Referenced by toast_save_datum().

1843 {
1844  bool result;
1845  Relation toastrel;
1846 
1847  toastrel = table_open(toastrelid, AccessShareLock);
1848 
1849  result = toastrel_valueid_exists(toastrel, valueid);
1850 
1851  table_close(toastrel, AccessShareLock);
1852 
1853  return result;
1854 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
static bool toastrel_valueid_exists(Relation toastrel, Oid valueid)
Definition: tuptoaster.c:1794
#define AccessShareLock
Definition: lockdefs.h:36
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

◆ toastrel_valueid_exists()

static bool toastrel_valueid_exists ( Relation  toastrel,
Oid  valueid 
)
static

Definition at line 1794 of file tuptoaster.c.

References BTEqualStrategyNumber, ObjectIdGetDatum, RelationGetRelid, RowExclusiveLock, ScanKeyInit(), SnapshotAny, systable_beginscan(), systable_endscan(), systable_getnext(), toast_close_indexes(), and toast_open_indexes().

Referenced by toast_save_datum(), and toastid_valueid_exists().

1795 {
1796  bool result = false;
1797  ScanKeyData toastkey;
1798  SysScanDesc toastscan;
1799  int num_indexes;
1800  int validIndex;
1801  Relation *toastidxs;
1802 
1803  /* Fetch a valid index relation */
1804  validIndex = toast_open_indexes(toastrel,
1806  &toastidxs,
1807  &num_indexes);
1808 
1809  /*
1810  * Setup a scan key to find chunks with matching va_valueid
1811  */
1812  ScanKeyInit(&toastkey,
1813  (AttrNumber) 1,
1814  BTEqualStrategyNumber, F_OIDEQ,
1815  ObjectIdGetDatum(valueid));
1816 
1817  /*
1818  * Is there any such chunk?
1819  */
1820  toastscan = systable_beginscan(toastrel,
1821  RelationGetRelid(toastidxs[validIndex]),
1822  true, SnapshotAny, 1, &toastkey);
1823 
1824  if (systable_getnext(toastscan) != NULL)
1825  result = true;
1826 
1827  systable_endscan(toastscan);
1828 
1829  /* Clean up */
1830  toast_close_indexes(toastidxs, num_indexes, RowExclusiveLock);
1831 
1832  return result;
1833 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
static int toast_open_indexes(Relation toastrel, LOCKMODE lock, Relation **toastidxs, int *num_indexes)
Definition: tuptoaster.c:2335
static void toast_close_indexes(Relation *toastidxs, int num_indexes, LOCKMODE lock)
Definition: tuptoaster.c:2394
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define RowExclusiveLock
Definition: lockdefs.h:38
#define SnapshotAny
Definition: snapmgr.h:70
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:416
#define BTEqualStrategyNumber
Definition: stratnum.h:31