diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml index 23ae5dd49b..5f9aa5b6c8 100644 --- a/doc/src/sgml/spi.sgml +++ b/doc/src/sgml/spi.sgml @@ -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 + + + + +HeapTuple tuple + + + +Input tuple to be copied + + + + + +TupleDesc tupdesc + + + +Input tuple descriptor to be copied + + + + + + + + +1997-12-24 + +Outputs + + + + +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 + + +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 + + +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. diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index e4c2dac40d..428a4cb7d3 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -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) diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index fa2ea2f361..2ea6e9bfc8 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -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); diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 9ad6d5dece..b0385bf1a6 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -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) { - int len; - Datum tmp; + /* 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 + { + /* 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; }