1/*-------------------------------------------------------------------------
4 * Helper functions for table AMs implementing compressed or
5 * out-of-line storage of varlena attributes.
7 * Copyright (c) 2000-2025, PostgreSQL Global Development Group
10 * src/backend/access/table/toast_helper.c
12 *-------------------------------------------------------------------------
20#include "catalog/pg_type_d.h"
25 * Prepare to TOAST a tuple.
27 * tupleDesc, toast_values, and toast_isnull are required parameters; they
28 * provide the necessary details about the tuple to be toasted.
30 * toast_oldvalues and toast_oldisnull should be NULL for a newly-inserted
31 * tuple; for an update, they should describe the existing tuple.
33 * All of these arrays should have a length equal to tupleDesc->natts.
35 * On return, toast_flags and toast_attr will have been initialized.
36 * toast_flags is just a single uint8, but toast_attr is a caller-provided
37 * array with a length equal to tupleDesc->natts. The caller need not
38 * perform any initialization of the array before calling this function.
44 int numAttrs = tupleDesc->
natts;
49 for (
i = 0;
i < numAttrs;
i++)
62 * For UPDATE get the old and new values of this attribute
70 * If the old value is stored on disk, check if it has changed so
71 * we have to delete it later.
78 memcmp(old_value, new_value,
82 * The old external stored value isn't needed any more
91 * This attribute isn't changed by this update so we reuse
92 * the original reference to the old value in the new
103 * For INSERT simply get the new value
109 * Handle NULL attributes
119 * Now look at varlena attributes
121 if (att->attlen == -1)
124 * If the table's attribute says PLAIN always, force it so.
126 if (att->attstorage == TYPSTORAGE_PLAIN)
130 * We took care of UPDATE above, so any external value we find
131 * still in the tuple must be someone else's that we cannot reuse
132 * (this includes the case of an out-of-line in-memory datum).
133 * Fetch it back (without decompression, unless we are forcing
134 * PLAIN storage). If necessary, we'll push it out as a new
135 * external value below.
140 if (att->attstorage == TYPSTORAGE_PLAIN)
150 * Remember the size of this attribute
157 * Not a varlena attribute, plain storage always
165 * Find the largest varlena attribute that satisfies certain criteria.
167 * The relevant column must not be marked TOASTCOL_IGNORE, and if the
168 * for_compression flag is passed as true, it must also not be marked
169 * TOASTCOL_INCOMPRESSIBLE.
171 * The column must have attstorage EXTERNAL or EXTENDED if check_main is
172 * false, and must have attstorage MAIN if check_main is true.
174 * The column must have a minimum size of MAXALIGN(TOAST_POINTER_SIZE);
175 * if not, no benefit is to be expected by compressing it.
177 * The return value is the index of the biggest suitable column, or
178 * -1 if there is none.
182 bool for_compression,
bool check_main)
185 int numAttrs = tupleDesc->
natts;
186 int biggest_attno = -1;
194 for (
i = 0;
i < numAttrs;
i++)
201 continue;
/* can't happen, toast_action would be PLAIN */
202 if (for_compression &&
205 if (check_main && att->attstorage != TYPSTORAGE_MAIN)
207 if (!check_main && att->attstorage != TYPSTORAGE_EXTENDED &&
208 att->attstorage != TYPSTORAGE_EXTERNAL)
218 return biggest_attno;
222 * Try compression for an attribute.
224 * If we find that the attribute is not compressible, mark it so.
237 /* successful compression */
247 /* incompressible, ignore on subsequent compression passes */
253 * Move an attribute to external storage.
272 * Perform appropriate cleanup after one tuple has been subjected to TOAST.
278 int numAttrs = tupleDesc->
natts;
281 * Free allocated temp values
287 for (
i = 0;
i < numAttrs;
i++)
297 * Delete external values from the old tuple
303 for (
i = 0;
i < numAttrs;
i++)
314 * Check for external stored attributes and delete them from the secondary
322 int numAttrs = tupleDesc->
natts;
325 for (
i = 0;
i < numAttrs;
i++)
static Datum values[MAXATTR]
struct varlena * detoast_attr(struct varlena *attr)
struct varlena * detoast_external_attr(struct varlena *attr)
#define TOAST_POINTER_SIZE
void pfree(void *pointer)
FormData_pg_attribute * Form_pg_attribute
static Datum PointerGetDatum(const void *X)
static Pointer DatumGetPointer(Datum X)
struct varlena * tai_oldexternal
void toast_tuple_init(ToastTupleContext *ttc)
void toast_delete_external(Relation rel, const Datum *values, const bool *isnull, bool is_speculative)
void toast_tuple_try_compression(ToastTupleContext *ttc, int attribute)
void toast_tuple_externalize(ToastTupleContext *ttc, int attribute, int options)
void toast_tuple_cleanup(ToastTupleContext *ttc)
int toast_tuple_find_biggest_attribute(ToastTupleContext *ttc, bool for_compression, bool check_main)
#define TOAST_NEEDS_CHANGE
#define TOASTCOL_NEEDS_DELETE_OLD
#define TOASTCOL_INCOMPRESSIBLE
#define TOAST_NEEDS_DELETE_OLD
#define TOASTCOL_NEEDS_FREE
void toast_delete_datum(Relation rel, Datum value, bool is_speculative)
Datum toast_save_datum(Relation rel, Datum value, struct varlena *oldexternal, int options)
Datum toast_compress_datum(Datum value, char cmethod)
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
static bool VARATT_IS_EXTERNAL_ONDISK(const void *PTR)
static Size VARSIZE_ANY(const void *PTR)
static bool VARATT_IS_EXTERNAL(const void *PTR)
static Size VARSIZE(const void *PTR)
static bool VARATT_IS_COMPRESSED(const void *PTR)
static Size VARSIZE_EXTERNAL(const void *PTR)