⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tuptoaster.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * tuptoaster.c *	  Support routines for external and compressed storage of *	  variable size attributes. * * Copyright (c) 2000-2005, PostgreSQL Global Development Group * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.53.2.3 2006/01/17 17:33:20 tgl Exp $ * * * INTERFACE ROUTINES *		toast_insert_or_update - *			Try to make a given tuple fit into one page by compressing *			or moving off attributes * *		toast_delete - *			Reclaim toast storage when a tuple is deleted * *		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"#include "utils/typcache.h"#undef TOAST_DEBUGstatic void toast_delete_datum(Relation rel, Datum value);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_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_datum_size * *	Return the physical storage size (possibly compressed) of a varlena datum * ---------- */Sizetoast_datum_size(Datum value){	varattrib  *attr = (varattrib *) DatumGetPointer(value);	Size		result;	if (VARATT_IS_EXTERNAL(attr))	{		/*		 * Attribute is stored externally - return the extsize whether		 * compressed or not.  We do not count the size of the toast pointer		 * ... should we?		 */		result = attr->va_content.va_external.va_extsize;	}	else	{		/*		 * Attribute is stored inline either compressed or not, just calculate		 * the size of the datum in either case.		 */		result = VARSIZE(attr);	}	return result;}/* ---------- * toast_delete - * *	Cascaded delete toast-entries on DELETE * ---------- */voidtoast_delete(Relation rel, HeapTuple oldtup){	TupleDesc	tupleDesc;	Form_pg_attribute *att;	int			numAttrs;	int			i;	Datum		toast_values[MaxHeapAttributeNumber];	bool		toast_isnull[MaxHeapAttributeNumber];	/*	 * Get the tuple descriptor and break down the tuple into fields.	 *	 * NOTE: it's debatable whether to use heap_deformtuple() here or just	 * heap_getattr() only the varlena columns.  The latter could win if there	 * are few varlena columns and many non-varlena ones. However,	 * heap_deformtuple costs only O(N) while the heap_getattr way would cost	 * O(N^2) if there are many varlena columns, so it seems better to err on	 * the side of linear cost.  (We won't even be here unless there's at	 * least one varlena column, by the way.)	 */	tupleDesc = rel->rd_att;	att = tupleDesc->attrs;	numAttrs = tupleDesc->natts;	Assert(numAttrs <= MaxHeapAttributeNumber);	heap_deform_tuple(oldtup, tupleDesc, toast_values, toast_isnull);	/*	 * Check for external stored attributes and delete them from the secondary	 * relation.	 */	for (i = 0; i < numAttrs; i++)	{		if (att[i]->attlen == -1)		{			Datum		value = toast_values[i];			if (!toast_isnull[i] && 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 * * Inputs: *	newtup: the candidate new tuple to be inserted *	oldtup: the old row version for UPDATE, or NULL for INSERT * Result: *	either newtup if no toasting is needed, or a palloc'd modified tuple *	that is what should actually get stored * * NOTE: neither newtup nor oldtup will be modified.  This is a change * from the pre-8.1 API of this routine. * ---------- */HeapTupletoast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup){	HeapTuple	result_tuple;	TupleDesc	tupleDesc;	Form_pg_attribute *att;	int			numAttrs;	int			i;	bool		need_change = false;	bool		need_free = false;	bool		need_delold = false;	bool		has_nulls = false;	Size		maxDataLen;	char		toast_action[MaxHeapAttributeNumber];	bool		toast_isnull[MaxHeapAttributeNumber];	bool		toast_oldisnull[MaxHeapAttributeNumber];	Datum		toast_values[MaxHeapAttributeNumber];	Datum		toast_oldvalues[MaxHeapAttributeNumber];	int32		toast_sizes[MaxHeapAttributeNumber];	bool		toast_free[MaxHeapAttributeNumber];	bool		toast_delold[MaxHeapAttributeNumber];	/*	 * Get the tuple descriptor and break down the tuple(s) into fields.	 */	tupleDesc = rel->rd_att;	att = tupleDesc->attrs;	numAttrs = tupleDesc->natts;	Assert(numAttrs <= MaxHeapAttributeNumber);	heap_deform_tuple(newtup, tupleDesc, toast_values, toast_isnull);	if (oldtup != NULL)		heap_deform_tuple(oldtup, tupleDesc, toast_oldvalues, toast_oldisnull);	/* ----------	 * 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	 *	 * NOTE: toast_sizes[i] is only made valid for varlena attributes with	 *		toast_action[i] different from 'p'.	 * ----------	 */	memset(toast_action, ' ', 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(toast_oldvalues[i]);			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 (att[i]->attlen == -1 && !toast_oldisnull[i] &&				VARATT_IS_EXTERNAL(old_value))			{				if (toast_isnull[i] || !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 stored 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			 */			new_value = (varattrib *) DatumGetPointer(toast_values[i]);		}		/*		 * Handle NULL attributes		 */		if (toast_isnull[i])		{			toast_action[i] = 'p';			has_nulls = true;			continue;		}		/*		 * Now look at varlena attributes		 */		if (att[i]->attlen == -1)		{			/*			 * If the table's attribute says PLAIN always, force it so.			 */			if (att[i]->attstorage == 'p')				toast_action[i] = 'p';			/*			 * We took care of UPDATE above, so any external value we find			 * still in the tuple must be someone else's we cannot reuse.			 * Expand it to plain (and, probably, toast it again below).			 */			if (VARATT_IS_EXTERNAL(new_value))			{				new_value = heap_tuple_untoast_attr(new_value);				toast_values[i] = PointerGetDatum(new_value);				toast_free[i] = true;				need_change = true;				need_free = true;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -