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

apache / iotdb / #10019

07 Sep 2023 04:50AM UTC coverage: 47.489% (-0.2%) from 47.655%
#10019

push

travis_ci

web-flow
Pipe: Fix ConcurrentModificationException caused by concurrently iterating through CachedSchemaPatternMatcher.extractors when an PipeHeartbeatEvent is being assigned (#11074)

* try to fix ConcurrentModificationException when assigning PipeHeartbeatEvent

* Update CachedSchemaPatternMatcher.java

---------

Co-authored-by: 马子坤 <55695098+DanielWang2035@users.noreply.github.com>

1 of 1 new or added line in 1 file covered. (100.0%)

80551 of 169622 relevant lines covered (47.49%)

0.47 hits per line

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

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

158
import org.apache.thrift.TException;
159
import org.slf4j.Logger;
160
import org.slf4j.LoggerFactory;
161

162
import java.util.ArrayList;
163
import java.util.Arrays;
164
import java.util.Collections;
165
import java.util.Comparator;
166
import java.util.HashMap;
167
import java.util.HashSet;
168
import java.util.Iterator;
169
import java.util.LinkedHashMap;
170
import java.util.LinkedHashSet;
171
import java.util.LinkedList;
172
import java.util.List;
173
import java.util.Locale;
174
import java.util.Map;
175
import java.util.Objects;
176
import java.util.Set;
177
import java.util.TimeZone;
178
import java.util.stream.Collectors;
179

180
import static com.google.common.base.Preconditions.checkState;
181
import static org.apache.iotdb.commons.conf.IoTDBConstant.ALLOWED_SCHEMA_PROPS;
182
import static org.apache.iotdb.commons.conf.IoTDBConstant.DEADBAND;
183
import static org.apache.iotdb.commons.conf.IoTDBConstant.LOSS;
184
import static org.apache.iotdb.commons.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCARD;
185
import static org.apache.iotdb.commons.udf.builtin.ModelInferenceFunction.FORECAST;
186
import static org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant.DEVICE;
187
import static org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant.ENDTIME;
188
import static org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet.PARTITION_FETCHER;
189
import static org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet.SCHEMA_FETCHER;
190
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.bindSchemaForExpression;
191
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.concatDeviceAndBindSchemaForExpression;
192
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.getMeasurementExpression;
193
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.normalizeExpression;
194
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.searchAggregationExpressions;
195
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.searchSourceExpressions;
196
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.toLowerCaseExpression;
197
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionTypeAnalyzer.analyzeExpression;
198
import static org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetDevice;
199
import static org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetMeasurement;
200
import static org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetPath;
201
import static org.apache.iotdb.db.queryengine.plan.optimization.LimitOffsetPushDown.canPushDownLimitOffsetInGroupByTimeForDevice;
202
import static org.apache.iotdb.db.queryengine.plan.optimization.LimitOffsetPushDown.pushDownLimitOffsetInGroupByTimeForDevice;
203
import static org.apache.iotdb.db.schemaengine.schemaregion.view.visitor.GetSourcePathsVisitor.getSourcePaths;
204
import static org.apache.iotdb.db.utils.constant.SqlConstant.COUNT_TIME_HEADER;
205
import static org.apache.iotdb.db.utils.constant.SqlConstant.MODEL_ID;
206

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

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

212
  private static final IoTDBConfig CONFIG = IoTDBDescriptor.getInstance().getConfig();
1✔
213

214
  private static final Expression DEVICE_EXPRESSION =
1✔
215
      TimeSeriesOperand.constructColumnHeaderExpression(DEVICE, TSDataType.TEXT);
1✔
216

217
  private static final Expression END_TIME_EXPRESSION =
1✔
218
      TimeSeriesOperand.constructColumnHeaderExpression(ENDTIME, TSDataType.INT64);
1✔
219

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

223
  private final IPartitionFetcher partitionFetcher;
224
  private final ISchemaFetcher schemaFetcher;
225
  private final IModelFetcher modelFetcher;
226

227
  private static final PerformanceOverviewMetrics PERFORMANCE_OVERVIEW_METRICS =
1✔
228
      PerformanceOverviewMetrics.getInstance();
1✔
229

230
  public AnalyzeVisitor(IPartitionFetcher partitionFetcher, ISchemaFetcher schemaFetcher) {
1✔
231
    this.partitionFetcher = partitionFetcher;
1✔
232
    this.schemaFetcher = schemaFetcher;
1✔
233
    this.modelFetcher = ModelFetcher.getInstance();
1✔
234
  }
1✔
235

236
  @Override
237
  public Analysis visitNode(StatementNode node, MPPQueryContext context) {
238
    throw new UnsupportedOperationException(
×
239
        "Unsupported statement type: " + node.getClass().getName());
×
240
  }
241

242
  @Override
243
  public Analysis visitExplain(ExplainStatement explainStatement, MPPQueryContext context) {
244
    Analysis analysis = visitQuery(explainStatement.getQueryStatement(), context);
×
245
    analysis.setStatement(explainStatement);
×
246
    analysis.setFinishQueryAfterAnalyze(true);
×
247
    return analysis;
×
248
  }
249

250
  @Override
251
  public Analysis visitQuery(QueryStatement queryStatement, MPPQueryContext context) {
252
    Analysis analysis = new Analysis();
1✔
253
    analysis.setLastLevelUseWildcard(queryStatement.isLastLevelUseWildcard());
1✔
254
    try {
255
      // check for semantic errors
256
      queryStatement.semanticCheck();
1✔
257

258
      if (queryStatement.isModelInferenceQuery()) {
1✔
259
        analyzeModelInference(analysis, queryStatement);
×
260
      }
261

262
      ISchemaTree schemaTree = analyzeSchema(queryStatement, analysis, context);
1✔
263
      // If there is no leaf node in the schema tree, the query should be completed immediately
264
      if (schemaTree.isEmpty()) {
1✔
265
        return finishQuery(queryStatement, analysis);
×
266
      }
267

268
      // extract global time filter from query filter and determine if there is a value filter
269
      analyzeGlobalTimeFilter(analysis, queryStatement);
1✔
270

271
      if (queryStatement.isLastQuery()) {
1✔
272
        return analyzeLastQuery(queryStatement, analysis, schemaTree);
×
273
      }
274

275
      List<Pair<Expression, String>> outputExpressions;
276
      if (queryStatement.isAlignByDevice()) {
1✔
277
        List<PartialPath> deviceList = analyzeFrom(queryStatement, schemaTree);
1✔
278

279
        if (canPushDownLimitOffsetInGroupByTimeForDevice(queryStatement)) {
1✔
280
          // remove the device which won't appear in resultSet after limit/offset
281
          deviceList = pushDownLimitOffsetInGroupByTimeForDevice(deviceList, queryStatement);
1✔
282
        }
283

284
        analyzeDeviceToWhere(analysis, queryStatement, schemaTree, deviceList);
1✔
285
        outputExpressions = analyzeSelect(analysis, queryStatement, schemaTree, deviceList);
1✔
286
        if (deviceList.isEmpty()) {
1✔
287
          return finishQuery(queryStatement, analysis);
×
288
        }
289
        analysis.setDeviceList(deviceList);
1✔
290

291
        analyzeDeviceToGroupBy(analysis, queryStatement, schemaTree, deviceList);
1✔
292
        analyzeDeviceToOrderBy(analysis, queryStatement, schemaTree, deviceList);
1✔
293
        analyzeHaving(analysis, queryStatement, schemaTree, deviceList);
1✔
294

295
        analyzeDeviceToAggregation(analysis, queryStatement);
1✔
296
        analyzeDeviceToSourceTransform(analysis, queryStatement);
1✔
297
        analyzeDeviceToSource(analysis, queryStatement);
1✔
298

299
        analyzeDeviceViewOutput(analysis, queryStatement);
1✔
300
        analyzeDeviceViewInput(analysis, queryStatement);
1✔
301

302
        analyzeInto(analysis, queryStatement, deviceList, outputExpressions);
1✔
303
      } else {
1✔
304
        Map<Integer, List<Pair<Expression, String>>> outputExpressionMap =
1✔
305
            analyzeSelect(analysis, queryStatement, schemaTree);
1✔
306

307
        outputExpressions = new ArrayList<>();
1✔
308
        outputExpressionMap.values().forEach(outputExpressions::addAll);
1✔
309
        analysis.setOutputExpressions(outputExpressions);
1✔
310
        if (outputExpressions.isEmpty()) {
1✔
311
          return finishQuery(queryStatement, analysis);
×
312
        }
313

314
        analyzeGroupBy(analysis, queryStatement, schemaTree);
1✔
315

316
        analyzeHaving(analysis, queryStatement, schemaTree);
1✔
317
        analyzeOrderBy(analysis, queryStatement, schemaTree);
1✔
318

319
        analyzeGroupByLevel(analysis, queryStatement, outputExpressionMap, outputExpressions);
1✔
320
        analyzeGroupByTag(analysis, queryStatement, outputExpressions);
1✔
321

322
        Set<Expression> selectExpressions = new LinkedHashSet<>();
1✔
323
        if (queryStatement.isOutputEndTime()) {
1✔
324
          selectExpressions.add(END_TIME_EXPRESSION);
×
325
        }
326
        for (Pair<Expression, String> outputExpressionAndAlias : outputExpressions) {
1✔
327
          Expression outputExpression = outputExpressionAndAlias.left;
1✔
328
          selectExpressions.add(outputExpression);
1✔
329
        }
1✔
330
        analysis.setSelectExpressions(selectExpressions);
1✔
331

332
        analyzeAggregation(analysis, queryStatement);
1✔
333

334
        analyzeWhere(analysis, queryStatement, schemaTree);
1✔
335
        analyzeSourceTransform(analysis, outputExpressions, queryStatement);
1✔
336

337
        analyzeSource(analysis, queryStatement);
1✔
338

339
        analyzeInto(analysis, queryStatement, outputExpressions);
1✔
340
      }
341

342
      analyzeGroupByTime(analysis, queryStatement);
1✔
343

344
      analyzeFill(analysis, queryStatement);
1✔
345

346
      // generate result set header according to output expressions
347
      analyzeOutput(analysis, queryStatement, outputExpressions);
1✔
348

349
      // fetch partition information
350
      analyzeDataPartition(analysis, queryStatement, schemaTree);
1✔
351

352
    } catch (StatementAnalyzeException e) {
×
353
      throw new StatementAnalyzeException(
×
354
          "Meet error when analyzing the query statement: " + e.getMessage());
×
355
    }
1✔
356
    return analysis;
1✔
357
  }
358

359
  private void analyzeModelInference(Analysis analysis, QueryStatement queryStatement) {
360
    FunctionExpression modelInferenceExpression =
×
361
        (FunctionExpression)
362
            queryStatement.getSelectComponent().getResultColumns().get(0).getExpression();
×
363
    String modelId = modelInferenceExpression.getFunctionAttributes().get(MODEL_ID);
×
364

365
    ModelInformation modelInformation = modelFetcher.getModelInformation(modelId);
×
366
    if (modelInformation == null || !modelInformation.available()) {
×
367
      throw new SemanticException("Model " + modelId + " is not available");
×
368
    }
369

370
    ModelInferenceFunction functionType =
×
371
        ModelInferenceFunction.valueOf(modelInferenceExpression.getFunctionName().toUpperCase());
×
372
    if (functionType == FORECAST) {
×
373
      ForecastModelInferenceDescriptor modelInferenceDescriptor =
×
374
          new ForecastModelInferenceDescriptor(
375
              functionType, (ForecastModeInformation) modelInformation);
376
      Map<String, String> modelInferenceAttributes =
×
377
          modelInferenceExpression.getFunctionAttributes();
×
378
      if (modelInferenceAttributes.containsKey("predict_length")) {
×
379
        modelInferenceDescriptor.setExpectedPredictLength(
×
380
            Integer.parseInt(modelInferenceAttributes.get("predict_length")));
×
381
      }
382
      analysis.setModelInferenceDescriptor(modelInferenceDescriptor);
×
383

384
      List<ResultColumn> newResultColumns = new ArrayList<>();
×
385
      for (Expression inputExpression : modelInferenceExpression.getExpressions()) {
×
386
        newResultColumns.add(
×
387
            new ResultColumn(inputExpression, ResultColumn.ColumnType.MODEL_INFERENCE));
388
      }
×
389
      queryStatement.getSelectComponent().setResultColumns(newResultColumns);
×
390

391
      OrderByComponent descTimeOrder = new OrderByComponent();
×
392
      descTimeOrder.addSortItem(new SortItem("TIME", Ordering.DESC));
×
393
      queryStatement.setOrderByComponent(descTimeOrder);
×
394
    } else {
×
395
      throw new IllegalArgumentException(
×
396
          "Unsupported model inference function type " + functionType);
397
    }
398
  }
×
399

400
  private ISchemaTree analyzeSchema(
401
      QueryStatement queryStatement, Analysis analysis, MPPQueryContext context) {
402
    // concat path and construct path pattern tree
403
    PathPatternTree patternTree = new PathPatternTree(queryStatement.useWildcard());
1✔
404
    queryStatement = (QueryStatement) new ConcatPathRewriter().rewrite(queryStatement, patternTree);
1✔
405
    analysis.setStatement(queryStatement);
1✔
406

407
    // request schema fetch API
408
    long startTime = System.nanoTime();
1✔
409
    ISchemaTree schemaTree;
410
    try {
411
      logger.debug("[StartFetchSchema]");
1✔
412
      if (queryStatement.isGroupByTag()) {
1✔
413
        schemaTree = schemaFetcher.fetchSchemaWithTags(patternTree, context);
×
414
      } else {
415
        schemaTree = schemaFetcher.fetchSchema(patternTree, context);
1✔
416
      }
417

418
      // make sure paths in logical view is fetched
419
      updateSchemaTreeByViews(analysis, schemaTree);
1✔
420
    } finally {
421
      logger.debug("[EndFetchSchema]");
1✔
422
      QueryPlanCostMetricSet.getInstance()
1✔
423
          .recordPlanCost(SCHEMA_FETCHER, System.nanoTime() - startTime);
1✔
424
    }
425
    analysis.setSchemaTree(schemaTree);
1✔
426
    return schemaTree;
1✔
427
  }
428

429
  private Analysis finishQuery(QueryStatement queryStatement, Analysis analysis) {
430
    if (queryStatement.isSelectInto()) {
×
431
      analysis.setRespDatasetHeader(
×
432
          DatasetHeaderFactory.getSelectIntoHeader(queryStatement.isAlignByDevice()));
×
433
    }
434
    if (queryStatement.isLastQuery()) {
×
435
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getLastQueryHeader());
×
436
    }
437
    analysis.setFinishQueryAfterAnalyze(true);
×
438
    return analysis;
×
439
  }
440

441
  private void analyzeGlobalTimeFilter(Analysis analysis, QueryStatement queryStatement) {
442
    Filter globalTimeFilter = null;
1✔
443
    boolean hasValueFilter = false;
1✔
444
    if (queryStatement.getWhereCondition() != null) {
1✔
445
      WhereCondition whereCondition = queryStatement.getWhereCondition();
1✔
446
      Expression predicate = whereCondition.getPredicate();
1✔
447

448
      Pair<Filter, Boolean> resultPair =
1✔
449
          ExpressionAnalyzer.extractGlobalTimeFilter(predicate, true, true);
1✔
450
      globalTimeFilter = resultPair.left;
1✔
451
      if (globalTimeFilter != null) {
1✔
452
        globalTimeFilter = PredicateRemoveNotRewriter.rewrite(globalTimeFilter);
1✔
453
      }
454
      hasValueFilter = resultPair.right;
1✔
455

456
      predicate = ExpressionAnalyzer.evaluatePredicate(predicate);
1✔
457

458
      // set where condition to null if predicate is true or time filter.
459
      if (!hasValueFilter
1✔
460
          || (predicate.getExpressionType().equals(ExpressionType.CONSTANT)
1✔
461
              && Boolean.parseBoolean(predicate.getExpressionString()))) {
×
462
        queryStatement.setWhereCondition(null);
1✔
463
      } else {
464
        whereCondition.setPredicate(predicate);
1✔
465
      }
466
    }
467
    analysis.setGlobalTimeFilter(globalTimeFilter);
1✔
468
    analysis.setHasValueFilter(hasValueFilter);
1✔
469
  }
1✔
470

471
  private Analysis analyzeLastQuery(
472
      QueryStatement queryStatement, Analysis analysis, ISchemaTree schemaTree) {
473
    if (analysis.hasValueFilter()) {
×
474
      throw new SemanticException("Only time filters are supported in LAST query");
×
475
    }
476
    analyzeLastOrderBy(analysis, queryStatement);
×
477

478
    List<Expression> selectExpressions = new ArrayList<>();
×
479
    for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) {
×
480
      selectExpressions.add(resultColumn.getExpression());
×
481
    }
×
482
    analyzeLastSource(analysis, selectExpressions, schemaTree);
×
483

484
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getLastQueryHeader());
×
485

486
    // fetch partition information
487
    analyzeDataPartition(analysis, queryStatement, schemaTree);
×
488

489
    return analysis;
×
490
  }
491

492
  private void analyzeLastSource(
493
      Analysis analysis, List<Expression> selectExpressions, ISchemaTree schemaTree) {
494
    Set<Expression> sourceExpressions;
495

496
    sourceExpressions = new LinkedHashSet<>();
×
497

498
    for (Expression selectExpression : selectExpressions) {
×
499
      for (Expression sourceExpression : bindSchemaForExpression(selectExpression, schemaTree)) {
×
500
        if (!(sourceExpression instanceof TimeSeriesOperand)) {
×
501
          throw new SemanticException(
×
502
              "Views with functions and expressions cannot be used in LAST query");
503
        }
504
        sourceExpressions.add(sourceExpression);
×
505
      }
×
506
    }
×
507
    analysis.setSourceExpressions(sourceExpressions);
×
508
  }
×
509

510
  private void updateSchemaTreeByViews(Analysis analysis, ISchemaTree originSchemaTree) {
511
    if (!originSchemaTree.hasLogicalViewMeasurement()) {
1✔
512
      return;
1✔
513
    }
514

515
    PathPatternTree patternTree = new PathPatternTree();
×
516
    boolean needToReFetch = false;
×
517
    boolean useLogicalView = false;
×
518
    try {
519
      Pair<List<MeasurementPath>, Integer> tempPair =
×
520
          originSchemaTree.searchMeasurementPaths(new PartialPath("root.**"));
×
521
      for (MeasurementPath measurementPath : tempPair.left) {
×
522
        if (measurementPath.getMeasurementSchema().isLogicalView()) {
×
523
          useLogicalView = true;
×
524
          LogicalViewSchema logicalViewSchema =
×
525
              (LogicalViewSchema) measurementPath.getMeasurementSchema();
×
526
          ViewExpression viewExpression = logicalViewSchema.getExpression();
×
527
          List<PartialPath> pathsNeedToReFetch = getSourcePaths(viewExpression);
×
528
          for (PartialPath path : pathsNeedToReFetch) {
×
529
            patternTree.appendFullPath(path);
×
530
            needToReFetch = true;
×
531
          }
×
532
        }
533
      }
×
534
    } catch (Exception e) {
×
535
      throw new SemanticException(e);
×
536
    }
×
537
    analysis.setUseLogicalView(useLogicalView);
×
538
    if (useLogicalView
×
539
        && analysis.getStatement() instanceof QueryStatement
×
540
        && (((QueryStatement) analysis.getStatement()).isGroupByTag())) {
×
541
      throw new SemanticException("Views cannot be used in GROUP BY TAGS query yet.");
×
542
    }
543

544
    if (needToReFetch) {
×
545
      ISchemaTree viewSchemaTree = this.schemaFetcher.fetchSchema(patternTree, null);
×
546
      originSchemaTree.mergeSchemaTree(viewSchemaTree);
×
547
      Set<String> allDatabases = viewSchemaTree.getDatabases();
×
548
      allDatabases.addAll(originSchemaTree.getDatabases());
×
549
      originSchemaTree.setDatabases(allDatabases);
×
550
    }
551
  }
×
552

553
  /** process select component for align by time. */
554
  private Map<Integer, List<Pair<Expression, String>>> analyzeSelect(
555
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
556
    Map<Integer, List<Pair<Expression, String>>> outputExpressionMap = new HashMap<>();
1✔
557

558
    boolean isGroupByLevel = queryStatement.isGroupByLevel();
1✔
559
    ColumnPaginationController paginationController =
1✔
560
        new ColumnPaginationController(
561
            queryStatement.getSeriesLimit(),
1✔
562
            queryStatement.getSeriesOffset(),
1✔
563
            queryStatement.isLastQuery() || isGroupByLevel);
1✔
564

565
    Set<String> aliasSet = new HashSet<>();
1✔
566

567
    int columnIndex = 0;
1✔
568

569
    for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) {
1✔
570
      List<Pair<Expression, String>> outputExpressions = new ArrayList<>();
1✔
571
      List<Expression> resultExpressions =
1✔
572
          bindSchemaForExpression(resultColumn.getExpression(), schemaTree);
1✔
573

574
      for (Expression resultExpression : resultExpressions) {
1✔
575
        if (paginationController.hasCurOffset()) {
1✔
576
          paginationController.consumeOffset();
×
577
        } else if (paginationController.hasCurLimit()) {
1✔
578
          if (isGroupByLevel) {
1✔
579
            analyzeExpressionType(analysis, resultExpression);
×
580
            outputExpressions.add(new Pair<>(resultExpression, resultColumn.getAlias()));
×
581
            queryStatement
×
582
                .getGroupByLevelComponent()
×
583
                .updateIsCountStar(resultColumn.getExpression());
×
584
          } else {
585
            Expression normalizedExpression = normalizeExpression(resultExpression);
1✔
586
            analyzeExpressionType(analysis, normalizedExpression);
1✔
587
            checkAliasUniqueness(resultColumn.getAlias(), aliasSet);
1✔
588
            outputExpressions.add(
1✔
589
                new Pair<>(
590
                    normalizedExpression,
591
                    analyzeAlias(
1✔
592
                        resultColumn.getAlias(),
1✔
593
                        resultExpression,
594
                        normalizedExpression,
595
                        queryStatement)));
596
          }
597
          paginationController.consumeLimit();
1✔
598
        } else {
599
          break;
600
        }
601
      }
1✔
602

603
      outputExpressionMap.put(columnIndex++, outputExpressions);
1✔
604
    }
1✔
605
    return outputExpressionMap;
1✔
606
  }
607

608
  private List<PartialPath> analyzeFrom(QueryStatement queryStatement, ISchemaTree schemaTree) {
609
    // device path patterns in FROM clause
610
    List<PartialPath> devicePatternList = queryStatement.getFromComponent().getPrefixPaths();
1✔
611

612
    Set<PartialPath> deviceSet = new HashSet<>();
1✔
613
    for (PartialPath devicePattern : devicePatternList) {
1✔
614
      // get all matched devices
615
      deviceSet.addAll(
1✔
616
          schemaTree.getMatchedDevices(devicePattern).stream()
1✔
617
              .map(DeviceSchemaInfo::getDevicePath)
1✔
618
              .collect(Collectors.toList()));
1✔
619
    }
1✔
620

621
    return queryStatement.getResultDeviceOrder() == Ordering.ASC
1✔
622
        ? deviceSet.stream().sorted().collect(Collectors.toList())
1✔
623
        : deviceSet.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
1✔
624
  }
625

626
  /** process select component for align by device. */
627
  private List<Pair<Expression, String>> analyzeSelect(
628
      Analysis analysis,
629
      QueryStatement queryStatement,
630
      ISchemaTree schemaTree,
631
      List<PartialPath> deviceSet) {
632
    List<Pair<Expression, String>> outputExpressions = new ArrayList<>();
1✔
633
    Map<String, Set<Expression>> deviceToSelectExpressions = new HashMap<>();
1✔
634
    ColumnPaginationController paginationController =
1✔
635
        new ColumnPaginationController(
636
            queryStatement.getSeriesLimit(), queryStatement.getSeriesOffset(), false);
1✔
637

638
    for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) {
1✔
639
      Expression selectExpression = resultColumn.getExpression();
1✔
640

641
      // select expression after removing wildcard
642
      // use LinkedHashMap for order-preserving
643
      Map<Expression, Map<String, Expression>> measurementToDeviceSelectExpressions =
1✔
644
          new LinkedHashMap<>();
645
      for (PartialPath device : deviceSet) {
1✔
646
        List<Expression> selectExpressionsOfOneDevice =
1✔
647
            concatDeviceAndBindSchemaForExpression(selectExpression, device, schemaTree);
1✔
648
        if (selectExpressionsOfOneDevice.isEmpty()) {
1✔
649
          continue;
×
650
        }
651

652
        updateMeasurementToDeviceSelectExpressions(
1✔
653
            analysis, measurementToDeviceSelectExpressions, device, selectExpressionsOfOneDevice);
654
      }
1✔
655

656
      checkAliasUniqueness(resultColumn.getAlias(), measurementToDeviceSelectExpressions);
1✔
657

658
      for (Map.Entry<Expression, Map<String, Expression>> entry :
659
          measurementToDeviceSelectExpressions.entrySet()) {
1✔
660
        Expression measurementExpression = entry.getKey();
1✔
661
        Map<String, Expression> deviceToSelectExpressionsOfOneMeasurement = entry.getValue();
1✔
662

663
        if (paginationController.hasCurOffset()) {
1✔
664
          paginationController.consumeOffset();
×
665
        } else if (paginationController.hasCurLimit()) {
1✔
666
          deviceToSelectExpressionsOfOneMeasurement
1✔
667
              .values()
1✔
668
              .forEach(expression -> analyzeExpressionType(analysis, expression));
1✔
669
          // check whether the datatype of paths which has the same measurement name are
670
          // consistent; if not, throw a SemanticException
671
          checkDataTypeConsistencyInAlignByDevice(
1✔
672
              analysis, new ArrayList<>(deviceToSelectExpressionsOfOneMeasurement.values()));
1✔
673

674
          // add outputExpressions
675
          Expression lowerCaseMeasurementExpression = toLowerCaseExpression(measurementExpression);
1✔
676
          analyzeExpressionType(analysis, lowerCaseMeasurementExpression);
1✔
677

678
          outputExpressions.add(
1✔
679
              new Pair<>(
680
                  lowerCaseMeasurementExpression,
681
                  analyzeAlias(
1✔
682
                      resultColumn.getAlias(),
1✔
683
                      measurementExpression,
684
                      lowerCaseMeasurementExpression,
685
                      queryStatement)));
686

687
          // add deviceToSelectExpressions
688
          updateDeviceToSelectExpressions(
1✔
689
              analysis, deviceToSelectExpressions, deviceToSelectExpressionsOfOneMeasurement);
690

691
          paginationController.consumeLimit();
1✔
692
        } else {
693
          break;
694
        }
695
      }
1✔
696
    }
1✔
697

698
    // remove devices without measurements to compute
699
    Set<PartialPath> noMeasurementDevices = new HashSet<>();
1✔
700
    for (PartialPath device : deviceSet) {
1✔
701
      if (!deviceToSelectExpressions.containsKey(device.getFullPath())) {
1✔
702
        noMeasurementDevices.add(device);
×
703
      }
704
    }
1✔
705
    deviceSet.removeAll(noMeasurementDevices);
1✔
706

707
    // when the select expression of any device is empty,
708
    // the where expression map also need remove this device
709
    if (analysis.getDeviceToWhereExpression() != null) {
1✔
710
      noMeasurementDevices.forEach(
1✔
711
          devicePath -> analysis.getDeviceToWhereExpression().remove(devicePath.getFullPath()));
×
712
    }
713

714
    Set<Expression> selectExpressions = new LinkedHashSet<>();
1✔
715
    selectExpressions.add(DEVICE_EXPRESSION);
1✔
716
    if (queryStatement.isOutputEndTime()) {
1✔
717
      selectExpressions.add(END_TIME_EXPRESSION);
×
718
    }
719
    outputExpressions.forEach(pair -> selectExpressions.add(pair.getLeft()));
1✔
720
    analysis.setSelectExpressions(selectExpressions);
1✔
721

722
    analysis.setDeviceToSelectExpressions(deviceToSelectExpressions);
1✔
723

724
    return outputExpressions;
1✔
725
  }
726

727
  private void updateMeasurementToDeviceSelectExpressions(
728
      Analysis analysis,
729
      Map<Expression, Map<String, Expression>> measurementToDeviceSelectExpressions,
730
      PartialPath device,
731
      List<Expression> selectExpressionsOfOneDevice) {
732
    for (Expression expression : selectExpressionsOfOneDevice) {
1✔
733
      Expression measurementExpression =
1✔
734
          ExpressionAnalyzer.getMeasurementExpression(expression, analysis);
1✔
735
      measurementToDeviceSelectExpressions
1✔
736
          .computeIfAbsent(measurementExpression, key -> new LinkedHashMap<>())
1✔
737
          .put(device.getFullPath(), ExpressionAnalyzer.toLowerCaseExpression(expression));
1✔
738
    }
1✔
739
  }
1✔
740

741
  private void updateDeviceToSelectExpressions(
742
      Analysis analysis,
743
      Map<String, Set<Expression>> deviceToSelectExpressions,
744
      Map<String, Expression> deviceToSelectExpressionsOfOneMeasurement) {
745

746
    for (Map.Entry<String, Expression> entry :
747
        deviceToSelectExpressionsOfOneMeasurement.entrySet()) {
1✔
748
      String deviceName = entry.getKey();
1✔
749
      Expression expression = entry.getValue();
1✔
750

751
      Expression lowerCaseExpression = toLowerCaseExpression(expression);
1✔
752
      analyzeExpressionType(analysis, lowerCaseExpression);
1✔
753
      deviceToSelectExpressions
1✔
754
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
755
          .add(lowerCaseExpression);
1✔
756
    }
1✔
757
  }
1✔
758

759
  private String analyzeAlias(
760
      String resultColumnAlias,
761
      Expression rawExpression,
762
      Expression normalizedExpression,
763
      QueryStatement queryStatement) {
764
    if (resultColumnAlias != null) {
1✔
765
      // use alias as output symbol
766
      return resultColumnAlias;
1✔
767
    }
768

769
    if (queryStatement.isCountTimeAggregation()) {
1✔
770
      return COUNT_TIME_HEADER;
×
771
    }
772

773
    if (!Objects.equals(normalizedExpression, rawExpression)) {
1✔
774
      return rawExpression.getOutputSymbol();
1✔
775
    }
776

777
    return null;
1✔
778
  }
779

780
  private void analyzeHaving(
781
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
782
    if (!queryStatement.hasHaving()) {
1✔
783
      return;
1✔
784
    }
785

786
    // get removeWildcard Expressions in Having
787
    List<Expression> conJunctions =
1✔
788
        ExpressionAnalyzer.bindSchemaForPredicate(
1✔
789
            queryStatement.getHavingCondition().getPredicate(),
1✔
790
            queryStatement.getFromComponent().getPrefixPaths(),
1✔
791
            schemaTree,
792
            true);
793
    Expression havingExpression =
1✔
794
        ExpressionUtils.constructQueryFilter(
1✔
795
            conJunctions.stream().distinct().collect(Collectors.toList()));
1✔
796
    havingExpression = normalizeExpression(havingExpression);
1✔
797

798
    TSDataType outputType = analyzeExpressionType(analysis, havingExpression);
1✔
799
    if (outputType != TSDataType.BOOLEAN) {
1✔
800
      throw new SemanticException(
×
801
          String.format(
×
802
              "The output type of the expression in HAVING clause should be BOOLEAN, actual data type: %s.",
803
              outputType));
804
    }
805

806
    analysis.setHavingExpression(havingExpression);
1✔
807
  }
1✔
808

809
  private void analyzeHaving(
810
      Analysis analysis,
811
      QueryStatement queryStatement,
812
      ISchemaTree schemaTree,
813
      List<PartialPath> deviceSet) {
814
    if (!queryStatement.hasHaving()) {
1✔
815
      return;
1✔
816
    }
817

818
    // two maps to be updated
819
    Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
820
        analysis.getDeviceToAggregationExpressions();
1✔
821
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
822
        analysis.getDeviceToOutputExpressions();
1✔
823

824
    Expression havingExpression = queryStatement.getHavingCondition().getPredicate();
1✔
825
    Set<Expression> conJunctions = new HashSet<>();
1✔
826

827
    for (PartialPath device : deviceSet) {
1✔
828
      List<Expression> expressionsInHaving =
1✔
829
          concatDeviceAndBindSchemaForExpression(havingExpression, device, schemaTree);
1✔
830

831
      conJunctions.addAll(
1✔
832
          expressionsInHaving.stream()
1✔
833
              .map(expression -> getMeasurementExpression(expression, analysis))
1✔
834
              .collect(Collectors.toList()));
1✔
835

836
      for (Expression expression : expressionsInHaving) {
1✔
837
        Set<Expression> aggregationExpressions = new LinkedHashSet<>();
1✔
838
        Set<Expression> normalizedAggregationExpressions = new LinkedHashSet<>();
1✔
839
        for (Expression aggregationExpression : searchAggregationExpressions(expression)) {
1✔
840
          Expression normalizedAggregationExpression = normalizeExpression(aggregationExpression);
1✔
841

842
          analyzeExpressionType(analysis, aggregationExpression);
1✔
843
          analyzeExpressionType(analysis, normalizedAggregationExpression);
1✔
844

845
          aggregationExpressions.add(aggregationExpression);
1✔
846
          normalizedAggregationExpressions.add(normalizedAggregationExpression);
1✔
847
        }
1✔
848
        deviceToOutputExpressions
1✔
849
            .computeIfAbsent(device.getFullPath(), key -> new LinkedHashSet<>())
1✔
850
            .addAll(aggregationExpressions);
1✔
851
        deviceToAggregationExpressions
1✔
852
            .computeIfAbsent(device.getFullPath(), key -> new LinkedHashSet<>())
1✔
853
            .addAll(normalizedAggregationExpressions);
1✔
854
      }
1✔
855
    }
1✔
856

857
    havingExpression = ExpressionUtils.constructQueryFilter(new ArrayList<>(conJunctions));
1✔
858
    TSDataType outputType = analyzeExpressionType(analysis, havingExpression);
1✔
859
    if (outputType != TSDataType.BOOLEAN) {
1✔
860
      throw new SemanticException(
×
861
          String.format(
×
862
              "The output type of the expression in HAVING clause should be BOOLEAN, actual data type: %s.",
863
              outputType));
864
    }
865
    analysis.setDeviceToAggregationExpressions(deviceToAggregationExpressions);
1✔
866
    analysis.setHavingExpression(havingExpression);
1✔
867
  }
1✔
868

869
  private void analyzeGroupByLevel(
870
      Analysis analysis,
871
      QueryStatement queryStatement,
872
      Map<Integer, List<Pair<Expression, String>>> outputExpressionMap,
873
      List<Pair<Expression, String>> outputExpressions) {
874
    if (!queryStatement.isGroupByLevel()) {
1✔
875
      return;
1✔
876
    }
877

878
    GroupByLevelController groupByLevelController =
×
879
        new GroupByLevelController(queryStatement.getGroupByLevelComponent().getLevels());
×
880

881
    List<Expression> groupedSelectExpressions = new LinkedList<>();
×
882

883
    for (List<Pair<Expression, String>> outputExpressionList : outputExpressionMap.values()) {
×
884
      Set<Expression> groupedSelectExpressionSet = new LinkedHashSet<>();
×
885
      for (int i = 0; i < outputExpressionList.size(); i++) {
×
886
        Pair<Expression, String> expressionAliasPair = outputExpressionList.get(i);
×
887
        boolean isCountStar = queryStatement.getGroupByLevelComponent().isCountStar(i);
×
888
        Expression groupedExpression =
×
889
            groupByLevelController.control(
×
890
                isCountStar, expressionAliasPair.left, expressionAliasPair.right);
891
        groupedSelectExpressionSet.add(groupedExpression);
×
892
      }
893
      groupedSelectExpressions.addAll(groupedSelectExpressionSet);
×
894
    }
×
895

896
    LinkedHashMap<Expression, Set<Expression>> groupByLevelExpressions = new LinkedHashMap<>();
×
897
    if (queryStatement.hasHaving()) {
×
898
      // update havingExpression
899
      Expression havingExpression = groupByLevelController.control(analysis.getHavingExpression());
×
900
      analyzeExpressionType(analysis, havingExpression);
×
901
      analysis.setHavingExpression(havingExpression);
×
902
      updateGroupByLevelExpressions(
×
903
          analysis,
904
          havingExpression,
905
          groupByLevelExpressions,
906
          groupByLevelController.getGroupedExpressionToRawExpressionsMap());
×
907
    }
908

909
    outputExpressions.clear();
×
910
    ColumnPaginationController paginationController =
×
911
        new ColumnPaginationController(
912
            queryStatement.getSeriesLimit(), queryStatement.getSeriesOffset(), false);
×
913
    for (Expression groupedExpression : groupedSelectExpressions) {
×
914
      if (paginationController.hasCurOffset()) {
×
915
        paginationController.consumeOffset();
×
916
      } else if (paginationController.hasCurLimit()) {
×
917
        Expression normalizedGroupedExpression = normalizeExpression(groupedExpression);
×
918
        analyzeExpressionType(analysis, normalizedGroupedExpression);
×
919
        outputExpressions.add(
×
920
            new Pair<>(
921
                normalizedGroupedExpression,
922
                analyzeAlias(
×
923
                    groupByLevelController.getAlias(groupedExpression.getExpressionString()),
×
924
                    groupedExpression,
925
                    normalizedGroupedExpression,
926
                    queryStatement)));
927
        updateGroupByLevelExpressions(
×
928
            analysis,
929
            groupedExpression,
930
            groupByLevelExpressions,
931
            groupByLevelController.getGroupedExpressionToRawExpressionsMap());
×
932
        paginationController.consumeLimit();
×
933
      } else {
934
        break;
935
      }
936
    }
×
937

938
    checkDataTypeConsistencyInGroupByLevel(analysis, groupByLevelExpressions);
×
939
    analysis.setCrossGroupByExpressions(groupByLevelExpressions);
×
940
  }
×
941

942
  private void checkDataTypeConsistencyInGroupByLevel(
943
      Analysis analysis, Map<Expression, Set<Expression>> groupByLevelExpressions) {
944
    for (Map.Entry<Expression, Set<Expression>> groupedExpressionRawExpressionsEntry :
945
        groupByLevelExpressions.entrySet()) {
×
946
      Expression groupedAggregationExpression = groupedExpressionRawExpressionsEntry.getKey();
×
947
      Set<Expression> rawAggregationExpressions = groupedExpressionRawExpressionsEntry.getValue();
×
948

949
      TSDataType checkedDataType = analysis.getType(groupedAggregationExpression);
×
950
      for (Expression rawAggregationExpression : rawAggregationExpressions) {
×
951
        if (analysis.getType(rawAggregationExpression) != checkedDataType) {
×
952
          throw new SemanticException(
×
953
              String.format(
×
954
                  "GROUP BY LEVEL: the data types of the same output column[%s] should be the same.",
955
                  groupedAggregationExpression));
956
        }
957
      }
×
958
    }
×
959
  }
×
960

961
  private void updateGroupByLevelExpressions(
962
      Analysis analysis,
963
      Expression expression,
964
      Map<Expression, Set<Expression>> groupByLevelExpressions,
965
      Map<Expression, Set<Expression>> groupedExpressionToRawExpressionsMap) {
966
    for (Expression groupedAggregationExpression : searchAggregationExpressions(expression)) {
×
967
      Set<Expression> groupedExpressionSet =
×
968
          groupedExpressionToRawExpressionsMap.get(groupedAggregationExpression).stream()
×
969
              .map(ExpressionAnalyzer::normalizeExpression)
×
970
              .collect(Collectors.toSet());
×
971
      Expression groupedAggregationExpressionWithoutAlias =
×
972
          normalizeExpression(groupedAggregationExpression);
×
973

974
      analyzeExpressionType(analysis, groupedAggregationExpressionWithoutAlias);
×
975
      groupedExpressionSet.forEach(
×
976
          groupedExpression -> analyzeExpressionType(analysis, groupedExpression));
×
977

978
      groupByLevelExpressions
×
979
          .computeIfAbsent(groupedAggregationExpressionWithoutAlias, key -> new HashSet<>())
×
980
          .addAll(groupedExpressionSet);
×
981
    }
×
982
  }
×
983

984
  /**
985
   * This method is used to analyze GROUP BY TAGS query.
986
   *
987
   * <p>TODO: support slimit/soffset/value filter
988
   */
989
  private void analyzeGroupByTag(
990
      Analysis analysis,
991
      QueryStatement queryStatement,
992
      List<Pair<Expression, String>> outputExpressions) {
993
    if (!queryStatement.isGroupByTag()) {
1✔
994
      return;
1✔
995
    }
996
    if (analysis.hasValueFilter()) {
×
997
      throw new SemanticException("Only time filters are supported in GROUP BY TAGS query");
×
998
    }
999

1000
    List<String> tagKeys = queryStatement.getGroupByTagComponent().getTagKeys();
×
1001
    Map<List<String>, LinkedHashMap<Expression, List<Expression>>>
1002
        tagValuesToGroupedTimeseriesOperands = new HashMap<>();
×
1003
    LinkedHashMap<Expression, Set<Expression>> outputExpressionToRawExpressionsMap =
×
1004
        new LinkedHashMap<>();
1005

1006
    for (Pair<Expression, String> outputExpressionAndAlias : outputExpressions) {
×
1007
      FunctionExpression rawExpression = (FunctionExpression) outputExpressionAndAlias.getLeft();
×
1008
      FunctionExpression measurementExpression =
×
1009
          (FunctionExpression) getMeasurementExpression(rawExpression, analysis);
×
1010
      outputExpressionToRawExpressionsMap
×
1011
          .computeIfAbsent(measurementExpression, v -> new HashSet<>())
×
1012
          .add(rawExpression);
×
1013

1014
      Map<String, String> tagMap =
×
1015
          ((MeasurementPath)
1016
                  ((TimeSeriesOperand) measurementExpression.getExpressions().get(0)).getPath())
×
1017
              .getTagMap();
×
1018
      List<String> tagValues = new ArrayList<>();
×
1019
      for (String tagKey : tagKeys) {
×
1020
        tagValues.add(tagMap.get(tagKey));
×
1021
      }
×
1022
      tagValuesToGroupedTimeseriesOperands
×
1023
          .computeIfAbsent(tagValues, key -> new LinkedHashMap<>())
×
1024
          .computeIfAbsent(measurementExpression, key -> new ArrayList<>())
×
1025
          .add(rawExpression.getExpressions().get(0));
×
1026
    }
×
1027

1028
    // update outputExpressions
1029
    outputExpressions.clear();
×
1030
    for (String tagKey : tagKeys) {
×
1031
      Expression tagKeyExpression =
×
1032
          TimeSeriesOperand.constructColumnHeaderExpression(tagKey, TSDataType.TEXT);
×
1033
      analyzeExpressionType(analysis, tagKeyExpression);
×
1034
      outputExpressions.add(new Pair<>(tagKeyExpression, null));
×
1035
    }
×
1036
    for (Expression outputExpression : outputExpressionToRawExpressionsMap.keySet()) {
×
1037
      // TODO: support alias
1038
      analyzeExpressionType(analysis, outputExpression);
×
1039
      outputExpressions.add(new Pair<>(outputExpression, null));
×
1040
    }
×
1041
    analysis.setTagKeys(queryStatement.getGroupByTagComponent().getTagKeys());
×
1042
    analysis.setTagValuesToGroupedTimeseriesOperands(tagValuesToGroupedTimeseriesOperands);
×
1043
    analysis.setCrossGroupByExpressions(outputExpressionToRawExpressionsMap);
×
1044
  }
×
1045

1046
  private void analyzeDeviceToAggregation(Analysis analysis, QueryStatement queryStatement) {
1047
    if (!queryStatement.isAggregationQuery()) {
1✔
1048
      return;
1✔
1049
    }
1050

1051
    updateDeviceToAggregationAndOutputExpressions(
1✔
1052
        analysis, analysis.getDeviceToSelectExpressions());
1✔
1053

1054
    if (queryStatement.hasOrderByExpression()) {
1✔
1055
      updateDeviceToAggregationAndOutputExpressions(
1✔
1056
          analysis, analysis.getDeviceToOrderByExpressions());
1✔
1057
    }
1058
  }
1✔
1059

1060
  private void updateDeviceToAggregationAndOutputExpressions(
1061
      Analysis analysis, Map<String, Set<Expression>> deviceToExpressions) {
1062
    // two maps to be updated
1063
    Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
1064
        analysis.getDeviceToAggregationExpressions();
1✔
1065
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
1066
        analysis.getDeviceToOutputExpressions();
1✔
1067

1068
    for (Map.Entry<String, Set<Expression>> deviceExpressionsEntry :
1069
        deviceToExpressions.entrySet()) {
1✔
1070
      String deviceName = deviceExpressionsEntry.getKey();
1✔
1071
      Set<Expression> expressionSet = deviceExpressionsEntry.getValue();
1✔
1072

1073
      for (Expression expression : expressionSet) {
1✔
1074
        for (Expression aggregationExpression : searchAggregationExpressions(expression)) {
1✔
1075
          Expression normalizedAggregationExpression = normalizeExpression(aggregationExpression);
1✔
1076

1077
          analyzeExpressionType(analysis, normalizedAggregationExpression);
1✔
1078

1079
          deviceToOutputExpressions
1✔
1080
              .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1081
              .add(aggregationExpression);
1✔
1082
          deviceToAggregationExpressions
1✔
1083
              .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1084
              .add(normalizedAggregationExpression);
1✔
1085
        }
1✔
1086
      }
1✔
1087
    }
1✔
1088
  }
1✔
1089

1090
  private void analyzeAggregation(Analysis analysis, QueryStatement queryStatement) {
1091
    if (!queryStatement.isAggregationQuery()) {
1✔
1092
      return;
1✔
1093
    }
1094

1095
    if (queryStatement.isGroupByLevel() || queryStatement.isGroupByTag()) {
1✔
1096
      Set<Expression> aggregationExpressions =
×
1097
          analysis.getCrossGroupByExpressions().values().stream()
×
1098
              .flatMap(Set::stream)
×
1099
              .collect(Collectors.toSet());
×
1100
      analysis.setAggregationExpressions(aggregationExpressions);
×
1101
      return;
×
1102
    }
1103

1104
    Set<Expression> aggregationExpressions = new HashSet<>();
1✔
1105
    for (Expression expression : analysis.getSelectExpressions()) {
1✔
1106
      aggregationExpressions.addAll(searchAggregationExpressions(expression));
1✔
1107
    }
1✔
1108
    if (queryStatement.hasHaving()) {
1✔
1109
      aggregationExpressions.addAll(searchAggregationExpressions(analysis.getHavingExpression()));
1✔
1110
    }
1111
    if (queryStatement.hasOrderByExpression()) {
1✔
1112
      for (Expression expression : analysis.getOrderByExpressions()) {
1✔
1113
        aggregationExpressions.addAll(searchAggregationExpressions(expression));
1✔
1114
      }
1✔
1115
    }
1116
    analysis.setAggregationExpressions(aggregationExpressions);
1✔
1117
  }
1✔
1118

1119
  private void analyzeDeviceToSourceTransform(Analysis analysis, QueryStatement queryStatement) {
1120
    if (queryStatement.isAggregationQuery()) {
1✔
1121
      Map<String, Set<Expression>> deviceToSourceTransformExpressions =
1✔
1122
          analysis.getDeviceToSourceTransformExpressions();
1✔
1123
      Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
1124
          analysis.getDeviceToAggregationExpressions();
1✔
1125

1126
      for (Map.Entry<String, Set<Expression>> entry : deviceToAggregationExpressions.entrySet()) {
1✔
1127
        String deviceName = entry.getKey();
1✔
1128
        Set<Expression> aggregationExpressions = entry.getValue();
1✔
1129

1130
        Set<Expression> sourceTransformExpressions =
1✔
1131
            deviceToSourceTransformExpressions.computeIfAbsent(
1✔
1132
                deviceName, k -> new LinkedHashSet<>());
1✔
1133

1134
        for (Expression expression : aggregationExpressions) {
1✔
1135
          // if count_time aggregation exist, it can exist only one count_time(*)
1136
          if (queryStatement.isCountTimeAggregation()) {
1✔
1137
            for (Expression countTimeSourceExpression :
1138
                ((FunctionExpression) expression).getCountTimeExpressions()) {
×
1139

1140
              analyzeExpressionType(analysis, countTimeSourceExpression);
×
1141
              sourceTransformExpressions.add(countTimeSourceExpression);
×
1142
            }
×
1143
          } else {
1144
            // We just process first input Expression of AggregationFunction,
1145
            // keep other input Expressions as origin
1146
            // If AggregationFunction need more than one input series,
1147
            // we need to reconsider the process of it
1148
            sourceTransformExpressions.add(expression.getExpressions().get(0));
1✔
1149
          }
1150
        }
1✔
1151

1152
        if (queryStatement.hasGroupByExpression()) {
1✔
1153
          sourceTransformExpressions.add(analysis.getDeviceToGroupByExpression().get(deviceName));
×
1154
        }
1155
      }
1✔
1156
    } else {
1✔
1157
      updateDeviceToSourceTransformAndOutputExpressions(
1✔
1158
          analysis, analysis.getDeviceToSelectExpressions());
1✔
1159
      if (queryStatement.hasOrderByExpression()) {
1✔
1160
        updateDeviceToSourceTransformAndOutputExpressions(
1✔
1161
            analysis, analysis.getDeviceToOrderByExpressions());
1✔
1162
      }
1163
    }
1164
  }
1✔
1165

1166
  private void updateDeviceToSourceTransformAndOutputExpressions(
1167
      Analysis analysis, Map<String, Set<Expression>> deviceToExpressions) {
1168
    // two maps to be updated
1169
    Map<String, Set<Expression>> deviceToSourceTransformExpressions =
1✔
1170
        analysis.getDeviceToSourceTransformExpressions();
1✔
1171
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
1172
        analysis.getDeviceToOutputExpressions();
1✔
1173

1174
    for (Map.Entry<String, Set<Expression>> deviceExpressionsEntry :
1175
        deviceToExpressions.entrySet()) {
1✔
1176
      String deviceName = deviceExpressionsEntry.getKey();
1✔
1177
      Set<Expression> expressions = deviceExpressionsEntry.getValue();
1✔
1178

1179
      Set<Expression> normalizedExpressions = new LinkedHashSet<>();
1✔
1180
      for (Expression expression : expressions) {
1✔
1181
        Expression normalizedExpression = normalizeExpression(expression);
1✔
1182
        analyzeExpressionType(analysis, normalizedExpression);
1✔
1183

1184
        normalizedExpressions.add(normalizedExpression);
1✔
1185
      }
1✔
1186
      deviceToOutputExpressions
1✔
1187
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1188
          .addAll(expressions);
1✔
1189
      deviceToSourceTransformExpressions
1✔
1190
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1191
          .addAll(normalizedExpressions);
1✔
1192
    }
1✔
1193
  }
1✔
1194

1195
  private void analyzeSourceTransform(
1196
      Analysis analysis,
1197
      List<Pair<Expression, String>> outputExpressions,
1198
      QueryStatement queryStatement) {
1199
    Set<Expression> sourceTransformExpressions = analysis.getSourceTransformExpressions();
1✔
1200

1201
    if (queryStatement.isAggregationQuery()) {
1✔
1202
      if (queryStatement.isCountTimeAggregation()) {
1✔
1203

1204
        for (Pair<Expression, String> pair : outputExpressions) {
×
1205
          FunctionExpression countTimeExpression = (FunctionExpression) pair.left;
×
1206
          for (Expression countTimeSourceExpression :
1207
              countTimeExpression.getCountTimeExpressions()) {
×
1208
            analyzeExpressionType(analysis, countTimeSourceExpression);
×
1209
            sourceTransformExpressions.add(countTimeSourceExpression);
×
1210
          }
×
1211
        }
×
1212

1213
        // count_time only returns one result
1214
        Pair<Expression, String> firstCountTimeExpression = outputExpressions.get(0);
×
1215
        outputExpressions.clear();
×
1216
        outputExpressions.add(firstCountTimeExpression);
×
1217

1218
      } else {
×
1219
        for (Expression aggExpression : analysis.getAggregationExpressions()) {
1✔
1220
          // for AggregationExpression, only the first Expression of input need to transform
1221
          sourceTransformExpressions.add(aggExpression.getExpressions().get(0));
1✔
1222
        }
1✔
1223
      }
1224

1225
      if (queryStatement.hasGroupByExpression()) {
1✔
1226
        sourceTransformExpressions.add(analysis.getGroupByExpression());
×
1227
      }
1228
    } else {
1229
      sourceTransformExpressions.addAll(analysis.getSelectExpressions());
1✔
1230
      if (queryStatement.hasOrderByExpression()) {
1✔
1231
        sourceTransformExpressions.addAll(analysis.getOrderByExpressions());
1✔
1232
      }
1233
    }
1234
  }
1✔
1235

1236
  private void analyzeDeviceToSource(Analysis analysis, QueryStatement queryStatement) {
1237
    Map<String, Set<Expression>> deviceToSourceExpressions = new HashMap<>();
1✔
1238
    Map<String, Set<Expression>> deviceToSourceTransformExpressions =
1✔
1239
        analysis.getDeviceToSourceTransformExpressions();
1✔
1240

1241
    for (Map.Entry<String, Set<Expression>> entry : deviceToSourceTransformExpressions.entrySet()) {
1✔
1242
      String deviceName = entry.getKey();
1✔
1243
      Set<Expression> sourceTransformExpressions = entry.getValue();
1✔
1244

1245
      Set<Expression> sourceExpressions = new LinkedHashSet<>();
1✔
1246
      sourceTransformExpressions.forEach(
1✔
1247
          expression -> sourceExpressions.addAll(searchSourceExpressions(expression)));
1✔
1248

1249
      deviceToSourceExpressions.put(deviceName, sourceExpressions);
1✔
1250
    }
1✔
1251

1252
    if (queryStatement.hasWhere()) {
1✔
1253
      Map<String, Expression> deviceToWhereExpression = analysis.getDeviceToWhereExpression();
1✔
1254
      for (Map.Entry<String, Expression> deviceWhereExpressionEntry :
1255
          deviceToWhereExpression.entrySet()) {
1✔
1256
        String deviceName = deviceWhereExpressionEntry.getKey();
1✔
1257
        Expression whereExpression = deviceWhereExpressionEntry.getValue();
1✔
1258
        deviceToSourceExpressions
1✔
1259
            .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1260
            .addAll(searchSourceExpressions(whereExpression));
1✔
1261
      }
1✔
1262
    }
1263

1264
    Map<String, List<String>> outputDeviceToQueriedDevicesMap = new LinkedHashMap<>();
1✔
1265
    for (Map.Entry<String, Set<Expression>> entry : deviceToSourceExpressions.entrySet()) {
1✔
1266
      String deviceName = entry.getKey();
1✔
1267
      Set<Expression> sourceExpressionsUnderDevice = entry.getValue();
1✔
1268
      Set<String> queriedDevices = new HashSet<>();
1✔
1269
      for (Expression expression : sourceExpressionsUnderDevice) {
1✔
1270
        queriedDevices.add(ExpressionAnalyzer.getDeviceNameInSourceExpression(expression));
1✔
1271
      }
1✔
1272
      if (queriedDevices.size() > 1) {
1✔
1273
        throw new SemanticException(
×
1274
            "Cross-device queries are not supported in ALIGN BY DEVICE queries.");
1275
      }
1276
      outputDeviceToQueriedDevicesMap.put(deviceName, new ArrayList<>(queriedDevices));
1✔
1277
    }
1✔
1278

1279
    analysis.setDeviceToSourceExpressions(deviceToSourceExpressions);
1✔
1280
    analysis.setOutputDeviceToQueriedDevicesMap(outputDeviceToQueriedDevicesMap);
1✔
1281
  }
1✔
1282

1283
  private void analyzeSource(Analysis analysis, QueryStatement queryStatement) {
1284
    Set<Expression> sourceExpressions = analysis.getSourceExpressions();
1✔
1285
    if (sourceExpressions == null) {
1✔
1286
      sourceExpressions = new HashSet<>();
1✔
1287
      analysis.setSourceExpressions(sourceExpressions);
1✔
1288
    }
1289

1290
    for (Expression expression : analysis.getSourceTransformExpressions()) {
1✔
1291
      sourceExpressions.addAll(searchSourceExpressions(expression));
1✔
1292
    }
1✔
1293
    if (queryStatement.hasWhere()) {
1✔
1294
      sourceExpressions.addAll(searchSourceExpressions(analysis.getWhereExpression()));
1✔
1295
    }
1296
  }
1✔
1297

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

1301
  private void analyzeDeviceToWhere(
1302
      Analysis analysis,
1303
      QueryStatement queryStatement,
1304
      ISchemaTree schemaTree,
1305
      List<PartialPath> deviceSet) {
1306
    if (!queryStatement.hasWhere()) {
1✔
1307
      return;
1✔
1308
    }
1309

1310
    Map<String, Expression> deviceToWhereExpression = new HashMap<>();
1✔
1311
    Iterator<PartialPath> deviceIterator = deviceSet.iterator();
1✔
1312
    while (deviceIterator.hasNext()) {
1✔
1313
      PartialPath devicePath = deviceIterator.next();
1✔
1314
      Expression whereExpression;
1315
      try {
1316
        whereExpression =
1✔
1317
            normalizeExpression(analyzeWhereSplitByDevice(queryStatement, devicePath, schemaTree));
1✔
1318
      } catch (MeasurementNotExistException e) {
×
1319
        logger.warn(
×
1320
            "Meets MeasurementNotExistException in analyzeDeviceToWhere when executing align by device, "
1321
                + "error msg: {}",
1322
            e.getMessage());
×
1323
        deviceIterator.remove();
×
1324
        continue;
×
1325
      }
1✔
1326

1327
      TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
1✔
1328
      if (outputType != TSDataType.BOOLEAN) {
1✔
1329
        throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
1330
      }
1331

1332
      deviceToWhereExpression.put(devicePath.getFullPath(), whereExpression);
1✔
1333
    }
1✔
1334
    analysis.setDeviceToWhereExpression(deviceToWhereExpression);
1✔
1335
  }
1✔
1336

1337
  private void analyzeWhere(
1338
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1339
    if (!queryStatement.hasWhere()) {
1✔
1340
      return;
1✔
1341
    }
1342
    List<Expression> conJunctions =
1✔
1343
        ExpressionAnalyzer.bindSchemaForPredicate(
1✔
1344
            queryStatement.getWhereCondition().getPredicate(),
1✔
1345
            queryStatement.getFromComponent().getPrefixPaths(),
1✔
1346
            schemaTree,
1347
            true);
1348
    Expression whereExpression =
1✔
1349
        ExpressionUtils.constructQueryFilter(
1✔
1350
            conJunctions.stream().distinct().collect(Collectors.toList()));
1✔
1351
    whereExpression = normalizeExpression(whereExpression);
1✔
1352
    TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
1✔
1353
    if (outputType != TSDataType.BOOLEAN) {
1✔
1354
      throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
1355
    }
1356
    analysis.setWhereExpression(whereExpression);
1✔
1357
  }
1✔
1358

1359
  private Expression analyzeWhereSplitByDevice(
1360
      QueryStatement queryStatement, PartialPath devicePath, ISchemaTree schemaTree) {
1361
    List<Expression> conJunctions =
1✔
1362
        ExpressionAnalyzer.concatDeviceAndBindSchemaForPredicate(
1✔
1363
            queryStatement.getWhereCondition().getPredicate(), devicePath, schemaTree, true);
1✔
1364
    return ExpressionUtils.constructQueryFilter(
1✔
1365
        conJunctions.stream().distinct().collect(Collectors.toList()));
1✔
1366
  }
1367

1368
  private void analyzeDeviceViewOutput(Analysis analysis, QueryStatement queryStatement) {
1369
    Set<Expression> selectExpressions = analysis.getSelectExpressions();
1✔
1370
    Set<Expression> deviceViewOutputExpressions = new LinkedHashSet<>();
1✔
1371
    if (queryStatement.isAggregationQuery()) {
1✔
1372
      deviceViewOutputExpressions.add(DEVICE_EXPRESSION);
1✔
1373
      if (queryStatement.isOutputEndTime()) {
1✔
1374
        deviceViewOutputExpressions.add(END_TIME_EXPRESSION);
×
1375
      }
1376
      for (Expression selectExpression : selectExpressions) {
1✔
1377
        deviceViewOutputExpressions.addAll(searchAggregationExpressions(selectExpression));
1✔
1378
      }
1✔
1379
      if (queryStatement.hasHaving()) {
1✔
1380
        deviceViewOutputExpressions.addAll(
1✔
1381
            searchAggregationExpressions(analysis.getHavingExpression()));
1✔
1382
      }
1383
      if (queryStatement.hasOrderByExpression()) {
1✔
1384
        for (Expression orderByExpression : analysis.getOrderByExpressions()) {
1✔
1385
          deviceViewOutputExpressions.addAll(searchAggregationExpressions(orderByExpression));
1✔
1386
        }
1✔
1387
      }
1388
    } else {
1389
      deviceViewOutputExpressions.addAll(selectExpressions);
1✔
1390
      if (queryStatement.hasOrderByExpression()) {
1✔
1391
        deviceViewOutputExpressions.addAll(analysis.getOrderByExpressions());
1✔
1392
      }
1393
    }
1394
    analysis.setDeviceViewOutputExpressions(deviceViewOutputExpressions);
1✔
1395
    analysis.setDeviceViewSpecialProcess(
1✔
1396
        analyzeDeviceViewSpecialProcess(deviceViewOutputExpressions, queryStatement, analysis));
1✔
1397
  }
1✔
1398

1399
  private boolean analyzeDeviceViewSpecialProcess(
1400
      Set<Expression> deviceViewOutputExpressions,
1401
      QueryStatement queryStatement,
1402
      Analysis analysis) {
1403
    if (queryStatement.isAggregationQuery()
1✔
1404
        || queryStatement.hasWhere()
1✔
1405
            && ExpressionAnalyzer.isDeviceViewNeedSpecialProcess(
1✔
1406
                queryStatement.getWhereCondition().getPredicate(), analysis)) {
1✔
1407
      return true;
1✔
1408
    }
1409
    for (Expression expression : deviceViewOutputExpressions) {
1✔
1410
      if (ExpressionAnalyzer.isDeviceViewNeedSpecialProcess(expression, analysis)) {
1✔
1411
        return true;
1✔
1412
      }
1413
    }
1✔
1414
    return false;
1✔
1415
  }
1416

1417
  private void analyzeDeviceViewInput(Analysis analysis, QueryStatement queryStatement) {
1418
    List<String> deviceViewOutputColumns =
1✔
1419
        analysis.getDeviceViewOutputExpressions().stream()
1✔
1420
            .map(Expression::getOutputSymbol)
1✔
1421
            .collect(Collectors.toList());
1✔
1422

1423
    Map<String, Set<String>> deviceToOutputColumnsMap = new LinkedHashMap<>();
1✔
1424
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
1425
        analysis.getDeviceToOutputExpressions();
1✔
1426
    for (Map.Entry<String, Set<Expression>> deviceOutputExpressionEntry :
1427
        deviceToOutputExpressions.entrySet()) {
1✔
1428
      Set<Expression> outputExpressionsUnderDevice = deviceOutputExpressionEntry.getValue();
1✔
1429
      checkDeviceViewInputUniqueness(outputExpressionsUnderDevice);
1✔
1430

1431
      Set<String> outputColumns = new LinkedHashSet<>();
1✔
1432
      if (queryStatement.isOutputEndTime()) {
1✔
1433
        outputColumns.add(ENDTIME);
×
1434
      }
1435
      for (Expression expression : outputExpressionsUnderDevice) {
1✔
1436
        outputColumns.add(getMeasurementExpression(expression, analysis).getOutputSymbol());
1✔
1437
      }
1✔
1438
      deviceToOutputColumnsMap.put(deviceOutputExpressionEntry.getKey(), outputColumns);
1✔
1439
    }
1✔
1440

1441
    Map<String, List<Integer>> deviceViewInputIndexesMap = new HashMap<>();
1✔
1442
    for (Map.Entry<String, Set<String>> deviceOutputColumnsEntry :
1443
        deviceToOutputColumnsMap.entrySet()) {
1✔
1444
      String deviceName = deviceOutputColumnsEntry.getKey();
1✔
1445
      List<String> outputsUnderDevice = new ArrayList<>(deviceOutputColumnsEntry.getValue());
1✔
1446

1447
      List<Integer> indexes = new ArrayList<>();
1✔
1448
      for (String output : outputsUnderDevice) {
1✔
1449
        int index = deviceViewOutputColumns.indexOf(output);
1✔
1450
        checkState(
1✔
1451
            index >= 1, "output column '%s' is not stored in %s", output, deviceViewOutputColumns);
1452
        indexes.add(index);
1✔
1453
      }
1✔
1454
      deviceViewInputIndexesMap.put(deviceName, indexes);
1✔
1455
    }
1✔
1456
    analysis.setDeviceViewInputIndexesMap(deviceViewInputIndexesMap);
1✔
1457
  }
1✔
1458

1459
  private void checkDeviceViewInputUniqueness(Set<Expression> outputExpressionsUnderDevice) {
1460
    Set<Expression> normalizedOutputExpressionsUnderDevice =
1✔
1461
        outputExpressionsUnderDevice.stream()
1✔
1462
            .map(ExpressionAnalyzer::normalizeExpression)
1✔
1463
            .collect(Collectors.toSet());
1✔
1464
    if (normalizedOutputExpressionsUnderDevice.size() < outputExpressionsUnderDevice.size()) {
1✔
1465
      throw new SemanticException(
×
1466
          "Views or measurement aliases representing the same data source "
1467
              + "cannot be queried concurrently in ALIGN BY DEVICE queries.");
1468
    }
1469
  }
1✔
1470

1471
  private void analyzeOutput(
1472
      Analysis analysis,
1473
      QueryStatement queryStatement,
1474
      List<Pair<Expression, String>> outputExpressions) {
1475
    if (queryStatement.isSelectInto()) {
1✔
1476
      analysis.setRespDatasetHeader(
1✔
1477
          DatasetHeaderFactory.getSelectIntoHeader(queryStatement.isAlignByDevice()));
1✔
1478
      return;
1✔
1479
    }
1480

1481
    if (queryStatement.isModelInferenceQuery()) {
1✔
1482
      List<ColumnHeader> columnHeaders = new ArrayList<>();
×
1483

1484
      ModelInferenceDescriptor modelInferenceDescriptor = analysis.getModelInferenceDescriptor();
×
1485
      if (Objects.requireNonNull(modelInferenceDescriptor.getFunctionType()) == FORECAST) {
×
1486
        ForecastModelInferenceDescriptor forecastModelInferenceDescriptor =
×
1487
            (ForecastModelInferenceDescriptor) modelInferenceDescriptor;
1488

1489
        List<TSDataType> inputTypeList = forecastModelInferenceDescriptor.getInputTypeList();
×
1490
        if (outputExpressions.size() != inputTypeList.size()) {
×
1491
          throw new SemanticException(
×
1492
              String.format(
×
1493
                  "The number of input expressions does not match the number of input types [%d] when training",
1494
                  inputTypeList.size()));
×
1495
        }
1496
        for (int i = 0; i < inputTypeList.size(); i++) {
×
1497
          Expression inputExpression = outputExpressions.get(i).left;
×
1498
          TSDataType inputDataType = analysis.getType(inputExpression);
×
1499
          if (inputDataType != inputTypeList.get(i)) {
×
1500
            throw new SemanticException(
×
1501
                String.format(
×
1502
                    "The type of input expression [%s] does not match the type of input type [%s] when training",
1503
                    inputDataType, inputTypeList.get(i)));
×
1504
          }
1505
        }
1506

1507
        List<FunctionExpression> modelInferenceOutputExpressions = new ArrayList<>();
×
1508
        for (int predictIndex : forecastModelInferenceDescriptor.getPredictIndexList()) {
×
1509
          Expression inputExpression = outputExpressions.get(predictIndex).left;
×
1510
          FunctionExpression modelInferenceOutputExpression =
×
1511
              new FunctionExpression(
1512
                  FORECAST.getFunctionName(),
×
1513
                  forecastModelInferenceDescriptor.getOutputAttributes(),
×
1514
                  Collections.singletonList(inputExpression));
×
1515
          analyzeExpression(analysis, modelInferenceOutputExpression);
×
1516
          modelInferenceOutputExpressions.add(modelInferenceOutputExpression);
×
1517
          columnHeaders.add(
×
1518
              new ColumnHeader(
1519
                  modelInferenceOutputExpression.toString(),
×
1520
                  analysis.getType(modelInferenceOutputExpression)));
×
1521
        }
×
1522
        forecastModelInferenceDescriptor.setModelInferenceOutputExpressions(
×
1523
            modelInferenceOutputExpressions);
1524
      } else {
×
1525
        throw new SemanticException(
×
1526
            "Unsupported model inference function type "
1527
                + modelInferenceDescriptor.getFunctionType());
×
1528
      }
1529
      analysis.setRespDatasetHeader(new DatasetHeader(columnHeaders, false));
×
1530
      return;
×
1531
    }
1532

1533
    boolean isIgnoreTimestamp = queryStatement.isAggregationQuery() && !queryStatement.isGroupBy();
1✔
1534
    List<ColumnHeader> columnHeaders = new ArrayList<>();
1✔
1535
    if (queryStatement.isAlignByDevice()) {
1✔
1536
      columnHeaders.add(new ColumnHeader(DEVICE, TSDataType.TEXT, null));
1✔
1537
    }
1538
    if (queryStatement.isOutputEndTime()) {
1✔
1539
      columnHeaders.add(new ColumnHeader(ENDTIME, TSDataType.INT64, null));
×
1540
    }
1541
    for (Pair<Expression, String> expressionAliasPair : outputExpressions) {
1✔
1542
      columnHeaders.add(
1✔
1543
          new ColumnHeader(
1544
              expressionAliasPair.left.getExpressionString(),
1✔
1545
              analysis.getType(expressionAliasPair.left),
1✔
1546
              expressionAliasPair.right));
1547
    }
1✔
1548
    analysis.setRespDatasetHeader(new DatasetHeader(columnHeaders, isIgnoreTimestamp));
1✔
1549
  }
1✔
1550

1551
  // For last query
1552
  private void analyzeLastOrderBy(Analysis analysis, QueryStatement queryStatement) {
1553
    if (!queryStatement.hasOrderBy()) {
×
1554
      return;
×
1555
    }
1556

1557
    if (queryStatement.onlyOrderByTimeseries()) {
×
1558
      analysis.setTimeseriesOrderingForLastQuery(
×
1559
          queryStatement.getOrderByComponent().getTimeseriesOrder());
×
1560
    }
1561

1562
    for (SortItem sortItem : queryStatement.getSortItemList()) {
×
1563
      String sortKey = sortItem.getSortKey();
×
1564
      if (!lastQueryColumnNames.contains(sortKey.toUpperCase())) {
×
1565
        throw new SemanticException(
×
1566
            String.format(
×
1567
                "%s in order by clause doesn't exist in the result of last query.", sortKey));
1568
      }
1569
    }
×
1570
  }
×
1571

1572
  private void analyzeOrderBy(
1573
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1574
    if (!queryStatement.hasOrderByExpression()) {
1✔
1575
      return;
1✔
1576
    }
1577

1578
    Set<Expression> orderByExpressions = new LinkedHashSet<>();
1✔
1579
    for (Expression expressionForItem : queryStatement.getExpressionSortItemList()) {
1✔
1580
      // Expression in a sortItem only indicates one column
1581
      List<Expression> expressions = bindSchemaForExpression(expressionForItem, schemaTree);
1✔
1582
      if (expressions.isEmpty()) {
1✔
1583
        throw new SemanticException(
×
1584
            String.format(
×
1585
                "%s in order by clause doesn't exist.", expressionForItem.getExpressionString()));
×
1586
      }
1587
      if (expressions.size() > 1) {
1✔
1588
        throw new SemanticException(
×
1589
            String.format(
×
1590
                "%s in order by clause shouldn't refer to more than one timeseries.",
1591
                expressionForItem.getExpressionString()));
×
1592
      }
1593
      expressionForItem = normalizeExpression(expressions.get(0));
1✔
1594
      TSDataType dataType = analyzeExpressionType(analysis, expressionForItem);
1✔
1595
      if (!dataType.isComparable()) {
1✔
1596
        throw new SemanticException(
×
1597
            String.format("The data type of %s is not comparable", dataType));
×
1598
      }
1599
      orderByExpressions.add(expressionForItem);
1✔
1600
    }
1✔
1601
    analysis.setOrderByExpressions(orderByExpressions);
1✔
1602
    queryStatement.updateSortItems(orderByExpressions);
1✔
1603
  }
1✔
1604

1605
  private TSDataType analyzeExpressionType(Analysis analysis, Expression expression) {
1606
    return analyzeExpression(analysis, expression);
1✔
1607
  }
1608

1609
  private void analyzeDeviceToGroupBy(
1610
      Analysis analysis,
1611
      QueryStatement queryStatement,
1612
      ISchemaTree schemaTree,
1613
      List<PartialPath> deviceSet) {
1614
    if (queryStatement.getGroupByComponent() == null) {
1✔
1615
      return;
1✔
1616
    }
1617
    GroupByComponent groupByComponent = queryStatement.getGroupByComponent();
×
1618
    WindowType windowType = groupByComponent.getWindowType();
×
1619

1620
    Map<String, Expression> deviceToGroupByExpression = new LinkedHashMap<>();
×
1621
    if (queryStatement.hasGroupByExpression()) {
×
1622
      Expression expression = groupByComponent.getControlColumnExpression();
×
1623
      for (PartialPath device : deviceSet) {
×
1624
        List<Expression> groupByExpressionsOfOneDevice =
×
1625
            concatDeviceAndBindSchemaForExpression(expression, device, schemaTree);
×
1626

1627
        if (groupByExpressionsOfOneDevice.isEmpty()) {
×
1628
          throw new SemanticException(
×
1629
              String.format("%s in group by clause doesn't exist.", expression));
×
1630
        }
1631
        if (groupByExpressionsOfOneDevice.size() > 1) {
×
1632
          throw new SemanticException(
×
1633
              String.format(
×
1634
                  "%s in group by clause shouldn't refer to more than one timeseries.",
1635
                  expression));
1636
        }
1637
        deviceToGroupByExpression.put(
×
1638
            device.getFullPath(), normalizeExpression(groupByExpressionsOfOneDevice.get(0)));
×
1639
      }
×
1640
    }
1641

1642
    GroupByParameter groupByParameter;
1643
    switch (windowType) {
×
1644
      case VARIATION_WINDOW:
1645
        double delta = ((GroupByVariationComponent) groupByComponent).getDelta();
×
1646
        for (Expression expression : deviceToGroupByExpression.values()) {
×
1647
          checkGroupByVariationExpressionType(analysis, expression, delta);
×
1648
        }
×
1649
        groupByParameter = new GroupByVariationParameter(groupByComponent.isIgnoringNull(), delta);
×
1650
        analysis.setDeviceToGroupByExpression(deviceToGroupByExpression);
×
1651
        break;
×
1652
      case CONDITION_WINDOW:
1653
        Expression keepExpression =
×
1654
            ((GroupByConditionComponent) groupByComponent).getKeepExpression();
×
1655
        for (Expression expression : deviceToGroupByExpression.values()) {
×
1656
          checkGroupByConditionExpressionType(analysis, expression, keepExpression);
×
1657
        }
×
1658
        groupByParameter =
×
1659
            new GroupByConditionParameter(groupByComponent.isIgnoringNull(), keepExpression);
×
1660
        analysis.setDeviceToGroupByExpression(deviceToGroupByExpression);
×
1661
        break;
×
1662
      case SESSION_WINDOW:
1663
        groupByParameter =
×
1664
            new GroupBySessionParameter(
1665
                ((GroupBySessionComponent) groupByComponent).getTimeInterval());
×
1666
        break;
×
1667
      case COUNT_WINDOW:
1668
        groupByParameter =
×
1669
            new GroupByCountParameter(
1670
                ((GroupByCountComponent) groupByComponent).getCountNumber(),
×
1671
                groupByComponent.isIgnoringNull());
×
1672
        analysis.setDeviceToGroupByExpression(deviceToGroupByExpression);
×
1673
        break;
×
1674
      default:
1675
        throw new UnsupportedOperationException("Unsupported window type");
×
1676
    }
1677
    analysis.setGroupByParameter(groupByParameter);
×
1678
  }
×
1679

1680
  private void analyzeDeviceToOrderBy(
1681
      Analysis analysis,
1682
      QueryStatement queryStatement,
1683
      ISchemaTree schemaTree,
1684
      List<PartialPath> deviceSet) {
1685
    if (!queryStatement.hasOrderByExpression()) {
1✔
1686
      return;
1✔
1687
    }
1688

1689
    Map<String, Set<Expression>> deviceToOrderByExpressions = new LinkedHashMap<>();
1✔
1690
    Map<String, List<SortItem>> deviceToSortItems = new LinkedHashMap<>();
1✔
1691
    // build the device-view outputColumn for the sortNode above the deviceViewNode
1692
    Set<Expression> deviceViewOrderByExpression = new LinkedHashSet<>();
1✔
1693
    for (PartialPath device : deviceSet) {
1✔
1694
      Set<Expression> orderByExpressionsForOneDevice = new LinkedHashSet<>();
1✔
1695
      for (Expression expressionForItem : queryStatement.getExpressionSortItemList()) {
1✔
1696
        List<Expression> expressions =
1✔
1697
            concatDeviceAndBindSchemaForExpression(expressionForItem, device, schemaTree);
1✔
1698
        if (expressions.isEmpty()) {
1✔
1699
          throw new SemanticException(
×
1700
              String.format(
×
1701
                  "%s in order by clause doesn't exist.", expressionForItem.getExpressionString()));
×
1702
        }
1703
        if (expressions.size() > 1) {
1✔
1704
          throw new SemanticException(
×
1705
              String.format(
×
1706
                  "%s in order by clause shouldn't refer to more than one timeseries.",
1707
                  expressionForItem.getExpressionString()));
×
1708
        }
1709
        expressionForItem = expressions.get(0);
1✔
1710
        TSDataType dataType = analyzeExpressionType(analysis, expressionForItem);
1✔
1711
        if (!dataType.isComparable()) {
1✔
1712
          throw new SemanticException(
×
1713
              String.format("The data type of %s is not comparable", dataType));
×
1714
        }
1715

1716
        Expression deviceViewExpression = getMeasurementExpression(expressionForItem, analysis);
1✔
1717
        analyzeExpressionType(analysis, deviceViewExpression);
1✔
1718

1719
        deviceViewOrderByExpression.add(deviceViewExpression);
1✔
1720
        orderByExpressionsForOneDevice.add(expressionForItem);
1✔
1721
      }
1✔
1722
      deviceToSortItems.put(
1✔
1723
          device.getFullPath(), queryStatement.getUpdatedSortItems(orderByExpressionsForOneDevice));
1✔
1724
      deviceToOrderByExpressions.put(device.getFullPath(), orderByExpressionsForOneDevice);
1✔
1725
    }
1✔
1726

1727
    analysis.setOrderByExpressions(deviceViewOrderByExpression);
1✔
1728
    queryStatement.updateSortItems(deviceViewOrderByExpression);
1✔
1729
    analysis.setDeviceToSortItems(deviceToSortItems);
1✔
1730
    analysis.setDeviceToOrderByExpressions(deviceToOrderByExpressions);
1✔
1731
  }
1✔
1732

1733
  private void analyzeGroupBy(
1734
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1735

1736
    if (queryStatement.getGroupByComponent() == null) {
1✔
1737
      return;
1✔
1738
    }
1739
    GroupByComponent groupByComponent = queryStatement.getGroupByComponent();
×
1740
    WindowType windowType = groupByComponent.getWindowType();
×
1741

1742
    Expression groupByExpression = null;
×
1743
    if (queryStatement.hasGroupByExpression()) {
×
1744
      groupByExpression = groupByComponent.getControlColumnExpression();
×
1745
      // Expression in group by variation clause only indicates one column
1746
      List<Expression> expressions = bindSchemaForExpression(groupByExpression, schemaTree);
×
1747
      if (expressions.isEmpty()) {
×
1748
        throw new SemanticException(
×
1749
            String.format(
×
1750
                "%s in group by clause doesn't exist.", groupByExpression.getExpressionString()));
×
1751
      }
1752
      if (expressions.size() > 1) {
×
1753
        throw new SemanticException(
×
1754
            String.format(
×
1755
                "%s in group by clause shouldn't refer to more than one timeseries.",
1756
                groupByExpression.getExpressionString()));
×
1757
      }
1758
      // Aggregation expression shouldn't exist in group by clause.
1759
      List<Expression> aggregationExpression = searchAggregationExpressions(expressions.get(0));
×
1760
      if (aggregationExpression != null && !aggregationExpression.isEmpty()) {
×
1761
        throw new SemanticException("Aggregation expression shouldn't exist in group by clause");
×
1762
      }
1763
      groupByExpression = normalizeExpression(expressions.get(0));
×
1764
    }
1765

1766
    if (windowType == WindowType.VARIATION_WINDOW) {
×
1767
      double delta = ((GroupByVariationComponent) groupByComponent).getDelta();
×
1768
      checkGroupByVariationExpressionType(analysis, groupByExpression, delta);
×
1769
      GroupByParameter groupByParameter =
×
1770
          new GroupByVariationParameter(groupByComponent.isIgnoringNull(), delta);
×
1771
      analysis.setGroupByExpression(groupByExpression);
×
1772
      analysis.setGroupByParameter(groupByParameter);
×
1773
    } else if (windowType == WindowType.CONDITION_WINDOW) {
×
1774
      Expression keepExpression =
×
1775
          ((GroupByConditionComponent) groupByComponent).getKeepExpression();
×
1776
      checkGroupByConditionExpressionType(analysis, groupByExpression, keepExpression);
×
1777
      GroupByParameter groupByParameter =
×
1778
          new GroupByConditionParameter(groupByComponent.isIgnoringNull(), keepExpression);
×
1779
      analysis.setGroupByExpression(groupByExpression);
×
1780
      analysis.setGroupByParameter(groupByParameter);
×
1781
    } else if (windowType == WindowType.SESSION_WINDOW) {
×
1782
      long interval = ((GroupBySessionComponent) groupByComponent).getTimeInterval();
×
1783
      GroupByParameter groupByParameter = new GroupBySessionParameter(interval);
×
1784
      analysis.setGroupByParameter(groupByParameter);
×
1785
    } else if (windowType == WindowType.COUNT_WINDOW) {
×
1786
      GroupByParameter groupByParameter =
×
1787
          new GroupByCountParameter(
1788
              ((GroupByCountComponent) groupByComponent).getCountNumber(),
×
1789
              groupByComponent.isIgnoringNull());
×
1790
      analyzeExpressionType(analysis, groupByExpression);
×
1791
      analysis.setGroupByExpression(groupByExpression);
×
1792
      analysis.setGroupByParameter(groupByParameter);
×
1793
    } else {
×
1794
      throw new SemanticException("Unsupported window type");
×
1795
    }
1796
  }
×
1797

1798
  private void checkGroupByVariationExpressionType(
1799
      Analysis analysis, Expression groupByExpression, double delta) {
1800
    TSDataType type = analyzeExpressionType(analysis, groupByExpression);
×
1801
    if (delta != 0 && !type.isNumeric()) {
×
1802
      throw new SemanticException("Only support numeric type when delta != 0");
×
1803
    }
1804
  }
×
1805

1806
  private void checkGroupByConditionExpressionType(
1807
      Analysis analysis, Expression groupByExpression, Expression keepExpression) {
1808
    TSDataType type = analyzeExpressionType(analysis, groupByExpression);
×
1809
    if (type != TSDataType.BOOLEAN) {
×
1810
      throw new SemanticException("Only support boolean type in predict of group by series");
×
1811
    }
1812

1813
    // check keep Expression
1814
    if (keepExpression instanceof CompareBinaryExpression) {
×
1815
      Expression leftExpression = ((CompareBinaryExpression) keepExpression).getLeftExpression();
×
1816
      Expression rightExpression = ((CompareBinaryExpression) keepExpression).getRightExpression();
×
1817
      if (!(leftExpression instanceof TimeSeriesOperand
×
1818
          && leftExpression.getExpressionString().equalsIgnoreCase("keep")
×
1819
          && rightExpression instanceof ConstantOperand)) {
1820
        throw new SemanticException(
×
1821
            String.format(
×
1822
                "Please check the keep condition ([%s]),it need to be a constant or a compare expression constructed by 'keep' and a long number.",
1823
                keepExpression.getExpressionString()));
×
1824
      }
1825
      return;
×
1826
    }
1827
    if (!(keepExpression instanceof ConstantOperand)) {
×
1828
      throw new SemanticException(
×
1829
          String.format(
×
1830
              "Please check the keep condition ([%s]),it need to be a constant or a compare expression constructed by 'keep' and a long number.",
1831
              keepExpression.getExpressionString()));
×
1832
    }
1833
  }
×
1834

1835
  private void analyzeGroupByTime(Analysis analysis, QueryStatement queryStatement) {
1836
    if (!queryStatement.isGroupByTime()) {
1✔
1837
      return;
1✔
1838
    }
1839

1840
    if (queryStatement.isResultSetEmpty()) {
1✔
1841
      analysis.setFinishQueryAfterAnalyze(true);
×
1842
    }
1843

1844
    GroupByTimeComponent groupByTimeComponent = queryStatement.getGroupByTimeComponent();
1✔
1845
    if ((groupByTimeComponent.isIntervalByMonth() || groupByTimeComponent.isSlidingStepByMonth())
1✔
1846
        && queryStatement.getResultTimeOrder() == Ordering.DESC) {
×
1847
      throw new SemanticException("Group by month doesn't support order by time desc now.");
×
1848
    }
1849
    if (!queryStatement.isCqQueryBody()
1✔
1850
        && (groupByTimeComponent.getStartTime() == 0 && groupByTimeComponent.getEndTime() == 0)) {
1✔
1851
      throw new SemanticException(
×
1852
          "The query time range should be specified in the GROUP BY TIME clause.");
1853
    }
1854
    analysis.setGroupByTimeParameter(new GroupByTimeParameter(groupByTimeComponent));
1✔
1855

1856
    Filter globalTimeFilter = analysis.getGlobalTimeFilter();
1✔
1857
    Filter groupByFilter = initGroupByFilter(groupByTimeComponent);
1✔
1858
    if (globalTimeFilter == null) {
1✔
1859
      globalTimeFilter = groupByFilter;
1✔
1860
    } else {
1861
      globalTimeFilter = FilterFactory.and(globalTimeFilter, groupByFilter);
1✔
1862
    }
1863
    analysis.setGlobalTimeFilter(globalTimeFilter);
1✔
1864
  }
1✔
1865

1866
  private void analyzeFill(Analysis analysis, QueryStatement queryStatement) {
1867
    if (queryStatement.getFillComponent() == null) {
1✔
1868
      return;
1✔
1869
    }
1870

1871
    FillComponent fillComponent = queryStatement.getFillComponent();
1✔
1872
    analysis.setFillDescriptor(
1✔
1873
        new FillDescriptor(fillComponent.getFillPolicy(), fillComponent.getFillValue()));
1✔
1874
  }
1✔
1875

1876
  private void analyzeDataPartition(
1877
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1878
    Set<String> deviceSet = new HashSet<>();
1✔
1879
    if (queryStatement.isAlignByDevice()) {
1✔
1880
      deviceSet =
1✔
1881
          analysis.getOutputDeviceToQueriedDevicesMap().values().stream()
1✔
1882
              .flatMap(List::stream)
1✔
1883
              .collect(Collectors.toSet());
1✔
1884
    } else {
1885
      for (Expression expression : analysis.getSourceExpressions()) {
1✔
1886
        deviceSet.add(ExpressionAnalyzer.getDeviceNameInSourceExpression(expression));
1✔
1887
      }
1✔
1888
    }
1889
    DataPartition dataPartition =
1✔
1890
        fetchDataPartitionByDevices(deviceSet, schemaTree, analysis.getGlobalTimeFilter());
1✔
1891
    analysis.setDataPartitionInfo(dataPartition);
1✔
1892
  }
1✔
1893

1894
  private DataPartition fetchDataPartitionByDevices(
1895
      Set<String> deviceSet, ISchemaTree schemaTree, Filter globalTimeFilter) {
1896
    long startTime = System.nanoTime();
1✔
1897
    try {
1898
      Pair<List<TTimePartitionSlot>, Pair<Boolean, Boolean>> res =
1✔
1899
          getTimePartitionSlotList(globalTimeFilter);
1✔
1900
      // there is no satisfied time range
1901
      if (res.left.isEmpty() && Boolean.FALSE.equals(res.right.left)) {
1✔
1902
        return new DataPartition(
1✔
1903
            Collections.emptyMap(),
1✔
1904
            CONFIG.getSeriesPartitionExecutorClass(),
1✔
1905
            CONFIG.getSeriesPartitionSlotNum());
1✔
1906
      }
1907
      Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap = new HashMap<>();
1✔
1908
      for (String devicePath : deviceSet) {
1✔
1909
        DataPartitionQueryParam queryParam =
1✔
1910
            new DataPartitionQueryParam(devicePath, res.left, res.right.left, res.right.right);
1✔
1911
        sgNameToQueryParamsMap
1✔
1912
            .computeIfAbsent(schemaTree.getBelongedDatabase(devicePath), key -> new ArrayList<>())
1✔
1913
            .add(queryParam);
1✔
1914
      }
1✔
1915

1916
      if (res.right.left || res.right.right) {
1✔
1917
        return partitionFetcher.getDataPartitionWithUnclosedTimeRange(sgNameToQueryParamsMap);
1✔
1918
      } else {
1919
        return partitionFetcher.getDataPartition(sgNameToQueryParamsMap);
1✔
1920
      }
1921
    } finally {
1922
      QueryPlanCostMetricSet.getInstance()
1✔
1923
          .recordPlanCost(PARTITION_FETCHER, System.nanoTime() - startTime);
1✔
1924
    }
1925
  }
1926

1927
  /**
1928
   * get TTimePartitionSlot list about this time filter
1929
   *
1930
   * @return List<TTimePartitionSlot>, if contains (-oo, XXX] time range, res.right.left = true; if
1931
   *     contains [XX, +oo), res.right.right = true
1932
   */
1933
  @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning
1934
  public static Pair<List<TTimePartitionSlot>, Pair<Boolean, Boolean>> getTimePartitionSlotList(
1935
      Filter timeFilter) {
1936
    if (timeFilter == null) {
1✔
1937
      // (-oo, +oo)
1938
      return new Pair<>(Collections.emptyList(), new Pair<>(true, true));
1✔
1939
    }
1940
    List<TimeRange> timeRangeList = timeFilter.getTimeRanges();
1✔
1941
    if (timeRangeList.isEmpty()) {
1✔
1942
      // no satisfied time range
1943
      return new Pair<>(Collections.emptyList(), new Pair<>(false, false));
1✔
1944
    } else if (timeRangeList.size() == 1
1✔
1945
        && (timeRangeList.get(0).getMin() == Long.MIN_VALUE
1✔
1946
            && timeRangeList.get(timeRangeList.size() - 1).getMax() == Long.MAX_VALUE)) {
1✔
1947
      // (-oo, +oo)
1948
      return new Pair<>(Collections.emptyList(), new Pair<>(true, true));
1✔
1949
    }
1950

1951
    boolean needLeftAll;
1952
    boolean needRightAll;
1953
    long endTime;
1954
    TTimePartitionSlot timePartitionSlot;
1955
    int index = 0;
1✔
1956
    int size = timeRangeList.size();
1✔
1957

1958
    if (timeRangeList.get(0).getMin() == Long.MIN_VALUE) {
1✔
1959
      needLeftAll = true;
1✔
1960
      endTime = TimePartitionUtils.getTimePartitionUpperBound(timeRangeList.get(0).getMax());
1✔
1961
      timePartitionSlot = TimePartitionUtils.getTimePartitionSlot(timeRangeList.get(0).getMax());
1✔
1962
    } else {
1963
      endTime = TimePartitionUtils.getTimePartitionUpperBound(timeRangeList.get(0).getMin());
1✔
1964
      timePartitionSlot = TimePartitionUtils.getTimePartitionSlot(timeRangeList.get(0).getMin());
1✔
1965
      needLeftAll = false;
1✔
1966
    }
1967

1968
    if (timeRangeList.get(size - 1).getMax() == Long.MAX_VALUE) {
1✔
1969
      needRightAll = true;
1✔
1970
      size--;
1✔
1971
    } else {
1972
      needRightAll = false;
1✔
1973
    }
1974

1975
    List<TTimePartitionSlot> result = new ArrayList<>();
1✔
1976
    while (index < size) {
1✔
1977
      long curLeft = timeRangeList.get(index).getMin();
1✔
1978
      long curRight = timeRangeList.get(index).getMax();
1✔
1979
      if (curLeft >= endTime) {
1✔
1980
        result.add(timePartitionSlot);
1✔
1981
        // next init
1982
        endTime = TimePartitionUtils.getTimePartitionUpperBound(curLeft);
1✔
1983
        timePartitionSlot = TimePartitionUtils.getTimePartitionSlot(curLeft);
1✔
1984
      } else if (curRight >= endTime) {
1✔
1985
        result.add(timePartitionSlot);
1✔
1986
        // next init
1987
        timePartitionSlot = new TTimePartitionSlot(endTime);
1✔
1988
        endTime = endTime + TimePartitionUtils.getTimePartitionInterval();
1✔
1989
      } else {
1990
        index++;
1✔
1991
      }
1992
    }
1✔
1993
    result.add(timePartitionSlot);
1✔
1994

1995
    if (needRightAll) {
1✔
1996
      TTimePartitionSlot lastTimePartitionSlot =
1✔
1997
          TimePartitionUtils.getTimePartitionSlot(
1✔
1998
              timeRangeList.get(timeRangeList.size() - 1).getMin());
1✔
1999
      if (lastTimePartitionSlot.startTime != timePartitionSlot.startTime) {
1✔
2000
        result.add(lastTimePartitionSlot);
×
2001
      }
2002
    }
2003
    return new Pair<>(result, new Pair<>(needLeftAll, needRightAll));
1✔
2004
  }
2005

2006
  private void analyzeInto(
2007
      Analysis analysis,
2008
      QueryStatement queryStatement,
2009
      List<PartialPath> deviceSet,
2010
      List<Pair<Expression, String>> outputExpressions) {
2011
    if (!queryStatement.isSelectInto()) {
1✔
2012
      return;
1✔
2013
    }
2014
    queryStatement.setOrderByComponent(null);
1✔
2015

2016
    List<PartialPath> sourceDevices = new ArrayList<>(deviceSet);
1✔
2017
    List<Expression> sourceColumns =
1✔
2018
        outputExpressions.stream()
1✔
2019
            .map(Pair::getLeft)
1✔
2020
            .collect(Collectors.toCollection(ArrayList::new));
1✔
2021

2022
    IntoComponent intoComponent = queryStatement.getIntoComponent();
1✔
2023
    intoComponent.validate(sourceDevices, sourceColumns);
1✔
2024

2025
    DeviceViewIntoPathDescriptor deviceViewIntoPathDescriptor = new DeviceViewIntoPathDescriptor();
1✔
2026
    PathPatternTree targetPathTree = new PathPatternTree();
1✔
2027
    IntoComponent.IntoDeviceMeasurementIterator intoDeviceMeasurementIterator =
1✔
2028
        intoComponent.getIntoDeviceMeasurementIterator();
1✔
2029
    for (PartialPath sourceDevice : sourceDevices) {
1✔
2030
      PartialPath deviceTemplate = intoDeviceMeasurementIterator.getDeviceTemplate();
1✔
2031
      boolean isAlignedDevice = intoDeviceMeasurementIterator.isAlignedDevice();
1✔
2032
      PartialPath targetDevice = constructTargetDevice(sourceDevice, deviceTemplate);
1✔
2033
      deviceViewIntoPathDescriptor.specifyDeviceAlignment(targetDevice.toString(), isAlignedDevice);
1✔
2034

2035
      for (Expression sourceColumn : sourceColumns) {
1✔
2036
        String measurementTemplate = intoDeviceMeasurementIterator.getMeasurementTemplate();
1✔
2037
        String targetMeasurement;
2038
        if (sourceColumn instanceof TimeSeriesOperand) {
1✔
2039
          targetMeasurement =
1✔
2040
              constructTargetMeasurement(
1✔
2041
                  sourceDevice.concatNode(sourceColumn.getExpressionString()), measurementTemplate);
1✔
2042
        } else {
2043
          targetMeasurement = measurementTemplate;
1✔
2044
        }
2045
        deviceViewIntoPathDescriptor.specifyTargetDeviceMeasurement(
1✔
2046
            sourceDevice, targetDevice, sourceColumn.getExpressionString(), targetMeasurement);
1✔
2047

2048
        targetPathTree.appendFullPath(targetDevice, targetMeasurement);
1✔
2049
        deviceViewIntoPathDescriptor.recordSourceColumnDataType(
1✔
2050
            sourceColumn.getExpressionString(), analysis.getType(sourceColumn));
1✔
2051

2052
        intoDeviceMeasurementIterator.nextMeasurement();
1✔
2053
      }
1✔
2054

2055
      intoDeviceMeasurementIterator.nextDevice();
1✔
2056
    }
1✔
2057
    deviceViewIntoPathDescriptor.validate();
1✔
2058

2059
    // fetch schema of target paths
2060
    long startTime = System.nanoTime();
1✔
2061
    ISchemaTree targetSchemaTree = schemaFetcher.fetchSchema(targetPathTree, null);
1✔
2062
    QueryPlanCostMetricSet.getInstance()
1✔
2063
        .recordPlanCost(SCHEMA_FETCHER, System.nanoTime() - startTime);
1✔
2064
    deviceViewIntoPathDescriptor.bindType(targetSchemaTree);
1✔
2065

2066
    analysis.setDeviceViewIntoPathDescriptor(deviceViewIntoPathDescriptor);
1✔
2067
  }
1✔
2068

2069
  private void analyzeInto(
2070
      Analysis analysis,
2071
      QueryStatement queryStatement,
2072
      List<Pair<Expression, String>> outputExpressions) {
2073
    if (!queryStatement.isSelectInto()) {
1✔
2074
      return;
1✔
2075
    }
2076
    queryStatement.setOrderByComponent(null);
1✔
2077

2078
    List<Expression> sourceColumns =
1✔
2079
        outputExpressions.stream()
1✔
2080
            .map(Pair::getLeft)
1✔
2081
            .collect(Collectors.toCollection(ArrayList::new));
1✔
2082

2083
    IntoComponent intoComponent = queryStatement.getIntoComponent();
1✔
2084
    intoComponent.validate(sourceColumns);
1✔
2085

2086
    IntoPathDescriptor intoPathDescriptor = new IntoPathDescriptor();
1✔
2087
    PathPatternTree targetPathTree = new PathPatternTree();
1✔
2088
    IntoComponent.IntoPathIterator intoPathIterator = intoComponent.getIntoPathIterator();
1✔
2089
    for (Pair<Expression, String> pair : outputExpressions) {
1✔
2090
      Expression sourceExpression = pair.left;
1✔
2091
      String viewPath = pair.right;
1✔
2092
      PartialPath deviceTemplate = intoPathIterator.getDeviceTemplate();
1✔
2093
      String measurementTemplate = intoPathIterator.getMeasurementTemplate();
1✔
2094
      boolean isAlignedDevice = intoPathIterator.isAlignedDevice();
1✔
2095

2096
      PartialPath sourcePath;
2097
      String sourceColumn = sourceExpression.getExpressionString();
1✔
2098
      PartialPath targetPath;
2099
      if (sourceExpression instanceof TimeSeriesOperand) {
1✔
2100
        if (viewPath != null) {
1✔
2101
          try {
2102
            sourcePath = new PartialPath(viewPath);
×
2103
          } catch (IllegalPathException e) {
×
2104
            throw new SemanticException(
×
2105
                String.format(
×
2106
                    "View path %s of source column %s is illegal path", viewPath, sourceColumn));
2107
          }
×
2108
        } else {
2109
          sourcePath = ((TimeSeriesOperand) sourceExpression).getPath();
1✔
2110
        }
2111
        targetPath = constructTargetPath(sourcePath, deviceTemplate, measurementTemplate);
1✔
2112
      } else {
2113
        targetPath = deviceTemplate.concatNode(measurementTemplate);
1✔
2114
      }
2115
      intoPathDescriptor.specifyTargetPath(sourceColumn, viewPath, targetPath);
1✔
2116
      intoPathDescriptor.specifyDeviceAlignment(
1✔
2117
          targetPath.getDevicePath().toString(), isAlignedDevice);
1✔
2118

2119
      targetPathTree.appendFullPath(targetPath);
1✔
2120
      intoPathDescriptor.recordSourceColumnDataType(
1✔
2121
          sourceColumn, analysis.getType(sourceExpression));
1✔
2122

2123
      intoPathIterator.next();
1✔
2124
    }
1✔
2125
    intoPathDescriptor.validate();
1✔
2126

2127
    // fetch schema of target paths
2128
    long startTime = System.nanoTime();
1✔
2129
    ISchemaTree targetSchemaTree = schemaFetcher.fetchSchema(targetPathTree, null);
1✔
2130
    updateSchemaTreeByViews(analysis, targetSchemaTree);
1✔
2131
    QueryPlanCostMetricSet.getInstance()
1✔
2132
        .recordPlanCost(SCHEMA_FETCHER, System.nanoTime() - startTime);
1✔
2133
    intoPathDescriptor.bindType(targetSchemaTree);
1✔
2134

2135
    analysis.setIntoPathDescriptor(intoPathDescriptor);
1✔
2136
  }
1✔
2137

2138
  /**
2139
   * Check datatype consistency in ALIGN BY DEVICE.
2140
   *
2141
   * <p>an inconsistent example: select s0 from root.sg1.d1, root.sg1.d2 align by device, return
2142
   * false while root.sg1.d1.s0 is INT32 and root.sg1.d2.s0 is FLOAT.
2143
   */
2144
  private void checkDataTypeConsistencyInAlignByDevice(
2145
      Analysis analysis, List<Expression> expressions) {
2146
    TSDataType checkedDataType = analysis.getType(expressions.get(0));
1✔
2147
    for (Expression expression : expressions) {
1✔
2148
      if (analysis.getType(expression) != checkedDataType) {
1✔
2149
        throw new SemanticException(
×
2150
            "ALIGN BY DEVICE: the data types of the same measurement column should be the same across devices.");
2151
      }
2152
    }
1✔
2153
  }
1✔
2154

2155
  private void checkAliasUniqueness(String alias, Set<String> aliasSet) {
2156
    if (alias != null) {
1✔
2157
      if (aliasSet.contains(alias)) {
1✔
2158
        throw new SemanticException(
1✔
2159
            String.format("alias '%s' can only be matched with one time series", alias));
1✔
2160
      }
2161
      aliasSet.add(alias);
1✔
2162
    }
2163
  }
1✔
2164

2165
  private void checkAliasUniqueness(
2166
      String alias, Map<Expression, Map<String, Expression>> measurementToDeviceSelectExpressions) {
2167
    if (alias != null && measurementToDeviceSelectExpressions.keySet().size() > 1) {
1✔
2168
      throw new SemanticException(
×
2169
          String.format("alias '%s' can only be matched with one time series", alias));
×
2170
    }
2171
  }
1✔
2172

2173
  @Override
2174
  public Analysis visitInsert(InsertStatement insertStatement, MPPQueryContext context) {
2175
    context.setQueryType(QueryType.WRITE);
1✔
2176
    insertStatement.semanticCheck();
1✔
2177
    long[] timeArray = insertStatement.getTimes();
1✔
2178
    PartialPath devicePath = insertStatement.getDevice();
1✔
2179
    String[] measurementList = insertStatement.getMeasurementList();
1✔
2180
    if (timeArray.length == 1) {
1✔
2181
      // construct insert row statement
2182
      InsertRowStatement insertRowStatement = new InsertRowStatement();
×
2183
      insertRowStatement.setDevicePath(devicePath);
×
2184
      insertRowStatement.setTime(timeArray[0]);
×
2185
      insertRowStatement.setMeasurements(measurementList);
×
2186
      insertRowStatement.setDataTypes(new TSDataType[measurementList.length]);
×
2187
      Object[] values = new Object[measurementList.length];
×
2188
      System.arraycopy(insertStatement.getValuesList().get(0), 0, values, 0, values.length);
×
2189
      insertRowStatement.setValues(values);
×
2190
      insertRowStatement.setNeedInferType(true);
×
2191
      insertRowStatement.setAligned(insertStatement.isAligned());
×
2192
      return insertRowStatement.accept(this, context);
×
2193
    } else {
2194
      // construct insert rows statement
2195
      // construct insert statement
2196
      InsertRowsOfOneDeviceStatement insertRowsOfOneDeviceStatement =
1✔
2197
          new InsertRowsOfOneDeviceStatement();
2198
      List<InsertRowStatement> insertRowStatementList = new ArrayList<>();
1✔
2199
      for (int i = 0; i < timeArray.length; i++) {
1✔
2200
        InsertRowStatement statement = new InsertRowStatement();
1✔
2201
        statement.setDevicePath(devicePath);
1✔
2202
        String[] measurements = new String[measurementList.length];
1✔
2203
        System.arraycopy(measurementList, 0, measurements, 0, measurements.length);
1✔
2204
        statement.setMeasurements(measurements);
1✔
2205
        statement.setTime(timeArray[i]);
1✔
2206
        TSDataType[] dataTypes = new TSDataType[measurementList.length];
1✔
2207
        statement.setDataTypes(dataTypes);
1✔
2208
        Object[] values = new Object[measurementList.length];
1✔
2209
        System.arraycopy(insertStatement.getValuesList().get(i), 0, values, 0, values.length);
1✔
2210
        statement.setValues(values);
1✔
2211
        statement.setAligned(insertStatement.isAligned());
1✔
2212
        statement.setNeedInferType(true);
1✔
2213
        insertRowStatementList.add(statement);
1✔
2214
      }
2215
      insertRowsOfOneDeviceStatement.setInsertRowStatementList(insertRowStatementList);
1✔
2216
      return insertRowsOfOneDeviceStatement.accept(this, context);
1✔
2217
    }
2218
  }
2219

2220
  @Override
2221
  public Analysis visitCreateTimeseries(
2222
      CreateTimeSeriesStatement createTimeSeriesStatement, MPPQueryContext context) {
2223
    context.setQueryType(QueryType.WRITE);
1✔
2224
    if (createTimeSeriesStatement.getPath().getNodeLength() < 3) {
1✔
2225
      throw new SemanticException(
×
2226
          new IllegalPathException(createTimeSeriesStatement.getPath().getFullPath()));
×
2227
    }
2228
    analyzeSchemaProps(createTimeSeriesStatement.getProps());
1✔
2229
    if (createTimeSeriesStatement.getTags() != null
1✔
2230
        && !createTimeSeriesStatement.getTags().isEmpty()
1✔
2231
        && createTimeSeriesStatement.getAttributes() != null
1✔
2232
        && !createTimeSeriesStatement.getAttributes().isEmpty()) {
1✔
2233
      for (String tagKey : createTimeSeriesStatement.getTags().keySet()) {
1✔
2234
        if (createTimeSeriesStatement.getAttributes().containsKey(tagKey)) {
1✔
2235
          throw new SemanticException(
1✔
2236
              String.format("Tag and attribute shouldn't have the same property key [%s]", tagKey));
1✔
2237
        }
2238
      }
×
2239
    }
2240

2241
    Analysis analysis = new Analysis();
×
2242
    analysis.setStatement(createTimeSeriesStatement);
×
2243

2244
    checkIsTemplateCompatible(
×
2245
        createTimeSeriesStatement.getPath(), createTimeSeriesStatement.getAlias());
×
2246

2247
    PathPatternTree patternTree = new PathPatternTree();
×
2248
    patternTree.appendFullPath(createTimeSeriesStatement.getPath());
×
2249
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2250
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2251
    return analysis;
×
2252
  }
2253

2254
  private void checkIsTemplateCompatible(PartialPath timeseriesPath, String alias) {
2255
    Pair<Template, PartialPath> templateInfo =
×
2256
        schemaFetcher.checkTemplateSetAndPreSetInfo(timeseriesPath, alias);
×
2257
    if (templateInfo != null) {
×
2258
      throw new SemanticException(
×
2259
          new TemplateIncompatibleException(
2260
              timeseriesPath.getFullPath(), templateInfo.left.getName(), templateInfo.right));
×
2261
    }
2262
  }
×
2263

2264
  private void checkIsTemplateCompatible(
2265
      PartialPath devicePath, List<String> measurements, List<String> aliasList) {
2266
    for (int i = 0; i < measurements.size(); i++) {
×
2267
      Pair<Template, PartialPath> templateInfo =
×
2268
          schemaFetcher.checkTemplateSetAndPreSetInfo(
×
2269
              devicePath.concatNode(measurements.get(i)),
×
2270
              aliasList == null ? null : aliasList.get(i));
×
2271
      if (templateInfo != null) {
×
2272
        throw new SemanticException(
×
2273
            new TemplateIncompatibleException(
2274
                devicePath.getFullPath() + measurements,
×
2275
                templateInfo.left.getName(),
×
2276
                templateInfo.right));
2277
      }
2278
    }
2279
  }
×
2280

2281
  private void analyzeSchemaProps(Map<String, String> props) {
2282
    if (props == null || props.isEmpty()) {
1✔
2283
      return;
1✔
2284
    }
2285
    Map<String, String> caseChangeMap = new HashMap<>();
×
2286
    for (String key : props.keySet()) {
×
2287
      caseChangeMap.put(key.toLowerCase(Locale.ROOT), key);
×
2288
    }
×
2289
    for (Map.Entry<String, String> caseChangeEntry : caseChangeMap.entrySet()) {
×
2290
      String lowerCaseKey = caseChangeEntry.getKey();
×
2291
      if (!ALLOWED_SCHEMA_PROPS.contains(lowerCaseKey)) {
×
2292
        throw new SemanticException(
×
2293
            new MetadataException(
2294
                String.format("%s is not a legal prop.", caseChangeEntry.getValue())));
×
2295
      }
2296
      props.put(lowerCaseKey, props.remove(caseChangeEntry.getValue()));
×
2297
    }
×
2298
    if (props.containsKey(DEADBAND)) {
×
2299
      props.put(LOSS, props.remove(DEADBAND));
×
2300
    }
2301
  }
×
2302

2303
  private void analyzeSchemaProps(List<Map<String, String>> propsList) {
2304
    if (propsList == null) {
×
2305
      return;
×
2306
    }
2307
    for (Map<String, String> props : propsList) {
×
2308
      analyzeSchemaProps(props);
×
2309
    }
×
2310
  }
×
2311

2312
  @Override
2313
  public Analysis visitCreateAlignedTimeseries(
2314
      CreateAlignedTimeSeriesStatement createAlignedTimeSeriesStatement, MPPQueryContext context) {
2315
    context.setQueryType(QueryType.WRITE);
1✔
2316
    if (createAlignedTimeSeriesStatement.getDevicePath().getNodeLength() < 2) {
1✔
2317
      throw new SemanticException(
×
2318
          new IllegalPathException(createAlignedTimeSeriesStatement.getDevicePath().getFullPath()));
×
2319
    }
2320
    List<String> measurements = createAlignedTimeSeriesStatement.getMeasurements();
1✔
2321
    Set<String> measurementsSet = new HashSet<>(measurements);
1✔
2322
    if (measurementsSet.size() < measurements.size()) {
1✔
2323
      throw new SemanticException(
1✔
2324
          "Measurement under an aligned device is not allowed to have the same measurement name");
2325
    }
2326

2327
    Analysis analysis = new Analysis();
×
2328
    analysis.setStatement(createAlignedTimeSeriesStatement);
×
2329

2330
    checkIsTemplateCompatible(
×
2331
        createAlignedTimeSeriesStatement.getDevicePath(),
×
2332
        createAlignedTimeSeriesStatement.getMeasurements(),
×
2333
        createAlignedTimeSeriesStatement.getAliasList());
×
2334

2335
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2336
    for (String measurement : createAlignedTimeSeriesStatement.getMeasurements()) {
×
2337
      pathPatternTree.appendFullPath(createAlignedTimeSeriesStatement.getDevicePath(), measurement);
×
2338
    }
×
2339

2340
    SchemaPartition schemaPartitionInfo;
2341
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2342
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2343
    return analysis;
×
2344
  }
2345

2346
  @Override
2347
  public Analysis visitInternalCreateTimeseries(
2348
      InternalCreateTimeSeriesStatement internalCreateTimeSeriesStatement,
2349
      MPPQueryContext context) {
2350
    context.setQueryType(QueryType.WRITE);
×
2351

2352
    Analysis analysis = new Analysis();
×
2353
    analysis.setStatement(internalCreateTimeSeriesStatement);
×
2354

2355
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2356
    for (String measurement : internalCreateTimeSeriesStatement.getMeasurements()) {
×
2357
      pathPatternTree.appendFullPath(
×
2358
          internalCreateTimeSeriesStatement.getDevicePath(), measurement);
×
2359
    }
×
2360

2361
    SchemaPartition schemaPartitionInfo;
2362
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2363
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2364
    return analysis;
×
2365
  }
2366

2367
  @Override
2368
  public Analysis visitInternalCreateMultiTimeSeries(
2369
      InternalCreateMultiTimeSeriesStatement internalCreateMultiTimeSeriesStatement,
2370
      MPPQueryContext context) {
2371
    context.setQueryType(QueryType.WRITE);
×
2372

2373
    Analysis analysis = new Analysis();
×
2374
    analysis.setStatement(internalCreateMultiTimeSeriesStatement);
×
2375

2376
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2377
    for (PartialPath devicePath : internalCreateMultiTimeSeriesStatement.getDeviceMap().keySet()) {
×
2378
      pathPatternTree.appendFullPath(devicePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
2379
    }
×
2380

2381
    SchemaPartition schemaPartitionInfo;
2382
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2383
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2384
    return analysis;
×
2385
  }
2386

2387
  @Override
2388
  public Analysis visitCreateMultiTimeseries(
2389
      CreateMultiTimeSeriesStatement createMultiTimeSeriesStatement, MPPQueryContext context) {
2390
    context.setQueryType(QueryType.WRITE);
×
2391
    Analysis analysis = new Analysis();
×
2392
    analysis.setStatement(createMultiTimeSeriesStatement);
×
2393

2394
    analyzeSchemaProps(createMultiTimeSeriesStatement.getPropsList());
×
2395

2396
    List<PartialPath> timeseriesPathList = createMultiTimeSeriesStatement.getPaths();
×
2397
    List<String> aliasList = createMultiTimeSeriesStatement.getAliasList();
×
2398
    for (int i = 0; i < timeseriesPathList.size(); i++) {
×
2399
      checkIsTemplateCompatible(
×
2400
          timeseriesPathList.get(i), aliasList == null ? null : aliasList.get(i));
×
2401
    }
2402

2403
    PathPatternTree patternTree = new PathPatternTree();
×
2404
    for (PartialPath path : createMultiTimeSeriesStatement.getPaths()) {
×
2405
      patternTree.appendFullPath(path);
×
2406
    }
×
2407
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2408
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2409
    return analysis;
×
2410
  }
2411

2412
  @Override
2413
  public Analysis visitAlterTimeseries(
2414
      AlterTimeSeriesStatement alterTimeSeriesStatement, MPPQueryContext context) {
2415
    context.setQueryType(QueryType.WRITE);
×
2416
    Analysis analysis = new Analysis();
×
2417
    analysis.setStatement(alterTimeSeriesStatement);
×
2418

2419
    Pair<Template, PartialPath> templateInfo =
×
2420
        schemaFetcher.checkTemplateSetAndPreSetInfo(
×
2421
            alterTimeSeriesStatement.getPath(), alterTimeSeriesStatement.getAlias());
×
2422
    if (templateInfo != null) {
×
2423
      throw new RuntimeException(
×
2424
          new TemplateIncompatibleException(
2425
              String.format(
×
2426
                  "Cannot alter template timeseries [%s] since schema template [%s] already set on path [%s].",
2427
                  alterTimeSeriesStatement.getPath().getFullPath(),
×
2428
                  templateInfo.left.getName(),
×
2429
                  templateInfo.right)));
2430
    }
2431

2432
    PathPatternTree patternTree = new PathPatternTree();
×
2433
    patternTree.appendFullPath(alterTimeSeriesStatement.getPath());
×
2434
    SchemaPartition schemaPartitionInfo;
2435
    schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2436
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2437
    return analysis;
×
2438
  }
2439

2440
  @Override
2441
  public Analysis visitInsertTablet(
2442
      InsertTabletStatement insertTabletStatement, MPPQueryContext context) {
2443
    context.setQueryType(QueryType.WRITE);
×
2444
    Analysis analysis = new Analysis();
×
2445
    validateSchema(analysis, insertTabletStatement, context);
×
2446
    InsertBaseStatement realStatement = removeLogicalView(analysis, insertTabletStatement);
×
2447
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2448
      return analysis;
×
2449
    }
2450
    analysis.setStatement(realStatement);
×
2451

2452
    if (realStatement instanceof InsertTabletStatement) {
×
2453
      InsertTabletStatement realInsertTabletStatement = (InsertTabletStatement) realStatement;
×
2454
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2455
      dataPartitionQueryParam.setDevicePath(
×
2456
          realInsertTabletStatement.getDevicePath().getFullPath());
×
2457
      dataPartitionQueryParam.setTimePartitionSlotList(
×
2458
          realInsertTabletStatement.getTimePartitionSlots());
×
2459

2460
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
×
2461
    } else {
2462
      return computeAnalysisForMultiTablets(analysis, (InsertMultiTabletsStatement) realStatement);
×
2463
    }
2464
  }
2465

2466
  @Override
2467
  public Analysis visitInsertRow(InsertRowStatement insertRowStatement, MPPQueryContext context) {
2468
    context.setQueryType(QueryType.WRITE);
×
2469
    Analysis analysis = new Analysis();
×
2470
    validateSchema(analysis, insertRowStatement, context);
×
2471
    InsertBaseStatement realInsertStatement = removeLogicalView(analysis, insertRowStatement);
×
2472
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2473
      return analysis;
×
2474
    }
2475
    analysis.setStatement(realInsertStatement);
×
2476

2477
    if (realInsertStatement instanceof InsertRowStatement) {
×
2478
      InsertRowStatement realInsertRowStatement = (InsertRowStatement) realInsertStatement;
×
2479
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2480
      dataPartitionQueryParam.setDevicePath(realInsertRowStatement.getDevicePath().getFullPath());
×
2481
      dataPartitionQueryParam.setTimePartitionSlotList(
×
2482
          Collections.singletonList(realInsertRowStatement.getTimePartitionSlot()));
×
2483

2484
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
×
2485
    } else {
2486
      return computeAnalysisForInsertRows(analysis, (InsertRowsStatement) realInsertStatement);
×
2487
    }
2488
  }
2489

2490
  private Analysis computeAnalysisForInsertRows(
2491
      Analysis analysis, InsertRowsStatement insertRowsStatement) {
2492
    Map<String, Set<TTimePartitionSlot>> dataPartitionQueryParamMap = new HashMap<>();
×
2493
    for (InsertRowStatement insertRowStatement : insertRowsStatement.getInsertRowStatementList()) {
×
2494
      Set<TTimePartitionSlot> timePartitionSlotSet =
×
2495
          dataPartitionQueryParamMap.computeIfAbsent(
×
2496
              insertRowStatement.getDevicePath().getFullPath(), k -> new HashSet<>());
×
2497
      timePartitionSlotSet.add(insertRowStatement.getTimePartitionSlot());
×
2498
    }
×
2499

2500
    List<DataPartitionQueryParam> dataPartitionQueryParams = new ArrayList<>();
×
2501
    for (Map.Entry<String, Set<TTimePartitionSlot>> entry : dataPartitionQueryParamMap.entrySet()) {
×
2502
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2503
      dataPartitionQueryParam.setDevicePath(entry.getKey());
×
2504
      dataPartitionQueryParam.setTimePartitionSlotList(new ArrayList<>(entry.getValue()));
×
2505
      dataPartitionQueryParams.add(dataPartitionQueryParam);
×
2506
    }
×
2507

2508
    return getAnalysisForWriting(analysis, dataPartitionQueryParams);
×
2509
  }
2510

2511
  @Override
2512
  public Analysis visitInsertRows(
2513
      InsertRowsStatement insertRowsStatement, MPPQueryContext context) {
2514
    context.setQueryType(QueryType.WRITE);
×
2515
    Analysis analysis = new Analysis();
×
2516
    validateSchema(analysis, insertRowsStatement, context);
×
2517
    InsertRowsStatement realInsertRowsStatement =
×
2518
        (InsertRowsStatement) removeLogicalView(analysis, insertRowsStatement);
×
2519
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2520
      return analysis;
×
2521
    }
2522
    analysis.setStatement(realInsertRowsStatement);
×
2523

2524
    return computeAnalysisForInsertRows(analysis, realInsertRowsStatement);
×
2525
  }
2526

2527
  private Analysis computeAnalysisForMultiTablets(
2528
      Analysis analysis, InsertMultiTabletsStatement insertMultiTabletsStatement) {
2529
    Map<String, Set<TTimePartitionSlot>> dataPartitionQueryParamMap = new HashMap<>();
×
2530
    for (InsertTabletStatement insertTabletStatement :
2531
        insertMultiTabletsStatement.getInsertTabletStatementList()) {
×
2532
      Set<TTimePartitionSlot> timePartitionSlotSet =
×
2533
          dataPartitionQueryParamMap.computeIfAbsent(
×
2534
              insertTabletStatement.getDevicePath().getFullPath(), k -> new HashSet<>());
×
2535
      timePartitionSlotSet.addAll(insertTabletStatement.getTimePartitionSlots());
×
2536
    }
×
2537

2538
    List<DataPartitionQueryParam> dataPartitionQueryParams = new ArrayList<>();
×
2539
    for (Map.Entry<String, Set<TTimePartitionSlot>> entry : dataPartitionQueryParamMap.entrySet()) {
×
2540
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2541
      dataPartitionQueryParam.setDevicePath(entry.getKey());
×
2542
      dataPartitionQueryParam.setTimePartitionSlotList(new ArrayList<>(entry.getValue()));
×
2543
      dataPartitionQueryParams.add(dataPartitionQueryParam);
×
2544
    }
×
2545

2546
    return getAnalysisForWriting(analysis, dataPartitionQueryParams);
×
2547
  }
2548

2549
  @Override
2550
  public Analysis visitInsertMultiTablets(
2551
      InsertMultiTabletsStatement insertMultiTabletsStatement, MPPQueryContext context) {
2552
    context.setQueryType(QueryType.WRITE);
×
2553
    Analysis analysis = new Analysis();
×
2554
    validateSchema(analysis, insertMultiTabletsStatement, context);
×
2555
    InsertMultiTabletsStatement realStatement =
×
2556
        (InsertMultiTabletsStatement) removeLogicalView(analysis, insertMultiTabletsStatement);
×
2557
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2558
      return analysis;
×
2559
    }
2560
    analysis.setStatement(realStatement);
×
2561

2562
    return computeAnalysisForMultiTablets(analysis, realStatement);
×
2563
  }
2564

2565
  @Override
2566
  public Analysis visitInsertRowsOfOneDevice(
2567
      InsertRowsOfOneDeviceStatement insertRowsOfOneDeviceStatement, MPPQueryContext context) {
2568
    context.setQueryType(QueryType.WRITE);
1✔
2569
    Analysis analysis = new Analysis();
1✔
2570
    validateSchema(analysis, insertRowsOfOneDeviceStatement, context);
1✔
2571
    InsertBaseStatement realInsertStatement =
1✔
2572
        removeLogicalView(analysis, insertRowsOfOneDeviceStatement);
1✔
2573
    if (analysis.isFinishQueryAfterAnalyze()) {
1✔
2574
      return analysis;
×
2575
    }
2576
    analysis.setStatement(realInsertStatement);
1✔
2577

2578
    if (realInsertStatement instanceof InsertRowsOfOneDeviceStatement) {
1✔
2579
      InsertRowsOfOneDeviceStatement realStatement =
1✔
2580
          (InsertRowsOfOneDeviceStatement) realInsertStatement;
2581
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
1✔
2582
      dataPartitionQueryParam.setDevicePath(realStatement.getDevicePath().getFullPath());
1✔
2583
      dataPartitionQueryParam.setTimePartitionSlotList(realStatement.getTimePartitionSlots());
1✔
2584

2585
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
1✔
2586
    } else {
2587
      return computeAnalysisForInsertRows(analysis, (InsertRowsStatement) realInsertStatement);
×
2588
    }
2589
  }
2590

2591
  @Override
2592
  public Analysis visitPipeEnrichedInsert(
2593
      PipeEnrichedInsertBaseStatement pipeEnrichedInsertBaseStatement, MPPQueryContext context) {
2594
    Analysis analysis;
2595

2596
    final InsertBaseStatement insertBaseStatement =
×
2597
        pipeEnrichedInsertBaseStatement.getInsertBaseStatement();
×
2598
    if (insertBaseStatement instanceof InsertTabletStatement) {
×
2599
      analysis = visitInsertTablet((InsertTabletStatement) insertBaseStatement, context);
×
2600
    } else if (insertBaseStatement instanceof InsertMultiTabletsStatement) {
×
2601
      analysis =
×
2602
          visitInsertMultiTablets((InsertMultiTabletsStatement) insertBaseStatement, context);
×
2603
    } else if (insertBaseStatement instanceof InsertRowStatement) {
×
2604
      analysis = visitInsertRow((InsertRowStatement) insertBaseStatement, context);
×
2605
    } else if (insertBaseStatement instanceof InsertRowsStatement) {
×
2606
      analysis = visitInsertRows((InsertRowsStatement) insertBaseStatement, context);
×
2607
    } else if (insertBaseStatement instanceof InsertRowsOfOneDeviceStatement) {
×
2608
      analysis =
×
2609
          visitInsertRowsOfOneDevice((InsertRowsOfOneDeviceStatement) insertBaseStatement, context);
×
2610
    } else {
2611
      throw new UnsupportedOperationException(
×
2612
          "Unsupported insert statement type: " + insertBaseStatement.getClass().getName());
×
2613
    }
2614

2615
    // statement may be changed because of logical view
2616
    pipeEnrichedInsertBaseStatement.setInsertBaseStatement(
×
2617
        (InsertBaseStatement) analysis.getStatement());
×
2618
    analysis.setStatement(pipeEnrichedInsertBaseStatement);
×
2619
    return analysis;
×
2620
  }
2621

2622
  private void validateSchema(
2623
      Analysis analysis, InsertBaseStatement insertStatement, MPPQueryContext context) {
2624
    final long startTime = System.nanoTime();
1✔
2625
    try {
2626
      SchemaValidator.validate(schemaFetcher, insertStatement, context);
1✔
2627
    } catch (SemanticException e) {
×
2628
      analysis.setFinishQueryAfterAnalyze(true);
×
2629
      if (e.getCause() instanceof IoTDBException) {
×
2630
        IoTDBException exception = (IoTDBException) e.getCause();
×
2631
        analysis.setFailStatus(
×
2632
            RpcUtils.getStatus(exception.getErrorCode(), exception.getMessage()));
×
2633
      } else {
×
2634
        analysis.setFailStatus(RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage()));
×
2635
      }
2636
    } finally {
2637
      PERFORMANCE_OVERVIEW_METRICS.recordScheduleSchemaValidateCost(System.nanoTime() - startTime);
1✔
2638
    }
2639
    boolean hasFailedMeasurement = insertStatement.hasFailedMeasurements();
1✔
2640
    String partialInsertMessage;
2641
    if (hasFailedMeasurement) {
1✔
2642
      partialInsertMessage =
×
2643
          String.format(
×
2644
              "Fail to insert measurements %s caused by %s",
2645
              insertStatement.getFailedMeasurements(), insertStatement.getFailedMessages());
×
2646
      logger.warn(partialInsertMessage);
×
2647
      analysis.setFailStatus(
×
2648
          RpcUtils.getStatus(TSStatusCode.METADATA_ERROR.getStatusCode(), partialInsertMessage));
×
2649
    }
2650
  }
1✔
2651

2652
  private InsertBaseStatement removeLogicalView(
2653
      Analysis analysis, InsertBaseStatement insertBaseStatement) {
2654
    try {
2655
      return insertBaseStatement.removeLogicalView();
1✔
2656
    } catch (SemanticException e) {
×
2657
      analysis.setFinishQueryAfterAnalyze(true);
×
2658
      if (e.getCause() instanceof IoTDBException) {
×
2659
        IoTDBException exception = (IoTDBException) e.getCause();
×
2660
        analysis.setFailStatus(
×
2661
            RpcUtils.getStatus(exception.getErrorCode(), exception.getMessage()));
×
2662
      } else {
×
2663
        analysis.setFailStatus(RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage()));
×
2664
      }
2665
      return insertBaseStatement;
×
2666
    }
2667
  }
2668

2669
  @Override
2670
  public Analysis visitLoadFile(LoadTsFileStatement loadTsFileStatement, MPPQueryContext context) {
2671
    return new LoadTsfileAnalyzer(loadTsFileStatement, context, partitionFetcher, schemaFetcher)
×
2672
        .analyzeFileByFile();
×
2673
  }
2674

2675
  @Override
2676
  public Analysis visitPipeEnrichedLoadFile(
2677
      PipeEnrichedLoadTsFileStatement pipeEnrichedLoadTsFileStatement, MPPQueryContext context) {
2678
    final Analysis analysis =
×
2679
        visitLoadFile(pipeEnrichedLoadTsFileStatement.getLoadTsFileStatement(), context);
×
2680
    analysis.setStatement(pipeEnrichedLoadTsFileStatement);
×
2681
    return analysis;
×
2682
  }
2683

2684
  /** get analysis according to statement and params */
2685
  private Analysis getAnalysisForWriting(
2686
      Analysis analysis, List<DataPartitionQueryParam> dataPartitionQueryParams) {
2687

2688
    DataPartition dataPartition =
1✔
2689
        partitionFetcher.getOrCreateDataPartition(dataPartitionQueryParams);
1✔
2690
    if (dataPartition.isEmpty()) {
1✔
2691
      analysis.setFinishQueryAfterAnalyze(true);
×
2692
      analysis.setFailStatus(
×
2693
          RpcUtils.getStatus(
×
2694
              TSStatusCode.DATABASE_NOT_EXIST.getStatusCode(),
×
2695
              "Database not exists and failed to create automatically "
2696
                  + "because enable_auto_create_schema is FALSE."));
2697
    }
2698
    analysis.setDataPartitionInfo(dataPartition);
1✔
2699
    return analysis;
1✔
2700
  }
2701

2702
  @Override
2703
  public Analysis visitShowTimeSeries(
2704
      ShowTimeSeriesStatement showTimeSeriesStatement, MPPQueryContext context) {
2705
    Analysis analysis = new Analysis();
×
2706
    analysis.setStatement(showTimeSeriesStatement);
×
2707

2708
    PathPatternTree patternTree = new PathPatternTree();
×
2709
    patternTree.appendPathPattern(showTimeSeriesStatement.getPathPattern());
×
2710
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2711
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2712

2713
    Map<Integer, Template> templateMap =
×
2714
        schemaFetcher.checkAllRelatedTemplate(showTimeSeriesStatement.getPathPattern());
×
2715
    analysis.setRelatedTemplateInfo(templateMap);
×
2716

2717
    if (showTimeSeriesStatement.isOrderByHeat()) {
×
2718
      patternTree.constructTree();
×
2719
      // request schema fetch API
2720
      logger.debug("[StartFetchSchema]");
×
2721
      ISchemaTree schemaTree = schemaFetcher.fetchSchema(patternTree, context);
×
2722
      updateSchemaTreeByViews(analysis, schemaTree);
×
2723
      logger.debug("[EndFetchSchema]]");
×
2724

2725
      analyzeLastSource(
×
2726
          analysis,
2727
          Collections.singletonList(
×
2728
              new TimeSeriesOperand(showTimeSeriesStatement.getPathPattern())),
×
2729
          schemaTree);
2730
      analyzeDataPartition(analysis, new QueryStatement(), schemaTree);
×
2731
    }
2732

2733
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTimeSeriesHeader());
×
2734
    return analysis;
×
2735
  }
2736

2737
  @Override
2738
  public Analysis visitShowStorageGroup(
2739
      ShowDatabaseStatement showDatabaseStatement, MPPQueryContext context) {
2740
    Analysis analysis = new Analysis();
×
2741
    analysis.setStatement(showDatabaseStatement);
×
2742
    analysis.setRespDatasetHeader(
×
2743
        DatasetHeaderFactory.getShowStorageGroupHeader(showDatabaseStatement.isDetailed()));
×
2744
    return analysis;
×
2745
  }
2746

2747
  @Override
2748
  public Analysis visitShowTTL(ShowTTLStatement showTTLStatement, MPPQueryContext context) {
2749
    Analysis analysis = new Analysis();
×
2750
    analysis.setStatement(showTTLStatement);
×
2751
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTTLHeader());
×
2752
    return analysis;
×
2753
  }
2754

2755
  @Override
2756
  public Analysis visitShowDevices(
2757
      ShowDevicesStatement showDevicesStatement, MPPQueryContext context) {
2758
    Analysis analysis = new Analysis();
×
2759
    analysis.setStatement(showDevicesStatement);
×
2760

2761
    PathPatternTree patternTree = new PathPatternTree();
×
2762
    patternTree.appendPathPattern(
×
2763
        showDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD));
×
2764
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2765

2766
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2767
    analysis.setRespDatasetHeader(
×
2768
        showDevicesStatement.hasSgCol()
×
2769
            ? DatasetHeaderFactory.getShowDevicesWithSgHeader()
×
2770
            : DatasetHeaderFactory.getShowDevicesHeader());
×
2771
    return analysis;
×
2772
  }
2773

2774
  @Override
2775
  public Analysis visitShowCluster(
2776
      ShowClusterStatement showClusterStatement, MPPQueryContext context) {
2777
    Analysis analysis = new Analysis();
×
2778
    analysis.setStatement(showClusterStatement);
×
2779
    if (showClusterStatement.isDetails()) {
×
2780
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowClusterDetailsHeader());
×
2781
    } else {
2782
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowClusterHeader());
×
2783
    }
2784
    return analysis;
×
2785
  }
2786

2787
  @Override
2788
  public Analysis visitCountStorageGroup(
2789
      CountDatabaseStatement countDatabaseStatement, MPPQueryContext context) {
2790
    Analysis analysis = new Analysis();
×
2791
    analysis.setStatement(countDatabaseStatement);
×
2792
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountStorageGroupHeader());
×
2793
    return analysis;
×
2794
  }
2795

2796
  @Override
2797
  public Analysis visitSchemaFetch(
2798
      SchemaFetchStatement schemaFetchStatement, MPPQueryContext context) {
2799
    Analysis analysis = new Analysis();
×
2800
    analysis.setStatement(schemaFetchStatement);
×
2801

2802
    SchemaPartition schemaPartition =
×
2803
        partitionFetcher.getSchemaPartition(schemaFetchStatement.getPatternTree());
×
2804
    analysis.setSchemaPartitionInfo(schemaPartition);
×
2805

2806
    if (schemaPartition.isEmpty()) {
×
2807
      analysis.setFinishQueryAfterAnalyze(true);
×
2808
    }
2809

2810
    return analysis;
×
2811
  }
2812

2813
  @Override
2814
  public Analysis visitCountDevices(
2815
      CountDevicesStatement countDevicesStatement, MPPQueryContext context) {
2816
    Analysis analysis = new Analysis();
×
2817
    analysis.setStatement(countDevicesStatement);
×
2818

2819
    PathPatternTree patternTree = new PathPatternTree();
×
2820
    patternTree.appendPathPattern(
×
2821
        countDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD));
×
2822
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2823

2824
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2825
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountDevicesHeader());
×
2826
    return analysis;
×
2827
  }
2828

2829
  @Override
2830
  public Analysis visitCountTimeSeries(
2831
      CountTimeSeriesStatement countTimeSeriesStatement, MPPQueryContext context) {
2832
    Analysis analysis = new Analysis();
×
2833
    analysis.setStatement(countTimeSeriesStatement);
×
2834

2835
    PathPatternTree patternTree = new PathPatternTree();
×
2836
    patternTree.appendPathPattern(countTimeSeriesStatement.getPathPattern());
×
2837
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2838
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2839

2840
    Map<Integer, Template> templateMap =
×
2841
        schemaFetcher.checkAllRelatedTemplate(countTimeSeriesStatement.getPathPattern());
×
2842
    analysis.setRelatedTemplateInfo(templateMap);
×
2843

2844
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountTimeSeriesHeader());
×
2845
    return analysis;
×
2846
  }
2847

2848
  @Override
2849
  public Analysis visitCountLevelTimeSeries(
2850
      CountLevelTimeSeriesStatement countLevelTimeSeriesStatement, MPPQueryContext context) {
2851
    Analysis analysis = new Analysis();
×
2852
    analysis.setStatement(countLevelTimeSeriesStatement);
×
2853

2854
    PathPatternTree patternTree = new PathPatternTree();
×
2855
    patternTree.appendPathPattern(countLevelTimeSeriesStatement.getPathPattern());
×
2856
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2857

2858
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2859
    Map<Integer, Template> templateMap =
×
2860
        schemaFetcher.checkAllRelatedTemplate(countLevelTimeSeriesStatement.getPathPattern());
×
2861
    analysis.setRelatedTemplateInfo(templateMap);
×
2862
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountLevelTimeSeriesHeader());
×
2863
    return analysis;
×
2864
  }
2865

2866
  @Override
2867
  public Analysis visitCountNodes(CountNodesStatement countStatement, MPPQueryContext context) {
2868
    Analysis analysis = new Analysis();
×
2869
    analysis.setStatement(countStatement);
×
2870

2871
    PathPatternTree patternTree = new PathPatternTree();
×
2872
    patternTree.appendPathPattern(countStatement.getPathPattern());
×
2873
    SchemaNodeManagementPartition schemaNodeManagementPartition =
×
2874
        partitionFetcher.getSchemaNodeManagementPartitionWithLevel(
×
2875
            patternTree, countStatement.getLevel());
×
2876

2877
    if (schemaNodeManagementPartition == null) {
×
2878
      return analysis;
×
2879
    }
2880
    if (!schemaNodeManagementPartition.getMatchedNode().isEmpty()
×
2881
        && schemaNodeManagementPartition.getSchemaPartition().getSchemaPartitionMap().size() == 0) {
×
2882
      analysis.setFinishQueryAfterAnalyze(true);
×
2883
    }
2884
    analysis.setMatchedNodes(schemaNodeManagementPartition.getMatchedNode());
×
2885
    analysis.setSchemaPartitionInfo(schemaNodeManagementPartition.getSchemaPartition());
×
2886
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountNodesHeader());
×
2887
    return analysis;
×
2888
  }
2889

2890
  @Override
2891
  public Analysis visitShowChildPaths(
2892
      ShowChildPathsStatement showChildPathsStatement, MPPQueryContext context) {
2893
    return visitSchemaNodeManagementPartition(
×
2894
        showChildPathsStatement,
2895
        showChildPathsStatement.getPartialPath(),
×
2896
        DatasetHeaderFactory.getShowChildPathsHeader());
×
2897
  }
2898

2899
  @Override
2900
  public Analysis visitShowChildNodes(
2901
      ShowChildNodesStatement showChildNodesStatement, MPPQueryContext context) {
2902
    return visitSchemaNodeManagementPartition(
×
2903
        showChildNodesStatement,
2904
        showChildNodesStatement.getPartialPath(),
×
2905
        DatasetHeaderFactory.getShowChildNodesHeader());
×
2906
  }
2907

2908
  @Override
2909
  public Analysis visitShowVersion(
2910
      ShowVersionStatement showVersionStatement, MPPQueryContext context) {
2911
    Analysis analysis = new Analysis();
×
2912
    analysis.setStatement(showVersionStatement);
×
2913
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowVersionHeader());
×
2914
    analysis.setFinishQueryAfterAnalyze(true);
×
2915
    return analysis;
×
2916
  }
2917

2918
  private Analysis visitSchemaNodeManagementPartition(
2919
      Statement statement, PartialPath path, DatasetHeader header) {
2920
    Analysis analysis = new Analysis();
×
2921
    analysis.setStatement(statement);
×
2922

2923
    PathPatternTree patternTree = new PathPatternTree();
×
2924
    patternTree.appendPathPattern(path);
×
2925
    SchemaNodeManagementPartition schemaNodeManagementPartition =
×
2926
        partitionFetcher.getSchemaNodeManagementPartition(patternTree);
×
2927

2928
    if (schemaNodeManagementPartition == null) {
×
2929
      return analysis;
×
2930
    }
2931
    if (!schemaNodeManagementPartition.getMatchedNode().isEmpty()
×
2932
        && schemaNodeManagementPartition.getSchemaPartition().getSchemaPartitionMap().size() == 0) {
×
2933
      analysis.setFinishQueryAfterAnalyze(true);
×
2934
    }
2935
    analysis.setMatchedNodes(schemaNodeManagementPartition.getMatchedNode());
×
2936
    analysis.setSchemaPartitionInfo(schemaNodeManagementPartition.getSchemaPartition());
×
2937
    analysis.setRespDatasetHeader(header);
×
2938
    return analysis;
×
2939
  }
2940

2941
  @Override
2942
  public Analysis visitDeleteData(
2943
      DeleteDataStatement deleteDataStatement, MPPQueryContext context) {
2944
    context.setQueryType(QueryType.WRITE);
×
2945
    Analysis analysis = new Analysis();
×
2946
    analysis.setStatement(deleteDataStatement);
×
2947

2948
    PathPatternTree patternTree = new PathPatternTree();
×
2949
    deleteDataStatement.getPathList().forEach(patternTree::appendPathPattern);
×
2950

2951
    ISchemaTree schemaTree = schemaFetcher.fetchSchema(patternTree, context);
×
2952
    Set<String> deduplicatedDevicePaths = new HashSet<>();
×
2953

2954
    if (schemaTree.hasLogicalViewMeasurement()) {
×
2955
      updateSchemaTreeByViews(analysis, schemaTree);
×
2956

2957
      Set<PartialPath> deletePatternSet = new HashSet<>(deleteDataStatement.getPathList());
×
2958
      IMeasurementSchema measurementSchema;
2959
      LogicalViewSchema logicalViewSchema;
2960
      PartialPath sourcePathOfAliasSeries;
2961
      for (MeasurementPath measurementPath :
2962
          schemaTree.searchMeasurementPaths(SchemaConstant.ALL_MATCH_PATTERN).left) {
×
2963
        measurementSchema = measurementPath.getMeasurementSchema();
×
2964
        if (measurementSchema.isLogicalView()) {
×
2965
          logicalViewSchema = (LogicalViewSchema) measurementSchema;
×
2966
          if (logicalViewSchema.isWritable()) {
×
2967
            sourcePathOfAliasSeries = logicalViewSchema.getSourcePathIfWritable();
×
2968
            deletePatternSet.add(sourcePathOfAliasSeries);
×
2969
            deduplicatedDevicePaths.add(sourcePathOfAliasSeries.getDevice());
×
2970
          }
2971
          deletePatternSet.remove(measurementPath);
×
2972
        } else {
2973
          deduplicatedDevicePaths.add(measurementPath.getDevice());
×
2974
        }
2975
      }
×
2976
      deleteDataStatement.setPathList(new ArrayList<>(deletePatternSet));
×
2977
    } else {
×
2978
      for (PartialPath devicePattern : patternTree.getAllDevicePaths()) {
×
2979
        schemaTree
×
2980
            .getMatchedDevices(devicePattern)
×
2981
            .forEach(
×
2982
                deviceSchemaInfo ->
2983
                    deduplicatedDevicePaths.add(deviceSchemaInfo.getDevicePath().getFullPath()));
×
2984
      }
×
2985
    }
2986
    analysis.setSchemaTree(schemaTree);
×
2987

2988
    Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap = new HashMap<>();
×
2989

2990
    deduplicatedDevicePaths.forEach(
×
2991
        devicePath -> {
2992
          DataPartitionQueryParam queryParam = new DataPartitionQueryParam();
×
2993
          queryParam.setDevicePath(devicePath);
×
2994
          sgNameToQueryParamsMap
×
2995
              .computeIfAbsent(schemaTree.getBelongedDatabase(devicePath), key -> new ArrayList<>())
×
2996
              .add(queryParam);
×
2997
        });
×
2998

2999
    DataPartition dataPartition = partitionFetcher.getDataPartition(sgNameToQueryParamsMap);
×
3000
    analysis.setDataPartitionInfo(dataPartition);
×
3001
    analysis.setFinishQueryAfterAnalyze(dataPartition.isEmpty());
×
3002

3003
    return analysis;
×
3004
  }
3005

3006
  @Override
3007
  public Analysis visitCreateSchemaTemplate(
3008
      CreateSchemaTemplateStatement createTemplateStatement, MPPQueryContext context) {
3009

3010
    context.setQueryType(QueryType.WRITE);
×
3011
    List<String> measurements = createTemplateStatement.getMeasurements();
×
3012
    Set<String> measurementsSet = new HashSet<>(measurements);
×
3013
    if (measurementsSet.size() < measurements.size()) {
×
3014
      throw new SemanticException(
×
3015
          "Measurement under template is not allowed to have the same measurement name");
3016
    }
3017
    Analysis analysis = new Analysis();
×
3018
    analysis.setStatement(createTemplateStatement);
×
3019
    return analysis;
×
3020
  }
3021

3022
  @Override
3023
  public Analysis visitShowNodesInSchemaTemplate(
3024
      ShowNodesInSchemaTemplateStatement showNodesInSchemaTemplateStatement,
3025
      MPPQueryContext context) {
3026
    Analysis analysis = new Analysis();
×
3027
    analysis.setStatement(showNodesInSchemaTemplateStatement);
×
3028
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowNodesInSchemaTemplateHeader());
×
3029
    return analysis;
×
3030
  }
3031

3032
  @Override
3033
  public Analysis visitShowSchemaTemplate(
3034
      ShowSchemaTemplateStatement showSchemaTemplateStatement, MPPQueryContext context) {
3035
    Analysis analysis = new Analysis();
×
3036
    analysis.setStatement(showSchemaTemplateStatement);
×
3037
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowSchemaTemplateHeader());
×
3038
    return analysis;
×
3039
  }
3040

3041
  private GroupByFilter initGroupByFilter(GroupByTimeComponent groupByTimeComponent) {
3042
    if (groupByTimeComponent.isIntervalByMonth() || groupByTimeComponent.isSlidingStepByMonth()) {
1✔
3043
      return new GroupByMonthFilter(
×
3044
          groupByTimeComponent.getInterval(),
×
3045
          groupByTimeComponent.getSlidingStep(),
×
3046
          groupByTimeComponent.getStartTime(),
×
3047
          groupByTimeComponent.getEndTime(),
×
3048
          groupByTimeComponent.isSlidingStepByMonth(),
×
3049
          groupByTimeComponent.isIntervalByMonth(),
×
3050
          TimeZone.getTimeZone("+00:00"));
×
3051
    } else {
3052
      long startTime =
3053
          groupByTimeComponent.isLeftCRightO()
1✔
3054
              ? groupByTimeComponent.getStartTime()
1✔
3055
              : groupByTimeComponent.getStartTime() + 1;
1✔
3056
      long endTime =
3057
          groupByTimeComponent.isLeftCRightO()
1✔
3058
              ? groupByTimeComponent.getEndTime()
1✔
3059
              : groupByTimeComponent.getEndTime() + 1;
1✔
3060
      return new GroupByFilter(
1✔
3061
          groupByTimeComponent.getInterval(),
1✔
3062
          groupByTimeComponent.getSlidingStep(),
1✔
3063
          startTime,
3064
          endTime);
3065
    }
3066
  }
3067

3068
  @Override
3069
  public Analysis visitSetSchemaTemplate(
3070
      SetSchemaTemplateStatement setSchemaTemplateStatement, MPPQueryContext context) {
3071
    context.setQueryType(QueryType.WRITE);
×
3072
    Analysis analysis = new Analysis();
×
3073
    analysis.setStatement(setSchemaTemplateStatement);
×
3074
    return analysis;
×
3075
  }
3076

3077
  @Override
3078
  public Analysis visitShowPathSetTemplate(
3079
      ShowPathSetTemplateStatement showPathSetTemplateStatement, MPPQueryContext context) {
3080
    Analysis analysis = new Analysis();
×
3081
    analysis.setStatement(showPathSetTemplateStatement);
×
3082
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowPathSetTemplateHeader());
×
3083
    return analysis;
×
3084
  }
3085

3086
  @Override
3087
  public Analysis visitActivateTemplate(
3088
      ActivateTemplateStatement activateTemplateStatement, MPPQueryContext context) {
3089
    context.setQueryType(QueryType.WRITE);
×
3090
    Analysis analysis = new Analysis();
×
3091
    analysis.setStatement(activateTemplateStatement);
×
3092

3093
    PartialPath activatePath = activateTemplateStatement.getPath();
×
3094

3095
    Pair<Template, PartialPath> templateSetInfo = schemaFetcher.checkTemplateSetInfo(activatePath);
×
3096
    if (templateSetInfo == null) {
×
3097
      throw new StatementAnalyzeException(
×
3098
          new MetadataException(
3099
              String.format(
×
3100
                  "Path [%s] has not been set any template.", activatePath.getFullPath())));
×
3101
    }
3102
    analysis.setTemplateSetInfo(
×
3103
        new Pair<>(templateSetInfo.left, Collections.singletonList(templateSetInfo.right)));
×
3104

3105
    PathPatternTree patternTree = new PathPatternTree();
×
3106
    patternTree.appendPathPattern(activatePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
3107
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3108

3109
    analysis.setSchemaPartitionInfo(partition);
×
3110

3111
    return analysis;
×
3112
  }
3113

3114
  @Override
3115
  public Analysis visitBatchActivateTemplate(
3116
      BatchActivateTemplateStatement batchActivateTemplateStatement, MPPQueryContext context) {
3117
    context.setQueryType(QueryType.WRITE);
×
3118
    Analysis analysis = new Analysis();
×
3119
    analysis.setStatement(batchActivateTemplateStatement);
×
3120

3121
    Map<PartialPath, Pair<Template, PartialPath>> deviceTemplateSetInfoMap =
×
3122
        new HashMap<>(batchActivateTemplateStatement.getPaths().size());
×
3123
    for (PartialPath devicePath : batchActivateTemplateStatement.getDevicePathList()) {
×
3124
      Pair<Template, PartialPath> templateSetInfo = schemaFetcher.checkTemplateSetInfo(devicePath);
×
3125
      if (templateSetInfo == null) {
×
3126
        throw new StatementAnalyzeException(
×
3127
            new MetadataException(
3128
                String.format(
×
3129
                    "Path [%s] has not been set any template.", devicePath.getFullPath())));
×
3130
      }
3131
      deviceTemplateSetInfoMap.put(devicePath, templateSetInfo);
×
3132
    }
×
3133
    analysis.setDeviceTemplateSetInfoMap(deviceTemplateSetInfoMap);
×
3134

3135
    PathPatternTree patternTree = new PathPatternTree();
×
3136
    for (PartialPath devicePath : batchActivateTemplateStatement.getDevicePathList()) {
×
3137
      // the devicePath is a path without wildcard
3138
      patternTree.appendFullPath(devicePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
3139
    }
×
3140
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3141

3142
    analysis.setSchemaPartitionInfo(partition);
×
3143

3144
    return analysis;
×
3145
  }
3146

3147
  @Override
3148
  public Analysis visitInternalBatchActivateTemplate(
3149
      InternalBatchActivateTemplateStatement internalBatchActivateTemplateStatement,
3150
      MPPQueryContext context) {
3151
    context.setQueryType(QueryType.WRITE);
×
3152
    Analysis analysis = new Analysis();
×
3153
    analysis.setStatement(internalBatchActivateTemplateStatement);
×
3154

3155
    PathPatternTree patternTree = new PathPatternTree();
×
3156
    for (PartialPath activatePath :
3157
        internalBatchActivateTemplateStatement.getDeviceMap().keySet()) {
×
3158
      // the devicePath is a path without wildcard
3159
      patternTree.appendFullPath(activatePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
3160
    }
×
3161
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3162

3163
    analysis.setSchemaPartitionInfo(partition);
×
3164

3165
    return analysis;
×
3166
  }
3167

3168
  @Override
3169
  public Analysis visitShowPathsUsingTemplate(
3170
      ShowPathsUsingTemplateStatement showPathsUsingTemplateStatement, MPPQueryContext context) {
3171
    Analysis analysis = new Analysis();
×
3172
    analysis.setStatement(showPathsUsingTemplateStatement);
×
3173
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowPathsUsingTemplateHeader());
×
3174

3175
    Pair<Template, List<PartialPath>> templateSetInfo =
×
3176
        schemaFetcher.getAllPathsSetTemplate(showPathsUsingTemplateStatement.getTemplateName());
×
3177

3178
    if (templateSetInfo == null
×
3179
        || templateSetInfo.right == null
3180
        || templateSetInfo.right.isEmpty()) {
×
3181
      analysis.setFinishQueryAfterAnalyze(true);
×
3182
      return analysis;
×
3183
    }
3184

3185
    analysis.setTemplateSetInfo(templateSetInfo);
×
3186

3187
    PathPatternTree patternTree = new PathPatternTree();
×
3188
    PartialPath rawPathPattern = showPathsUsingTemplateStatement.getPathPattern();
×
3189
    List<PartialPath> specifiedPatternList = new ArrayList<>();
×
3190
    templateSetInfo.right.forEach(
×
3191
        setPath -> {
3192
          for (PartialPath specifiedPattern : rawPathPattern.alterPrefixPath(setPath)) {
×
3193
            patternTree.appendPathPattern(specifiedPattern);
×
3194
            specifiedPatternList.add(specifiedPattern);
×
3195
          }
×
3196
        });
×
3197

3198
    if (specifiedPatternList.isEmpty()) {
×
3199
      analysis.setFinishQueryAfterAnalyze(true);
×
3200
      return analysis;
×
3201
    }
3202

3203
    analysis.setSpecifiedTemplateRelatedPathPatternList(specifiedPatternList);
×
3204

3205
    SchemaPartition partition = partitionFetcher.getSchemaPartition(patternTree);
×
3206
    analysis.setSchemaPartitionInfo(partition);
×
3207
    if (partition.isEmpty()) {
×
3208
      analysis.setFinishQueryAfterAnalyze(true);
×
3209
      return analysis;
×
3210
    }
3211

3212
    return analysis;
×
3213
  }
3214

3215
  @Override
3216
  public Analysis visitShowQueries(
3217
      ShowQueriesStatement showQueriesStatement, MPPQueryContext context) {
3218
    Analysis analysis = new Analysis();
×
3219
    analysis.setStatement(showQueriesStatement);
×
3220
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowQueriesHeader());
×
3221
    analysis.setVirtualSource(true);
×
3222

3223
    List<TDataNodeLocation> allRunningDataNodeLocations = getRunningDataNodeLocations();
×
3224
    if (allRunningDataNodeLocations.isEmpty()) {
×
3225
      analysis.setFinishQueryAfterAnalyze(true);
×
3226
    }
3227
    // TODO Constant folding optimization for Where Predicate after True/False Constant introduced
3228
    if (allRunningDataNodeLocations.isEmpty()) {
×
3229
      throw new StatementAnalyzeException("no Running DataNodes");
×
3230
    }
3231
    analysis.setRunningDataNodeLocations(allRunningDataNodeLocations);
×
3232

3233
    Set<Expression> sourceExpressions = new HashSet<>();
×
3234
    for (ColumnHeader columnHeader : analysis.getRespDatasetHeader().getColumnHeaders()) {
×
3235
      sourceExpressions.add(
×
3236
          TimeSeriesOperand.constructColumnHeaderExpression(
×
3237
              columnHeader.getColumnName(), columnHeader.getColumnType()));
×
3238
    }
×
3239
    analysis.setSourceExpressions(sourceExpressions);
×
3240
    sourceExpressions.forEach(expression -> analyzeExpressionType(analysis, expression));
×
3241

3242
    analyzeWhere(analysis, showQueriesStatement);
×
3243

3244
    analysis.setMergeOrderParameter(new OrderByParameter(showQueriesStatement.getSortItemList()));
×
3245

3246
    return analysis;
×
3247
  }
3248

3249
  private List<TDataNodeLocation> getRunningDataNodeLocations() {
3250
    try (ConfigNodeClient client =
3251
        ConfigNodeClientManager.getInstance().borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) {
×
3252
      TGetDataNodeLocationsResp showDataNodesResp = client.getRunningDataNodeLocations();
×
3253
      if (showDataNodesResp.getStatus().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
×
3254
        throw new StatementAnalyzeException(
×
3255
            "An error occurred when executing getRunningDataNodeLocations():"
3256
                + showDataNodesResp.getStatus().getMessage());
×
3257
      }
3258
      return showDataNodesResp.getDataNodeLocationList();
×
3259
    } catch (ClientManagerException | TException e) {
×
3260
      throw new StatementAnalyzeException(
×
3261
          "An error occurred when executing getRunningDataNodeLocations():" + e.getMessage());
×
3262
    }
3263
  }
3264

3265
  private void analyzeWhere(Analysis analysis, ShowQueriesStatement showQueriesStatement) {
3266
    WhereCondition whereCondition = showQueriesStatement.getWhereCondition();
×
3267
    if (whereCondition == null) {
×
3268
      return;
×
3269
    }
3270

3271
    Expression whereExpression =
×
3272
        ExpressionAnalyzer.bindTypeForTimeSeriesOperand(
×
3273
            whereCondition.getPredicate(), ColumnHeaderConstant.showQueriesColumnHeaders);
×
3274

3275
    TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
×
3276
    if (outputType != TSDataType.BOOLEAN) {
×
3277
      throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
3278
    }
3279

3280
    analysis.setWhereExpression(whereExpression);
×
3281
  }
×
3282

3283
  // region view
3284

3285
  /**
3286
   * Compute how many paths exist, get the schema tree and the number of existed paths.
3287
   *
3288
   * @return a pair of ISchemaTree, and the number of exist paths.
3289
   */
3290
  private Pair<ISchemaTree, Integer> fetchSchemaOfPathsAndCount(
3291
      List<PartialPath> pathList, Analysis analysis, MPPQueryContext context) {
3292
    ISchemaTree schemaTree = analysis.getSchemaTree();
×
3293
    if (schemaTree == null) {
×
3294
      // source is not represented by query, thus has not done fetch schema.
3295
      PathPatternTree pathPatternTree = new PathPatternTree();
×
3296
      for (PartialPath path : pathList) {
×
3297
        pathPatternTree.appendPathPattern(path);
×
3298
      }
×
3299
      schemaTree = this.schemaFetcher.fetchSchema(pathPatternTree, context);
×
3300
    }
3301

3302
    // search each path, make sure they all exist.
3303
    int numOfExistPaths = 0;
×
3304
    for (PartialPath path : pathList) {
×
3305
      Pair<List<MeasurementPath>, Integer> pathPair = schemaTree.searchMeasurementPaths(path);
×
3306
      numOfExistPaths += !pathPair.left.isEmpty() ? 1 : 0;
×
3307
    }
×
3308
    return new Pair<>(schemaTree, numOfExistPaths);
×
3309
  }
3310

3311
  /**
3312
   * @param pathList the paths you want to check
3313
   * @param schemaTree the given schema tree
3314
   * @return if all paths you give can be found in schema tree, return a pair of view paths and
3315
   *     null; else return view paths and the non-exist path.
3316
   */
3317
  private Pair<List<PartialPath>, PartialPath> findAllViewsInPaths(
3318
      List<PartialPath> pathList, ISchemaTree schemaTree) {
3319
    List<PartialPath> result = new ArrayList<>();
×
3320
    for (PartialPath path : pathList) {
×
3321
      Pair<List<MeasurementPath>, Integer> measurementPathList =
×
3322
          schemaTree.searchMeasurementPaths(path);
×
3323
      if (measurementPathList.left.isEmpty()) {
×
3324
        return new Pair<>(result, path);
×
3325
      }
3326
      for (MeasurementPath measurementPath : measurementPathList.left) {
×
3327
        if (measurementPath.getMeasurementSchema().isLogicalView()) {
×
3328
          result.add(measurementPath);
×
3329
        }
3330
      }
×
3331
    }
×
3332
    return new Pair<>(result, null);
×
3333
  }
3334

3335
  private Pair<List<Expression>, Analysis> analyzeQueryInLogicalViewStatement(
3336
      Analysis analysis, QueryStatement queryStatement, MPPQueryContext context) {
3337
    Analysis queryAnalysis = this.visitQuery(queryStatement, context);
×
3338
    analysis.setSchemaTree(queryAnalysis.getSchemaTree());
×
3339
    // get all expression from resultColumns
3340
    List<Pair<Expression, String>> outputExpressions = queryAnalysis.getOutputExpressions();
×
3341
    if (queryAnalysis.isFailed()) {
×
3342
      analysis.setFinishQueryAfterAnalyze(true);
×
3343
      analysis.setFailStatus(queryAnalysis.getFailStatus());
×
3344
      return new Pair<>(null, analysis);
×
3345
    }
3346
    if (outputExpressions == null) {
×
3347
      analysis.setFinishQueryAfterAnalyze(true);
×
3348
      analysis.setFailStatus(
×
3349
          RpcUtils.getStatus(
×
3350
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3351
              "Columns in the query statement is empty. Please check your SQL."));
3352
      return new Pair<>(null, analysis);
×
3353
    }
3354
    if (queryAnalysis.useLogicalView()) {
×
3355
      analysis.setFinishQueryAfterAnalyze(true);
×
3356
      analysis.setFailStatus(
×
3357
          RpcUtils.getStatus(
×
3358
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3359
              "Can not create a view based on existing views. Check the query in your SQL."));
3360
      return new Pair<>(null, analysis);
×
3361
    }
3362
    List<Expression> expressionList = new ArrayList<>();
×
3363
    for (Pair<Expression, String> thisPair : outputExpressions) {
×
3364
      expressionList.add(thisPair.left);
×
3365
    }
×
3366
    return new Pair<>(expressionList, analysis);
×
3367
  }
3368

3369
  private void checkViewsInSource(
3370
      Analysis analysis, List<Expression> sourceExpressionList, MPPQueryContext context) {
3371
    List<PartialPath> pathsNeedCheck = new ArrayList<>();
×
3372
    for (Expression expression : sourceExpressionList) {
×
3373
      if (expression instanceof TimeSeriesOperand) {
×
3374
        pathsNeedCheck.add(((TimeSeriesOperand) expression).getPath());
×
3375
      }
3376
    }
×
3377
    Pair<ISchemaTree, Integer> schemaOfNeedToCheck =
×
3378
        fetchSchemaOfPathsAndCount(pathsNeedCheck, analysis, context);
×
3379
    if (schemaOfNeedToCheck.right != pathsNeedCheck.size()) {
×
3380
      // some source paths is not exist, and could not fetch schema.
3381
      analysis.setFinishQueryAfterAnalyze(true);
×
3382
      analysis.setFailStatus(
×
3383
          RpcUtils.getStatus(
×
3384
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3385
              "Can not create a view based on non-exist time series."));
3386
      return;
×
3387
    }
3388
    Pair<List<PartialPath>, PartialPath> viewInSourceCheckResult =
×
3389
        findAllViewsInPaths(pathsNeedCheck, schemaOfNeedToCheck.left);
×
3390
    if (viewInSourceCheckResult.right != null) {
×
3391
      // some source paths is not exist
3392
      analysis.setFinishQueryAfterAnalyze(true);
×
3393
      analysis.setFailStatus(
×
3394
          RpcUtils.getStatus(
×
3395
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3396
              "Path "
3397
                  + viewInSourceCheckResult.right.toString()
×
3398
                  + " does not exist! You can not create a view based on non-exist time series."));
3399
      return;
×
3400
    }
3401
    if (!viewInSourceCheckResult.left.isEmpty()) {
×
3402
      // some source paths is logical view
3403
      analysis.setFinishQueryAfterAnalyze(true);
×
3404
      analysis.setFailStatus(
×
3405
          RpcUtils.getStatus(
×
3406
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3407
              "Can not create a view based on existing views."));
3408
    }
3409
  }
×
3410

3411
  private void checkPathsInCreateLogicalView(
3412
      Analysis analysis, CreateLogicalViewStatement createLogicalViewStatement) {
3413
    Pair<Boolean, String> checkResult = createLogicalViewStatement.checkAllPaths();
×
3414
    if (Boolean.FALSE.equals(checkResult.left)) {
×
3415
      analysis.setFinishQueryAfterAnalyze(true);
×
3416
      analysis.setFailStatus(
×
3417
          RpcUtils.getStatus(
×
3418
              TSStatusCode.ILLEGAL_PATH.getStatusCode(),
×
3419
              "The path " + checkResult.right + " is illegal."));
3420
      return;
×
3421
    }
3422
    // make sure there are no redundant paths in targets. Please note that redundant paths in source
3423
    // are legal!
3424
    List<PartialPath> targetPathList = createLogicalViewStatement.getTargetPathList();
×
3425
    Set<String> targetStringSet = new HashSet<>();
×
3426
    for (PartialPath path : targetPathList) {
×
3427
      boolean repeatPathNotExist = targetStringSet.add(path.toString());
×
3428
      if (!repeatPathNotExist) {
×
3429
        analysis.setFinishQueryAfterAnalyze(true);
×
3430
        analysis.setFailStatus(
×
3431
            RpcUtils.getStatus(
×
3432
                TSStatusCode.ILLEGAL_PATH.getStatusCode(),
×
3433
                String.format("Path [%s] is redundant in target paths.", path)));
×
3434
        return;
×
3435
      }
3436
    }
×
3437
    if (createLogicalViewStatement.getSourceExpressionList().size() != targetPathList.size()) {
×
3438
      analysis.setFinishQueryAfterAnalyze(true);
×
3439
      analysis.setFailStatus(
×
3440
          RpcUtils.getStatus(
×
3441
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3442
              String.format(
×
3443
                  "The number of target paths (%d) and sources (%d) are miss matched! Please check your SQL.",
3444
                  createLogicalViewStatement.getTargetPathList().size(),
×
3445
                  createLogicalViewStatement.getSourceExpressionList().size())));
×
3446
      return;
×
3447
    }
3448
    // make sure all paths are NOt under any template
3449
    try {
3450
      for (PartialPath path : createLogicalViewStatement.getTargetPathList()) {
×
3451
        checkIsTemplateCompatible(path, null);
×
3452
      }
×
3453
    } catch (Exception e) {
×
3454
      analysis.setFinishQueryAfterAnalyze(true);
×
3455
      analysis.setFailStatus(
×
3456
          RpcUtils.getStatus(
×
3457
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3458
              "Can not create view under template."));
3459
    }
×
3460
  }
×
3461

3462
  // create Logical View
3463
  @Override
3464
  public Analysis visitCreateLogicalView(
3465
      CreateLogicalViewStatement createLogicalViewStatement, MPPQueryContext context) {
3466
    Analysis analysis = new Analysis();
×
3467
    context.setQueryType(QueryType.WRITE);
×
3468
    analysis.setStatement(createLogicalViewStatement);
×
3469

3470
    if (createLogicalViewStatement.getViewExpression() == null) {
×
3471
      // analyze query in statement
3472
      QueryStatement queryStatement = createLogicalViewStatement.getQueryStatement();
×
3473
      if (queryStatement != null) {
×
3474
        Pair<List<Expression>, Analysis> queryAnalysisPair =
×
3475
            this.analyzeQueryInLogicalViewStatement(analysis, queryStatement, context);
×
3476
        if (queryAnalysisPair.right.isFinishQueryAfterAnalyze()) {
×
3477
          return analysis;
×
3478
        } else if (queryAnalysisPair.left != null) {
×
3479
          try {
3480
            createLogicalViewStatement.setSourceExpressions(queryAnalysisPair.left);
×
3481
          } catch (UnsupportedViewException e) {
×
3482
            analysis.setFinishQueryAfterAnalyze(true);
×
3483
            analysis.setFailStatus(RpcUtils.getStatus(e.getErrorCode(), e.getMessage()));
×
3484
            return analysis;
×
3485
          }
×
3486
        }
3487
      }
3488
    }
3489

3490
    // use source and into item to generate target views
3491
    createLogicalViewStatement.parseIntoItemIfNecessary();
×
3492

3493
    // check target paths; check source expressions.
3494
    checkPathsInCreateLogicalView(analysis, createLogicalViewStatement);
×
3495
    if (analysis.isFinishQueryAfterAnalyze()) {
×
3496
      return analysis;
×
3497
    }
3498

3499
    // make sure there is no view in source
3500
    List<Expression> sourceExpressionList = createLogicalViewStatement.getSourceExpressionList();
×
3501
    checkViewsInSource(analysis, sourceExpressionList, context);
×
3502
    if (analysis.isFinishQueryAfterAnalyze()) {
×
3503
      return analysis;
×
3504
    }
3505

3506
    // set schema partition info, this info will be used to split logical plan node.
3507
    PathPatternTree patternTree = new PathPatternTree();
×
3508
    for (PartialPath thisFullPath : createLogicalViewStatement.getTargetPathList()) {
×
3509
      patternTree.appendFullPath(thisFullPath);
×
3510
    }
×
3511
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3512
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
3513

3514
    return analysis;
×
3515
  }
3516

3517
  @Override
3518
  public Analysis visitShowLogicalView(
3519
      ShowLogicalViewStatement showLogicalViewStatement, MPPQueryContext context) {
3520
    context.setQueryType(QueryType.READ);
×
3521
    Analysis analysis = new Analysis();
×
3522
    analysis.setStatement(showLogicalViewStatement);
×
3523

3524
    PathPatternTree patternTree = new PathPatternTree();
×
3525
    patternTree.appendPathPattern(showLogicalViewStatement.getPathPattern());
×
3526
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
3527
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
3528

3529
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowLogicalViewHeader());
×
3530
    return analysis;
×
3531
  }
3532
  // endregion view
3533
}
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

© 2026 Coveralls, Inc