First off to say that I fully agree that a UDF must not let
exceptions escape.  I have no issue with that.

Claudio says in the v2.1.4 release notes: "Since UDFs have no
formal mechanism to signal errors, the returned value would
have to be used as an indicator."

I was wondering if anyone had had any bright ideas about how
we might fix that shortcoming?

If we take some existing code as an example, for example the
power function in fbudf.cpp.  We can see that an input error
situation (negatives) is flagged by a NULL return.

This is something we've had to make work because FB offers no
better alternative, but it is far from ideal.  For example it
is even complex in SQL code to interpret the NULL result and
report an error message in this case - because it might not
have been an error: NULL is the correct response if the inputs
were NULL.  So such SQL would have to do all the same input
checking as done inside the UDF.  It rapidly gets very messy.

The thought I had was whether it might be possible to create
a variation of the DECLARE EXTERNAL FUNCTION  RETURNS PARAMETER
clause.  Something like a RETURNS EXCEPTION [PARAMETER] n
where "n" is the parameter number used to return the exception
information.

Parameter n would be initialised to null when the UDF is called
by Firebird.  On return:

  - if the parameter remains NULL then no error
  - any non-null (value) assigned to the parameter indicates
    that an error occured.
  - if parameter is a number the number is returned as part
    of a generic SQL exception message.
  - if the parameter is a string the string is returned as
    (part of?) an SQL exception message.


So the power example would become:

declare external function dPower
double precision by descriptor, double precision by descriptor,
double precision by descriptor, integer by descriptor
returns parameter 3
returns exception 4
entry_point 'power' module_name 'fbudf';

and the relevant part of the udf code could become:
FBUDF_API void power(const paramdsc* v, const paramdsc* v2,
  paramdsc* rc, paramdsc* rce)
[...]
        if (rct < 0 || rct2 < 0 || !d && d2 < 0)
        {
                internal::setnull(rc);
                internal::set_int_type(rce, 1);
                return;
        }

Something like this could make UDFs more powerful and error
situations easier to deal with.

-- 
Geoff Worboys
Telesis Computing Pty Ltd


------------------------------------------------------------------------------
All the data continuously generated in your IT infrastructure 
contains a definitive record of customers, application performance, 
security threats, fraudulent activity, and more. Splunk takes this 
data and makes sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-novd2d
Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel

Reply via email to