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

📄 heaptuple.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 4 页
字号:
/*------------------------------------------------------------------------- * * heaptuple.c *	  This file contains heap tuple accessor and mutator routines, as well *	  as various tuple utilities. * * NOTE: there is massive duplication of code in this module to * support both the convention that a null is marked by a bool TRUE, * and the convention that a null is marked by a char 'n'.	The latter * convention is deprecated but it'll probably be a long time before * we can get rid of it entirely. * * * Some notes about varlenas and this code: * * Before Postgres 8.3 varlenas always had a 4-byte length header, and * therefore always needed 4-byte alignment (at least).  This wasted space * for short varlenas, for example CHAR(1) took 5 bytes and could need up to * 3 additional padding bytes for alignment. * * Now, a short varlena (up to 126 data bytes) is reduced to a 1-byte header * and we don't align it.  To hide this from datatype-specific functions that * don't want to deal with it, such a datum is considered "toasted" and will * be expanded back to the normal 4-byte-header format by pg_detoast_datum. * (In performance-critical code paths we can use pg_detoast_datum_packed * and the appropriate access macros to avoid that overhead.)  Note that this * conversion is performed directly in heap_form_tuple (or heap_formtuple), * without explicitly invoking the toaster. * * This change will break any code that assumes it needn't detoast values * that have been put into a tuple but never sent to disk.	Hopefully there * are few such places. * * Varlenas still have alignment 'i' (or 'd') in pg_type/pg_attribute, since * that's the normal requirement for the untoasted format.  But we ignore that * for the 1-byte-header format.  This means that the actual start position * of a varlena datum may vary depending on which format it has.  To determine * what is stored, we have to require that alignment padding bytes be zero. * (Postgres actually has always zeroed them, but now it's required!)  Since * the first byte of a 1-byte-header varlena can never be zero, we can examine * the first byte after the previous datum to tell if it's a pad byte or the * start of a 1-byte-header varlena. * * Note that while formerly we could rely on the first varlena column of a * system catalog to be at the offset suggested by the C struct for the * catalog, this is now risky: it's only safe if the preceding field is * word-aligned, so that there will never be any padding. * * We don't pack varlenas whose attstorage is 'p', since the data type * isn't expecting to have to detoast values.  This is used in particular * by oidvector and int2vector, which are used in the system catalogs * and we'd like to still refer to them via C struct offsets. * * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.120 2008/01/01 19:45:45 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "access/tuptoaster.h"#include "executor/tuptable.h"/* Does att's datatype allow packing into the 1-byte-header varlena format? */#define ATT_IS_PACKABLE(att) \	((att)->attlen == -1 && (att)->attstorage != 'p')/* Use this if it's already known varlena */#define VARLENA_ATT_IS_PACKABLE(att) \	((att)->attstorage != 'p')/* ---------------------------------------------------------------- *						misc support routines * ---------------------------------------------------------------- *//* * heap_compute_data_size *		Determine size of the data area of a tuple to be constructed */Sizeheap_compute_data_size(TupleDesc tupleDesc,					   Datum *values,					   bool *isnull){	Size		data_length = 0;	int			i;	int			numberOfAttributes = tupleDesc->natts;	Form_pg_attribute *att = tupleDesc->attrs;	for (i = 0; i < numberOfAttributes; i++)	{		Datum		val;		if (isnull[i])			continue;		val = values[i];		if (ATT_IS_PACKABLE(att[i]) &&			VARATT_CAN_MAKE_SHORT(DatumGetPointer(val)))		{			/*			 * we're anticipating converting to a short varlena header, so			 * adjust length and don't count any alignment			 */			data_length += VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val));		}		else		{			data_length = att_align_datum(data_length, att[i]->attalign,										  att[i]->attlen, val);			data_length = att_addlength_datum(data_length, att[i]->attlen,											  val);		}	}	return data_length;}/* ---------------- *		ComputeDataSize * * Determine size of the data area of a tuple to be constructed * * OLD API with char 'n'/' ' convention for indicating nulls * ---------------- */static SizeComputeDataSize(TupleDesc tupleDesc,				Datum *values,				char *nulls){	Size		data_length = 0;	int			i;	int			numberOfAttributes = tupleDesc->natts;	Form_pg_attribute *att = tupleDesc->attrs;	for (i = 0; i < numberOfAttributes; i++)	{		Datum		val;		if (nulls[i] != ' ')			continue;		val = values[i];		if (ATT_IS_PACKABLE(att[i]) &&			VARATT_CAN_MAKE_SHORT(DatumGetPointer(val)))		{			/*			 * we're anticipating converting to a short varlena header, so			 * adjust length and don't count any alignment			 */			data_length += VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val));		}		else		{			data_length = att_align_datum(data_length, att[i]->attalign,										  att[i]->attlen, val);			data_length = att_addlength_datum(data_length, att[i]->attlen,											  val);		}	}	return data_length;}/* * heap_fill_tuple *		Load data portion of a tuple from values/isnull arrays * * We also fill the null bitmap (if any) and set the infomask bits * that reflect the tuple's data contents. * * NOTE: it is now REQUIRED that the caller have pre-zeroed the data area. */voidheap_fill_tuple(TupleDesc tupleDesc,				Datum *values, bool *isnull,				char *data, Size data_size,				uint16 *infomask, bits8 *bit){	bits8	   *bitP;	int			bitmask;	int			i;	int			numberOfAttributes = tupleDesc->natts;	Form_pg_attribute *att = tupleDesc->attrs;#ifdef USE_ASSERT_CHECKING	char	   *start = data;#endif	if (bit != NULL)	{		bitP = &bit[-1];		bitmask = HIGHBIT;	}	else	{		/* just to keep compiler quiet */		bitP = NULL;		bitmask = 0;	}	*infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTERNAL);	for (i = 0; i < numberOfAttributes; i++)	{		Size		data_length;		if (bit != NULL)		{			if (bitmask != HIGHBIT)				bitmask <<= 1;			else			{				bitP += 1;				*bitP = 0x0;				bitmask = 1;			}			if (isnull[i])			{				*infomask |= HEAP_HASNULL;				continue;			}			*bitP |= bitmask;		}		/*		 * XXX we use the att_align macros on the pointer value itself, not on		 * an offset.  This is a bit of a hack.		 */		if (att[i]->attbyval)		{			/* pass-by-value */			data = (char *) att_align_nominal((long) data, att[i]->attalign);			store_att_byval(data, values[i], att[i]->attlen);			data_length = att[i]->attlen;		}		else if (att[i]->attlen == -1)		{			/* varlena */			Pointer		val = DatumGetPointer(values[i]);			*infomask |= HEAP_HASVARWIDTH;			if (VARATT_IS_EXTERNAL(val))			{				*infomask |= HEAP_HASEXTERNAL;				/* no alignment, since it's short by definition */				data_length = VARSIZE_EXTERNAL(val);				memcpy(data, val, data_length);			}			else if (VARATT_IS_SHORT(val))			{				/* no alignment for short varlenas */				data_length = VARSIZE_SHORT(val);				memcpy(data, val, data_length);			}			else if (VARLENA_ATT_IS_PACKABLE(att[i]) &&					 VARATT_CAN_MAKE_SHORT(val))			{				/* convert to short varlena -- no alignment */				data_length = VARATT_CONVERTED_SHORT_SIZE(val);				SET_VARSIZE_SHORT(data, data_length);				memcpy(data + 1, VARDATA(val), data_length - 1);			}			else			{				/* full 4-byte header varlena */				data = (char *) att_align_nominal((long) data,												  att[i]->attalign);				data_length = VARSIZE(val);				memcpy(data, val, data_length);			}		}		else if (att[i]->attlen == -2)		{			/* cstring ... never needs alignment */			*infomask |= HEAP_HASVARWIDTH;			Assert(att[i]->attalign == 'c');			data_length = strlen(DatumGetCString(values[i])) + 1;			memcpy(data, DatumGetPointer(values[i]), data_length);		}		else		{			/* fixed-length pass-by-reference */			data = (char *) att_align_nominal((long) data, att[i]->attalign);			Assert(att[i]->attlen > 0);			data_length = att[i]->attlen;			memcpy(data, DatumGetPointer(values[i]), data_length);		}		data += data_length;	}	Assert((data - start) == data_size);}/* ---------------- *		DataFill * * Load data portion of a tuple from values/nulls arrays * * OLD API with char 'n'/' ' convention for indicating nulls * ---------------- */static voidDataFill(TupleDesc tupleDesc,		 Datum *values, char *nulls,		 char *data, Size data_size,		 uint16 *infomask, bits8 *bit){	bits8	   *bitP;	int			bitmask;	int			i;	int			numberOfAttributes = tupleDesc->natts;	Form_pg_attribute *att = tupleDesc->attrs;#ifdef USE_ASSERT_CHECKING	char	   *start = data;#endif	if (bit != NULL)	{		bitP = &bit[-1];		bitmask = HIGHBIT;	}	else	{		/* just to keep compiler quiet */		bitP = NULL;		bitmask = 0;	}	*infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTERNAL);	for (i = 0; i < numberOfAttributes; i++)	{		Size		data_length;		if (bit != NULL)		{			if (bitmask != HIGHBIT)				bitmask <<= 1;			else			{				bitP += 1;				*bitP = 0x0;				bitmask = 1;			}			if (nulls[i] == 'n')			{				*infomask |= HEAP_HASNULL;				continue;			}			*bitP |= bitmask;		}		/*		 * XXX we use the att_align macros on the pointer value itself, not on		 * an offset.  This is a bit of a hack.		 */		if (att[i]->attbyval)		{			/* pass-by-value */			data = (char *) att_align_nominal((long) data, att[i]->attalign);			store_att_byval(data, values[i], att[i]->attlen);			data_length = att[i]->attlen;		}		else if (att[i]->attlen == -1)		{			/* varlena */			Pointer		val = DatumGetPointer(values[i]);			*infomask |= HEAP_HASVARWIDTH;			if (VARATT_IS_EXTERNAL(val))			{				*infomask |= HEAP_HASEXTERNAL;				/* no alignment, since it's short by definition */				data_length = VARSIZE_EXTERNAL(val);				memcpy(data, val, data_length);			}			else if (VARATT_IS_SHORT(val))			{				/* no alignment for short varlenas */				data_length = VARSIZE_SHORT(val);				memcpy(data, val, data_length);			}			else if (VARLENA_ATT_IS_PACKABLE(att[i]) &&					 VARATT_CAN_MAKE_SHORT(val))			{				/* convert to short varlena -- no alignment */				data_length = VARATT_CONVERTED_SHORT_SIZE(val);				SET_VARSIZE_SHORT(data, data_length);				memcpy(data + 1, VARDATA(val), data_length - 1);			}			else			{				/* full 4-byte header varlena */				data = (char *) att_align_nominal((long) data,												  att[i]->attalign);				data_length = VARSIZE(val);				memcpy(data, val, data_length);			}		}		else if (att[i]->attlen == -2)		{			/* cstring ... never needs alignment */			*infomask |= HEAP_HASVARWIDTH;			Assert(att[i]->attalign == 'c');			data_length = strlen(DatumGetCString(values[i])) + 1;			memcpy(data, DatumGetPointer(values[i]), data_length);		}		else		{			/* fixed-length pass-by-reference */			data = (char *) att_align_nominal((long) data, att[i]->attalign);			Assert(att[i]->attlen > 0);			data_length = att[i]->attlen;			memcpy(data, DatumGetPointer(values[i]), data_length);		}		data += data_length;	}	Assert((data - start) == data_size);}/* ---------------------------------------------------------------- *						heap tuple interface * ---------------------------------------------------------------- *//* ---------------- *		heap_attisnull	- returns TRUE iff tuple attribute is not present * ---------------- */boolheap_attisnull(HeapTuple tup, int attnum){	if (attnum > (int) HeapTupleHeaderGetNatts(tup->t_data))		return true;	if (attnum > 0)	{		if (HeapTupleNoNulls(tup))			return false;		return att_isnull(attnum - 1, tup->t_data->t_bits);	}	switch (attnum)	{		case TableOidAttributeNumber:		case SelfItemPointerAttributeNumber:		case ObjectIdAttributeNumber:		case MinTransactionIdAttributeNumber:		case MinCommandIdAttributeNumber:		case MaxTransactionIdAttributeNumber:		case MaxCommandIdAttributeNumber:			/* these are never null */			break;		default:			elog(ERROR, "invalid attnum: %d", attnum);	}	return false;}/* ---------------- *		nocachegetattr * *		This only gets called from fastgetattr() macro, in cases where *		we can't use a cacheoffset and the value is not null. * *		This caches attribute offsets in the attribute descriptor. * *		An alternative way to speed things up would be to cache offsets *		with the tuple, but that seems more difficult unless you take *		the storage hit of actually putting those offsets into the *		tuple you send to disk.  Yuck. * *		This scheme will be slightly slower than that, but should *		perform well for queries which hit large #'s of tuples.  After *		you cache the offsets once, examining all the other tuples using

⌨️ 快捷键说明

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