forked from opendistro-for-elasticsearch/sql
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ExpressionAnalyzer.java
154 lines (134 loc) · 6.24 KB
/
ExpressionAnalyzer.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.sql.analysis;
import com.amazon.opendistroforelasticsearch.sql.ast.AbstractNodeVisitor;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.AggregateFunction;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.And;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Compare;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.EqualTo;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Field;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Function;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Literal;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Not;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Or;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.UnresolvedAttribute;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.UnresolvedExpression;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Xor;
import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils;
import com.amazon.opendistroforelasticsearch.sql.exception.SemanticCheckException;
import com.amazon.opendistroforelasticsearch.sql.expression.DSL;
import com.amazon.opendistroforelasticsearch.sql.expression.Expression;
import com.amazon.opendistroforelasticsearch.sql.expression.ReferenceExpression;
import com.amazon.opendistroforelasticsearch.sql.expression.aggregation.Aggregator;
import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionName;
import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionRepository;
import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionName;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* Analyze the {@link UnresolvedExpression} in the {@link AnalysisContext} to construct the {@link
* Expression}.
*/
public class ExpressionAnalyzer extends AbstractNodeVisitor<Expression, AnalysisContext> {
private final BuiltinFunctionRepository repository;
private final DSL dsl;
public ExpressionAnalyzer(
BuiltinFunctionRepository repository) {
this.repository = repository;
this.dsl = new DSL(repository);
}
public Expression analyze(UnresolvedExpression unresolved, AnalysisContext context) {
return unresolved.accept(this, context);
}
@Override
public Expression visitUnresolvedAttribute(UnresolvedAttribute node, AnalysisContext context) {
TypeEnvironment typeEnv = context.peek();
ReferenceExpression ref = DSL.ref(node.getAttr());
typeEnv.resolve(ref);
return ref;
}
@Override
public Expression visitEqualTo(EqualTo node, AnalysisContext context) {
Expression left = node.getLeft().accept(this, context);
Expression right = node.getRight().accept(this, context);
return dsl.equal(context.peek(), left, right);
}
@Override
public Expression visitLiteral(Literal node, AnalysisContext context) {
return DSL.literal(ExprValueUtils.fromObjectValue(node.getValue()));
}
@Override
public Expression visitAnd(And node, AnalysisContext context) {
Expression left = node.getLeft().accept(this, context);
Expression right = node.getRight().accept(this, context);
return dsl.and(context.peek(), left, right);
}
@Override
public Expression visitOr(Or node, AnalysisContext context) {
Expression left = node.getLeft().accept(this, context);
Expression right = node.getRight().accept(this, context);
return dsl.or(context.peek(), left, right);
}
@Override
public Expression visitXor(Xor node, AnalysisContext context) {
Expression left = node.getLeft().accept(this, context);
Expression right = node.getRight().accept(this, context);
return dsl.xor(context.peek(), left, right);
}
@Override
public Expression visitNot(Not node, AnalysisContext context) {
return dsl.not(context.peek(), node.getExpression().accept(this, context));
}
@Override
public Expression visitAggregateFunction(AggregateFunction node, AnalysisContext context) {
Optional<BuiltinFunctionName> builtinFunctionName = BuiltinFunctionName.of(node.getFuncName());
if (builtinFunctionName.isPresent()) {
Expression arg = node.getField().accept(this, context);
return (Aggregator)
repository.compile(
builtinFunctionName.get().getName(), Collections.singletonList(arg), context.peek());
} else {
throw new SemanticCheckException("Unsupported aggregation function " + node.getFuncName());
}
}
@Override
public Expression visitFunction(Function node, AnalysisContext context) {
FunctionName functionName = FunctionName.of(node.getFuncName());
List<Expression> arguments =
node.getFuncArgs().stream()
.map(unresolvedExpression -> analyze(unresolvedExpression, context))
.collect(Collectors.toList());
return (Expression) repository.compile(functionName, arguments, context.peek());
}
@Override
public Expression visitCompare(Compare node, AnalysisContext context) {
FunctionName functionName = FunctionName.of(node.getOperator());
Expression left = analyze(node.getLeft(), context);
Expression right = analyze(node.getRight(), context);
return (Expression)
repository.compile(functionName, Arrays.asList(left, right), context.peek());
}
@Override
public Expression visitField(Field node, AnalysisContext context) {
String attr = node.getField().toString();
TypeEnvironment typeEnv = context.peek();
ReferenceExpression ref = DSL.ref(attr);
typeEnv.resolve(ref);
return ref;
}
}