|
|
|
|
@ -3,7 +3,7 @@ |
|
|
|
|
* procedural language |
|
|
|
|
* |
|
|
|
|
* IDENTIFICATION |
|
|
|
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.154.2.1 2005/11/22 18:23:30 momjian Exp $ |
|
|
|
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.154.2.2 2006/01/03 22:48:21 tgl Exp $ |
|
|
|
|
* |
|
|
|
|
* This software is copyrighted by Jan Wieck - Hamburg. |
|
|
|
|
* |
|
|
|
|
@ -343,10 +343,48 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo) |
|
|
|
|
{ |
|
|
|
|
if (estate.retistuple) |
|
|
|
|
{ |
|
|
|
|
/* Copy tuple to upper executor memory, as a tuple Datum */ |
|
|
|
|
/*
|
|
|
|
|
* We have to check that the returned tuple actually matches |
|
|
|
|
* the expected result type. XXX would be better to cache the |
|
|
|
|
* tupdesc instead of repeating get_call_result_type() |
|
|
|
|
*/ |
|
|
|
|
TupleDesc tupdesc; |
|
|
|
|
|
|
|
|
|
switch (get_call_result_type(fcinfo, NULL, &tupdesc)) |
|
|
|
|
{ |
|
|
|
|
case TYPEFUNC_COMPOSITE: |
|
|
|
|
/* got the expected result rowtype, now check it */ |
|
|
|
|
if (estate.rettupdesc == NULL || |
|
|
|
|
!compatible_tupdesc(estate.rettupdesc, tupdesc)) |
|
|
|
|
ereport(ERROR, |
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH), |
|
|
|
|
errmsg("returned record type does not match expected record type"))); |
|
|
|
|
break; |
|
|
|
|
case TYPEFUNC_RECORD: |
|
|
|
|
/*
|
|
|
|
|
* Failed to determine actual type of RECORD. We could |
|
|
|
|
* raise an error here, but what this means in practice |
|
|
|
|
* is that the caller is expecting any old generic |
|
|
|
|
* rowtype, so we don't really need to be restrictive. |
|
|
|
|
* Pass back the generated result type, instead. |
|
|
|
|
*/ |
|
|
|
|
tupdesc = estate.rettupdesc; |
|
|
|
|
if (tupdesc == NULL) /* shouldn't happen */ |
|
|
|
|
elog(ERROR, "return type must be a row type"); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
/* shouldn't get here if retistuple is true ... */ |
|
|
|
|
elog(ERROR, "return type must be a row type"); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Copy tuple to upper executor memory, as a tuple Datum. |
|
|
|
|
* Make sure it is labeled with the caller-supplied tuple type. |
|
|
|
|
*/ |
|
|
|
|
estate.retval = |
|
|
|
|
PointerGetDatum(SPI_returntuple((HeapTuple) (estate.retval), |
|
|
|
|
estate.rettupdesc)); |
|
|
|
|
tupdesc)); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
|