]> granicus.if.org Git - postgresql/commitdiff
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:10 +0000 (22:48 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 3 Jan 2006 22:48:10 +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 15c6085569c0c58d2d767bacd471b1e8dc6da27f..5ae280eaf7d635aae0973f77ea623053a8070527 100644 (file)
@@ -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
                {