@Override
public RowExpression visitCall(CallExpression call, final Void context)
{
FunctionInfo function;
Signature signature = call.getSignature();
if (signature.getName().equals(CAST)) {
if (call.getArguments().get(0).getType().equals(UnknownType.UNKNOWN)) {
return constantNull(call.getType());
}
function = registry.getCoercion(call.getArguments().get(0).getType(), call.getType());
}
else {
switch (signature.getName()) {
// TODO: optimize these special forms
case IF:
case NULL_IF:
case SWITCH:
case TRY_CAST:
case IS_NULL:
case "IS_DISTINCT_FROM":
case COALESCE:
case "AND":
case "OR":
case IN:
return call;
default:
function = registry.getExactFunction(signature);
if (function == null) {
// TODO: temporary hack to deal with magic timestamp literal functions which don't have an "exact" form and need to be "resolved"
function = registry.resolveFunction(QualifiedName.of(signature.getName()), signature.getArgumentTypes(), false);
}
}
}
List<RowExpression> arguments = Lists.transform(call.getArguments(), new Function<RowExpression, RowExpression>()
{
@Override
public RowExpression apply(RowExpression input)
{
return input.accept(Visitor.this, context);
}
});
if (Iterables.all(arguments, instanceOf(ConstantExpression.class)) && function.isDeterministic()) {
MethodHandle method = function.getMethodHandle();
if (method.type().parameterCount() > 0 && method.type().parameterType(0) == ConnectorSession.class) {
method = method.bindTo(session);
}
List<Object> constantArguments = new ArrayList<>();
for (RowExpression argument : arguments) {
Object value = ((ConstantExpression) argument).getValue();
// if any argument is null, return null
if (value == null) {
return constantNull(call.getType());
}
constantArguments.add(value);
}
try {
return constant(method.invokeWithArguments(constantArguments), call.getType());
}
catch (Throwable e) {
if (e instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
throw Throwables.propagate(e);
}
}
return call(signature, typeManager.getType(signature.getReturnType()), arguments);
}