Add checks to verify that a plpgsql function returning a rowtype is actually
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 3 Jan 2006 22:48:28 +0000 (22:48 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 3 Jan 2006 22:48:28 +0000 (22:48 +0000)
returning the rowtype it's supposed to return.  Per reports from David Niblett
and Michael Fuhr.

src/pl/plpgsql/src/pl_exec.c

index 0470a14f999f79270bd315b7662226ac77f0a436..9d17ead258fb32d6233dd370526b539e01ba6ccb 100644 (file)
@@ -3,7 +3,7 @@
  *           procedural language
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.127.4.3 2005/06/20 22:51:49 tgl Exp $
+ *   $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.127.4.4 2006/01/03 22:48:28 tgl Exp $
  *
  *   This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -382,10 +382,37 @@ 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.
+            */
+           ReturnSetInfo *rsi = estate.rsi;
+           TupleDesc   tupdesc;
+
+           if (rsi && IsA(rsi, ReturnSetInfo) &&
+               rsi->expectedDesc != NULL)
+               tupdesc = rsi->expectedDesc;
+           else if (estate.fn_rettype == RECORDOID)
+           {
+               /* assume caller can handle any record type */
+               tupdesc = estate.rettupdesc;
+           }
+           else
+               tupdesc = lookup_rowtype_tupdesc(estate.fn_rettype, -1);
+           /* 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")));
+
+           /*
+            * 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
        {