Subject Design of new built-in functions
Author Dmitry Yemanov
All,

Let's have a discussion on how we map new engine functions to BLR codes. The
current approach (one BLR verb per function) requires many code
modifications and wastes the limited BLR space. Now we have more than 50
available positions, but that's not too many, actually. I know we're going
to deprecate BLR a some point in the future, but it's not going to happen
very soon, so we need some short-term solution.

I see two alternative approaches to design system-defined functions (SDFs):

1) as per Borland's conference paper "Extending SQL Functionality in
InterBase"
2) as per Yaffil's implementation

Both (1) and (2) use the existing blr_function verb to execute the function,
the major difference is in the layering. Proposal (1) places SDFs under
FUN_execute(), so the engine tries the hardcoded list of functions from
builtin.cpp if the referenced UDF couldn't be found in metadata. As a
(positive?) side effect, it allows UDFs to override SDFs. The negative side
(in Borland's POV) is that all strings are passed via PCHAR and it makes it
impossible to provide a proper INTL support for the string arguments and
returns. But, as we support "by descriptor" parameters passing mechanism, it
shouldn't be a big problem for us. However, buildin.cpp will require many
calls back into the engine which will make it just a smaller relation of
evl.cpp. IMHO, it breaks the engine's layering a bit, as FUN becomes a
gateway back to the engine.

Proposal (2) designs SDFs at the EVL layer. The engine looks up the
hardcoded list of SDFs before querying RDB$FUNCTIONS and, if the function is
SDF, it just call local functions. By "local" I mean that all SDFs are
implemented as static functions inside EVL, the same way as engine functions
are handled now. Of course, everything is passed via descriptors and
returned via an impure area. The advantages of this approach is that is
keeps the current layering and avoids calling the almost useless FUN code.
The disadvantage is that SDFs override UDFs, so users cannot implement their
own version of the built-in functions.

IMO, such a function override sounds like a useful feature, so (1) looks
better here. But please note that we never supported it and (2) exactly fits
our current behaviour. Now, when we add a new built-in function, it hides
the UDF with the same name and call syntax.

My vote goes to (2), as otherwise we'll have undefined behaviour - some
functions (new ones) can be overriden by UDFs whilst others cannot (old
ones). As soon as we move away from BLR, we could reconsider this behaviour
and allow UDFs to override all SDFs.

Opinions?


Dmitry