Search in sources :

Example 1 with Argument

use of io.trino.spi.procedure.Procedure.Argument in project trino by trinodb.

the class CallTask method execute.

@Override
public ListenableFuture<Void> execute(Call call, QueryStateMachine stateMachine, List<Expression> parameters, WarningCollector warningCollector) {
    if (!transactionManager.isAutoCommit(stateMachine.getSession().getRequiredTransactionId())) {
        throw new TrinoException(NOT_SUPPORTED, "Procedures cannot be called within a transaction (use autocommit mode)");
    }
    Session session = stateMachine.getSession();
    QualifiedObjectName procedureName = createQualifiedObjectName(session, call, call.getName());
    CatalogName catalogName = plannerContext.getMetadata().getCatalogHandle(stateMachine.getSession(), procedureName.getCatalogName()).orElseThrow(() -> semanticException(CATALOG_NOT_FOUND, call, "Catalog '%s' does not exist", procedureName.getCatalogName()));
    Procedure procedure = procedureRegistry.resolve(catalogName, 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 semanticException(INVALID_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().getCanonicalValue();
            if (names.put(name, argument) != null) {
                throw semanticException(INVALID_ARGUMENTS, argument, "Duplicate procedure argument: %s", name);
            }
            if (!positions.containsKey(name)) {
                throw semanticException(INVALID_ARGUMENTS, argument, "Unknown argument name: %s", name);
            }
        } else if (i < procedure.getArguments().size()) {
            names.put(procedure.getArguments().get(i).getName(), argument);
        } else {
            throw semanticException(INVALID_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 semanticException(INVALID_ARGUMENTS, call, "Required procedure argument '%s' is missing", argument);
    });
    // get argument values
    Object[] values = new Object[procedure.getArguments().size()];
    Map<NodeRef<Parameter>, Expression> parameterLookup = parameterExtractor(call, parameters);
    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(parameterLookup), callArgument.getValue());
        Type type = argument.getType();
        Object value = evaluateConstantExpression(expression, type, plannerContext, session, accessControl, parameterLookup);
        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, 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 TrinoException(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.equals(type)) {
            arguments.add(session.toConnectorSession(catalogName));
        } else if (ConnectorAccessControl.class.equals(type)) {
            arguments.add(new InjectedConnectorAccessControl(accessControl, session.toSecurityContext(), catalogName.getCatalogName()));
        } else {
            arguments.add(valuesIterator.next());
        }
    }
    accessControl.checkCanExecuteProcedure(session.toSecurityContext(), procedureName);
    stateMachine.setRoutines(ImmutableList.of(new RoutineInfo(procedureName.getObjectName(), session.getUser())));
    try {
        procedure.getMethodHandle().invokeWithArguments(arguments);
    } catch (Throwable t) {
        if (t instanceof InterruptedException) {
            Thread.currentThread().interrupt();
        }
        throwIfInstanceOf(t, TrinoException.class);
        throw new TrinoException(PROCEDURE_CALL_FAILED, t);
    }
    return immediateVoidFuture();
}
Also used : InjectedConnectorAccessControl(io.trino.security.InjectedConnectorAccessControl) TransactionManager(io.trino.transaction.TransactionManager) ParameterUtils.parameterExtractor(io.trino.sql.ParameterUtils.parameterExtractor) NOT_SUPPORTED(io.trino.spi.StandardErrorCode.NOT_SUPPORTED) CatalogName(io.trino.connector.CatalogName) Arrays.asList(java.util.Arrays.asList) Map(java.util.Map) SemanticExceptions.semanticException(io.trino.sql.analyzer.SemanticExceptions.semanticException) Argument(io.trino.spi.procedure.Procedure.Argument) Futures.immediateVoidFuture(com.google.common.util.concurrent.Futures.immediateVoidFuture) INVALID_ARGUMENTS(io.trino.spi.StandardErrorCode.INVALID_ARGUMENTS) Predicate(java.util.function.Predicate) ExpressionTreeRewriter(io.trino.sql.tree.ExpressionTreeRewriter) ConnectorAccessControl(io.trino.spi.connector.ConnectorAccessControl) TrinoException(io.trino.spi.TrinoException) TypeUtils.writeNativeValue(io.trino.spi.type.TypeUtils.writeNativeValue) List(java.util.List) AccessControl(io.trino.security.AccessControl) Parameter(io.trino.sql.tree.Parameter) Entry(java.util.Map.Entry) Expression(io.trino.sql.tree.Expression) PROCEDURE_CALL_FAILED(io.trino.spi.StandardErrorCode.PROCEDURE_CALL_FAILED) Session(io.trino.Session) PlannerContext(io.trino.sql.PlannerContext) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) ExpressionInterpreter.evaluateConstantExpression(io.trino.sql.planner.ExpressionInterpreter.evaluateConstantExpression) RoutineInfo(io.trino.spi.eventlistener.RoutineInfo) Type(io.trino.spi.type.Type) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Inject(javax.inject.Inject) LinkedHashMap(java.util.LinkedHashMap) INVALID_PROCEDURE_ARGUMENT(io.trino.spi.StandardErrorCode.INVALID_PROCEDURE_ARGUMENT) ImmutableList(com.google.common.collect.ImmutableList) Procedure(io.trino.spi.procedure.Procedure) Verify.verify(com.google.common.base.Verify.verify) MetadataUtil.createQualifiedObjectName(io.trino.metadata.MetadataUtil.createQualifiedObjectName) NodeRef(io.trino.sql.tree.NodeRef) Objects.requireNonNull(java.util.Objects.requireNonNull) Iterator(java.util.Iterator) CATALOG_NOT_FOUND(io.trino.spi.StandardErrorCode.CATALOG_NOT_FOUND) ConnectorSession(io.trino.spi.connector.ConnectorSession) Throwables.throwIfInstanceOf(com.google.common.base.Throwables.throwIfInstanceOf) CallArgument(io.trino.sql.tree.CallArgument) Call(io.trino.sql.tree.Call) MethodType(java.lang.invoke.MethodType) QualifiedObjectName(io.trino.metadata.QualifiedObjectName) ProcedureRegistry(io.trino.metadata.ProcedureRegistry) WarningCollector(io.trino.execution.warnings.WarningCollector) BlockBuilder(io.trino.spi.block.BlockBuilder) ParameterRewriter(io.trino.sql.planner.ParameterRewriter) CallArgument(io.trino.sql.tree.CallArgument) Argument(io.trino.spi.procedure.Procedure.Argument) CallArgument(io.trino.sql.tree.CallArgument) ParameterRewriter(io.trino.sql.planner.ParameterRewriter) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) RoutineInfo(io.trino.spi.eventlistener.RoutineInfo) NodeRef(io.trino.sql.tree.NodeRef) Procedure(io.trino.spi.procedure.Procedure) MethodType(java.lang.invoke.MethodType) InjectedConnectorAccessControl(io.trino.security.InjectedConnectorAccessControl) ConnectorAccessControl(io.trino.spi.connector.ConnectorAccessControl) MetadataUtil.createQualifiedObjectName(io.trino.metadata.MetadataUtil.createQualifiedObjectName) QualifiedObjectName(io.trino.metadata.QualifiedObjectName) InjectedConnectorAccessControl(io.trino.security.InjectedConnectorAccessControl) Type(io.trino.spi.type.Type) MethodType(java.lang.invoke.MethodType) Expression(io.trino.sql.tree.Expression) ExpressionInterpreter.evaluateConstantExpression(io.trino.sql.planner.ExpressionInterpreter.evaluateConstantExpression) TrinoException(io.trino.spi.TrinoException) CatalogName(io.trino.connector.CatalogName) Session(io.trino.Session) ConnectorSession(io.trino.spi.connector.ConnectorSession)

Example 2 with Argument

use of io.trino.spi.procedure.Procedure.Argument in project trino by trinodb.

the class ProcedureRegistry method validateProcedure.

private void validateProcedure(Procedure procedure) {
    List<Class<?>> parameters = procedure.getMethodHandle().type().parameterList().stream().filter(type -> !ConnectorSession.class.equals(type)).filter(type -> !ConnectorAccessControl.class.equals(type)).collect(toList());
    for (int i = 0; i < procedure.getArguments().size(); i++) {
        Argument argument = procedure.getArguments().get(i);
        Type type = 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 : PROCEDURE_NOT_FOUND(io.trino.spi.StandardErrorCode.PROCEDURE_NOT_FOUND) Type(io.trino.spi.type.Type) BOOLEAN(io.trino.spi.type.BooleanType.BOOLEAN) CatalogName(io.trino.connector.CatalogName) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) VARCHAR(io.trino.spi.type.VarcharType.VARCHAR) Procedure(io.trino.spi.procedure.Procedure) Map(java.util.Map) Objects.requireNonNull(java.util.Objects.requireNonNull) Argument(io.trino.spi.procedure.Procedure.Argument) MapType(io.trino.spi.type.MapType) Collection(java.util.Collection) ConnectorAccessControl(io.trino.spi.connector.ConnectorAccessControl) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) TrinoException(io.trino.spi.TrinoException) ArrayType(io.trino.spi.type.ArrayType) ThreadSafe(javax.annotation.concurrent.ThreadSafe) ConnectorSession(io.trino.spi.connector.ConnectorSession) Maps(com.google.common.collect.Maps) SchemaTableName(io.trino.spi.connector.SchemaTableName) Primitives(com.google.common.primitives.Primitives) Preconditions.checkState(com.google.common.base.Preconditions.checkState) DOUBLE(io.trino.spi.type.DoubleType.DOUBLE) List(java.util.List) Collectors.toList(java.util.stream.Collectors.toList) BIGINT(io.trino.spi.type.BigintType.BIGINT) Type(io.trino.spi.type.Type) MapType(io.trino.spi.type.MapType) ArrayType(io.trino.spi.type.ArrayType) ConnectorAccessControl(io.trino.spi.connector.ConnectorAccessControl) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) Argument(io.trino.spi.procedure.Procedure.Argument)

Aggregations

CatalogName (io.trino.connector.CatalogName)2 TrinoException (io.trino.spi.TrinoException)2 ConnectorAccessControl (io.trino.spi.connector.ConnectorAccessControl)2 ConnectorSession (io.trino.spi.connector.ConnectorSession)2 Procedure (io.trino.spi.procedure.Procedure)2 Argument (io.trino.spi.procedure.Procedure.Argument)2 Type (io.trino.spi.type.Type)2 Preconditions.checkArgument (com.google.common.base.Preconditions.checkArgument)1 Preconditions.checkState (com.google.common.base.Preconditions.checkState)1 Throwables.throwIfInstanceOf (com.google.common.base.Throwables.throwIfInstanceOf)1 Verify.verify (com.google.common.base.Verify.verify)1 ImmutableList (com.google.common.collect.ImmutableList)1 Maps (com.google.common.collect.Maps)1 Primitives (com.google.common.primitives.Primitives)1 Futures.immediateVoidFuture (com.google.common.util.concurrent.Futures.immediateVoidFuture)1 ListenableFuture (com.google.common.util.concurrent.ListenableFuture)1 Session (io.trino.Session)1 WarningCollector (io.trino.execution.warnings.WarningCollector)1 MetadataUtil.createQualifiedObjectName (io.trino.metadata.MetadataUtil.createQualifiedObjectName)1 ProcedureRegistry (io.trino.metadata.ProcedureRegistry)1