diff options
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/access/heap/tuptoaster.c | 81 | ||||
| -rw-r--r-- | src/backend/utils/cache/catcache.c | 19 | 
2 files changed, 99 insertions, 1 deletions
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index 1fc4801e23e..1f66d172827 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -929,6 +929,87 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,  /* ---------- + * toast_flatten_tuple - + * + *	"Flatten" a tuple to contain no out-of-line toasted fields. + *	(This does not eliminate compressed or short-header datums.) + * ---------- + */ +HeapTuple +toast_flatten_tuple(HeapTuple tup, TupleDesc tupleDesc) +{ +	HeapTuple	new_tuple; +	Form_pg_attribute *att = tupleDesc->attrs; +	int			numAttrs = tupleDesc->natts; +	int			i; +	Datum		toast_values[MaxTupleAttributeNumber]; +	bool		toast_isnull[MaxTupleAttributeNumber]; +	bool		toast_free[MaxTupleAttributeNumber]; + +	/* +	 * Break down the tuple into fields. +	 */ +	Assert(numAttrs <= MaxTupleAttributeNumber); +	heap_deform_tuple(tup, 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] && att[i]->attlen == -1) +		{ +			struct varlena *new_value; + +			new_value = (struct varlena *) DatumGetPointer(toast_values[i]); +			if (VARATT_IS_EXTERNAL(new_value)) +			{ +				new_value = toast_fetch_datum(new_value); +				toast_values[i] = PointerGetDatum(new_value); +				toast_free[i] = true; +			} +		} +	} + +	/* +	 * Form the reconfigured tuple. +	 */ +	new_tuple = heap_form_tuple(tupleDesc, toast_values, toast_isnull); + +	/* +	 * Be sure to copy the tuple's OID and identity fields.  We also make a +	 * point of copying visibility info, just in case anybody looks at those +	 * fields in a syscache entry. +	 */ +	if (tupleDesc->tdhasoid) +		HeapTupleSetOid(new_tuple, HeapTupleGetOid(tup)); + +	new_tuple->t_self = tup->t_self; +	new_tuple->t_tableOid = tup->t_tableOid; + +	new_tuple->t_data->t_choice = tup->t_data->t_choice; +	new_tuple->t_data->t_ctid = tup->t_data->t_ctid; +	new_tuple->t_data->t_infomask &= ~HEAP_XACT_MASK; +	new_tuple->t_data->t_infomask |= +		tup->t_data->t_infomask & HEAP_XACT_MASK; +	new_tuple->t_data->t_infomask2 &= ~HEAP2_XACT_MASK; +	new_tuple->t_data->t_infomask2 |= +		tup->t_data->t_infomask2 & HEAP2_XACT_MASK; + +	/* +	 * Free allocated temp values +	 */ +	for (i = 0; i < numAttrs; i++) +		if (toast_free[i]) +			pfree(DatumGetPointer(toast_values[i])); + +	return new_tuple; +} + + +/* ----------   * toast_flatten_tuple_attribute -   *   *	If a Datum is of composite type, "flatten" it to contain no toasted fields. diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index 0692b5b014a..970a137ff33 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -19,6 +19,7 @@  #include "access/heapam.h"  #include "access/relscan.h"  #include "access/sysattr.h" +#include "access/tuptoaster.h"  #include "access/valid.h"  #include "catalog/pg_operator.h"  #include "catalog/pg_type.h" @@ -1596,16 +1597,32 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp,  						uint32 hashValue, Index hashIndex, bool negative)  {  	CatCTup    *ct; +	HeapTuple	dtp;  	MemoryContext oldcxt;  	/* +	 * If there are any out-of-line toasted fields in the tuple, expand them +	 * in-line.  This saves cycles during later use of the catcache entry, +	 * and also protects us against the possibility of the toast tuples being +	 * freed before we attempt to fetch them, in case of something using a +	 * slightly stale catcache entry. +	 */ +	if (HeapTupleHasExternal(ntp)) +		dtp = toast_flatten_tuple(ntp, cache->cc_tupdesc); +	else +		dtp = ntp; + +	/*  	 * Allocate CatCTup header in cache memory, and copy the tuple there too.  	 */  	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);  	ct = (CatCTup *) palloc(sizeof(CatCTup)); -	heap_copytuple_with_tuple(ntp, &ct->tuple); +	heap_copytuple_with_tuple(dtp, &ct->tuple);  	MemoryContextSwitchTo(oldcxt); +	if (dtp != ntp) +		heap_freetuple(dtp); +  	/*  	 * Finish initializing the CatCTup header, and add it to the cache's  	 * linked list and counts.  | 
