diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execQual.c | 32 | ||||
-rw-r--r-- | src/backend/executor/execTuples.c | 79 | ||||
-rw-r--r-- | src/backend/executor/functions.c | 1 | ||||
-rw-r--r-- | src/backend/executor/spi.c | 7 |
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); |