• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

apache / iotdb / #9805

pending completion
#9805

push

travis_ci

web-flow
[IOTDB-6105] Load: NPE when analyzing tsfile (#10821) (#10833)

(cherry picked from commit 2e6d9527c)

271 of 271 new or added lines in 5 files covered. (100.0%)

79671 of 165738 relevant lines covered (48.07%)

0.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

44.2
/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one
3
 * or more contributor license agreements.  See the NOTICE file
4
 * distributed with this work for additional information
5
 * regarding copyright ownership.  The ASF licenses this file
6
 * to you under the Apache License, Version 2.0 (the
7
 * "License"); you may not use this file except in compliance
8
 * with the License.  You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19

20
package org.apache.iotdb.db.queryengine.plan.analyze;
21

22
import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
23
import org.apache.iotdb.common.rpc.thrift.TTimePartitionSlot;
24
import org.apache.iotdb.commons.client.exception.ClientManagerException;
25
import org.apache.iotdb.commons.conf.IoTDBConstant;
26
import org.apache.iotdb.commons.exception.IllegalPathException;
27
import org.apache.iotdb.commons.exception.IoTDBException;
28
import org.apache.iotdb.commons.exception.MetadataException;
29
import org.apache.iotdb.commons.partition.DataPartition;
30
import org.apache.iotdb.commons.partition.DataPartitionQueryParam;
31
import org.apache.iotdb.commons.partition.SchemaNodeManagementPartition;
32
import org.apache.iotdb.commons.partition.SchemaPartition;
33
import org.apache.iotdb.commons.path.MeasurementPath;
34
import org.apache.iotdb.commons.path.PartialPath;
35
import org.apache.iotdb.commons.path.PathPatternTree;
36
import org.apache.iotdb.commons.schema.view.LogicalViewSchema;
37
import org.apache.iotdb.commons.schema.view.viewExpression.ViewExpression;
38
import org.apache.iotdb.commons.service.metric.PerformanceOverviewMetrics;
39
import org.apache.iotdb.confignode.rpc.thrift.TGetDataNodeLocationsResp;
40
import org.apache.iotdb.db.conf.IoTDBConfig;
41
import org.apache.iotdb.db.conf.IoTDBDescriptor;
42
import org.apache.iotdb.db.exception.metadata.template.TemplateIncompatibleException;
43
import org.apache.iotdb.db.exception.metadata.view.UnsupportedViewException;
44
import org.apache.iotdb.db.exception.sql.MeasurementNotExistException;
45
import org.apache.iotdb.db.exception.sql.SemanticException;
46
import org.apache.iotdb.db.exception.sql.StatementAnalyzeException;
47
import org.apache.iotdb.db.protocol.client.ConfigNodeClient;
48
import org.apache.iotdb.db.protocol.client.ConfigNodeClientManager;
49
import org.apache.iotdb.db.protocol.client.ConfigNodeInfo;
50
import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
51
import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
52
import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant;
53
import org.apache.iotdb.db.queryengine.common.header.DatasetHeader;
54
import org.apache.iotdb.db.queryengine.common.header.DatasetHeaderFactory;
55
import org.apache.iotdb.db.queryengine.common.schematree.DeviceSchemaInfo;
56
import org.apache.iotdb.db.queryengine.common.schematree.ISchemaTree;
57
import org.apache.iotdb.db.queryengine.execution.operator.window.WindowType;
58
import org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet;
59
import org.apache.iotdb.db.queryengine.plan.analyze.schema.ISchemaFetcher;
60
import org.apache.iotdb.db.queryengine.plan.analyze.schema.SchemaValidator;
61
import org.apache.iotdb.db.queryengine.plan.expression.Expression;
62
import org.apache.iotdb.db.queryengine.plan.expression.ExpressionType;
63
import org.apache.iotdb.db.queryengine.plan.expression.binary.CompareBinaryExpression;
64
import org.apache.iotdb.db.queryengine.plan.expression.leaf.ConstantOperand;
65
import org.apache.iotdb.db.queryengine.plan.expression.leaf.TimeSeriesOperand;
66
import org.apache.iotdb.db.queryengine.plan.expression.multi.FunctionExpression;
67
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.DeviceViewIntoPathDescriptor;
68
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.FillDescriptor;
69
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.GroupByConditionParameter;
70
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.GroupByCountParameter;
71
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.GroupByParameter;
72
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.GroupBySessionParameter;
73
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.GroupByTimeParameter;
74
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.GroupByVariationParameter;
75
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.IntoPathDescriptor;
76
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.OrderByParameter;
77
import org.apache.iotdb.db.queryengine.plan.statement.Statement;
78
import org.apache.iotdb.db.queryengine.plan.statement.StatementNode;
79
import org.apache.iotdb.db.queryengine.plan.statement.StatementVisitor;
80
import org.apache.iotdb.db.queryengine.plan.statement.component.FillComponent;
81
import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByComponent;
82
import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByConditionComponent;
83
import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByCountComponent;
84
import org.apache.iotdb.db.queryengine.plan.statement.component.GroupBySessionComponent;
85
import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByTimeComponent;
86
import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByVariationComponent;
87
import org.apache.iotdb.db.queryengine.plan.statement.component.IntoComponent;
88
import org.apache.iotdb.db.queryengine.plan.statement.component.Ordering;
89
import org.apache.iotdb.db.queryengine.plan.statement.component.ResultColumn;
90
import org.apache.iotdb.db.queryengine.plan.statement.component.SortItem;
91
import org.apache.iotdb.db.queryengine.plan.statement.component.WhereCondition;
92
import org.apache.iotdb.db.queryengine.plan.statement.crud.DeleteDataStatement;
93
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertBaseStatement;
94
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertMultiTabletsStatement;
95
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowStatement;
96
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsOfOneDeviceStatement;
97
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsStatement;
98
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertStatement;
99
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement;
100
import org.apache.iotdb.db.queryengine.plan.statement.crud.LoadTsFileStatement;
101
import org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement;
102
import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalBatchActivateTemplateStatement;
103
import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalCreateMultiTimeSeriesStatement;
104
import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalCreateTimeSeriesStatement;
105
import org.apache.iotdb.db.queryengine.plan.statement.internal.SchemaFetchStatement;
106
import org.apache.iotdb.db.queryengine.plan.statement.metadata.AlterTimeSeriesStatement;
107
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountDatabaseStatement;
108
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountDevicesStatement;
109
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountLevelTimeSeriesStatement;
110
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountNodesStatement;
111
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountTimeSeriesStatement;
112
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateAlignedTimeSeriesStatement;
113
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateMultiTimeSeriesStatement;
114
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateTimeSeriesStatement;
115
import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildNodesStatement;
116
import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildPathsStatement;
117
import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterStatement;
118
import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDatabaseStatement;
119
import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDevicesStatement;
120
import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTTLStatement;
121
import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTimeSeriesStatement;
122
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ActivateTemplateStatement;
123
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.BatchActivateTemplateStatement;
124
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.CreateSchemaTemplateStatement;
125
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.SetSchemaTemplateStatement;
126
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ShowNodesInSchemaTemplateStatement;
127
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ShowPathSetTemplateStatement;
128
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ShowPathsUsingTemplateStatement;
129
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ShowSchemaTemplateStatement;
130
import org.apache.iotdb.db.queryengine.plan.statement.metadata.view.CreateLogicalViewStatement;
131
import org.apache.iotdb.db.queryengine.plan.statement.metadata.view.ShowLogicalViewStatement;
132
import org.apache.iotdb.db.queryengine.plan.statement.sys.ExplainStatement;
133
import org.apache.iotdb.db.queryengine.plan.statement.sys.ShowQueriesStatement;
134
import org.apache.iotdb.db.queryengine.plan.statement.sys.ShowVersionStatement;
135
import org.apache.iotdb.db.schemaengine.SchemaConstant;
136
import org.apache.iotdb.db.schemaengine.template.Template;
137
import org.apache.iotdb.db.utils.TimePartitionUtils;
138
import org.apache.iotdb.rpc.RpcUtils;
139
import org.apache.iotdb.rpc.TSStatusCode;
140
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
141
import org.apache.iotdb.tsfile.read.common.TimeRange;
142
import org.apache.iotdb.tsfile.read.filter.GroupByFilter;
143
import org.apache.iotdb.tsfile.read.filter.GroupByMonthFilter;
144
import org.apache.iotdb.tsfile.read.filter.PredicateRemoveNotRewriter;
145
import org.apache.iotdb.tsfile.read.filter.basic.Filter;
146
import org.apache.iotdb.tsfile.read.filter.factory.FilterFactory;
147
import org.apache.iotdb.tsfile.utils.Pair;
148
import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
149

150
import org.apache.thrift.TException;
151
import org.slf4j.Logger;
152
import org.slf4j.LoggerFactory;
153

154
import java.util.ArrayList;
155
import java.util.Arrays;
156
import java.util.Collections;
157
import java.util.HashMap;
158
import java.util.HashSet;
159
import java.util.Iterator;
160
import java.util.LinkedHashMap;
161
import java.util.LinkedHashSet;
162
import java.util.LinkedList;
163
import java.util.List;
164
import java.util.Locale;
165
import java.util.Map;
166
import java.util.Objects;
167
import java.util.Set;
168
import java.util.TimeZone;
169
import java.util.stream.Collectors;
170

171
import static com.google.common.base.Preconditions.checkState;
172
import static org.apache.iotdb.commons.conf.IoTDBConstant.ALLOWED_SCHEMA_PROPS;
173
import static org.apache.iotdb.commons.conf.IoTDBConstant.DEADBAND;
174
import static org.apache.iotdb.commons.conf.IoTDBConstant.LOSS;
175
import static org.apache.iotdb.commons.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCARD;
176
import static org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant.DEVICE;
177
import static org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant.ENDTIME;
178
import static org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet.PARTITION_FETCHER;
179
import static org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet.SCHEMA_FETCHER;
180
import static org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetDevice;
181
import static org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetMeasurement;
182
import static org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetPath;
183
import static org.apache.iotdb.db.schemaengine.schemaregion.view.visitor.GetSourcePathsVisitor.getSourcePaths;
184

185
/** This visitor is used to analyze each type of Statement and returns the {@link Analysis}. */
186
public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> {
187

188
  private static final Logger logger = LoggerFactory.getLogger(AnalyzeVisitor.class);
1✔
189

190
  private static final IoTDBConfig CONFIG = IoTDBDescriptor.getInstance().getConfig();
1✔
191

192
  private static final Expression deviceExpression =
1✔
193
      TimeSeriesOperand.constructColumnHeaderExpression(DEVICE, TSDataType.TEXT);
1✔
194

195
  private static final Expression endTimeExpression =
1✔
196
      TimeSeriesOperand.constructColumnHeaderExpression(ENDTIME, TSDataType.INT64);
1✔
197

198
  private final List<String> lastQueryColumnNames =
1✔
199
      new ArrayList<>(Arrays.asList("TIME", "TIMESERIES", "VALUE", "DATATYPE"));
1✔
200

201
  private final IPartitionFetcher partitionFetcher;
202
  private final ISchemaFetcher schemaFetcher;
203

204
  private static final PerformanceOverviewMetrics PERFORMANCE_OVERVIEW_METRICS =
1✔
205
      PerformanceOverviewMetrics.getInstance();
1✔
206

207
  public AnalyzeVisitor(IPartitionFetcher partitionFetcher, ISchemaFetcher schemaFetcher) {
1✔
208
    this.partitionFetcher = partitionFetcher;
1✔
209
    this.schemaFetcher = schemaFetcher;
1✔
210
  }
1✔
211

212
  @Override
213
  public Analysis visitNode(StatementNode node, MPPQueryContext context) {
214
    throw new UnsupportedOperationException(
×
215
        "Unsupported statement type: " + node.getClass().getName());
×
216
  }
217

218
  @Override
219
  public Analysis visitExplain(ExplainStatement explainStatement, MPPQueryContext context) {
220
    Analysis analysis = visitQuery(explainStatement.getQueryStatement(), context);
×
221
    analysis.setStatement(explainStatement);
×
222
    analysis.setFinishQueryAfterAnalyze(true);
×
223
    return analysis;
×
224
  }
225

226
  @Override
227
  public Analysis visitQuery(QueryStatement queryStatement, MPPQueryContext context) {
228
    Analysis analysis = new Analysis();
1✔
229
    try {
230
      // check for semantic errors
231
      queryStatement.semanticCheck();
1✔
232

233
      ISchemaTree schemaTree = analyzeSchema(queryStatement, analysis, context);
1✔
234
      // If there is no leaf node in the schema tree, the query should be completed immediately
235
      if (schemaTree.isEmpty()) {
1✔
236
        return finishQuery(queryStatement, analysis);
×
237
      }
238

239
      // extract global time filter from query filter and determine if there is a value filter
240
      analyzeGlobalTimeFilter(analysis, queryStatement);
1✔
241

242
      if (queryStatement.isLastQuery()) {
1✔
243
        return analyzeLastQuery(queryStatement, analysis, schemaTree);
×
244
      }
245

246
      List<Pair<Expression, String>> outputExpressions;
247
      if (queryStatement.isAlignByDevice()) {
1✔
248
        Set<PartialPath> deviceSet = analyzeFrom(queryStatement, schemaTree);
1✔
249

250
        analyzeDeviceToWhere(analysis, queryStatement, schemaTree, deviceSet);
1✔
251
        outputExpressions = analyzeSelect(analysis, queryStatement, schemaTree, deviceSet);
1✔
252
        if (deviceSet.isEmpty()) {
1✔
253
          return finishQuery(queryStatement, analysis);
×
254
        }
255

256
        analyzeDeviceToGroupBy(analysis, queryStatement, schemaTree, deviceSet);
1✔
257
        analyzeDeviceToOrderBy(analysis, queryStatement, schemaTree, deviceSet);
1✔
258
        analyzeHaving(analysis, queryStatement, schemaTree, deviceSet);
1✔
259

260
        analyzeDeviceToAggregation(analysis, queryStatement);
1✔
261
        analyzeDeviceToSourceTransform(analysis, queryStatement);
1✔
262
        analyzeDeviceToSource(analysis, queryStatement);
1✔
263

264
        analyzeDeviceViewOutput(analysis, queryStatement);
1✔
265
        analyzeDeviceViewInput(analysis, queryStatement);
1✔
266

267
        analyzeInto(analysis, queryStatement, deviceSet, outputExpressions);
1✔
268
      } else {
1✔
269
        Map<Integer, List<Pair<Expression, String>>> outputExpressionMap =
1✔
270
            analyzeSelect(analysis, queryStatement, schemaTree);
1✔
271

272
        outputExpressions = new ArrayList<>();
1✔
273
        outputExpressionMap.values().forEach(outputExpressions::addAll);
1✔
274
        analysis.setOutputExpressions(outputExpressions);
1✔
275
        if (outputExpressions.isEmpty()) {
1✔
276
          return finishQuery(queryStatement, analysis);
×
277
        }
278

279
        analyzeGroupBy(analysis, queryStatement, schemaTree);
1✔
280
        analyzeHaving(analysis, queryStatement, schemaTree);
1✔
281
        analyzeOrderBy(analysis, queryStatement, schemaTree);
1✔
282

283
        analyzeGroupByLevel(analysis, queryStatement, outputExpressionMap, outputExpressions);
1✔
284
        analyzeGroupByTag(analysis, queryStatement, outputExpressions);
1✔
285

286
        Set<Expression> selectExpressions = new LinkedHashSet<>();
1✔
287
        if (queryStatement.isOutputEndTime()) {
1✔
288
          selectExpressions.add(endTimeExpression);
×
289
        }
290
        for (Pair<Expression, String> outputExpressionAndAlias : outputExpressions) {
1✔
291
          selectExpressions.add(outputExpressionAndAlias.left);
1✔
292
        }
1✔
293
        analysis.setSelectExpressions(selectExpressions);
1✔
294

295
        analyzeAggregation(analysis, queryStatement);
1✔
296

297
        analyzeWhere(analysis, queryStatement, schemaTree);
1✔
298
        analyzeSourceTransform(analysis, queryStatement);
1✔
299

300
        analyzeSource(analysis, queryStatement);
1✔
301

302
        analyzeInto(analysis, queryStatement, outputExpressions);
1✔
303
      }
304

305
      analyzeGroupByTime(analysis, queryStatement);
1✔
306

307
      analyzeFill(analysis, queryStatement);
1✔
308

309
      // generate result set header according to output expressions
310
      analyzeOutput(analysis, queryStatement, outputExpressions);
1✔
311

312
      // fetch partition information
313
      analyzeDataPartition(analysis, queryStatement, schemaTree);
1✔
314

315
    } catch (StatementAnalyzeException e) {
×
316
      throw new StatementAnalyzeException(
×
317
          "Meet error when analyzing the query statement: " + e.getMessage());
×
318
    }
1✔
319
    return analysis;
1✔
320
  }
321

322
  private ISchemaTree analyzeSchema(
323
      QueryStatement queryStatement, Analysis analysis, MPPQueryContext context) {
324
    // concat path and construct path pattern tree
325
    PathPatternTree patternTree = new PathPatternTree(queryStatement.useWildcard());
1✔
326
    queryStatement = (QueryStatement) new ConcatPathRewriter().rewrite(queryStatement, patternTree);
1✔
327
    analysis.setStatement(queryStatement);
1✔
328

329
    // request schema fetch API
330
    long startTime = System.nanoTime();
1✔
331
    ISchemaTree schemaTree;
332
    try {
333
      logger.debug("[StartFetchSchema]");
1✔
334
      if (queryStatement.isGroupByTag()) {
1✔
335
        schemaTree = schemaFetcher.fetchSchemaWithTags(patternTree, context);
×
336
      } else {
337
        schemaTree = schemaFetcher.fetchSchema(patternTree, context);
1✔
338
      }
339

340
      // make sure paths in logical view is fetched
341
      updateSchemaTreeByViews(analysis, schemaTree);
1✔
342
    } finally {
343
      logger.debug("[EndFetchSchema]");
1✔
344
      QueryPlanCostMetricSet.getInstance()
1✔
345
          .recordPlanCost(SCHEMA_FETCHER, System.nanoTime() - startTime);
1✔
346
    }
347
    analysis.setSchemaTree(schemaTree);
1✔
348
    return schemaTree;
1✔
349
  }
350

351
  private Analysis finishQuery(QueryStatement queryStatement, Analysis analysis) {
352
    if (queryStatement.isSelectInto()) {
×
353
      analysis.setRespDatasetHeader(
×
354
          DatasetHeaderFactory.getSelectIntoHeader(queryStatement.isAlignByDevice()));
×
355
    }
356
    if (queryStatement.isLastQuery()) {
×
357
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getLastQueryHeader());
×
358
    }
359
    analysis.setFinishQueryAfterAnalyze(true);
×
360
    return analysis;
×
361
  }
362

363
  private void analyzeGlobalTimeFilter(Analysis analysis, QueryStatement queryStatement) {
364
    Filter globalTimeFilter = null;
1✔
365
    boolean hasValueFilter = false;
1✔
366
    if (queryStatement.getWhereCondition() != null) {
1✔
367
      WhereCondition whereCondition = queryStatement.getWhereCondition();
1✔
368
      Expression predicate = whereCondition.getPredicate();
1✔
369

370
      Pair<Filter, Boolean> resultPair =
1✔
371
          ExpressionAnalyzer.extractGlobalTimeFilter(predicate, true, true);
1✔
372
      globalTimeFilter = resultPair.left;
1✔
373
      if (globalTimeFilter != null) {
1✔
374
        globalTimeFilter = PredicateRemoveNotRewriter.rewrite(globalTimeFilter);
1✔
375
      }
376
      hasValueFilter = resultPair.right;
1✔
377

378
      predicate = ExpressionAnalyzer.evaluatePredicate(predicate);
1✔
379

380
      // set where condition to null if predicate is true or time filter.
381
      if (!hasValueFilter
1✔
382
          || (predicate.getExpressionType().equals(ExpressionType.CONSTANT)
1✔
383
              && Boolean.parseBoolean(predicate.getExpressionString()))) {
×
384
        queryStatement.setWhereCondition(null);
1✔
385
      } else {
386
        whereCondition.setPredicate(predicate);
1✔
387
      }
388
    }
389
    if (queryStatement.isGroupByTime()) {
1✔
390
      GroupByTimeComponent groupByTimeComponent = queryStatement.getGroupByTimeComponent();
1✔
391
      Filter groupByFilter = initGroupByFilter(groupByTimeComponent);
1✔
392
      if (globalTimeFilter == null) {
1✔
393
        globalTimeFilter = groupByFilter;
1✔
394
      } else {
395
        globalTimeFilter = FilterFactory.and(globalTimeFilter, groupByFilter);
1✔
396
      }
397
    }
398
    analysis.setGlobalTimeFilter(globalTimeFilter);
1✔
399
    analysis.setHasValueFilter(hasValueFilter);
1✔
400
  }
1✔
401

402
  private Analysis analyzeLastQuery(
403
      QueryStatement queryStatement, Analysis analysis, ISchemaTree schemaTree) {
404
    if (analysis.hasValueFilter()) {
×
405
      throw new SemanticException("Only time filters are supported in LAST query");
×
406
    }
407
    analyzeLastOrderBy(analysis, queryStatement);
×
408

409
    List<Expression> selectExpressions = new ArrayList<>();
×
410
    for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) {
×
411
      selectExpressions.add(resultColumn.getExpression());
×
412
    }
×
413
    analyzeLastSource(analysis, selectExpressions, schemaTree);
×
414

415
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getLastQueryHeader());
×
416

417
    // fetch partition information
418
    analyzeDataPartition(analysis, queryStatement, schemaTree);
×
419

420
    return analysis;
×
421
  }
422

423
  private void analyzeLastSource(
424
      Analysis analysis, List<Expression> selectExpressions, ISchemaTree schemaTree) {
425
    Set<Expression> sourceExpressions;
426

427
    sourceExpressions = new LinkedHashSet<>();
×
428

429
    for (Expression selectExpression : selectExpressions) {
×
430
      for (Expression sourceExpression :
431
          ExpressionAnalyzer.bindSchemaForExpression(selectExpression, schemaTree)) {
×
432
        if (!(sourceExpression instanceof TimeSeriesOperand)) {
×
433
          throw new SemanticException(
×
434
              "Views with functions and expressions cannot be used in LAST query");
435
        }
436
        sourceExpressions.add(sourceExpression);
×
437
      }
×
438
    }
×
439
    analysis.setSourceExpressions(sourceExpressions);
×
440
  }
×
441

442
  private void updateSchemaTreeByViews(Analysis analysis, ISchemaTree originSchemaTree) {
443
    if (!originSchemaTree.hasLogicalViewMeasurement()) {
1✔
444
      return;
1✔
445
    }
446

447
    PathPatternTree patternTree = new PathPatternTree();
×
448
    boolean needToReFetch = false;
×
449
    boolean useLogicalView = false;
×
450
    try {
451
      Pair<List<MeasurementPath>, Integer> tempPair =
×
452
          originSchemaTree.searchMeasurementPaths(new PartialPath("root.**"));
×
453
      for (MeasurementPath measurementPath : tempPair.left) {
×
454
        if (measurementPath.getMeasurementSchema().isLogicalView()) {
×
455
          useLogicalView = true;
×
456
          LogicalViewSchema logicalViewSchema =
×
457
              (LogicalViewSchema) measurementPath.getMeasurementSchema();
×
458
          ViewExpression viewExpression = logicalViewSchema.getExpression();
×
459
          List<PartialPath> pathsNeedToReFetch = getSourcePaths(viewExpression);
×
460
          for (PartialPath path : pathsNeedToReFetch) {
×
461
            patternTree.appendFullPath(path);
×
462
            needToReFetch = true;
×
463
          }
×
464
        }
465
      }
×
466
    } catch (Exception e) {
×
467
      throw new SemanticException(e);
×
468
    }
×
469
    analysis.setUseLogicalView(useLogicalView);
×
470
    if (useLogicalView
×
471
        && analysis.getStatement() instanceof QueryStatement
×
472
        && (((QueryStatement) analysis.getStatement()).isGroupByTag())) {
×
473
      throw new SemanticException("Views cannot be used in GROUP BY TAGS query yet.");
×
474
    }
475

476
    if (needToReFetch) {
×
477
      ISchemaTree viewSchemaTree = this.schemaFetcher.fetchSchema(patternTree, null);
×
478
      originSchemaTree.mergeSchemaTree(viewSchemaTree);
×
479
      Set<String> allDatabases = viewSchemaTree.getDatabases();
×
480
      allDatabases.addAll(originSchemaTree.getDatabases());
×
481
      originSchemaTree.setDatabases(allDatabases);
×
482
    }
483
  }
×
484

485
  private Map<Integer, List<Pair<Expression, String>>> analyzeSelect(
486
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
487
    Map<Integer, List<Pair<Expression, String>>> outputExpressionMap = new HashMap<>();
1✔
488

489
    boolean isGroupByLevel = queryStatement.isGroupByLevel();
1✔
490
    ColumnPaginationController paginationController =
1✔
491
        new ColumnPaginationController(
492
            queryStatement.getSeriesLimit(),
1✔
493
            queryStatement.getSeriesOffset(),
1✔
494
            queryStatement.isLastQuery() || isGroupByLevel);
1✔
495

496
    Set<String> aliasSet = new HashSet<>();
1✔
497

498
    int columnIndex = 0;
1✔
499

500
    for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) {
1✔
501
      List<Pair<Expression, String>> outputExpressions = new ArrayList<>();
1✔
502

503
      List<Expression> resultExpressions =
1✔
504
          ExpressionAnalyzer.bindSchemaForExpression(resultColumn.getExpression(), schemaTree);
1✔
505
      for (Expression expression : resultExpressions) {
1✔
506
        if (paginationController.hasCurOffset()) {
1✔
507
          paginationController.consumeOffset();
×
508
        } else if (paginationController.hasCurLimit()) {
1✔
509
          if (isGroupByLevel) {
1✔
510
            analyzeExpressionType(analysis, expression);
×
511
            outputExpressions.add(new Pair<>(expression, resultColumn.getAlias()));
×
512
            queryStatement
×
513
                .getGroupByLevelComponent()
×
514
                .updateIsCountStar(resultColumn.getExpression());
×
515
          } else {
516
            Expression normalizedExpression = ExpressionAnalyzer.normalizeExpression(expression);
1✔
517
            analyzeExpressionType(analysis, normalizedExpression);
1✔
518

519
            checkAliasUniqueness(resultColumn.getAlias(), aliasSet);
1✔
520

521
            outputExpressions.add(
1✔
522
                new Pair<>(
523
                    normalizedExpression,
524
                    analyzeAlias(resultColumn.getAlias(), expression, normalizedExpression)));
1✔
525
          }
526
          paginationController.consumeLimit();
1✔
527
        } else {
528
          break;
529
        }
530
      }
1✔
531
      outputExpressionMap.put(columnIndex++, outputExpressions);
1✔
532
    }
1✔
533
    return outputExpressionMap;
1✔
534
  }
535

536
  private Set<PartialPath> analyzeFrom(QueryStatement queryStatement, ISchemaTree schemaTree) {
537
    // device path patterns in FROM clause
538
    List<PartialPath> devicePatternList = queryStatement.getFromComponent().getPrefixPaths();
1✔
539

540
    Set<PartialPath> deviceSet = new LinkedHashSet<>();
1✔
541
    for (PartialPath devicePattern : devicePatternList) {
1✔
542
      // get all matched devices
543
      deviceSet.addAll(
1✔
544
          schemaTree.getMatchedDevices(devicePattern).stream()
1✔
545
              .map(DeviceSchemaInfo::getDevicePath)
1✔
546
              .collect(Collectors.toList()));
1✔
547
    }
1✔
548
    return deviceSet;
1✔
549
  }
550

551
  private List<Pair<Expression, String>> analyzeSelect(
552
      Analysis analysis,
553
      QueryStatement queryStatement,
554
      ISchemaTree schemaTree,
555
      Set<PartialPath> deviceSet) {
556
    List<Pair<Expression, String>> outputExpressions = new ArrayList<>();
1✔
557
    Map<String, Set<Expression>> deviceToSelectExpressions = new HashMap<>();
1✔
558

559
    ColumnPaginationController paginationController =
1✔
560
        new ColumnPaginationController(
561
            queryStatement.getSeriesLimit(), queryStatement.getSeriesOffset(), false);
1✔
562
    Set<PartialPath> noMeasurementDevices = new HashSet<>(deviceSet);
1✔
563

564
    for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) {
1✔
565
      Expression selectExpression = resultColumn.getExpression();
1✔
566

567
      // select expression after removing wildcard
568
      // use LinkedHashMap for order-preserving
569
      Map<Expression, Map<String, Expression>> measurementToDeviceSelectExpressions =
1✔
570
          new LinkedHashMap<>();
571
      for (PartialPath device : deviceSet) {
1✔
572
        List<Expression> selectExpressionsOfOneDevice =
1✔
573
            ExpressionAnalyzer.concatDeviceAndBindSchemaForExpression(
1✔
574
                selectExpression, device, schemaTree);
575
        if (selectExpressionsOfOneDevice.isEmpty()) {
1✔
576
          continue;
×
577
        }
578
        noMeasurementDevices.remove(device);
1✔
579
        updateMeasurementToDeviceSelectExpressions(
1✔
580
            analysis, measurementToDeviceSelectExpressions, device, selectExpressionsOfOneDevice);
581
      }
1✔
582

583
      checkAliasUniqueness(resultColumn.getAlias(), measurementToDeviceSelectExpressions);
1✔
584

585
      for (Map.Entry<Expression, Map<String, Expression>> measurementDeviceSelectExpressionsEntry :
586
          measurementToDeviceSelectExpressions.entrySet()) {
1✔
587
        Expression measurementExpression = measurementDeviceSelectExpressionsEntry.getKey();
1✔
588
        Map<String, Expression> deviceToSelectExpressionsOfOneMeasurement =
1✔
589
            measurementDeviceSelectExpressionsEntry.getValue();
1✔
590

591
        if (paginationController.hasCurOffset()) {
1✔
592
          paginationController.consumeOffset();
×
593
        } else if (paginationController.hasCurLimit()) {
1✔
594
          deviceToSelectExpressionsOfOneMeasurement
1✔
595
              .values()
1✔
596
              .forEach(expression -> analyzeExpressionType(analysis, expression));
1✔
597
          // check whether the datatype of paths which has the same measurement name are
598
          // consistent; if not, throw a SemanticException
599
          checkDataTypeConsistencyInAlignByDevice(
1✔
600
              analysis, new ArrayList<>(deviceToSelectExpressionsOfOneMeasurement.values()));
1✔
601

602
          // add outputExpressions
603
          Expression normalizedMeasurementExpression =
1✔
604
              ExpressionAnalyzer.toLowerCaseExpression(measurementExpression);
1✔
605
          analyzeExpressionType(analysis, normalizedMeasurementExpression);
1✔
606
          outputExpressions.add(
1✔
607
              new Pair<>(
608
                  normalizedMeasurementExpression,
609
                  analyzeAlias(
1✔
610
                      resultColumn.getAlias(),
1✔
611
                      measurementExpression,
612
                      normalizedMeasurementExpression)));
613

614
          // add deviceToSelectExpressions
615
          updateDeviceToSelectExpressions(
1✔
616
              analysis, deviceToSelectExpressions, deviceToSelectExpressionsOfOneMeasurement);
617

618
          paginationController.consumeLimit();
1✔
619
        } else {
620
          break;
621
        }
622
      }
1✔
623
    }
1✔
624

625
    // remove devices without measurements to compute
626
    deviceSet.removeAll(noMeasurementDevices);
1✔
627

628
    // when the select expression of any device is empty,
629
    // the where expression map also need remove this device
630
    if (analysis.getDeviceToWhereExpression() != null) {
1✔
631
      noMeasurementDevices.forEach(
1✔
632
          devicePath -> analysis.getDeviceToWhereExpression().remove(devicePath.getFullPath()));
×
633
    }
634

635
    analysis.setDeviceToSelectExpressions(deviceToSelectExpressions);
1✔
636

637
    // set selectExpressions
638
    Set<Expression> selectExpressions = new LinkedHashSet<>();
1✔
639
    selectExpressions.add(deviceExpression);
1✔
640
    if (queryStatement.isOutputEndTime()) {
1✔
641
      selectExpressions.add(endTimeExpression);
×
642
    }
643
    selectExpressions.addAll(
1✔
644
        outputExpressions.stream()
1✔
645
            .map(Pair::getLeft)
1✔
646
            .collect(Collectors.toCollection(LinkedHashSet::new)));
1✔
647
    analysis.setSelectExpressions(selectExpressions);
1✔
648

649
    return outputExpressions;
1✔
650
  }
651

652
  private void updateMeasurementToDeviceSelectExpressions(
653
      Analysis analysis,
654
      Map<Expression, Map<String, Expression>> measurementToDeviceSelectExpressions,
655
      PartialPath device,
656
      List<Expression> selectExpressionsOfOneDevice) {
657
    for (Expression expression : selectExpressionsOfOneDevice) {
1✔
658
      Expression measurementExpression =
1✔
659
          ExpressionAnalyzer.getMeasurementExpression(expression, analysis);
1✔
660
      measurementToDeviceSelectExpressions
1✔
661
          .computeIfAbsent(measurementExpression, key -> new LinkedHashMap<>())
1✔
662
          .put(device.getFullPath(), ExpressionAnalyzer.toLowerCaseExpression(expression));
1✔
663
    }
1✔
664
  }
1✔
665

666
  private void updateDeviceToSelectExpressions(
667
      Analysis analysis,
668
      Map<String, Set<Expression>> deviceToSelectExpressions,
669
      Map<String, Expression> deviceToSelectExpressionsOfOneMeasurement) {
670
    for (Map.Entry<String, Expression> deviceNameSelectExpressionEntry :
671
        deviceToSelectExpressionsOfOneMeasurement.entrySet()) {
1✔
672
      String deviceName = deviceNameSelectExpressionEntry.getKey();
1✔
673
      Expression expression = deviceNameSelectExpressionEntry.getValue();
1✔
674

675
      Expression normalizedExpression = ExpressionAnalyzer.toLowerCaseExpression(expression);
1✔
676
      analyzeExpressionType(analysis, normalizedExpression);
1✔
677
      deviceToSelectExpressions
1✔
678
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
679
          .add(normalizedExpression);
1✔
680
    }
1✔
681
  }
1✔
682

683
  private String analyzeAlias(
684
      String resultColumnAlias, Expression rawExpression, Expression normalizedExpression) {
685
    if (resultColumnAlias != null) {
1✔
686
      // use alias as output symbol
687
      return resultColumnAlias;
1✔
688
    }
689

690
    if (!Objects.equals(normalizedExpression, rawExpression)) {
1✔
691
      return rawExpression.getOutputSymbol();
1✔
692
    }
693
    return null;
1✔
694
  }
695

696
  private void analyzeHaving(
697
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
698
    if (!queryStatement.hasHaving()) {
1✔
699
      return;
1✔
700
    }
701

702
    // get removeWildcard Expressions in Having
703
    List<Expression> conJunctions =
1✔
704
        ExpressionAnalyzer.bindSchemaForPredicate(
1✔
705
            queryStatement.getHavingCondition().getPredicate(),
1✔
706
            queryStatement.getFromComponent().getPrefixPaths(),
1✔
707
            schemaTree,
708
            true);
709
    Expression havingExpression =
1✔
710
        ExpressionUtils.constructQueryFilter(
1✔
711
            conJunctions.stream().distinct().collect(Collectors.toList()));
1✔
712
    havingExpression = ExpressionAnalyzer.normalizeExpression(havingExpression);
1✔
713
    TSDataType outputType = analyzeExpressionType(analysis, havingExpression);
1✔
714
    if (outputType != TSDataType.BOOLEAN) {
1✔
715
      throw new SemanticException(
×
716
          String.format(
×
717
              "The output type of the expression in HAVING clause should be BOOLEAN, actual data type: %s.",
718
              outputType));
719
    }
720
    analysis.setHavingExpression(havingExpression);
1✔
721
  }
1✔
722

723
  private void analyzeHaving(
724
      Analysis analysis,
725
      QueryStatement queryStatement,
726
      ISchemaTree schemaTree,
727
      Set<PartialPath> deviceSet) {
728
    if (!queryStatement.hasHaving()) {
1✔
729
      return;
1✔
730
    }
731

732
    // two maps to be updated
733
    Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
734
        analysis.getDeviceToAggregationExpressions();
1✔
735
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
736
        analysis.getDeviceToOutputExpressions();
1✔
737

738
    Expression havingExpression = queryStatement.getHavingCondition().getPredicate();
1✔
739
    Set<Expression> conJunctions = new HashSet<>();
1✔
740

741
    for (PartialPath device : deviceSet) {
1✔
742
      List<Expression> expressionsInHaving =
1✔
743
          ExpressionAnalyzer.concatDeviceAndBindSchemaForExpression(
1✔
744
              havingExpression, device, schemaTree);
745

746
      conJunctions.addAll(
1✔
747
          expressionsInHaving.stream()
1✔
748
              .map(expression -> ExpressionAnalyzer.getMeasurementExpression(expression, analysis))
1✔
749
              .collect(Collectors.toList()));
1✔
750

751
      for (Expression expression : expressionsInHaving) {
1✔
752
        Set<Expression> aggregationExpressions = new LinkedHashSet<>();
1✔
753
        Set<Expression> normalizedAggregationExpressions = new LinkedHashSet<>();
1✔
754
        for (Expression aggregationExpression :
755
            ExpressionAnalyzer.searchAggregationExpressions(expression)) {
1✔
756
          Expression normalizedAggregationExpression =
1✔
757
              ExpressionAnalyzer.normalizeExpression(aggregationExpression);
1✔
758

759
          analyzeExpressionType(analysis, aggregationExpression);
1✔
760
          analyzeExpressionType(analysis, normalizedAggregationExpression);
1✔
761

762
          aggregationExpressions.add(aggregationExpression);
1✔
763
          normalizedAggregationExpressions.add(normalizedAggregationExpression);
1✔
764
        }
1✔
765
        deviceToOutputExpressions
1✔
766
            .computeIfAbsent(device.getFullPath(), key -> new LinkedHashSet<>())
1✔
767
            .addAll(aggregationExpressions);
1✔
768
        deviceToAggregationExpressions
1✔
769
            .computeIfAbsent(device.getFullPath(), key -> new LinkedHashSet<>())
1✔
770
            .addAll(normalizedAggregationExpressions);
1✔
771
      }
1✔
772
    }
1✔
773

774
    havingExpression = ExpressionUtils.constructQueryFilter(new ArrayList<>(conJunctions));
1✔
775
    TSDataType outputType = analyzeExpressionType(analysis, havingExpression);
1✔
776
    if (outputType != TSDataType.BOOLEAN) {
1✔
777
      throw new SemanticException(
×
778
          String.format(
×
779
              "The output type of the expression in HAVING clause should be BOOLEAN, actual data type: %s.",
780
              outputType));
781
    }
782
    analysis.setDeviceToAggregationExpressions(deviceToAggregationExpressions);
1✔
783
    analysis.setHavingExpression(havingExpression);
1✔
784
  }
1✔
785

786
  private void analyzeGroupByLevel(
787
      Analysis analysis,
788
      QueryStatement queryStatement,
789
      Map<Integer, List<Pair<Expression, String>>> outputExpressionMap,
790
      List<Pair<Expression, String>> outputExpressions) {
791
    if (!queryStatement.isGroupByLevel()) {
1✔
792
      return;
1✔
793
    }
794

795
    GroupByLevelController groupByLevelController =
×
796
        new GroupByLevelController(queryStatement.getGroupByLevelComponent().getLevels());
×
797

798
    List<Expression> groupedSelectExpressions = new LinkedList<>();
×
799

800
    for (List<Pair<Expression, String>> outputExpressionList : outputExpressionMap.values()) {
×
801
      Set<Expression> groupedSelectExpressionSet = new LinkedHashSet<>();
×
802
      for (int i = 0; i < outputExpressionList.size(); i++) {
×
803
        Pair<Expression, String> expressionAliasPair = outputExpressionList.get(i);
×
804
        boolean isCountStar = queryStatement.getGroupByLevelComponent().isCountStar(i);
×
805
        Expression groupedExpression =
×
806
            groupByLevelController.control(
×
807
                isCountStar, expressionAliasPair.left, expressionAliasPair.right);
808
        groupedSelectExpressionSet.add(groupedExpression);
×
809
      }
810
      groupedSelectExpressions.addAll(groupedSelectExpressionSet);
×
811
    }
×
812

813
    LinkedHashMap<Expression, Set<Expression>> groupByLevelExpressions = new LinkedHashMap<>();
×
814
    if (queryStatement.hasHaving()) {
×
815
      // update havingExpression
816
      Expression havingExpression = groupByLevelController.control(analysis.getHavingExpression());
×
817
      analyzeExpressionType(analysis, havingExpression);
×
818
      analysis.setHavingExpression(havingExpression);
×
819
      updateGroupByLevelExpressions(
×
820
          analysis,
821
          havingExpression,
822
          groupByLevelExpressions,
823
          groupByLevelController.getGroupedExpressionToRawExpressionsMap());
×
824
    }
825

826
    outputExpressions.clear();
×
827
    ColumnPaginationController paginationController =
×
828
        new ColumnPaginationController(
829
            queryStatement.getSeriesLimit(), queryStatement.getSeriesOffset(), false);
×
830
    for (Expression groupedExpression : groupedSelectExpressions) {
×
831
      if (paginationController.hasCurOffset()) {
×
832
        paginationController.consumeOffset();
×
833
      } else if (paginationController.hasCurLimit()) {
×
834
        Expression normalizedGroupedExpression =
×
835
            ExpressionAnalyzer.normalizeExpression(groupedExpression);
×
836
        analyzeExpressionType(analysis, normalizedGroupedExpression);
×
837
        outputExpressions.add(
×
838
            new Pair<>(
839
                normalizedGroupedExpression,
840
                analyzeAlias(
×
841
                    groupByLevelController.getAlias(groupedExpression.getExpressionString()),
×
842
                    groupedExpression,
843
                    normalizedGroupedExpression)));
844
        updateGroupByLevelExpressions(
×
845
            analysis,
846
            groupedExpression,
847
            groupByLevelExpressions,
848
            groupByLevelController.getGroupedExpressionToRawExpressionsMap());
×
849
        paginationController.consumeLimit();
×
850
      } else {
851
        break;
852
      }
853
    }
×
854

855
    checkDataTypeConsistencyInGroupByLevel(analysis, groupByLevelExpressions);
×
856
    analysis.setCrossGroupByExpressions(groupByLevelExpressions);
×
857
  }
×
858

859
  private void checkDataTypeConsistencyInGroupByLevel(
860
      Analysis analysis, Map<Expression, Set<Expression>> groupByLevelExpressions) {
861
    for (Map.Entry<Expression, Set<Expression>> groupedExpressionRawExpressionsEntry :
862
        groupByLevelExpressions.entrySet()) {
×
863
      Expression groupedAggregationExpression = groupedExpressionRawExpressionsEntry.getKey();
×
864
      Set<Expression> rawAggregationExpressions = groupedExpressionRawExpressionsEntry.getValue();
×
865

866
      TSDataType checkedDataType = analysis.getType(groupedAggregationExpression);
×
867
      for (Expression rawAggregationExpression : rawAggregationExpressions) {
×
868
        if (analysis.getType(rawAggregationExpression) != checkedDataType) {
×
869
          throw new SemanticException(
×
870
              String.format(
×
871
                  "GROUP BY LEVEL: the data types of the same output column[%s] should be the same.",
872
                  groupedAggregationExpression));
873
        }
874
      }
×
875
    }
×
876
  }
×
877

878
  private void updateGroupByLevelExpressions(
879
      Analysis analysis,
880
      Expression expression,
881
      Map<Expression, Set<Expression>> groupByLevelExpressions,
882
      Map<Expression, Set<Expression>> groupedExpressionToRawExpressionsMap) {
883
    for (Expression groupedAggregationExpression :
884
        ExpressionAnalyzer.searchAggregationExpressions(expression)) {
×
885
      Set<Expression> groupedExpressionSet =
×
886
          groupedExpressionToRawExpressionsMap.get(groupedAggregationExpression).stream()
×
887
              .map(ExpressionAnalyzer::normalizeExpression)
×
888
              .collect(Collectors.toSet());
×
889
      Expression groupedAggregationExpressionWithoutAlias =
×
890
          ExpressionAnalyzer.normalizeExpression(groupedAggregationExpression);
×
891

892
      analyzeExpressionType(analysis, groupedAggregationExpressionWithoutAlias);
×
893
      groupedExpressionSet.forEach(
×
894
          groupedExpression -> analyzeExpressionType(analysis, groupedExpression));
×
895

896
      groupByLevelExpressions
×
897
          .computeIfAbsent(groupedAggregationExpressionWithoutAlias, key -> new HashSet<>())
×
898
          .addAll(groupedExpressionSet);
×
899
    }
×
900
  }
×
901

902
  /**
903
   * This method is used to analyze GROUP BY TAGS query.
904
   *
905
   * <p>TODO: support slimit/soffset/value filter
906
   */
907
  private void analyzeGroupByTag(
908
      Analysis analysis,
909
      QueryStatement queryStatement,
910
      List<Pair<Expression, String>> outputExpressions) {
911
    if (!queryStatement.isGroupByTag()) {
1✔
912
      return;
1✔
913
    }
914
    if (analysis.hasValueFilter()) {
×
915
      throw new SemanticException("Only time filters are supported in GROUP BY TAGS query");
×
916
    }
917

918
    List<String> tagKeys = queryStatement.getGroupByTagComponent().getTagKeys();
×
919
    Map<List<String>, LinkedHashMap<Expression, List<Expression>>>
920
        tagValuesToGroupedTimeseriesOperands = new HashMap<>();
×
921
    LinkedHashMap<Expression, Set<Expression>> outputExpressionToRawExpressionsMap =
×
922
        new LinkedHashMap<>();
923

924
    for (Pair<Expression, String> outputExpressionAndAlias : outputExpressions) {
×
925
      FunctionExpression rawExpression = (FunctionExpression) outputExpressionAndAlias.getLeft();
×
926
      FunctionExpression measurementExpression =
×
927
          (FunctionExpression) ExpressionAnalyzer.getMeasurementExpression(rawExpression, analysis);
×
928
      outputExpressionToRawExpressionsMap
×
929
          .computeIfAbsent(measurementExpression, v -> new HashSet<>())
×
930
          .add(rawExpression);
×
931

932
      Map<String, String> tagMap =
×
933
          ((MeasurementPath)
934
                  ((TimeSeriesOperand) measurementExpression.getExpressions().get(0)).getPath())
×
935
              .getTagMap();
×
936
      List<String> tagValues = new ArrayList<>();
×
937
      for (String tagKey : tagKeys) {
×
938
        tagValues.add(tagMap.get(tagKey));
×
939
      }
×
940
      tagValuesToGroupedTimeseriesOperands
×
941
          .computeIfAbsent(tagValues, key -> new LinkedHashMap<>())
×
942
          .computeIfAbsent(measurementExpression, key -> new ArrayList<>())
×
943
          .add(rawExpression.getExpressions().get(0));
×
944
    }
×
945

946
    // update outputExpressions
947
    outputExpressions.clear();
×
948
    for (String tagKey : tagKeys) {
×
949
      Expression tagKeyExpression =
×
950
          TimeSeriesOperand.constructColumnHeaderExpression(tagKey, TSDataType.TEXT);
×
951
      analyzeExpressionType(analysis, tagKeyExpression);
×
952
      outputExpressions.add(new Pair<>(tagKeyExpression, null));
×
953
    }
×
954
    for (Expression outputExpression : outputExpressionToRawExpressionsMap.keySet()) {
×
955
      // TODO: support alias
956
      analyzeExpressionType(analysis, outputExpression);
×
957
      outputExpressions.add(new Pair<>(outputExpression, null));
×
958
    }
×
959
    analysis.setTagKeys(queryStatement.getGroupByTagComponent().getTagKeys());
×
960
    analysis.setTagValuesToGroupedTimeseriesOperands(tagValuesToGroupedTimeseriesOperands);
×
961
    analysis.setCrossGroupByExpressions(outputExpressionToRawExpressionsMap);
×
962
  }
×
963

964
  private void analyzeDeviceToAggregation(Analysis analysis, QueryStatement queryStatement) {
965
    if (!queryStatement.isAggregationQuery()) {
1✔
966
      return;
1✔
967
    }
968

969
    updateDeviceToAggregationAndOutputExpressions(
1✔
970
        analysis, analysis.getDeviceToSelectExpressions());
1✔
971
    if (queryStatement.hasOrderByExpression()) {
1✔
972
      updateDeviceToAggregationAndOutputExpressions(
1✔
973
          analysis, analysis.getDeviceToOrderByExpressions());
1✔
974
    }
975
  }
1✔
976

977
  private void updateDeviceToAggregationAndOutputExpressions(
978
      Analysis analysis, Map<String, Set<Expression>> deviceToExpressions) {
979
    // two maps to be updated
980
    Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
981
        analysis.getDeviceToAggregationExpressions();
1✔
982
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
983
        analysis.getDeviceToOutputExpressions();
1✔
984

985
    for (Map.Entry<String, Set<Expression>> deviceExpressionsEntry :
986
        deviceToExpressions.entrySet()) {
1✔
987
      String deviceName = deviceExpressionsEntry.getKey();
1✔
988
      Set<Expression> expressionSet = deviceExpressionsEntry.getValue();
1✔
989

990
      Set<Expression> aggregationExpressions = new LinkedHashSet<>();
1✔
991
      Set<Expression> normalizedAggregationExpressions = new LinkedHashSet<>();
1✔
992
      for (Expression expression : expressionSet) {
1✔
993
        for (Expression aggregationExpression :
994
            ExpressionAnalyzer.searchAggregationExpressions(expression)) {
1✔
995
          Expression normalizedAggregationExpression =
1✔
996
              ExpressionAnalyzer.normalizeExpression(aggregationExpression);
1✔
997
          analyzeExpressionType(analysis, normalizedAggregationExpression);
1✔
998

999
          aggregationExpressions.add(aggregationExpression);
1✔
1000
          normalizedAggregationExpressions.add(normalizedAggregationExpression);
1✔
1001
        }
1✔
1002
      }
1✔
1003
      deviceToOutputExpressions
1✔
1004
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1005
          .addAll(aggregationExpressions);
1✔
1006
      deviceToAggregationExpressions
1✔
1007
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1008
          .addAll(normalizedAggregationExpressions);
1✔
1009
    }
1✔
1010
  }
1✔
1011

1012
  private void analyzeAggregation(Analysis analysis, QueryStatement queryStatement) {
1013
    if (!queryStatement.isAggregationQuery()) {
1✔
1014
      return;
1✔
1015
    }
1016

1017
    if (queryStatement.isGroupByLevel() || queryStatement.isGroupByTag()) {
1✔
1018
      Set<Expression> aggregationExpressions =
×
1019
          analysis.getCrossGroupByExpressions().values().stream()
×
1020
              .flatMap(Set::stream)
×
1021
              .collect(Collectors.toSet());
×
1022
      analysis.setAggregationExpressions(aggregationExpressions);
×
1023
    } else {
×
1024
      Set<Expression> aggregationExpressions = new HashSet<>();
1✔
1025
      for (Expression expression : analysis.getSelectExpressions()) {
1✔
1026
        aggregationExpressions.addAll(ExpressionAnalyzer.searchAggregationExpressions(expression));
1✔
1027
      }
1✔
1028
      if (queryStatement.hasHaving()) {
1✔
1029
        aggregationExpressions.addAll(
1✔
1030
            ExpressionAnalyzer.searchAggregationExpressions(analysis.getHavingExpression()));
1✔
1031
      }
1032
      if (queryStatement.hasOrderByExpression()) {
1✔
1033
        for (Expression expression : analysis.getOrderByExpressions()) {
1✔
1034
          aggregationExpressions.addAll(
1✔
1035
              ExpressionAnalyzer.searchAggregationExpressions(expression));
1✔
1036
        }
1✔
1037
      }
1038
      analysis.setAggregationExpressions(aggregationExpressions);
1✔
1039
    }
1040
  }
1✔
1041

1042
  private void analyzeDeviceToSourceTransform(Analysis analysis, QueryStatement queryStatement) {
1043
    if (queryStatement.isAggregationQuery()) {
1✔
1044
      Map<String, Set<Expression>> deviceToSourceTransformExpressions = new HashMap<>();
1✔
1045

1046
      Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
1047
          analysis.getDeviceToAggregationExpressions();
1✔
1048
      for (Map.Entry<String, Set<Expression>> deviceAggregationExpressionsEntry :
1049
          deviceToAggregationExpressions.entrySet()) {
1✔
1050
        String deviceName = deviceAggregationExpressionsEntry.getKey();
1✔
1051
        Set<Expression> aggregationExpressions = deviceAggregationExpressionsEntry.getValue();
1✔
1052

1053
        Set<Expression> sourceTransformExpressions = new LinkedHashSet<>();
1✔
1054
        for (Expression expression : aggregationExpressions) {
1✔
1055
          // We just process first input Expression of AggregationFunction,
1056
          // keep other input Expressions as origin
1057
          // If AggregationFunction need more than one input series,
1058
          // we need to reconsider the process of it
1059
          sourceTransformExpressions.add(expression.getExpressions().get(0));
1✔
1060
        }
1✔
1061
        if (queryStatement.hasGroupByExpression()) {
1✔
1062
          sourceTransformExpressions.add(analysis.getDeviceToGroupByExpression().get(deviceName));
×
1063
        }
1064
        deviceToSourceTransformExpressions.put(deviceName, sourceTransformExpressions);
1✔
1065
      }
1✔
1066
      analysis.setDeviceToSourceTransformExpressions(deviceToSourceTransformExpressions);
1✔
1067
    } else {
1✔
1068
      updateDeviceToSourceTransformAndOutputExpressions(
1✔
1069
          analysis, analysis.getDeviceToSelectExpressions());
1✔
1070
      if (queryStatement.hasOrderByExpression()) {
1✔
1071
        updateDeviceToSourceTransformAndOutputExpressions(
1✔
1072
            analysis, analysis.getDeviceToOrderByExpressions());
1✔
1073
      }
1074
    }
1075
  }
1✔
1076

1077
  private void updateDeviceToSourceTransformAndOutputExpressions(
1078
      Analysis analysis, Map<String, Set<Expression>> deviceToExpressions) {
1079
    // two maps to be updated
1080
    Map<String, Set<Expression>> deviceToSourceTransformExpressions =
1✔
1081
        analysis.getDeviceToSourceTransformExpressions();
1✔
1082
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
1083
        analysis.getDeviceToOutputExpressions();
1✔
1084

1085
    for (Map.Entry<String, Set<Expression>> deviceExpressionsEntry :
1086
        deviceToExpressions.entrySet()) {
1✔
1087
      String deviceName = deviceExpressionsEntry.getKey();
1✔
1088
      Set<Expression> expressions = deviceExpressionsEntry.getValue();
1✔
1089

1090
      Set<Expression> normalizedExpressions = new LinkedHashSet<>();
1✔
1091
      for (Expression expression : expressions) {
1✔
1092
        Expression normalizedExpression = ExpressionAnalyzer.normalizeExpression(expression);
1✔
1093
        analyzeExpressionType(analysis, normalizedExpression);
1✔
1094

1095
        normalizedExpressions.add(normalizedExpression);
1✔
1096
      }
1✔
1097
      deviceToOutputExpressions
1✔
1098
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1099
          .addAll(expressions);
1✔
1100
      deviceToSourceTransformExpressions
1✔
1101
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1102
          .addAll(normalizedExpressions);
1✔
1103
    }
1✔
1104
  }
1✔
1105

1106
  private void analyzeSourceTransform(Analysis analysis, QueryStatement queryStatement) {
1107
    Set<Expression> sourceTransformExpressions = new HashSet<>();
1✔
1108
    if (queryStatement.isAggregationQuery()) {
1✔
1109
      for (Expression expression : analysis.getAggregationExpressions()) {
1✔
1110
        // for AggregationExpression, only the first Expression of input need to transform
1111
        sourceTransformExpressions.add(expression.getExpressions().get(0));
1✔
1112
      }
1✔
1113
      if (queryStatement.hasGroupByExpression()) {
1✔
1114
        sourceTransformExpressions.add(analysis.getGroupByExpression());
×
1115
      }
1116
    } else {
1117
      sourceTransformExpressions.addAll(analysis.getSelectExpressions());
1✔
1118
      if (queryStatement.hasOrderByExpression()) {
1✔
1119
        sourceTransformExpressions.addAll(analysis.getOrderByExpressions());
1✔
1120
      }
1121
    }
1122
    analysis.setSourceTransformExpressions(sourceTransformExpressions);
1✔
1123
  }
1✔
1124

1125
  private void analyzeDeviceToSource(Analysis analysis, QueryStatement queryStatement) {
1126
    Map<String, Set<Expression>> deviceToSourceExpressions = new HashMap<>();
1✔
1127
    Map<String, Set<Expression>> deviceToSourceTransformExpressions =
1✔
1128
        analysis.getDeviceToSourceTransformExpressions();
1✔
1129
    for (Map.Entry<String, Set<Expression>> deviceSourceTransformExpressionsEntry :
1130
        deviceToSourceTransformExpressions.entrySet()) {
1✔
1131
      String deviceName = deviceSourceTransformExpressionsEntry.getKey();
1✔
1132
      Set<Expression> sourceTransformExpressions = deviceSourceTransformExpressionsEntry.getValue();
1✔
1133

1134
      Set<Expression> sourceExpressions = new LinkedHashSet<>();
1✔
1135
      for (Expression expression : sourceTransformExpressions) {
1✔
1136
        sourceExpressions.addAll(ExpressionAnalyzer.searchSourceExpressions(expression));
1✔
1137
      }
1✔
1138
      deviceToSourceExpressions.put(deviceName, sourceExpressions);
1✔
1139
    }
1✔
1140
    if (queryStatement.hasWhere()) {
1✔
1141
      Map<String, Expression> deviceToWhereExpression = analysis.getDeviceToWhereExpression();
1✔
1142
      for (Map.Entry<String, Expression> deviceWhereExpressionEntry :
1143
          deviceToWhereExpression.entrySet()) {
1✔
1144
        String deviceName = deviceWhereExpressionEntry.getKey();
1✔
1145
        Expression whereExpression = deviceWhereExpressionEntry.getValue();
1✔
1146
        deviceToSourceExpressions
1✔
1147
            .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1148
            .addAll(ExpressionAnalyzer.searchSourceExpressions(whereExpression));
1✔
1149
      }
1✔
1150
    }
1151

1152
    Map<String, List<String>> outputDeviceToQueriedDevicesMap = new LinkedHashMap<>();
1✔
1153
    for (Map.Entry<String, Set<Expression>> deviceSourceExpressionsEntry :
1154
        deviceToSourceExpressions.entrySet()) {
1✔
1155
      Set<Expression> sourceExpressionsUnderDevice = deviceSourceExpressionsEntry.getValue();
1✔
1156
      Set<String> queriedDevices = new HashSet<>();
1✔
1157
      for (Expression expression : sourceExpressionsUnderDevice) {
1✔
1158
        queriedDevices.add(ExpressionAnalyzer.getDeviceNameInSourceExpression(expression));
1✔
1159
      }
1✔
1160
      if (queriedDevices.size() > 1) {
1✔
1161
        throw new SemanticException(
×
1162
            "Cross-device queries are not supported in ALIGN BY DEVICE queries.");
1163
      }
1164
      outputDeviceToQueriedDevicesMap.put(
1✔
1165
          deviceSourceExpressionsEntry.getKey(), new ArrayList<>(queriedDevices));
1✔
1166
    }
1✔
1167

1168
    analysis.setDeviceToSourceExpressions(deviceToSourceExpressions);
1✔
1169
    analysis.setOutputDeviceToQueriedDevicesMap(outputDeviceToQueriedDevicesMap);
1✔
1170
  }
1✔
1171

1172
  private void analyzeSource(Analysis analysis, QueryStatement queryStatement) {
1173
    Set<Expression> sourceExpressions = new HashSet<>();
1✔
1174
    for (Expression expression : analysis.getSourceTransformExpressions()) {
1✔
1175
      sourceExpressions.addAll(ExpressionAnalyzer.searchSourceExpressions(expression));
1✔
1176
    }
1✔
1177
    if (queryStatement.hasWhere()) {
1✔
1178
      sourceExpressions.addAll(
1✔
1179
          ExpressionAnalyzer.searchSourceExpressions(analysis.getWhereExpression()));
1✔
1180
    }
1181
    analysis.setSourceExpressions(sourceExpressions);
1✔
1182
  }
1✔
1183

1184
  private static final String WHERE_WRONG_TYPE_ERROR_MSG =
1185
      "The output type of the expression in WHERE clause should be BOOLEAN, actual data type: %s.";
1186

1187
  private void analyzeDeviceToWhere(
1188
      Analysis analysis,
1189
      QueryStatement queryStatement,
1190
      ISchemaTree schemaTree,
1191
      Set<PartialPath> deviceSet) {
1192
    if (!queryStatement.hasWhere()) {
1✔
1193
      return;
1✔
1194
    }
1195

1196
    Map<String, Expression> deviceToWhereExpression = new HashMap<>();
1✔
1197
    Iterator<PartialPath> deviceIterator = deviceSet.iterator();
1✔
1198
    while (deviceIterator.hasNext()) {
1✔
1199
      PartialPath devicePath = deviceIterator.next();
1✔
1200
      Expression whereExpression;
1201
      try {
1202
        whereExpression =
1✔
1203
            ExpressionAnalyzer.normalizeExpression(
1✔
1204
                analyzeWhereSplitByDevice(queryStatement, devicePath, schemaTree));
1✔
1205
      } catch (MeasurementNotExistException e) {
×
1206
        logger.warn(
×
1207
            "Meets MeasurementNotExistException in analyzeDeviceToWhere when executing align by device, "
1208
                + "error msg: {}",
1209
            e.getMessage());
×
1210
        deviceIterator.remove();
×
1211
        continue;
×
1212
      }
1✔
1213

1214
      TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
1✔
1215
      if (outputType != TSDataType.BOOLEAN) {
1✔
1216
        throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
1217
      }
1218

1219
      deviceToWhereExpression.put(devicePath.getFullPath(), whereExpression);
1✔
1220
    }
1✔
1221
    analysis.setDeviceToWhereExpression(deviceToWhereExpression);
1✔
1222
  }
1✔
1223

1224
  private void analyzeWhere(
1225
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1226
    if (!queryStatement.hasWhere()) {
1✔
1227
      return;
1✔
1228
    }
1229
    List<Expression> conJunctions =
1✔
1230
        ExpressionAnalyzer.bindSchemaForPredicate(
1✔
1231
            queryStatement.getWhereCondition().getPredicate(),
1✔
1232
            queryStatement.getFromComponent().getPrefixPaths(),
1✔
1233
            schemaTree,
1234
            true);
1235
    Expression whereExpression =
1✔
1236
        ExpressionUtils.constructQueryFilter(
1✔
1237
            conJunctions.stream().distinct().collect(Collectors.toList()));
1✔
1238
    whereExpression = ExpressionAnalyzer.normalizeExpression(whereExpression);
1✔
1239
    TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
1✔
1240
    if (outputType != TSDataType.BOOLEAN) {
1✔
1241
      throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
1242
    }
1243
    analysis.setWhereExpression(whereExpression);
1✔
1244
  }
1✔
1245

1246
  private Expression analyzeWhereSplitByDevice(
1247
      QueryStatement queryStatement, PartialPath devicePath, ISchemaTree schemaTree) {
1248
    List<Expression> conJunctions =
1✔
1249
        ExpressionAnalyzer.concatDeviceAndBindSchemaForPredicate(
1✔
1250
            queryStatement.getWhereCondition().getPredicate(), devicePath, schemaTree, true);
1✔
1251
    return ExpressionUtils.constructQueryFilter(
1✔
1252
        conJunctions.stream().distinct().collect(Collectors.toList()));
1✔
1253
  }
1254

1255
  private void analyzeDeviceViewOutput(Analysis analysis, QueryStatement queryStatement) {
1256
    Set<Expression> selectExpressions = analysis.getSelectExpressions();
1✔
1257
    Set<Expression> deviceViewOutputExpressions = new LinkedHashSet<>();
1✔
1258
    if (queryStatement.isAggregationQuery()) {
1✔
1259
      deviceViewOutputExpressions.add(deviceExpression);
1✔
1260
      if (queryStatement.isOutputEndTime()) {
1✔
1261
        deviceViewOutputExpressions.add(endTimeExpression);
×
1262
      }
1263
      for (Expression selectExpression : selectExpressions) {
1✔
1264
        deviceViewOutputExpressions.addAll(
1✔
1265
            ExpressionAnalyzer.searchAggregationExpressions(selectExpression));
1✔
1266
      }
1✔
1267
      if (queryStatement.hasHaving()) {
1✔
1268
        deviceViewOutputExpressions.addAll(
1✔
1269
            ExpressionAnalyzer.searchAggregationExpressions(analysis.getHavingExpression()));
1✔
1270
      }
1271
      if (queryStatement.hasOrderByExpression()) {
1✔
1272
        for (Expression orderByExpression : analysis.getOrderByExpressions()) {
1✔
1273
          deviceViewOutputExpressions.addAll(
1✔
1274
              ExpressionAnalyzer.searchAggregationExpressions(orderByExpression));
1✔
1275
        }
1✔
1276
      }
1277
    } else {
1278
      deviceViewOutputExpressions.addAll(selectExpressions);
1✔
1279
      if (queryStatement.hasOrderByExpression()) {
1✔
1280
        deviceViewOutputExpressions.addAll(analysis.getOrderByExpressions());
1✔
1281
      }
1282
    }
1283
    analysis.setDeviceViewOutputExpressions(deviceViewOutputExpressions);
1✔
1284
    analysis.setDeviceViewSpecialProcess(
1✔
1285
        analyzeDeviceViewSpecialProcess(deviceViewOutputExpressions, queryStatement, analysis));
1✔
1286
  }
1✔
1287

1288
  private boolean analyzeDeviceViewSpecialProcess(
1289
      Set<Expression> deviceViewOutputExpressions,
1290
      QueryStatement queryStatement,
1291
      Analysis analysis) {
1292
    if (queryStatement.isAggregationQuery()
1✔
1293
        || queryStatement.hasWhere()
1✔
1294
            && ExpressionAnalyzer.isDeviceViewNeedSpecialProcess(
1✔
1295
                queryStatement.getWhereCondition().getPredicate(), analysis)) {
1✔
1296
      return true;
1✔
1297
    }
1298
    for (Expression expression : deviceViewOutputExpressions) {
1✔
1299
      if (ExpressionAnalyzer.isDeviceViewNeedSpecialProcess(expression, analysis)) {
1✔
1300
        return true;
1✔
1301
      }
1302
    }
1✔
1303
    return false;
1✔
1304
  }
1305

1306
  private void analyzeDeviceViewInput(Analysis analysis, QueryStatement queryStatement) {
1307
    List<String> deviceViewOutputColumns =
1✔
1308
        analysis.getDeviceViewOutputExpressions().stream()
1✔
1309
            .map(Expression::getOutputSymbol)
1✔
1310
            .collect(Collectors.toList());
1✔
1311

1312
    Map<String, Set<String>> deviceToOutputColumnsMap = new LinkedHashMap<>();
1✔
1313
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
1314
        analysis.getDeviceToOutputExpressions();
1✔
1315
    for (Map.Entry<String, Set<Expression>> deviceOutputExpressionEntry :
1316
        deviceToOutputExpressions.entrySet()) {
1✔
1317
      Set<Expression> outputExpressionsUnderDevice = deviceOutputExpressionEntry.getValue();
1✔
1318
      checkDeviceViewInputUniqueness(outputExpressionsUnderDevice);
1✔
1319

1320
      Set<String> outputColumns = new LinkedHashSet<>();
1✔
1321
      if (queryStatement.isOutputEndTime()) {
1✔
1322
        outputColumns.add(ENDTIME);
×
1323
      }
1324
      for (Expression expression : outputExpressionsUnderDevice) {
1✔
1325
        outputColumns.add(
1✔
1326
            ExpressionAnalyzer.getMeasurementExpression(expression, analysis).getOutputSymbol());
1✔
1327
      }
1✔
1328
      deviceToOutputColumnsMap.put(deviceOutputExpressionEntry.getKey(), outputColumns);
1✔
1329
    }
1✔
1330

1331
    Map<String, List<Integer>> deviceViewInputIndexesMap = new HashMap<>();
1✔
1332
    for (Map.Entry<String, Set<String>> deviceOutputColumnsEntry :
1333
        deviceToOutputColumnsMap.entrySet()) {
1✔
1334
      String deviceName = deviceOutputColumnsEntry.getKey();
1✔
1335
      List<String> outputsUnderDevice = new ArrayList<>(deviceOutputColumnsEntry.getValue());
1✔
1336

1337
      List<Integer> indexes = new ArrayList<>();
1✔
1338
      for (String output : outputsUnderDevice) {
1✔
1339
        int index = deviceViewOutputColumns.indexOf(output);
1✔
1340
        checkState(
1✔
1341
            index >= 1, "output column '%s' is not stored in %s", output, deviceViewOutputColumns);
1342
        indexes.add(index);
1✔
1343
      }
1✔
1344
      deviceViewInputIndexesMap.put(deviceName, indexes);
1✔
1345
    }
1✔
1346
    analysis.setDeviceViewInputIndexesMap(deviceViewInputIndexesMap);
1✔
1347
  }
1✔
1348

1349
  private void checkDeviceViewInputUniqueness(Set<Expression> outputExpressionsUnderDevice) {
1350
    Set<Expression> normalizedOutputExpressionsUnderDevice =
1✔
1351
        outputExpressionsUnderDevice.stream()
1✔
1352
            .map(ExpressionAnalyzer::normalizeExpression)
1✔
1353
            .collect(Collectors.toSet());
1✔
1354
    if (normalizedOutputExpressionsUnderDevice.size() < outputExpressionsUnderDevice.size()) {
1✔
1355
      throw new SemanticException(
×
1356
          "Views or measurement aliases representing the same data source "
1357
              + "cannot be queried concurrently in ALIGN BY DEVICE queries.");
1358
    }
1359
  }
1✔
1360

1361
  private void analyzeOutput(
1362
      Analysis analysis,
1363
      QueryStatement queryStatement,
1364
      List<Pair<Expression, String>> outputExpressions) {
1365
    if (queryStatement.isSelectInto()) {
1✔
1366
      analysis.setRespDatasetHeader(
1✔
1367
          DatasetHeaderFactory.getSelectIntoHeader(queryStatement.isAlignByDevice()));
1✔
1368
      return;
1✔
1369
    }
1370

1371
    boolean isIgnoreTimestamp = queryStatement.isAggregationQuery() && !queryStatement.isGroupBy();
1✔
1372
    List<ColumnHeader> columnHeaders = new ArrayList<>();
1✔
1373
    if (queryStatement.isAlignByDevice()) {
1✔
1374
      columnHeaders.add(new ColumnHeader(DEVICE, TSDataType.TEXT, null));
1✔
1375
    }
1376
    if (queryStatement.isOutputEndTime()) {
1✔
1377
      columnHeaders.add(new ColumnHeader(ENDTIME, TSDataType.INT64, null));
×
1378
    }
1379
    for (Pair<Expression, String> expressionAliasPair : outputExpressions) {
1✔
1380
      columnHeaders.add(
1✔
1381
          new ColumnHeader(
1382
              expressionAliasPair.left.getExpressionString(),
1✔
1383
              analysis.getType(expressionAliasPair.left),
1✔
1384
              expressionAliasPair.right));
1385
    }
1✔
1386
    analysis.setRespDatasetHeader(new DatasetHeader(columnHeaders, isIgnoreTimestamp));
1✔
1387
  }
1✔
1388

1389
  // For last query
1390
  private void analyzeLastOrderBy(Analysis analysis, QueryStatement queryStatement) {
1391
    if (!queryStatement.hasOrderBy()) return;
×
1392

1393
    if (queryStatement.onlyOrderByTimeseries()) {
×
1394
      analysis.setTimeseriesOrderingForLastQuery(
×
1395
          queryStatement.getOrderByComponent().getTimeseriesOrder());
×
1396
    }
1397

1398
    for (SortItem sortItem : queryStatement.getSortItemList()) {
×
1399
      String sortKey = sortItem.getSortKey();
×
1400
      if (!lastQueryColumnNames.contains(sortKey.toUpperCase())) {
×
1401
        throw new SemanticException(
×
1402
            String.format(
×
1403
                "%s in order by clause doesn't exist in the result of last query.", sortKey));
1404
      }
1405
    }
×
1406
  }
×
1407

1408
  private void analyzeOrderBy(
1409
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1410
    if (!queryStatement.hasOrderByExpression()) return;
1✔
1411

1412
    Set<Expression> orderByExpressions = new LinkedHashSet<>();
1✔
1413
    for (Expression expressionForItem : queryStatement.getExpressionSortItemList()) {
1✔
1414
      // Expression in a sortItem only indicates one column
1415
      List<Expression> expressions =
1✔
1416
          ExpressionAnalyzer.bindSchemaForExpression(expressionForItem, schemaTree);
1✔
1417
      if (expressions.isEmpty()) {
1✔
1418
        throw new SemanticException(
×
1419
            String.format(
×
1420
                "%s in order by clause doesn't exist.", expressionForItem.getExpressionString()));
×
1421
      }
1422
      if (expressions.size() > 1) {
1✔
1423
        throw new SemanticException(
×
1424
            String.format(
×
1425
                "%s in order by clause shouldn't refer to more than one timeseries.",
1426
                expressionForItem.getExpressionString()));
×
1427
      }
1428
      expressionForItem = ExpressionAnalyzer.normalizeExpression(expressions.get(0));
1✔
1429
      TSDataType dataType = analyzeExpressionType(analysis, expressionForItem);
1✔
1430
      if (!dataType.isComparable()) {
1✔
1431
        throw new SemanticException(
×
1432
            String.format("The data type of %s is not comparable", dataType));
×
1433
      }
1434
      orderByExpressions.add(expressionForItem);
1✔
1435
    }
1✔
1436
    analysis.setOrderByExpressions(orderByExpressions);
1✔
1437
    queryStatement.updateSortItems(orderByExpressions);
1✔
1438
  }
1✔
1439

1440
  private TSDataType analyzeExpressionType(Analysis analysis, Expression expression) {
1441
    return ExpressionTypeAnalyzer.analyzeExpression(analysis, expression);
1✔
1442
  }
1443

1444
  private void analyzeDeviceToGroupBy(
1445
      Analysis analysis,
1446
      QueryStatement queryStatement,
1447
      ISchemaTree schemaTree,
1448
      Set<PartialPath> deviceSet) {
1449
    if (queryStatement.getGroupByComponent() == null) {
1✔
1450
      return;
1✔
1451
    }
1452
    GroupByComponent groupByComponent = queryStatement.getGroupByComponent();
×
1453
    WindowType windowType = groupByComponent.getWindowType();
×
1454

1455
    Map<String, Expression> deviceToGroupByExpression = new LinkedHashMap<>();
×
1456
    if (queryStatement.hasGroupByExpression()) {
×
1457
      Expression expression = groupByComponent.getControlColumnExpression();
×
1458
      for (PartialPath device : deviceSet) {
×
1459
        List<Expression> groupByExpressionsOfOneDevice =
×
1460
            ExpressionAnalyzer.concatDeviceAndBindSchemaForExpression(
×
1461
                expression, device, schemaTree);
1462

1463
        if (groupByExpressionsOfOneDevice.isEmpty()) {
×
1464
          throw new SemanticException(
×
1465
              String.format("%s in group by clause doesn't exist.", expression));
×
1466
        }
1467
        if (groupByExpressionsOfOneDevice.size() > 1) {
×
1468
          throw new SemanticException(
×
1469
              String.format(
×
1470
                  "%s in group by clause shouldn't refer to more than one timeseries.",
1471
                  expression));
1472
        }
1473
        deviceToGroupByExpression.put(
×
1474
            device.getFullPath(),
×
1475
            ExpressionAnalyzer.normalizeExpression(groupByExpressionsOfOneDevice.get(0)));
×
1476
      }
×
1477
    }
1478

1479
    GroupByParameter groupByParameter;
1480
    switch (windowType) {
×
1481
      case VARIATION_WINDOW:
1482
        double delta = ((GroupByVariationComponent) groupByComponent).getDelta();
×
1483
        for (Expression expression : deviceToGroupByExpression.values()) {
×
1484
          checkGroupByVariationExpressionType(analysis, expression, delta);
×
1485
        }
×
1486
        groupByParameter = new GroupByVariationParameter(groupByComponent.isIgnoringNull(), delta);
×
1487
        analysis.setDeviceToGroupByExpression(deviceToGroupByExpression);
×
1488
        break;
×
1489
      case CONDITION_WINDOW:
1490
        Expression keepExpression =
×
1491
            ((GroupByConditionComponent) groupByComponent).getKeepExpression();
×
1492
        for (Expression expression : deviceToGroupByExpression.values()) {
×
1493
          checkGroupByConditionExpressionType(analysis, expression, keepExpression);
×
1494
        }
×
1495
        groupByParameter =
×
1496
            new GroupByConditionParameter(groupByComponent.isIgnoringNull(), keepExpression);
×
1497
        analysis.setDeviceToGroupByExpression(deviceToGroupByExpression);
×
1498
        break;
×
1499
      case SESSION_WINDOW:
1500
        groupByParameter =
×
1501
            new GroupBySessionParameter(
1502
                ((GroupBySessionComponent) groupByComponent).getTimeInterval());
×
1503
        break;
×
1504
      case COUNT_WINDOW:
1505
        groupByParameter =
×
1506
            new GroupByCountParameter(
1507
                ((GroupByCountComponent) groupByComponent).getCountNumber(),
×
1508
                groupByComponent.isIgnoringNull());
×
1509
        analysis.setDeviceToGroupByExpression(deviceToGroupByExpression);
×
1510
        break;
×
1511
      default:
1512
        throw new UnsupportedOperationException("Unsupported window type");
×
1513
    }
1514
    analysis.setGroupByParameter(groupByParameter);
×
1515
  }
×
1516

1517
  private void analyzeDeviceToOrderBy(
1518
      Analysis analysis,
1519
      QueryStatement queryStatement,
1520
      ISchemaTree schemaTree,
1521
      Set<PartialPath> deviceSet) {
1522
    if (!queryStatement.hasOrderByExpression()) {
1✔
1523
      return;
1✔
1524
    }
1525

1526
    Map<String, Set<Expression>> deviceToOrderByExpressions = new LinkedHashMap<>();
1✔
1527
    Map<String, List<SortItem>> deviceToSortItems = new LinkedHashMap<>();
1✔
1528
    // build the device-view outputColumn for the sortNode above the deviceViewNode
1529
    Set<Expression> deviceViewOrderByExpression = new LinkedHashSet<>();
1✔
1530
    for (PartialPath device : deviceSet) {
1✔
1531
      Set<Expression> orderByExpressionsForOneDevice = new LinkedHashSet<>();
1✔
1532
      for (Expression expressionForItem : queryStatement.getExpressionSortItemList()) {
1✔
1533
        List<Expression> expressions =
1✔
1534
            ExpressionAnalyzer.concatDeviceAndBindSchemaForExpression(
1✔
1535
                expressionForItem, device, schemaTree);
1536
        if (expressions.isEmpty()) {
1✔
1537
          throw new SemanticException(
×
1538
              String.format(
×
1539
                  "%s in order by clause doesn't exist.", expressionForItem.getExpressionString()));
×
1540
        }
1541
        if (expressions.size() > 1) {
1✔
1542
          throw new SemanticException(
×
1543
              String.format(
×
1544
                  "%s in order by clause shouldn't refer to more than one timeseries.",
1545
                  expressionForItem.getExpressionString()));
×
1546
        }
1547
        expressionForItem = expressions.get(0);
1✔
1548
        TSDataType dataType = analyzeExpressionType(analysis, expressionForItem);
1✔
1549
        if (!dataType.isComparable()) {
1✔
1550
          throw new SemanticException(
×
1551
              String.format("The data type of %s is not comparable", dataType));
×
1552
        }
1553

1554
        Expression deviceViewExpression =
1✔
1555
            ExpressionAnalyzer.getMeasurementExpression(expressionForItem, analysis);
1✔
1556
        analyzeExpressionType(analysis, deviceViewExpression);
1✔
1557

1558
        deviceViewOrderByExpression.add(deviceViewExpression);
1✔
1559
        orderByExpressionsForOneDevice.add(expressionForItem);
1✔
1560
      }
1✔
1561
      deviceToSortItems.put(
1✔
1562
          device.getFullPath(), queryStatement.getUpdatedSortItems(orderByExpressionsForOneDevice));
1✔
1563
      deviceToOrderByExpressions.put(device.getFullPath(), orderByExpressionsForOneDevice);
1✔
1564
    }
1✔
1565

1566
    analysis.setOrderByExpressions(deviceViewOrderByExpression);
1✔
1567
    queryStatement.updateSortItems(deviceViewOrderByExpression);
1✔
1568
    analysis.setDeviceToSortItems(deviceToSortItems);
1✔
1569
    analysis.setDeviceToOrderByExpressions(deviceToOrderByExpressions);
1✔
1570
  }
1✔
1571

1572
  private void analyzeGroupBy(
1573
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1574

1575
    if (queryStatement.getGroupByComponent() == null) {
1✔
1576
      return;
1✔
1577
    }
1578
    GroupByComponent groupByComponent = queryStatement.getGroupByComponent();
×
1579
    WindowType windowType = groupByComponent.getWindowType();
×
1580

1581
    Expression groupByExpression = null;
×
1582
    if (queryStatement.hasGroupByExpression()) {
×
1583
      groupByExpression = groupByComponent.getControlColumnExpression();
×
1584
      // Expression in group by variation clause only indicates one column
1585
      List<Expression> expressions =
×
1586
          ExpressionAnalyzer.bindSchemaForExpression(groupByExpression, schemaTree);
×
1587
      if (expressions.isEmpty()) {
×
1588
        throw new SemanticException(
×
1589
            String.format(
×
1590
                "%s in group by clause doesn't exist.", groupByExpression.getExpressionString()));
×
1591
      }
1592
      if (expressions.size() > 1) {
×
1593
        throw new SemanticException(
×
1594
            String.format(
×
1595
                "%s in group by clause shouldn't refer to more than one timeseries.",
1596
                groupByExpression.getExpressionString()));
×
1597
      }
1598
      // Aggregation expression shouldn't exist in group by clause.
1599
      List<Expression> aggregationExpression =
×
1600
          ExpressionAnalyzer.searchAggregationExpressions(expressions.get(0));
×
1601
      if (aggregationExpression != null && !aggregationExpression.isEmpty()) {
×
1602
        throw new SemanticException("Aggregation expression shouldn't exist in group by clause");
×
1603
      }
1604
      groupByExpression = ExpressionAnalyzer.normalizeExpression(expressions.get(0));
×
1605
    }
1606

1607
    if (windowType == WindowType.VARIATION_WINDOW) {
×
1608
      double delta = ((GroupByVariationComponent) groupByComponent).getDelta();
×
1609
      checkGroupByVariationExpressionType(analysis, groupByExpression, delta);
×
1610
      GroupByParameter groupByParameter =
×
1611
          new GroupByVariationParameter(groupByComponent.isIgnoringNull(), delta);
×
1612
      analysis.setGroupByExpression(groupByExpression);
×
1613
      analysis.setGroupByParameter(groupByParameter);
×
1614
    } else if (windowType == WindowType.CONDITION_WINDOW) {
×
1615
      Expression keepExpression =
×
1616
          ((GroupByConditionComponent) groupByComponent).getKeepExpression();
×
1617
      checkGroupByConditionExpressionType(analysis, groupByExpression, keepExpression);
×
1618
      GroupByParameter groupByParameter =
×
1619
          new GroupByConditionParameter(groupByComponent.isIgnoringNull(), keepExpression);
×
1620
      analysis.setGroupByExpression(groupByExpression);
×
1621
      analysis.setGroupByParameter(groupByParameter);
×
1622
    } else if (windowType == WindowType.SESSION_WINDOW) {
×
1623
      long interval = ((GroupBySessionComponent) groupByComponent).getTimeInterval();
×
1624
      GroupByParameter groupByParameter = new GroupBySessionParameter(interval);
×
1625
      analysis.setGroupByParameter(groupByParameter);
×
1626
    } else if (windowType == WindowType.COUNT_WINDOW) {
×
1627
      GroupByParameter groupByParameter =
×
1628
          new GroupByCountParameter(
1629
              ((GroupByCountComponent) groupByComponent).getCountNumber(),
×
1630
              groupByComponent.isIgnoringNull());
×
1631
      analyzeExpressionType(analysis, groupByExpression);
×
1632
      analysis.setGroupByExpression(groupByExpression);
×
1633
      analysis.setGroupByParameter(groupByParameter);
×
1634
    } else {
×
1635
      throw new SemanticException("Unsupported window type");
×
1636
    }
1637
  }
×
1638

1639
  private void checkGroupByVariationExpressionType(
1640
      Analysis analysis, Expression groupByExpression, double delta) {
1641
    TSDataType type = analyzeExpressionType(analysis, groupByExpression);
×
1642
    if (delta != 0 && !type.isNumeric()) {
×
1643
      throw new SemanticException("Only support numeric type when delta != 0");
×
1644
    }
1645
  }
×
1646

1647
  private void checkGroupByConditionExpressionType(
1648
      Analysis analysis, Expression groupByExpression, Expression keepExpression) {
1649
    TSDataType type = analyzeExpressionType(analysis, groupByExpression);
×
1650
    if (type != TSDataType.BOOLEAN) {
×
1651
      throw new SemanticException("Only support boolean type in predict of group by series");
×
1652
    }
1653

1654
    // check keep Expression
1655
    if (keepExpression instanceof CompareBinaryExpression) {
×
1656
      Expression leftExpression = ((CompareBinaryExpression) keepExpression).getLeftExpression();
×
1657
      Expression rightExpression = ((CompareBinaryExpression) keepExpression).getRightExpression();
×
1658
      if (!(leftExpression instanceof TimeSeriesOperand
×
1659
          && leftExpression.getExpressionString().equalsIgnoreCase("keep")
×
1660
          && rightExpression instanceof ConstantOperand)) {
1661
        throw new SemanticException(
×
1662
            String.format(
×
1663
                "Please check the keep condition ([%s]),it need to be a constant or a compare expression constructed by 'keep' and a long number.",
1664
                keepExpression.getExpressionString()));
×
1665
      }
1666
      return;
×
1667
    }
1668
    if (!(keepExpression instanceof ConstantOperand)) {
×
1669
      throw new SemanticException(
×
1670
          String.format(
×
1671
              "Please check the keep condition ([%s]),it need to be a constant or a compare expression constructed by 'keep' and a long number.",
1672
              keepExpression.getExpressionString()));
×
1673
    }
1674
  }
×
1675

1676
  private void analyzeGroupByTime(Analysis analysis, QueryStatement queryStatement) {
1677
    if (!queryStatement.isGroupByTime()) {
1✔
1678
      return;
1✔
1679
    }
1680

1681
    GroupByTimeComponent groupByTimeComponent = queryStatement.getGroupByTimeComponent();
1✔
1682
    if ((groupByTimeComponent.isIntervalByMonth() || groupByTimeComponent.isSlidingStepByMonth())
1✔
1683
        && queryStatement.getResultTimeOrder() == Ordering.DESC) {
×
1684
      throw new SemanticException("Group by month doesn't support order by time desc now.");
×
1685
    }
1686
    if (!queryStatement.isCqQueryBody()
1✔
1687
        && (groupByTimeComponent.getStartTime() == 0 && groupByTimeComponent.getEndTime() == 0)) {
1✔
1688
      throw new SemanticException(
×
1689
          "The query time range should be specified in the GROUP BY TIME clause.");
1690
    }
1691
    analysis.setGroupByTimeParameter(new GroupByTimeParameter(groupByTimeComponent));
1✔
1692
  }
1✔
1693

1694
  private void analyzeFill(Analysis analysis, QueryStatement queryStatement) {
1695
    if (queryStatement.getFillComponent() == null) {
1✔
1696
      return;
1✔
1697
    }
1698

1699
    FillComponent fillComponent = queryStatement.getFillComponent();
1✔
1700
    analysis.setFillDescriptor(
1✔
1701
        new FillDescriptor(fillComponent.getFillPolicy(), fillComponent.getFillValue()));
1✔
1702
  }
1✔
1703

1704
  private void analyzeDataPartition(
1705
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1706
    Set<String> deviceSet = new HashSet<>();
1✔
1707
    if (queryStatement.isAlignByDevice()) {
1✔
1708
      deviceSet =
1✔
1709
          analysis.getOutputDeviceToQueriedDevicesMap().values().stream()
1✔
1710
              .flatMap(List::stream)
1✔
1711
              .collect(Collectors.toSet());
1✔
1712
    } else {
1713
      for (Expression expression : analysis.getSourceExpressions()) {
1✔
1714
        deviceSet.add(ExpressionAnalyzer.getDeviceNameInSourceExpression(expression));
1✔
1715
      }
1✔
1716
    }
1717
    DataPartition dataPartition =
1✔
1718
        fetchDataPartitionByDevices(deviceSet, schemaTree, analysis.getGlobalTimeFilter());
1✔
1719
    analysis.setDataPartitionInfo(dataPartition);
1✔
1720
  }
1✔
1721

1722
  private DataPartition fetchDataPartitionByDevices(
1723
      Set<String> deviceSet, ISchemaTree schemaTree, Filter globalTimeFilter) {
1724
    long startTime = System.nanoTime();
1✔
1725
    try {
1726
      Pair<List<TTimePartitionSlot>, Pair<Boolean, Boolean>> res =
1✔
1727
          getTimePartitionSlotList(globalTimeFilter);
1✔
1728
      // there is no satisfied time range
1729
      if (res.left.isEmpty() && Boolean.FALSE.equals(res.right.left)) {
1✔
1730
        return new DataPartition(
1✔
1731
            Collections.emptyMap(),
1✔
1732
            CONFIG.getSeriesPartitionExecutorClass(),
1✔
1733
            CONFIG.getSeriesPartitionSlotNum());
1✔
1734
      }
1735
      Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap = new HashMap<>();
1✔
1736
      for (String devicePath : deviceSet) {
1✔
1737
        DataPartitionQueryParam queryParam =
1✔
1738
            new DataPartitionQueryParam(devicePath, res.left, res.right.left, res.right.right);
1✔
1739
        sgNameToQueryParamsMap
1✔
1740
            .computeIfAbsent(schemaTree.getBelongedDatabase(devicePath), key -> new ArrayList<>())
1✔
1741
            .add(queryParam);
1✔
1742
      }
1✔
1743

1744
      if (res.right.left || res.right.right) {
1✔
1745
        return partitionFetcher.getDataPartitionWithUnclosedTimeRange(sgNameToQueryParamsMap);
1✔
1746
      } else {
1747
        return partitionFetcher.getDataPartition(sgNameToQueryParamsMap);
1✔
1748
      }
1749
    } finally {
1750
      QueryPlanCostMetricSet.getInstance()
1✔
1751
          .recordPlanCost(PARTITION_FETCHER, System.nanoTime() - startTime);
1✔
1752
    }
1753
  }
1754

1755
  /**
1756
   * get TTimePartitionSlot list about this time filter
1757
   *
1758
   * @return List<TTimePartitionSlot>, if contains (-oo, XXX] time range, res.right.left = true; if
1759
   *     contains [XX, +oo), res.right.right = true
1760
   */
1761
  @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning
1762
  public static Pair<List<TTimePartitionSlot>, Pair<Boolean, Boolean>> getTimePartitionSlotList(
1763
      Filter timeFilter) {
1764
    if (timeFilter == null) {
1✔
1765
      // (-oo, +oo)
1766
      return new Pair<>(Collections.emptyList(), new Pair<>(true, true));
1✔
1767
    }
1768
    List<TimeRange> timeRangeList = timeFilter.getTimeRanges();
1✔
1769
    if (timeRangeList.isEmpty()) {
1✔
1770
      // no satisfied time range
1771
      return new Pair<>(Collections.emptyList(), new Pair<>(false, false));
1✔
1772
    } else if (timeRangeList.size() == 1
1✔
1773
        && (timeRangeList.get(0).getMin() == Long.MIN_VALUE
1✔
1774
            && timeRangeList.get(timeRangeList.size() - 1).getMax() == Long.MAX_VALUE)) {
1✔
1775
      // (-oo, +oo)
1776
      return new Pair<>(Collections.emptyList(), new Pair<>(true, true));
1✔
1777
    }
1778

1779
    boolean needLeftAll;
1780
    boolean needRightAll;
1781
    long startTime;
1782
    long endTime;
1783
    TTimePartitionSlot timePartitionSlot;
1784
    int index = 0;
1✔
1785
    int size = timeRangeList.size();
1✔
1786

1787
    if (timeRangeList.get(0).getMin() == Long.MIN_VALUE) {
1✔
1788
      needLeftAll = true;
1✔
1789
      startTime =
1✔
1790
          (timeRangeList.get(0).getMax() / TimePartitionUtils.timePartitionInterval)
1✔
1791
              * TimePartitionUtils.timePartitionInterval; // included
1792
      endTime = startTime + TimePartitionUtils.timePartitionInterval; // excluded
1✔
1793
      timePartitionSlot = TimePartitionUtils.getTimePartition(timeRangeList.get(0).getMax());
1✔
1794
    } else {
1795
      startTime =
1✔
1796
          (timeRangeList.get(0).getMin() / TimePartitionUtils.timePartitionInterval)
1✔
1797
              * TimePartitionUtils.timePartitionInterval; // included
1798
      endTime = startTime + TimePartitionUtils.timePartitionInterval; // excluded
1✔
1799
      timePartitionSlot = TimePartitionUtils.getTimePartition(timeRangeList.get(0).getMin());
1✔
1800
      needLeftAll = false;
1✔
1801
    }
1802

1803
    if (timeRangeList.get(size - 1).getMax() == Long.MAX_VALUE) {
1✔
1804
      needRightAll = true;
1✔
1805
      size--;
1✔
1806
    } else {
1807
      needRightAll = false;
1✔
1808
    }
1809

1810
    List<TTimePartitionSlot> result = new ArrayList<>();
1✔
1811
    while (index < size) {
1✔
1812
      long curLeft = timeRangeList.get(index).getMin();
1✔
1813
      long curRight = timeRangeList.get(index).getMax();
1✔
1814
      if (curLeft >= endTime) {
1✔
1815
        result.add(timePartitionSlot);
1✔
1816
        // next init
1817
        endTime =
1✔
1818
            (curLeft / TimePartitionUtils.timePartitionInterval + 1)
1819
                * TimePartitionUtils.timePartitionInterval;
1820
        timePartitionSlot = TimePartitionUtils.getTimePartition(curLeft);
1✔
1821
      } else if (curRight >= endTime) {
1✔
1822
        result.add(timePartitionSlot);
1✔
1823
        // next init
1824
        timePartitionSlot = new TTimePartitionSlot(endTime);
1✔
1825
        endTime = endTime + TimePartitionUtils.timePartitionInterval;
1✔
1826
      } else {
1827
        index++;
1✔
1828
      }
1829
    }
1✔
1830
    result.add(timePartitionSlot);
1✔
1831

1832
    if (needRightAll) {
1✔
1833
      TTimePartitionSlot lastTimePartitionSlot =
1✔
1834
          TimePartitionUtils.getTimePartition(timeRangeList.get(timeRangeList.size() - 1).getMin());
1✔
1835
      if (lastTimePartitionSlot.startTime != timePartitionSlot.startTime) {
1✔
1836
        result.add(lastTimePartitionSlot);
×
1837
      }
1838
    }
1839
    return new Pair<>(result, new Pair<>(needLeftAll, needRightAll));
1✔
1840
  }
1841

1842
  private void analyzeInto(
1843
      Analysis analysis,
1844
      QueryStatement queryStatement,
1845
      Set<PartialPath> deviceSet,
1846
      List<Pair<Expression, String>> outputExpressions) {
1847
    if (!queryStatement.isSelectInto()) {
1✔
1848
      return;
1✔
1849
    }
1850
    queryStatement.setOrderByComponent(null);
1✔
1851

1852
    List<PartialPath> sourceDevices = new ArrayList<>(deviceSet);
1✔
1853
    List<Expression> sourceColumns =
1✔
1854
        outputExpressions.stream()
1✔
1855
            .map(Pair::getLeft)
1✔
1856
            .collect(Collectors.toCollection(ArrayList::new));
1✔
1857

1858
    IntoComponent intoComponent = queryStatement.getIntoComponent();
1✔
1859
    intoComponent.validate(sourceDevices, sourceColumns);
1✔
1860

1861
    DeviceViewIntoPathDescriptor deviceViewIntoPathDescriptor = new DeviceViewIntoPathDescriptor();
1✔
1862
    PathPatternTree targetPathTree = new PathPatternTree();
1✔
1863
    IntoComponent.IntoDeviceMeasurementIterator intoDeviceMeasurementIterator =
1✔
1864
        intoComponent.getIntoDeviceMeasurementIterator();
1✔
1865
    for (PartialPath sourceDevice : sourceDevices) {
1✔
1866
      PartialPath deviceTemplate = intoDeviceMeasurementIterator.getDeviceTemplate();
1✔
1867
      boolean isAlignedDevice = intoDeviceMeasurementIterator.isAlignedDevice();
1✔
1868
      PartialPath targetDevice = constructTargetDevice(sourceDevice, deviceTemplate);
1✔
1869
      deviceViewIntoPathDescriptor.specifyDeviceAlignment(targetDevice.toString(), isAlignedDevice);
1✔
1870

1871
      for (Expression sourceColumn : sourceColumns) {
1✔
1872
        String measurementTemplate = intoDeviceMeasurementIterator.getMeasurementTemplate();
1✔
1873
        String targetMeasurement;
1874
        if (sourceColumn instanceof TimeSeriesOperand) {
1✔
1875
          targetMeasurement =
1✔
1876
              constructTargetMeasurement(
1✔
1877
                  sourceDevice.concatNode(sourceColumn.getExpressionString()), measurementTemplate);
1✔
1878
        } else {
1879
          targetMeasurement = measurementTemplate;
1✔
1880
        }
1881
        deviceViewIntoPathDescriptor.specifyTargetDeviceMeasurement(
1✔
1882
            sourceDevice, targetDevice, sourceColumn.getExpressionString(), targetMeasurement);
1✔
1883

1884
        targetPathTree.appendFullPath(targetDevice, targetMeasurement);
1✔
1885
        deviceViewIntoPathDescriptor.recordSourceColumnDataType(
1✔
1886
            sourceColumn.getExpressionString(), analysis.getType(sourceColumn));
1✔
1887

1888
        intoDeviceMeasurementIterator.nextMeasurement();
1✔
1889
      }
1✔
1890

1891
      intoDeviceMeasurementIterator.nextDevice();
1✔
1892
    }
1✔
1893
    deviceViewIntoPathDescriptor.validate();
1✔
1894

1895
    // fetch schema of target paths
1896
    long startTime = System.nanoTime();
1✔
1897
    ISchemaTree targetSchemaTree = schemaFetcher.fetchSchema(targetPathTree, null);
1✔
1898
    QueryPlanCostMetricSet.getInstance()
1✔
1899
        .recordPlanCost(SCHEMA_FETCHER, System.nanoTime() - startTime);
1✔
1900
    deviceViewIntoPathDescriptor.bindType(targetSchemaTree);
1✔
1901

1902
    analysis.setDeviceViewIntoPathDescriptor(deviceViewIntoPathDescriptor);
1✔
1903
  }
1✔
1904

1905
  private void analyzeInto(
1906
      Analysis analysis,
1907
      QueryStatement queryStatement,
1908
      List<Pair<Expression, String>> outputExpressions) {
1909
    if (!queryStatement.isSelectInto()) {
1✔
1910
      return;
1✔
1911
    }
1912
    queryStatement.setOrderByComponent(null);
1✔
1913

1914
    List<Expression> sourceColumns =
1✔
1915
        outputExpressions.stream()
1✔
1916
            .map(Pair::getLeft)
1✔
1917
            .collect(Collectors.toCollection(ArrayList::new));
1✔
1918

1919
    IntoComponent intoComponent = queryStatement.getIntoComponent();
1✔
1920
    intoComponent.validate(sourceColumns);
1✔
1921

1922
    IntoPathDescriptor intoPathDescriptor = new IntoPathDescriptor();
1✔
1923
    PathPatternTree targetPathTree = new PathPatternTree();
1✔
1924
    IntoComponent.IntoPathIterator intoPathIterator = intoComponent.getIntoPathIterator();
1✔
1925
    for (Pair<Expression, String> pair : outputExpressions) {
1✔
1926
      Expression sourceExpression = pair.left;
1✔
1927
      String viewPath = pair.right;
1✔
1928
      PartialPath deviceTemplate = intoPathIterator.getDeviceTemplate();
1✔
1929
      String measurementTemplate = intoPathIterator.getMeasurementTemplate();
1✔
1930
      boolean isAlignedDevice = intoPathIterator.isAlignedDevice();
1✔
1931

1932
      PartialPath sourcePath;
1933
      String sourceColumn = sourceExpression.getExpressionString();
1✔
1934
      PartialPath targetPath;
1935
      if (sourceExpression instanceof TimeSeriesOperand) {
1✔
1936
        if (viewPath != null) {
1✔
1937
          try {
1938
            sourcePath = new PartialPath(viewPath);
×
1939
          } catch (IllegalPathException e) {
×
1940
            throw new SemanticException(
×
1941
                String.format(
×
1942
                    "View path %s of source column %s is illegal path", viewPath, sourceColumn));
1943
          }
×
1944
        } else {
1945
          sourcePath = ((TimeSeriesOperand) sourceExpression).getPath();
1✔
1946
        }
1947
        targetPath = constructTargetPath(sourcePath, deviceTemplate, measurementTemplate);
1✔
1948
      } else {
1949
        targetPath = deviceTemplate.concatNode(measurementTemplate);
1✔
1950
      }
1951
      intoPathDescriptor.specifyTargetPath(sourceColumn, viewPath, targetPath);
1✔
1952
      intoPathDescriptor.specifyDeviceAlignment(
1✔
1953
          targetPath.getDevicePath().toString(), isAlignedDevice);
1✔
1954

1955
      targetPathTree.appendFullPath(targetPath);
1✔
1956
      intoPathDescriptor.recordSourceColumnDataType(
1✔
1957
          sourceColumn, analysis.getType(sourceExpression));
1✔
1958

1959
      intoPathIterator.next();
1✔
1960
    }
1✔
1961
    intoPathDescriptor.validate();
1✔
1962

1963
    // fetch schema of target paths
1964
    long startTime = System.nanoTime();
1✔
1965
    ISchemaTree targetSchemaTree = schemaFetcher.fetchSchema(targetPathTree, null);
1✔
1966
    updateSchemaTreeByViews(analysis, targetSchemaTree);
1✔
1967
    QueryPlanCostMetricSet.getInstance()
1✔
1968
        .recordPlanCost(SCHEMA_FETCHER, System.nanoTime() - startTime);
1✔
1969
    intoPathDescriptor.bindType(targetSchemaTree);
1✔
1970

1971
    analysis.setIntoPathDescriptor(intoPathDescriptor);
1✔
1972
  }
1✔
1973

1974
  /**
1975
   * Check datatype consistency in ALIGN BY DEVICE.
1976
   *
1977
   * <p>an inconsistent example: select s0 from root.sg1.d1, root.sg1.d2 align by device, return
1978
   * false while root.sg1.d1.s0 is INT32 and root.sg1.d2.s0 is FLOAT.
1979
   */
1980
  private void checkDataTypeConsistencyInAlignByDevice(
1981
      Analysis analysis, List<Expression> expressions) {
1982
    TSDataType checkedDataType = analysis.getType(expressions.get(0));
1✔
1983
    for (Expression expression : expressions) {
1✔
1984
      if (analysis.getType(expression) != checkedDataType) {
1✔
1985
        throw new SemanticException(
×
1986
            "ALIGN BY DEVICE: the data types of the same measurement column should be the same across devices.");
1987
      }
1988
    }
1✔
1989
  }
1✔
1990

1991
  private void checkAliasUniqueness(String alias, Set<String> aliasSet) {
1992
    if (alias != null) {
1✔
1993
      if (aliasSet.contains(alias)) {
1✔
1994
        throw new SemanticException(
1✔
1995
            String.format("alias '%s' can only be matched with one time series", alias));
1✔
1996
      }
1997
      aliasSet.add(alias);
1✔
1998
    }
1999
  }
1✔
2000

2001
  private void checkAliasUniqueness(
2002
      String alias, Map<Expression, Map<String, Expression>> measurementToDeviceSelectExpressions) {
2003
    if (alias != null && measurementToDeviceSelectExpressions.keySet().size() > 1) {
1✔
2004
      throw new SemanticException(
×
2005
          String.format("alias '%s' can only be matched with one time series", alias));
×
2006
    }
2007
  }
1✔
2008

2009
  @Override
2010
  public Analysis visitInsert(InsertStatement insertStatement, MPPQueryContext context) {
2011
    context.setQueryType(QueryType.WRITE);
1✔
2012
    insertStatement.semanticCheck();
1✔
2013
    long[] timeArray = insertStatement.getTimes();
1✔
2014
    PartialPath devicePath = insertStatement.getDevice();
1✔
2015
    String[] measurementList = insertStatement.getMeasurementList();
1✔
2016
    if (timeArray.length == 1) {
1✔
2017
      // construct insert row statement
2018
      InsertRowStatement insertRowStatement = new InsertRowStatement();
×
2019
      insertRowStatement.setDevicePath(devicePath);
×
2020
      insertRowStatement.setTime(timeArray[0]);
×
2021
      insertRowStatement.setMeasurements(measurementList);
×
2022
      insertRowStatement.setDataTypes(new TSDataType[measurementList.length]);
×
2023
      Object[] values = new Object[measurementList.length];
×
2024
      System.arraycopy(insertStatement.getValuesList().get(0), 0, values, 0, values.length);
×
2025
      insertRowStatement.setValues(values);
×
2026
      insertRowStatement.setNeedInferType(true);
×
2027
      insertRowStatement.setAligned(insertStatement.isAligned());
×
2028
      return insertRowStatement.accept(this, context);
×
2029
    } else {
2030
      // construct insert rows statement
2031
      // construct insert statement
2032
      InsertRowsOfOneDeviceStatement insertRowsOfOneDeviceStatement =
1✔
2033
          new InsertRowsOfOneDeviceStatement();
2034
      List<InsertRowStatement> insertRowStatementList = new ArrayList<>();
1✔
2035
      for (int i = 0; i < timeArray.length; i++) {
1✔
2036
        InsertRowStatement statement = new InsertRowStatement();
1✔
2037
        statement.setDevicePath(devicePath);
1✔
2038
        String[] measurements = new String[measurementList.length];
1✔
2039
        System.arraycopy(measurementList, 0, measurements, 0, measurements.length);
1✔
2040
        statement.setMeasurements(measurements);
1✔
2041
        statement.setTime(timeArray[i]);
1✔
2042
        TSDataType[] dataTypes = new TSDataType[measurementList.length];
1✔
2043
        statement.setDataTypes(dataTypes);
1✔
2044
        Object[] values = new Object[measurementList.length];
1✔
2045
        System.arraycopy(insertStatement.getValuesList().get(i), 0, values, 0, values.length);
1✔
2046
        statement.setValues(values);
1✔
2047
        statement.setAligned(insertStatement.isAligned());
1✔
2048
        statement.setNeedInferType(true);
1✔
2049
        insertRowStatementList.add(statement);
1✔
2050
      }
2051
      insertRowsOfOneDeviceStatement.setInsertRowStatementList(insertRowStatementList);
1✔
2052
      return insertRowsOfOneDeviceStatement.accept(this, context);
1✔
2053
    }
2054
  }
2055

2056
  @Override
2057
  public Analysis visitCreateTimeseries(
2058
      CreateTimeSeriesStatement createTimeSeriesStatement, MPPQueryContext context) {
2059
    context.setQueryType(QueryType.WRITE);
1✔
2060
    if (createTimeSeriesStatement.getPath().getNodeLength() < 3) {
1✔
2061
      throw new SemanticException(
×
2062
          new IllegalPathException(createTimeSeriesStatement.getPath().getFullPath()));
×
2063
    }
2064
    analyzeSchemaProps(createTimeSeriesStatement.getProps());
1✔
2065
    if (createTimeSeriesStatement.getTags() != null
1✔
2066
        && !createTimeSeriesStatement.getTags().isEmpty()
1✔
2067
        && createTimeSeriesStatement.getAttributes() != null
1✔
2068
        && !createTimeSeriesStatement.getAttributes().isEmpty()) {
1✔
2069
      for (String tagKey : createTimeSeriesStatement.getTags().keySet()) {
1✔
2070
        if (createTimeSeriesStatement.getAttributes().containsKey(tagKey)) {
1✔
2071
          throw new SemanticException(
1✔
2072
              String.format("Tag and attribute shouldn't have the same property key [%s]", tagKey));
1✔
2073
        }
2074
      }
×
2075
    }
2076

2077
    Analysis analysis = new Analysis();
×
2078
    analysis.setStatement(createTimeSeriesStatement);
×
2079

2080
    checkIsTemplateCompatible(
×
2081
        createTimeSeriesStatement.getPath(), createTimeSeriesStatement.getAlias());
×
2082

2083
    PathPatternTree patternTree = new PathPatternTree();
×
2084
    patternTree.appendFullPath(createTimeSeriesStatement.getPath());
×
2085
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2086
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2087
    return analysis;
×
2088
  }
2089

2090
  private void checkIsTemplateCompatible(PartialPath timeseriesPath, String alias) {
2091
    Pair<Template, PartialPath> templateInfo =
×
2092
        schemaFetcher.checkTemplateSetAndPreSetInfo(timeseriesPath, alias);
×
2093
    if (templateInfo != null) {
×
2094
      throw new SemanticException(
×
2095
          new TemplateIncompatibleException(
2096
              timeseriesPath.getFullPath(), templateInfo.left.getName(), templateInfo.right));
×
2097
    }
2098
  }
×
2099

2100
  private void checkIsTemplateCompatible(
2101
      PartialPath devicePath, List<String> measurements, List<String> aliasList) {
2102
    for (int i = 0; i < measurements.size(); i++) {
×
2103
      Pair<Template, PartialPath> templateInfo =
×
2104
          schemaFetcher.checkTemplateSetAndPreSetInfo(
×
2105
              devicePath.concatNode(measurements.get(i)),
×
2106
              aliasList == null ? null : aliasList.get(i));
×
2107
      if (templateInfo != null) {
×
2108
        throw new SemanticException(
×
2109
            new TemplateIncompatibleException(
2110
                devicePath.getFullPath() + measurements,
×
2111
                templateInfo.left.getName(),
×
2112
                templateInfo.right));
2113
      }
2114
    }
2115
  }
×
2116

2117
  private void analyzeSchemaProps(Map<String, String> props) {
2118
    if (props == null || props.isEmpty()) {
1✔
2119
      return;
1✔
2120
    }
2121
    Map<String, String> caseChangeMap = new HashMap<>();
×
2122
    for (String key : props.keySet()) {
×
2123
      caseChangeMap.put(key.toLowerCase(Locale.ROOT), key);
×
2124
    }
×
2125
    for (Map.Entry<String, String> caseChangeEntry : caseChangeMap.entrySet()) {
×
2126
      String lowerCaseKey = caseChangeEntry.getKey();
×
2127
      if (!ALLOWED_SCHEMA_PROPS.contains(lowerCaseKey)) {
×
2128
        throw new SemanticException(
×
2129
            new MetadataException(
2130
                String.format("%s is not a legal prop.", caseChangeEntry.getValue())));
×
2131
      }
2132
      props.put(lowerCaseKey, props.remove(caseChangeEntry.getValue()));
×
2133
    }
×
2134
    if (props.containsKey(DEADBAND)) {
×
2135
      props.put(LOSS, props.remove(DEADBAND));
×
2136
    }
2137
  }
×
2138

2139
  private void analyzeSchemaProps(List<Map<String, String>> propsList) {
2140
    if (propsList == null) {
×
2141
      return;
×
2142
    }
2143
    for (Map<String, String> props : propsList) {
×
2144
      analyzeSchemaProps(props);
×
2145
    }
×
2146
  }
×
2147

2148
  @Override
2149
  public Analysis visitCreateAlignedTimeseries(
2150
      CreateAlignedTimeSeriesStatement createAlignedTimeSeriesStatement, MPPQueryContext context) {
2151
    context.setQueryType(QueryType.WRITE);
1✔
2152
    if (createAlignedTimeSeriesStatement.getDevicePath().getNodeLength() < 2) {
1✔
2153
      throw new SemanticException(
×
2154
          new IllegalPathException(createAlignedTimeSeriesStatement.getDevicePath().getFullPath()));
×
2155
    }
2156
    List<String> measurements = createAlignedTimeSeriesStatement.getMeasurements();
1✔
2157
    Set<String> measurementsSet = new HashSet<>(measurements);
1✔
2158
    if (measurementsSet.size() < measurements.size()) {
1✔
2159
      throw new SemanticException(
1✔
2160
          "Measurement under an aligned device is not allowed to have the same measurement name");
2161
    }
2162

2163
    Analysis analysis = new Analysis();
×
2164
    analysis.setStatement(createAlignedTimeSeriesStatement);
×
2165

2166
    checkIsTemplateCompatible(
×
2167
        createAlignedTimeSeriesStatement.getDevicePath(),
×
2168
        createAlignedTimeSeriesStatement.getMeasurements(),
×
2169
        createAlignedTimeSeriesStatement.getAliasList());
×
2170

2171
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2172
    for (String measurement : createAlignedTimeSeriesStatement.getMeasurements()) {
×
2173
      pathPatternTree.appendFullPath(createAlignedTimeSeriesStatement.getDevicePath(), measurement);
×
2174
    }
×
2175

2176
    SchemaPartition schemaPartitionInfo;
2177
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2178
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2179
    return analysis;
×
2180
  }
2181

2182
  @Override
2183
  public Analysis visitInternalCreateTimeseries(
2184
      InternalCreateTimeSeriesStatement internalCreateTimeSeriesStatement,
2185
      MPPQueryContext context) {
2186
    context.setQueryType(QueryType.WRITE);
×
2187

2188
    Analysis analysis = new Analysis();
×
2189
    analysis.setStatement(internalCreateTimeSeriesStatement);
×
2190

2191
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2192
    for (String measurement : internalCreateTimeSeriesStatement.getMeasurements()) {
×
2193
      pathPatternTree.appendFullPath(
×
2194
          internalCreateTimeSeriesStatement.getDevicePath(), measurement);
×
2195
    }
×
2196

2197
    SchemaPartition schemaPartitionInfo;
2198
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2199
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2200
    return analysis;
×
2201
  }
2202

2203
  @Override
2204
  public Analysis visitInternalCreateMultiTimeSeries(
2205
      InternalCreateMultiTimeSeriesStatement internalCreateMultiTimeSeriesStatement,
2206
      MPPQueryContext context) {
2207
    context.setQueryType(QueryType.WRITE);
×
2208

2209
    Analysis analysis = new Analysis();
×
2210
    analysis.setStatement(internalCreateMultiTimeSeriesStatement);
×
2211

2212
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2213
    for (PartialPath devicePath : internalCreateMultiTimeSeriesStatement.getDeviceMap().keySet()) {
×
2214
      pathPatternTree.appendFullPath(devicePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
2215
    }
×
2216

2217
    SchemaPartition schemaPartitionInfo;
2218
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2219
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2220
    return analysis;
×
2221
  }
2222

2223
  @Override
2224
  public Analysis visitCreateMultiTimeseries(
2225
      CreateMultiTimeSeriesStatement createMultiTimeSeriesStatement, MPPQueryContext context) {
2226
    context.setQueryType(QueryType.WRITE);
×
2227
    Analysis analysis = new Analysis();
×
2228
    analysis.setStatement(createMultiTimeSeriesStatement);
×
2229

2230
    analyzeSchemaProps(createMultiTimeSeriesStatement.getPropsList());
×
2231

2232
    List<PartialPath> timeseriesPathList = createMultiTimeSeriesStatement.getPaths();
×
2233
    List<String> aliasList = createMultiTimeSeriesStatement.getAliasList();
×
2234
    for (int i = 0; i < timeseriesPathList.size(); i++) {
×
2235
      checkIsTemplateCompatible(
×
2236
          timeseriesPathList.get(i), aliasList == null ? null : aliasList.get(i));
×
2237
    }
2238

2239
    PathPatternTree patternTree = new PathPatternTree();
×
2240
    for (PartialPath path : createMultiTimeSeriesStatement.getPaths()) {
×
2241
      patternTree.appendFullPath(path);
×
2242
    }
×
2243
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2244
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2245
    return analysis;
×
2246
  }
2247

2248
  @Override
2249
  public Analysis visitAlterTimeseries(
2250
      AlterTimeSeriesStatement alterTimeSeriesStatement, MPPQueryContext context) {
2251
    context.setQueryType(QueryType.WRITE);
×
2252
    Analysis analysis = new Analysis();
×
2253
    analysis.setStatement(alterTimeSeriesStatement);
×
2254

2255
    Pair<Template, PartialPath> templateInfo =
×
2256
        schemaFetcher.checkTemplateSetAndPreSetInfo(
×
2257
            alterTimeSeriesStatement.getPath(), alterTimeSeriesStatement.getAlias());
×
2258
    if (templateInfo != null) {
×
2259
      throw new RuntimeException(
×
2260
          new TemplateIncompatibleException(
2261
              String.format(
×
2262
                  "Cannot alter template timeseries [%s] since schema template [%s] already set on path [%s].",
2263
                  alterTimeSeriesStatement.getPath().getFullPath(),
×
2264
                  templateInfo.left.getName(),
×
2265
                  templateInfo.right)));
2266
    }
2267

2268
    PathPatternTree patternTree = new PathPatternTree();
×
2269
    patternTree.appendFullPath(alterTimeSeriesStatement.getPath());
×
2270
    SchemaPartition schemaPartitionInfo;
2271
    schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2272
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2273
    return analysis;
×
2274
  }
2275

2276
  @Override
2277
  public Analysis visitInsertTablet(
2278
      InsertTabletStatement insertTabletStatement, MPPQueryContext context) {
2279
    context.setQueryType(QueryType.WRITE);
×
2280
    Analysis analysis = new Analysis();
×
2281
    validateSchema(analysis, insertTabletStatement, context);
×
2282
    InsertBaseStatement realStatement = removeLogicalView(analysis, insertTabletStatement);
×
2283
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2284
      return analysis;
×
2285
    }
2286
    analysis.setStatement(realStatement);
×
2287

2288
    if (realStatement instanceof InsertTabletStatement) {
×
2289
      InsertTabletStatement realInsertTabletStatement = (InsertTabletStatement) realStatement;
×
2290
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2291
      dataPartitionQueryParam.setDevicePath(
×
2292
          realInsertTabletStatement.getDevicePath().getFullPath());
×
2293
      dataPartitionQueryParam.setTimePartitionSlotList(
×
2294
          realInsertTabletStatement.getTimePartitionSlots());
×
2295

2296
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
×
2297
    } else {
2298
      return computeAnalysisForMultiTablets(analysis, (InsertMultiTabletsStatement) realStatement);
×
2299
    }
2300
  }
2301

2302
  @Override
2303
  public Analysis visitInsertRow(InsertRowStatement insertRowStatement, MPPQueryContext context) {
2304
    context.setQueryType(QueryType.WRITE);
×
2305
    Analysis analysis = new Analysis();
×
2306
    validateSchema(analysis, insertRowStatement, context);
×
2307
    InsertBaseStatement realInsertStatement = removeLogicalView(analysis, insertRowStatement);
×
2308
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2309
      return analysis;
×
2310
    }
2311
    analysis.setStatement(realInsertStatement);
×
2312

2313
    if (realInsertStatement instanceof InsertRowStatement) {
×
2314
      InsertRowStatement realInsertRowStatement = (InsertRowStatement) realInsertStatement;
×
2315
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2316
      dataPartitionQueryParam.setDevicePath(realInsertRowStatement.getDevicePath().getFullPath());
×
2317
      dataPartitionQueryParam.setTimePartitionSlotList(
×
2318
          Collections.singletonList(realInsertRowStatement.getTimePartitionSlot()));
×
2319

2320
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
×
2321
    } else {
2322
      return computeAnalysisForInsertRows(analysis, (InsertRowsStatement) realInsertStatement);
×
2323
    }
2324
  }
2325

2326
  private Analysis computeAnalysisForInsertRows(
2327
      Analysis analysis, InsertRowsStatement insertRowsStatement) {
2328
    Map<String, Set<TTimePartitionSlot>> dataPartitionQueryParamMap = new HashMap<>();
×
2329
    for (InsertRowStatement insertRowStatement : insertRowsStatement.getInsertRowStatementList()) {
×
2330
      Set<TTimePartitionSlot> timePartitionSlotSet =
×
2331
          dataPartitionQueryParamMap.computeIfAbsent(
×
2332
              insertRowStatement.getDevicePath().getFullPath(), k -> new HashSet<>());
×
2333
      timePartitionSlotSet.add(insertRowStatement.getTimePartitionSlot());
×
2334
    }
×
2335

2336
    List<DataPartitionQueryParam> dataPartitionQueryParams = new ArrayList<>();
×
2337
    for (Map.Entry<String, Set<TTimePartitionSlot>> entry : dataPartitionQueryParamMap.entrySet()) {
×
2338
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2339
      dataPartitionQueryParam.setDevicePath(entry.getKey());
×
2340
      dataPartitionQueryParam.setTimePartitionSlotList(new ArrayList<>(entry.getValue()));
×
2341
      dataPartitionQueryParams.add(dataPartitionQueryParam);
×
2342
    }
×
2343

2344
    return getAnalysisForWriting(analysis, dataPartitionQueryParams);
×
2345
  }
2346

2347
  @Override
2348
  public Analysis visitInsertRows(
2349
      InsertRowsStatement insertRowsStatement, MPPQueryContext context) {
2350
    context.setQueryType(QueryType.WRITE);
×
2351
    Analysis analysis = new Analysis();
×
2352
    validateSchema(analysis, insertRowsStatement, context);
×
2353
    InsertRowsStatement realInsertRowsStatement =
×
2354
        (InsertRowsStatement) removeLogicalView(analysis, insertRowsStatement);
×
2355
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2356
      return analysis;
×
2357
    }
2358
    analysis.setStatement(realInsertRowsStatement);
×
2359

2360
    return computeAnalysisForInsertRows(analysis, realInsertRowsStatement);
×
2361
  }
2362

2363
  private Analysis computeAnalysisForMultiTablets(
2364
      Analysis analysis, InsertMultiTabletsStatement insertMultiTabletsStatement) {
2365
    Map<String, Set<TTimePartitionSlot>> dataPartitionQueryParamMap = new HashMap<>();
×
2366
    for (InsertTabletStatement insertTabletStatement :
2367
        insertMultiTabletsStatement.getInsertTabletStatementList()) {
×
2368
      Set<TTimePartitionSlot> timePartitionSlotSet =
×
2369
          dataPartitionQueryParamMap.computeIfAbsent(
×
2370
              insertTabletStatement.getDevicePath().getFullPath(), k -> new HashSet<>());
×
2371
      timePartitionSlotSet.addAll(insertTabletStatement.getTimePartitionSlots());
×
2372
    }
×
2373

2374
    List<DataPartitionQueryParam> dataPartitionQueryParams = new ArrayList<>();
×
2375
    for (Map.Entry<String, Set<TTimePartitionSlot>> entry : dataPartitionQueryParamMap.entrySet()) {
×
2376
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2377
      dataPartitionQueryParam.setDevicePath(entry.getKey());
×
2378
      dataPartitionQueryParam.setTimePartitionSlotList(new ArrayList<>(entry.getValue()));
×
2379
      dataPartitionQueryParams.add(dataPartitionQueryParam);
×
2380
    }
×
2381

2382
    return getAnalysisForWriting(analysis, dataPartitionQueryParams);
×
2383
  }
2384

2385
  @Override
2386
  public Analysis visitInsertMultiTablets(
2387
      InsertMultiTabletsStatement insertMultiTabletsStatement, MPPQueryContext context) {
2388
    context.setQueryType(QueryType.WRITE);
×
2389
    Analysis analysis = new Analysis();
×
2390
    validateSchema(analysis, insertMultiTabletsStatement, context);
×
2391
    InsertMultiTabletsStatement realStatement =
×
2392
        (InsertMultiTabletsStatement) removeLogicalView(analysis, insertMultiTabletsStatement);
×
2393
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2394
      return analysis;
×
2395
    }
2396
    analysis.setStatement(realStatement);
×
2397

2398
    return computeAnalysisForMultiTablets(analysis, realStatement);
×
2399
  }
2400

2401
  @Override
2402
  public Analysis visitInsertRowsOfOneDevice(
2403
      InsertRowsOfOneDeviceStatement insertRowsOfOneDeviceStatement, MPPQueryContext context) {
2404
    context.setQueryType(QueryType.WRITE);
1✔
2405
    Analysis analysis = new Analysis();
1✔
2406
    validateSchema(analysis, insertRowsOfOneDeviceStatement, context);
1✔
2407
    InsertBaseStatement realInsertStatement =
1✔
2408
        removeLogicalView(analysis, insertRowsOfOneDeviceStatement);
1✔
2409
    if (analysis.isFinishQueryAfterAnalyze()) {
1✔
2410
      return analysis;
×
2411
    }
2412
    analysis.setStatement(realInsertStatement);
1✔
2413

2414
    if (realInsertStatement instanceof InsertRowsOfOneDeviceStatement) {
1✔
2415
      InsertRowsOfOneDeviceStatement realStatement =
1✔
2416
          (InsertRowsOfOneDeviceStatement) realInsertStatement;
2417
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
1✔
2418
      dataPartitionQueryParam.setDevicePath(realStatement.getDevicePath().getFullPath());
1✔
2419
      dataPartitionQueryParam.setTimePartitionSlotList(realStatement.getTimePartitionSlots());
1✔
2420

2421
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
1✔
2422
    } else {
2423
      return computeAnalysisForInsertRows(analysis, (InsertRowsStatement) realInsertStatement);
×
2424
    }
2425
  }
2426

2427
  private void validateSchema(
2428
      Analysis analysis, InsertBaseStatement insertStatement, MPPQueryContext context) {
2429
    final long startTime = System.nanoTime();
1✔
2430
    try {
2431
      SchemaValidator.validate(schemaFetcher, insertStatement, context);
1✔
2432
    } catch (SemanticException e) {
×
2433
      analysis.setFinishQueryAfterAnalyze(true);
×
2434
      if (e.getCause() instanceof IoTDBException) {
×
2435
        IoTDBException exception = (IoTDBException) e.getCause();
×
2436
        analysis.setFailStatus(
×
2437
            RpcUtils.getStatus(exception.getErrorCode(), exception.getMessage()));
×
2438
      } else {
×
2439
        analysis.setFailStatus(RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage()));
×
2440
      }
2441
    } finally {
2442
      PERFORMANCE_OVERVIEW_METRICS.recordScheduleSchemaValidateCost(System.nanoTime() - startTime);
1✔
2443
    }
2444
    boolean hasFailedMeasurement = insertStatement.hasFailedMeasurements();
1✔
2445
    String partialInsertMessage;
2446
    if (hasFailedMeasurement) {
1✔
2447
      partialInsertMessage =
×
2448
          String.format(
×
2449
              "Fail to insert measurements %s caused by %s",
2450
              insertStatement.getFailedMeasurements(), insertStatement.getFailedMessages());
×
2451
      logger.warn(partialInsertMessage);
×
2452
      analysis.setFailStatus(
×
2453
          RpcUtils.getStatus(TSStatusCode.METADATA_ERROR.getStatusCode(), partialInsertMessage));
×
2454
    }
2455
  }
1✔
2456

2457
  private InsertBaseStatement removeLogicalView(
2458
      Analysis analysis, InsertBaseStatement insertBaseStatement) {
2459
    try {
2460
      return insertBaseStatement.removeLogicalView();
1✔
2461
    } catch (SemanticException e) {
×
2462
      analysis.setFinishQueryAfterAnalyze(true);
×
2463
      if (e.getCause() instanceof IoTDBException) {
×
2464
        IoTDBException exception = (IoTDBException) e.getCause();
×
2465
        analysis.setFailStatus(
×
2466
            RpcUtils.getStatus(exception.getErrorCode(), exception.getMessage()));
×
2467
      } else {
×
2468
        analysis.setFailStatus(RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage()));
×
2469
      }
2470
      return insertBaseStatement;
×
2471
    }
2472
  }
2473

2474
  @Override
2475
  public Analysis visitLoadFile(LoadTsFileStatement loadTsFileStatement, MPPQueryContext context) {
2476
    return new LoadTsfileAnalyzer(loadTsFileStatement, context, partitionFetcher, schemaFetcher)
×
2477
        .analyzeFileByFile();
×
2478
  }
2479

2480
  /** get analysis according to statement and params */
2481
  private Analysis getAnalysisForWriting(
2482
      Analysis analysis, List<DataPartitionQueryParam> dataPartitionQueryParams) {
2483

2484
    DataPartition dataPartition =
1✔
2485
        partitionFetcher.getOrCreateDataPartition(dataPartitionQueryParams);
1✔
2486
    if (dataPartition.isEmpty()) {
1✔
2487
      analysis.setFinishQueryAfterAnalyze(true);
×
2488
      analysis.setFailStatus(
×
2489
          RpcUtils.getStatus(
×
2490
              TSStatusCode.DATABASE_NOT_EXIST.getStatusCode(),
×
2491
              "Database not exists and failed to create automatically "
2492
                  + "because enable_auto_create_schema is FALSE."));
2493
    }
2494
    analysis.setDataPartitionInfo(dataPartition);
1✔
2495
    return analysis;
1✔
2496
  }
2497

2498
  @Override
2499
  public Analysis visitShowTimeSeries(
2500
      ShowTimeSeriesStatement showTimeSeriesStatement, MPPQueryContext context) {
2501
    Analysis analysis = new Analysis();
×
2502
    analysis.setStatement(showTimeSeriesStatement);
×
2503

2504
    PathPatternTree patternTree = new PathPatternTree();
×
2505
    patternTree.appendPathPattern(showTimeSeriesStatement.getPathPattern());
×
2506
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2507
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2508

2509
    Map<Integer, Template> templateMap =
×
2510
        schemaFetcher.checkAllRelatedTemplate(showTimeSeriesStatement.getPathPattern());
×
2511
    analysis.setRelatedTemplateInfo(templateMap);
×
2512

2513
    if (showTimeSeriesStatement.isOrderByHeat()) {
×
2514
      patternTree.constructTree();
×
2515
      // request schema fetch API
2516
      logger.debug("[StartFetchSchema]");
×
2517
      ISchemaTree schemaTree = schemaFetcher.fetchSchema(patternTree, context);
×
2518
      updateSchemaTreeByViews(analysis, schemaTree);
×
2519
      logger.debug("[EndFetchSchema]]");
×
2520

2521
      analyzeLastSource(
×
2522
          analysis,
2523
          Collections.singletonList(
×
2524
              new TimeSeriesOperand(showTimeSeriesStatement.getPathPattern())),
×
2525
          schemaTree);
2526
      analyzeDataPartition(analysis, new QueryStatement(), schemaTree);
×
2527
    }
2528

2529
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTimeSeriesHeader());
×
2530
    return analysis;
×
2531
  }
2532

2533
  @Override
2534
  public Analysis visitShowStorageGroup(
2535
      ShowDatabaseStatement showDatabaseStatement, MPPQueryContext context) {
2536
    Analysis analysis = new Analysis();
×
2537
    analysis.setStatement(showDatabaseStatement);
×
2538
    analysis.setRespDatasetHeader(
×
2539
        DatasetHeaderFactory.getShowStorageGroupHeader(showDatabaseStatement.isDetailed()));
×
2540
    return analysis;
×
2541
  }
2542

2543
  @Override
2544
  public Analysis visitShowTTL(ShowTTLStatement showTTLStatement, MPPQueryContext context) {
2545
    Analysis analysis = new Analysis();
×
2546
    analysis.setStatement(showTTLStatement);
×
2547
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTTLHeader());
×
2548
    return analysis;
×
2549
  }
2550

2551
  @Override
2552
  public Analysis visitShowDevices(
2553
      ShowDevicesStatement showDevicesStatement, MPPQueryContext context) {
2554
    Analysis analysis = new Analysis();
×
2555
    analysis.setStatement(showDevicesStatement);
×
2556

2557
    PathPatternTree patternTree = new PathPatternTree();
×
2558
    patternTree.appendPathPattern(
×
2559
        showDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD));
×
2560
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2561

2562
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2563
    analysis.setRespDatasetHeader(
×
2564
        showDevicesStatement.hasSgCol()
×
2565
            ? DatasetHeaderFactory.getShowDevicesWithSgHeader()
×
2566
            : DatasetHeaderFactory.getShowDevicesHeader());
×
2567
    return analysis;
×
2568
  }
2569

2570
  @Override
2571
  public Analysis visitShowCluster(
2572
      ShowClusterStatement showClusterStatement, MPPQueryContext context) {
2573
    Analysis analysis = new Analysis();
×
2574
    analysis.setStatement(showClusterStatement);
×
2575
    if (showClusterStatement.isDetails()) {
×
2576
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowClusterDetailsHeader());
×
2577
    } else {
2578
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowClusterHeader());
×
2579
    }
2580
    return analysis;
×
2581
  }
2582

2583
  @Override
2584
  public Analysis visitCountStorageGroup(
2585
      CountDatabaseStatement countDatabaseStatement, MPPQueryContext context) {
2586
    Analysis analysis = new Analysis();
×
2587
    analysis.setStatement(countDatabaseStatement);
×
2588
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountStorageGroupHeader());
×
2589
    return analysis;
×
2590
  }
2591

2592
  @Override
2593
  public Analysis visitSchemaFetch(
2594
      SchemaFetchStatement schemaFetchStatement, MPPQueryContext context) {
2595
    Analysis analysis = new Analysis();
×
2596
    analysis.setStatement(schemaFetchStatement);
×
2597

2598
    SchemaPartition schemaPartition =
×
2599
        partitionFetcher.getSchemaPartition(schemaFetchStatement.getPatternTree());
×
2600
    analysis.setSchemaPartitionInfo(schemaPartition);
×
2601

2602
    if (schemaPartition.isEmpty()) {
×
2603
      analysis.setFinishQueryAfterAnalyze(true);
×
2604
    }
2605

2606
    return analysis;
×
2607
  }
2608

2609
  @Override
2610
  public Analysis visitCountDevices(
2611
      CountDevicesStatement countDevicesStatement, MPPQueryContext context) {
2612
    Analysis analysis = new Analysis();
×
2613
    analysis.setStatement(countDevicesStatement);
×
2614

2615
    PathPatternTree patternTree = new PathPatternTree();
×
2616
    patternTree.appendPathPattern(
×
2617
        countDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD));
×
2618
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2619

2620
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2621
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountDevicesHeader());
×
2622
    return analysis;
×
2623
  }
2624

2625
  @Override
2626
  public Analysis visitCountTimeSeries(
2627
      CountTimeSeriesStatement countTimeSeriesStatement, MPPQueryContext context) {
2628
    Analysis analysis = new Analysis();
×
2629
    analysis.setStatement(countTimeSeriesStatement);
×
2630

2631
    PathPatternTree patternTree = new PathPatternTree();
×
2632
    patternTree.appendPathPattern(countTimeSeriesStatement.getPathPattern());
×
2633
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2634
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2635

2636
    Map<Integer, Template> templateMap =
×
2637
        schemaFetcher.checkAllRelatedTemplate(countTimeSeriesStatement.getPathPattern());
×
2638
    analysis.setRelatedTemplateInfo(templateMap);
×
2639

2640
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountTimeSeriesHeader());
×
2641
    return analysis;
×
2642
  }
2643

2644
  @Override
2645
  public Analysis visitCountLevelTimeSeries(
2646
      CountLevelTimeSeriesStatement countLevelTimeSeriesStatement, MPPQueryContext context) {
2647
    Analysis analysis = new Analysis();
×
2648
    analysis.setStatement(countLevelTimeSeriesStatement);
×
2649

2650
    PathPatternTree patternTree = new PathPatternTree();
×
2651
    patternTree.appendPathPattern(countLevelTimeSeriesStatement.getPathPattern());
×
2652
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2653

2654
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2655
    Map<Integer, Template> templateMap =
×
2656
        schemaFetcher.checkAllRelatedTemplate(countLevelTimeSeriesStatement.getPathPattern());
×
2657
    analysis.setRelatedTemplateInfo(templateMap);
×
2658
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountLevelTimeSeriesHeader());
×
2659
    return analysis;
×
2660
  }
2661

2662
  @Override
2663
  public Analysis visitCountNodes(CountNodesStatement countStatement, MPPQueryContext context) {
2664
    Analysis analysis = new Analysis();
×
2665
    analysis.setStatement(countStatement);
×
2666

2667
    PathPatternTree patternTree = new PathPatternTree();
×
2668
    patternTree.appendPathPattern(countStatement.getPathPattern());
×
2669
    SchemaNodeManagementPartition schemaNodeManagementPartition =
×
2670
        partitionFetcher.getSchemaNodeManagementPartitionWithLevel(
×
2671
            patternTree, countStatement.getLevel());
×
2672

2673
    if (schemaNodeManagementPartition == null) {
×
2674
      return analysis;
×
2675
    }
2676
    if (!schemaNodeManagementPartition.getMatchedNode().isEmpty()
×
2677
        && schemaNodeManagementPartition.getSchemaPartition().getSchemaPartitionMap().size() == 0) {
×
2678
      analysis.setFinishQueryAfterAnalyze(true);
×
2679
    }
2680
    analysis.setMatchedNodes(schemaNodeManagementPartition.getMatchedNode());
×
2681
    analysis.setSchemaPartitionInfo(schemaNodeManagementPartition.getSchemaPartition());
×
2682
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountNodesHeader());
×
2683
    return analysis;
×
2684
  }
2685

2686
  @Override
2687
  public Analysis visitShowChildPaths(
2688
      ShowChildPathsStatement showChildPathsStatement, MPPQueryContext context) {
2689
    return visitSchemaNodeManagementPartition(
×
2690
        showChildPathsStatement,
2691
        showChildPathsStatement.getPartialPath(),
×
2692
        DatasetHeaderFactory.getShowChildPathsHeader());
×
2693
  }
2694

2695
  @Override
2696
  public Analysis visitShowChildNodes(
2697
      ShowChildNodesStatement showChildNodesStatement, MPPQueryContext context) {
2698
    return visitSchemaNodeManagementPartition(
×
2699
        showChildNodesStatement,
2700
        showChildNodesStatement.getPartialPath(),
×
2701
        DatasetHeaderFactory.getShowChildNodesHeader());
×
2702
  }
2703

2704
  @Override
2705
  public Analysis visitShowVersion(
2706
      ShowVersionStatement showVersionStatement, MPPQueryContext context) {
2707
    Analysis analysis = new Analysis();
×
2708
    analysis.setStatement(showVersionStatement);
×
2709
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowVersionHeader());
×
2710
    analysis.setFinishQueryAfterAnalyze(true);
×
2711
    return analysis;
×
2712
  }
2713

2714
  private Analysis visitSchemaNodeManagementPartition(
2715
      Statement statement, PartialPath path, DatasetHeader header) {
2716
    Analysis analysis = new Analysis();
×
2717
    analysis.setStatement(statement);
×
2718

2719
    PathPatternTree patternTree = new PathPatternTree();
×
2720
    patternTree.appendPathPattern(path);
×
2721
    SchemaNodeManagementPartition schemaNodeManagementPartition =
×
2722
        partitionFetcher.getSchemaNodeManagementPartition(patternTree);
×
2723

2724
    if (schemaNodeManagementPartition == null) {
×
2725
      return analysis;
×
2726
    }
2727
    if (!schemaNodeManagementPartition.getMatchedNode().isEmpty()
×
2728
        && schemaNodeManagementPartition.getSchemaPartition().getSchemaPartitionMap().size() == 0) {
×
2729
      analysis.setFinishQueryAfterAnalyze(true);
×
2730
    }
2731
    analysis.setMatchedNodes(schemaNodeManagementPartition.getMatchedNode());
×
2732
    analysis.setSchemaPartitionInfo(schemaNodeManagementPartition.getSchemaPartition());
×
2733
    analysis.setRespDatasetHeader(header);
×
2734
    return analysis;
×
2735
  }
2736

2737
  @Override
2738
  public Analysis visitDeleteData(
2739
      DeleteDataStatement deleteDataStatement, MPPQueryContext context) {
2740
    context.setQueryType(QueryType.WRITE);
×
2741
    Analysis analysis = new Analysis();
×
2742
    analysis.setStatement(deleteDataStatement);
×
2743

2744
    PathPatternTree patternTree = new PathPatternTree();
×
2745
    deleteDataStatement.getPathList().forEach(patternTree::appendPathPattern);
×
2746

2747
    ISchemaTree schemaTree = schemaFetcher.fetchSchema(patternTree, context);
×
2748
    Set<String> deduplicatedDevicePaths = new HashSet<>();
×
2749

2750
    if (schemaTree.hasLogicalViewMeasurement()) {
×
2751
      updateSchemaTreeByViews(analysis, schemaTree);
×
2752

2753
      Set<PartialPath> deletePatternSet = new HashSet<>(deleteDataStatement.getPathList());
×
2754
      IMeasurementSchema measurementSchema;
2755
      LogicalViewSchema logicalViewSchema;
2756
      PartialPath sourcePathOfAliasSeries;
2757
      for (MeasurementPath measurementPath :
2758
          schemaTree.searchMeasurementPaths(SchemaConstant.ALL_MATCH_PATTERN).left) {
×
2759
        measurementSchema = measurementPath.getMeasurementSchema();
×
2760
        if (measurementSchema.isLogicalView()) {
×
2761
          logicalViewSchema = (LogicalViewSchema) measurementSchema;
×
2762
          if (logicalViewSchema.isWritable()) {
×
2763
            sourcePathOfAliasSeries = logicalViewSchema.getSourcePathIfWritable();
×
2764
            deletePatternSet.add(sourcePathOfAliasSeries);
×
2765
            deduplicatedDevicePaths.add(sourcePathOfAliasSeries.getDevice());
×
2766
          } else {
2767
            deletePatternSet.remove(measurementPath);
×
2768
          }
2769
        } else {
2770
          deduplicatedDevicePaths.add(measurementPath.getDevice());
×
2771
        }
2772
      }
×
2773
      deleteDataStatement.setPathList(new ArrayList<>(deletePatternSet));
×
2774
    } else {
×
2775
      for (PartialPath devicePattern : patternTree.getAllDevicePaths()) {
×
2776
        schemaTree
×
2777
            .getMatchedDevices(devicePattern)
×
2778
            .forEach(
×
2779
                deviceSchemaInfo ->
2780
                    deduplicatedDevicePaths.add(deviceSchemaInfo.getDevicePath().getFullPath()));
×
2781
      }
×
2782
    }
2783
    analysis.setSchemaTree(schemaTree);
×
2784

2785
    Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap = new HashMap<>();
×
2786

2787
    deduplicatedDevicePaths.forEach(
×
2788
        devicePath -> {
2789
          DataPartitionQueryParam queryParam = new DataPartitionQueryParam();
×
2790
          queryParam.setDevicePath(devicePath);
×
2791
          sgNameToQueryParamsMap
×
2792
              .computeIfAbsent(schemaTree.getBelongedDatabase(devicePath), key -> new ArrayList<>())
×
2793
              .add(queryParam);
×
2794
        });
×
2795

2796
    DataPartition dataPartition = partitionFetcher.getDataPartition(sgNameToQueryParamsMap);
×
2797
    analysis.setDataPartitionInfo(dataPartition);
×
2798
    analysis.setFinishQueryAfterAnalyze(dataPartition.isEmpty());
×
2799

2800
    return analysis;
×
2801
  }
2802

2803
  @Override
2804
  public Analysis visitCreateSchemaTemplate(
2805
      CreateSchemaTemplateStatement createTemplateStatement, MPPQueryContext context) {
2806

2807
    context.setQueryType(QueryType.WRITE);
×
2808
    List<String> measurements = createTemplateStatement.getMeasurements();
×
2809
    Set<String> measurementsSet = new HashSet<>(measurements);
×
2810
    if (measurementsSet.size() < measurements.size()) {
×
2811
      throw new SemanticException(
×
2812
          "Measurement under template is not allowed to have the same measurement name");
2813
    }
2814
    Analysis analysis = new Analysis();
×
2815
    analysis.setStatement(createTemplateStatement);
×
2816
    return analysis;
×
2817
  }
2818

2819
  @Override
2820
  public Analysis visitShowNodesInSchemaTemplate(
2821
      ShowNodesInSchemaTemplateStatement showNodesInSchemaTemplateStatement,
2822
      MPPQueryContext context) {
2823
    Analysis analysis = new Analysis();
×
2824
    analysis.setStatement(showNodesInSchemaTemplateStatement);
×
2825
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowNodesInSchemaTemplateHeader());
×
2826
    return analysis;
×
2827
  }
2828

2829
  @Override
2830
  public Analysis visitShowSchemaTemplate(
2831
      ShowSchemaTemplateStatement showSchemaTemplateStatement, MPPQueryContext context) {
2832
    Analysis analysis = new Analysis();
×
2833
    analysis.setStatement(showSchemaTemplateStatement);
×
2834
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowSchemaTemplateHeader());
×
2835
    return analysis;
×
2836
  }
2837

2838
  private GroupByFilter initGroupByFilter(GroupByTimeComponent groupByTimeComponent) {
2839
    if (groupByTimeComponent.isIntervalByMonth() || groupByTimeComponent.isSlidingStepByMonth()) {
1✔
2840
      return new GroupByMonthFilter(
×
2841
          groupByTimeComponent.getInterval(),
×
2842
          groupByTimeComponent.getSlidingStep(),
×
2843
          groupByTimeComponent.getStartTime(),
×
2844
          groupByTimeComponent.getEndTime(),
×
2845
          groupByTimeComponent.isSlidingStepByMonth(),
×
2846
          groupByTimeComponent.isIntervalByMonth(),
×
2847
          TimeZone.getTimeZone("+00:00"));
×
2848
    } else {
2849
      long startTime =
2850
          groupByTimeComponent.isLeftCRightO()
1✔
2851
              ? groupByTimeComponent.getStartTime()
1✔
2852
              : groupByTimeComponent.getStartTime() + 1;
1✔
2853
      long endTime =
2854
          groupByTimeComponent.isLeftCRightO()
1✔
2855
              ? groupByTimeComponent.getEndTime()
1✔
2856
              : groupByTimeComponent.getEndTime() + 1;
1✔
2857
      return new GroupByFilter(
1✔
2858
          groupByTimeComponent.getInterval(),
1✔
2859
          groupByTimeComponent.getSlidingStep(),
1✔
2860
          startTime,
2861
          endTime);
2862
    }
2863
  }
2864

2865
  @Override
2866
  public Analysis visitSetSchemaTemplate(
2867
      SetSchemaTemplateStatement setSchemaTemplateStatement, MPPQueryContext context) {
2868
    context.setQueryType(QueryType.WRITE);
×
2869
    Analysis analysis = new Analysis();
×
2870
    analysis.setStatement(setSchemaTemplateStatement);
×
2871
    return analysis;
×
2872
  }
2873

2874
  @Override
2875
  public Analysis visitShowPathSetTemplate(
2876
      ShowPathSetTemplateStatement showPathSetTemplateStatement, MPPQueryContext context) {
2877
    Analysis analysis = new Analysis();
×
2878
    analysis.setStatement(showPathSetTemplateStatement);
×
2879
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowPathSetTemplateHeader());
×
2880
    return analysis;
×
2881
  }
2882

2883
  @Override
2884
  public Analysis visitActivateTemplate(
2885
      ActivateTemplateStatement activateTemplateStatement, MPPQueryContext context) {
2886
    context.setQueryType(QueryType.WRITE);
×
2887
    Analysis analysis = new Analysis();
×
2888
    analysis.setStatement(activateTemplateStatement);
×
2889

2890
    PartialPath activatePath = activateTemplateStatement.getPath();
×
2891

2892
    Pair<Template, PartialPath> templateSetInfo = schemaFetcher.checkTemplateSetInfo(activatePath);
×
2893
    if (templateSetInfo == null) {
×
2894
      throw new StatementAnalyzeException(
×
2895
          new MetadataException(
2896
              String.format(
×
2897
                  "Path [%s] has not been set any template.", activatePath.getFullPath())));
×
2898
    }
2899
    analysis.setTemplateSetInfo(
×
2900
        new Pair<>(templateSetInfo.left, Collections.singletonList(templateSetInfo.right)));
×
2901

2902
    PathPatternTree patternTree = new PathPatternTree();
×
2903
    patternTree.appendPathPattern(activatePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
2904
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2905

2906
    analysis.setSchemaPartitionInfo(partition);
×
2907

2908
    return analysis;
×
2909
  }
2910

2911
  @Override
2912
  public Analysis visitBatchActivateTemplate(
2913
      BatchActivateTemplateStatement batchActivateTemplateStatement, MPPQueryContext context) {
2914
    context.setQueryType(QueryType.WRITE);
×
2915
    Analysis analysis = new Analysis();
×
2916
    analysis.setStatement(batchActivateTemplateStatement);
×
2917

2918
    Map<PartialPath, Pair<Template, PartialPath>> deviceTemplateSetInfoMap =
×
2919
        new HashMap<>(batchActivateTemplateStatement.getPaths().size());
×
2920
    for (PartialPath devicePath : batchActivateTemplateStatement.getDevicePathList()) {
×
2921
      Pair<Template, PartialPath> templateSetInfo = schemaFetcher.checkTemplateSetInfo(devicePath);
×
2922
      if (templateSetInfo == null) {
×
2923
        throw new StatementAnalyzeException(
×
2924
            new MetadataException(
2925
                String.format(
×
2926
                    "Path [%s] has not been set any template.", devicePath.getFullPath())));
×
2927
      }
2928
      deviceTemplateSetInfoMap.put(devicePath, templateSetInfo);
×
2929
    }
×
2930
    analysis.setDeviceTemplateSetInfoMap(deviceTemplateSetInfoMap);
×
2931

2932
    PathPatternTree patternTree = new PathPatternTree();
×
2933
    for (PartialPath devicePath : batchActivateTemplateStatement.getDevicePathList()) {
×
2934
      // the devicePath is a path without wildcard
2935
      patternTree.appendFullPath(devicePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
2936
    }
×
2937
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2938

2939
    analysis.setSchemaPartitionInfo(partition);
×
2940

2941
    return analysis;
×
2942
  }
2943

2944
  @Override
2945
  public Analysis visitInternalBatchActivateTemplate(
2946
      InternalBatchActivateTemplateStatement internalBatchActivateTemplateStatement,
2947
      MPPQueryContext context) {
2948
    context.setQueryType(QueryType.WRITE);
×
2949
    Analysis analysis = new Analysis();
×
2950
    analysis.setStatement(internalBatchActivateTemplateStatement);
×
2951

2952
    PathPatternTree patternTree = new PathPatternTree();
×
2953
    for (PartialPath activatePath :
2954
        internalBatchActivateTemplateStatement.getDeviceMap().keySet()) {
×
2955
      // the devicePath is a path without wildcard
2956
      patternTree.appendFullPath(activatePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
2957
    }
×
2958
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2959

2960
    analysis.setSchemaPartitionInfo(partition);
×
2961

2962
    return analysis;
×
2963
  }
2964

2965
  @Override
2966
  public Analysis visitShowPathsUsingTemplate(
2967
      ShowPathsUsingTemplateStatement showPathsUsingTemplateStatement, MPPQueryContext context) {
2968
    Analysis analysis = new Analysis();
×
2969
    analysis.setStatement(showPathsUsingTemplateStatement);
×
2970
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowPathsUsingTemplateHeader());
×
2971

2972
    Pair<Template, List<PartialPath>> templateSetInfo =
×
2973
        schemaFetcher.getAllPathsSetTemplate(showPathsUsingTemplateStatement.getTemplateName());
×
2974

2975
    if (templateSetInfo == null
×
2976
        || templateSetInfo.right == null
2977
        || templateSetInfo.right.isEmpty()) {
×
2978
      analysis.setFinishQueryAfterAnalyze(true);
×
2979
      return analysis;
×
2980
    }
2981

2982
    analysis.setTemplateSetInfo(templateSetInfo);
×
2983

2984
    PathPatternTree patternTree = new PathPatternTree();
×
2985
    PartialPath rawPathPattern = showPathsUsingTemplateStatement.getPathPattern();
×
2986
    List<PartialPath> specifiedPatternList = new ArrayList<>();
×
2987
    templateSetInfo.right.forEach(
×
2988
        setPath -> {
2989
          for (PartialPath specifiedPattern : rawPathPattern.alterPrefixPath(setPath)) {
×
2990
            patternTree.appendPathPattern(specifiedPattern);
×
2991
            specifiedPatternList.add(specifiedPattern);
×
2992
          }
×
2993
        });
×
2994

2995
    if (specifiedPatternList.isEmpty()) {
×
2996
      analysis.setFinishQueryAfterAnalyze(true);
×
2997
      return analysis;
×
2998
    }
2999

3000
    analysis.setSpecifiedTemplateRelatedPathPatternList(specifiedPatternList);
×
3001

3002
    SchemaPartition partition = partitionFetcher.getSchemaPartition(patternTree);
×
3003
    analysis.setSchemaPartitionInfo(partition);
×
3004
    if (partition.isEmpty()) {
×
3005
      analysis.setFinishQueryAfterAnalyze(true);
×
3006
      return analysis;
×
3007
    }
3008

3009
    return analysis;
×
3010
  }
3011

3012
  @Override
3013
  public Analysis visitShowQueries(
3014
      ShowQueriesStatement showQueriesStatement, MPPQueryContext context) {
3015
    Analysis analysis = new Analysis();
×
3016
    analysis.setStatement(showQueriesStatement);
×
3017
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowQueriesHeader());
×
3018
    analysis.setVirtualSource(true);
×
3019

3020
    List<TDataNodeLocation> allRunningDataNodeLocations = getRunningDataNodeLocations();
×
3021
    if (allRunningDataNodeLocations.isEmpty()) {
×
3022
      analysis.setFinishQueryAfterAnalyze(true);
×
3023
    }
3024
    // TODO Constant folding optimization for Where Predicate after True/False Constant introduced
3025
    if (allRunningDataNodeLocations.isEmpty()) {
×
3026
      throw new StatementAnalyzeException("no Running DataNodes");
×
3027
    }
3028
    analysis.setRunningDataNodeLocations(allRunningDataNodeLocations);
×
3029

3030
    Set<Expression> sourceExpressions = new HashSet<>();
×
3031
    for (ColumnHeader columnHeader : analysis.getRespDatasetHeader().getColumnHeaders()) {
×
3032
      sourceExpressions.add(
×
3033
          TimeSeriesOperand.constructColumnHeaderExpression(
×
3034
              columnHeader.getColumnName(), columnHeader.getColumnType()));
×
3035
    }
×
3036
    analysis.setSourceExpressions(sourceExpressions);
×
3037
    sourceExpressions.forEach(expression -> analyzeExpressionType(analysis, expression));
×
3038

3039
    analyzeWhere(analysis, showQueriesStatement);
×
3040

3041
    analysis.setMergeOrderParameter(new OrderByParameter(showQueriesStatement.getSortItemList()));
×
3042

3043
    return analysis;
×
3044
  }
3045

3046
  private List<TDataNodeLocation> getRunningDataNodeLocations() {
3047
    try (ConfigNodeClient client =
3048
        ConfigNodeClientManager.getInstance().borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) {
×
3049
      TGetDataNodeLocationsResp showDataNodesResp = client.getRunningDataNodeLocations();
×
3050
      if (showDataNodesResp.getStatus().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
×
3051
        throw new StatementAnalyzeException(
×
3052
            "An error occurred when executing getRunningDataNodeLocations():"
3053
                + showDataNodesResp.getStatus().getMessage());
×
3054
      }
3055
      return showDataNodesResp.getDataNodeLocationList();
×
3056
    } catch (ClientManagerException | TException e) {
×
3057
      throw new StatementAnalyzeException(
×
3058
          "An error occurred when executing getRunningDataNodeLocations():" + e.getMessage());
×
3059
    }
3060
  }
3061

3062
  private void analyzeWhere(Analysis analysis, ShowQueriesStatement showQueriesStatement) {
3063
    WhereCondition whereCondition = showQueriesStatement.getWhereCondition();
×
3064
    if (whereCondition == null) {
×
3065
      return;
×
3066
    }
3067

3068
    Expression whereExpression =
×
3069
        ExpressionAnalyzer.bindTypeForTimeSeriesOperand(
×
3070
            whereCondition.getPredicate(), ColumnHeaderConstant.showQueriesColumnHeaders);
×
3071

3072
    TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
×
3073
    if (outputType != TSDataType.BOOLEAN) {
×
3074
      throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
3075
    }
3076

3077
    analysis.setWhereExpression(whereExpression);
×
3078
  }
×
3079

3080
  // region view
3081

3082
  /**
3083
   * Compute how many paths exist, get the schema tree and the number of existed paths.
3084
   *
3085
   * @return a pair of ISchemaTree, and the number of exist paths.
3086
   */
3087
  private Pair<ISchemaTree, Integer> fetchSchemaOfPathsAndCount(
3088
      List<PartialPath> pathList, Analysis analysis, MPPQueryContext context) {
3089
    ISchemaTree schemaTree = analysis.getSchemaTree();
×
3090
    if (schemaTree == null) {
×
3091
      // source is not represented by query, thus has not done fetch schema.
3092
      PathPatternTree pathPatternTree = new PathPatternTree();
×
3093
      for (PartialPath path : pathList) {
×
3094
        pathPatternTree.appendPathPattern(path);
×
3095
      }
×
3096
      schemaTree = this.schemaFetcher.fetchSchema(pathPatternTree, context);
×
3097
    }
3098

3099
    // search each path, make sure they all exist.
3100
    int numOfExistPaths = 0;
×
3101
    for (PartialPath path : pathList) {
×
3102
      Pair<List<MeasurementPath>, Integer> pathPair = schemaTree.searchMeasurementPaths(path);
×
3103
      numOfExistPaths += !pathPair.left.isEmpty() ? 1 : 0;
×
3104
    }
×
3105
    return new Pair<>(schemaTree, numOfExistPaths);
×
3106
  }
3107

3108
  /**
3109
   * @param pathList the paths you want to check
3110
   * @param schemaTree the given schema tree
3111
   * @return if all paths you give can be found in schema tree, return a pair of view paths and
3112
   *     null; else return view paths and the non-exist path.
3113
   */
3114
  private Pair<List<PartialPath>, PartialPath> findAllViewsInPaths(
3115
      List<PartialPath> pathList, ISchemaTree schemaTree) {
3116
    List<PartialPath> result = new ArrayList<>();
×
3117
    for (PartialPath path : pathList) {
×
3118
      Pair<List<MeasurementPath>, Integer> measurementPathList =
×
3119
          schemaTree.searchMeasurementPaths(path);
×
3120
      if (measurementPathList.left.isEmpty()) {
×
3121
        return new Pair<>(result, path);
×
3122
      }
3123
      for (MeasurementPath measurementPath : measurementPathList.left) {
×
3124
        if (measurementPath.getMeasurementSchema().isLogicalView()) {
×
3125
          result.add(measurementPath);
×
3126
        }
3127
      }
×
3128
    }
×
3129
    return new Pair<>(result, null);
×
3130
  }
3131

3132
  private Pair<List<Expression>, Analysis> analyzeQueryInLogicalViewStatement(
3133
      Analysis analysis, QueryStatement queryStatement, MPPQueryContext context) {
3134
    Analysis queryAnalysis = this.visitQuery(queryStatement, context);
×
3135
    analysis.setSchemaTree(queryAnalysis.getSchemaTree());
×
3136
    // get all expression from resultColumns
3137
    List<Pair<Expression, String>> outputExpressions = queryAnalysis.getOutputExpressions();
×
3138
    if (queryAnalysis.isFailed()) {
×
3139
      analysis.setFinishQueryAfterAnalyze(true);
×
3140
      analysis.setFailStatus(queryAnalysis.getFailStatus());
×
3141
      return new Pair<>(null, analysis);
×
3142
    }
3143
    if (outputExpressions == null) {
×
3144
      analysis.setFinishQueryAfterAnalyze(true);
×
3145
      analysis.setFailStatus(
×
3146
          RpcUtils.getStatus(
×
3147
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3148
              "Columns in the query statement is empty. Please check your SQL."));
3149
      return new Pair<>(null, analysis);
×
3150
    }
3151
    if (queryAnalysis.useLogicalView()) {
×
3152
      analysis.setFinishQueryAfterAnalyze(true);
×
3153
      analysis.setFailStatus(
×
3154
          RpcUtils.getStatus(
×
3155
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3156
              "Can not create a view based on existing views. Check the query in your SQL."));
3157
      return new Pair<>(null, analysis);
×
3158
    }
3159
    List<Expression> expressionList = new ArrayList<>();
×
3160
    for (Pair<Expression, String> thisPair : outputExpressions) {
×
3161
      expressionList.add(thisPair.left);
×
3162
    }
×
3163
    return new Pair<>(expressionList, analysis);
×
3164
  }
3165

3166
  private void checkViewsInSource(
3167
      Analysis analysis, List<Expression> sourceExpressionList, MPPQueryContext context) {
3168
    List<PartialPath> pathsNeedCheck = new ArrayList<>();
×
3169
    for (Expression expression : sourceExpressionList) {
×
3170
      if (expression instanceof TimeSeriesOperand) {
×
3171
        pathsNeedCheck.add(((TimeSeriesOperand) expression).getPath());
×
3172
      }
3173
    }
×
3174
    Pair<ISchemaTree, Integer> schemaOfNeedToCheck =
×
3175
        fetchSchemaOfPathsAndCount(pathsNeedCheck, analysis, context);
×
3176
    if (schemaOfNeedToCheck.right != pathsNeedCheck.size()) {
×
3177
      // some source paths is not exist, and could not fetch schema.
3178
      analysis.setFinishQueryAfterAnalyze(true);
×
3179
      analysis.setFailStatus(
×
3180
          RpcUtils.getStatus(
×
3181
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3182
              "Can not create a view based on non-exist time series."));
3183
      return;
×
3184
    }
3185
    Pair<List<PartialPath>, PartialPath> viewInSourceCheckResult =
×
3186
        findAllViewsInPaths(pathsNeedCheck, schemaOfNeedToCheck.left);
×
3187
    if (viewInSourceCheckResult.right != null) {
×
3188
      // some source paths is not exist
3189
      analysis.setFinishQueryAfterAnalyze(true);
×
3190
      analysis.setFailStatus(
×
3191
          RpcUtils.getStatus(
×
3192
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3193
              "Path "
3194
                  + viewInSourceCheckResult.right.toString()
×
3195
                  + " does not exist! You can not create a view based on non-exist time series."));
3196
      return;
×
3197
    }
3198
    if (!viewInSourceCheckResult.left.isEmpty()) {
×
3199
      // some source paths is logical view
3200
      analysis.setFinishQueryAfterAnalyze(true);
×
3201
      analysis.setFailStatus(
×
3202
          RpcUtils.getStatus(
×
3203
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3204
              "Can not create a view based on existing views."));
3205
    }
3206
  }
×
3207

3208
  private void checkPathsInCreateLogicalView(
3209
      Analysis analysis, CreateLogicalViewStatement createLogicalViewStatement) {
3210
    Pair<Boolean, String> checkResult = createLogicalViewStatement.checkAllPaths();
×
3211
    if (Boolean.FALSE.equals(checkResult.left)) {
×
3212
      analysis.setFinishQueryAfterAnalyze(true);
×
3213
      analysis.setFailStatus(
×
3214
          RpcUtils.getStatus(
×
3215
              TSStatusCode.ILLEGAL_PATH.getStatusCode(),
×
3216
              "The path " + checkResult.right + " is illegal."));
3217
      return;
×
3218
    }
3219
    // make sure there are no redundant paths in targets. Please note that redundant paths in source
3220
    // are legal!
3221
    List<PartialPath> targetPathList = createLogicalViewStatement.getTargetPathList();
×
3222
    Set<String> targetStringSet = new HashSet<>();
×
3223
    for (PartialPath path : targetPathList) {
×
3224
      boolean repeatPathNotExist = targetStringSet.add(path.toString());
×
3225
      if (!repeatPathNotExist) {
×
3226
        analysis.setFinishQueryAfterAnalyze(true);
×
3227
        analysis.setFailStatus(
×
3228
            RpcUtils.getStatus(
×
3229
                TSStatusCode.ILLEGAL_PATH.getStatusCode(),
×
3230
                String.format("Path [%s] is redundant in target paths.", path)));
×
3231
        return;
×
3232
      }
3233
    }
×
3234
    if (createLogicalViewStatement.getSourceExpressionList().size() != targetPathList.size()) {
×
3235
      analysis.setFinishQueryAfterAnalyze(true);
×
3236
      analysis.setFailStatus(
×
3237
          RpcUtils.getStatus(
×
3238
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3239
              String.format(
×
3240
                  "The number of target paths (%d) and sources (%d) are miss matched! Please check your SQL.",
3241
                  createLogicalViewStatement.getTargetPathList().size(),
×
3242
                  createLogicalViewStatement.getSourceExpressionList().size())));
×
3243
      return;
×
3244
    }
3245
    // make sure all paths are NOt under any template
3246
    try {
3247
      for (PartialPath path : createLogicalViewStatement.getTargetPathList()) {
×
3248
        checkIsTemplateCompatible(path, null);
×
3249
      }
×
3250
    } catch (Exception e) {
×
3251
      analysis.setFinishQueryAfterAnalyze(true);
×
3252
      analysis.setFailStatus(
×
3253
          RpcUtils.getStatus(
×
3254
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3255
              "Can not create view under template."));
3256
    }
×
3257
  }
×
3258

3259
  // create Logical View
3260
  @Override
3261
  public Analysis visitCreateLogicalView(
3262
      CreateLogicalViewStatement createLogicalViewStatement, MPPQueryContext context) {
3263
    Analysis analysis = new Analysis();
×
3264
    context.setQueryType(QueryType.WRITE);
×
3265
    analysis.setStatement(createLogicalViewStatement);
×
3266

3267
    if (createLogicalViewStatement.getViewExpression() == null) {
×
3268
      // analyze query in statement
3269
      QueryStatement queryStatement = createLogicalViewStatement.getQueryStatement();
×
3270
      if (queryStatement != null) {
×
3271
        Pair<List<Expression>, Analysis> queryAnalysisPair =
×
3272
            this.analyzeQueryInLogicalViewStatement(analysis, queryStatement, context);
×
3273
        if (queryAnalysisPair.right.isFinishQueryAfterAnalyze()) {
×
3274
          return analysis;
×
3275
        } else if (queryAnalysisPair.left != null) {
×
3276
          try {
3277
            createLogicalViewStatement.setSourceExpressions(queryAnalysisPair.left);
×
3278
          } catch (UnsupportedViewException e) {
×
3279
            analysis.setFinishQueryAfterAnalyze(true);
×
3280
            analysis.setFailStatus(RpcUtils.getStatus(e.getErrorCode(), e.getMessage()));
×
3281
            return analysis;
×
3282
          }
×
3283
        }
3284
      }
3285
    }
3286

3287
    // use source and into item to generate target views
3288
    createLogicalViewStatement.parseIntoItemIfNecessary();
×
3289

3290
    // check target paths; check source expressions.
3291
    checkPathsInCreateLogicalView(analysis, createLogicalViewStatement);
×
3292
    if (analysis.isFinishQueryAfterAnalyze()) {
×
3293
      return analysis;
×
3294
    }
3295

3296
    // make sure there is no view in source
3297
    List<Expression> sourceExpressionList = createLogicalViewStatement.getSourceExpressionList();
×
3298
    checkViewsInSource(analysis, sourceExpressionList, context);
×
3299
    if (analysis.isFinishQueryAfterAnalyze()) {
×
3300
      return analysis;
×
3301
    }
3302

3303
    // set schema partition info, this info will be used to split logical plan node.
3304
    PathPatternTree patternTree = new PathPatternTree();
×
3305
    for (PartialPath thisFullPath : createLogicalViewStatement.getTargetPathList()) {
×
3306
      patternTree.appendFullPath(thisFullPath);
×
3307
    }
×
3308
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3309
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
3310

3311
    return analysis;
×
3312
  }
3313

3314
  @Override
3315
  public Analysis visitShowLogicalView(
3316
      ShowLogicalViewStatement showLogicalViewStatement, MPPQueryContext context) {
3317
    context.setQueryType(QueryType.READ);
×
3318
    Analysis analysis = new Analysis();
×
3319
    analysis.setStatement(showLogicalViewStatement);
×
3320

3321
    PathPatternTree patternTree = new PathPatternTree();
×
3322
    patternTree.appendPathPattern(showLogicalViewStatement.getPathPattern());
×
3323
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
3324
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
3325

3326
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowLogicalViewHeader());
×
3327
    return analysis;
×
3328
  }
3329
  // endregion view
3330
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc