Fix coredump in plpgsql when trying to return a rowtype result.
Need to return a TupleTableSlot, not just a bare tuple.
This commit is contained in:
parent
ea08e6cd55
commit
0053cebea5
|
@ -1272,6 +1272,135 @@ TBD
|
||||||
<!-- *********************************************** -->
|
<!-- *********************************************** -->
|
||||||
<!-- *********************************************** -->
|
<!-- *********************************************** -->
|
||||||
|
|
||||||
|
<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">
|
<REFENTRY ID="SPI-SPIMODIFYTUPLE">
|
||||||
<REFMETA>
|
<REFMETA>
|
||||||
<REFENTRYTITLE>SPI_modifytuple</REFENTRYTITLE>
|
<REFENTRYTITLE>SPI_modifytuple</REFENTRYTITLE>
|
||||||
|
@ -2695,6 +2824,7 @@ made in this context.
|
||||||
<Function>palloc</Function>/<Function>repalloc</Function> or by SPI utility
|
<Function>palloc</Function>/<Function>repalloc</Function> or by SPI utility
|
||||||
functions (except for <Function>SPI_copytuple</Function>,
|
functions (except for <Function>SPI_copytuple</Function>,
|
||||||
<Function>SPI_copytupledesc</Function>,
|
<Function>SPI_copytupledesc</Function>,
|
||||||
|
<Function>SPI_copytupleintoslot</Function>,
|
||||||
<Function>SPI_modifytuple</Function>,
|
<Function>SPI_modifytuple</Function>,
|
||||||
<Function>SPI_palloc</Function> and <Function>SPI_repalloc</Function>) are
|
<Function>SPI_palloc</Function> and <Function>SPI_repalloc</Function>) are
|
||||||
made in this context.
|
made in this context.
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -360,6 +360,40 @@ SPI_copytupledesc(TupleDesc tupdesc)
|
||||||
return ctupdesc;
|
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
|
HeapTuple
|
||||||
SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
|
SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
|
||||||
Datum *Values, char *Nulls)
|
Datum *Values, char *Nulls)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* spi.h
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -89,6 +89,8 @@ extern int SPI_freeplan(void *plan);
|
||||||
|
|
||||||
extern HeapTuple SPI_copytuple(HeapTuple tuple);
|
extern HeapTuple SPI_copytuple(HeapTuple tuple);
|
||||||
extern TupleDesc SPI_copytupledesc(TupleDesc tupdesc);
|
extern TupleDesc SPI_copytupledesc(TupleDesc tupdesc);
|
||||||
|
extern TupleTableSlot *SPI_copytupleintoslot(HeapTuple tuple,
|
||||||
|
TupleDesc tupdesc);
|
||||||
extern HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts,
|
extern HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts,
|
||||||
int *attnum, Datum *Values, char *Nulls);
|
int *attnum, Datum *Values, char *Nulls);
|
||||||
extern int SPI_fnumber(TupleDesc tupdesc, char *fname);
|
extern int SPI_fnumber(TupleDesc tupdesc, char *fname);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
|
@ -400,32 +400,43 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo)
|
||||||
|
|
||||||
fcinfo->isnull = estate.retisnull;
|
fcinfo->isnull = estate.retisnull;
|
||||||
|
|
||||||
if (!estate.retistuple)
|
if (!estate.retisnull)
|
||||||
{
|
{
|
||||||
estate.retval = exec_cast_value(estate.retval, estate.rettype,
|
if (estate.retistuple)
|
||||||
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;
|
/* Copy tuple to upper executor memory */
|
||||||
Datum tmp;
|
/* Here we need to return a TupleTableSlot not just a tuple */
|
||||||
|
estate.retval = (Datum)
|
||||||
|
SPI_copytupleintoslot((HeapTuple) (estate.retval),
|
||||||
|
estate.rettupdesc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* 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)
|
if (func->fn_rettyplen < 0)
|
||||||
len = VARSIZE(estate.retval);
|
len = VARSIZE(estate.retval);
|
||||||
else
|
else
|
||||||
len = func->fn_rettyplen;
|
len = func->fn_rettyplen;
|
||||||
|
|
||||||
tmp = (Datum) SPI_palloc(len);
|
tmp = (Datum) SPI_palloc(len);
|
||||||
memcpy((void *) tmp, (void *) estate.retval, len);
|
memcpy((void *) tmp, (void *) estate.retval, len);
|
||||||
estate.retval = tmp;
|
estate.retval = tmp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1619,8 +1630,8 @@ exec_stmt_return(PLpgSQL_execstate * estate, PLpgSQL_stmt_return * stmt)
|
||||||
|
|
||||||
if (HeapTupleIsValid(rec->tup))
|
if (HeapTupleIsValid(rec->tup))
|
||||||
{
|
{
|
||||||
estate->retval = (Datum) SPI_copytuple(rec->tup);
|
estate->retval = (Datum) rec->tup;
|
||||||
estate->rettupdesc = SPI_copytupledesc(rec->tupdesc);
|
estate->rettupdesc = rec->tupdesc;
|
||||||
estate->retisnull = false;
|
estate->retisnull = false;
|
||||||
}
|
}
|
||||||
return PLPGSQL_RC_RETURN;
|
return PLPGSQL_RC_RETURN;
|
||||||
|
@ -1631,16 +1642,10 @@ exec_stmt_return(PLpgSQL_execstate * estate, PLpgSQL_stmt_return * stmt)
|
||||||
exec_run_select(estate, stmt->expr, 1, NULL);
|
exec_run_select(estate, stmt->expr, 1, NULL);
|
||||||
if (estate->eval_processed > 0)
|
if (estate->eval_processed > 0)
|
||||||
{
|
{
|
||||||
estate->retval = (Datum) SPI_copytuple(estate->eval_tuptable->vals[0]);
|
estate->retval = (Datum) estate->eval_tuptable->vals[0];
|
||||||
estate->rettupdesc = SPI_copytupledesc(estate->eval_tuptable->tupdesc);
|
estate->rettupdesc = estate->eval_tuptable->tupdesc;
|
||||||
estate->retisnull = false;
|
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;
|
return PLPGSQL_RC_RETURN;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue