summaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execQual.c32
-rw-r--r--src/backend/executor/execTuples.c79
-rw-r--r--src/backend/executor/functions.c1
-rw-r--r--src/backend/executor/spi.c7
4 files changed, 77 insertions, 42 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index d3c2f437d1..d5e828967f 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -882,8 +882,6 @@ ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate, ExprContext *econtext,
{
Var *variable = (Var *) wrvstate->xprstate.expr;
TupleTableSlot *slot = econtext->ecxt_scantuple;
- HeapTuple tuple;
- TupleDesc tupleDesc;
HeapTupleHeader dtuple;
if (isDone)
@@ -894,32 +892,20 @@ ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate, ExprContext *econtext,
if (wrvstate->wrv_junkFilter != NULL)
slot = ExecFilterJunk(wrvstate->wrv_junkFilter, slot);
- tuple = ExecFetchSlotTuple(slot);
- tupleDesc = slot->tts_tupleDescriptor;
-
/*
- * We have to make a copy of the tuple so we can safely insert the Datum
- * overhead fields, which are not set in on-disk tuples.
+ * Copy the slot tuple and make sure any toasted fields get detoasted.
*/
- dtuple = (HeapTupleHeader) palloc(tuple->t_len);
- memcpy((char *) dtuple, (char *) tuple->t_data, tuple->t_len);
-
- HeapTupleHeaderSetDatumLength(dtuple, tuple->t_len);
+ dtuple = DatumGetHeapTupleHeader(ExecFetchSlotTupleDatum(slot));
/*
- * If the Var identifies a named composite type, label the tuple with that
- * type; otherwise use what is in the tupleDesc.
+ * If the Var identifies a named composite type, label the datum with that
+ * type; otherwise we'll use the slot's info.
*/
if (variable->vartype != RECORDOID)
{
HeapTupleHeaderSetTypeId(dtuple, variable->vartype);
HeapTupleHeaderSetTypMod(dtuple, variable->vartypmod);
}
- else
- {
- HeapTupleHeaderSetTypeId(dtuple, tupleDesc->tdtypeid);
- HeapTupleHeaderSetTypMod(dtuple, tupleDesc->tdtypmod);
- }
return PointerGetDatum(dtuple);
}
@@ -977,13 +963,13 @@ ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, ExprContext *econtext,
}
/*
- * We have to make a copy of the tuple so we can safely insert the Datum
- * overhead fields, which are not set in on-disk tuples.
+ * Copy the slot tuple and make sure any toasted fields get detoasted.
*/
- dtuple = (HeapTupleHeader) palloc(tuple->t_len);
- memcpy((char *) dtuple, (char *) tuple->t_data, tuple->t_len);
+ dtuple = DatumGetHeapTupleHeader(ExecFetchSlotTupleDatum(slot));
- HeapTupleHeaderSetDatumLength(dtuple, tuple->t_len);
+ /*
+ * Reset datum's type ID fields to match the Var.
+ */
HeapTupleHeaderSetTypeId(dtuple, variable->vartype);
HeapTupleHeaderSetTypMod(dtuple, variable->vartypmod);
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 7b5ba41f5f..97bd26a854 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -91,6 +91,7 @@
*/
#include "postgres.h"
+#include "access/tuptoaster.h"
#include "funcapi.h"
#include "catalog/pg_type.h"
#include "nodes/nodeFuncs.h"
@@ -768,27 +769,21 @@ ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
* ExecFetchSlotTupleDatum
* Fetch the slot's tuple as a composite-type Datum.
*
- * We convert the slot's contents to local physical-tuple form,
- * and fill in the Datum header fields. Note that the result
- * always points to storage owned by the slot.
+ * The result is always freshly palloc'd in the caller's memory context.
* --------------------------------
*/
Datum
ExecFetchSlotTupleDatum(TupleTableSlot *slot)
{
HeapTuple tup;
- HeapTupleHeader td;
TupleDesc tupdesc;
- /* Make sure we can scribble on the slot contents ... */
- tup = ExecMaterializeSlot(slot);
- /* ... and set up the composite-Datum header fields, in case not done */
- td = tup->t_data;
+ /* Fetch slot's contents in regular-physical-tuple form */
+ tup = ExecFetchSlotTuple(slot);
tupdesc = slot->tts_tupleDescriptor;
- HeapTupleHeaderSetDatumLength(td, tup->t_len);
- HeapTupleHeaderSetTypeId(td, tupdesc->tdtypeid);
- HeapTupleHeaderSetTypMod(td, tupdesc->tdtypmod);
- return PointerGetDatum(td);
+
+ /* Convert to Datum form */
+ return heap_copy_tuple_as_datum(tup, tupdesc);
}
/* --------------------------------
@@ -1192,6 +1187,66 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
}
/*
+ * HeapTupleHeaderGetDatum - convert a HeapTupleHeader pointer to a Datum.
+ *
+ * This must *not* get applied to an on-disk tuple; the tuple should be
+ * freshly made by heap_form_tuple or some wrapper routine for it (such as
+ * BuildTupleFromCStrings). Be sure also that the tupledesc used to build
+ * the tuple has a properly "blessed" rowtype.
+ *
+ * Formerly this was a macro equivalent to PointerGetDatum, relying on the
+ * fact that heap_form_tuple fills in the appropriate tuple header fields
+ * for a composite Datum. However, we now require that composite Datums not
+ * contain any external TOAST pointers. We do not want heap_form_tuple itself
+ * to enforce that; more specifically, the rule applies only to actual Datums
+ * and not to HeapTuple structures. Therefore, HeapTupleHeaderGetDatum is
+ * now a function that detects whether there are externally-toasted fields
+ * and constructs a new tuple with inlined fields if so. We still need
+ * heap_form_tuple to insert the Datum header fields, because otherwise this
+ * code would have no way to obtain a tupledesc for the tuple.
+ *
+ * Note that if we do build a new tuple, it's palloc'd in the current
+ * memory context. Beware of code that changes context between the initial
+ * heap_form_tuple/etc call and calling HeapTuple(Header)GetDatum.
+ *
+ * For performance-critical callers, it could be worthwhile to take extra
+ * steps to ensure that there aren't TOAST pointers in the output of
+ * heap_form_tuple to begin with. It's likely however that the costs of the
+ * typcache lookup and tuple disassembly/reassembly are swamped by TOAST
+ * dereference costs, so that the benefits of such extra effort would be
+ * minimal.
+ *
+ * XXX it would likely be better to create wrapper functions that produce
+ * a composite Datum from the field values in one step. However, there's
+ * enough code using the existing APIs that we couldn't get rid of this
+ * hack anytime soon.
+ */
+Datum
+HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
+{
+ Datum result;
+ TupleDesc tupDesc;
+
+ /* No work if there are no external TOAST pointers in the tuple */
+ if (!HeapTupleHeaderHasExternal(tuple))
+ return PointerGetDatum(tuple);
+
+ /* Use the type data saved by heap_form_tuple to look up the rowtype */
+ tupDesc = lookup_rowtype_tupdesc(HeapTupleHeaderGetTypeId(tuple),
+ HeapTupleHeaderGetTypMod(tuple));
+
+ /* And do the flattening */
+ result = toast_flatten_tuple_to_datum(tuple,
+ HeapTupleHeaderGetDatumLength(tuple),
+ tupDesc);
+
+ ReleaseTupleDesc(tupDesc);
+
+ return result;
+}
+
+
+/*
* Functions for sending tuples to the frontend (or other specified destination)
* as though it is a SELECT result. These are used by utility commands that
* need to project directly to the destination and don't need or want full
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index c6f6451466..b5fa130579 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -581,7 +581,6 @@ postquel_get_single_result(TupleTableSlot *slot,
/* We must return the whole tuple as a Datum. */
fcinfo->isnull = false;
value = ExecFetchSlotTupleDatum(slot);
- value = datumCopy(value, fcache->typbyval, fcache->typlen);
}
else
{
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 3cffc2ad72..0f8f742caa 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -639,12 +639,7 @@ SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc)
oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
}
- dtup = (HeapTupleHeader) palloc(tuple->t_len);
- memcpy((char *) dtup, (char *) tuple->t_data, tuple->t_len);
-
- HeapTupleHeaderSetDatumLength(dtup, tuple->t_len);
- HeapTupleHeaderSetTypeId(dtup, tupdesc->tdtypeid);
- HeapTupleHeaderSetTypMod(dtup, tupdesc->tdtypmod);
+ dtup = DatumGetHeapTupleHeader(heap_copy_tuple_as_datum(tuple, tupdesc));
if (oldcxt)
MemoryContextSwitchTo(oldcxt);