NULL <=> non-NULL conversions you didn’t ask for
Teaching you how to declare, use, and write UDFs is outside the scope of this guide.However, we must warn you that UDFs can occasionally perform unexpected NULL conversions.This will sometimes result in NULL input being converted to a regular value, and other times in the nullification of valid input like '' (an empty string).
The main cause of this problem is that with “old style” UDF calling (inherited from InterBase), it is not possible to pass NULL as input to the function.When a UDF like LTRIM (left trim) is called with a NULL argument, the argument is passed to the function as an empty string.(Note: in Firebird 2 and up, it can also be passed as a null pointer.We’ll get to that later.)From inside the function there is no way of telling if this argument represents a real empty string or a NULL.So what does the function implementor do?He has to make a choice: either take the argument at face value, or assume it was originally a NULL and treat it accordingly.
If the function result type is a pointer, returning NULL is possible even if receiving NULL isn’t.Thus, the following unexpected things can happen:
-
You call a UDF with a
NULLargument.It is passed as a value, e.g.0or''.Within the function, this argument is not changed back toNULL;a non-NULLresult is returned. -
You call a UDF with a valid argument like
0or''.It is passed as-is (obviously).But the function code supposes that this value really represents aNULL, treats it as a black hole, and returnsNULLto the caller.
Both conversions are usually unwanted, but the second probably more so than the first (better validate something NULL than wreck something valid).To get back to our LTRIM example: in Firebird 1.0, this function returns NULL if you feed it an empty string.This is wrong.In 1.5 it never returns NULL: even NULL strings (passed by the engine as '') are “trimmed” to empty strings.This is also wrong, but it’s considered the lesser of two evils.Firebird 2 has finally got it right: a NULL string gives a NULL result, an empty string is trimmed to an empty string — at least if you declare the function in the right way.