Need to return a TupleTableSlot, not just a bare tuple.
<!-- *********************************************** -->
<!-- *********************************************** -->
+<REFENTRY ID="SPI-SPICOPYTUPLEINTOSLOT">
+<REFMETA>
+<REFENTRYTITLE>SPI_copytupleintoslot</REFENTRYTITLE>
+<REFMISCINFO>SPI - Tuple and Descriptor Copy</REFMISCINFO>
+</REFMETA>
+<REFNAMEDIV>
+<REFNAME>SPI_copytupleintoslot
+</REFNAME>
+<REFPURPOSE>
+Makes copy of tuple and descriptor in upper Executor context
+</REFPURPOSE>
+<INDEXTERM ID="IX-SPI-SPICOPYTUPLEINTOSLOT-1"><PRIMARY>SPI</PRIMARY><SECONDARY>copying tuples</SECONDARY></INDEXTERM>
+<INDEXTERM ID="IX-SPI-SPICOPYTUPLEINTOSLOT-2"><PRIMARY>SPI_copytupleintoslot</PRIMARY></INDEXTERM>
+</REFNAMEDIV>
+<REFSYNOPSISDIV>
+<REFSYNOPSISDIVINFO>
+<DATE>1997-12-24</DATE>
+</REFSYNOPSISDIVINFO>
+<SYNOPSIS>
+SPI_copytupleintoslot(<REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>)
+</SYNOPSIS>
+
+<REFSECT2 ID="R2-SPI-SPICOPYTUPLEINTOSLOT-1">
+<REFSECT2INFO>
+<DATE>1997-12-24</DATE>
+</REFSECT2INFO>
+<TITLE>Inputs
+</TITLE>
+<VARIABLELIST>
+<VARLISTENTRY>
+<TERM>
+HeapTuple <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
+</TERM>
+<LISTITEM>
+<PARA>
+Input tuple to be copied
+</PARA>
+</LISTITEM>
+</VARLISTENTRY>
+<VARLISTENTRY>
+<TERM>
+TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
+</TERM>
+<LISTITEM>
+<PARA>
+Input tuple descriptor to be copied
+</PARA>
+</LISTITEM>
+</VARLISTENTRY>
+</VARIABLELIST>
+</REFSECT2>
+
+<REFSECT2 ID="R2-SPI-SPICOPYTUPLEINTOSLOT-2">
+<REFSECT2INFO>
+<DATE>1997-12-24</DATE>
+</REFSECT2INFO>
+<TITLE>Outputs
+</TITLE>
+<VARIABLELIST>
+<VARLISTENTRY>
+<TERM>
+TupleTableSlot *
+</TERM>
+<LISTITEM>
+<PARA>
+Tuple slot containing copied tuple and descriptor
+<SimpleList>
+<Member>
+ <ReturnValue>non-NULL</ReturnValue>
+ if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
+ and <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
+ are not NULL and the copy was successful
+</Member>
+<Member>
+ <ReturnValue>NULL</ReturnValue>
+ only if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
+ or <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
+ is NULL
+</Member>
+</SimpleList>
+</para>
+</LISTITEM>
+</VARLISTENTRY>
+</VARIABLELIST>
+</REFSECT2>
+</REFSYNOPSISDIV>
+
+<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-1">
+<REFSECT1INFO>
+<DATE>1997-12-24</DATE>
+</REFSECT1INFO>
+<TITLE>Description
+</TITLE>
+<PARA>
+<FUNCTION>SPI_copytupleintoslot</FUNCTION>
+ makes a copy of tuple in upper Executor context, returning it in the
+ form of a filled-in TupleTableSlot.
+ See the section on Memory Management.
+</PARA>
+</REFSECT1>
+<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-2">
+<TITLE>Usage
+</TITLE>
+<Para>
+TBD
+</PARA>
+</REFSECT1>
+<!--
+<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-3">
+<TITLE>Algorithm
+</TITLE>
+<PARA>
+</PARA>
+</REFSECT1>
+-->
+<!--
+<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-4">
+<TITLE>Structures
+</TITLE>
+<PARA>None
+</PARA>
+</REFSECT1>
+-->
+</REFENTRY>
+
+<!-- *********************************************** -->
+<!-- *********************************************** -->
+<!-- *********************************************** -->
+
<REFENTRY ID="SPI-SPIMODIFYTUPLE">
<REFMETA>
<REFENTRYTITLE>SPI_modifytuple</REFENTRYTITLE>
<Function>palloc</Function>/<Function>repalloc</Function> or by SPI utility
functions (except for <Function>SPI_copytuple</Function>,
<Function>SPI_copytupledesc</Function>,
+<Function>SPI_copytupleintoslot</Function>,
<Function>SPI_modifytuple</Function>,
<Function>SPI_palloc</Function> and <Function>SPI_repalloc</Function>) are
made in this context.
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.60 2001/10/25 05:49:29 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.61 2001/11/05 19:41:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return ctupdesc;
}
+TupleTableSlot *
+SPI_copytupleintoslot(HeapTuple tuple, TupleDesc tupdesc)
+{
+ MemoryContext oldcxt = NULL;
+ TupleTableSlot *cslot;
+ HeapTuple ctuple;
+ TupleDesc ctupdesc;
+
+ if (tuple == NULL || tupdesc == NULL)
+ {
+ SPI_result = SPI_ERROR_ARGUMENT;
+ return NULL;
+ }
+
+ if (_SPI_curid + 1 == _SPI_connected) /* connected */
+ {
+ if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
+ elog(FATAL, "SPI: stack corrupted");
+ oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
+ }
+
+ ctuple = heap_copytuple(tuple);
+ ctupdesc = CreateTupleDescCopy(tupdesc);
+
+ cslot = MakeTupleTableSlot();
+ ExecSetSlotDescriptor(cslot, ctupdesc, true);
+ cslot = ExecStoreTuple(ctuple, cslot, InvalidBuffer, true);
+
+ if (oldcxt)
+ MemoryContextSwitchTo(oldcxt);
+
+ return cslot;
+}
+
HeapTuple
SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
Datum *Values, char *Nulls)
*
* spi.h
*
- * $Id: spi.h,v 1.31 2001/11/05 17:46:33 momjian Exp $
+ * $Id: spi.h,v 1.32 2001/11/05 19:41:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern HeapTuple SPI_copytuple(HeapTuple tuple);
extern TupleDesc SPI_copytupledesc(TupleDesc tupdesc);
+extern TupleTableSlot *SPI_copytupleintoslot(HeapTuple tuple,
+ TupleDesc tupdesc);
extern HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts,
int *attnum, Datum *Values, char *Nulls);
extern int SPI_fnumber(TupleDesc tupdesc, char *fname);
* procedural language
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.48 2001/10/25 05:50:20 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.49 2001/11/05 19:41:56 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
fcinfo->isnull = estate.retisnull;
- if (!estate.retistuple)
+ if (!estate.retisnull)
{
- estate.retval = exec_cast_value(estate.retval, estate.rettype,
- func->fn_rettype,
- &(func->fn_retinput),
- func->fn_rettypelem,
- -1,
- &fcinfo->isnull);
-
- /*
- * If the functions return type isn't by value, copy the value
- * into upper executor memory context.
- */
- if (!fcinfo->isnull && !func->fn_retbyval)
+ if (estate.retistuple)
+ {
+ /* Copy tuple to upper executor memory */
+ /* Here we need to return a TupleTableSlot not just a tuple */
+ estate.retval = (Datum)
+ SPI_copytupleintoslot((HeapTuple) (estate.retval),
+ estate.rettupdesc);
+ }
+ else
{
- int len;
- Datum tmp;
+ /* Cast value to proper type */
+ estate.retval = exec_cast_value(estate.retval, estate.rettype,
+ func->fn_rettype,
+ &(func->fn_retinput),
+ func->fn_rettypelem,
+ -1,
+ &fcinfo->isnull);
+ /*
+ * If the functions return type isn't by value, copy the value
+ * into upper executor memory context.
+ */
+ if (!fcinfo->isnull && !func->fn_retbyval)
+ {
+ int len;
+ Datum tmp;
- if (func->fn_rettyplen < 0)
- len = VARSIZE(estate.retval);
- else
- len = func->fn_rettyplen;
+ if (func->fn_rettyplen < 0)
+ len = VARSIZE(estate.retval);
+ else
+ len = func->fn_rettyplen;
- tmp = (Datum) SPI_palloc(len);
- memcpy((void *) tmp, (void *) estate.retval, len);
- estate.retval = tmp;
+ tmp = (Datum) SPI_palloc(len);
+ memcpy((void *) tmp, (void *) estate.retval, len);
+ estate.retval = tmp;
+ }
}
}
if (HeapTupleIsValid(rec->tup))
{
- estate->retval = (Datum) SPI_copytuple(rec->tup);
- estate->rettupdesc = SPI_copytupledesc(rec->tupdesc);
+ estate->retval = (Datum) rec->tup;
+ estate->rettupdesc = rec->tupdesc;
estate->retisnull = false;
}
return PLPGSQL_RC_RETURN;
exec_run_select(estate, stmt->expr, 1, NULL);
if (estate->eval_processed > 0)
{
- estate->retval = (Datum) SPI_copytuple(estate->eval_tuptable->vals[0]);
- estate->rettupdesc = SPI_copytupledesc(estate->eval_tuptable->tupdesc);
+ estate->retval = (Datum) estate->eval_tuptable->vals[0];
+ estate->rettupdesc = estate->eval_tuptable->tupdesc;
estate->retisnull = false;
}
-
- /*
- * Okay to clean up here, since we already copied result tuple
- * to upper executor.
- */
- exec_eval_cleanup(estate);
}
return PLPGSQL_RC_RETURN;
}