Search in sources :

Example 1 with Argument

use of com.facebook.presto.spi.procedure.Procedure.Argument in project presto by prestodb.

the class ProcedureRegistry method validateProcedure.

private void validateProcedure(Procedure procedure) {
    List<Class<?>> parameters = procedure.getMethodHandle().type().parameterList().stream().filter(type -> !ConnectorSession.class.isAssignableFrom(type)).collect(toList());
    for (int i = 0; i < procedure.getArguments().size(); i++) {
        Argument argument = procedure.getArguments().get(i);
        Type type = typeManager.getType(argument.getType());
        Class<?> argumentType = Primitives.unwrap(parameters.get(i));
        Class<?> expectedType = getObjectType(type);
        checkArgument(expectedType.equals(argumentType), "Argument '%s' has invalid type %s (expected %s)", argument.getName(), argumentType.getName(), expectedType.getName());
    }
}
Also used : VARCHAR(com.facebook.presto.common.type.VarcharType.VARCHAR) PrestoException(com.facebook.presto.spi.PrestoException) PROCEDURE_NOT_FOUND(com.facebook.presto.spi.StandardErrorCode.PROCEDURE_NOT_FOUND) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) SchemaTableName(com.facebook.presto.spi.SchemaTableName) MAP(com.facebook.presto.common.type.StandardTypes.MAP) TypeManager(com.facebook.presto.common.type.TypeManager) Map(java.util.Map) Objects.requireNonNull(java.util.Objects.requireNonNull) BOOLEAN(com.facebook.presto.common.type.BooleanType.BOOLEAN) Type(com.facebook.presto.common.type.Type) Argument(com.facebook.presto.spi.procedure.Procedure.Argument) BIGINT(com.facebook.presto.common.type.BigintType.BIGINT) DOUBLE(com.facebook.presto.common.type.DoubleType.DOUBLE) Collection(java.util.Collection) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ThreadSafe(javax.annotation.concurrent.ThreadSafe) Maps(com.google.common.collect.Maps) ARRAY(com.facebook.presto.common.type.StandardTypes.ARRAY) Primitives(com.google.common.primitives.Primitives) Preconditions.checkState(com.google.common.base.Preconditions.checkState) ConnectorSession(com.facebook.presto.spi.ConnectorSession) Procedure(com.facebook.presto.spi.procedure.Procedure) List(java.util.List) Collectors.toList(java.util.stream.Collectors.toList) ConnectorId(com.facebook.presto.spi.ConnectorId) Type(com.facebook.presto.common.type.Type) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) Argument(com.facebook.presto.spi.procedure.Procedure.Argument) ConnectorSession(com.facebook.presto.spi.ConnectorSession)

Example 2 with Argument

use of com.facebook.presto.spi.procedure.Procedure.Argument in project presto by prestodb.

the class CallTask method execute.

@Override
public ListenableFuture<?> execute(Call call, TransactionManager transactionManager, Metadata metadata, AccessControl accessControl, QueryStateMachine stateMachine, List<Expression> parameters) {
    if (!stateMachine.isAutoCommit()) {
        throw new PrestoException(NOT_SUPPORTED, "Procedures cannot be called within a transaction (use autocommit mode)");
    }
    Session session = stateMachine.getSession();
    QualifiedObjectName procedureName = createQualifiedObjectName(session, call, call.getName());
    ConnectorId connectorId = metadata.getCatalogHandle(stateMachine.getSession(), procedureName.getCatalogName()).orElseThrow(() -> new SemanticException(MISSING_CATALOG, call, "Catalog %s does not exist", procedureName.getCatalogName()));
    Procedure procedure = metadata.getProcedureRegistry().resolve(connectorId, procedureName.asSchemaTableName());
    // map declared argument names to positions
    Map<String, Integer> positions = new HashMap<>();
    for (int i = 0; i < procedure.getArguments().size(); i++) {
        positions.put(procedure.getArguments().get(i).getName(), i);
    }
    // per specification, do not allow mixing argument types
    Predicate<CallArgument> hasName = argument -> argument.getName().isPresent();
    boolean anyNamed = call.getArguments().stream().anyMatch(hasName);
    boolean allNamed = call.getArguments().stream().allMatch(hasName);
    if (anyNamed && !allNamed) {
        throw new SemanticException(INVALID_PROCEDURE_ARGUMENTS, call, "Named and positional arguments cannot be mixed");
    }
    // get the argument names in call order
    Map<String, CallArgument> names = new LinkedHashMap<>();
    for (int i = 0; i < call.getArguments().size(); i++) {
        CallArgument argument = call.getArguments().get(i);
        if (argument.getName().isPresent()) {
            String name = argument.getName().get();
            if (names.put(name, argument) != null) {
                throw new SemanticException(INVALID_PROCEDURE_ARGUMENTS, argument, "Duplicate procedure argument: %s", name);
            }
            if (!positions.containsKey(name)) {
                throw new SemanticException(INVALID_PROCEDURE_ARGUMENTS, argument, "Unknown argument name: %s", name);
            }
        } else if (i < procedure.getArguments().size()) {
            names.put(procedure.getArguments().get(i).getName(), argument);
        } else {
            throw new SemanticException(INVALID_PROCEDURE_ARGUMENTS, call, "Too many arguments for procedure");
        }
    }
    // verify argument count
    if (names.size() < positions.size()) {
        throw new SemanticException(INVALID_PROCEDURE_ARGUMENTS, call, "Too few arguments for procedure");
    }
    // get argument values
    Object[] values = new Object[procedure.getArguments().size()];
    for (Entry<String, CallArgument> entry : names.entrySet()) {
        CallArgument callArgument = entry.getValue();
        int index = positions.get(entry.getKey());
        Argument argument = procedure.getArguments().get(index);
        Expression expression = ExpressionTreeRewriter.rewriteWith(new ParameterRewriter(parameters), callArgument.getValue());
        Type type = metadata.getType(argument.getType());
        checkCondition(type != null, INVALID_PROCEDURE_DEFINITION, "Unknown procedure argument type: %s", argument.getType());
        Object value = evaluateConstantExpression(expression, type, metadata, session, parameters);
        values[index] = toTypeObjectValue(session, type, value);
    }
    // validate arguments
    MethodType methodType = procedure.getMethodHandle().type();
    for (int i = 0; i < procedure.getArguments().size(); i++) {
        if ((values[i] == null) && methodType.parameterType(i).isPrimitive()) {
            String name = procedure.getArguments().get(i).getName();
            throw new PrestoException(INVALID_PROCEDURE_ARGUMENT, "Procedure argument cannot be null: " + name);
        }
    }
    // insert session argument
    List<Object> arguments = new ArrayList<>();
    Iterator<Object> valuesIterator = asList(values).iterator();
    for (Class<?> type : methodType.parameterList()) {
        if (ConnectorSession.class.isAssignableFrom(type)) {
            arguments.add(session.toConnectorSession(connectorId));
        } else {
            arguments.add(valuesIterator.next());
        }
    }
    try {
        procedure.getMethodHandle().invokeWithArguments(arguments);
    } catch (Throwable t) {
        if (t instanceof InterruptedException) {
            Thread.currentThread().interrupt();
        }
        propagateIfInstanceOf(t, PrestoException.class);
        throw new PrestoException(PROCEDURE_CALL_FAILED, t);
    }
    return immediateFuture(null);
}
Also used : ExpressionTreeRewriter(com.facebook.presto.sql.tree.ExpressionTreeRewriter) QualifiedObjectName(com.facebook.presto.metadata.QualifiedObjectName) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) HashMap(java.util.HashMap) TypeUtils.writeNativeValue(com.facebook.presto.spi.type.TypeUtils.writeNativeValue) PrestoException(com.facebook.presto.spi.PrestoException) SemanticException(com.facebook.presto.sql.analyzer.SemanticException) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) MISSING_CATALOG(com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_CATALOG) Type(com.facebook.presto.spi.type.Type) Arrays.asList(java.util.Arrays.asList) Map(java.util.Map) BlockBuilderStatus(com.facebook.presto.spi.block.BlockBuilderStatus) ExpressionInterpreter.evaluateConstantExpression(com.facebook.presto.sql.planner.ExpressionInterpreter.evaluateConstantExpression) INVALID_PROCEDURE_DEFINITION(com.facebook.presto.spi.StandardErrorCode.INVALID_PROCEDURE_DEFINITION) TransactionManager(com.facebook.presto.transaction.TransactionManager) Argument(com.facebook.presto.spi.procedure.Procedure.Argument) Failures.checkCondition(com.facebook.presto.util.Failures.checkCondition) Futures.immediateFuture(com.google.common.util.concurrent.Futures.immediateFuture) Iterator(java.util.Iterator) ParameterRewriter(com.facebook.presto.sql.planner.ParameterRewriter) Predicate(java.util.function.Predicate) Session(com.facebook.presto.Session) Throwables.propagateIfInstanceOf(com.google.common.base.Throwables.propagateIfInstanceOf) BlockBuilder(com.facebook.presto.spi.block.BlockBuilder) CallArgument(com.facebook.presto.sql.tree.CallArgument) ConnectorSession(com.facebook.presto.spi.ConnectorSession) INVALID_PROCEDURE_ARGUMENT(com.facebook.presto.spi.StandardErrorCode.INVALID_PROCEDURE_ARGUMENT) Procedure(com.facebook.presto.spi.procedure.Procedure) List(java.util.List) MethodType(java.lang.invoke.MethodType) Expression(com.facebook.presto.sql.tree.Expression) NOT_SUPPORTED(com.facebook.presto.spi.StandardErrorCode.NOT_SUPPORTED) MetadataUtil.createQualifiedObjectName(com.facebook.presto.metadata.MetadataUtil.createQualifiedObjectName) Entry(java.util.Map.Entry) ConnectorId(com.facebook.presto.connector.ConnectorId) Call(com.facebook.presto.sql.tree.Call) PROCEDURE_CALL_FAILED(com.facebook.presto.spi.StandardErrorCode.PROCEDURE_CALL_FAILED) INVALID_PROCEDURE_ARGUMENTS(com.facebook.presto.sql.analyzer.SemanticErrorCode.INVALID_PROCEDURE_ARGUMENTS) Metadata(com.facebook.presto.metadata.Metadata) AccessControl(com.facebook.presto.security.AccessControl) CallArgument(com.facebook.presto.sql.tree.CallArgument) Argument(com.facebook.presto.spi.procedure.Procedure.Argument) CallArgument(com.facebook.presto.sql.tree.CallArgument) ParameterRewriter(com.facebook.presto.sql.planner.ParameterRewriter) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ArrayList(java.util.ArrayList) PrestoException(com.facebook.presto.spi.PrestoException) LinkedHashMap(java.util.LinkedHashMap) Procedure(com.facebook.presto.spi.procedure.Procedure) ConnectorId(com.facebook.presto.connector.ConnectorId) SemanticException(com.facebook.presto.sql.analyzer.SemanticException) MethodType(java.lang.invoke.MethodType) QualifiedObjectName(com.facebook.presto.metadata.QualifiedObjectName) MetadataUtil.createQualifiedObjectName(com.facebook.presto.metadata.MetadataUtil.createQualifiedObjectName) Type(com.facebook.presto.spi.type.Type) MethodType(java.lang.invoke.MethodType) ExpressionInterpreter.evaluateConstantExpression(com.facebook.presto.sql.planner.ExpressionInterpreter.evaluateConstantExpression) Expression(com.facebook.presto.sql.tree.Expression) Session(com.facebook.presto.Session) ConnectorSession(com.facebook.presto.spi.ConnectorSession)

Example 3 with Argument

use of com.facebook.presto.spi.procedure.Procedure.Argument in project presto by prestodb.

the class CallTask method execute.

@Override
public ListenableFuture<?> execute(Call call, TransactionManager transactionManager, Metadata metadata, AccessControl accessControl, Session session, List<Expression> parameters, WarningCollector warningCollector) {
    if (!transactionManager.getTransactionInfo(session.getRequiredTransactionId()).isAutoCommitContext()) {
        throw new PrestoException(NOT_SUPPORTED, "Procedures cannot be called within a transaction (use autocommit mode)");
    }
    QualifiedObjectName procedureName = createQualifiedObjectName(session, call, call.getName());
    ConnectorId connectorId = metadata.getCatalogHandle(session, procedureName.getCatalogName()).orElseThrow(() -> new SemanticException(MISSING_CATALOG, call, "Catalog %s does not exist", procedureName.getCatalogName()));
    Procedure procedure = metadata.getProcedureRegistry().resolve(connectorId, toSchemaTableName(procedureName));
    // map declared argument names to positions
    Map<String, Integer> positions = new HashMap<>();
    for (int i = 0; i < procedure.getArguments().size(); i++) {
        positions.put(procedure.getArguments().get(i).getName(), i);
    }
    // per specification, do not allow mixing argument types
    Predicate<CallArgument> hasName = argument -> argument.getName().isPresent();
    boolean anyNamed = call.getArguments().stream().anyMatch(hasName);
    boolean allNamed = call.getArguments().stream().allMatch(hasName);
    if (anyNamed && !allNamed) {
        throw new SemanticException(INVALID_PROCEDURE_ARGUMENTS, call, "Named and positional arguments cannot be mixed");
    }
    // get the argument names in call order
    Map<String, CallArgument> names = new LinkedHashMap<>();
    for (int i = 0; i < call.getArguments().size(); i++) {
        CallArgument argument = call.getArguments().get(i);
        if (argument.getName().isPresent()) {
            String name = argument.getName().get();
            if (names.put(name, argument) != null) {
                throw new SemanticException(INVALID_PROCEDURE_ARGUMENTS, argument, "Duplicate procedure argument: %s", name);
            }
            if (!positions.containsKey(name)) {
                throw new SemanticException(INVALID_PROCEDURE_ARGUMENTS, argument, "Unknown argument name: %s", name);
            }
        } else if (i < procedure.getArguments().size()) {
            names.put(procedure.getArguments().get(i).getName(), argument);
        } else {
            throw new SemanticException(INVALID_PROCEDURE_ARGUMENTS, call, "Too many arguments for procedure");
        }
    }
    procedure.getArguments().stream().filter(Argument::isRequired).filter(argument -> !names.containsKey(argument.getName())).map(Argument::getName).findFirst().ifPresent(argument -> {
        throw new SemanticException(INVALID_PROCEDURE_ARGUMENTS, call, format("Required procedure argument '%s' is missing", argument));
    });
    // get argument values
    Object[] values = new Object[procedure.getArguments().size()];
    for (Entry<String, CallArgument> entry : names.entrySet()) {
        CallArgument callArgument = entry.getValue();
        int index = positions.get(entry.getKey());
        Argument argument = procedure.getArguments().get(index);
        Expression expression = ExpressionTreeRewriter.rewriteWith(new ParameterRewriter(parameters), callArgument.getValue());
        Type type = metadata.getType(argument.getType());
        checkCondition(type != null, INVALID_PROCEDURE_DEFINITION, "Unknown procedure argument type: %s", argument.getType());
        Object value = evaluateConstantExpression(expression, type, metadata, session, parameters);
        values[index] = toTypeObjectValue(session, type, value);
    }
    // fill values with optional arguments defaults
    for (int i = 0; i < procedure.getArguments().size(); i++) {
        Argument argument = procedure.getArguments().get(i);
        if (!names.containsKey(argument.getName())) {
            verify(argument.isOptional());
            values[i] = toTypeObjectValue(session, metadata.getType(argument.getType()), argument.getDefaultValue());
        }
    }
    // validate arguments
    MethodType methodType = procedure.getMethodHandle().type();
    for (int i = 0; i < procedure.getArguments().size(); i++) {
        if ((values[i] == null) && methodType.parameterType(i).isPrimitive()) {
            String name = procedure.getArguments().get(i).getName();
            throw new PrestoException(INVALID_PROCEDURE_ARGUMENT, "Procedure argument cannot be null: " + name);
        }
    }
    // insert session argument
    List<Object> arguments = new ArrayList<>();
    Iterator<Object> valuesIterator = asList(values).iterator();
    for (Class<?> type : methodType.parameterList()) {
        if (ConnectorSession.class.isAssignableFrom(type)) {
            arguments.add(session.toConnectorSession(connectorId));
        } else {
            arguments.add(valuesIterator.next());
        }
    }
    try {
        procedure.getMethodHandle().invokeWithArguments(arguments);
    } catch (Throwable t) {
        if (t instanceof InterruptedException) {
            Thread.currentThread().interrupt();
        }
        throwIfInstanceOf(t, PrestoException.class);
        throw new PrestoException(PROCEDURE_CALL_FAILED, t);
    }
    return immediateFuture(null);
}
Also used : ExpressionTreeRewriter(com.facebook.presto.sql.tree.ExpressionTreeRewriter) WarningCollector(com.facebook.presto.spi.WarningCollector) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) HashMap(java.util.HashMap) PrestoException(com.facebook.presto.spi.PrestoException) SemanticException(com.facebook.presto.sql.analyzer.SemanticException) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) MISSING_CATALOG(com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_CATALOG) Verify.verify(com.google.common.base.Verify.verify) Arrays.asList(java.util.Arrays.asList) Map(java.util.Map) QualifiedObjectName(com.facebook.presto.common.QualifiedObjectName) ExpressionInterpreter.evaluateConstantExpression(com.facebook.presto.sql.planner.ExpressionInterpreter.evaluateConstantExpression) INVALID_PROCEDURE_DEFINITION(com.facebook.presto.spi.StandardErrorCode.INVALID_PROCEDURE_DEFINITION) TransactionManager(com.facebook.presto.transaction.TransactionManager) Type(com.facebook.presto.common.type.Type) Argument(com.facebook.presto.spi.procedure.Procedure.Argument) Failures.checkCondition(com.facebook.presto.util.Failures.checkCondition) Futures.immediateFuture(com.google.common.util.concurrent.Futures.immediateFuture) BlockBuilder(com.facebook.presto.common.block.BlockBuilder) MetadataUtil.toSchemaTableName(com.facebook.presto.metadata.MetadataUtil.toSchemaTableName) Iterator(java.util.Iterator) ParameterRewriter(com.facebook.presto.sql.planner.ParameterRewriter) Predicate(java.util.function.Predicate) Session(com.facebook.presto.Session) TypeUtils.writeNativeValue(com.facebook.presto.common.type.TypeUtils.writeNativeValue) CallArgument(com.facebook.presto.sql.tree.CallArgument) Throwables.throwIfInstanceOf(com.google.common.base.Throwables.throwIfInstanceOf) String.format(java.lang.String.format) ConnectorSession(com.facebook.presto.spi.ConnectorSession) INVALID_PROCEDURE_ARGUMENT(com.facebook.presto.spi.StandardErrorCode.INVALID_PROCEDURE_ARGUMENT) Procedure(com.facebook.presto.spi.procedure.Procedure) List(java.util.List) MethodType(java.lang.invoke.MethodType) Expression(com.facebook.presto.sql.tree.Expression) NOT_SUPPORTED(com.facebook.presto.spi.StandardErrorCode.NOT_SUPPORTED) MetadataUtil.createQualifiedObjectName(com.facebook.presto.metadata.MetadataUtil.createQualifiedObjectName) Entry(java.util.Map.Entry) Call(com.facebook.presto.sql.tree.Call) ConnectorId(com.facebook.presto.spi.ConnectorId) PROCEDURE_CALL_FAILED(com.facebook.presto.spi.StandardErrorCode.PROCEDURE_CALL_FAILED) INVALID_PROCEDURE_ARGUMENTS(com.facebook.presto.sql.analyzer.SemanticErrorCode.INVALID_PROCEDURE_ARGUMENTS) Metadata(com.facebook.presto.metadata.Metadata) AccessControl(com.facebook.presto.security.AccessControl) CallArgument(com.facebook.presto.sql.tree.CallArgument) Argument(com.facebook.presto.spi.procedure.Procedure.Argument) CallArgument(com.facebook.presto.sql.tree.CallArgument) ParameterRewriter(com.facebook.presto.sql.planner.ParameterRewriter) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ArrayList(java.util.ArrayList) PrestoException(com.facebook.presto.spi.PrestoException) LinkedHashMap(java.util.LinkedHashMap) Procedure(com.facebook.presto.spi.procedure.Procedure) ConnectorId(com.facebook.presto.spi.ConnectorId) SemanticException(com.facebook.presto.sql.analyzer.SemanticException) MethodType(java.lang.invoke.MethodType) QualifiedObjectName(com.facebook.presto.common.QualifiedObjectName) MetadataUtil.createQualifiedObjectName(com.facebook.presto.metadata.MetadataUtil.createQualifiedObjectName) Type(com.facebook.presto.common.type.Type) MethodType(java.lang.invoke.MethodType) ExpressionInterpreter.evaluateConstantExpression(com.facebook.presto.sql.planner.ExpressionInterpreter.evaluateConstantExpression) Expression(com.facebook.presto.sql.tree.Expression)

Aggregations

ConnectorSession (com.facebook.presto.spi.ConnectorSession)3 PrestoException (com.facebook.presto.spi.PrestoException)3 Procedure (com.facebook.presto.spi.procedure.Procedure)3 Argument (com.facebook.presto.spi.procedure.Procedure.Argument)3 List (java.util.List)3 Map (java.util.Map)3 Session (com.facebook.presto.Session)2 Type (com.facebook.presto.common.type.Type)2 Metadata (com.facebook.presto.metadata.Metadata)2 MetadataUtil.createQualifiedObjectName (com.facebook.presto.metadata.MetadataUtil.createQualifiedObjectName)2 AccessControl (com.facebook.presto.security.AccessControl)2 INVALID_PROCEDURE_ARGUMENT (com.facebook.presto.spi.StandardErrorCode.INVALID_PROCEDURE_ARGUMENT)2 INVALID_PROCEDURE_DEFINITION (com.facebook.presto.spi.StandardErrorCode.INVALID_PROCEDURE_DEFINITION)2 NOT_SUPPORTED (com.facebook.presto.spi.StandardErrorCode.NOT_SUPPORTED)2 PROCEDURE_CALL_FAILED (com.facebook.presto.spi.StandardErrorCode.PROCEDURE_CALL_FAILED)2 INVALID_PROCEDURE_ARGUMENTS (com.facebook.presto.sql.analyzer.SemanticErrorCode.INVALID_PROCEDURE_ARGUMENTS)2 MISSING_CATALOG (com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_CATALOG)2 SemanticException (com.facebook.presto.sql.analyzer.SemanticException)2 ExpressionInterpreter.evaluateConstantExpression (com.facebook.presto.sql.planner.ExpressionInterpreter.evaluateConstantExpression)2 ParameterRewriter (com.facebook.presto.sql.planner.ParameterRewriter)2