tuptoaster.c

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

C
1,307
字号
			 * If the table's attribute says PLAIN always, force it so.			 */			if (att[i]->attstorage == 'p')				toast_action[i] = 'p';			/*			 * We took care of UPDATE above, so any external value we find			 * still in the tuple must be someone else's we cannot reuse.			 * Expand it to plain (and, probably, toast it again below).			 */			if (VARATT_IS_EXTERNAL(DatumGetPointer(toast_values[i])))			{				toast_values[i] = PointerGetDatum(heap_tuple_untoast_attr(						(varattrib *) DatumGetPointer(toast_values[i])));				toast_free[i] = true;				need_change = true;				need_free = true;			}			/*			 * Remember the size of this attribute			 */			toast_sizes[i] = VARATT_SIZE(DatumGetPointer(toast_values[i]));		}		else		{			/*			 * Not a variable size attribute, plain storage always			 */			toast_action[i] = 'p';			toast_sizes[i] = att[i]->attlen;		}	}	/* ----------	 * Compress and/or save external until data fits into target length	 *	 *	1: Inline compress attributes with attstorage 'x'	 *	2: Store attributes with attstorage 'x' or 'e' external	 *	3: Inline compress attributes with attstorage 'm'	 *	4: Store attributes with attstorage 'm' external	 * ----------	 */	maxDataLen = offsetof(HeapTupleHeaderData, t_bits);	if (has_nulls)		maxDataLen += BITMAPLEN(numAttrs);	maxDataLen = TOAST_TUPLE_TARGET - MAXALIGN(maxDataLen);	/*	 * Look for attributes with attstorage 'x' to compress	 */	while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >		   maxDataLen)	{		int			biggest_attno = -1;		int32		biggest_size = MAXALIGN(sizeof(varattrib));		Datum		old_value;		Datum		new_value;		/*		 * Search for the biggest yet uncompressed internal attribute		 */		for (i = 0; i < numAttrs; i++)		{			if (toast_action[i] != ' ')				continue;			if (VARATT_IS_EXTENDED(toast_values[i]))				continue;			if (att[i]->attstorage != 'x')				continue;			if (toast_sizes[i] > biggest_size)			{				biggest_attno = i;				biggest_size = toast_sizes[i];			}		}		if (biggest_attno < 0)			break;		/*		 * Attempt to compress it inline		 */		i = biggest_attno;		old_value = toast_values[i];		new_value = toast_compress_datum(old_value);		if (DatumGetPointer(new_value) != NULL)		{			/* successful compression */			if (toast_free[i])				pfree(DatumGetPointer(old_value));			toast_values[i] = new_value;			toast_free[i] = true;			toast_sizes[i] = VARATT_SIZE(toast_values[i]);			need_change = true;			need_free = true;		}		else		{			/*			 * incompressible data, ignore on subsequent compression			 * passes			 */			toast_action[i] = 'x';		}	}	/*	 * Second we look for attributes of attstorage 'x' or 'e' that are	 * still inline.	 */	while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >		   maxDataLen && rel->rd_rel->reltoastrelid != InvalidOid)	{		int			biggest_attno = -1;		int32		biggest_size = MAXALIGN(sizeof(varattrib));		Datum		old_value;		/*------		 * Search for the biggest yet inlined attribute with		 * attstorage equals 'x' or 'e'		 *------		 */		for (i = 0; i < numAttrs; i++)		{			if (toast_action[i] == 'p')				continue;			if (VARATT_IS_EXTERNAL(toast_values[i]))				continue;			if (att[i]->attstorage != 'x' && att[i]->attstorage != 'e')				continue;			if (toast_sizes[i] > biggest_size)			{				biggest_attno = i;				biggest_size = toast_sizes[i];			}		}		if (biggest_attno < 0)			break;		/*		 * Store this external		 */		i = biggest_attno;		old_value = toast_values[i];		toast_action[i] = 'p';		toast_values[i] = toast_save_datum(rel, toast_values[i]);		if (toast_free[i])			pfree(DatumGetPointer(old_value));		toast_free[i] = true;		toast_sizes[i] = VARATT_SIZE(toast_values[i]);		need_change = true;		need_free = true;	}	/*	 * Round 3 - this time we take attributes with storage 'm' into	 * compression	 */	while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >		   maxDataLen)	{		int			biggest_attno = -1;		int32		biggest_size = MAXALIGN(sizeof(varattrib));		Datum		old_value;		Datum		new_value;		/*		 * Search for the biggest yet uncompressed internal attribute		 */		for (i = 0; i < numAttrs; i++)		{			if (toast_action[i] != ' ')				continue;			if (VARATT_IS_EXTENDED(toast_values[i]))				continue;			if (att[i]->attstorage != 'm')				continue;			if (toast_sizes[i] > biggest_size)			{				biggest_attno = i;				biggest_size = toast_sizes[i];			}		}		if (biggest_attno < 0)			break;		/*		 * Attempt to compress it inline		 */		i = biggest_attno;		old_value = toast_values[i];		new_value = toast_compress_datum(old_value);		if (DatumGetPointer(new_value) != NULL)		{			/* successful compression */			if (toast_free[i])				pfree(DatumGetPointer(old_value));			toast_values[i] = new_value;			toast_free[i] = true;			toast_sizes[i] = VARATT_SIZE(toast_values[i]);			need_change = true;			need_free = true;		}		else		{			/*			 * incompressible data, ignore on subsequent compression			 * passes			 */			toast_action[i] = 'x';		}	}	/*	 * Finally we store attributes of type 'm' external	 */	while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >		   maxDataLen && rel->rd_rel->reltoastrelid != InvalidOid)	{		int			biggest_attno = -1;		int32		biggest_size = MAXALIGN(sizeof(varattrib));		Datum		old_value;		/*--------		 * Search for the biggest yet inlined attribute with		 * attstorage = 'm'		 *--------		 */		for (i = 0; i < numAttrs; i++)		{			if (toast_action[i] == 'p')				continue;			if (VARATT_IS_EXTERNAL(toast_values[i]))				continue;			if (att[i]->attstorage != 'm')				continue;			if (toast_sizes[i] > biggest_size)			{				biggest_attno = i;				biggest_size = toast_sizes[i];			}		}		if (biggest_attno < 0)			break;		/*		 * Store this external		 */		i = biggest_attno;		old_value = toast_values[i];		toast_action[i] = 'p';		toast_values[i] = toast_save_datum(rel, toast_values[i]);		if (toast_free[i])			pfree(DatumGetPointer(old_value));		toast_free[i] = true;		toast_sizes[i] = VARATT_SIZE(toast_values[i]);		need_change = true;		need_free = true;	}	/*	 * In the case we toasted any values, we need to build a new heap	 * tuple with the changed values.	 */	if (need_change)	{		HeapTupleHeader olddata = newtup->t_data;		char	   *new_data;		int32		new_len;		/*		 * Calculate the new size of the tuple.  Header size should not		 * change, but data size might.		 */		new_len = offsetof(HeapTupleHeaderData, t_bits);		if (has_nulls)			new_len += BITMAPLEN(numAttrs);		if (olddata->t_infomask & HEAP_HASOID)			new_len += sizeof(Oid);		new_len = MAXALIGN(new_len);		Assert(new_len == olddata->t_hoff);		new_len += ComputeDataSize(tupleDesc, toast_values, toast_nulls);		/*		 * Allocate new tuple in same context as old one.		 */		new_data = (char *) MemoryContextAlloc(newtup->t_datamcxt, new_len);		newtup->t_data = (HeapTupleHeader) new_data;		newtup->t_len = new_len;		/*		 * Put the tuple header and the changed values into place		 */		memcpy(new_data, olddata, olddata->t_hoff);		DataFill((char *) new_data + olddata->t_hoff,				 tupleDesc,				 toast_values,				 toast_nulls,				 &(newtup->t_data->t_infomask),				 has_nulls ? newtup->t_data->t_bits : NULL);		/*		 * In the case we modified a previously modified tuple again, free		 * the memory from the previous run		 */		if ((char *) olddata != ((char *) newtup + HEAPTUPLESIZE))			pfree(olddata);	}	/*	 * Free allocated temp values	 */	if (need_free)		for (i = 0; i < numAttrs; i++)			if (toast_free[i])				pfree(DatumGetPointer(toast_values[i]));	/*	 * Delete external values from the old tuple	 */	if (need_delold)		for (i = 0; i < numAttrs; i++)			if (toast_delold[i])				toast_delete_datum(rel,					heap_getattr(oldtup, i + 1, tupleDesc, &old_isnull));}/* ---------- * toast_compress_datum - * *	Create a compressed version of a varlena datum * *	If we fail (ie, compressed result is actually bigger than original) *	then return NULL.  We must not use compressed data if it'd expand *	the tuple! * ---------- */Datumtoast_compress_datum(Datum value){	varattrib  *tmp;	tmp = (varattrib *) palloc(sizeof(PGLZ_Header) + VARATT_SIZE(value));	pglz_compress(VARATT_DATA(value), VARATT_SIZE(value) - VARHDRSZ,				  (PGLZ_Header *) tmp,				  PGLZ_strategy_default);	if (VARATT_SIZE(tmp) < VARATT_SIZE(value))	{		/* successful compression */		VARATT_SIZEP(tmp) |= VARATT_FLAG_COMPRESSED;		return PointerGetDatum(tmp);	}	else	{		/* incompressible data */		pfree(tmp);		return PointerGetDatum(NULL);	}}/* ---------- * toast_save_datum - * *	Save one single datum into the secondary relation and return *	a varattrib reference for it. * ---------- */static Datumtoast_save_datum(Relation rel, Datum value){	Relation	toastrel;	Relation	toastidx;	HeapTuple	toasttup;	InsertIndexResult idxres;	TupleDesc	toasttupDesc;	Datum		t_values[3];	char		t_nulls[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;	/*	 * 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 = newoid();	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_nulls[0] = ' ';	t_nulls[1] = ' ';	t_nulls[2] = ' ';	/*	 * Get the data to process	 */	data_p = VARATT_DATA(value);	data_todo = VARATT_SIZE(value) - VARHDRSZ;

⌨️ 快捷键说明

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