use of io.trino.sql.planner.ParameterRewriter in project trino by trinodb.
the class PropertyUtil method evaluateProperty.
private static Object evaluateProperty(Expression expression, PropertyMetadata<?> property, Session session, PlannerContext plannerContext, AccessControl accessControl, Map<NodeRef<Parameter>, Expression> parameters, ErrorCodeSupplier errorCode, String propertyTypeDescription) {
Object sqlObjectValue;
try {
Type expectedType = property.getSqlType();
Expression rewritten = ExpressionTreeRewriter.rewriteWith(new ParameterRewriter(parameters), expression);
Object value = evaluateConstantExpression(rewritten, expectedType, plannerContext, session, accessControl, parameters);
// convert to object value type of SQL type
BlockBuilder blockBuilder = expectedType.createBlockBuilder(null, 1);
writeNativeValue(expectedType, blockBuilder, value);
sqlObjectValue = expectedType.getObjectValue(session.toConnectorSession(), blockBuilder, 0);
} catch (TrinoException e) {
throw new TrinoException(errorCode, format("Invalid value for %s '%s': Cannot convert [%s] to %s", propertyTypeDescription, property.getName(), expression, property.getSqlType()), e);
}
if (sqlObjectValue == null) {
throw new TrinoException(errorCode, format("Invalid null value for %s '%s' from [%s]", propertyTypeDescription, property.getName(), expression));
}
try {
return property.decode(sqlObjectValue);
} catch (Exception e) {
throw new TrinoException(errorCode, format("Unable to set %s '%s' to [%s]: %s", propertyTypeDescription, property.getName(), expression, e.getMessage()), e);
}
}
use of io.trino.sql.planner.ParameterRewriter 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();
}
use of io.trino.sql.planner.ParameterRewriter in project trino by trinodb.
the class SessionPropertyManager method evaluatePropertyValue.
public static Object evaluatePropertyValue(Expression expression, Type expectedType, Session session, PlannerContext plannerContext, AccessControl accessControl, Map<NodeRef<Parameter>, Expression> parameters) {
Expression rewritten = ExpressionTreeRewriter.rewriteWith(new ParameterRewriter(parameters), expression);
Object value = evaluateConstantExpression(rewritten, expectedType, plannerContext, session, accessControl, parameters);
// convert to object value type of SQL type
BlockBuilder blockBuilder = expectedType.createBlockBuilder(null, 1);
writeNativeValue(expectedType, blockBuilder, value);
Object objectValue = expectedType.getObjectValue(session.toConnectorSession(), blockBuilder, 0);
if (objectValue == null) {
throw new TrinoException(INVALID_SESSION_PROPERTY, "Session property value must not be null");
}
return objectValue;
}
Aggregations