tuptoaster.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,307 行 · 第 1/3 页
C
1,307 行
/*------------------------------------------------------------------------- * * tuptoaster.c * Support routines for external and compressed storage of * variable size attributes. * * Copyright (c) 2000-2003, PostgreSQL Global Development Group * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.38 2003/08/04 23:59:37 tgl Exp $ * * * INTERFACE ROUTINES * heap_tuple_toast_attrs - * Try to make a given tuple fit into one page by compressing * or moving off attributes * * heap_tuple_untoast_attr - * Fetch back a given value from the "secondary" relation * *------------------------------------------------------------------------- */#include "postgres.h"#include <unistd.h>#include <fcntl.h>#include "access/heapam.h"#include "access/genam.h"#include "access/tuptoaster.h"#include "catalog/catalog.h"#include "utils/rel.h"#include "utils/builtins.h"#include "utils/fmgroids.h"#include "utils/pg_lzcompress.h"#undef TOAST_DEBUGstatic void toast_delete(Relation rel, HeapTuple oldtup);static void toast_delete_datum(Relation rel, Datum value);static void toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup);static Datum toast_save_datum(Relation rel, Datum value);static varattrib *toast_fetch_datum(varattrib *attr);static varattrib *toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length);/* ---------- * heap_tuple_toast_attrs - * * This is the central public entry point for toasting from heapam. * * Calls the appropriate event specific action. * ---------- */voidheap_tuple_toast_attrs(Relation rel, HeapTuple newtup, HeapTuple oldtup){ if (newtup == NULL) toast_delete(rel, oldtup); else toast_insert_or_update(rel, newtup, oldtup);}/* ---------- * heap_tuple_fetch_attr - * * Public entry point to get back a toasted value * external storage (possibly still in compressed format). * ---------- */varattrib *heap_tuple_fetch_attr(varattrib *attr){ varattrib *result; if (VARATT_IS_EXTERNAL(attr)) { /* * This is an external stored plain value */ result = toast_fetch_datum(attr); } else { /* * This is a plain value inside of the main tuple - why am I * called? */ result = attr; } return result;}/* ---------- * heap_tuple_untoast_attr - * * Public entry point to get back a toasted value from compression * or external storage. * ---------- */varattrib *heap_tuple_untoast_attr(varattrib *attr){ varattrib *result; if (VARATT_IS_EXTERNAL(attr)) { if (VARATT_IS_COMPRESSED(attr)) { /* ---------- * This is an external stored compressed value * Fetch it from the toast heap and decompress. * ---------- */ varattrib *tmp; tmp = toast_fetch_datum(attr); result = (varattrib *) palloc(attr->va_content.va_external.va_rawsize + VARHDRSZ); VARATT_SIZEP(result) = attr->va_content.va_external.va_rawsize + VARHDRSZ; pglz_decompress((PGLZ_Header *) tmp, VARATT_DATA(result)); pfree(tmp); } else { /* * This is an external stored plain value */ result = toast_fetch_datum(attr); } } else if (VARATT_IS_COMPRESSED(attr)) { /* * This is a compressed value inside of the main tuple */ result = (varattrib *) palloc(attr->va_content.va_compressed.va_rawsize + VARHDRSZ); VARATT_SIZEP(result) = attr->va_content.va_compressed.va_rawsize + VARHDRSZ; pglz_decompress((PGLZ_Header *) attr, VARATT_DATA(result)); } else /* * This is a plain value inside of the main tuple - why am I * called? */ return attr; return result;}/* ---------- * heap_tuple_untoast_attr_slice - * * Public entry point to get back part of a toasted value * from compression or external storage. * ---------- */varattrib *heap_tuple_untoast_attr_slice(varattrib *attr, int32 sliceoffset, int32 slicelength){ varattrib *preslice; varattrib *result; int32 attrsize; if (VARATT_IS_COMPRESSED(attr)) { varattrib *tmp; if (VARATT_IS_EXTERNAL(attr)) tmp = toast_fetch_datum(attr); else { tmp = attr; /* compressed in main tuple */ } preslice = (varattrib *) palloc(attr->va_content.va_external.va_rawsize + VARHDRSZ); VARATT_SIZEP(preslice) = attr->va_content.va_external.va_rawsize + VARHDRSZ; pglz_decompress((PGLZ_Header *) tmp, VARATT_DATA(preslice)); if (tmp != attr) pfree(tmp); } else { /* Plain value */ if (VARATT_IS_EXTERNAL(attr)) { /* fast path */ return (toast_fetch_datum_slice(attr, sliceoffset, slicelength)); } else preslice = attr; } /* slicing of datum for compressed cases and plain value */ attrsize = VARSIZE(preslice) - VARHDRSZ; if (sliceoffset >= attrsize) { sliceoffset = 0; slicelength = 0; } if (((sliceoffset + slicelength) > attrsize) || slicelength < 0) slicelength = attrsize - sliceoffset; result = (varattrib *) palloc(slicelength + VARHDRSZ); VARATT_SIZEP(result) = slicelength + VARHDRSZ; memcpy(VARDATA(result), VARDATA(preslice) + sliceoffset, slicelength); if (preslice != attr) pfree(preslice); return result;}/* ---------- * toast_raw_datum_size - * * Return the raw (detoasted) size of a varlena datum * ---------- */Sizetoast_raw_datum_size(Datum value){ varattrib *attr = (varattrib *) DatumGetPointer(value); Size result; if (VARATT_IS_COMPRESSED(attr)) { /* * va_rawsize shows the original data size, whether the datum is * external or not. */ result = attr->va_content.va_compressed.va_rawsize + VARHDRSZ; } else if (VARATT_IS_EXTERNAL(attr)) { /* * an uncompressed external attribute has rawsize including the * header (not too consistent!) */ result = attr->va_content.va_external.va_rawsize; } else { /* plain untoasted datum */ result = VARSIZE(attr); } return result;}/* ---------- * toast_delete - * * Cascaded delete toast-entries on DELETE * ---------- */static voidtoast_delete(Relation rel, HeapTuple oldtup){ TupleDesc tupleDesc; Form_pg_attribute *att; int numAttrs; int i; Datum value; bool isnull; /* * Get the tuple descriptor, the number of and attribute descriptors. */ tupleDesc = rel->rd_att; numAttrs = tupleDesc->natts; att = tupleDesc->attrs; /* * Check for external stored attributes and delete them from the * secondary relation. */ for (i = 0; i < numAttrs; i++) { if (att[i]->attlen == -1) { value = heap_getattr(oldtup, i + 1, tupleDesc, &isnull); if (!isnull && VARATT_IS_EXTERNAL(value)) toast_delete_datum(rel, value); } }}/* ---------- * toast_insert_or_update - * * Delete no-longer-used toast-entries and create new ones to * make the new tuple fit on INSERT or UPDATE * ---------- */static voidtoast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup){ TupleDesc tupleDesc; Form_pg_attribute *att; int numAttrs; int i; bool old_isnull; bool new_isnull; bool need_change = false; bool need_free = false; bool need_delold = false; bool has_nulls = false; Size maxDataLen; char toast_action[MaxHeapAttributeNumber]; char toast_nulls[MaxHeapAttributeNumber]; Datum toast_values[MaxHeapAttributeNumber]; int32 toast_sizes[MaxHeapAttributeNumber]; bool toast_free[MaxHeapAttributeNumber]; bool toast_delold[MaxHeapAttributeNumber]; /* * Get the tuple descriptor, the number of and attribute descriptors * and the location of the tuple values. */ tupleDesc = rel->rd_att; numAttrs = tupleDesc->natts; att = tupleDesc->attrs; /* ---------- * Then collect information about the values given * * NOTE: toast_action[i] can have these values: * ' ' default handling * 'p' already processed --- don't touch it * 'x' incompressible, but OK to move off * ---------- */ memset(toast_action, ' ', numAttrs * sizeof(char)); memset(toast_nulls, ' ', numAttrs * sizeof(char)); memset(toast_free, 0, numAttrs * sizeof(bool)); memset(toast_delold, 0, numAttrs * sizeof(bool)); for (i = 0; i < numAttrs; i++) { varattrib *old_value; varattrib *new_value; if (oldtup != NULL) { /* * For UPDATE get the old and new values of this attribute */ old_value = (varattrib *) DatumGetPointer( heap_getattr(oldtup, i + 1, tupleDesc, &old_isnull)); toast_values[i] = heap_getattr(newtup, i + 1, tupleDesc, &new_isnull); new_value = (varattrib *) DatumGetPointer(toast_values[i]); /* * If the old value is an external stored one, check if it has * changed so we have to delete it later. */ if (!old_isnull && att[i]->attlen == -1 && VARATT_IS_EXTERNAL(old_value)) { if (new_isnull || !VARATT_IS_EXTERNAL(new_value) || old_value->va_content.va_external.va_valueid != new_value->va_content.va_external.va_valueid || old_value->va_content.va_external.va_toastrelid != new_value->va_content.va_external.va_toastrelid) { /* * The old external store value isn't needed any more * after the update */ toast_delold[i] = true; need_delold = true; } else { /* * This attribute isn't changed by this update so we * reuse the original reference to the old value in * the new tuple. */ toast_action[i] = 'p'; toast_sizes[i] = VARATT_SIZE(toast_values[i]); continue; } } } else { /* * For INSERT simply get the new value */ toast_values[i] = heap_getattr(newtup, i + 1, tupleDesc, &new_isnull); } /* * Handle NULL attributes */ if (new_isnull) { toast_action[i] = 'p'; toast_nulls[i] = 'n'; has_nulls = true; continue; } /* * Now look at varsize attributes */ if (att[i]->attlen == -1) { /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?