use of com.facebook.presto.operator.scalar.BuiltInScalarFunctionImplementation in project presto by prestodb.
the class BytecodeUtils method generateInvocation.
public static BytecodeNode generateInvocation(Scope scope, String name, JavaScalarFunctionImplementation function, Optional<BytecodeNode> instance, List<BytecodeNode> arguments, CallSiteBinder binder, Optional<OutputBlockVariableAndType> outputBlockVariableAndType) {
LabelNode end = new LabelNode("end");
BytecodeBlock block = new BytecodeBlock().setDescription("invoke " + name);
List<Class<?>> stackTypes = new ArrayList<>();
if (function instanceof BuiltInScalarFunctionImplementation && ((BuiltInScalarFunctionImplementation) function).getInstanceFactory().isPresent()) {
checkArgument(instance.isPresent());
}
// Index of current parameter in the MethodHandle
int currentParameterIndex = 0;
// Index of parameter (without @IsNull) in Presto function
int realParameterIndex = 0;
// Go through all the choices in the function and then pick the best one
List<ScalarFunctionImplementationChoice> choices = getAllScalarFunctionImplementationChoices(function);
ScalarFunctionImplementationChoice bestChoice = null;
for (ScalarFunctionImplementationChoice currentChoice : choices) {
boolean isValid = true;
for (int i = 0; i < arguments.size(); i++) {
if (currentChoice.getArgumentProperty(i).getArgumentType() != VALUE_TYPE) {
continue;
}
if (currentChoice.getArgumentProperty(i).getNullConvention() == BLOCK_AND_POSITION && !(arguments.get(i) instanceof InputReferenceNode) || currentChoice.getReturnPlaceConvention() == PROVIDED_BLOCKBUILDER && (!outputBlockVariableAndType.isPresent())) {
isValid = false;
break;
}
}
if (isValid) {
bestChoice = currentChoice;
}
}
checkState(bestChoice != null, "None of the scalar function implementation choices are valid");
Binding binding = binder.bind(bestChoice.getMethodHandle());
MethodType methodType = binding.getType();
Class<?> returnType = methodType.returnType();
Class<?> unboxedReturnType = Primitives.unwrap(returnType);
boolean boundInstance = false;
while (currentParameterIndex < methodType.parameterArray().length) {
Class<?> type = methodType.parameterArray()[currentParameterIndex];
stackTypes.add(type);
if (bestChoice.getInstanceFactory().isPresent() && !boundInstance) {
checkState(type.equals(bestChoice.getInstanceFactory().get().type().returnType()), "Mismatched type for instance parameter");
block.append(instance.get());
boundInstance = true;
} else if (type == SqlFunctionProperties.class) {
block.append(scope.getVariable("properties"));
} else if (type == BlockBuilder.class) {
block.append(outputBlockVariableAndType.get().getOutputBlockVariable());
} else {
ArgumentProperty argumentProperty = bestChoice.getArgumentProperty(realParameterIndex);
switch(argumentProperty.getArgumentType()) {
case VALUE_TYPE:
// Apply null convention for value type argument
switch(argumentProperty.getNullConvention()) {
case RETURN_NULL_ON_NULL:
block.append(arguments.get(realParameterIndex));
checkArgument(!Primitives.isWrapperType(type), "Non-nullable argument must not be primitive wrapper type");
switch(bestChoice.getReturnPlaceConvention()) {
case STACK:
block.append(ifWasNullPopAndGoto(scope, end, unboxedReturnType, Lists.reverse(stackTypes)));
break;
case PROVIDED_BLOCKBUILDER:
checkArgument(unboxedReturnType == void.class);
block.append(ifWasNullClearPopAppendAndGoto(scope, end, unboxedReturnType, outputBlockVariableAndType.get().getOutputBlockVariable(), Lists.reverse(stackTypes)));
break;
default:
throw new UnsupportedOperationException(format("Unsupported return place convention: %s", bestChoice.getReturnPlaceConvention()));
}
break;
case USE_NULL_FLAG:
block.append(arguments.get(realParameterIndex));
block.append(scope.getVariable("wasNull"));
block.append(scope.getVariable("wasNull").set(constantFalse()));
stackTypes.add(boolean.class);
currentParameterIndex++;
break;
case USE_BOXED_TYPE:
block.append(arguments.get(realParameterIndex));
block.append(boxPrimitiveIfNecessary(scope, type));
block.append(scope.getVariable("wasNull").set(constantFalse()));
break;
case BLOCK_AND_POSITION:
InputReferenceNode inputReferenceNode = (InputReferenceNode) arguments.get(realParameterIndex);
block.append(inputReferenceNode.produceBlockAndPosition());
stackTypes.add(int.class);
currentParameterIndex++;
break;
default:
throw new UnsupportedOperationException(format("Unsupported null convention: %s", argumentProperty.getNullConvention()));
}
break;
case FUNCTION_TYPE:
block.append(arguments.get(realParameterIndex));
break;
default:
throw new UnsupportedOperationException(format("Unsupported argument type: %s", argumentProperty.getArgumentType()));
}
realParameterIndex++;
}
currentParameterIndex++;
}
block.append(invoke(binding, name));
if (bestChoice.isNullable()) {
switch(bestChoice.getReturnPlaceConvention()) {
case STACK:
block.append(unboxPrimitiveIfNecessary(scope, returnType));
break;
case PROVIDED_BLOCKBUILDER:
// no-op
break;
default:
throw new UnsupportedOperationException(format("Unsupported return place convention: %s", bestChoice.getReturnPlaceConvention()));
}
}
block.visitLabel(end);
if (outputBlockVariableAndType.isPresent()) {
switch(bestChoice.getReturnPlaceConvention()) {
case STACK:
block.append(generateWrite(binder, scope, scope.getVariable("wasNull"), outputBlockVariableAndType.get().getType(), outputBlockVariableAndType.get().getOutputBlockVariable()));
break;
case PROVIDED_BLOCKBUILDER:
// no-op
break;
default:
throw new UnsupportedOperationException(format("Unsupported return place convention: %s", bestChoice.getReturnPlaceConvention()));
}
}
return block;
}
use of com.facebook.presto.operator.scalar.BuiltInScalarFunctionImplementation in project presto by prestodb.
the class BytecodeGeneratorContext method generateCall.
/**
* Generates a function call with null handling, automatic binding of session parameter, etc.
*/
public BytecodeNode generateCall(String name, JavaScalarFunctionImplementation function, List<BytecodeNode> arguments, Optional<OutputBlockVariableAndType> outputBlockVariableAndType) {
Optional<BytecodeNode> instance = Optional.empty();
if (function instanceof BuiltInScalarFunctionImplementation && ((BuiltInScalarFunctionImplementation) function).getInstanceFactory().isPresent()) {
FieldDefinition field = cachedInstanceBinder.getCachedInstance(((BuiltInScalarFunctionImplementation) function).getInstanceFactory().get());
instance = Optional.of(scope.getThis().getField(field));
}
return generateInvocation(scope, name, function, instance, arguments, callSiteBinder, outputBlockVariableAndType);
}
use of com.facebook.presto.operator.scalar.BuiltInScalarFunctionImplementation in project presto by prestodb.
the class TestAnnotationEngineForScalars method testSingleImplementationScalarParse.
@Test
public void testSingleImplementationScalarParse() {
Signature expectedSignature = new Signature(QualifiedObjectName.valueOf(DEFAULT_NAMESPACE, "single_implementation_parametric_scalar"), FunctionKind.SCALAR, DOUBLE.getTypeSignature(), ImmutableList.of(DOUBLE.getTypeSignature()));
List<SqlScalarFunction> functions = ScalarFromAnnotationsParser.parseFunctionDefinition(SingleImplementationScalarFunction.class);
assertEquals(functions.size(), 1);
ParametricScalar scalar = (ParametricScalar) functions.get(0);
assertEquals(scalar.getSignature(), expectedSignature);
assertTrue(scalar.isDeterministic());
assertEquals(scalar.getVisibility(), PUBLIC);
assertEquals(scalar.getDescription(), "Simple scalar with single implementation based on class");
assertImplementationCount(scalar, 1, 0, 0);
BuiltInScalarFunctionImplementation specialized = scalar.specialize(BoundVariables.builder().build(), 1, FUNCTION_AND_TYPE_MANAGER);
assertFalse(specialized.getInstanceFactory().isPresent());
assertEquals(specialized.getArgumentProperty(0).getNullConvention(), RETURN_NULL_ON_NULL);
}
use of com.facebook.presto.operator.scalar.BuiltInScalarFunctionImplementation in project presto by prestodb.
the class TestAnnotationEngineForScalars method testWithNullableComplexArgScalarParse.
@Test
public void testWithNullableComplexArgScalarParse() {
Signature expectedSignature = new Signature(QualifiedObjectName.valueOf(DEFAULT_NAMESPACE, "scalar_with_nullable_complex"), FunctionKind.SCALAR, DOUBLE.getTypeSignature(), ImmutableList.of(DOUBLE.getTypeSignature(), DOUBLE.getTypeSignature()));
List<SqlScalarFunction> functions = ScalarFromAnnotationsParser.parseFunctionDefinition(WithNullableComplexArgScalarFunction.class);
assertEquals(functions.size(), 1);
ParametricScalar scalar = (ParametricScalar) functions.get(0);
assertEquals(scalar.getSignature(), expectedSignature);
assertTrue(scalar.isDeterministic());
assertEquals(scalar.getVisibility(), PUBLIC);
assertEquals(scalar.getDescription(), "Simple scalar with nullable complex type");
BuiltInScalarFunctionImplementation specialized = scalar.specialize(BoundVariables.builder().build(), 2, FUNCTION_AND_TYPE_MANAGER);
assertFalse(specialized.getInstanceFactory().isPresent());
assertEquals(specialized.getArgumentProperty(0), valueTypeArgumentProperty(RETURN_NULL_ON_NULL));
assertEquals(specialized.getArgumentProperty(1), valueTypeArgumentProperty(USE_BOXED_TYPE));
}
use of com.facebook.presto.operator.scalar.BuiltInScalarFunctionImplementation in project presto by prestodb.
the class InvokeFunctionBytecodeExpression method invokeFunction.
public static BytecodeExpression invokeFunction(Scope scope, CachedInstanceBinder cachedInstanceBinder, String name, JavaScalarFunctionImplementation function, List<BytecodeExpression> parameters) {
requireNonNull(scope, "scope is null");
requireNonNull(function, "function is null");
Optional<BytecodeNode> instance = Optional.empty();
if (function instanceof BuiltInScalarFunctionImplementation && ((BuiltInScalarFunctionImplementation) function).getInstanceFactory().isPresent()) {
FieldDefinition field = cachedInstanceBinder.getCachedInstance(((BuiltInScalarFunctionImplementation) function).getInstanceFactory().get());
instance = Optional.of(scope.getThis().getField(field));
}
return new InvokeFunctionBytecodeExpression(scope, cachedInstanceBinder.getCallSiteBinder(), name, function, instance, parameters);
}
Aggregations