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

📄 tuptoaster.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
					new_value = heap_tuple_fetch_attr(new_value);				toast_values[i] = PointerGetDatum(new_value);				toast_free[i] = true;				need_change = true;				need_free = true;			}			/*			 * Remember the size of this attribute			 */			toast_sizes[i] = VARSIZE_ANY(new_value);		}		else		{			/*			 * Not a varlena attribute, plain storage always			 */			toast_action[i] = 'p';		}	}	/* ----------	 * 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	 * ----------	 */	/* compute header overhead --- this should match heap_form_tuple() */	hoff = offsetof(HeapTupleHeaderData, t_bits);	if (has_nulls)		hoff += BITMAPLEN(numAttrs);	if (newtup->t_data->t_infomask & HEAP_HASOID)		hoff += sizeof(Oid);	hoff = MAXALIGN(hoff);	Assert(hoff == newtup->t_data->t_hoff);	/* now convert to a limit on the tuple data size */	maxDataLen = TOAST_TUPLE_TARGET - hoff;	/*	 * Look for attributes with attstorage 'x' to compress	 */	while (heap_compute_data_size(tupleDesc,								  toast_values, toast_isnull) > maxDataLen)	{		int			biggest_attno = -1;		int32		biggest_size = MAXALIGN(TOAST_POINTER_SIZE);		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_EXTERNAL(toast_values[i]))				continue;		/* can't happen, toast_action would be 'p' */			if (VARATT_IS_COMPRESSED(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] = VARSIZE(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.	But skip this if there's no toast table to push them to.	 */	while (heap_compute_data_size(tupleDesc,								  toast_values, toast_isnull) > maxDataLen &&		   rel->rd_rel->reltoastrelid != InvalidOid)	{		int			biggest_attno = -1;		int32		biggest_size = MAXALIGN(TOAST_POINTER_SIZE);		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;		/* can't happen, toast_action would be 'p' */			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],										   use_wal, use_fsm);		if (toast_free[i])			pfree(DatumGetPointer(old_value));		toast_free[i] = true;		need_change = true;		need_free = true;	}	/*	 * Round 3 - this time we take attributes with storage 'm' into	 * compression	 */	while (heap_compute_data_size(tupleDesc,								  toast_values, toast_isnull) > maxDataLen)	{		int			biggest_attno = -1;		int32		biggest_size = MAXALIGN(TOAST_POINTER_SIZE);		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_EXTERNAL(toast_values[i]))				continue;		/* can't happen, toast_action would be 'p' */			if (VARATT_IS_COMPRESSED(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] = VARSIZE(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, if possible.	 */	while (heap_compute_data_size(tupleDesc,								  toast_values, toast_isnull) > maxDataLen &&		   rel->rd_rel->reltoastrelid != InvalidOid)	{		int			biggest_attno = -1;		int32		biggest_size = MAXALIGN(TOAST_POINTER_SIZE);		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;		/* can't happen, toast_action would be 'p' */			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],										   use_wal, use_fsm);		if (toast_free[i])			pfree(DatumGetPointer(old_value));		toast_free[i] = true;		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;		HeapTupleHeader new_data;		int32		new_len;		int32		new_data_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_data_len = heap_compute_data_size(tupleDesc,											  toast_values, toast_isnull);		new_len += new_data_len;		/*		 * Allocate and zero the space needed, and fill HeapTupleData fields.		 */		result_tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + new_len);		result_tuple->t_len = new_len;		result_tuple->t_self = newtup->t_self;		result_tuple->t_tableOid = newtup->t_tableOid;		new_data = (HeapTupleHeader) ((char *) result_tuple + HEAPTUPLESIZE);		result_tuple->t_data = new_data;		/*		 * Put the existing tuple header and the changed values into place		 */		memcpy(new_data, olddata, olddata->t_hoff);		heap_fill_tuple(tupleDesc,						toast_values,						toast_isnull,						(char *) new_data + olddata->t_hoff,						new_data_len,						&(new_data->t_infomask),						has_nulls ? new_data->t_bits : NULL);	}	else		result_tuple = newtup;	/*	 * 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, toast_oldvalues[i]);	return result_tuple;}/* ---------- * toast_flatten_tuple_attribute - * *	If a Datum is of composite type, "flatten" it to contain no toasted fields. *	This must be invoked on any potentially-composite field that is to be *	inserted into a tuple.	Doing this preserves the invariant that toasting *	goes only one level deep in a tuple. * *	Note that flattening does not mean expansion of short-header varlenas, *	so in one sense toasting is allowed within composite datums. * ---------- */Datumtoast_flatten_tuple_attribute(Datum value,							  Oid typeId, int32 typeMod){	TupleDesc	tupleDesc;	HeapTupleHeader olddata;	HeapTupleHeader new_data;	int32		new_len;	int32		new_data_len;	HeapTupleData tmptup;	Form_pg_attribute *att;	int			numAttrs;	int			i;	bool		need_change = false;	bool		has_nulls = false;	Datum		toast_values[MaxTupleAttributeNumber];	bool		toast_isnull[MaxTupleAttributeNumber];	bool		toast_free[MaxTupleAttributeNumber];	/*	 * See if it's a composite type, and get the tupdesc if so.	 */	tupleDesc = lookup_rowtype_tupdesc_noerror(typeId, typeMod, true);	if (tupleDesc == NULL)		return value;			/* not a composite type */	att = tupleDesc->attrs;	numAttrs = tupleDesc->natts;	/*	 * Break down the tuple into fields.	 */	olddata = DatumGetHeapTupleHeader(value);	Assert(typeId == HeapTupleHeaderGetTypeId(olddata));	Assert(typeMod == HeapTupleHeaderGetTypMod(olddata));	/* Build a temporary HeapTuple control structure */	tmptup.t_len = HeapTupleHeaderGetDatumLength(olddata);	ItemPointerSetInvalid(&(tmptup.t_self));	tmptup.t_tableOid = InvalidOid;	tmptup.t_data = olddata;	Assert(numAttrs <= MaxTupleAttributeNumber);	heap_deform_tuple(&tmptup, tupleDesc, toast_values, toast_isnull);	memset(toast_free, 0, numAttrs * sizeof(bool));	for (i = 0; i < numAttrs; i++)	{		/*		 * Look at non-null varlena attributes		 */		if (toast_isnull[i])			has_nulls = true;		else if (att[i]->attlen == -1)		{			struct varlena *new_value;			new_value = (struct varlena *) DatumGetPointer(toast_values[i]);			if (VARATT_IS_EXTERNAL(new_value) ||				VARATT_IS_COMPRESSED(new_value))			{				new_value = heap_tuple_untoast_attr(new_value);				toast_values[i] = PointerGetDatum(new_value);				toast_free[i] = true;				need_change = true;			}		}	}	/*	 * If nothing to untoast, just return the original tuple.	 */	if (!need_change)	{		ReleaseTupleDesc(tupleDesc);		return value;	}	/*	 * 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_data_len = heap_compute_data_size(tupleDesc,										  toast_values, toast_isnull);	new_len += new_data_len;	new_data = (HeapTupleHeader) palloc0(new_len);	/*	 * Put the tuple header and the changed values into place	 */	memcpy(new_data, olddata, olddata->t_hoff);	HeapTupleHeaderSetDatumLength(new_data, new_len);	heap_fill_tuple(tupleDesc,					toast_values,					toast_isnull,					(char *) new_data + olddata->t_hoff,					new_data_len,					&(new_data->t_infomask),					has_nulls ? new_data->t_bits : NULL);	/*	 * Free allocated temp values	 */	for (i = 0; i < numAttrs; i++)		if (toast_free[i])			pfree(DatumGetPointer(toast_values[i]));	ReleaseTupleDesc(tupleDesc);	return PointerGetDatum(new_data);}/* ---------- * 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! * *	We use VAR{SIZE,DATA}_ANY so we can handle short varlenas here without *	copying them.  But we can't handle external or compressed datums. * ---------- */Datumtoast_compress_datum(Datum value){	struct varlena *tmp;	int32		valsize = VARSIZE_ANY_EXHDR(value);	Assert(!VARATT_IS_EXTERNAL(value));	Assert(!VARATT_IS_COMPRESSED(value));	/*	 * No point in wasting a palloc cycle if value is too short for	 * compression	 */	if (valsize < PGLZ_strategy_default->min_input_size)		return PointerGetDatum(NULL);	tmp = (struct varlena *) palloc(PGLZ_MAX_OUTPUT(valsize));	if (pglz_compress(VARDATA_ANY(value), valsize,					  (PGLZ_Header *) tmp, PGLZ_strategy_default) &&		VARSIZE(tmp) < VARSIZE_ANY(value))	{		/* successful compression */		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 Datum reference for it. * ---------- */static Datumtoast_save_datum(Relation rel, Datum value,				 bool use_wal, bool use_fsm){	Relation	toastrel;	Relation	toastidx;	HeapTuple	toasttup;	TupleDesc	toasttupDesc;	Datum		t_values[3];	bool		t_isnull[3];	CommandId	mycid = GetCurrentCommandId(true);	struct varlena *result;	struct varatt_external toast_pointer;	struct	{		struct varlena hdr;		char		data[TOAST_MAX_CHUNK_SIZE];	/* make struct big enough */		int32		align_it;	/* ensure struct is aligned well enough */	}			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.	 */

⌨️ 快捷键说明

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