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

📄 tuptoaster.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * tuptoaster.c *	  Support routines for external and compressed storage of *	  variable size attributes. * * Copyright (c) 2000-2008, PostgreSQL Global Development Group * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.81.2.3 2008/06/13 02:59:52 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/genam.h"#include "access/heapam.h"#include "access/tuptoaster.h"#include "access/xact.h"#include "catalog/catalog.h"#include "utils/fmgroids.h"#include "utils/pg_lzcompress.h"#include "utils/typcache.h"#undef TOAST_DEBUG/* Size of an EXTERNAL datum that contains a standard TOAST pointer */#define TOAST_POINTER_SIZE (VARHDRSZ_EXTERNAL + sizeof(struct varatt_external))/* * Testing whether an externally-stored value is compressed now requires * comparing extsize (the actual length of the external data) to rawsize * (the original uncompressed datum's size).  The latter includes VARHDRSZ * overhead, the former doesn't.  We never use compression unless it actually * saves space, so we expect either equality or less-than. */#define VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer) \	((toast_pointer).va_extsize < (toast_pointer).va_rawsize - VARHDRSZ)/* * Macro to fetch the possibly-unaligned contents of an EXTERNAL datum * into a local "struct varatt_external" toast pointer.  This should be * just a memcpy, but some versions of gcc seem to produce broken code * that assumes the datum contents are aligned.  Introducing an explicit * intermediate "varattrib_1b_e *" variable seems to fix it. */#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr) \do { \	varattrib_1b_e *attre = (varattrib_1b_e *) (attr); \	Assert(VARATT_IS_EXTERNAL(attre)); \	Assert(VARSIZE_EXTERNAL(attre) == sizeof(toast_pointer) + VARHDRSZ_EXTERNAL); \	memcpy(&(toast_pointer), VARDATA_EXTERNAL(attre), sizeof(toast_pointer)); \} while (0)static void toast_delete_datum(Relation rel, Datum value);static Datum toast_save_datum(Relation rel, Datum value,				 bool use_wal, bool use_fsm);static struct varlena *toast_fetch_datum(struct varlena * attr);static struct varlena *toast_fetch_datum_slice(struct varlena * attr,						int32 sliceoffset, int32 length);/* ---------- * heap_tuple_fetch_attr - * *	Public entry point to get back a toasted value from *	external storage (possibly still in compressed format). * * This will return a datum that contains all the data internally, ie, not * relying on external storage, but it can still be compressed or have a short * header. ---------- */struct varlena *heap_tuple_fetch_attr(struct varlena * attr){	struct varlena *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. * ---------- */struct varlena *heap_tuple_untoast_attr(struct varlena * attr){	if (VARATT_IS_EXTERNAL(attr))	{		/*		 * This is an externally stored datum --- fetch it back from there		 */		attr = toast_fetch_datum(attr);		/* If it's compressed, decompress it */		if (VARATT_IS_COMPRESSED(attr))		{			PGLZ_Header *tmp = (PGLZ_Header *) attr;			attr = (struct varlena *) palloc(PGLZ_RAW_SIZE(tmp) + VARHDRSZ);			SET_VARSIZE(attr, PGLZ_RAW_SIZE(tmp) + VARHDRSZ);			pglz_decompress(tmp, VARDATA(attr));			pfree(tmp);		}	}	else if (VARATT_IS_COMPRESSED(attr))	{		/*		 * This is a compressed value inside of the main tuple		 */		PGLZ_Header *tmp = (PGLZ_Header *) attr;		attr = (struct varlena *) palloc(PGLZ_RAW_SIZE(tmp) + VARHDRSZ);		SET_VARSIZE(attr, PGLZ_RAW_SIZE(tmp) + VARHDRSZ);		pglz_decompress(tmp, VARDATA(attr));	}	else if (VARATT_IS_SHORT(attr))	{		/*		 * This is a short-header varlena --- convert to 4-byte header format		 */		Size		data_size = VARSIZE_SHORT(attr) - VARHDRSZ_SHORT;		Size		new_size = data_size + VARHDRSZ;		struct varlena *new_attr;		new_attr = (struct varlena *) palloc(new_size);		SET_VARSIZE(new_attr, new_size);		memcpy(VARDATA(new_attr), VARDATA_SHORT(attr), data_size);		attr = new_attr;	}	return attr;}/* ---------- * heap_tuple_untoast_attr_slice - * *		Public entry point to get back part of a toasted value *		from compression or external storage. * ---------- */struct varlena *heap_tuple_untoast_attr_slice(struct varlena * attr,							  int32 sliceoffset, int32 slicelength){	struct varlena *preslice;	struct varlena *result;	char	   *attrdata;	int32		attrsize;	if (VARATT_IS_EXTERNAL(attr))	{		struct varatt_external toast_pointer;		VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);		/* fast path for non-compressed external datums */		if (!VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer))			return toast_fetch_datum_slice(attr, sliceoffset, slicelength);		/* fetch it back (compressed marker will get set automatically) */		preslice = toast_fetch_datum(attr);	}	else		preslice = attr;	if (VARATT_IS_COMPRESSED(preslice))	{		PGLZ_Header *tmp = (PGLZ_Header *) preslice;		Size		size = PGLZ_RAW_SIZE(tmp) + VARHDRSZ;		preslice = (struct varlena *) palloc(size);		SET_VARSIZE(preslice, size);		pglz_decompress(tmp, VARDATA(preslice));		if (tmp != (PGLZ_Header *) attr)			pfree(tmp);	}	if (VARATT_IS_SHORT(preslice))	{		attrdata = VARDATA_SHORT(preslice);		attrsize = VARSIZE_SHORT(preslice) - VARHDRSZ_SHORT;	}	else	{		attrdata = VARDATA(preslice);		attrsize = VARSIZE(preslice) - VARHDRSZ;	}	/* slicing of datum for compressed cases and plain value */	if (sliceoffset >= attrsize)	{		sliceoffset = 0;		slicelength = 0;	}	if (((sliceoffset + slicelength) > attrsize) || slicelength < 0)		slicelength = attrsize - sliceoffset;	result = (struct varlena *) palloc(slicelength + VARHDRSZ);	SET_VARSIZE(result, slicelength + VARHDRSZ);	memcpy(VARDATA(result), attrdata + sliceoffset, slicelength);	if (preslice != attr)		pfree(preslice);	return result;}/* ---------- * toast_raw_datum_size - * *	Return the raw (detoasted) size of a varlena datum *	(including the VARHDRSZ header) * ---------- */Sizetoast_raw_datum_size(Datum value){	struct varlena *attr = (struct varlena *) DatumGetPointer(value);	Size		result;	if (VARATT_IS_EXTERNAL(attr))	{		/* va_rawsize is the size of the original datum -- including header */		struct varatt_external toast_pointer;		VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);		result = toast_pointer.va_rawsize;	}	else if (VARATT_IS_COMPRESSED(attr))	{		/* here, va_rawsize is just the payload size */		result = VARRAWSIZE_4B_C(attr) + VARHDRSZ;	}	else if (VARATT_IS_SHORT(attr))	{		/*		 * we have to normalize the header length to VARHDRSZ or else the		 * callers of this function will be confused.		 */		result = VARSIZE_SHORT(attr) - VARHDRSZ_SHORT + VARHDRSZ;	}	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){	struct varlena *attr = (struct varlena *) 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?		 */		struct varatt_external toast_pointer;		VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);		result = toast_pointer.va_extsize;	}	else if (VARATT_IS_SHORT(attr))	{		result = VARSIZE_SHORT(attr);	}	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];	/*	 * We should only ever be called for tuples of plain relations ---	 * recursing on a toast rel is bad news.	 */	Assert(rel->rd_rel->relkind == RELKIND_RELATION);	/*	 * 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 *	use_wal, use_fsm: flags to be passed to heap_insert() for toast rows * 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,					   bool use_wal, bool use_fsm){	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;	Size		hoff;	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];	/*	 * We should only ever be called for tuples of plain relations ---	 * recursing on a toast rel is bad news.	 */	Assert(rel->rd_rel->relkind == RELKIND_RELATION);	/*	 * 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++)	{		struct varlena *old_value;		struct varlena *new_value;		if (oldtup != NULL)		{			/*			 * For UPDATE get the old and new values of this attribute			 */			old_value = (struct varlena *) DatumGetPointer(toast_oldvalues[i]);			new_value = (struct varlena *) 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) ||					memcmp((char *) old_value, (char *) new_value,						   VARSIZE_EXTERNAL(old_value)) != 0)				{					/*					 * 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';					continue;				}			}		}		else		{			/*			 * For INSERT simply get the new value			 */			new_value = (struct varlena *) 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.			 * Fetch it back (without decompression, unless we are forcing			 * PLAIN storage).	If necessary, we'll push it out as a new			 * external value below.			 */			if (VARATT_IS_EXTERNAL(new_value))			{				if (att[i]->attstorage == 'p')					new_value = heap_tuple_untoast_attr(new_value);				else

⌨️ 快捷键说明

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