aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/heap/tuptoaster.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/heap/tuptoaster.c')
-rw-r--r--src/backend/access/heap/tuptoaster.c92
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);
}