Search in sources :

Example 6 with BuiltInScalarFunctionImplementation

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;
}
Also used : LabelNode(com.facebook.presto.bytecode.instruction.LabelNode) Binding(com.facebook.presto.bytecode.Binding) MethodType(java.lang.invoke.MethodType) ArgumentProperty(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentProperty) BuiltInScalarFunctionImplementation(com.facebook.presto.operator.scalar.BuiltInScalarFunctionImplementation) SqlFunctionProperties(com.facebook.presto.common.function.SqlFunctionProperties) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) ArrayList(java.util.ArrayList) ScalarFunctionImplementationChoice(com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice) InputReferenceNode(com.facebook.presto.sql.gen.InputReferenceCompiler.InputReferenceNode)

Example 7 with BuiltInScalarFunctionImplementation

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);
}
Also used : BuiltInScalarFunctionImplementation(com.facebook.presto.operator.scalar.BuiltInScalarFunctionImplementation) FieldDefinition(com.facebook.presto.bytecode.FieldDefinition) BytecodeNode(com.facebook.presto.bytecode.BytecodeNode)

Example 8 with BuiltInScalarFunctionImplementation

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);
}
Also used : BuiltInScalarFunctionImplementation(com.facebook.presto.operator.scalar.BuiltInScalarFunctionImplementation) TypeSignature.parseTypeSignature(com.facebook.presto.common.type.TypeSignature.parseTypeSignature) Signature(com.facebook.presto.spi.function.Signature) ParametricScalar(com.facebook.presto.operator.scalar.ParametricScalar) SqlScalarFunction(com.facebook.presto.metadata.SqlScalarFunction) Test(org.testng.annotations.Test)

Example 9 with BuiltInScalarFunctionImplementation

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));
}
Also used : BuiltInScalarFunctionImplementation(com.facebook.presto.operator.scalar.BuiltInScalarFunctionImplementation) TypeSignature.parseTypeSignature(com.facebook.presto.common.type.TypeSignature.parseTypeSignature) Signature(com.facebook.presto.spi.function.Signature) ParametricScalar(com.facebook.presto.operator.scalar.ParametricScalar) SqlScalarFunction(com.facebook.presto.metadata.SqlScalarFunction) Test(org.testng.annotations.Test)

Example 10 with BuiltInScalarFunctionImplementation

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);
}
Also used : BuiltInScalarFunctionImplementation(com.facebook.presto.operator.scalar.BuiltInScalarFunctionImplementation) FieldDefinition(com.facebook.presto.bytecode.FieldDefinition) BytecodeNode(com.facebook.presto.bytecode.BytecodeNode)

Aggregations

BuiltInScalarFunctionImplementation (com.facebook.presto.operator.scalar.BuiltInScalarFunctionImplementation)14 TypeSignature.parseTypeSignature (com.facebook.presto.common.type.TypeSignature.parseTypeSignature)10 Signature (com.facebook.presto.spi.function.Signature)10 Test (org.testng.annotations.Test)9 TypeSignature (com.facebook.presto.common.type.TypeSignature)7 ImmutableMap (com.google.common.collect.ImmutableMap)7 Block (com.facebook.presto.common.block.Block)6 LongArrayBlock (com.facebook.presto.common.block.LongArrayBlock)6 ADD (com.facebook.presto.common.function.OperatorType.ADD)6 IS_DISTINCT_FROM (com.facebook.presto.common.function.OperatorType.IS_DISTINCT_FROM)6 MAX_SHORT_PRECISION (com.facebook.presto.common.type.Decimals.MAX_SHORT_PRECISION)6 StandardTypes (com.facebook.presto.common.type.StandardTypes)6 BOOLEAN (com.facebook.presto.common.type.StandardTypes.BOOLEAN)6 VARCHAR (com.facebook.presto.common.type.StandardTypes.VARCHAR)6 FunctionAndTypeManager.createTestFunctionAndTypeManager (com.facebook.presto.metadata.FunctionAndTypeManager.createTestFunctionAndTypeManager)6 VARCHAR_TO_BIGINT_RETURN_VALUE (com.facebook.presto.metadata.TestPolymorphicScalarFunction.TestMethods.VARCHAR_TO_BIGINT_RETURN_VALUE)6 VARCHAR_TO_VARCHAR_RETURN_VALUE (com.facebook.presto.metadata.TestPolymorphicScalarFunction.TestMethods.VARCHAR_TO_VARCHAR_RETURN_VALUE)6 ArgumentProperty.valueTypeArgumentProperty (com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.ArgumentProperty.valueTypeArgumentProperty)6 BLOCK_AND_POSITION (com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.NullConvention.BLOCK_AND_POSITION)6 USE_NULL_FLAG (com.facebook.presto.operator.scalar.ScalarFunctionImplementationChoice.NullConvention.USE_NULL_FLAG)6