Fix coredump in plpgsql when trying to return a rowtype result.
authorTom Lane
Mon, 5 Nov 2001 19:41:56 +0000 (19:41 +0000)
committerTom Lane
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
 
 
 
+
+
+SPI_copytupleintoslot
+SPI - Tuple and Descriptor Copy
+
+
+SPI_copytupleintoslot
+
+
+Makes copy of tuple and descriptor in upper Executor context
+
+SPIcopying tuples
+SPI_copytupleintoslot
+
+
+
+1997-12-24
+
+
+SPI_copytupleintoslot(tuple, tupdesc)
+
+
+
+
+1997-12-24
+
+Inputs</div> <div class="diff add">+
+
+
+
+HeapTuple tuple
+
+
+
+Input tuple to be copied
+
+
+
+
+
+TupleDesc tupdesc
+
+
+
+Input tuple descriptor to be copied
+
+
+
+
+
+
+
+
+1997-12-24
+
+Outputs</div> <div class="diff add">+
+
+
+
+TupleTableSlot *
+
+
+
+Tuple slot containing copied tuple and descriptor
+
+
non-NULL
+ if tuple
+ and tupdesc
+ are not NULL and the copy was successful
+
+
+   NULL
+ only if tuple
+ or tupdesc
+ is NULL
+
+
+
+
+
+
+
+
+
+
+
+1997-12-24
+
+Description</div> <div class="diff add">+
+
+SPI_copytupleintoslot 
+   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.
+
+
+
+Usage</div> <div class="diff add">+
+
+TBD
+
+
+
+
+
+
+
+
+
+
 
 
 SPI_modifytuple
@@ -2695,6 +2824,7 @@ made in this context.
 palloc/repalloc or by SPI utility
 functions (except for SPI_copytuple,
 SPI_copytupledesc,
+SPI_copytupleintoslot,
 SPI_modifytuple,
 SPI_palloc and SPI_repalloc) 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;
    }