diff --git a/presto-main/src/main/java/com/facebook/presto/translator/AbstractExpressionTranslator.java b/presto-main/src/main/java/com/facebook/presto/translator/AbstractExpressionTranslator.java new file mode 100644 index 000000000000..d1faf4240e1c --- /dev/null +++ b/presto-main/src/main/java/com/facebook/presto/translator/AbstractExpressionTranslator.java @@ -0,0 +1,129 @@ +package com.facebook.presto.translator; + +import com.facebook.presto.spi.relation.CallExpression; +import com.facebook.presto.spi.relation.ConstantExpression; +import com.facebook.presto.spi.relation.InputReferenceExpression; +import com.facebook.presto.spi.relation.LambdaDefinitionExpression; +import com.facebook.presto.spi.relation.SpecialFormExpression; +import com.facebook.presto.spi.relation.VariableReferenceExpression; +import com.facebook.presto.spi.translator.ExpressionTranslator; +import com.facebook.presto.spi.translator.TargetExpression; +import com.facebook.presto.translator.registry.ConstantTypeRegistry; +import com.facebook.presto.translator.registry.FunctionRegistry; + +import java.util.Map; + +public abstract class AbstractExpressionTranslator + implements ExpressionTranslator +{ + private final FunctionRegistry functionRegistry; + private final ConstantTypeRegistry constantTypeRegistry; + + public AbstractExpressionTranslator(FunctionRegistry functionRegistry, ConstantTypeRegistry constantTypeRegistry) + { + this.functionRegistry = functionRegistry; + this.constantTypeRegistry = constantTypeRegistry; + } + + @Override + public TargetExpression translateCallExpression(CallExpression callExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateInputReferenceExpression(InputReferenceExpression inputReferenceExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateConstantExpression(ConstantExpression constantExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateLambdaDefinitionExpression(LambdaDefinitionExpression lambdaDefinitionExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateVariableReferenceExpression(VariableReferenceExpression variableReferenceExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateIf(SpecialFormExpression specialFormExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateNullIf(SpecialFormExpression specialFormExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateSwitch(SpecialFormExpression specialFormExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateWhen(SpecialFormExpression specialFormExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateIsNull(SpecialFormExpression specialFormExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateCoalesce(SpecialFormExpression specialFormExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateIn(SpecialFormExpression specialFormExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateAnd(SpecialFormExpression specialFormExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateOr(SpecialFormExpression specialFormExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateDereference(SpecialFormExpression specialFormExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateRowConstructor(SpecialFormExpression specialFormExpression, Map context) + { + return null; + } + + @Override + public TargetExpression translateBind(SpecialFormExpression specialFormExpression, Map context) + { + return null; + } +} diff --git a/presto-main/src/main/java/com/facebook/presto/translator/RowExpressionTranslator.java b/presto-main/src/main/java/com/facebook/presto/translator/RowExpressionTranslator.java new file mode 100644 index 000000000000..97149277254a --- /dev/null +++ b/presto-main/src/main/java/com/facebook/presto/translator/RowExpressionTranslator.java @@ -0,0 +1,33 @@ +package com.facebook.presto.translator; + +import com.facebook.presto.spi.ColumnHandle; +import com.facebook.presto.spi.function.FunctionMetadataManager; +import com.facebook.presto.spi.function.StandardFunctionResolution; +import com.facebook.presto.spi.relation.DeterminismEvaluator; +import com.facebook.presto.spi.relation.LogicalRowExpressions; +import com.facebook.presto.spi.relation.RowExpression; +import com.facebook.presto.spi.relation.VariableReferenceExpression; +import com.facebook.presto.spi.translator.ExpressionTranslator; +import com.facebook.presto.spi.translator.TargetExpression; + +import java.util.Map; + +public class RowExpressionTranslator +{ + private final RowExpressionTranslatorVisitor visitor; + private final LogicalRowExpressions logicalRowExpressions; + + public RowExpressionTranslator( + ExpressionTranslator expressionTranslator, FunctionMetadataManager functionMetadataManager, StandardFunctionResolution functionResolution, DeterminismEvaluator determinismEvaluator) + { + this.visitor = new RowExpressionTranslatorVisitor<>(expressionTranslator); + this.logicalRowExpressions = new LogicalRowExpressions(determinismEvaluator, functionResolution, functionMetadataManager); + } + + public TargetExpression translate( + RowExpression expression, + Map assignments) + { + return logicalRowExpressions.convertToConjunctiveNormalForm(expression).accept(visitor, assignments); + } +} diff --git a/presto-main/src/main/java/com/facebook/presto/translator/RowExpressionTranslatorVisitor.java b/presto-main/src/main/java/com/facebook/presto/translator/RowExpressionTranslatorVisitor.java new file mode 100644 index 000000000000..dccfda749c15 --- /dev/null +++ b/presto-main/src/main/java/com/facebook/presto/translator/RowExpressionTranslatorVisitor.java @@ -0,0 +1,90 @@ +package com.facebook.presto.translator; + +import com.facebook.presto.spi.ColumnHandle; +import com.facebook.presto.spi.relation.CallExpression; +import com.facebook.presto.spi.relation.ConstantExpression; +import com.facebook.presto.spi.relation.InputReferenceExpression; +import com.facebook.presto.spi.relation.LambdaDefinitionExpression; +import com.facebook.presto.spi.relation.RowExpressionVisitor; +import com.facebook.presto.spi.relation.SpecialFormExpression; +import com.facebook.presto.spi.relation.VariableReferenceExpression; +import com.facebook.presto.spi.translator.ExpressionTranslator; +import com.facebook.presto.spi.translator.TargetExpression; + +import java.util.Map; + +import static java.util.Objects.requireNonNull; + +class RowExpressionTranslatorVisitor + implements RowExpressionVisitor, Map> +{ + private final ExpressionTranslator expressionTranslator; + + public RowExpressionTranslatorVisitor(ExpressionTranslator expressionTranslator) + { + this.expressionTranslator = requireNonNull(expressionTranslator); + } + + @Override + public TargetExpression visitCall(CallExpression call, Map context) + { + return expressionTranslator.translateCallExpression(call, context); + } + + @Override + public TargetExpression visitInputReference(InputReferenceExpression reference, Map context) + { + return expressionTranslator.translateInputReferenceExpression(reference, context); + } + + @Override + public TargetExpression visitConstant(ConstantExpression literal, Map context) + { + return expressionTranslator.translateConstantExpression(literal, context); + } + + @Override + public TargetExpression visitLambda(LambdaDefinitionExpression lambda, Map context) + { + return expressionTranslator.translateLambdaDefinitionExpression(lambda, context); + } + + @Override + public TargetExpression visitVariableReference(VariableReferenceExpression reference, Map context) + { + return expressionTranslator.translateVariableReferenceExpression(reference, context); + } + + @Override + public TargetExpression visitSpecialForm(SpecialFormExpression specialForm, Map context) + { + switch (specialForm.getForm()) { + case IF: + return expressionTranslator.translateIf(specialForm, context); + case NULL_IF: + return expressionTranslator.translateNullIf(specialForm, context); + case SWITCH: + return expressionTranslator.translateSwitch(specialForm, context); + case WHEN: + return expressionTranslator.translateWhen(specialForm, context); + case IS_NULL: + return expressionTranslator.translateIsNull(specialForm, context); + case COALESCE: + return expressionTranslator.translateCoalesce(specialForm, context); + case IN: + return expressionTranslator.translateIn(specialForm, context); + case AND: + return expressionTranslator.translateAnd(specialForm, context); + case OR: + return expressionTranslator.translateOr(specialForm, context); + case DEREFERENCE: + return expressionTranslator.translateDereference(specialForm, context); + case ROW_CONSTRUCTOR: + return expressionTranslator.translateRowConstructor(specialForm, context); + case BIND: + return expressionTranslator.translateBind(specialForm, context); + default: + throw new IllegalStateException("Unexpected value: " + specialForm.getForm()); + } + } +} diff --git a/presto-main/src/main/java/com/facebook/presto/translator/registry/ConstantTypeRegistry.java b/presto-main/src/main/java/com/facebook/presto/translator/registry/ConstantTypeRegistry.java new file mode 100644 index 000000000000..14e1c76bb29d --- /dev/null +++ b/presto-main/src/main/java/com/facebook/presto/translator/registry/ConstantTypeRegistry.java @@ -0,0 +1,34 @@ +package com.facebook.presto.translator.registry; + +import com.facebook.presto.spi.type.Type; +import com.facebook.presto.spi.type.TypeSignature; +import com.google.common.collect.ImmutableSet; + +import java.util.Arrays; +import java.util.Set; + +import static com.facebook.presto.translator.registry.ScalarFromAnnotationsParser.removeTypeParameters; + +public class ConstantTypeRegistry +{ + private final Set constantTypes; + + public ConstantTypeRegistry(Type... types) + { + ImmutableSet.Builder constantTypes = ImmutableSet.builder(); + Arrays.stream(types).forEach(type -> { + constantTypes.add(removeTypeParameters(type.getTypeSignature())); + }); + this.constantTypes = constantTypes.build(); + } + + public Set getConstantTypes() + { + return constantTypes; + } + + public boolean constantTypesContains(TypeSignature typeSignature) + { + return constantTypes.contains(typeSignature); + } +} diff --git a/presto-main/src/main/java/com/facebook/presto/translator/registry/FunctionRegistry.java b/presto-main/src/main/java/com/facebook/presto/translator/registry/FunctionRegistry.java new file mode 100644 index 000000000000..76d8e2bc56fb --- /dev/null +++ b/presto-main/src/main/java/com/facebook/presto/translator/registry/FunctionRegistry.java @@ -0,0 +1,34 @@ +package com.facebook.presto.translator.registry; + +import com.facebook.presto.spi.function.FunctionMetadata; +import com.google.common.collect.ImmutableMap; + +import java.lang.invoke.MethodHandle; +import java.util.Arrays; + +import static com.facebook.presto.translator.registry.ScalarFromAnnotationsParser.parseFunctionDefinitions; + +public class FunctionRegistry +{ + private final ImmutableMap translators; + + public FunctionRegistry(Class... classes) + { + ImmutableMap.Builder functions = ImmutableMap.builder(); + Arrays.stream(classes).forEach(functionDefinition -> { + functions.putAll(parseFunctionDefinitions(functionDefinition)); + }); + + this.translators = functions.build(); + } + + public ImmutableMap getTranslators() + { + return translators; + } + + public MethodHandle getTranslatorForFunction(FunctionMetadata function) + { + return translators.get(function); + } +} diff --git a/presto-main/src/main/java/com/facebook/presto/translator/registry/ScalarFromAnnotationsParser.java b/presto-main/src/main/java/com/facebook/presto/translator/registry/ScalarFromAnnotationsParser.java new file mode 100644 index 000000000000..99dcf989e969 --- /dev/null +++ b/presto-main/src/main/java/com/facebook/presto/translator/registry/ScalarFromAnnotationsParser.java @@ -0,0 +1,187 @@ +package com.facebook.presto.translator.registry; + +import com.facebook.presto.spi.function.FunctionMetadata; +import com.facebook.presto.spi.function.ScalarFunction; +import com.facebook.presto.spi.function.ScalarOperator; +import com.facebook.presto.spi.function.SqlType; +import com.facebook.presto.spi.type.TypeSignature; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import java.lang.annotation.Annotation; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +import static com.facebook.presto.spi.function.FunctionKind.SCALAR; +import static com.facebook.presto.spi.type.TypeSignature.parseTypeSignature; +import static com.facebook.presto.translator.registry.ScalarHeader.fromAnnotatedElement; +import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; + +public class ScalarFromAnnotationsParser +{ + private ScalarFromAnnotationsParser() + { + } + + public static Map parseFunctionDefinitions(Class clazz) + { + ImmutableMap.Builder translatorBuilder = ImmutableMap.builder(); + for (ScalarHeaderAndMethods methods : findScalarsFromSetClass(clazz)) { + translatorBuilder.putAll(scalarToFunctionMetadata(methods)); + } + + return translatorBuilder.build(); + } + + public static TypeSignature removeTypeParameters(TypeSignature typeSignature) + { + return new TypeSignature(typeSignature.getBase()); + } + + public static FunctionMetadata removeTypeParameters(FunctionMetadata metadata) + { + ImmutableList.Builder argumentsBuilder = ImmutableList.builder(); + for (TypeSignature typeSignature : metadata.getArgumentTypes()) { + argumentsBuilder.add(removeTypeParameters(typeSignature)); + } + + if (metadata.getOperatorType().isPresent()) { + return new FunctionMetadata( + metadata.getOperatorType().get(), + argumentsBuilder.build(), + metadata.getReturnType(), + metadata.getFunctionKind(), + metadata.isDeterministic(), + metadata.isCalledOnNullInput()); + } + else { + return new FunctionMetadata( + metadata.getName(), + argumentsBuilder.build(), + metadata.getReturnType(), + metadata.getFunctionKind(), + metadata.isDeterministic(), + metadata.isCalledOnNullInput()); + } + } + + private static MethodHandle getMethodHandle(Method method) + { + try { + return MethodHandles.lookup().unreflect(method); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private static List findScalarsFromSetClass(Class clazz) + { + ImmutableList.Builder builder = ImmutableList.builder(); + for (Method method : findPublicMethodsWithAnnotation(clazz, SqlType.class, ScalarFunction.class, ScalarOperator.class)) { + boolean annotationCondition = (method.getAnnotation(ScalarFunction.class) != null) || (method.getAnnotation(ScalarOperator.class) != null); + checkArgument(annotationCondition, format("Method [%s] annotated with @SqlType is missing @ScalarFunction or @ScalarOperator", method)); + + for (ScalarHeader header : fromAnnotatedElement(method)) { + builder.add(new ScalarHeaderAndMethods(header, ImmutableSet.of(method))); + } + } + List methods = builder.build(); + checkArgument(!methods.isEmpty(), "Class [%s] does not have any methods annotated with @ScalarFunction or @ScalarOperator", clazz.getName()); + + return methods; + } + + private static Map scalarToFunctionMetadata(ScalarHeaderAndMethods scalar) + { + ScalarHeader header = scalar.getHeader(); + + ImmutableMap.Builder metadataBuilder = ImmutableMap.builder(); + for (Method method : scalar.getMethods()) { + FunctionMetadata metadata = methodToFunctionMetadata(header, method); + metadataBuilder.put(removeTypeParameters(metadata), getMethodHandle(method)); + } + + return metadataBuilder.build(); + } + + private static FunctionMetadata methodToFunctionMetadata(ScalarHeader header, Method method) + { + requireNonNull(header, "header is null"); + + // return type + SqlType annotatedReturnType = method.getAnnotation(SqlType.class); + checkArgument(annotatedReturnType != null, format("Method [%s] is missing @SqlType annotation", method)); + TypeSignature returnType = parseTypeSignature(annotatedReturnType.value(), ImmutableSet.of()); + + // argument type + ImmutableList.Builder argumentTypes = new ImmutableList.Builder<>(); + for (Parameter parameter : method.getParameters()) { + Annotation[] annotations = parameter.getAnnotations(); + + SqlType type = Stream.of(annotations) + .filter(SqlType.class::isInstance) + .map(SqlType.class::cast) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(format("Method [%s] is missing @SqlType annotation for parameter", method))); + TypeSignature typeSignature = parseTypeSignature(type.value(), ImmutableSet.of()); + argumentTypes.add(typeSignature); + } + + if (header.getOperatorType().isPresent()) { + return new FunctionMetadata(header.getOperatorType().get(), argumentTypes.build(), returnType, SCALAR, header.isDeterministic(), header.isCalledOnNullInput()); + } + else { + return new FunctionMetadata(header.getName(), argumentTypes.build(), returnType, SCALAR, header.isDeterministic(), header.isCalledOnNullInput()); + } + } + + @SafeVarargs + private static Set findPublicMethodsWithAnnotation(Class clazz, Class... annotationClasses) + { + ImmutableSet.Builder methods = ImmutableSet.builder(); + for (Method method : clazz.getDeclaredMethods()) { + for (Annotation annotation : method.getAnnotations()) { + for (Class annotationClass : annotationClasses) { + if (annotationClass.isInstance(annotation)) { + checkArgument(Modifier.isPublic(method.getModifiers()), "Method [%s] annotated with @%s must be public", method, annotationClass.getSimpleName()); + methods.add(method); + } + } + } + } + return methods.build(); + } + + private static class ScalarHeaderAndMethods + { + private final ScalarHeader header; + private final Set methods; + + public ScalarHeaderAndMethods(ScalarHeader header, Set methods) + { + this.header = requireNonNull(header, "header is null"); + this.methods = requireNonNull(methods, "methods are null"); + } + + public ScalarHeader getHeader() + { + return header; + } + + public Set getMethods() + { + return methods; + } + } +} diff --git a/presto-main/src/main/java/com/facebook/presto/translator/registry/ScalarHeader.java b/presto-main/src/main/java/com/facebook/presto/translator/registry/ScalarHeader.java new file mode 100644 index 000000000000..c28b538019d7 --- /dev/null +++ b/presto-main/src/main/java/com/facebook/presto/translator/registry/ScalarHeader.java @@ -0,0 +1,104 @@ +package com.facebook.presto.translator.registry; + +import com.facebook.presto.spi.function.OperatorType; +import com.facebook.presto.spi.function.ScalarFunction; +import com.facebook.presto.spi.function.ScalarOperator; +import com.facebook.presto.spi.relation.FullyQualifiedName; +import com.google.common.collect.ImmutableList; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.CaseFormat.LOWER_CAMEL; +import static com.google.common.base.CaseFormat.LOWER_UNDERSCORE; +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; + +public class ScalarHeader +{ + private final FullyQualifiedName name; + private final Optional operatorType; + private final boolean deterministic; + private final boolean calledOnNullInput; + + private ScalarHeader(String name, boolean deterministic, boolean calledOnNullInput) + { + // TODO This is a hack. Engine should provide an API for connectors to overwrite functions. Connector should not hard code the builtin function namespace. + this.name = requireNonNull(FullyQualifiedName.of("presto", "default", name)); + this.operatorType = Optional.empty(); + this.deterministic = deterministic; + this.calledOnNullInput = calledOnNullInput; + } + + private ScalarHeader(OperatorType operatorType, boolean deterministic, boolean calledOnNullInput) + { + this.name = operatorType.getFunctionName(); + this.operatorType = Optional.of(operatorType); + this.deterministic = deterministic; + this.calledOnNullInput = calledOnNullInput; + } + + private static String annotatedName(AnnotatedElement annotatedElement) + { + if (annotatedElement instanceof Class) { + return ((Class) annotatedElement).getSimpleName(); + } + else if (annotatedElement instanceof Method) { + return ((Method) annotatedElement).getName(); + } + + throw new UnsupportedOperationException("Only Classes and Methods are supported as annotated elements."); + } + + private static String camelToSnake(String name) + { + return LOWER_CAMEL.to(LOWER_UNDERSCORE, name); + } + + public static List fromAnnotatedElement(AnnotatedElement annotated) + { + ScalarFunction scalarFunction = annotated.getAnnotation(ScalarFunction.class); + ScalarOperator scalarOperator = annotated.getAnnotation(ScalarOperator.class); + + ImmutableList.Builder builder = ImmutableList.builder(); + + if (scalarFunction != null) { + String baseName = scalarFunction.value().isEmpty() ? camelToSnake(annotatedName(annotated)) : scalarFunction.value(); + builder.add(new ScalarHeader(baseName, scalarFunction.deterministic(), scalarFunction.calledOnNullInput())); + + for (String alias : scalarFunction.alias()) { + builder.add(new ScalarHeader(alias, scalarFunction.deterministic(), scalarFunction.calledOnNullInput())); + } + } + + if (scalarOperator != null) { + builder.add(new ScalarHeader(scalarOperator.value(), true, scalarOperator.value().isCalledOnNullInput())); + } + + List result = builder.build(); + checkArgument(!result.isEmpty()); + return result; + } + + public FullyQualifiedName getName() + { + return name; + } + + public Optional getOperatorType() + { + return operatorType; + } + + public boolean isDeterministic() + { + return deterministic; + } + + public boolean isCalledOnNullInput() + { + return calledOnNullInput; + } +} diff --git a/presto-spi/src/main/java/com/facebook/presto/spi/translator/ExpressionTranslator.java b/presto-spi/src/main/java/com/facebook/presto/spi/translator/ExpressionTranslator.java new file mode 100644 index 000000000000..170d2fef55d4 --- /dev/null +++ b/presto-spi/src/main/java/com/facebook/presto/spi/translator/ExpressionTranslator.java @@ -0,0 +1,48 @@ +package com.facebook.presto.spi.translator; + +import com.facebook.presto.spi.ColumnHandle; +import com.facebook.presto.spi.relation.CallExpression; +import com.facebook.presto.spi.relation.ConstantExpression; +import com.facebook.presto.spi.relation.InputReferenceExpression; +import com.facebook.presto.spi.relation.LambdaDefinitionExpression; +import com.facebook.presto.spi.relation.SpecialFormExpression; +import com.facebook.presto.spi.relation.VariableReferenceExpression; + +import java.util.Map; + +public interface ExpressionTranslator +{ + TargetExpression translateCallExpression(CallExpression callExpression, Map context); + + TargetExpression translateInputReferenceExpression(InputReferenceExpression inputReferenceExpression, Map context); + + TargetExpression translateConstantExpression(ConstantExpression constantExpression, Map context); + + TargetExpression translateLambdaDefinitionExpression(LambdaDefinitionExpression lambdaDefinitionExpression, Map context); + + TargetExpression translateVariableReferenceExpression(VariableReferenceExpression variableReferenceExpression, Map context); + + TargetExpression translateIf(SpecialFormExpression specialFormExpression, Map context); + + TargetExpression translateNullIf(SpecialFormExpression specialFormExpression, Map context); + + TargetExpression translateSwitch(SpecialFormExpression specialFormExpression, Map context); + + TargetExpression translateWhen(SpecialFormExpression specialFormExpression, Map context); + + TargetExpression translateIsNull(SpecialFormExpression specialFormExpression, Map context); + + TargetExpression translateCoalesce(SpecialFormExpression specialFormExpression, Map context); + + TargetExpression translateIn(SpecialFormExpression specialFormExpression, Map context); + + TargetExpression translateAnd(SpecialFormExpression specialFormExpression, Map context); + + TargetExpression translateOr(SpecialFormExpression specialFormExpression, Map context); + + TargetExpression translateDereference(SpecialFormExpression specialFormExpression, Map context); + + TargetExpression translateRowConstructor(SpecialFormExpression specialFormExpression, Map context); + + TargetExpression translateBind(SpecialFormExpression specialFormExpression, Map context); +} diff --git a/presto-spi/src/main/java/com/facebook/presto/spi/translator/TargetExpression.java b/presto-spi/src/main/java/com/facebook/presto/spi/translator/TargetExpression.java new file mode 100644 index 000000000000..01569b6bc0f5 --- /dev/null +++ b/presto-spi/src/main/java/com/facebook/presto/spi/translator/TargetExpression.java @@ -0,0 +1,60 @@ +package com.facebook.presto.spi.translator; + +import com.facebook.presto.spi.relation.RowExpression; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +public class TargetExpression +{ + private RowExpression originalExpression; + private List params; + private Optional translatedExpression; + + public TargetExpression(Optional translatedExpression) + { + this.translatedExpression = translatedExpression; + } + + public static TargetExpression empty() + { + return new TargetExpression(Optional.empty()); + } + + public boolean isTranslatedExpressionPresent() + { + return translatedExpression.isPresent(); + } + + public RowExpression getOriginalExpression() + { + return originalExpression; + } + + public void setOriginalExpression(RowExpression originalExpression) + { + this.originalExpression = originalExpression; + } + + public List getParams() + { + // TODO fix so that the params list is already unmodifiable on init + return Collections.unmodifiableList(params); + } + + public void addParam(TargetExpression param) + { + this.params.add(param); + } + + public Optional getTranslatedExpression() + { + return translatedExpression; + } + + public void setTranslatedExpression(Optional translatedExpression) + { + this.translatedExpression = translatedExpression; + } +}