From: Tom Lane Date: Tue, 3 Jan 2006 22:48:10 +0000 (+0000) Subject: Add checks to verify that a plpgsql function returning a rowtype is actually X-Git-Tag: REL8_2_BETA1~1660 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=41ec930d7ca3a6637cb80f4d02c1a7a556dcd513;p=postgresql Add checks to verify that a plpgsql function returning a rowtype is actually returning the rowtype it's supposed to return. Per reports from David Niblett and Michael Fuhr. --- diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 15c6085569..5ae280eaf7 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.158 2005/12/28 01:30:01 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.159 2006/01/03 22:48:10 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 {