1 | /* | |
2 | * Copyright OpenSearch Contributors | |
3 | * SPDX-License-Identifier: Apache-2.0 | |
4 | */ | |
5 | ||
6 | ||
7 | package org.opensearch.sql.analysis; | |
8 | ||
9 | import static org.opensearch.sql.ast.tree.Sort.NullOrder.NULL_FIRST; | |
10 | import static org.opensearch.sql.ast.tree.Sort.NullOrder.NULL_LAST; | |
11 | import static org.opensearch.sql.ast.tree.Sort.SortOrder.ASC; | |
12 | import static org.opensearch.sql.ast.tree.Sort.SortOrder.DESC; | |
13 | import static org.opensearch.sql.data.type.ExprCoreType.STRUCT; | |
14 | import static org.opensearch.sql.utils.MLCommonsConstants.ACTION; | |
15 | import static org.opensearch.sql.utils.MLCommonsConstants.MODELID; | |
16 | import static org.opensearch.sql.utils.MLCommonsConstants.PREDICT; | |
17 | import static org.opensearch.sql.utils.MLCommonsConstants.RCF_ANOMALOUS; | |
18 | import static org.opensearch.sql.utils.MLCommonsConstants.RCF_ANOMALY_GRADE; | |
19 | import static org.opensearch.sql.utils.MLCommonsConstants.RCF_SCORE; | |
20 | import static org.opensearch.sql.utils.MLCommonsConstants.RCF_TIMESTAMP; | |
21 | import static org.opensearch.sql.utils.MLCommonsConstants.STATUS; | |
22 | import static org.opensearch.sql.utils.MLCommonsConstants.TASKID; | |
23 | import static org.opensearch.sql.utils.MLCommonsConstants.TIME_FIELD; | |
24 | import static org.opensearch.sql.utils.MLCommonsConstants.TRAIN; | |
25 | import static org.opensearch.sql.utils.MLCommonsConstants.TRAINANDPREDICT; | |
26 | import static org.opensearch.sql.utils.SystemIndexUtils.CATALOGS_TABLE_NAME; | |
27 | ||
28 | import com.google.common.collect.ImmutableList; | |
29 | import com.google.common.collect.ImmutableList.Builder; | |
30 | import com.google.common.collect.ImmutableMap; | |
31 | import com.google.common.collect.ImmutableSet; | |
32 | import java.util.ArrayList; | |
33 | import java.util.List; | |
34 | import java.util.Objects; | |
35 | import java.util.Optional; | |
36 | import java.util.Set; | |
37 | import java.util.stream.Collectors; | |
38 | import org.apache.commons.lang3.tuple.ImmutablePair; | |
39 | import org.apache.commons.lang3.tuple.Pair; | |
40 | import org.opensearch.sql.CatalogSchemaName; | |
41 | import org.opensearch.sql.analysis.symbol.Namespace; | |
42 | import org.opensearch.sql.analysis.symbol.Symbol; | |
43 | import org.opensearch.sql.ast.AbstractNodeVisitor; | |
44 | import org.opensearch.sql.ast.expression.Argument; | |
45 | import org.opensearch.sql.ast.expression.Field; | |
46 | import org.opensearch.sql.ast.expression.Let; | |
47 | import org.opensearch.sql.ast.expression.Literal; | |
48 | import org.opensearch.sql.ast.expression.Map; | |
49 | import org.opensearch.sql.ast.expression.ParseMethod; | |
50 | import org.opensearch.sql.ast.expression.QualifiedName; | |
51 | import org.opensearch.sql.ast.expression.UnresolvedExpression; | |
52 | import org.opensearch.sql.ast.tree.AD; | |
53 | import org.opensearch.sql.ast.tree.Aggregation; | |
54 | import org.opensearch.sql.ast.tree.Dedupe; | |
55 | import org.opensearch.sql.ast.tree.Eval; | |
56 | import org.opensearch.sql.ast.tree.Filter; | |
57 | import org.opensearch.sql.ast.tree.Head; | |
58 | import org.opensearch.sql.ast.tree.Kmeans; | |
59 | import org.opensearch.sql.ast.tree.Limit; | |
60 | import org.opensearch.sql.ast.tree.ML; | |
61 | import org.opensearch.sql.ast.tree.Parse; | |
62 | import org.opensearch.sql.ast.tree.Project; | |
63 | import org.opensearch.sql.ast.tree.RareTopN; | |
64 | import org.opensearch.sql.ast.tree.Relation; | |
65 | import org.opensearch.sql.ast.tree.RelationSubquery; | |
66 | import org.opensearch.sql.ast.tree.Rename; | |
67 | import org.opensearch.sql.ast.tree.Sort; | |
68 | import org.opensearch.sql.ast.tree.Sort.SortOption; | |
69 | import org.opensearch.sql.ast.tree.TableFunction; | |
70 | import org.opensearch.sql.ast.tree.UnresolvedPlan; | |
71 | import org.opensearch.sql.ast.tree.Values; | |
72 | import org.opensearch.sql.catalog.CatalogService; | |
73 | import org.opensearch.sql.catalog.model.Catalog; | |
74 | import org.opensearch.sql.data.model.ExprMissingValue; | |
75 | import org.opensearch.sql.data.type.ExprCoreType; | |
76 | import org.opensearch.sql.exception.SemanticCheckException; | |
77 | import org.opensearch.sql.expression.DSL; | |
78 | import org.opensearch.sql.expression.Expression; | |
79 | import org.opensearch.sql.expression.LiteralExpression; | |
80 | import org.opensearch.sql.expression.NamedExpression; | |
81 | import org.opensearch.sql.expression.ReferenceExpression; | |
82 | import org.opensearch.sql.expression.aggregation.Aggregator; | |
83 | import org.opensearch.sql.expression.aggregation.NamedAggregator; | |
84 | import org.opensearch.sql.expression.function.BuiltinFunctionRepository; | |
85 | import org.opensearch.sql.expression.function.FunctionName; | |
86 | import org.opensearch.sql.expression.function.TableFunctionImplementation; | |
87 | import org.opensearch.sql.expression.parse.ParseExpression; | |
88 | import org.opensearch.sql.planner.logical.LogicalAD; | |
89 | import org.opensearch.sql.planner.logical.LogicalAggregation; | |
90 | import org.opensearch.sql.planner.logical.LogicalDedupe; | |
91 | import org.opensearch.sql.planner.logical.LogicalEval; | |
92 | import org.opensearch.sql.planner.logical.LogicalFilter; | |
93 | import org.opensearch.sql.planner.logical.LogicalLimit; | |
94 | import org.opensearch.sql.planner.logical.LogicalML; | |
95 | import org.opensearch.sql.planner.logical.LogicalMLCommons; | |
96 | import org.opensearch.sql.planner.logical.LogicalPlan; | |
97 | import org.opensearch.sql.planner.logical.LogicalProject; | |
98 | import org.opensearch.sql.planner.logical.LogicalRareTopN; | |
99 | import org.opensearch.sql.planner.logical.LogicalRelation; | |
100 | import org.opensearch.sql.planner.logical.LogicalRemove; | |
101 | import org.opensearch.sql.planner.logical.LogicalRename; | |
102 | import org.opensearch.sql.planner.logical.LogicalSort; | |
103 | import org.opensearch.sql.planner.logical.LogicalValues; | |
104 | import org.opensearch.sql.planner.physical.catalog.CatalogTable; | |
105 | import org.opensearch.sql.storage.Table; | |
106 | import org.opensearch.sql.utils.ParseUtils; | |
107 | ||
108 | /** | |
109 | * Analyze the {@link UnresolvedPlan} in the {@link AnalysisContext} to construct the {@link | |
110 | * LogicalPlan}. | |
111 | */ | |
112 | public class Analyzer extends AbstractNodeVisitor<LogicalPlan, AnalysisContext> { | |
113 | ||
114 | private final ExpressionAnalyzer expressionAnalyzer; | |
115 | ||
116 | private final SelectExpressionAnalyzer selectExpressionAnalyzer; | |
117 | ||
118 | private final NamedExpressionAnalyzer namedExpressionAnalyzer; | |
119 | ||
120 | private final CatalogService catalogService; | |
121 | ||
122 | private final BuiltinFunctionRepository repository; | |
123 | ||
124 | /** | |
125 | * Constructor. | |
126 | */ | |
127 | public Analyzer( | |
128 | ExpressionAnalyzer expressionAnalyzer, | |
129 | CatalogService catalogService, | |
130 | BuiltinFunctionRepository repository) { | |
131 | this.expressionAnalyzer = expressionAnalyzer; | |
132 | this.catalogService = catalogService; | |
133 | this.selectExpressionAnalyzer = new SelectExpressionAnalyzer(expressionAnalyzer); | |
134 | this.namedExpressionAnalyzer = new NamedExpressionAnalyzer(expressionAnalyzer); | |
135 | this.repository = repository; | |
136 | } | |
137 | ||
138 | public LogicalPlan analyze(UnresolvedPlan unresolved, AnalysisContext context) { | |
139 |
1
1. analyze : replaced return value with null for org/opensearch/sql/analysis/Analyzer::analyze → KILLED |
return unresolved.accept(this, context); |
140 | } | |
141 | ||
142 | @Override | |
143 | public LogicalPlan visitRelation(Relation node, AnalysisContext context) { | |
144 | QualifiedName qualifiedName = node.getTableQualifiedName(); | |
145 | Set<String> allowedCatalogNames = catalogService.getCatalogs() | |
146 | .stream() | |
147 | .map(Catalog::getName) | |
148 | .collect(Collectors.toSet()); | |
149 | CatalogSchemaIdentifierNameResolver catalogSchemaIdentifierNameResolver | |
150 | = new CatalogSchemaIdentifierNameResolver(qualifiedName.getParts(), allowedCatalogNames); | |
151 | String tableName = catalogSchemaIdentifierNameResolver.getIdentifierName(); | |
152 |
1
1. visitRelation : removed call to org/opensearch/sql/analysis/AnalysisContext::push → KILLED |
context.push(); |
153 | TypeEnvironment curEnv = context.peek(); | |
154 | Table table; | |
155 |
1
1. visitRelation : negated conditional → KILLED |
if (CATALOGS_TABLE_NAME.equals(tableName)) { |
156 | table = new CatalogTable(catalogService); | |
157 | } else { | |
158 | table = catalogService | |
159 | .getCatalog(catalogSchemaIdentifierNameResolver.getCatalogName()) | |
160 | .getStorageEngine() | |
161 | .getTable(new CatalogSchemaName(catalogSchemaIdentifierNameResolver.getCatalogName(), | |
162 | catalogSchemaIdentifierNameResolver.getSchemaName()), | |
163 | catalogSchemaIdentifierNameResolver.getIdentifierName()); | |
164 | } | |
165 |
2
1. lambda$visitRelation$0 : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → KILLED 2. visitRelation : removed call to java/util/Map::forEach → KILLED |
table.getFieldTypes().forEach((k, v) -> curEnv.define(new Symbol(Namespace.FIELD_NAME, k), v)); |
166 | ||
167 | // Put index name or its alias in index namespace on type environment so qualifier | |
168 | // can be removed when analyzing qualified name. The value (expr type) here doesn't matter. | |
169 |
1
1. visitRelation : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → SURVIVED |
curEnv.define(new Symbol(Namespace.INDEX_NAME, |
170 |
1
1. visitRelation : negated conditional → KILLED |
(node.getAlias() == null) ? tableName : node.getAlias()), STRUCT); |
171 | ||
172 |
1
1. visitRelation : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitRelation → KILLED |
return new LogicalRelation(tableName, table); |
173 | } | |
174 | ||
175 | ||
176 | @Override | |
177 | public LogicalPlan visitRelationSubquery(RelationSubquery node, AnalysisContext context) { | |
178 | LogicalPlan subquery = analyze(node.getChild().get(0), context); | |
179 | // inherit the parent environment to keep the subquery fields in current environment | |
180 | TypeEnvironment curEnv = context.peek(); | |
181 | ||
182 | // Put subquery alias in index namespace so the qualifier can be removed | |
183 | // when analyzing qualified name in the subquery layer | |
184 |
1
1. visitRelationSubquery : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → SURVIVED |
curEnv.define(new Symbol(Namespace.INDEX_NAME, node.getAliasAsTableName()), STRUCT); |
185 |
1
1. visitRelationSubquery : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitRelationSubquery → KILLED |
return subquery; |
186 | } | |
187 | ||
188 | @Override | |
189 | public LogicalPlan visitTableFunction(TableFunction node, AnalysisContext context) { | |
190 | QualifiedName qualifiedName = node.getFunctionName(); | |
191 | Set<String> allowedCatalogNames = catalogService.getCatalogs() | |
192 | .stream() | |
193 | .map(Catalog::getName) | |
194 | .collect(Collectors.toSet()); | |
195 | CatalogSchemaIdentifierNameResolver catalogSchemaIdentifierNameResolver | |
196 | = new CatalogSchemaIdentifierNameResolver(qualifiedName.getParts(), allowedCatalogNames); | |
197 | ||
198 | FunctionName functionName | |
199 | = FunctionName.of(catalogSchemaIdentifierNameResolver.getIdentifierName()); | |
200 | List<Expression> arguments = node.getArguments().stream() | |
201 |
1
1. lambda$visitTableFunction$1 : replaced return value with null for org/opensearch/sql/analysis/Analyzer::lambda$visitTableFunction$1 → KILLED |
.map(unresolvedExpression -> this.expressionAnalyzer.analyze(unresolvedExpression, context)) |
202 | .collect(Collectors.toList()); | |
203 | TableFunctionImplementation tableFunctionImplementation | |
204 | = (TableFunctionImplementation) repository.compile( | |
205 | catalogSchemaIdentifierNameResolver.getCatalogName(), functionName, arguments); | |
206 |
1
1. visitTableFunction : removed call to org/opensearch/sql/analysis/AnalysisContext::push → SURVIVED |
context.push(); |
207 | TypeEnvironment curEnv = context.peek(); | |
208 | Table table = tableFunctionImplementation.applyArguments(); | |
209 |
2
1. lambda$visitTableFunction$2 : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → SURVIVED 2. visitTableFunction : removed call to java/util/Map::forEach → SURVIVED |
table.getFieldTypes().forEach((k, v) -> curEnv.define(new Symbol(Namespace.FIELD_NAME, k), v)); |
210 |
1
1. visitTableFunction : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → SURVIVED |
curEnv.define(new Symbol(Namespace.INDEX_NAME, |
211 | catalogSchemaIdentifierNameResolver.getIdentifierName()), STRUCT); | |
212 |
1
1. visitTableFunction : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitTableFunction → KILLED |
return new LogicalRelation(catalogSchemaIdentifierNameResolver.getIdentifierName(), |
213 | tableFunctionImplementation.applyArguments()); | |
214 | } | |
215 | ||
216 | ||
217 | @Override | |
218 | public LogicalPlan visitLimit(Limit node, AnalysisContext context) { | |
219 | LogicalPlan child = node.getChild().get(0).accept(this, context); | |
220 |
1
1. visitLimit : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitLimit → KILLED |
return new LogicalLimit(child, node.getLimit(), node.getOffset()); |
221 | } | |
222 | ||
223 | @Override | |
224 | public LogicalPlan visitFilter(Filter node, AnalysisContext context) { | |
225 | LogicalPlan child = node.getChild().get(0).accept(this, context); | |
226 | Expression condition = expressionAnalyzer.analyze(node.getCondition(), context); | |
227 | ||
228 | ExpressionReferenceOptimizer optimizer = | |
229 | new ExpressionReferenceOptimizer(expressionAnalyzer.getRepository(), child); | |
230 | Expression optimized = optimizer.optimize(condition, context); | |
231 |
1
1. visitFilter : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitFilter → KILLED |
return new LogicalFilter(child, optimized); |
232 | } | |
233 | ||
234 | /** | |
235 | * Build {@link LogicalRename}. | |
236 | */ | |
237 | @Override | |
238 | public LogicalPlan visitRename(Rename node, AnalysisContext context) { | |
239 | LogicalPlan child = node.getChild().get(0).accept(this, context); | |
240 | ImmutableMap.Builder<ReferenceExpression, ReferenceExpression> renameMapBuilder = | |
241 | new ImmutableMap.Builder<>(); | |
242 | for (Map renameMap : node.getRenameList()) { | |
243 | Expression origin = expressionAnalyzer.analyze(renameMap.getOrigin(), context); | |
244 | // We should define the new target field in the context instead of analyze it. | |
245 |
1
1. visitRename : negated conditional → KILLED |
if (renameMap.getTarget() instanceof Field) { |
246 | ReferenceExpression target = | |
247 | new ReferenceExpression(((Field) renameMap.getTarget()).getField().toString(), | |
248 | origin.type()); | |
249 | ReferenceExpression originExpr = DSL.ref(origin.toString(), origin.type()); | |
250 | TypeEnvironment curEnv = context.peek(); | |
251 |
1
1. visitRename : removed call to org/opensearch/sql/analysis/TypeEnvironment::remove → KILLED |
curEnv.remove(originExpr); |
252 |
1
1. visitRename : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → KILLED |
curEnv.define(target); |
253 | renameMapBuilder.put(originExpr, target); | |
254 | } else { | |
255 | throw new SemanticCheckException( | |
256 | String.format("the target expected to be field, but is %s", renameMap.getTarget())); | |
257 | } | |
258 | } | |
259 | ||
260 |
1
1. visitRename : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitRename → KILLED |
return new LogicalRename(child, renameMapBuilder.build()); |
261 | } | |
262 | ||
263 | /** | |
264 | * Build {@link LogicalAggregation}. | |
265 | */ | |
266 | @Override | |
267 | public LogicalPlan visitAggregation(Aggregation node, AnalysisContext context) { | |
268 | final LogicalPlan child = node.getChild().get(0).accept(this, context); | |
269 | ImmutableList.Builder<NamedAggregator> aggregatorBuilder = new ImmutableList.Builder<>(); | |
270 | for (UnresolvedExpression expr : node.getAggExprList()) { | |
271 | NamedExpression aggExpr = namedExpressionAnalyzer.analyze(expr, context); | |
272 | aggregatorBuilder | |
273 | .add(new NamedAggregator(aggExpr.getNameOrAlias(), (Aggregator) aggExpr.getDelegated())); | |
274 | } | |
275 | ||
276 | ImmutableList.Builder<NamedExpression> groupbyBuilder = new ImmutableList.Builder<>(); | |
277 | // Span should be first expression if exist. | |
278 |
1
1. visitAggregation : negated conditional → KILLED |
if (node.getSpan() != null) { |
279 | groupbyBuilder.add(namedExpressionAnalyzer.analyze(node.getSpan(), context)); | |
280 | } | |
281 | ||
282 | for (UnresolvedExpression expr : node.getGroupExprList()) { | |
283 | groupbyBuilder.add(namedExpressionAnalyzer.analyze(expr, context)); | |
284 | } | |
285 | ImmutableList<NamedExpression> groupBys = groupbyBuilder.build(); | |
286 | ||
287 | ImmutableList<NamedAggregator> aggregators = aggregatorBuilder.build(); | |
288 | // new context | |
289 |
1
1. visitAggregation : removed call to org/opensearch/sql/analysis/AnalysisContext::push → KILLED |
context.push(); |
290 | TypeEnvironment newEnv = context.peek(); | |
291 |
2
1. lambda$visitAggregation$3 : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → KILLED 2. visitAggregation : removed call to com/google/common/collect/ImmutableList::forEach → KILLED |
aggregators.forEach(aggregator -> newEnv.define(new Symbol(Namespace.FIELD_NAME, |
292 | aggregator.getName()), aggregator.type())); | |
293 |
2
1. lambda$visitAggregation$4 : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → KILLED 2. visitAggregation : removed call to com/google/common/collect/ImmutableList::forEach → KILLED |
groupBys.forEach(group -> newEnv.define(new Symbol(Namespace.FIELD_NAME, |
294 | group.getNameOrAlias()), group.type())); | |
295 |
1
1. visitAggregation : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitAggregation → KILLED |
return new LogicalAggregation(child, aggregators, groupBys); |
296 | } | |
297 | ||
298 | /** | |
299 | * Build {@link LogicalRareTopN}. | |
300 | */ | |
301 | @Override | |
302 | public LogicalPlan visitRareTopN(RareTopN node, AnalysisContext context) { | |
303 | final LogicalPlan child = node.getChild().get(0).accept(this, context); | |
304 | ||
305 | ImmutableList.Builder<Expression> groupbyBuilder = new ImmutableList.Builder<>(); | |
306 | for (UnresolvedExpression expr : node.getGroupExprList()) { | |
307 | groupbyBuilder.add(expressionAnalyzer.analyze(expr, context)); | |
308 | } | |
309 | ImmutableList<Expression> groupBys = groupbyBuilder.build(); | |
310 | ||
311 | ImmutableList.Builder<Expression> fieldsBuilder = new ImmutableList.Builder<>(); | |
312 | for (Field f : node.getFields()) { | |
313 | fieldsBuilder.add(expressionAnalyzer.analyze(f, context)); | |
314 | } | |
315 | ImmutableList<Expression> fields = fieldsBuilder.build(); | |
316 | ||
317 | // new context | |
318 |
1
1. visitRareTopN : removed call to org/opensearch/sql/analysis/AnalysisContext::push → SURVIVED |
context.push(); |
319 | TypeEnvironment newEnv = context.peek(); | |
320 |
2
1. lambda$visitRareTopN$5 : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → SURVIVED 2. visitRareTopN : removed call to com/google/common/collect/ImmutableList::forEach → SURVIVED |
groupBys.forEach(group -> newEnv.define(new Symbol(Namespace.FIELD_NAME, |
321 | group.toString()), group.type())); | |
322 |
2
1. lambda$visitRareTopN$6 : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → SURVIVED 2. visitRareTopN : removed call to com/google/common/collect/ImmutableList::forEach → SURVIVED |
fields.forEach(field -> newEnv.define(new Symbol(Namespace.FIELD_NAME, |
323 | field.toString()), field.type())); | |
324 | ||
325 | List<Argument> options = node.getNoOfResults(); | |
326 | Integer noOfResults = (Integer) options.get(0).getValue().getValue(); | |
327 | ||
328 |
1
1. visitRareTopN : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitRareTopN → KILLED |
return new LogicalRareTopN(child, node.getCommandType(), noOfResults, fields, groupBys); |
329 | } | |
330 | ||
331 | /** | |
332 | * Build {@link LogicalProject} or {@link LogicalRemove} from {@link Field}. | |
333 | * | |
334 | * <p>Todo, the include/exclude fields should change the env definition. The cons of current | |
335 | * implementation is even the query contain the field reference which has been excluded from | |
336 | * fields command. There is no {@link SemanticCheckException} will be thrown. Instead, the during | |
337 | * runtime evaluation, the not exist field will be resolve to {@link ExprMissingValue} which will | |
338 | * not impact the correctness. | |
339 | * | |
340 | * <p>Postpone the implementation when finding more use case. | |
341 | */ | |
342 | @Override | |
343 | public LogicalPlan visitProject(Project node, AnalysisContext context) { | |
344 | LogicalPlan child = node.getChild().get(0).accept(this, context); | |
345 | ||
346 |
1
1. visitProject : negated conditional → KILLED |
if (node.hasArgument()) { |
347 | Argument argument = node.getArgExprList().get(0); | |
348 | Boolean exclude = (Boolean) argument.getValue().getValue(); | |
349 |
1
1. visitProject : negated conditional → KILLED |
if (exclude) { |
350 | TypeEnvironment curEnv = context.peek(); | |
351 | List<ReferenceExpression> referenceExpressions = | |
352 | node.getProjectList().stream() | |
353 |
1
1. lambda$visitProject$7 : replaced return value with null for org/opensearch/sql/analysis/Analyzer::lambda$visitProject$7 → KILLED |
.map(expr -> (ReferenceExpression) expressionAnalyzer.analyze(expr, context)) |
354 | .collect(Collectors.toList()); | |
355 |
2
1. lambda$visitProject$8 : removed call to org/opensearch/sql/analysis/TypeEnvironment::remove → KILLED 2. visitProject : removed call to java/util/List::forEach → KILLED |
referenceExpressions.forEach(ref -> curEnv.remove(ref)); |
356 |
1
1. visitProject : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitProject → KILLED |
return new LogicalRemove(child, ImmutableSet.copyOf(referenceExpressions)); |
357 | } | |
358 | } | |
359 | ||
360 | // For each unresolved window function, analyze it by "insert" a window and sort operator | |
361 | // between project and its child. | |
362 | for (UnresolvedExpression expr : node.getProjectList()) { | |
363 | WindowExpressionAnalyzer windowAnalyzer = | |
364 | new WindowExpressionAnalyzer(expressionAnalyzer, child); | |
365 | child = windowAnalyzer.analyze(expr, context); | |
366 | } | |
367 | ||
368 | for (UnresolvedExpression expr : node.getProjectList()) { | |
369 | HighlightAnalyzer highlightAnalyzer = new HighlightAnalyzer(expressionAnalyzer, child); | |
370 | child = highlightAnalyzer.analyze(expr, context); | |
371 | } | |
372 | ||
373 | List<NamedExpression> namedExpressions = | |
374 | selectExpressionAnalyzer.analyze(node.getProjectList(), context, | |
375 | new ExpressionReferenceOptimizer(expressionAnalyzer.getRepository(), child)); | |
376 | // new context | |
377 |
1
1. visitProject : removed call to org/opensearch/sql/analysis/AnalysisContext::push → KILLED |
context.push(); |
378 | TypeEnvironment newEnv = context.peek(); | |
379 |
2
1. lambda$visitProject$9 : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → KILLED 2. visitProject : removed call to java/util/List::forEach → KILLED |
namedExpressions.forEach(expr -> newEnv.define(new Symbol(Namespace.FIELD_NAME, |
380 | expr.getNameOrAlias()), expr.type())); | |
381 | List<NamedExpression> namedParseExpressions = context.getNamedParseExpressions(); | |
382 |
1
1. visitProject : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitProject → KILLED |
return new LogicalProject(child, namedExpressions, namedParseExpressions); |
383 | } | |
384 | ||
385 | /** | |
386 | * Build {@link LogicalEval}. | |
387 | */ | |
388 | @Override | |
389 | public LogicalPlan visitEval(Eval node, AnalysisContext context) { | |
390 | LogicalPlan child = node.getChild().get(0).accept(this, context); | |
391 | ImmutableList.Builder<Pair<ReferenceExpression, Expression>> expressionsBuilder = | |
392 | new Builder<>(); | |
393 | for (Let let : node.getExpressionList()) { | |
394 | Expression expression = expressionAnalyzer.analyze(let.getExpression(), context); | |
395 | ReferenceExpression ref = DSL.ref(let.getVar().getField().toString(), expression.type()); | |
396 | expressionsBuilder.add(ImmutablePair.of(ref, expression)); | |
397 | TypeEnvironment typeEnvironment = context.peek(); | |
398 | // define the new reference in type env. | |
399 |
1
1. visitEval : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → SURVIVED |
typeEnvironment.define(ref); |
400 | } | |
401 |
1
1. visitEval : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitEval → KILLED |
return new LogicalEval(child, expressionsBuilder.build()); |
402 | } | |
403 | ||
404 | /** | |
405 | * Build {@link ParseExpression} to context and skip to child nodes. | |
406 | */ | |
407 | @Override | |
408 | public LogicalPlan visitParse(Parse node, AnalysisContext context) { | |
409 | LogicalPlan child = node.getChild().get(0).accept(this, context); | |
410 | Expression sourceField = expressionAnalyzer.analyze(node.getSourceField(), context); | |
411 | ParseMethod parseMethod = node.getParseMethod(); | |
412 | java.util.Map<String, Literal> arguments = node.getArguments(); | |
413 | String pattern = (String) node.getPattern().getValue(); | |
414 | Expression patternExpression = DSL.literal(pattern); | |
415 | ||
416 | TypeEnvironment curEnv = context.peek(); | |
417 |
1
1. visitParse : removed call to java/util/List::forEach → KILLED |
ParseUtils.getNamedGroupCandidates(parseMethod, pattern, arguments).forEach(group -> { |
418 | ParseExpression expr = ParseUtils.createParseExpression(parseMethod, sourceField, | |
419 | patternExpression, DSL.literal(group)); | |
420 |
1
1. lambda$visitParse$10 : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → SURVIVED |
curEnv.define(new Symbol(Namespace.FIELD_NAME, group), expr.type()); |
421 | context.getNamedParseExpressions().add(new NamedExpression(group, expr)); | |
422 | }); | |
423 |
1
1. visitParse : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitParse → KILLED |
return child; |
424 | } | |
425 | ||
426 | /** | |
427 | * Build {@link LogicalSort}. | |
428 | */ | |
429 | @Override | |
430 | public LogicalPlan visitSort(Sort node, AnalysisContext context) { | |
431 | LogicalPlan child = node.getChild().get(0).accept(this, context); | |
432 | ExpressionReferenceOptimizer optimizer = | |
433 | new ExpressionReferenceOptimizer(expressionAnalyzer.getRepository(), child); | |
434 | ||
435 | List<Pair<SortOption, Expression>> sortList = | |
436 | node.getSortList().stream() | |
437 | .map( | |
438 | sortField -> { | |
439 | Expression expression = optimizer.optimize( | |
440 | expressionAnalyzer.analyze(sortField.getField(), context), context); | |
441 |
1
1. lambda$visitSort$11 : replaced return value with null for org/opensearch/sql/analysis/Analyzer::lambda$visitSort$11 → KILLED |
return ImmutablePair.of(analyzeSortOption(sortField.getFieldArgs()), expression); |
442 | }) | |
443 | .collect(Collectors.toList()); | |
444 |
1
1. visitSort : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitSort → KILLED |
return new LogicalSort(child, sortList); |
445 | } | |
446 | ||
447 | /** | |
448 | * Build {@link LogicalDedupe}. | |
449 | */ | |
450 | @Override | |
451 | public LogicalPlan visitDedupe(Dedupe node, AnalysisContext context) { | |
452 | LogicalPlan child = node.getChild().get(0).accept(this, context); | |
453 | List<Argument> options = node.getOptions(); | |
454 | // Todo, refactor the option. | |
455 | Integer allowedDuplication = (Integer) options.get(0).getValue().getValue(); | |
456 | Boolean keepEmpty = (Boolean) options.get(1).getValue().getValue(); | |
457 | Boolean consecutive = (Boolean) options.get(2).getValue().getValue(); | |
458 | ||
459 |
1
1. visitDedupe : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitDedupe → KILLED |
return new LogicalDedupe( |
460 | child, | |
461 | node.getFields().stream() | |
462 |
1
1. lambda$visitDedupe$12 : replaced return value with null for org/opensearch/sql/analysis/Analyzer::lambda$visitDedupe$12 → KILLED |
.map(f -> expressionAnalyzer.analyze(f, context)) |
463 | .collect(Collectors.toList()), | |
464 | allowedDuplication, | |
465 | keepEmpty, | |
466 | consecutive); | |
467 | } | |
468 | ||
469 | /** | |
470 | * Logical head is identical to {@link LogicalLimit}. | |
471 | */ | |
472 | public LogicalPlan visitHead(Head node, AnalysisContext context) { | |
473 | LogicalPlan child = node.getChild().get(0).accept(this, context); | |
474 |
1
1. visitHead : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitHead → KILLED |
return new LogicalLimit(child, node.getSize(), node.getFrom()); |
475 | } | |
476 | ||
477 | @Override | |
478 | public LogicalPlan visitValues(Values node, AnalysisContext context) { | |
479 | List<List<Literal>> values = node.getValues(); | |
480 | List<List<LiteralExpression>> valueExprs = new ArrayList<>(); | |
481 | for (List<Literal> value : values) { | |
482 | valueExprs.add(value.stream() | |
483 |
1
1. lambda$visitValues$13 : replaced return value with null for org/opensearch/sql/analysis/Analyzer::lambda$visitValues$13 → KILLED |
.map(val -> (LiteralExpression) expressionAnalyzer.analyze(val, context)) |
484 | .collect(Collectors.toList())); | |
485 | } | |
486 |
1
1. visitValues : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitValues → KILLED |
return new LogicalValues(valueExprs); |
487 | } | |
488 | ||
489 | /** | |
490 | * Build {@link LogicalMLCommons} for Kmeans command. | |
491 | */ | |
492 | @Override | |
493 | public LogicalPlan visitKmeans(Kmeans node, AnalysisContext context) { | |
494 | LogicalPlan child = node.getChild().get(0).accept(this, context); | |
495 | java.util.Map<String, Literal> options = node.getArguments(); | |
496 | ||
497 | TypeEnvironment currentEnv = context.peek(); | |
498 |
1
1. visitKmeans : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → SURVIVED |
currentEnv.define(new Symbol(Namespace.FIELD_NAME, "ClusterID"), ExprCoreType.INTEGER); |
499 | ||
500 |
1
1. visitKmeans : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitKmeans → KILLED |
return new LogicalMLCommons(child, "kmeans", options); |
501 | } | |
502 | ||
503 | /** | |
504 | * Build {@link LogicalAD} for AD command. | |
505 | */ | |
506 | @Override | |
507 | public LogicalPlan visitAD(AD node, AnalysisContext context) { | |
508 | LogicalPlan child = node.getChild().get(0).accept(this, context); | |
509 | java.util.Map<String, Literal> options = node.getArguments(); | |
510 | ||
511 | TypeEnvironment currentEnv = context.peek(); | |
512 | ||
513 |
1
1. visitAD : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → KILLED |
currentEnv.define(new Symbol(Namespace.FIELD_NAME, RCF_SCORE), ExprCoreType.DOUBLE); |
514 |
1
1. visitAD : negated conditional → KILLED |
if (Objects.isNull(node.getArguments().get(TIME_FIELD))) { |
515 |
1
1. visitAD : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → KILLED |
currentEnv.define(new Symbol(Namespace.FIELD_NAME, RCF_ANOMALOUS), ExprCoreType.BOOLEAN); |
516 | } else { | |
517 |
1
1. visitAD : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → KILLED |
currentEnv.define(new Symbol(Namespace.FIELD_NAME, RCF_ANOMALY_GRADE), ExprCoreType.DOUBLE); |
518 |
1
1. visitAD : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → KILLED |
currentEnv.define(new Symbol(Namespace.FIELD_NAME, |
519 | (String) node.getArguments().get(TIME_FIELD).getValue()), ExprCoreType.TIMESTAMP); | |
520 | } | |
521 |
1
1. visitAD : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitAD → KILLED |
return new LogicalAD(child, options); |
522 | } | |
523 | ||
524 | /** | |
525 | * Build {@link LogicalML} for ml command. | |
526 | */ | |
527 | @Override | |
528 | public LogicalPlan visitML(ML node, AnalysisContext context) { | |
529 | LogicalPlan child = node.getChild().get(0).accept(this, context); | |
530 | TypeEnvironment currentEnv = context.peek(); | |
531 | node.getOutputSchema(currentEnv).entrySet().stream() | |
532 |
2
1. lambda$visitML$14 : removed call to org/opensearch/sql/analysis/TypeEnvironment::define → KILLED 2. visitML : removed call to java/util/stream/Stream::forEach → KILLED |
.forEach(v -> currentEnv.define(new Symbol(Namespace.FIELD_NAME, v.getKey()), v.getValue())); |
533 | ||
534 |
1
1. visitML : replaced return value with null for org/opensearch/sql/analysis/Analyzer::visitML → KILLED |
return new LogicalML(child, node.getArguments()); |
535 | } | |
536 | ||
537 | /** | |
538 | * The first argument is always "asc", others are optional. | |
539 | * Given nullFirst argument, use its value. Otherwise just use DEFAULT_ASC/DESC. | |
540 | */ | |
541 | private SortOption analyzeSortOption(List<Argument> fieldArgs) { | |
542 | Boolean asc = (Boolean) fieldArgs.get(0).getValue().getValue(); | |
543 | Optional<Argument> nullFirst = fieldArgs.stream() | |
544 |
2
1. lambda$analyzeSortOption$15 : replaced boolean return with false for org/opensearch/sql/analysis/Analyzer::lambda$analyzeSortOption$15 → KILLED 2. lambda$analyzeSortOption$15 : replaced boolean return with true for org/opensearch/sql/analysis/Analyzer::lambda$analyzeSortOption$15 → KILLED |
.filter(option -> "nullFirst".equals(option.getArgName())).findFirst(); |
545 | ||
546 |
1
1. analyzeSortOption : negated conditional → KILLED |
if (nullFirst.isPresent()) { |
547 | Boolean isNullFirst = (Boolean) nullFirst.get().getValue().getValue(); | |
548 |
3
1. analyzeSortOption : negated conditional → KILLED 2. analyzeSortOption : negated conditional → KILLED 3. analyzeSortOption : replaced return value with null for org/opensearch/sql/analysis/Analyzer::analyzeSortOption → KILLED |
return new SortOption((asc ? ASC : DESC), (isNullFirst ? NULL_FIRST : NULL_LAST)); |
549 | } | |
550 |
2
1. analyzeSortOption : negated conditional → KILLED 2. analyzeSortOption : replaced return value with null for org/opensearch/sql/analysis/Analyzer::analyzeSortOption → KILLED |
return asc ? SortOption.DEFAULT_ASC : SortOption.DEFAULT_DESC; |
551 | } | |
552 | ||
553 | } | |
Mutations | ||
139 |
1.1 |
|
152 |
1.1 |
|
155 |
1.1 |
|
165 |
1.1 2.2 |
|
169 |
1.1 |
|
170 |
1.1 |
|
172 |
1.1 |
|
184 |
1.1 |
|
185 |
1.1 |
|
201 |
1.1 |
|
206 |
1.1 |
|
209 |
1.1 2.2 |
|
210 |
1.1 |
|
212 |
1.1 |
|
220 |
1.1 |
|
231 |
1.1 |
|
245 |
1.1 |
|
251 |
1.1 |
|
252 |
1.1 |
|
260 |
1.1 |
|
278 |
1.1 |
|
289 |
1.1 |
|
291 |
1.1 2.2 |
|
293 |
1.1 2.2 |
|
295 |
1.1 |
|
318 |
1.1 |
|
320 |
1.1 2.2 |
|
322 |
1.1 2.2 |
|
328 |
1.1 |
|
346 |
1.1 |
|
349 |
1.1 |
|
353 |
1.1 |
|
355 |
1.1 2.2 |
|
356 |
1.1 |
|
377 |
1.1 |
|
379 |
1.1 2.2 |
|
382 |
1.1 |
|
399 |
1.1 |
|
401 |
1.1 |
|
417 |
1.1 |
|
420 |
1.1 |
|
423 |
1.1 |
|
441 |
1.1 |
|
444 |
1.1 |
|
459 |
1.1 |
|
462 |
1.1 |
|
474 |
1.1 |
|
483 |
1.1 |
|
486 |
1.1 |
|
498 |
1.1 |
|
500 |
1.1 |
|
513 |
1.1 |
|
514 |
1.1 |
|
515 |
1.1 |
|
517 |
1.1 |
|
518 |
1.1 |
|
521 |
1.1 |
|
532 |
1.1 2.2 |
|
534 |
1.1 |
|
544 |
1.1 2.2 |
|
546 |
1.1 |
|
548 |
1.1 2.2 3.3 |
|
550 |
1.1 2.2 |