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

📄 heaptuple.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 4 页
字号:
 *		the same attribute descriptor will go much quicker. -cim 5/4/91 * *		NOTE: if you need to change this code, see also heap_deform_tuple. *		Also see nocache_index_getattr, which is the same code for index *		tuples. * ---------------- */Datumnocachegetattr(HeapTuple tuple,			   int attnum,			   TupleDesc tupleDesc,			   bool *isnull){	HeapTupleHeader tup = tuple->t_data;	Form_pg_attribute *att = tupleDesc->attrs;	char	   *tp;				/* ptr to data part of tuple */	bits8	   *bp = tup->t_bits;		/* ptr to null bitmap in tuple */	bool		slow = false;	/* do we have to walk attrs? */	int			off;			/* current offset within data */	(void) isnull;				/* not used */	/* ----------------	 *	 Three cases:	 *	 *	 1: No nulls and no variable-width attributes.	 *	 2: Has a null or a var-width AFTER att.	 *	 3: Has nulls or var-widths BEFORE att.	 * ----------------	 */#ifdef IN_MACRO/* This is handled in the macro */	Assert(attnum > 0);	if (isnull)		*isnull = false;#endif	attnum--;	if (HeapTupleNoNulls(tuple))	{#ifdef IN_MACRO/* This is handled in the macro */		if (att[attnum]->attcacheoff >= 0)		{			return fetchatt(att[attnum],							(char *) tup + tup->t_hoff +							att[attnum]->attcacheoff);		}#endif	}	else	{		/*		 * there's a null somewhere in the tuple		 *		 * check to see if desired att is null		 */#ifdef IN_MACRO/* This is handled in the macro */		if (att_isnull(attnum, bp))		{			if (isnull)				*isnull = true;			return (Datum) NULL;		}#endif		/*		 * Now check to see if any preceding bits are null...		 */		{			int			byte = attnum >> 3;			int			finalbit = attnum & 0x07;			/* check for nulls "before" final bit of last byte */			if ((~bp[byte]) & ((1 << finalbit) - 1))				slow = true;			else			{				/* check for nulls in any "earlier" bytes */				int			i;				for (i = 0; i < byte; i++)				{					if (bp[i] != 0xFF)					{						slow = true;						break;					}				}			}		}	}	tp = (char *) tup + tup->t_hoff;	if (!slow)	{		/*		 * If we get here, there are no nulls up to and including the target		 * attribute.  If we have a cached offset, we can use it.		 */		if (att[attnum]->attcacheoff >= 0)		{			return fetchatt(att[attnum],							tp + att[attnum]->attcacheoff);		}		/*		 * Otherwise, check for non-fixed-length attrs up to and including		 * target.	If there aren't any, it's safe to cheaply initialize the		 * cached offsets for these attrs.		 */		if (HeapTupleHasVarWidth(tuple))		{			int			j;			for (j = 0; j <= attnum; j++)			{				if (att[j]->attlen <= 0)				{					slow = true;					break;				}			}		}	}	if (!slow)	{		int			natts = tupleDesc->natts;		int			j = 1;		/*		 * If we get here, we have a tuple with no nulls or var-widths up to		 * and including the target attribute, so we can use the cached offset		 * ... only we don't have it yet, or we'd not have got here.  Since		 * it's cheap to compute offsets for fixed-width columns, we take the		 * opportunity to initialize the cached offsets for *all* the leading		 * fixed-width columns, in hope of avoiding future visits to this		 * routine.		 */		att[0]->attcacheoff = 0;		/* we might have set some offsets in the slow path previously */		while (j < natts && att[j]->attcacheoff > 0)			j++;		off = att[j - 1]->attcacheoff + att[j - 1]->attlen;		for (; j < natts; j++)		{			if (att[j]->attlen <= 0)				break;			off = att_align_nominal(off, att[j]->attalign);			att[j]->attcacheoff = off;			off += att[j]->attlen;		}		Assert(j > attnum);		off = att[attnum]->attcacheoff;	}	else	{		bool		usecache = true;		int			i;		/*		 * Now we know that we have to walk the tuple CAREFULLY.  But we still		 * might be able to cache some offsets for next time.		 *		 * Note - This loop is a little tricky.  For each non-null attribute,		 * we have to first account for alignment padding before the attr,		 * then advance over the attr based on its length.	Nulls have no		 * storage and no alignment padding either.  We can use/set		 * attcacheoff until we reach either a null or a var-width attribute.		 */		off = 0;		for (i = 0;; i++)		/* loop exit is at "break" */		{			if (HeapTupleHasNulls(tuple) && att_isnull(i, bp))			{				usecache = false;				continue;		/* this cannot be the target att */			}			/* If we know the next offset, we can skip the rest */			if (usecache && att[i]->attcacheoff >= 0)				off = att[i]->attcacheoff;			else if (att[i]->attlen == -1)			{				/*				 * We can only cache the offset for a varlena attribute if the				 * offset is already suitably aligned, so that there would be				 * no pad bytes in any case: then the offset will be valid for				 * either an aligned or unaligned value.				 */				if (usecache &&					off == att_align_nominal(off, att[i]->attalign))					att[i]->attcacheoff = off;				else				{					off = att_align_pointer(off, att[i]->attalign, -1,											tp + off);					usecache = false;				}			}			else			{				/* not varlena, so safe to use att_align_nominal */				off = att_align_nominal(off, att[i]->attalign);				if (usecache)					att[i]->attcacheoff = off;			}			if (i == attnum)				break;			off = att_addlength_pointer(off, att[i]->attlen, tp + off);			if (usecache && att[i]->attlen <= 0)				usecache = false;		}	}	return fetchatt(att[attnum], tp + off);}/* ---------------- *		heap_getsysattr * *		Fetch the value of a system attribute for a tuple. * * This is a support routine for the heap_getattr macro.  The macro * has already determined that the attnum refers to a system attribute. * ---------------- */Datumheap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull){	Datum		result;	Assert(tup);	/* Currently, no sys attribute ever reads as NULL. */	if (isnull)		*isnull = false;	switch (attnum)	{		case SelfItemPointerAttributeNumber:			/* pass-by-reference datatype */			result = PointerGetDatum(&(tup->t_self));			break;		case ObjectIdAttributeNumber:			result = ObjectIdGetDatum(HeapTupleGetOid(tup));			break;		case MinTransactionIdAttributeNumber:			result = TransactionIdGetDatum(HeapTupleHeaderGetXmin(tup->t_data));			break;		case MaxTransactionIdAttributeNumber:			result = TransactionIdGetDatum(HeapTupleHeaderGetXmax(tup->t_data));			break;		case MinCommandIdAttributeNumber:		case MaxCommandIdAttributeNumber:			/*			 * cmin and cmax are now both aliases for the same field, which			 * can in fact also be a combo command id.	XXX perhaps we should			 * return the "real" cmin or cmax if possible, that is if we are			 * inside the originating transaction?			 */			result = CommandIdGetDatum(HeapTupleHeaderGetRawCommandId(tup->t_data));			break;		case TableOidAttributeNumber:			result = ObjectIdGetDatum(tup->t_tableOid);			break;		default:			elog(ERROR, "invalid attnum: %d", attnum);			result = 0;			/* keep compiler quiet */			break;	}	return result;}/* ---------------- *		heap_copytuple * *		returns a copy of an entire tuple * * The HeapTuple struct, tuple header, and tuple data are all allocated * as a single palloc() block. * ---------------- */HeapTupleheap_copytuple(HeapTuple tuple){	HeapTuple	newTuple;	if (!HeapTupleIsValid(tuple) || tuple->t_data == NULL)		return NULL;	newTuple = (HeapTuple) palloc(HEAPTUPLESIZE + tuple->t_len);	newTuple->t_len = tuple->t_len;	newTuple->t_self = tuple->t_self;	newTuple->t_tableOid = tuple->t_tableOid;	newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);	memcpy((char *) newTuple->t_data, (char *) tuple->t_data, tuple->t_len);	return newTuple;}/* ---------------- *		heap_copytuple_with_tuple * *		copy a tuple into a caller-supplied HeapTuple management struct * * Note that after calling this function, the "dest" HeapTuple will not be * allocated as a single palloc() block (unlike with heap_copytuple()). * ---------------- */voidheap_copytuple_with_tuple(HeapTuple src, HeapTuple dest){	if (!HeapTupleIsValid(src) || src->t_data == NULL)	{		dest->t_data = NULL;		return;	}	dest->t_len = src->t_len;	dest->t_self = src->t_self;	dest->t_tableOid = src->t_tableOid;	dest->t_data = (HeapTupleHeader) palloc(src->t_len);	memcpy((char *) dest->t_data, (char *) src->t_data, src->t_len);}/* * heap_form_tuple *		construct a tuple from the given values[] and isnull[] arrays, *		which are of the length indicated by tupleDescriptor->natts * * The result is allocated in the current memory context. */HeapTupleheap_form_tuple(TupleDesc tupleDescriptor,				Datum *values,				bool *isnull){	HeapTuple	tuple;			/* return tuple */	HeapTupleHeader td;			/* tuple data */	Size		len,				data_len;	int			hoff;	bool		hasnull = false;	Form_pg_attribute *att = tupleDescriptor->attrs;	int			numberOfAttributes = tupleDescriptor->natts;	int			i;	if (numberOfAttributes > MaxTupleAttributeNumber)		ereport(ERROR,				(errcode(ERRCODE_TOO_MANY_COLUMNS),				 errmsg("number of columns (%d) exceeds limit (%d)",						numberOfAttributes, MaxTupleAttributeNumber)));	/*	 * Check for nulls and embedded tuples; expand any toasted attributes in	 * embedded tuples.  This preserves the invariant that toasting can only	 * go one level deep.	 *	 * We can skip calling toast_flatten_tuple_attribute() if the attribute	 * couldn't possibly be of composite type.  All composite datums are	 * varlena and have alignment 'd'; furthermore they aren't arrays. Also,	 * if an attribute is already toasted, it must have been sent to disk	 * already and so cannot contain toasted attributes.	 */	for (i = 0; i < numberOfAttributes; i++)	{		if (isnull[i])			hasnull = true;		else if (att[i]->attlen == -1 &&				 att[i]->attalign == 'd' &&				 att[i]->attndims == 0 &&				 !VARATT_IS_EXTENDED(values[i]))		{			values[i] = toast_flatten_tuple_attribute(values[i],													  att[i]->atttypid,													  att[i]->atttypmod);		}	}	/*	 * Determine total space needed	 */	len = offsetof(HeapTupleHeaderData, t_bits);	if (hasnull)		len += BITMAPLEN(numberOfAttributes);	if (tupleDescriptor->tdhasoid)		len += sizeof(Oid);	hoff = len = MAXALIGN(len); /* align user data safely */	data_len = heap_compute_data_size(tupleDescriptor, values, isnull);	len += data_len;	/*	 * Allocate and zero the space needed.	Note that the tuple body and	 * HeapTupleData management structure are allocated in one chunk.	 */	tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);	tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);	/*	 * And fill in the information.  Note we fill the Datum fields even though	 * this tuple may never become a Datum.	 */	tuple->t_len = len;	ItemPointerSetInvalid(&(tuple->t_self));	tuple->t_tableOid = InvalidOid;	HeapTupleHeaderSetDatumLength(td, len);	HeapTupleHeaderSetTypeId(td, tupleDescriptor->tdtypeid);	HeapTupleHeaderSetTypMod(td, tupleDescriptor->tdtypmod);	HeapTupleHeaderSetNatts(td, numberOfAttributes);	td->t_hoff = hoff;	if (tupleDescriptor->tdhasoid)		/* else leave infomask = 0 */		td->t_infomask = HEAP_HASOID;	heap_fill_tuple(tupleDescriptor,					values,					isnull,					(char *) td + hoff,					data_len,					&td->t_infomask,					(hasnull ? td->t_bits : NULL));	return tuple;}/* ---------------- *		heap_formtuple * *		construct a tuple from the given values[] and nulls[] arrays * *		Null attributes are indicated by a 'n' in the appropriate byte *		of nulls[]. Non-null attributes are indicated by a ' ' (space). * * OLD API with char 'n'/' ' convention for indicating nulls * ---------------- */HeapTupleheap_formtuple(TupleDesc tupleDescriptor,			   Datum *values,			   char *nulls){	HeapTuple	tuple;			/* return tuple */	HeapTupleHeader td;			/* tuple data */	Size		len,				data_len;	int			hoff;	bool		hasnull = false;	Form_pg_attribute *att = tupleDescriptor->attrs;	int			numberOfAttributes = tupleDescriptor->natts;	int			i;	if (numberOfAttributes > MaxTupleAttributeNumber)		ereport(ERROR,				(errcode(ERRCODE_TOO_MANY_COLUMNS),				 errmsg("number of columns (%d) exceeds limit (%d)",						numberOfAttributes, MaxTupleAttributeNumber)));	/*	 * Check for nulls and embedded tuples; expand any toasted attributes in	 * embedded tuples.  This preserves the invariant that toasting can only	 * go one level deep.	 *	 * We can skip calling toast_flatten_tuple_attribute() if the attribute	 * couldn't possibly be of composite type.  All composite datums are	 * varlena and have alignment 'd'; furthermore they aren't arrays. Also,	 * if an attribute is already toasted, it must have been sent to disk	 * already and so cannot contain toasted attributes.	 */	for (i = 0; i < numberOfAttributes; i++)	{		if (nulls[i] != ' ')			hasnull = true;		else if (att[i]->attlen == -1 &&				 att[i]->attalign == 'd' &&

⌨️ 快捷键说明

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