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

📄 tuptoaster.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
	toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);	toasttupDesc = toastrel->rd_att;	toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock);	/*	 * Get the data pointer and length, and compute va_rawsize and va_extsize.	 *	 * va_rawsize is the size of the equivalent fully uncompressed datum, so	 * we have to adjust for short headers.	 *	 * va_extsize is the actual size of the data payload in the toast records.	 */	if (VARATT_IS_SHORT(value))	{		data_p = VARDATA_SHORT(value);		data_todo = VARSIZE_SHORT(value) - VARHDRSZ_SHORT;		toast_pointer.va_rawsize = data_todo + VARHDRSZ;		/* as if not short */		toast_pointer.va_extsize = data_todo;	}	else if (VARATT_IS_COMPRESSED(value))	{		data_p = VARDATA(value);		data_todo = VARSIZE(value) - VARHDRSZ;		/* rawsize in a compressed datum is just the size of the payload */		toast_pointer.va_rawsize = VARRAWSIZE_4B_C(value) + VARHDRSZ;		toast_pointer.va_extsize = data_todo;		/* Assert that the numbers look like it's compressed */		Assert(VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer));	}	else	{		data_p = VARDATA(value);		data_todo = VARSIZE(value) - VARHDRSZ;		toast_pointer.va_rawsize = VARSIZE(value);		toast_pointer.va_extsize = data_todo;	}	toast_pointer.va_valueid = GetNewOidWithIndex(toastrel, toastidx);	toast_pointer.va_toastrelid = rel->rd_rel->reltoastrelid;	/*	 * Initialize constant parts of the tuple data	 */	t_values[0] = ObjectIdGetDatum(toast_pointer.va_valueid);	t_values[2] = PointerGetDatum(&chunk_data);	t_isnull[0] = false;	t_isnull[1] = false;	t_isnull[2] = false;	/*	 * Split up the item into chunks	 */	while (data_todo > 0)	{		/*		 * Calculate the size of this chunk		 */		chunk_size = Min(TOAST_MAX_CHUNK_SIZE, data_todo);		/*		 * Build a tuple and store it		 */		t_values[1] = Int32GetDatum(chunk_seq++);		SET_VARSIZE(&chunk_data, chunk_size + VARHDRSZ);		memcpy(VARDATA(&chunk_data), data_p, chunk_size);		toasttup = heap_form_tuple(toasttupDesc, t_values, t_isnull);		heap_insert(toastrel, toasttup, mycid, use_wal, use_fsm);		/*		 * Create the index entry.	We cheat a little here by not using		 * FormIndexDatum: this relies on the knowledge that the index columns		 * are the same as the initial columns of the table.		 *		 * Note also that there had better not be any user-created index on		 * the TOAST table, since we don't bother to update anything else.		 */		index_insert(toastidx, t_values, t_isnull,					 &(toasttup->t_self),					 toastrel, toastidx->rd_index->indisunique);		/*		 * Free memory		 */		heap_freetuple(toasttup);		/*		 * Move on to next chunk		 */		data_todo -= chunk_size;		data_p += chunk_size;	}	/*	 * Done - close toast relation	 */	index_close(toastidx, RowExclusiveLock);	heap_close(toastrel, RowExclusiveLock);	/*	 * Create the TOAST pointer value that we'll return	 */	result = (struct varlena *) palloc(TOAST_POINTER_SIZE);	SET_VARSIZE_EXTERNAL(result, TOAST_POINTER_SIZE);	memcpy(VARDATA_EXTERNAL(result), &toast_pointer, sizeof(toast_pointer));	return PointerGetDatum(result);}/* ---------- * toast_delete_datum - * *	Delete a single external stored value. * ---------- */static voidtoast_delete_datum(Relation rel, Datum value){	struct varlena *attr = (struct varlena *) DatumGetPointer(value);	struct varatt_external toast_pointer;	Relation	toastrel;	Relation	toastidx;	ScanKeyData toastkey;	IndexScanDesc toastscan;	HeapTuple	toasttup;	if (!VARATT_IS_EXTERNAL(attr))		return;	/* Must copy to access aligned fields */	VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);	/*	 * Open the toast relation and its index	 */	toastrel = heap_open(toast_pointer.va_toastrelid, RowExclusiveLock);	toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock);	/*	 * Setup a scan key to fetch from the index by va_valueid (we don't	 * particularly care whether we see them in sequence or not)	 */	ScanKeyInit(&toastkey,				(AttrNumber) 1,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(toast_pointer.va_valueid));	/*	 * Find the chunks by index	 */	toastscan = index_beginscan(toastrel, toastidx,								SnapshotToast, 1, &toastkey);	while ((toasttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)	{		/*		 * Have a chunk, delete it		 */		simple_heap_delete(toastrel, &toasttup->t_self);	}	/*	 * End scan and close relations	 */	index_endscan(toastscan);	index_close(toastidx, RowExclusiveLock);	heap_close(toastrel, RowExclusiveLock);}/* ---------- * toast_fetch_datum - * *	Reconstruct an in memory Datum from the chunks saved *	in the toast relation * ---------- */static struct varlena *toast_fetch_datum(struct varlena * attr){	Relation	toastrel;	Relation	toastidx;	ScanKeyData toastkey;	IndexScanDesc toastscan;	HeapTuple	ttup;	TupleDesc	toasttupDesc;	struct varlena *result;	struct varatt_external toast_pointer;	int32		ressize;	int32		residx,				nextidx;	int32		numchunks;	Pointer		chunk;	bool		isnull;	char	   *chunkdata;	int32		chunksize;	/* Must copy to access aligned fields */	VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);	ressize = toast_pointer.va_extsize;	numchunks = ((ressize - 1) / TOAST_MAX_CHUNK_SIZE) + 1;	result = (struct varlena *) palloc(ressize + VARHDRSZ);	if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer))		SET_VARSIZE_COMPRESSED(result, ressize + VARHDRSZ);	else		SET_VARSIZE(result, ressize + VARHDRSZ);	/*	 * Open the toast relation and its index	 */	toastrel = heap_open(toast_pointer.va_toastrelid, AccessShareLock);	toasttupDesc = toastrel->rd_att;	toastidx = index_open(toastrel->rd_rel->reltoastidxid, AccessShareLock);	/*	 * Setup a scan key to fetch from the index by va_valueid	 */	ScanKeyInit(&toastkey,				(AttrNumber) 1,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(toast_pointer.va_valueid));	/*	 * Read the chunks by index	 *	 * Note that because the index is actually on (valueid, chunkidx) we will	 * see the chunks in chunkidx order, even though we didn't explicitly ask	 * for it.	 */	nextidx = 0;	toastscan = index_beginscan(toastrel, toastidx,								SnapshotToast, 1, &toastkey);	while ((ttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)	{		/*		 * Have a chunk, extract the sequence number and the data		 */		residx = DatumGetInt32(fastgetattr(ttup, 2, toasttupDesc, &isnull));		Assert(!isnull);		chunk = DatumGetPointer(fastgetattr(ttup, 3, toasttupDesc, &isnull));		Assert(!isnull);		if (!VARATT_IS_EXTENDED(chunk))		{			chunksize = VARSIZE(chunk) - VARHDRSZ;			chunkdata = VARDATA(chunk);		}		else if (VARATT_IS_SHORT(chunk))		{			/* could happen due to heap_form_tuple doing its thing */			chunksize = VARSIZE_SHORT(chunk) - VARHDRSZ_SHORT;			chunkdata = VARDATA_SHORT(chunk);		}		else		{			/* should never happen */			elog(ERROR, "found toasted toast chunk for toast value %u in %s",				 toast_pointer.va_valueid,				 RelationGetRelationName(toastrel));			chunksize = 0;		/* keep compiler quiet */			chunkdata = NULL;		}		/*		 * Some checks on the data we've found		 */		if (residx != nextidx)			elog(ERROR, "unexpected chunk number %d (expected %d) for toast value %u in %s",				 residx, nextidx,				 toast_pointer.va_valueid,				 RelationGetRelationName(toastrel));		if (residx < numchunks - 1)		{			if (chunksize != TOAST_MAX_CHUNK_SIZE)				elog(ERROR, "unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s",					 chunksize, (int) TOAST_MAX_CHUNK_SIZE,					 residx, numchunks,					 toast_pointer.va_valueid,					 RelationGetRelationName(toastrel));		}		else if (residx == numchunks - 1)		{			if ((residx * TOAST_MAX_CHUNK_SIZE + chunksize) != ressize)				elog(ERROR, "unexpected chunk size %d (expected %d) in final chunk %d for toast value %u in %s",					 chunksize,					 (int) (ressize - residx * TOAST_MAX_CHUNK_SIZE),					 residx,					 toast_pointer.va_valueid,					 RelationGetRelationName(toastrel));		}		else			elog(ERROR, "unexpected chunk number %d (out of range %d..%d) for toast value %u in %s",				 residx,				 0, numchunks - 1,				 toast_pointer.va_valueid,				 RelationGetRelationName(toastrel));		/*		 * Copy the data into proper place in our result		 */		memcpy(VARDATA(result) + residx * TOAST_MAX_CHUNK_SIZE,			   chunkdata,			   chunksize);		nextidx++;	}	/*	 * Final checks that we successfully fetched the datum	 */	if (nextidx != numchunks)		elog(ERROR, "missing chunk number %d for toast value %u in %s",			 nextidx,			 toast_pointer.va_valueid,			 RelationGetRelationName(toastrel));	/*	 * End scan and close relations	 */	index_endscan(toastscan);	index_close(toastidx, AccessShareLock);	heap_close(toastrel, AccessShareLock);	return result;}/* ---------- * toast_fetch_datum_slice - * *	Reconstruct a segment of a Datum from the chunks saved *	in the toast relation * ---------- */static struct varlena *toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length){	Relation	toastrel;	Relation	toastidx;	ScanKeyData toastkey[3];	int			nscankeys;	IndexScanDesc toastscan;	HeapTuple	ttup;	TupleDesc	toasttupDesc;	struct varlena *result;	struct varatt_external toast_pointer;	int32		attrsize;	int32		residx;	int32		nextidx;	int			numchunks;	int			startchunk;	int			endchunk;	int32		startoffset;	int32		endoffset;	int			totalchunks;	Pointer		chunk;	bool		isnull;	char	   *chunkdata;	int32		chunksize;	int32		chcpystrt;	int32		chcpyend;	Assert(VARATT_IS_EXTERNAL(attr));	/* Must copy to access aligned fields */	VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);	/*	 * It's nonsense to fetch slices of a compressed datum -- this isn't lo_*	 * we can't return a compressed datum which is meaningful to toast later	 */	Assert(!VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer));	attrsize = toast_pointer.va_extsize;	totalchunks = ((attrsize - 1) / TOAST_MAX_CHUNK_SIZE) + 1;	if (sliceoffset >= attrsize)	{		sliceoffset = 0;		length = 0;	}	if (((sliceoffset + length) > attrsize) || length < 0)		length = attrsize - sliceoffset;	result = (struct varlena *) palloc(length + VARHDRSZ);	if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer))		SET_VARSIZE_COMPRESSED(result, length + VARHDRSZ);	else		SET_VARSIZE(result, length + VARHDRSZ);	if (length == 0)		return result;			/* Can save a lot of work at this point! */	startchunk = sliceoffset / TOAST_MAX_CHUNK_SIZE;	endchunk = (sliceoffset + length - 1) / TOAST_MAX_CHUNK_SIZE;	numchunks = (endchunk - startchunk) + 1;	startoffset = sliceoffset % TOAST_MAX_CHUNK_SIZE;	endoffset = (sliceoffset + length - 1) % TOAST_MAX_CHUNK_SIZE;	/*	 * Open the toast relation and its index	 */	toastrel = heap_open(toast_pointer.va_toastrelid, AccessShareLock);	toasttupDesc = toastrel->rd_att;	toastidx = index_open(toastrel->rd_rel->reltoastidxid, AccessShareLock);	/*	 * Setup a scan key to fetch from the index. This is either two keys or	 * three depending on the number of chunks.	 */	ScanKeyInit(&toastkey[0],				(AttrNumber) 1,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(toast_pointer.va_valueid));	/*	 * Use equality condition for one chunk, a range condition otherwise:	 */	if (numchunks == 1)	{		ScanKeyInit(&toastkey[1],					(AttrNumber) 2,					BTEqualStrategyNumber, F_INT4EQ,					Int32GetDatum(startchunk));		nscankeys = 2;	}	else	{		ScanKeyInit(&toastkey[1],					(AttrNumber) 2,					BTGreaterEqualStrategyNumber, F_INT4GE,					Int32GetDatum(startchunk));		ScanKeyInit(&toastkey[2],					(AttrNumber) 2,					BTLessEqualStrategyNumber, F_INT4LE,					Int32GetDatum(endchunk));		nscankeys = 3;	}	/*	 * Read the chunks by index	 *	 * The index is on (valueid, chunkidx) so they will come in order	 */	nextidx = startchunk;	toastscan = index_beginscan(toastrel, toastidx,								SnapshotToast, nscankeys, toastkey);	while ((ttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)	{		/*		 * Have a chunk, extract the sequence number and the data		 */		residx = DatumGetInt32(fastgetattr(ttup, 2, toasttupDesc, &isnull));		Assert(!isnull);		chunk = DatumGetPointer(fastgetattr(ttup, 3, toasttupDesc, &isnull));		Assert(!isnull);		if (!VARATT_IS_EXTENDED(chunk))		{			chunksize = VARSIZE(chunk) - VARHDRSZ;			chunkdata = VARDATA(chunk);		}		else if (VARATT_IS_SHORT(chunk))		{			/* could happen due to heap_form_tuple doing its thing */			chunksize = VARSIZE_SHORT(chunk) - VARHDRSZ_SHORT;			chunkdata = VARDATA_SHORT(chunk);		}		else		{			/* should never happen */			elog(ERROR, "found toasted toast chunk for toast value %u in %s",				 toast_pointer.va_valueid,				 RelationGetRelationName(toastrel));			chunksize = 0;		/* keep compiler quiet */			chunkdata = NULL;		}		/*		 * Some checks on the data we've found		 */		if ((residx != nextidx) || (residx > endchunk) || (residx < startchunk))			elog(ERROR, "unexpected chunk number %d (expected %d) for toast value %u in %s",				 residx, nextidx,				 toast_pointer.va_valueid,				 RelationGetRelationName(toastrel));		if (residx < totalchunks - 1)		{			if (chunksize != TOAST_MAX_CHUNK_SIZE)				elog(ERROR, "unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s when fetching slice",					 chunksize, (int) TOAST_MAX_CHUNK_SIZE,					 residx, totalchunks,					 toast_pointer.va_valueid,					 RelationGetRelationName(toastrel));		}		else if (residx == totalchunks - 1)		{			if ((residx * TOAST_MAX_CHUNK_SIZE + chunksize) != attrsize)				elog(ERROR, "unexpected chunk size %d (expected %d) in final chunk %d for toast value %u in %s when fetching slice",					 chunksize,					 (int) (attrsize - residx * TOAST_MAX_CHUNK_SIZE),					 residx,					 toast_pointer.va_valueid,					 RelationGetRelationName(toastrel));		}		else			elog(ERROR, "unexpected chunk number %d (out of range %d..%d) for toast value %u in %s",				 residx,				 0, totalchunks - 1,				 toast_pointer.va_valueid,				 RelationGetRelationName(toastrel));		/*		 * Copy the data into proper place in our result		 */		chcpystrt = 0;		chcpyend = chunksize - 1;		if (residx == startchunk)			chcpystrt = startoffset;		if (residx == endchunk)			chcpyend = endoffset;		memcpy(VARDATA(result) +			   (residx * TOAST_MAX_CHUNK_SIZE - sliceoffset) + chcpystrt,			   chunkdata + chcpystrt,			   (chcpyend - chcpystrt) + 1);		nextidx++;	}	/*	 * Final checks that we successfully fetched the datum	 */	if (nextidx != (endchunk + 1))		elog(ERROR, "missing chunk number %d for toast value %u in %s",			 nextidx,			 toast_pointer.va_valueid,			 RelationGetRelationName(toastrel));	/*	 * End scan and close relations	 */	index_endscan(toastscan);	index_close(toastidx, AccessShareLock);	heap_close(toastrel, AccessShareLock);	return result;}

⌨️ 快捷键说明

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