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.c133
1 files changed, 128 insertions, 5 deletions
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c
index f206a3f28eb..c36cc42309e 100644
--- a/src/backend/access/heap/tuptoaster.c
+++ b/src/backend/access/heap/tuptoaster.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.42 2004/06/04 20:35:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.43 2004/06/05 01:55:04 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -35,6 +35,7 @@
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/pg_lzcompress.h"
+#include "utils/typcache.h"
#undef TOAST_DEBUG
@@ -458,10 +459,10 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
* still in the tuple must be someone else's we cannot reuse.
* Expand it to plain (and, probably, toast it again below).
*/
- if (VARATT_IS_EXTERNAL(DatumGetPointer(toast_values[i])))
+ if (VARATT_IS_EXTERNAL(new_value))
{
- toast_values[i] = PointerGetDatum(heap_tuple_untoast_attr(
- (varattrib *) DatumGetPointer(toast_values[i])));
+ new_value = heap_tuple_untoast_attr(new_value);
+ toast_values[i] = PointerGetDatum(new_value);
toast_free[i] = true;
need_change = true;
need_free = true;
@@ -470,7 +471,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
/*
* Remember the size of this attribute
*/
- toast_sizes[i] = VARATT_SIZE(DatumGetPointer(toast_values[i]));
+ toast_sizes[i] = VARATT_SIZE(new_value);
}
else
{
@@ -786,6 +787,128 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
/* ----------
+ * 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.
+ * ----------
+ */
+Datum
+toast_flatten_tuple_attribute(Datum value,
+ Oid typeId, int32 typeMod)
+{
+ TupleDesc tupleDesc;
+ HeapTupleHeader olddata;
+ HeapTupleHeader new_data;
+ int32 new_len;
+ HeapTupleData tmptup;
+ Form_pg_attribute *att;
+ int numAttrs;
+ int i;
+ bool need_change = false;
+ bool has_nulls = false;
+ Datum toast_values[MaxTupleAttributeNumber];
+ char toast_nulls[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_deformtuple(&tmptup, tupleDesc, toast_values, toast_nulls);
+
+ memset(toast_free, 0, numAttrs * sizeof(bool));
+
+ for (i = 0; i < numAttrs; i++)
+ {
+ /*
+ * Look at non-null varlena attributes
+ */
+ if (toast_nulls[i] == 'n')
+ has_nulls = true;
+ else if (att[i]->attlen == -1)
+ {
+ varattrib *new_value;
+
+ new_value = (varattrib *) DatumGetPointer(toast_values[i]);
+ if (VARATT_IS_EXTENDED(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)
+ 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_len += ComputeDataSize(tupleDesc, toast_values, toast_nulls);
+
+ 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);
+
+ DataFill((char *) new_data + olddata->t_hoff,
+ tupleDesc,
+ toast_values,
+ toast_nulls,
+ &(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]));
+
+ return PointerGetDatum(new_data);
+}
+
+
+/* ----------
* toast_compress_datum -
*
* Create a compressed version of a varlena datum