diff options
-rw-r--r-- | src/backend/access/heap/tuptoaster.c | 78 | ||||
-rw-r--r-- | src/backend/utils/cache/catcache.c | 19 | ||||
-rw-r--r-- | src/include/access/tuptoaster.h | 9 |
3 files changed, 105 insertions, 1 deletions
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index 0f1d2a9e7db..33c408db59c 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -810,6 +810,84 @@ 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) + { + varattrib *new_value; + + new_value = (varattrib *) 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; + + /* + * 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 0b27bc034c0..bca544fe96f 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -17,6 +17,7 @@ #include "access/genam.h" #include "access/hash.h" #include "access/heapam.h" +#include "access/tuptoaster.h" #include "access/valid.h" #include "catalog/pg_operator.h" #include "catalog/pg_type.h" @@ -1634,16 +1635,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. diff --git a/src/include/access/tuptoaster.h b/src/include/access/tuptoaster.h index 6f2686106f9..bf70a8abb7e 100644 --- a/src/include/access/tuptoaster.h +++ b/src/include/access/tuptoaster.h @@ -113,6 +113,15 @@ extern varattrib *heap_tuple_untoast_attr_slice(varattrib *attr, int32 slicelength); /* ---------- + * toast_flatten_tuple - + * + * "Flatten" a tuple to contain no out-of-line toasted fields. + * (This does not eliminate compressed or short-header datums.) + * ---------- + */ +extern HeapTuple toast_flatten_tuple(HeapTuple tup, TupleDesc tupleDesc); + +/* ---------- * toast_flatten_tuple_attribute - * * If a Datum is of composite type, "flatten" it to contain no toasted fields. |