Verbosity of Function Return Type Checks - Mailing list pgsql-hackers

From Volkan YAZICI
Subject Verbosity of Function Return Type Checks
Date
Msg-id 87d4kj90nr.fsf@alamut.mobiliz.com.tr
Whole thread Raw
Responses Re: Verbosity of Function Return Type Checks  (Alvaro Herrera <alvherre@commandprompt.com>)
List pgsql-hackers
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))));
 }

 /* ----------

pgsql-hackers by date:

Previous
From: Simon Riggs
Date:
Subject: Re: For what should pg_stop_backup wait?
Next
From: Tom Lane
Date:
Subject: Re: patch: Add columns via CREATE OR REPLACE VIEW