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

📄 tuptoaster.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
 */static Datumtoast_save_datum(Relation rel, Datum value){	Relation	toastrel;	Relation	toastidx;	HeapTuple	toasttup;	TupleDesc	toasttupDesc;	Datum		t_values[3];	bool		t_isnull[3];	varattrib  *result;	struct	{		struct varlena hdr;		char		data[TOAST_MAX_CHUNK_SIZE];	}			chunk_data;	int32		chunk_size;	int32		chunk_seq = 0;	char	   *data_p;	int32		data_todo;	/*	 * Open the toast relation and its index.  We can use the index to check	 * uniqueness of the OID we assign to the toasted item, even though it has	 * additional columns besides OID.	 */	toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);	toasttupDesc = toastrel->rd_att;	toastidx = index_open(toastrel->rd_rel->reltoastidxid);	/*	 * Create the varattrib reference	 */	result = (varattrib *) palloc(sizeof(varattrib));	result->va_header = sizeof(varattrib) | VARATT_FLAG_EXTERNAL;	if (VARATT_IS_COMPRESSED(value))	{		result->va_header |= VARATT_FLAG_COMPRESSED;		result->va_content.va_external.va_rawsize =			((varattrib *) value)->va_content.va_compressed.va_rawsize;	}	else		result->va_content.va_external.va_rawsize = VARATT_SIZE(value);	result->va_content.va_external.va_extsize =		VARATT_SIZE(value) - VARHDRSZ;	result->va_content.va_external.va_valueid =		GetNewOidWithIndex(toastrel, toastidx);	result->va_content.va_external.va_toastrelid =		rel->rd_rel->reltoastrelid;	/*	 * Initialize constant parts of the tuple data	 */	t_values[0] = ObjectIdGetDatum(result->va_content.va_external.va_valueid);	t_values[2] = PointerGetDatum(&chunk_data);	t_isnull[0] = false;	t_isnull[1] = false;	t_isnull[2] = false;	/*	 * Get the data to process	 */	data_p = VARATT_DATA(value);	data_todo = VARATT_SIZE(value) - VARHDRSZ;	/*	 * We must explicitly lock the toast index because we aren't using an	 * index scan here.	 */	LockRelation(toastidx, RowExclusiveLock);	/*	 * 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++);		VARATT_SIZEP(&chunk_data) = chunk_size + VARHDRSZ;		memcpy(VARATT_DATA(&chunk_data), data_p, chunk_size);		toasttup = heap_form_tuple(toasttupDesc, t_values, t_isnull);		if (!HeapTupleIsValid(toasttup))			elog(ERROR, "failed to build TOAST tuple");		simple_heap_insert(toastrel, toasttup);		/*		 * 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 and return the reference	 */	UnlockRelation(toastidx, RowExclusiveLock);	index_close(toastidx);	heap_close(toastrel, RowExclusiveLock);	return PointerGetDatum(result);}/* ---------- * toast_delete_datum - * *	Delete a single external stored value. * ---------- */static voidtoast_delete_datum(Relation rel, Datum value){	varattrib  *attr = (varattrib *) DatumGetPointer(value);	Relation	toastrel;	Relation	toastidx;	ScanKeyData toastkey;	IndexScanDesc toastscan;	HeapTuple	toasttup;	if (!VARATT_IS_EXTERNAL(attr))		return;	/*	 * Open the toast relation and it's index	 */	toastrel = heap_open(attr->va_content.va_external.va_toastrelid,						 RowExclusiveLock);	toastidx = index_open(toastrel->rd_rel->reltoastidxid);	/*	 * 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(attr->va_content.va_external.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);	heap_close(toastrel, RowExclusiveLock);}/* ---------- * toast_fetch_datum - * *	Reconstruct an in memory varattrib from the chunks saved *	in the toast relation * ---------- */static varattrib *toast_fetch_datum(varattrib *attr){	Relation	toastrel;	Relation	toastidx;	ScanKeyData toastkey;	IndexScanDesc toastscan;	HeapTuple	ttup;	TupleDesc	toasttupDesc;	varattrib  *result;	int32		ressize;	int32		residx,				nextidx;	int32		numchunks;	Pointer		chunk;	bool		isnull;	int32		chunksize;	ressize = attr->va_content.va_external.va_extsize;	numchunks = ((ressize - 1) / TOAST_MAX_CHUNK_SIZE) + 1;	result = (varattrib *) palloc(ressize + VARHDRSZ);	VARATT_SIZEP(result) = ressize + VARHDRSZ;	if (VARATT_IS_COMPRESSED(attr))		VARATT_SIZEP(result) |= VARATT_FLAG_COMPRESSED;	/*	 * Open the toast relation and its index	 */	toastrel = heap_open(attr->va_content.va_external.va_toastrelid,						 AccessShareLock);	toasttupDesc = toastrel->rd_att;	toastidx = index_open(toastrel->rd_rel->reltoastidxid);	/*	 * Setup a scan key to fetch from the index by va_valueid	 */	ScanKeyInit(&toastkey,				(AttrNumber) 1,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(attr->va_content.va_external.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);		chunksize = VARATT_SIZE(chunk) - VARHDRSZ;		/*		 * Some checks on the data we've found		 */		if (residx != nextidx)			elog(ERROR, "unexpected chunk number %d (expected %d) for toast value %u",				 residx, nextidx,				 attr->va_content.va_external.va_valueid);		if (residx < numchunks - 1)		{			if (chunksize != TOAST_MAX_CHUNK_SIZE)				elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %u",					 chunksize, residx,					 attr->va_content.va_external.va_valueid);		}		else if (residx < numchunks)		{			if ((residx * TOAST_MAX_CHUNK_SIZE + chunksize) != ressize)				elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %u",					 chunksize, residx,					 attr->va_content.va_external.va_valueid);		}		else			elog(ERROR, "unexpected chunk number %d for toast value %u",				 residx,				 attr->va_content.va_external.va_valueid);		/*		 * Copy the data into proper place in our result		 */		memcpy(((char *) VARATT_DATA(result)) + residx * TOAST_MAX_CHUNK_SIZE,			   VARATT_DATA(chunk),			   chunksize);		nextidx++;	}	/*	 * Final checks that we successfully fetched the datum	 */	if (nextidx != numchunks)		elog(ERROR, "missing chunk number %d for toast value %u",			 nextidx,			 attr->va_content.va_external.va_valueid);	/*	 * End scan and close relations	 */	index_endscan(toastscan);	index_close(toastidx);	heap_close(toastrel, AccessShareLock);	return result;}/* ---------- * toast_fetch_datum_slice - * *	Reconstruct a segment of a varattrib from the chunks saved *	in the toast relation * ---------- */static varattrib *toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length){	Relation	toastrel;	Relation	toastidx;	ScanKeyData toastkey[3];	int			nscankeys;	IndexScanDesc toastscan;	HeapTuple	ttup;	TupleDesc	toasttupDesc;	varattrib  *result;	int32		attrsize;	int32		residx;	int32		nextidx;	int			numchunks;	int			startchunk;	int			endchunk;	int32		startoffset;	int32		endoffset;	int			totalchunks;	Pointer		chunk;	bool		isnull;	int32		chunksize;	int32		chcpystrt;	int32		chcpyend;	attrsize = attr->va_content.va_external.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 = (varattrib *) palloc(length + VARHDRSZ);	VARATT_SIZEP(result) = length + VARHDRSZ;	if (VARATT_IS_COMPRESSED(attr))		VARATT_SIZEP(result) |= VARATT_FLAG_COMPRESSED;	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 it's index	 */	toastrel = heap_open(attr->va_content.va_external.va_toastrelid,						 AccessShareLock);	toasttupDesc = toastrel->rd_att;	toastidx = index_open(toastrel->rd_rel->reltoastidxid);	/*	 * 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(attr->va_content.va_external.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);		chunksize = VARATT_SIZE(chunk) - VARHDRSZ;		/*		 * 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",				 residx, nextidx,				 attr->va_content.va_external.va_valueid);		if (residx < totalchunks - 1)		{			if (chunksize != TOAST_MAX_CHUNK_SIZE)				elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %u",					 chunksize, residx,					 attr->va_content.va_external.va_valueid);		}		else		{			if ((residx * TOAST_MAX_CHUNK_SIZE + chunksize) != attrsize)				elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %u",					 chunksize, residx,					 attr->va_content.va_external.va_valueid);		}		/*		 * 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(((char *) VARATT_DATA(result)) +			   (residx * TOAST_MAX_CHUNK_SIZE - sliceoffset) + chcpystrt,			   VARATT_DATA(chunk) + 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",			 nextidx,			 attr->va_content.va_external.va_valueid);	/*	 * End scan and close relations	 */	index_endscan(toastscan);	index_close(toastidx);	heap_close(toastrel, AccessShareLock);	return result;}

⌨️ 快捷键说明

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