]> granicus.if.org Git - postgresql/commitdiff
Fix coredump in plpgsql when trying to return a rowtype result.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 5 Nov 2001 19:41:56 +0000 (19:41 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 5 Nov 2001 19:41:56 +0000 (19:41 +0000)
Need to return a TupleTableSlot, not just a bare tuple.

doc/src/sgml/spi.sgml
src/backend/executor/spi.c
src/include/executor/spi.h
src/pl/plpgsql/src/pl_exec.c

index 23ae5dd49be355d9e2378845a1b8079c59edbf01..5f9aa5b6c80ff38940fbb83223c5bc122985ef7d 100644 (file)
@@ -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">
 <REFMETA>
 <REFENTRYTITLE>SPI_modifytuple</REFENTRYTITLE>
@@ -2695,6 +2824,7 @@ made in this context.
 <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.
index e4c2dac40db074325ddac7c3fb154738a1b236a6..428a4cb7d3fe34f78b35dc372387aa8ed151969d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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;
 }
 
+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)
index fa2ea2f361f79875ba0cbdee6aa49a95a3e1f6ee..2ea6e9bfc8facac590971ab31efb135aa9f32546 100644 (file)
@@ -2,7 +2,7 @@
  *
  * 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 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);
index 9ad6d5dece353998d6f4228d60e8eaec7ec158b7..b0385bf1a6f7e21af362e3f9f192228fcbf718ef 100644 (file)
@@ -3,7 +3,7 @@
  *                       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.
  *
@@ -400,32 +400,43 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo)
 
        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;
+                       }
                }
        }
 
@@ -1619,8 +1630,8 @@ exec_stmt_return(PLpgSQL_execstate * estate, PLpgSQL_stmt_return * stmt)
 
                        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;
@@ -1631,16 +1642,10 @@ exec_stmt_return(PLpgSQL_execstate * estate, PLpgSQL_stmt_return * stmt)
                        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;
        }