public interface UserDefinedFunctionAdapterFactory
UserDefinedFunctionAdapter
for
a given function call.
When a query string with a reference to a user-defined function is translated into an executable query, the
parser first looks-up the function factory for the given function identifier and calls
getSignature(FieldMetaData[], JavaTypes.Type[], Object[])
to determine, whether or not that factory can provide a function adapter for the given input parameters. If
this check fails, the whole query is already rejected by the query parser.
If however the check succeeded the query translator later on uses the same factory and calls
createInstance(FieldMetaData[], JavaTypes.Type[], Object[])
to actually create an instance of a suitable UserDefinedFunctionAdapter
.
Registration of a UserDefinedFunctionAdapterFactory
at the engine bears the following advantages over
registration of a UserDefinedFunctionAdapter
:
ROUND(Type.DOUBLE value) -> Type.DOUBLE,
ROUND(Type.DOUBLE value, Type.INTEGER decimals) -> Type.DOUBLE
ROUND(Type.BIGDECIMAL value) -> Type.BIGDECIMAL,
ROUND(Type.BIGDECIMAL value, Type.INTEGER decimals) -> Type.BIGDECIMAL
UserDefinedFunctionAdapterFactory
may also take static instantiation parameters into account.
The values of such parameters are constant and are already present at parse time.
An exemplary user-defined function charAt(String; Integer)
could take the character index to
extract as an instantiation parameter, whereas the string parameter that the character is to be extracted
from could constitute a runtime parameter. A query SELECT charAt(aStringColumn ; 3) FROM source;
could
then extract all the third characters from the column values of aStringColum
. The parameter 3
constitutes an instantiation parameter. In the function signature and the function call, this is denoted
by the semi-colon (;
) which separates the runtime parameters from the instantiation parameters.
Both the instantiation parameter types and their actual values can be taken into account when looking up a suitable function adapter. In the example it could thus be reasonable to check whether the index parameter is a positive integer and otherwise reject the query early in the parser.
createInstance(FieldMetaData[], JavaTypes.Type[], Object[])
is newly created for every single call, than this adapter instance is guaranteed to be bound to one specific function
call in one specific query only and is never shared with other function calls in the same or in other queries.
It thus depends on the factory, whether or not the adapter may be shared or not.
Repeat
function which may be called with two different signatures,
Repeat(Type.STRING str) -> Type.STRING
, and Repeat(Type.STRING str ; Type.INTEGER times) -> Type.STRING
,
First the class defines the adapter class RepeatFunctionAdapter
, which is given the instantiation parameter times
as
a constant argument to its constructor. The adapter itself defines its signature, without considering the instantiation parameter types.
Those are only relevant to the factory, not the adapter itself.
Next, the getSignature(FieldMetaData[], JavaTypes.Type[], Object[])
performs several checks to see if the given parameter and instantiation parameter types
match any of the signatures and on success returns the matching signature.
Finally, createInstance(FieldMetaData[], JavaTypes.Type[], Object[])
instantiates a concrete RepeatFunctionAdapter
instance with either
the given instantiation parameter or else the default parameter 1.
public class RepeatFunctionAdapterFactory implements UserDefinedFunctionAdapterFactory { public static class RepeatFunctionAdapter implements UserDefinedFunctionAdapter { private final int times; public RepeatFunctionAdapter(int times) { this.times = times; }@Override
public Type getReturnType() { return Type.STRING; }@Override
public Type[] getParameterTypes() { return new Type[] { Type.STRING }; }@Override
public Object eval(Object... parameters) { if (parameters[0] == null) return null; String result = ""; for (int i=1; i<
times; i++) result += (String)parameters[0]; return result; } }@Override
public Signature getSignature(FieldMetaData[] parameterMetaData, Type[] instantiationParameterTypes, Object[] instantiationParameters) throws UserDefinedFunctionException { Type[] parameterTypes = FieldMetaDatas.getJavaTypes(parameterMetaData); if (parameterTypes.length != 1 || !Type.STRING.equals(parameterTypes[0])) throw new UserDefinedFunctionException("Expects exactly one input parameter of type STRING."); if (instantiationParameterTypes.length>
1 || !Type.INTEGER.equals(instantiationParameterTypes[0])) throw new UserDefinedFunctionException("Expects exactly at most one instantiation parameter of type INTEGER."); if (instantiationParameterTypes.length == 1 && ((Integer)instantiationParameters[0])<=
0) throw new UserDefinedFunctionException("Instantiation parameter needs to be a positive integer."); return Adapters.createSignature(Type.STRING, parameterTypes, instantiationParameterTypes); }@Override
public UserDefinedFunctionAdapter createInstance(FieldMetaData[] parameterMetaData, Type[] instantiationParameterTypes, Object[] instantiationParameters) { final int times = instantiationParameters.length>
0 ? (Integer)instantiationParameters[0] : 1; return new RepeatFunctionAdapter(times); } }
Modifier and Type | Method and Description |
---|---|
UserDefinedFunctionAdapter |
createInstance(FieldMetaData[] parameterMetaData,
JavaTypes.Type[] instantiationParameterTypes,
Object[] instantiationParameters)
Instantiates a
UserDefinedFunctionAdapter for the given runtime parameter types and instantiation parameters. |
Signature |
getSignature(FieldMetaData[] parameterMetaData,
JavaTypes.Type[] instantiationParameterTypes,
Object[] instantiationParameters)
Determines, whether or not this factory is able to instantiate a
UserDefinedFunctionAdapter for
the given runtime parameter types and the additional instantiation parameter types and values. |
Signature getSignature(FieldMetaData[] parameterMetaData, JavaTypes.Type[] instantiationParameterTypes, Object[] instantiationParameters) throws UserDefinedFunctionException
UserDefinedFunctionAdapter
for
the given runtime parameter types and the additional instantiation parameter types and values. If an
adapter could be instantiated, the exact Signature
of this function adapter is returned, otherwise
an UserDefinedFunctionException
is thrown.
UserDefinedFunctionAdapter.eval(Object...)
method. Besides the parameter type, the FieldMetaData
object corresponding to each runtime parameters offers additional information, e.g. the name of the parameter or flags
describing the "null-ability" and case-sensitivity of the parameter.
createInstance(FieldMetaData[], JavaTypes.Type[], Object[])
method so that the concrete adapter instance can be created depending on those instantiation parameters. Their types
and values are also given to getSignature(FieldMetaData[], JavaTypes.Type[], Object[])
so
that the decision, whether or not an adapter could be instantiated, can also take those information into account.parameterMetaData
- An array of FieldMetaData
objects describing the runtime parameters that the
adapter should be able to acceptinstantiationParameterTypes
- The instantiation parameter types that a matching function adapter is to be
searched forinstantiationParameters
- The actual values of the instantiation parameters.Signature
object describing the actual parameters types, instantiation parameter types and the return
type of the adapter that this factory would return for the given arguments.
UserDefinedFunctionException
- if this factory would not be able to instantiate a UserDefinedFunctionAdapter
for the given argumentsUserDefinedFunctionAdapter createInstance(FieldMetaData[] parameterMetaData, JavaTypes.Type[] instantiationParameterTypes, Object[] instantiationParameters)
UserDefinedFunctionAdapter
for the given runtime parameter types and instantiation parameters.
If getSignature(FieldMetaData[], JavaTypes.Type[], Object[])
did not throw an UserDefinedFunctionException
, calling createInstance()
with the same arguments
shall succeed and return a valid adapter.
getSignature(FieldMetaData[], JavaTypes.Type[], Object[])
failed with an
UserDefinedFunctionException
, createInstance()
will equally fail with a corresponding
RuntimeException
.parameterMetaData
- An array of FieldMetaData
objects describing the runtime parameters that the
adapter should be able to acceptinstantiationParameterTypes
- The instantiation parameter typesinstantiationParameters
- The actual values of the instantiation parameters.UserDefinedFunctionAdapter
object