diff options
Diffstat (limited to 'src/backend/access/heap/tuptoaster.c')
-rw-r--r-- | src/backend/access/heap/tuptoaster.c | 92 |
1 files changed, 44 insertions, 48 deletions
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index 050f048a9b0..b340e469834 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -944,6 +944,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, * * "Flatten" a tuple to contain no out-of-line toasted fields. * (This does not eliminate compressed or short-header datums.) + * + * Note: we expect the caller already checked HeapTupleHasExternal(tup), + * so there is no need for a short-circuit path. * ---------- */ HeapTuple @@ -1021,59 +1024,61 @@ toast_flatten_tuple(HeapTuple tup, TupleDesc tupleDesc) /* ---------- - * toast_flatten_tuple_attribute - + * toast_flatten_tuple_to_datum - + * + * "Flatten" a tuple containing out-of-line toasted fields into a Datum. + * The result is always palloc'd in the current memory context. + * + * We have a general rule that Datums of container types (rows, arrays, + * ranges, etc) must not contain any external TOAST pointers. Without + * this rule, we'd have to look inside each Datum when preparing a tuple + * for storage, which would be expensive and would fail to extend cleanly + * to new sorts of container types. + * + * However, we don't want to say that tuples represented as HeapTuples + * can't contain toasted fields, so instead this routine should be called + * when such a HeapTuple is being converted into a Datum. * - * 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. + * While we're at it, we decompress any compressed fields too. This is not + * necessary for correctness, but reflects an expectation that compression + * will be more effective if applied to the whole tuple not individual + * fields. We are not so concerned about that that we want to deconstruct + * and reconstruct tuples just to get rid of compressed fields, however. + * So callers typically won't call this unless they see that the tuple has + * at least one external field. * - * Note that flattening does not mean expansion of short-header varlenas, - * so in one sense toasting is allowed within composite datums. + * On the other hand, in-line short-header varlena fields are left alone. + * If we "untoasted" them here, they'd just get changed back to short-header + * format anyway within heap_fill_tuple. * ---------- */ Datum -toast_flatten_tuple_attribute(Datum value, - Oid typeId, int32 typeMod) +toast_flatten_tuple_to_datum(HeapTupleHeader tup, + uint32 tup_len, + TupleDesc tupleDesc) { - TupleDesc tupleDesc; - HeapTupleHeader olddata; HeapTupleHeader new_data; int32 new_header_len; int32 new_data_len; int32 new_tuple_len; HeapTupleData tmptup; - Form_pg_attribute *att; - int numAttrs; + Form_pg_attribute *att = tupleDesc->attrs; + int numAttrs = tupleDesc->natts; 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); + tmptup.t_len = tup_len; ItemPointerSetInvalid(&(tmptup.t_self)); tmptup.t_tableOid = InvalidOid; - tmptup.t_data = olddata; + tmptup.t_data = tup; + /* + * Break down the tuple into fields. + */ Assert(numAttrs <= MaxTupleAttributeNumber); heap_deform_tuple(&tmptup, tupleDesc, toast_values, toast_isnull); @@ -1097,21 +1102,11 @@ toast_flatten_tuple_attribute(Datum 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. * * This should match the reconstruction code in toast_insert_or_update. @@ -1119,7 +1114,7 @@ toast_flatten_tuple_attribute(Datum value, new_header_len = offsetof(HeapTupleHeaderData, t_bits); if (has_nulls) new_header_len += BITMAPLEN(numAttrs); - if (olddata->t_infomask & HEAP_HASOID) + if (tup->t_infomask & HEAP_HASOID) new_header_len += sizeof(Oid); new_header_len = MAXALIGN(new_header_len); new_data_len = heap_compute_data_size(tupleDesc, @@ -1131,14 +1126,16 @@ toast_flatten_tuple_attribute(Datum value, /* * Copy the existing tuple header, but adjust natts and t_hoff. */ - memcpy(new_data, olddata, offsetof(HeapTupleHeaderData, t_bits)); + memcpy(new_data, tup, offsetof(HeapTupleHeaderData, t_bits)); HeapTupleHeaderSetNatts(new_data, numAttrs); new_data->t_hoff = new_header_len; - if (olddata->t_infomask & HEAP_HASOID) - HeapTupleHeaderSetOid(new_data, HeapTupleHeaderGetOid(olddata)); + if (tup->t_infomask & HEAP_HASOID) + HeapTupleHeaderSetOid(new_data, HeapTupleHeaderGetOid(tup)); - /* Reset the datum length field, too */ + /* Set the composite-Datum header fields correctly */ HeapTupleHeaderSetDatumLength(new_data, new_tuple_len); + HeapTupleHeaderSetTypeId(new_data, tupleDesc->tdtypeid); + HeapTupleHeaderSetTypMod(new_data, tupleDesc->tdtypmod); /* Copy over the data, and fill the null bitmap if needed */ heap_fill_tuple(tupleDesc, @@ -1155,7 +1152,6 @@ toast_flatten_tuple_attribute(Datum value, for (i = 0; i < numAttrs; i++) if (toast_free[i]) pfree(DatumGetPointer(toast_values[i])); - ReleaseTupleDesc(tupleDesc); return PointerGetDatum(new_data); } |