Hi,

Yesterday I needed to fiddle with PostgreSQL internals to be able to
debug a PL/pgSQL procedure returning a set of records. I attached the
patch I used to increase the verbosity of error messages related with
function return type checks. I'll be appreciated if any developer could
commit this patch (or a similar one) into the core.


Regards.

Index: src/pl/plpgsql/src/pl_exec.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v
retrieving revision 1.216
diff -u -r1.216 pl_exec.c
--- src/pl/plpgsql/src/pl_exec.c	16 May 2008 18:34:51 -0000	1.216
+++ src/pl/plpgsql/src/pl_exec.c	8 Aug 2008 11:52:02 -0000
@@ -190,7 +190,7 @@
 					   Oid reqtype, int32 reqtypmod,
 					   bool isnull);
 static void exec_init_tuple_store(PLpgSQL_execstate *estate);
-static bool compatible_tupdesc(TupleDesc td1, TupleDesc td2);
+static void validate_tupdesc_compat(TupleDesc td1, TupleDesc td2);
 static void exec_set_found(PLpgSQL_execstate *estate, bool state);
 static void plpgsql_create_econtext(PLpgSQL_execstate *estate);
 static void free_var(PLpgSQL_var *var);
@@ -386,11 +386,12 @@
 			{
 				case TYPEFUNC_COMPOSITE:
 					/* got the expected result rowtype, now check it */
-					if (estate.rettupdesc == NULL ||
-						!compatible_tupdesc(estate.rettupdesc, tupdesc))
+					if (!estate.rettupdesc)
 						ereport(ERROR,
 								(errcode(ERRCODE_DATATYPE_MISMATCH),
-								 errmsg("returned record type does not match expected record type")));
+								 errmsg("returned record type does not match "
+										"expected record type")));
+					validate_tupdesc_compat(tupdesc, estate.rettupdesc);
 					break;
 				case TYPEFUNC_RECORD:
 
@@ -707,11 +708,8 @@
 		rettup = NULL;
 	else
 	{
-		if (!compatible_tupdesc(estate.rettupdesc,
-								trigdata->tg_relation->rd_att))
-			ereport(ERROR,
-					(errcode(ERRCODE_DATATYPE_MISMATCH),
-					 errmsg("returned tuple structure does not match table of trigger event")));
+		validate_tupdesc_compat(trigdata->tg_relation->rd_att,
+								estate.rettupdesc);
 		/* Copy tuple to upper executor memory */
 		rettup = SPI_copytuple((HeapTuple) DatumGetPointer(estate.retval));
 	}
@@ -2202,10 +2200,7 @@
 						   errmsg("record \"%s\" is not assigned yet",
 								  rec->refname),
 						   errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
-					if (!compatible_tupdesc(tupdesc, rec->tupdesc))
-						ereport(ERROR,
-								(errcode(ERRCODE_DATATYPE_MISMATCH),
-						errmsg("wrong record type supplied in RETURN NEXT")));
+					validate_tupdesc_compat(rec->tupdesc, tupdesc);
 					tuple = rec->tup;
 				}
 				break;
@@ -2311,10 +2306,7 @@
 										   stmt->params);
 	}
 
-	if (!compatible_tupdesc(estate->rettupdesc, portal->tupDesc))
-		ereport(ERROR,
-				(errcode(ERRCODE_DATATYPE_MISMATCH),
-		  errmsg("structure of query does not match function result type")));
+	validate_tupdesc_compat(portal->tupDesc, estate->rettupdesc);
 
 	while (true)
 	{
@@ -5138,23 +5130,32 @@
 }
 
 /*
- * Check two tupledescs have matching number and types of attributes
+ * Validates compatibility of supplied TupleDesc's by checking # and type of
+ * available arguments.
  */
-static bool
-compatible_tupdesc(TupleDesc td1, TupleDesc td2)
+static void
+validate_tupdesc_compat(TupleDesc td1, TupleDesc td2)
 {
-	int			i;
+	int i;
 
 	if (td1->natts != td2->natts)
-		return false;
+		ereport(ERROR,
+				(errcode(ERRCODE_DATATYPE_MISMATCH),
+				 errmsg("Number of returned columns (%d) does not match "
+						"expected column count (%d).",
+					    td1->natts, td2->natts)));
 
 	for (i = 0; i < td1->natts; i++)
-	{
 		if (td1->attrs[i]->atttypid != td2->attrs[i]->atttypid)
-			return false;
-	}
-
-	return true;
+			ereport(ERROR,
+					(errcode(ERRCODE_DATATYPE_MISMATCH),
+					 errmsg("Returned record type (%s) does not match "
+							"expected record type (%s) in column %d (%s).",
+							format_type_with_typemod(td1->attrs[i]->atttypid,
+								                     td1->attrs[i]->atttypmod),
+							format_type_with_typemod(td2->attrs[i]->atttypid,
+													 td2->attrs[i]->atttypmod),
+							(1+i), NameStr(td2->attrs[i]->attname))));
 }
 
 /* ----------
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to