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

From Volkan YAZICI
Subject Re: Verbosity of Function Return Type Checks
Date
Msg-id 871vzzf70b.fsf@alamut.mobiliz.com.tr
Whole thread Raw
In response to Re: Verbosity of Function Return Type Checks  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: Verbosity of Function Return Type Checks
List pgsql-hackers
On Thu, 04 Sep 2008, Tom Lane <tgl@sss.pgh.pa.us> writes:
> This is not ready to go: you've lost the ability to localize most of
> the error message strings.

How can I make this available? What's your suggestion?

> Also, "char *msg" should be "const char *msg"

Done.

> if you're going to pass literal constants to it, and this gives me the
> willies even though the passed-in strings are supposedly all fixed:
>         errmsg(msg),
> Use
>         errmsg("%s", msg),
> to be safe.

Done.

> Actually, the entire concept of varying the main message to suit the
> context exactly, while the detail messages are *not* changing, seems
> pretty bogus...

I share your concerns but couldn't come up with a better approach. I'd
be happy to hear your suggestions.

> Another problem with it is it's likely going to fail completely on
> dropped columns (which will have atttypid = 0).

Is it ok if I'd replace

  if (td1->attrs[i]->atttypid != td2->attrs[i]->atttypid)

line in validate_tupdesc_compat with

  if (td1->attrs[i]->atttypid &&
      td2->attrs[i]->atttypid &&
      td1->attrs[i]->atttypid != td2->attrs[i]->atttypid)

expression to fix this?


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.219
diff -c -r1.219 pl_exec.c
*** src/pl/plpgsql/src/pl_exec.c    1 Sep 2008 22:30:33 -0000    1.219
--- src/pl/plpgsql/src/pl_exec.c    5 Sep 2008 06:13:18 -0000
***************
*** 188,194 ****
                         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 exec_set_found(PLpgSQL_execstate *estate, bool state);
  static void plpgsql_create_econtext(PLpgSQL_execstate *estate);
  static void free_var(PLpgSQL_var *var);
--- 188,195 ----
                         Oid reqtype, int32 reqtypmod,
                         bool isnull);
  static void exec_init_tuple_store(PLpgSQL_execstate *estate);
! static void validate_tupdesc_compat(TupleDesc td1, TupleDesc td2,
!                                     const char *msg);
  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);
***************
*** 384,394 ****
              {
                  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:

--- 385,393 ----
              {
                  case TYPEFUNC_COMPOSITE:
                      /* got the expected result rowtype, now check it */
!                     validate_tupdesc_compat(tupdesc, estate.rettupdesc,
!                                             "returned record type does not "
!                                             "match expected record type");
                      break;
                  case TYPEFUNC_RECORD:

***************
*** 705,715 ****
          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")));
          /* Copy tuple to upper executor memory */
          rettup = SPI_copytuple((HeapTuple) DatumGetPointer(estate.retval));
      }
--- 704,713 ----
          rettup = NULL;
      else
      {
!         validate_tupdesc_compat(trigdata->tg_relation->rd_att,
!                                 estate.rettupdesc,
!                                 "returned tuple structure does not match "
!                                 "table of trigger event");
          /* Copy tuple to upper executor memory */
          rettup = SPI_copytuple((HeapTuple) DatumGetPointer(estate.retval));
      }
***************
*** 2199,2209 ****
                            (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                             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")));
                      tuple = rec->tup;
                  }
                  break;
--- 2197,2207 ----
                            (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                             errmsg("record \"%s\" is not assigned yet",
                                    rec->refname),
!                            errdetail("The tuple structure of a not-yet-assigned"
!                                      " record is indeterminate.")));
!                     validate_tupdesc_compat(rec->tupdesc, tupdesc,
!                                             "wrong record type supplied in "
!                                             "RETURN NEXT");
                      tuple = rec->tup;
                  }
                  break;
***************
*** 2309,2318 ****
                                             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")));

      while (true)
      {
--- 2307,2315 ----
                                             stmt->params);
      }

!     validate_tupdesc_compat(portal->tupDesc, estate->rettupdesc,
!                             "structure of query does not match function "
!                             "result type");

      while (true)
      {
***************
*** 5145,5167 ****
  }

  /*
!  * Check two tupledescs have matching number and types of attributes
   */
! static bool
! compatible_tupdesc(TupleDesc td1, TupleDesc td2)
  {
!     int            i;

      if (td1->natts != td2->natts)
!         return false;

      for (i = 0; i < td1->natts; i++)
-     {
          if (td1->attrs[i]->atttypid != td2->attrs[i]->atttypid)
!             return false;
!     }
!
!     return true;
  }

  /* ----------
--- 5142,5178 ----
  }

  /*
!  * Validates compatibility of supplied TupleDesc couple by checking # and type
!  * of available arguments.
   */
! static void
! validate_tupdesc_compat(TupleDesc td1, TupleDesc td2, const char *msg)
  {
!     int i;
!
!     if (!td1 || !td2)
!         ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg(msg)));

      if (td1->natts != td2->natts)
!         ereport(ERROR,
!                 (errcode(ERRCODE_DATATYPE_MISMATCH),
!                  errmsg("%s", msg),
!                  errdetail("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)
!             ereport(ERROR,
!                     (errcode(ERRCODE_DATATYPE_MISMATCH),
!                      errmsg("%s", msg),
!                      errdetail("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: Volkan YAZICI
Date:
Subject: Re: Verbosity of Function Return Type Checks
Next
From: Markus Wanner
Date:
Subject: Re: WIP: Column-level Privileges