From 495be39266f2f74e1626577fb20dd42d40a99006 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 3 Jan 2006 22:48:21 +0000 Subject: [PATCH] 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. --- src/pl/plpgsql/src/pl_exec.c | 44 +++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 95acb3a9d8c..39e7ae510c7 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.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 {