Header And Logo

| The world's most advanced open source database.

Functions | Variables

toasting.c File Reference

#include "postgres.h"
#include "access/tuptoaster.h"
#include "access/xact.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/namespace.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_type.h"
#include "catalog/toasting.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "utils/builtins.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for toasting.c:

Go to the source code of this file.


static bool create_toast_table (Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptions)
static bool needs_toast_table (Relation rel)
void AlterTableCreateToastTable (Oid relOid, Datum reloptions)
void BootstrapToastTable (char *relName, Oid toastOid, Oid toastIndexOid)


Oid binary_upgrade_next_toast_pg_class_oid
Oid binary_upgrade_next_toast_pg_type_oid = InvalidOid

Function Documentation

void AlterTableCreateToastTable ( Oid  relOid,
Datum  reloptions 

Definition at line 56 of file toasting.c.

References AccessExclusiveLock, create_toast_table(), heap_close, heap_open(), InvalidOid, and NoLock.

Referenced by ATRewriteCatalogs(), intorel_startup(), make_new_heap(), and ProcessUtilitySlow().

    Relation    rel;

     * Grab an exclusive lock on the target table, since we'll update its
     * pg_class tuple. This is redundant for all present uses, since caller
     * will have such a lock already.  But the lock is needed to ensure that
     * concurrent readers of the pg_class tuple won't have visibility issues,
     * so let's be safe.
    rel = heap_open(relOid, AccessExclusiveLock);

    /* create_toast_table does all the work */
    (void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions);

    heap_close(rel, NoLock);

void BootstrapToastTable ( char *  relName,
Oid  toastOid,
Oid  toastIndexOid 

Definition at line 81 of file toasting.c.

References AccessExclusiveLock, create_toast_table(), elog, ereport, errcode(), errmsg(), ERROR, heap_close, heap_openrv(), makeRangeVar(), NoLock, NULL, RelationData::rd_rel, RELKIND_MATVIEW, and RELKIND_RELATION.

    Relation    rel;

    rel = heap_openrv(makeRangeVar(NULL, relName, -1), AccessExclusiveLock);

    if (rel->rd_rel->relkind != RELKIND_RELATION &&
        rel->rd_rel->relkind != RELKIND_MATVIEW)
                 errmsg("\"%s\" is not a table or materialized view",

    /* create_toast_table does all the work */
    if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0))
        elog(ERROR, "\"%s\" does not require a toast table",

    heap_close(rel, NoLock);

static bool create_toast_table ( Relation  rel,
Oid  toastOid,
Oid  toastIndexOid,
Datum  reloptions 
) [static]

Definition at line 111 of file toasting.c.

References Assert, tupleDesc::attrs, binary_upgrade_next_toast_pg_class_oid, binary_upgrade_next_toast_pg_type_oid, BTREE_AM_OID, BYTEAOID, CatalogUpdateIndexes(), ObjectAddress::classId, CommandCounterIncrement(), CreateTemplateTupleDesc(), DEPENDENCY_INTERNAL, elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, GetTempToastNamespace(), heap_close, heap_create_with_catalog(), heap_freetuple(), heap_inplace_update(), heap_open(), HeapTupleIsValid, IndexInfo::ii_BrokenHotChain, IndexInfo::ii_Concurrent, IndexInfo::ii_ExclusionOps, IndexInfo::ii_ExclusionProcs, IndexInfo::ii_ExclusionStrats, IndexInfo::ii_Expressions, IndexInfo::ii_ExpressionsState, IndexInfo::ii_KeyAttrNumbers, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_Predicate, IndexInfo::ii_PredicateState, IndexInfo::ii_ReadyForInserts, IndexInfo::ii_Unique, index_create(), INT4OID, InvalidOid, IsBinaryUpgrade, IsBootstrapProcessingMode, isTempOrToastNamespace(), list_make2, makeNode, needs_toast_table(), NIL, NoLock, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, OIDOID, ONCOMMIT_NOOP, RelationData::rd_rel, recordDependencyOn(), RelationGetRelid, RelationIsMapped, RelationRelationId, RELKIND_TOASTVALUE, RELOID, RowExclusiveLock, SearchSysCacheCopy1, ShareLock, simple_heap_update(), snprintf(), HeapTupleData::t_self, and TupleDescInitEntry().

Referenced by AlterTableCreateToastTable(), and BootstrapToastTable().

    Oid         relOid = RelationGetRelid(rel);
    HeapTuple   reltup;
    TupleDesc   tupdesc;
    bool        shared_relation;
    bool        mapped_relation;
    Relation    toast_rel;
    Relation    class_rel;
    Oid         toast_relid;
    Oid         toast_typid = InvalidOid;
    Oid         namespaceid;
    char        toast_relname[NAMEDATALEN];
    char        toast_idxname[NAMEDATALEN];
    IndexInfo  *indexInfo;
    Oid         collationObjectId[2];
    Oid         classObjectId[2];
    int16       coloptions[2];
    ObjectAddress baseobject,

     * Toast table is shared if and only if its parent is.
     * We cannot allow toasting a shared relation after initdb (because
     * there's no way to mark it toasted in other databases' pg_class).
    shared_relation = rel->rd_rel->relisshared;
    if (shared_relation && !IsBootstrapProcessingMode())
                 errmsg("shared tables cannot be toasted after initdb")));

    /* It's mapped if and only if its parent is, too */
    mapped_relation = RelationIsMapped(rel);

     * Is it already toasted?
    if (rel->rd_rel->reltoastrelid != InvalidOid)
        return false;

     * Check to see whether the table actually needs a TOAST table.
     * If an update-in-place toast relfilenode is specified, force toast file
     * creation even if it seems not to need one.
    if (!needs_toast_table(rel) &&
        (!IsBinaryUpgrade ||
        return false;

     * Create the toast table and its index
    snprintf(toast_relname, sizeof(toast_relname),
             "pg_toast_%u", relOid);
    snprintf(toast_idxname, sizeof(toast_idxname),
             "pg_toast_%u_index", relOid);

    /* this is pretty painful...  need a tuple descriptor */
    tupdesc = CreateTemplateTupleDesc(3, false);
    TupleDescInitEntry(tupdesc, (AttrNumber) 1,
                       -1, 0);
    TupleDescInitEntry(tupdesc, (AttrNumber) 2,
                       -1, 0);
    TupleDescInitEntry(tupdesc, (AttrNumber) 3,
                       -1, 0);

     * Ensure that the toast table doesn't itself get toasted, or we'll be
     * toast :-(.  This is essential for chunk_data because type bytea is
     * toastable; hit the other two just to be sure.
    tupdesc->attrs[0]->attstorage = 'p';
    tupdesc->attrs[1]->attstorage = 'p';
    tupdesc->attrs[2]->attstorage = 'p';

     * Toast tables for regular relations go in pg_toast; those for temp
     * relations go into the per-backend temp-toast-table namespace.
    if (isTempOrToastNamespace(rel->rd_rel->relnamespace))
        namespaceid = GetTempToastNamespace();
        namespaceid = PG_TOAST_NAMESPACE;

    /* Use binary-upgrade override for pg_type.oid, if supplied. */
    if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_toast_pg_type_oid))
        toast_typid = binary_upgrade_next_toast_pg_type_oid;
        binary_upgrade_next_toast_pg_type_oid = InvalidOid;

    toast_relid = heap_create_with_catalog(toast_relname,
    Assert(toast_relid != InvalidOid);

    /* make the toast relation visible, else heap_open will fail */

    /* ShareLock is not really needed here, but take it anyway */
    toast_rel = heap_open(toast_relid, ShareLock);

     * Create unique index on chunk_id, chunk_seq.
     * NOTE: the normal TOAST access routines could actually function with a
     * single-column index on chunk_id only. However, the slice access
     * routines use both columns for faster access to an individual chunk. In
     * addition, we want it to be unique as a check against the possibility of
     * duplicate TOAST chunk OIDs. The index might also be a little more
     * efficient this way, since btree isn't all that happy with large numbers
     * of equal keys.

    indexInfo = makeNode(IndexInfo);
    indexInfo->ii_NumIndexAttrs = 2;
    indexInfo->ii_KeyAttrNumbers[0] = 1;
    indexInfo->ii_KeyAttrNumbers[1] = 2;
    indexInfo->ii_Expressions = NIL;
    indexInfo->ii_ExpressionsState = NIL;
    indexInfo->ii_Predicate = NIL;
    indexInfo->ii_PredicateState = NIL;
    indexInfo->ii_ExclusionOps = NULL;
    indexInfo->ii_ExclusionProcs = NULL;
    indexInfo->ii_ExclusionStrats = NULL;
    indexInfo->ii_Unique = true;
    indexInfo->ii_ReadyForInserts = true;
    indexInfo->ii_Concurrent = false;
    indexInfo->ii_BrokenHotChain = false;

    collationObjectId[0] = InvalidOid;
    collationObjectId[1] = InvalidOid;

    classObjectId[0] = OID_BTREE_OPS_OID;
    classObjectId[1] = INT4_BTREE_OPS_OID;

    coloptions[0] = 0;
    coloptions[1] = 0;

    index_create(toast_rel, toast_idxname, toastIndexOid, InvalidOid,
                 list_make2("chunk_id", "chunk_seq"),
                 collationObjectId, classObjectId, coloptions, (Datum) 0,
                 true, false, false, false,
                 true, false, false, true);

    heap_close(toast_rel, NoLock);

     * Store the toast table's OID in the parent relation's pg_class row
    class_rel = heap_open(RelationRelationId, RowExclusiveLock);

    reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
    if (!HeapTupleIsValid(reltup))
        elog(ERROR, "cache lookup failed for relation %u", relOid);

    ((Form_pg_class) GETSTRUCT(reltup))->reltoastrelid = toast_relid;

    if (!IsBootstrapProcessingMode())
        /* normal case, use a transactional update */
        simple_heap_update(class_rel, &reltup->t_self, reltup);

        /* Keep catalog indexes current */
        CatalogUpdateIndexes(class_rel, reltup);
        /* While bootstrapping, we cannot UPDATE, so overwrite in-place */
        heap_inplace_update(class_rel, reltup);


    heap_close(class_rel, RowExclusiveLock);

     * Register dependency from the toast table to the master, so that the
     * toast table will be deleted if the master is.  Skip this in bootstrap
     * mode.
    if (!IsBootstrapProcessingMode())
        baseobject.classId = RelationRelationId;
        baseobject.objectId = relOid;
        baseobject.objectSubId = 0;
        toastobject.classId = RelationRelationId;
        toastobject.objectId = toast_relid;
        toastobject.objectSubId = 0;

        recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL);

     * Make changes visible

    return true;

static bool needs_toast_table ( Relation  rel  )  [static]

Definition at line 349 of file toasting.c.

References att_align_nominal, tupleDesc::attrs, BITMAPLEN, i, MAXALIGN, tupleDesc::natts, offsetof, RelationData::rd_att, TOAST_TUPLE_THRESHOLD, and type_maximum_size().

Referenced by create_toast_table().

    int32       data_length = 0;
    bool        maxlength_unknown = false;
    bool        has_toastable_attrs = false;
    TupleDesc   tupdesc;
    Form_pg_attribute *att;
    int32       tuple_length;
    int         i;

    tupdesc = rel->rd_att;
    att = tupdesc->attrs;

    for (i = 0; i < tupdesc->natts; i++)
        if (att[i]->attisdropped)
        data_length = att_align_nominal(data_length, att[i]->attalign);
        if (att[i]->attlen > 0)
            /* Fixed-length types are never toastable */
            data_length += att[i]->attlen;
            int32       maxlen = type_maximum_size(att[i]->atttypid,

            if (maxlen < 0)
                maxlength_unknown = true;
                data_length += maxlen;
            if (att[i]->attstorage != 'p')
                has_toastable_attrs = true;
    if (!has_toastable_attrs)
        return false;           /* nothing to toast? */
    if (maxlength_unknown)
        return true;            /* any unlimited-length attrs? */
    tuple_length = MAXALIGN(offsetof(HeapTupleHeaderData, t_bits) +
                            BITMAPLEN(tupdesc->natts)) +
    return (tuple_length > TOAST_TUPLE_THRESHOLD);

Variable Documentation

Definition at line 78 of file heap.c.

Definition at line 36 of file toasting.c.

Referenced by create_toast_table(), and set_next_toast_pg_type_oid().