Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 0053ceb

Browse files
committed
Fix coredump in plpgsql when trying to return a rowtype result.
Need to return a TupleTableSlot, not just a bare tuple.
1 parent ea08e6c commit 0053ceb

File tree

4 files changed

+206
-35
lines changed

4 files changed

+206
-35
lines changed

doc/src/sgml/spi.sgml

+130
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,135 @@ TBD
12721272
<!-- *********************************************** -->
12731273
<!-- *********************************************** -->
12741274

1275+
<REFENTRY ID="SPI-SPICOPYTUPLEINTOSLOT">
1276+
<REFMETA>
1277+
<REFENTRYTITLE>SPI_copytupleintoslot</REFENTRYTITLE>
1278+
<REFMISCINFO>SPI - Tuple and Descriptor Copy</REFMISCINFO>
1279+
</REFMETA>
1280+
<REFNAMEDIV>
1281+
<REFNAME>SPI_copytupleintoslot
1282+
</REFNAME>
1283+
<REFPURPOSE>
1284+
Makes copy of tuple and descriptor in upper Executor context
1285+
</REFPURPOSE>
1286+
<INDEXTERM ID="IX-SPI-SPICOPYTUPLEINTOSLOT-1"><PRIMARY>SPI</PRIMARY><SECONDARY>copying tuples</SECONDARY></INDEXTERM>
1287+
<INDEXTERM ID="IX-SPI-SPICOPYTUPLEINTOSLOT-2"><PRIMARY>SPI_copytupleintoslot</PRIMARY></INDEXTERM>
1288+
</REFNAMEDIV>
1289+
<REFSYNOPSISDIV>
1290+
<REFSYNOPSISDIVINFO>
1291+
<DATE>1997-12-24</DATE>
1292+
</REFSYNOPSISDIVINFO>
1293+
<SYNOPSIS>
1294+
SPI_copytupleintoslot(<REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>)
1295+
</SYNOPSIS>
1296+
1297+
<REFSECT2 ID="R2-SPI-SPICOPYTUPLEINTOSLOT-1">
1298+
<REFSECT2INFO>
1299+
<DATE>1997-12-24</DATE>
1300+
</REFSECT2INFO>
1301+
<TITLE>Inputs
1302+
</TITLE>
1303+
<VARIABLELIST>
1304+
<VARLISTENTRY>
1305+
<TERM>
1306+
HeapTuple <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
1307+
</TERM>
1308+
<LISTITEM>
1309+
<PARA>
1310+
Input tuple to be copied
1311+
</PARA>
1312+
</LISTITEM>
1313+
</VARLISTENTRY>
1314+
<VARLISTENTRY>
1315+
<TERM>
1316+
TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
1317+
</TERM>
1318+
<LISTITEM>
1319+
<PARA>
1320+
Input tuple descriptor to be copied
1321+
</PARA>
1322+
</LISTITEM>
1323+
</VARLISTENTRY>
1324+
</VARIABLELIST>
1325+
</REFSECT2>
1326+
1327+
<REFSECT2 ID="R2-SPI-SPICOPYTUPLEINTOSLOT-2">
1328+
<REFSECT2INFO>
1329+
<DATE>1997-12-24</DATE>
1330+
</REFSECT2INFO>
1331+
<TITLE>Outputs
1332+
</TITLE>
1333+
<VARIABLELIST>
1334+
<VARLISTENTRY>
1335+
<TERM>
1336+
TupleTableSlot *
1337+
</TERM>
1338+
<LISTITEM>
1339+
<PARA>
1340+
Tuple slot containing copied tuple and descriptor
1341+
<SimpleList>
1342+
<Member>
1343+
<ReturnValue>non-NULL</ReturnValue>
1344+
if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
1345+
and <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
1346+
are not NULL and the copy was successful
1347+
</Member>
1348+
<Member>
1349+
<ReturnValue>NULL</ReturnValue>
1350+
only if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
1351+
or <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
1352+
is NULL
1353+
</Member>
1354+
</SimpleList>
1355+
</para>
1356+
</LISTITEM>
1357+
</VARLISTENTRY>
1358+
</VARIABLELIST>
1359+
</REFSECT2>
1360+
</REFSYNOPSISDIV>
1361+
1362+
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-1">
1363+
<REFSECT1INFO>
1364+
<DATE>1997-12-24</DATE>
1365+
</REFSECT1INFO>
1366+
<TITLE>Description
1367+
</TITLE>
1368+
<PARA>
1369+
<FUNCTION>SPI_copytupleintoslot</FUNCTION>
1370+
makes a copy of tuple in upper Executor context, returning it in the
1371+
form of a filled-in TupleTableSlot.
1372+
See the section on Memory Management.
1373+
</PARA>
1374+
</REFSECT1>
1375+
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-2">
1376+
<TITLE>Usage
1377+
</TITLE>
1378+
<Para>
1379+
TBD
1380+
</PARA>
1381+
</REFSECT1>
1382+
<!--
1383+
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-3">
1384+
<TITLE>Algorithm
1385+
</TITLE>
1386+
<PARA>
1387+
</PARA>
1388+
</REFSECT1>
1389+
-->
1390+
<!--
1391+
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-4">
1392+
<TITLE>Structures
1393+
</TITLE>
1394+
<PARA>None
1395+
</PARA>
1396+
</REFSECT1>
1397+
-->
1398+
</REFENTRY>
1399+
1400+
<!-- *********************************************** -->
1401+
<!-- *********************************************** -->
1402+
<!-- *********************************************** -->
1403+
12751404
<REFENTRY ID="SPI-SPIMODIFYTUPLE">
12761405
<REFMETA>
12771406
<REFENTRYTITLE>SPI_modifytuple</REFENTRYTITLE>
@@ -2695,6 +2824,7 @@ made in this context.
26952824
<Function>palloc</Function>/<Function>repalloc</Function> or by SPI utility
26962825
functions (except for <Function>SPI_copytuple</Function>,
26972826
<Function>SPI_copytupledesc</Function>,
2827+
<Function>SPI_copytupleintoslot</Function>,
26982828
<Function>SPI_modifytuple</Function>,
26992829
<Function>SPI_palloc</Function> and <Function>SPI_repalloc</Function>) are
27002830
made in this context.

src/backend/executor/spi.c

+35-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.60 2001/10/25 05:49:29 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.61 2001/11/05 19:41:56 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -360,6 +360,40 @@ SPI_copytupledesc(TupleDesc tupdesc)
360360
return ctupdesc;
361361
}
362362

363+
TupleTableSlot *
364+
SPI_copytupleintoslot(HeapTuple tuple, TupleDesc tupdesc)
365+
{
366+
MemoryContext oldcxt = NULL;
367+
TupleTableSlot *cslot;
368+
HeapTuple ctuple;
369+
TupleDesc ctupdesc;
370+
371+
if (tuple == NULL || tupdesc == NULL)
372+
{
373+
SPI_result = SPI_ERROR_ARGUMENT;
374+
return NULL;
375+
}
376+
377+
if (_SPI_curid + 1 == _SPI_connected) /* connected */
378+
{
379+
if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
380+
elog(FATAL, "SPI: stack corrupted");
381+
oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
382+
}
383+
384+
ctuple = heap_copytuple(tuple);
385+
ctupdesc = CreateTupleDescCopy(tupdesc);
386+
387+
cslot = MakeTupleTableSlot();
388+
ExecSetSlotDescriptor(cslot, ctupdesc, true);
389+
cslot = ExecStoreTuple(ctuple, cslot, InvalidBuffer, true);
390+
391+
if (oldcxt)
392+
MemoryContextSwitchTo(oldcxt);
393+
394+
return cslot;
395+
}
396+
363397
HeapTuple
364398
SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
365399
Datum *Values, char *Nulls)

src/include/executor/spi.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
*
33
* spi.h
44
*
5-
* $Id: spi.h,v 1.31 2001/11/05 17:46:33 momjian Exp $
5+
* $Id: spi.h,v 1.32 2001/11/05 19:41:56 tgl Exp $
66
*
77
*-------------------------------------------------------------------------
88
*/
@@ -89,6 +89,8 @@ extern int SPI_freeplan(void *plan);
8989

9090
extern HeapTuple SPI_copytuple(HeapTuple tuple);
9191
extern TupleDesc SPI_copytupledesc(TupleDesc tupdesc);
92+
extern TupleTableSlot *SPI_copytupleintoslot(HeapTuple tuple,
93+
TupleDesc tupdesc);
9294
extern HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts,
9395
int *attnum, Datum *Values, char *Nulls);
9496
extern int SPI_fnumber(TupleDesc tupdesc, char *fname);

src/pl/plpgsql/src/pl_exec.c

+38-33
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.48 2001/10/25 05:50:20 momjian Exp $
6+
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.49 2001/11/05 19:41:56 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -400,32 +400,43 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo)
400400

401401
fcinfo->isnull = estate.retisnull;
402402

403-
if (!estate.retistuple)
403+
if (!estate.retisnull)
404404
{
405-
estate.retval = exec_cast_value(estate.retval, estate.rettype,
406-
func->fn_rettype,
407-
&(func->fn_retinput),
408-
func->fn_rettypelem,
409-
-1,
410-
&fcinfo->isnull);
411-
412-
/*
413-
* If the functions return type isn't by value, copy the value
414-
* into upper executor memory context.
415-
*/
416-
if (!fcinfo->isnull && !func->fn_retbyval)
405+
if (estate.retistuple)
406+
{
407+
/* Copy tuple to upper executor memory */
408+
/* Here we need to return a TupleTableSlot not just a tuple */
409+
estate.retval = (Datum)
410+
SPI_copytupleintoslot((HeapTuple) (estate.retval),
411+
estate.rettupdesc);
412+
}
413+
else
417414
{
418-
int len;
419-
Datum tmp;
415+
/* Cast value to proper type */
416+
estate.retval = exec_cast_value(estate.retval, estate.rettype,
417+
func->fn_rettype,
418+
&(func->fn_retinput),
419+
func->fn_rettypelem,
420+
-1,
421+
&fcinfo->isnull);
422+
/*
423+
* If the functions return type isn't by value, copy the value
424+
* into upper executor memory context.
425+
*/
426+
if (!fcinfo->isnull && !func->fn_retbyval)
427+
{
428+
int len;
429+
Datum tmp;
420430

421-
if (func->fn_rettyplen < 0)
422-
len = VARSIZE(estate.retval);
423-
else
424-
len = func->fn_rettyplen;
431+
if (func->fn_rettyplen < 0)
432+
len = VARSIZE(estate.retval);
433+
else
434+
len = func->fn_rettyplen;
425435

426-
tmp = (Datum) SPI_palloc(len);
427-
memcpy((void *) tmp, (void *) estate.retval, len);
428-
estate.retval = tmp;
436+
tmp = (Datum) SPI_palloc(len);
437+
memcpy((void *) tmp, (void *) estate.retval, len);
438+
estate.retval = tmp;
439+
}
429440
}
430441
}
431442

@@ -1619,8 +1630,8 @@ exec_stmt_return(PLpgSQL_execstate * estate, PLpgSQL_stmt_return * stmt)
16191630

16201631
if (HeapTupleIsValid(rec->tup))
16211632
{
1622-
estate->retval = (Datum) SPI_copytuple(rec->tup);
1623-
estate->rettupdesc = SPI_copytupledesc(rec->tupdesc);
1633+
estate->retval = (Datum) rec->tup;
1634+
estate->rettupdesc = rec->tupdesc;
16241635
estate->retisnull = false;
16251636
}
16261637
return PLPGSQL_RC_RETURN;
@@ -1631,16 +1642,10 @@ exec_stmt_return(PLpgSQL_execstate * estate, PLpgSQL_stmt_return * stmt)
16311642
exec_run_select(estate, stmt->expr, 1, NULL);
16321643
if (estate->eval_processed > 0)
16331644
{
1634-
estate->retval = (Datum) SPI_copytuple(estate->eval_tuptable->vals[0]);
1635-
estate->rettupdesc = SPI_copytupledesc(estate->eval_tuptable->tupdesc);
1645+
estate->retval = (Datum) estate->eval_tuptable->vals[0];
1646+
estate->rettupdesc = estate->eval_tuptable->tupdesc;
16361647
estate->retisnull = false;
16371648
}
1638-
1639-
/*
1640-
* Okay to clean up here, since we already copied result tuple
1641-
* to upper executor.
1642-
*/
1643-
exec_eval_cleanup(estate);
16441649
}
16451650
return PLPGSQL_RC_RETURN;
16461651
}

0 commit comments

Comments
 (0)