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 + -
显示快捷键?