tuptoaster.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,307 行 · 第 1/3 页

C
1,307
字号
	/*	 * Open the toast relation	 */	toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);	toasttupDesc = toastrel->rd_att;	toastidx = index_open(toastrel->rd_rel->reltoastidxid);	/*	 * 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_formtuple(toasttupDesc, t_values, t_nulls);		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.		 */		idxres = index_insert(toastidx, t_values, t_nulls,							  &(toasttup->t_self),							  toastrel, toastidx->rd_index->indisunique);		if (idxres == NULL)			elog(ERROR, "failed to insert index entry for TOAST tuple");		/*		 * Free memory		 */		pfree(idxres);		heap_freetuple(toasttup);		/*		 * Move on to next chunk		 */		data_todo -= chunk_size;		data_p += chunk_size;	}	/*	 * Done - close toast relation and return the reference	 */	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)	 */	ScanKeyEntryInitialize(&toastkey,						   (bits16) 0,						   (AttrNumber) 1,						   (RegProcedure) 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	 */	ScanKeyEntryInitialize(&toastkey,						   (bits16) 0,						   (AttrNumber) 1,						   (RegProcedure) 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(heap_getattr(ttup, 2, toasttupDesc, &isnull));		Assert(!isnull);		chunk = DatumGetPointer(heap_getattr(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.	 */	ScanKeyEntryInitialize(&toastkey[0],						   (bits16) 0,						   (AttrNumber) 1,						   (RegProcedure) F_OIDEQ,			  ObjectIdGetDatum(attr->va_content.va_external.va_valueid));	/*	 * Now dependent on number of chunks:	 */	if (numchunks == 1)	{		ScanKeyEntryInitialize(&toastkey[1],							   (bits16) 0,							   (AttrNumber) 2,							   (RegProcedure) F_INT4EQ,							   Int32GetDatum(startchunk));		nscankeys = 2;	}	else	{		ScanKeyEntryInitialize(&toastkey[1],							   (bits16) 0,							   (AttrNumber) 2,							   (RegProcedure) F_INT4GE,							   Int32GetDatum(startchunk));		ScanKeyEntryInitialize(&toastkey[2],							   (bits16) 0,							   (AttrNumber) 2,							   (RegProcedure) 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(heap_getattr(ttup, 2, toasttupDesc, &isnull));		Assert(!isnull);		chunk = DatumGetPointer(heap_getattr(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 + =
减小字号Ctrl + -
显示快捷键?