public interface UserDefinedFunctionAdapter
Implementation of a user-defined function involves (i) the specification of the functions signature, i.e. its required input parameter types and its return type, and (ii) the definition of the logic to be evaluated when calling the function.
If the function shall be overloaded with multiple distinct signatures a
UserDefinedFunctionAdapterFactory
needs to be implemented which itself instantiates
the correct adapter for a set of input parameters if possible.
The query parser and translator verify the functions signature and ensure that the
arguments passed to the function match the required input parameter types. Those types
do not need to match exactly, but an argument needs to be convertible to the required
parameter type only through trivial casts, i.e. no information must be lost with the cast.
Trivial casts, such as e.g. from Type.INTEGER
to Type.LONG
or from
Type.FLOAT
to Type.DOUBLE
may be implicitly applied by the parser and
translator when looking up a matching function adapter. Hence a function with the signature
(Type.DOUBLE, Type.DOUBLE) -> Type.DOUBLE
also matches to a call with two Type.INTEGER
arguments or a call with one Type.INTEGER
and one Type.DOUBLE
argument. However,
if for instance any of the arguments is of type Type.BIGDECIMAL
or Type.STRING
,
the signature will not match and the adapter does not qualify for the function call.
As a general hint, the input parameter types should be as general as possible, whereas the
output parameters should be as strict as possible.
If only a single function adapter is registered, this adapter may not maintain
any internal state, as it may be shared among several queries (referencing a database
connection or any other external resource already constitutes state and should
be avoided). Otherwise, if a factory is registered which itself creates function adapter
instances as needed, those adapters may maintain internal state, as they are only used
for one single query (see UserDefinedFunctionAdapterFactory
).
The methods getReturnType()
and getParameterTypes()
may not throw any exceptions at all, otherwise parsing and translating the query string
into a runnable query will already fail. Exceptions thrown in eval(Object ...)
are caught and logged during query runtime but do not affect the overall processing of
the query. Instead, if function evaluation failed with an exception, the function result
will be null
. Therefore, the result of a call to a user-defined function is
always considered null-able.
toString()
method from Java
to the SQL world. The functions signature is (Type.UNKNOWN) -> Type.STRING
which means
it accepts any input parameter it is given and returns a string representation, based on the
parameters toString()
method. As getParameterTypes()
returned exactly one parameter type, it is safe in eval()
to assume that the first
entry of the parameters array exists without further checks applied.
public class ToString implements UserDefinedFunctionAdapter { public ToString() { }@Override
public Type getReturnType() { return Type.STRING; }@Override
public Type[] getParameterTypes() { return new Type[] { Type.UNKNOWN }; }@Override
public Object eval(Object... parameters) { return String.valueOf(parameters[0]); } }
Modifier and Type | Method and Description |
---|---|
Object |
eval(Object... parameters)
Evaluates the user-defined function.
|
JavaTypes.Type[] |
getParameterTypes()
Returns the parameter types of the user-defined function.
|
JavaTypes.Type |
getReturnType()
Returns the return type of the user-defined function.
|
JavaTypes.Type getReturnType()
JavaTypes.Type[] getParameterTypes()
Object eval(Object... parameters)
getParameterTypes()
and the result has to
be of the type returned by getReturnType()
.parameters
- the parameters for the evaluation of the user defined function