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

apache / iotdb / #10018

07 Sep 2023 05:00AM UTC coverage: 47.717% (+0.03%) from 47.691%
#10018

push

travis_ci

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

* try to fix ConcurrentModificationException when assigning PipeHeartbeatEvent

* Update CachedSchemaPatternMatcher.java

---------

Co-authored-by: 马子坤 <55695098+DanielWang2035@users.noreply.github.com>
(cherry picked from commit ac0dd9d31)

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

80262 of 168204 relevant lines covered (47.72%)

0.48 hits per line

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

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

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

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

152
import org.apache.thrift.TException;
153
import org.slf4j.Logger;
154
import org.slf4j.LoggerFactory;
155

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

174
import static com.google.common.base.Preconditions.checkState;
175
import static org.apache.iotdb.commons.conf.IoTDBConstant.ALLOWED_SCHEMA_PROPS;
176
import static org.apache.iotdb.commons.conf.IoTDBConstant.DEADBAND;
177
import static org.apache.iotdb.commons.conf.IoTDBConstant.LOSS;
178
import static org.apache.iotdb.commons.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCARD;
179
import static org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant.DEVICE;
180
import static org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant.ENDTIME;
181
import static org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet.PARTITION_FETCHER;
182
import static org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet.SCHEMA_FETCHER;
183
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.bindSchemaForExpression;
184
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.concatDeviceAndBindSchemaForExpression;
185
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.getMeasurementExpression;
186
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.normalizeExpression;
187
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.searchAggregationExpressions;
188
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.searchSourceExpressions;
189
import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.toLowerCaseExpression;
190
import static org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetDevice;
191
import static org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetMeasurement;
192
import static org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetPath;
193
import static org.apache.iotdb.db.queryengine.plan.optimization.LimitOffsetPushDown.canPushDownLimitOffsetInGroupByTimeForDevice;
194
import static org.apache.iotdb.db.queryengine.plan.optimization.LimitOffsetPushDown.pushDownLimitOffsetInGroupByTimeForDevice;
195
import static org.apache.iotdb.db.schemaengine.schemaregion.view.visitor.GetSourcePathsVisitor.getSourcePaths;
196
import static org.apache.iotdb.db.utils.constant.SqlConstant.COUNT_TIME_HEADER;
197

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

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

203
  private static final IoTDBConfig CONFIG = IoTDBDescriptor.getInstance().getConfig();
1✔
204

205
  private static final Expression DEVICE_EXPRESSION =
1✔
206
      TimeSeriesOperand.constructColumnHeaderExpression(DEVICE, TSDataType.TEXT);
1✔
207

208
  private static final Expression END_TIME_EXPRESSION =
1✔
209
      TimeSeriesOperand.constructColumnHeaderExpression(ENDTIME, TSDataType.INT64);
1✔
210

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

214
  private final IPartitionFetcher partitionFetcher;
215
  private final ISchemaFetcher schemaFetcher;
216

217
  private static final PerformanceOverviewMetrics PERFORMANCE_OVERVIEW_METRICS =
1✔
218
      PerformanceOverviewMetrics.getInstance();
1✔
219

220
  public AnalyzeVisitor(IPartitionFetcher partitionFetcher, ISchemaFetcher schemaFetcher) {
1✔
221
    this.partitionFetcher = partitionFetcher;
1✔
222
    this.schemaFetcher = schemaFetcher;
1✔
223
  }
1✔
224

225
  @Override
226
  public Analysis visitNode(StatementNode node, MPPQueryContext context) {
227
    throw new UnsupportedOperationException(
×
228
        "Unsupported statement type: " + node.getClass().getName());
×
229
  }
230

231
  @Override
232
  public Analysis visitExplain(ExplainStatement explainStatement, MPPQueryContext context) {
233
    Analysis analysis = visitQuery(explainStatement.getQueryStatement(), context);
×
234
    analysis.setStatement(explainStatement);
×
235
    analysis.setFinishQueryAfterAnalyze(true);
×
236
    return analysis;
×
237
  }
238

239
  @Override
240
  public Analysis visitQuery(QueryStatement queryStatement, MPPQueryContext context) {
241
    Analysis analysis = new Analysis();
1✔
242
    analysis.setLastLevelUseWildcard(queryStatement.isLastLevelUseWildcard());
1✔
243
    try {
244
      // check for semantic errors
245
      queryStatement.semanticCheck();
1✔
246

247
      ISchemaTree schemaTree = analyzeSchema(queryStatement, analysis, context);
1✔
248
      // If there is no leaf node in the schema tree, the query should be completed immediately
249
      if (schemaTree.isEmpty()) {
1✔
250
        return finishQuery(queryStatement, analysis);
×
251
      }
252

253
      // extract global time filter from query filter and determine if there is a value filter
254
      analyzeGlobalTimeFilter(analysis, queryStatement);
1✔
255

256
      if (queryStatement.isLastQuery()) {
1✔
257
        return analyzeLastQuery(queryStatement, analysis, schemaTree);
×
258
      }
259

260
      List<Pair<Expression, String>> outputExpressions;
261
      if (queryStatement.isAlignByDevice()) {
1✔
262
        List<PartialPath> deviceList = analyzeFrom(queryStatement, schemaTree);
1✔
263

264
        if (canPushDownLimitOffsetInGroupByTimeForDevice(queryStatement)) {
1✔
265
          // remove the device which won't appear in resultSet after limit/offset
266
          deviceList = pushDownLimitOffsetInGroupByTimeForDevice(deviceList, queryStatement);
1✔
267
        }
268

269
        analyzeDeviceToWhere(analysis, queryStatement, schemaTree, deviceList);
1✔
270
        outputExpressions = analyzeSelect(analysis, queryStatement, schemaTree, deviceList);
1✔
271
        if (deviceList.isEmpty()) {
1✔
272
          return finishQuery(queryStatement, analysis);
×
273
        }
274
        analysis.setDeviceList(deviceList);
1✔
275

276
        analyzeDeviceToGroupBy(analysis, queryStatement, schemaTree, deviceList);
1✔
277
        analyzeDeviceToOrderBy(analysis, queryStatement, schemaTree, deviceList);
1✔
278
        analyzeHaving(analysis, queryStatement, schemaTree, deviceList);
1✔
279

280
        analyzeDeviceToAggregation(analysis, queryStatement);
1✔
281
        analyzeDeviceToSourceTransform(analysis, queryStatement);
1✔
282
        analyzeDeviceToSource(analysis, queryStatement);
1✔
283

284
        analyzeDeviceViewOutput(analysis, queryStatement);
1✔
285
        analyzeDeviceViewInput(analysis, queryStatement);
1✔
286

287
        analyzeInto(analysis, queryStatement, deviceList, outputExpressions);
1✔
288
      } else {
1✔
289
        Map<Integer, List<Pair<Expression, String>>> outputExpressionMap =
1✔
290
            analyzeSelect(analysis, queryStatement, schemaTree);
1✔
291

292
        outputExpressions = new ArrayList<>();
1✔
293
        outputExpressionMap.values().forEach(outputExpressions::addAll);
1✔
294
        analysis.setOutputExpressions(outputExpressions);
1✔
295
        if (outputExpressions.isEmpty()) {
1✔
296
          return finishQuery(queryStatement, analysis);
×
297
        }
298

299
        analyzeGroupBy(analysis, queryStatement, schemaTree);
1✔
300

301
        analyzeHaving(analysis, queryStatement, schemaTree);
1✔
302
        analyzeOrderBy(analysis, queryStatement, schemaTree);
1✔
303

304
        analyzeGroupByLevel(analysis, queryStatement, outputExpressionMap, outputExpressions);
1✔
305
        analyzeGroupByTag(analysis, queryStatement, outputExpressions);
1✔
306

307
        Set<Expression> selectExpressions = new LinkedHashSet<>();
1✔
308
        if (queryStatement.isOutputEndTime()) {
1✔
309
          selectExpressions.add(END_TIME_EXPRESSION);
×
310
        }
311
        for (Pair<Expression, String> outputExpressionAndAlias : outputExpressions) {
1✔
312
          Expression outputExpression = outputExpressionAndAlias.left;
1✔
313
          selectExpressions.add(outputExpression);
1✔
314
        }
1✔
315
        analysis.setSelectExpressions(selectExpressions);
1✔
316

317
        analyzeAggregation(analysis, queryStatement);
1✔
318

319
        analyzeWhere(analysis, queryStatement, schemaTree);
1✔
320
        analyzeSourceTransform(analysis, outputExpressions, queryStatement);
1✔
321

322
        analyzeSource(analysis, queryStatement);
1✔
323

324
        analyzeInto(analysis, queryStatement, outputExpressions);
1✔
325
      }
326

327
      analyzeGroupByTime(analysis, queryStatement);
1✔
328

329
      analyzeFill(analysis, queryStatement);
1✔
330

331
      // generate result set header according to output expressions
332
      analyzeOutput(analysis, queryStatement, outputExpressions);
1✔
333

334
      // fetch partition information
335
      analyzeDataPartition(analysis, queryStatement, schemaTree);
1✔
336

337
    } catch (StatementAnalyzeException e) {
×
338
      throw new StatementAnalyzeException(
×
339
          "Meet error when analyzing the query statement: " + e.getMessage());
×
340
    }
1✔
341
    return analysis;
1✔
342
  }
343

344
  private ISchemaTree analyzeSchema(
345
      QueryStatement queryStatement, Analysis analysis, MPPQueryContext context) {
346
    // concat path and construct path pattern tree
347
    PathPatternTree patternTree = new PathPatternTree(queryStatement.useWildcard());
1✔
348
    queryStatement = (QueryStatement) new ConcatPathRewriter().rewrite(queryStatement, patternTree);
1✔
349
    analysis.setStatement(queryStatement);
1✔
350

351
    // request schema fetch API
352
    long startTime = System.nanoTime();
1✔
353
    ISchemaTree schemaTree;
354
    try {
355
      logger.debug("[StartFetchSchema]");
1✔
356
      if (queryStatement.isGroupByTag()) {
1✔
357
        schemaTree = schemaFetcher.fetchSchemaWithTags(patternTree, context);
×
358
      } else {
359
        schemaTree = schemaFetcher.fetchSchema(patternTree, context);
1✔
360
      }
361

362
      // make sure paths in logical view is fetched
363
      updateSchemaTreeByViews(analysis, schemaTree);
1✔
364
    } finally {
365
      logger.debug("[EndFetchSchema]");
1✔
366
      QueryPlanCostMetricSet.getInstance()
1✔
367
          .recordPlanCost(SCHEMA_FETCHER, System.nanoTime() - startTime);
1✔
368
    }
369
    analysis.setSchemaTree(schemaTree);
1✔
370
    return schemaTree;
1✔
371
  }
372

373
  private Analysis finishQuery(QueryStatement queryStatement, Analysis analysis) {
374
    if (queryStatement.isSelectInto()) {
×
375
      analysis.setRespDatasetHeader(
×
376
          DatasetHeaderFactory.getSelectIntoHeader(queryStatement.isAlignByDevice()));
×
377
    }
378
    if (queryStatement.isLastQuery()) {
×
379
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getLastQueryHeader());
×
380
    }
381
    analysis.setFinishQueryAfterAnalyze(true);
×
382
    return analysis;
×
383
  }
384

385
  private void analyzeGlobalTimeFilter(Analysis analysis, QueryStatement queryStatement) {
386
    Filter globalTimeFilter = null;
1✔
387
    boolean hasValueFilter = false;
1✔
388
    if (queryStatement.getWhereCondition() != null) {
1✔
389
      WhereCondition whereCondition = queryStatement.getWhereCondition();
1✔
390
      Expression predicate = whereCondition.getPredicate();
1✔
391

392
      Pair<Filter, Boolean> resultPair =
1✔
393
          ExpressionAnalyzer.extractGlobalTimeFilter(predicate, true, true);
1✔
394
      globalTimeFilter = resultPair.left;
1✔
395
      if (globalTimeFilter != null) {
1✔
396
        globalTimeFilter = PredicateRemoveNotRewriter.rewrite(globalTimeFilter);
1✔
397
      }
398
      hasValueFilter = resultPair.right;
1✔
399

400
      predicate = ExpressionAnalyzer.evaluatePredicate(predicate);
1✔
401

402
      // set where condition to null if predicate is true or time filter.
403
      if (!hasValueFilter
1✔
404
          || (predicate.getExpressionType().equals(ExpressionType.CONSTANT)
1✔
405
              && Boolean.parseBoolean(predicate.getExpressionString()))) {
×
406
        queryStatement.setWhereCondition(null);
1✔
407
      } else {
408
        whereCondition.setPredicate(predicate);
1✔
409
      }
410
    }
411
    analysis.setGlobalTimeFilter(globalTimeFilter);
1✔
412
    analysis.setHasValueFilter(hasValueFilter);
1✔
413
  }
1✔
414

415
  private Analysis analyzeLastQuery(
416
      QueryStatement queryStatement, Analysis analysis, ISchemaTree schemaTree) {
417
    if (analysis.hasValueFilter()) {
×
418
      throw new SemanticException("Only time filters are supported in LAST query");
×
419
    }
420
    analyzeLastOrderBy(analysis, queryStatement);
×
421

422
    List<Expression> selectExpressions = new ArrayList<>();
×
423
    for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) {
×
424
      selectExpressions.add(resultColumn.getExpression());
×
425
    }
×
426
    analyzeLastSource(analysis, selectExpressions, schemaTree);
×
427

428
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getLastQueryHeader());
×
429

430
    // fetch partition information
431
    analyzeDataPartition(analysis, queryStatement, schemaTree);
×
432

433
    return analysis;
×
434
  }
435

436
  private void analyzeLastSource(
437
      Analysis analysis, List<Expression> selectExpressions, ISchemaTree schemaTree) {
438
    Set<Expression> sourceExpressions;
439

440
    sourceExpressions = new LinkedHashSet<>();
×
441

442
    for (Expression selectExpression : selectExpressions) {
×
443
      for (Expression sourceExpression : bindSchemaForExpression(selectExpression, schemaTree)) {
×
444
        if (!(sourceExpression instanceof TimeSeriesOperand)) {
×
445
          throw new SemanticException(
×
446
              "Views with functions and expressions cannot be used in LAST query");
447
        }
448
        sourceExpressions.add(sourceExpression);
×
449
      }
×
450
    }
×
451
    analysis.setSourceExpressions(sourceExpressions);
×
452
  }
×
453

454
  private void updateSchemaTreeByViews(Analysis analysis, ISchemaTree originSchemaTree) {
455
    if (!originSchemaTree.hasLogicalViewMeasurement()) {
1✔
456
      return;
1✔
457
    }
458

459
    PathPatternTree patternTree = new PathPatternTree();
×
460
    boolean needToReFetch = false;
×
461
    boolean useLogicalView = false;
×
462
    try {
463
      Pair<List<MeasurementPath>, Integer> tempPair =
×
464
          originSchemaTree.searchMeasurementPaths(new PartialPath("root.**"));
×
465
      for (MeasurementPath measurementPath : tempPair.left) {
×
466
        if (measurementPath.getMeasurementSchema().isLogicalView()) {
×
467
          useLogicalView = true;
×
468
          LogicalViewSchema logicalViewSchema =
×
469
              (LogicalViewSchema) measurementPath.getMeasurementSchema();
×
470
          ViewExpression viewExpression = logicalViewSchema.getExpression();
×
471
          List<PartialPath> pathsNeedToReFetch = getSourcePaths(viewExpression);
×
472
          for (PartialPath path : pathsNeedToReFetch) {
×
473
            patternTree.appendFullPath(path);
×
474
            needToReFetch = true;
×
475
          }
×
476
        }
477
      }
×
478
    } catch (Exception e) {
×
479
      throw new SemanticException(e);
×
480
    }
×
481
    analysis.setUseLogicalView(useLogicalView);
×
482
    if (useLogicalView
×
483
        && analysis.getStatement() instanceof QueryStatement
×
484
        && (((QueryStatement) analysis.getStatement()).isGroupByTag())) {
×
485
      throw new SemanticException("Views cannot be used in GROUP BY TAGS query yet.");
×
486
    }
487

488
    if (needToReFetch) {
×
489
      ISchemaTree viewSchemaTree = this.schemaFetcher.fetchSchema(patternTree, null);
×
490
      originSchemaTree.mergeSchemaTree(viewSchemaTree);
×
491
      Set<String> allDatabases = viewSchemaTree.getDatabases();
×
492
      allDatabases.addAll(originSchemaTree.getDatabases());
×
493
      originSchemaTree.setDatabases(allDatabases);
×
494
    }
495
  }
×
496

497
  /** process select component for align by time. */
498
  private Map<Integer, List<Pair<Expression, String>>> analyzeSelect(
499
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
500
    Map<Integer, List<Pair<Expression, String>>> outputExpressionMap = new HashMap<>();
1✔
501

502
    boolean isGroupByLevel = queryStatement.isGroupByLevel();
1✔
503
    ColumnPaginationController paginationController =
1✔
504
        new ColumnPaginationController(
505
            queryStatement.getSeriesLimit(),
1✔
506
            queryStatement.getSeriesOffset(),
1✔
507
            queryStatement.isLastQuery() || isGroupByLevel);
1✔
508

509
    Set<String> aliasSet = new HashSet<>();
1✔
510

511
    int columnIndex = 0;
1✔
512

513
    for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) {
1✔
514
      List<Pair<Expression, String>> outputExpressions = new ArrayList<>();
1✔
515
      List<Expression> resultExpressions =
1✔
516
          bindSchemaForExpression(resultColumn.getExpression(), schemaTree);
1✔
517

518
      for (Expression resultExpression : resultExpressions) {
1✔
519
        if (paginationController.hasCurOffset()) {
1✔
520
          paginationController.consumeOffset();
×
521
        } else if (paginationController.hasCurLimit()) {
1✔
522
          if (isGroupByLevel) {
1✔
523
            analyzeExpressionType(analysis, resultExpression);
×
524
            outputExpressions.add(new Pair<>(resultExpression, resultColumn.getAlias()));
×
525
            queryStatement
×
526
                .getGroupByLevelComponent()
×
527
                .updateIsCountStar(resultColumn.getExpression());
×
528
          } else {
529
            Expression normalizedExpression = normalizeExpression(resultExpression);
1✔
530
            analyzeExpressionType(analysis, normalizedExpression);
1✔
531
            checkAliasUniqueness(resultColumn.getAlias(), aliasSet);
1✔
532
            outputExpressions.add(
1✔
533
                new Pair<>(
534
                    normalizedExpression,
535
                    analyzeAlias(
1✔
536
                        resultColumn.getAlias(),
1✔
537
                        resultExpression,
538
                        normalizedExpression,
539
                        queryStatement)));
540
          }
541
          paginationController.consumeLimit();
1✔
542
        } else {
543
          break;
544
        }
545
      }
1✔
546

547
      outputExpressionMap.put(columnIndex++, outputExpressions);
1✔
548
    }
1✔
549
    return outputExpressionMap;
1✔
550
  }
551

552
  private List<PartialPath> analyzeFrom(QueryStatement queryStatement, ISchemaTree schemaTree) {
553
    // device path patterns in FROM clause
554
    List<PartialPath> devicePatternList = queryStatement.getFromComponent().getPrefixPaths();
1✔
555

556
    Set<PartialPath> deviceSet = new HashSet<>();
1✔
557
    for (PartialPath devicePattern : devicePatternList) {
1✔
558
      // get all matched devices
559
      deviceSet.addAll(
1✔
560
          schemaTree.getMatchedDevices(devicePattern).stream()
1✔
561
              .map(DeviceSchemaInfo::getDevicePath)
1✔
562
              .collect(Collectors.toList()));
1✔
563
    }
1✔
564

565
    return queryStatement.getResultDeviceOrder() == Ordering.ASC
1✔
566
        ? deviceSet.stream().sorted().collect(Collectors.toList())
1✔
567
        : deviceSet.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
1✔
568
  }
569

570
  /** process select component for align by device. */
571
  private List<Pair<Expression, String>> analyzeSelect(
572
      Analysis analysis,
573
      QueryStatement queryStatement,
574
      ISchemaTree schemaTree,
575
      List<PartialPath> deviceSet) {
576
    List<Pair<Expression, String>> outputExpressions = new ArrayList<>();
1✔
577
    Map<String, Set<Expression>> deviceToSelectExpressions = new HashMap<>();
1✔
578
    ColumnPaginationController paginationController =
1✔
579
        new ColumnPaginationController(
580
            queryStatement.getSeriesLimit(), queryStatement.getSeriesOffset(), false);
1✔
581

582
    for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) {
1✔
583
      Expression selectExpression = resultColumn.getExpression();
1✔
584

585
      // select expression after removing wildcard
586
      // use LinkedHashMap for order-preserving
587
      Map<Expression, Map<String, Expression>> measurementToDeviceSelectExpressions =
1✔
588
          new LinkedHashMap<>();
589
      for (PartialPath device : deviceSet) {
1✔
590
        List<Expression> selectExpressionsOfOneDevice =
1✔
591
            concatDeviceAndBindSchemaForExpression(selectExpression, device, schemaTree);
1✔
592
        if (selectExpressionsOfOneDevice.isEmpty()) {
1✔
593
          continue;
×
594
        }
595

596
        updateMeasurementToDeviceSelectExpressions(
1✔
597
            analysis, measurementToDeviceSelectExpressions, device, selectExpressionsOfOneDevice);
598
      }
1✔
599

600
      checkAliasUniqueness(resultColumn.getAlias(), measurementToDeviceSelectExpressions);
1✔
601

602
      for (Map.Entry<Expression, Map<String, Expression>> entry :
603
          measurementToDeviceSelectExpressions.entrySet()) {
1✔
604
        Expression measurementExpression = entry.getKey();
1✔
605
        Map<String, Expression> deviceToSelectExpressionsOfOneMeasurement = entry.getValue();
1✔
606

607
        if (paginationController.hasCurOffset()) {
1✔
608
          paginationController.consumeOffset();
×
609
        } else if (paginationController.hasCurLimit()) {
1✔
610
          deviceToSelectExpressionsOfOneMeasurement
1✔
611
              .values()
1✔
612
              .forEach(expression -> analyzeExpressionType(analysis, expression));
1✔
613
          // check whether the datatype of paths which has the same measurement name are
614
          // consistent; if not, throw a SemanticException
615
          checkDataTypeConsistencyInAlignByDevice(
1✔
616
              analysis, new ArrayList<>(deviceToSelectExpressionsOfOneMeasurement.values()));
1✔
617

618
          // add outputExpressions
619
          Expression lowerCaseMeasurementExpression = toLowerCaseExpression(measurementExpression);
1✔
620
          analyzeExpressionType(analysis, lowerCaseMeasurementExpression);
1✔
621

622
          outputExpressions.add(
1✔
623
              new Pair<>(
624
                  lowerCaseMeasurementExpression,
625
                  analyzeAlias(
1✔
626
                      resultColumn.getAlias(),
1✔
627
                      measurementExpression,
628
                      lowerCaseMeasurementExpression,
629
                      queryStatement)));
630

631
          // add deviceToSelectExpressions
632
          updateDeviceToSelectExpressions(
1✔
633
              analysis, deviceToSelectExpressions, deviceToSelectExpressionsOfOneMeasurement);
634

635
          paginationController.consumeLimit();
1✔
636
        } else {
637
          break;
638
        }
639
      }
1✔
640
    }
1✔
641

642
    // remove devices without measurements to compute
643
    Set<PartialPath> noMeasurementDevices = new HashSet<>();
1✔
644
    for (PartialPath device : deviceSet) {
1✔
645
      if (!deviceToSelectExpressions.containsKey(device.getFullPath())) {
1✔
646
        noMeasurementDevices.add(device);
×
647
      }
648
    }
1✔
649
    deviceSet.removeAll(noMeasurementDevices);
1✔
650

651
    // when the select expression of any device is empty,
652
    // the where expression map also need remove this device
653
    if (analysis.getDeviceToWhereExpression() != null) {
1✔
654
      noMeasurementDevices.forEach(
1✔
655
          devicePath -> analysis.getDeviceToWhereExpression().remove(devicePath.getFullPath()));
×
656
    }
657

658
    Set<Expression> selectExpressions = new LinkedHashSet<>();
1✔
659
    selectExpressions.add(DEVICE_EXPRESSION);
1✔
660
    if (queryStatement.isOutputEndTime()) {
1✔
661
      selectExpressions.add(END_TIME_EXPRESSION);
×
662
    }
663
    outputExpressions.forEach(pair -> selectExpressions.add(pair.getLeft()));
1✔
664
    analysis.setSelectExpressions(selectExpressions);
1✔
665

666
    analysis.setDeviceToSelectExpressions(deviceToSelectExpressions);
1✔
667

668
    return outputExpressions;
1✔
669
  }
670

671
  private void updateMeasurementToDeviceSelectExpressions(
672
      Analysis analysis,
673
      Map<Expression, Map<String, Expression>> measurementToDeviceSelectExpressions,
674
      PartialPath device,
675
      List<Expression> selectExpressionsOfOneDevice) {
676
    for (Expression expression : selectExpressionsOfOneDevice) {
1✔
677
      Expression measurementExpression =
1✔
678
          ExpressionAnalyzer.getMeasurementExpression(expression, analysis);
1✔
679
      measurementToDeviceSelectExpressions
1✔
680
          .computeIfAbsent(measurementExpression, key -> new LinkedHashMap<>())
1✔
681
          .put(device.getFullPath(), ExpressionAnalyzer.toLowerCaseExpression(expression));
1✔
682
    }
1✔
683
  }
1✔
684

685
  private void updateDeviceToSelectExpressions(
686
      Analysis analysis,
687
      Map<String, Set<Expression>> deviceToSelectExpressions,
688
      Map<String, Expression> deviceToSelectExpressionsOfOneMeasurement) {
689

690
    for (Map.Entry<String, Expression> entry :
691
        deviceToSelectExpressionsOfOneMeasurement.entrySet()) {
1✔
692
      String deviceName = entry.getKey();
1✔
693
      Expression expression = entry.getValue();
1✔
694

695
      Expression lowerCaseExpression = toLowerCaseExpression(expression);
1✔
696
      analyzeExpressionType(analysis, lowerCaseExpression);
1✔
697
      deviceToSelectExpressions
1✔
698
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
699
          .add(lowerCaseExpression);
1✔
700
    }
1✔
701
  }
1✔
702

703
  private String analyzeAlias(
704
      String resultColumnAlias,
705
      Expression rawExpression,
706
      Expression normalizedExpression,
707
      QueryStatement queryStatement) {
708
    if (resultColumnAlias != null) {
1✔
709
      // use alias as output symbol
710
      return resultColumnAlias;
1✔
711
    }
712

713
    if (queryStatement.isCountTimeAggregation()) {
1✔
714
      return COUNT_TIME_HEADER;
×
715
    }
716

717
    if (!Objects.equals(normalizedExpression, rawExpression)) {
1✔
718
      return rawExpression.getOutputSymbol();
1✔
719
    }
720

721
    return null;
1✔
722
  }
723

724
  private void analyzeHaving(
725
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
726
    if (!queryStatement.hasHaving()) {
1✔
727
      return;
1✔
728
    }
729

730
    // get removeWildcard Expressions in Having
731
    List<Expression> conJunctions =
1✔
732
        ExpressionAnalyzer.bindSchemaForPredicate(
1✔
733
            queryStatement.getHavingCondition().getPredicate(),
1✔
734
            queryStatement.getFromComponent().getPrefixPaths(),
1✔
735
            schemaTree,
736
            true);
737
    Expression havingExpression =
1✔
738
        ExpressionUtils.constructQueryFilter(
1✔
739
            conJunctions.stream().distinct().collect(Collectors.toList()));
1✔
740
    havingExpression = normalizeExpression(havingExpression);
1✔
741

742
    TSDataType outputType = analyzeExpressionType(analysis, havingExpression);
1✔
743
    if (outputType != TSDataType.BOOLEAN) {
1✔
744
      throw new SemanticException(
×
745
          String.format(
×
746
              "The output type of the expression in HAVING clause should be BOOLEAN, actual data type: %s.",
747
              outputType));
748
    }
749

750
    analysis.setHavingExpression(havingExpression);
1✔
751
  }
1✔
752

753
  private void analyzeHaving(
754
      Analysis analysis,
755
      QueryStatement queryStatement,
756
      ISchemaTree schemaTree,
757
      List<PartialPath> deviceSet) {
758
    if (!queryStatement.hasHaving()) {
1✔
759
      return;
1✔
760
    }
761

762
    // two maps to be updated
763
    Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
764
        analysis.getDeviceToAggregationExpressions();
1✔
765
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
766
        analysis.getDeviceToOutputExpressions();
1✔
767

768
    Expression havingExpression = queryStatement.getHavingCondition().getPredicate();
1✔
769
    Set<Expression> conJunctions = new HashSet<>();
1✔
770

771
    for (PartialPath device : deviceSet) {
1✔
772
      List<Expression> expressionsInHaving =
1✔
773
          concatDeviceAndBindSchemaForExpression(havingExpression, device, schemaTree);
1✔
774

775
      conJunctions.addAll(
1✔
776
          expressionsInHaving.stream()
1✔
777
              .map(expression -> getMeasurementExpression(expression, analysis))
1✔
778
              .collect(Collectors.toList()));
1✔
779

780
      for (Expression expression : expressionsInHaving) {
1✔
781
        Set<Expression> aggregationExpressions = new LinkedHashSet<>();
1✔
782
        Set<Expression> normalizedAggregationExpressions = new LinkedHashSet<>();
1✔
783
        for (Expression aggregationExpression : searchAggregationExpressions(expression)) {
1✔
784
          Expression normalizedAggregationExpression = normalizeExpression(aggregationExpression);
1✔
785

786
          analyzeExpressionType(analysis, aggregationExpression);
1✔
787
          analyzeExpressionType(analysis, normalizedAggregationExpression);
1✔
788

789
          aggregationExpressions.add(aggregationExpression);
1✔
790
          normalizedAggregationExpressions.add(normalizedAggregationExpression);
1✔
791
        }
1✔
792
        deviceToOutputExpressions
1✔
793
            .computeIfAbsent(device.getFullPath(), key -> new LinkedHashSet<>())
1✔
794
            .addAll(aggregationExpressions);
1✔
795
        deviceToAggregationExpressions
1✔
796
            .computeIfAbsent(device.getFullPath(), key -> new LinkedHashSet<>())
1✔
797
            .addAll(normalizedAggregationExpressions);
1✔
798
      }
1✔
799
    }
1✔
800

801
    havingExpression = ExpressionUtils.constructQueryFilter(new ArrayList<>(conJunctions));
1✔
802
    TSDataType outputType = analyzeExpressionType(analysis, havingExpression);
1✔
803
    if (outputType != TSDataType.BOOLEAN) {
1✔
804
      throw new SemanticException(
×
805
          String.format(
×
806
              "The output type of the expression in HAVING clause should be BOOLEAN, actual data type: %s.",
807
              outputType));
808
    }
809
    analysis.setDeviceToAggregationExpressions(deviceToAggregationExpressions);
1✔
810
    analysis.setHavingExpression(havingExpression);
1✔
811
  }
1✔
812

813
  private void analyzeGroupByLevel(
814
      Analysis analysis,
815
      QueryStatement queryStatement,
816
      Map<Integer, List<Pair<Expression, String>>> outputExpressionMap,
817
      List<Pair<Expression, String>> outputExpressions) {
818
    if (!queryStatement.isGroupByLevel()) {
1✔
819
      return;
1✔
820
    }
821

822
    GroupByLevelController groupByLevelController =
×
823
        new GroupByLevelController(queryStatement.getGroupByLevelComponent().getLevels());
×
824

825
    List<Expression> groupedSelectExpressions = new LinkedList<>();
×
826

827
    for (List<Pair<Expression, String>> outputExpressionList : outputExpressionMap.values()) {
×
828
      Set<Expression> groupedSelectExpressionSet = new LinkedHashSet<>();
×
829
      for (int i = 0; i < outputExpressionList.size(); i++) {
×
830
        Pair<Expression, String> expressionAliasPair = outputExpressionList.get(i);
×
831
        boolean isCountStar = queryStatement.getGroupByLevelComponent().isCountStar(i);
×
832
        Expression groupedExpression =
×
833
            groupByLevelController.control(
×
834
                isCountStar, expressionAliasPair.left, expressionAliasPair.right);
835
        groupedSelectExpressionSet.add(groupedExpression);
×
836
      }
837
      groupedSelectExpressions.addAll(groupedSelectExpressionSet);
×
838
    }
×
839

840
    LinkedHashMap<Expression, Set<Expression>> groupByLevelExpressions = new LinkedHashMap<>();
×
841
    if (queryStatement.hasHaving()) {
×
842
      // update havingExpression
843
      Expression havingExpression = groupByLevelController.control(analysis.getHavingExpression());
×
844
      analyzeExpressionType(analysis, havingExpression);
×
845
      analysis.setHavingExpression(havingExpression);
×
846
      updateGroupByLevelExpressions(
×
847
          analysis,
848
          havingExpression,
849
          groupByLevelExpressions,
850
          groupByLevelController.getGroupedExpressionToRawExpressionsMap());
×
851
    }
852

853
    outputExpressions.clear();
×
854
    ColumnPaginationController paginationController =
×
855
        new ColumnPaginationController(
856
            queryStatement.getSeriesLimit(), queryStatement.getSeriesOffset(), false);
×
857
    for (Expression groupedExpression : groupedSelectExpressions) {
×
858
      if (paginationController.hasCurOffset()) {
×
859
        paginationController.consumeOffset();
×
860
      } else if (paginationController.hasCurLimit()) {
×
861
        Expression normalizedGroupedExpression = normalizeExpression(groupedExpression);
×
862
        analyzeExpressionType(analysis, normalizedGroupedExpression);
×
863
        outputExpressions.add(
×
864
            new Pair<>(
865
                normalizedGroupedExpression,
866
                analyzeAlias(
×
867
                    groupByLevelController.getAlias(groupedExpression.getExpressionString()),
×
868
                    groupedExpression,
869
                    normalizedGroupedExpression,
870
                    queryStatement)));
871
        updateGroupByLevelExpressions(
×
872
            analysis,
873
            groupedExpression,
874
            groupByLevelExpressions,
875
            groupByLevelController.getGroupedExpressionToRawExpressionsMap());
×
876
        paginationController.consumeLimit();
×
877
      } else {
878
        break;
879
      }
880
    }
×
881

882
    checkDataTypeConsistencyInGroupByLevel(analysis, groupByLevelExpressions);
×
883
    analysis.setCrossGroupByExpressions(groupByLevelExpressions);
×
884
  }
×
885

886
  private void checkDataTypeConsistencyInGroupByLevel(
887
      Analysis analysis, Map<Expression, Set<Expression>> groupByLevelExpressions) {
888
    for (Map.Entry<Expression, Set<Expression>> groupedExpressionRawExpressionsEntry :
889
        groupByLevelExpressions.entrySet()) {
×
890
      Expression groupedAggregationExpression = groupedExpressionRawExpressionsEntry.getKey();
×
891
      Set<Expression> rawAggregationExpressions = groupedExpressionRawExpressionsEntry.getValue();
×
892

893
      TSDataType checkedDataType = analysis.getType(groupedAggregationExpression);
×
894
      for (Expression rawAggregationExpression : rawAggregationExpressions) {
×
895
        if (analysis.getType(rawAggregationExpression) != checkedDataType) {
×
896
          throw new SemanticException(
×
897
              String.format(
×
898
                  "GROUP BY LEVEL: the data types of the same output column[%s] should be the same.",
899
                  groupedAggregationExpression));
900
        }
901
      }
×
902
    }
×
903
  }
×
904

905
  private void updateGroupByLevelExpressions(
906
      Analysis analysis,
907
      Expression expression,
908
      Map<Expression, Set<Expression>> groupByLevelExpressions,
909
      Map<Expression, Set<Expression>> groupedExpressionToRawExpressionsMap) {
910
    for (Expression groupedAggregationExpression : searchAggregationExpressions(expression)) {
×
911
      Set<Expression> groupedExpressionSet =
×
912
          groupedExpressionToRawExpressionsMap.get(groupedAggregationExpression).stream()
×
913
              .map(ExpressionAnalyzer::normalizeExpression)
×
914
              .collect(Collectors.toSet());
×
915
      Expression groupedAggregationExpressionWithoutAlias =
×
916
          normalizeExpression(groupedAggregationExpression);
×
917

918
      analyzeExpressionType(analysis, groupedAggregationExpressionWithoutAlias);
×
919
      groupedExpressionSet.forEach(
×
920
          groupedExpression -> analyzeExpressionType(analysis, groupedExpression));
×
921

922
      groupByLevelExpressions
×
923
          .computeIfAbsent(groupedAggregationExpressionWithoutAlias, key -> new HashSet<>())
×
924
          .addAll(groupedExpressionSet);
×
925
    }
×
926
  }
×
927

928
  /**
929
   * This method is used to analyze GROUP BY TAGS query.
930
   *
931
   * <p>TODO: support slimit/soffset/value filter
932
   */
933
  private void analyzeGroupByTag(
934
      Analysis analysis,
935
      QueryStatement queryStatement,
936
      List<Pair<Expression, String>> outputExpressions) {
937
    if (!queryStatement.isGroupByTag()) {
1✔
938
      return;
1✔
939
    }
940
    if (analysis.hasValueFilter()) {
×
941
      throw new SemanticException("Only time filters are supported in GROUP BY TAGS query");
×
942
    }
943

944
    List<String> tagKeys = queryStatement.getGroupByTagComponent().getTagKeys();
×
945
    Map<List<String>, LinkedHashMap<Expression, List<Expression>>>
946
        tagValuesToGroupedTimeseriesOperands = new HashMap<>();
×
947
    LinkedHashMap<Expression, Set<Expression>> outputExpressionToRawExpressionsMap =
×
948
        new LinkedHashMap<>();
949

950
    for (Pair<Expression, String> outputExpressionAndAlias : outputExpressions) {
×
951
      FunctionExpression rawExpression = (FunctionExpression) outputExpressionAndAlias.getLeft();
×
952
      FunctionExpression measurementExpression =
×
953
          (FunctionExpression) getMeasurementExpression(rawExpression, analysis);
×
954
      outputExpressionToRawExpressionsMap
×
955
          .computeIfAbsent(measurementExpression, v -> new HashSet<>())
×
956
          .add(rawExpression);
×
957

958
      Map<String, String> tagMap =
×
959
          ((MeasurementPath)
960
                  ((TimeSeriesOperand) measurementExpression.getExpressions().get(0)).getPath())
×
961
              .getTagMap();
×
962
      List<String> tagValues = new ArrayList<>();
×
963
      for (String tagKey : tagKeys) {
×
964
        tagValues.add(tagMap.get(tagKey));
×
965
      }
×
966
      tagValuesToGroupedTimeseriesOperands
×
967
          .computeIfAbsent(tagValues, key -> new LinkedHashMap<>())
×
968
          .computeIfAbsent(measurementExpression, key -> new ArrayList<>())
×
969
          .add(rawExpression.getExpressions().get(0));
×
970
    }
×
971

972
    // update outputExpressions
973
    outputExpressions.clear();
×
974
    for (String tagKey : tagKeys) {
×
975
      Expression tagKeyExpression =
×
976
          TimeSeriesOperand.constructColumnHeaderExpression(tagKey, TSDataType.TEXT);
×
977
      analyzeExpressionType(analysis, tagKeyExpression);
×
978
      outputExpressions.add(new Pair<>(tagKeyExpression, null));
×
979
    }
×
980
    for (Expression outputExpression : outputExpressionToRawExpressionsMap.keySet()) {
×
981
      // TODO: support alias
982
      analyzeExpressionType(analysis, outputExpression);
×
983
      outputExpressions.add(new Pair<>(outputExpression, null));
×
984
    }
×
985
    analysis.setTagKeys(queryStatement.getGroupByTagComponent().getTagKeys());
×
986
    analysis.setTagValuesToGroupedTimeseriesOperands(tagValuesToGroupedTimeseriesOperands);
×
987
    analysis.setCrossGroupByExpressions(outputExpressionToRawExpressionsMap);
×
988
  }
×
989

990
  private void analyzeDeviceToAggregation(Analysis analysis, QueryStatement queryStatement) {
991
    if (!queryStatement.isAggregationQuery()) {
1✔
992
      return;
1✔
993
    }
994

995
    updateDeviceToAggregationAndOutputExpressions(
1✔
996
        analysis, analysis.getDeviceToSelectExpressions());
1✔
997

998
    if (queryStatement.hasOrderByExpression()) {
1✔
999
      updateDeviceToAggregationAndOutputExpressions(
1✔
1000
          analysis, analysis.getDeviceToOrderByExpressions());
1✔
1001
    }
1002
  }
1✔
1003

1004
  private void updateDeviceToAggregationAndOutputExpressions(
1005
      Analysis analysis, Map<String, Set<Expression>> deviceToExpressions) {
1006
    // two maps to be updated
1007
    Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
1008
        analysis.getDeviceToAggregationExpressions();
1✔
1009
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
1010
        analysis.getDeviceToOutputExpressions();
1✔
1011

1012
    for (Map.Entry<String, Set<Expression>> deviceExpressionsEntry :
1013
        deviceToExpressions.entrySet()) {
1✔
1014
      String deviceName = deviceExpressionsEntry.getKey();
1✔
1015
      Set<Expression> expressionSet = deviceExpressionsEntry.getValue();
1✔
1016

1017
      for (Expression expression : expressionSet) {
1✔
1018
        for (Expression aggregationExpression : searchAggregationExpressions(expression)) {
1✔
1019
          Expression normalizedAggregationExpression = normalizeExpression(aggregationExpression);
1✔
1020

1021
          analyzeExpressionType(analysis, normalizedAggregationExpression);
1✔
1022

1023
          deviceToOutputExpressions
1✔
1024
              .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1025
              .add(aggregationExpression);
1✔
1026
          deviceToAggregationExpressions
1✔
1027
              .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1028
              .add(normalizedAggregationExpression);
1✔
1029
        }
1✔
1030
      }
1✔
1031
    }
1✔
1032
  }
1✔
1033

1034
  private void analyzeAggregation(Analysis analysis, QueryStatement queryStatement) {
1035
    if (!queryStatement.isAggregationQuery()) {
1✔
1036
      return;
1✔
1037
    }
1038

1039
    if (queryStatement.isGroupByLevel() || queryStatement.isGroupByTag()) {
1✔
1040
      Set<Expression> aggregationExpressions =
×
1041
          analysis.getCrossGroupByExpressions().values().stream()
×
1042
              .flatMap(Set::stream)
×
1043
              .collect(Collectors.toSet());
×
1044
      analysis.setAggregationExpressions(aggregationExpressions);
×
1045
      return;
×
1046
    }
1047

1048
    Set<Expression> aggregationExpressions = new HashSet<>();
1✔
1049
    for (Expression expression : analysis.getSelectExpressions()) {
1✔
1050
      aggregationExpressions.addAll(searchAggregationExpressions(expression));
1✔
1051
    }
1✔
1052
    if (queryStatement.hasHaving()) {
1✔
1053
      aggregationExpressions.addAll(searchAggregationExpressions(analysis.getHavingExpression()));
1✔
1054
    }
1055
    if (queryStatement.hasOrderByExpression()) {
1✔
1056
      for (Expression expression : analysis.getOrderByExpressions()) {
1✔
1057
        aggregationExpressions.addAll(searchAggregationExpressions(expression));
1✔
1058
      }
1✔
1059
    }
1060
    analysis.setAggregationExpressions(aggregationExpressions);
1✔
1061
  }
1✔
1062

1063
  private void analyzeDeviceToSourceTransform(Analysis analysis, QueryStatement queryStatement) {
1064
    if (queryStatement.isAggregationQuery()) {
1✔
1065
      Map<String, Set<Expression>> deviceToSourceTransformExpressions =
1✔
1066
          analysis.getDeviceToSourceTransformExpressions();
1✔
1067
      Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
1068
          analysis.getDeviceToAggregationExpressions();
1✔
1069

1070
      for (Map.Entry<String, Set<Expression>> entry : deviceToAggregationExpressions.entrySet()) {
1✔
1071
        String deviceName = entry.getKey();
1✔
1072
        Set<Expression> aggregationExpressions = entry.getValue();
1✔
1073

1074
        Set<Expression> sourceTransformExpressions =
1✔
1075
            deviceToSourceTransformExpressions.computeIfAbsent(
1✔
1076
                deviceName, k -> new LinkedHashSet<>());
1✔
1077

1078
        for (Expression expression : aggregationExpressions) {
1✔
1079
          // if count_time aggregation exist, it can exist only one count_time(*)
1080
          if (queryStatement.isCountTimeAggregation()) {
1✔
1081
            for (Expression countTimeSourceExpression :
1082
                ((FunctionExpression) expression).getCountTimeExpressions()) {
×
1083

1084
              analyzeExpressionType(analysis, countTimeSourceExpression);
×
1085
              sourceTransformExpressions.add(countTimeSourceExpression);
×
1086
            }
×
1087
          } else {
1088
            // We just process first input Expression of AggregationFunction,
1089
            // keep other input Expressions as origin
1090
            // If AggregationFunction need more than one input series,
1091
            // we need to reconsider the process of it
1092
            sourceTransformExpressions.add(expression.getExpressions().get(0));
1✔
1093
          }
1094
        }
1✔
1095

1096
        if (queryStatement.hasGroupByExpression()) {
1✔
1097
          sourceTransformExpressions.add(analysis.getDeviceToGroupByExpression().get(deviceName));
×
1098
        }
1099
      }
1✔
1100
    } else {
1✔
1101
      updateDeviceToSourceTransformAndOutputExpressions(
1✔
1102
          analysis, analysis.getDeviceToSelectExpressions());
1✔
1103
      if (queryStatement.hasOrderByExpression()) {
1✔
1104
        updateDeviceToSourceTransformAndOutputExpressions(
1✔
1105
            analysis, analysis.getDeviceToOrderByExpressions());
1✔
1106
      }
1107
    }
1108
  }
1✔
1109

1110
  private void updateDeviceToSourceTransformAndOutputExpressions(
1111
      Analysis analysis, Map<String, Set<Expression>> deviceToExpressions) {
1112
    // two maps to be updated
1113
    Map<String, Set<Expression>> deviceToSourceTransformExpressions =
1✔
1114
        analysis.getDeviceToSourceTransformExpressions();
1✔
1115
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
1116
        analysis.getDeviceToOutputExpressions();
1✔
1117

1118
    for (Map.Entry<String, Set<Expression>> deviceExpressionsEntry :
1119
        deviceToExpressions.entrySet()) {
1✔
1120
      String deviceName = deviceExpressionsEntry.getKey();
1✔
1121
      Set<Expression> expressions = deviceExpressionsEntry.getValue();
1✔
1122

1123
      Set<Expression> normalizedExpressions = new LinkedHashSet<>();
1✔
1124
      for (Expression expression : expressions) {
1✔
1125
        Expression normalizedExpression = normalizeExpression(expression);
1✔
1126
        analyzeExpressionType(analysis, normalizedExpression);
1✔
1127

1128
        normalizedExpressions.add(normalizedExpression);
1✔
1129
      }
1✔
1130
      deviceToOutputExpressions
1✔
1131
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1132
          .addAll(expressions);
1✔
1133
      deviceToSourceTransformExpressions
1✔
1134
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1135
          .addAll(normalizedExpressions);
1✔
1136
    }
1✔
1137
  }
1✔
1138

1139
  private void analyzeSourceTransform(
1140
      Analysis analysis,
1141
      List<Pair<Expression, String>> outputExpressions,
1142
      QueryStatement queryStatement) {
1143
    Set<Expression> sourceTransformExpressions = analysis.getSourceTransformExpressions();
1✔
1144

1145
    if (queryStatement.isAggregationQuery()) {
1✔
1146
      if (queryStatement.isCountTimeAggregation()) {
1✔
1147

1148
        for (Pair<Expression, String> pair : outputExpressions) {
×
1149
          FunctionExpression countTimeExpression = (FunctionExpression) pair.left;
×
1150
          for (Expression countTimeSourceExpression :
1151
              countTimeExpression.getCountTimeExpressions()) {
×
1152
            analyzeExpressionType(analysis, countTimeSourceExpression);
×
1153
            sourceTransformExpressions.add(countTimeSourceExpression);
×
1154
          }
×
1155
        }
×
1156

1157
        // count_time only returns one result
1158
        Pair<Expression, String> firstCountTimeExpression = outputExpressions.get(0);
×
1159
        outputExpressions.clear();
×
1160
        outputExpressions.add(firstCountTimeExpression);
×
1161

1162
      } else {
×
1163
        for (Expression aggExpression : analysis.getAggregationExpressions()) {
1✔
1164
          // for AggregationExpression, only the first Expression of input need to transform
1165
          sourceTransformExpressions.add(aggExpression.getExpressions().get(0));
1✔
1166
        }
1✔
1167
      }
1168

1169
      if (queryStatement.hasGroupByExpression()) {
1✔
1170
        sourceTransformExpressions.add(analysis.getGroupByExpression());
×
1171
      }
1172
    } else {
1173
      sourceTransformExpressions.addAll(analysis.getSelectExpressions());
1✔
1174
      if (queryStatement.hasOrderByExpression()) {
1✔
1175
        sourceTransformExpressions.addAll(analysis.getOrderByExpressions());
1✔
1176
      }
1177
    }
1178
  }
1✔
1179

1180
  private void analyzeDeviceToSource(Analysis analysis, QueryStatement queryStatement) {
1181
    Map<String, Set<Expression>> deviceToSourceExpressions = new HashMap<>();
1✔
1182
    Map<String, Set<Expression>> deviceToSourceTransformExpressions =
1✔
1183
        analysis.getDeviceToSourceTransformExpressions();
1✔
1184

1185
    for (Map.Entry<String, Set<Expression>> entry : deviceToSourceTransformExpressions.entrySet()) {
1✔
1186
      String deviceName = entry.getKey();
1✔
1187
      Set<Expression> sourceTransformExpressions = entry.getValue();
1✔
1188

1189
      Set<Expression> sourceExpressions = new LinkedHashSet<>();
1✔
1190
      sourceTransformExpressions.forEach(
1✔
1191
          expression -> sourceExpressions.addAll(searchSourceExpressions(expression)));
1✔
1192

1193
      deviceToSourceExpressions.put(deviceName, sourceExpressions);
1✔
1194
    }
1✔
1195

1196
    if (queryStatement.hasWhere()) {
1✔
1197
      Map<String, Expression> deviceToWhereExpression = analysis.getDeviceToWhereExpression();
1✔
1198
      for (Map.Entry<String, Expression> deviceWhereExpressionEntry :
1199
          deviceToWhereExpression.entrySet()) {
1✔
1200
        String deviceName = deviceWhereExpressionEntry.getKey();
1✔
1201
        Expression whereExpression = deviceWhereExpressionEntry.getValue();
1✔
1202
        deviceToSourceExpressions
1✔
1203
            .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1204
            .addAll(searchSourceExpressions(whereExpression));
1✔
1205
      }
1✔
1206
    }
1207

1208
    Map<String, List<String>> outputDeviceToQueriedDevicesMap = new LinkedHashMap<>();
1✔
1209
    for (Map.Entry<String, Set<Expression>> entry : deviceToSourceExpressions.entrySet()) {
1✔
1210
      String deviceName = entry.getKey();
1✔
1211
      Set<Expression> sourceExpressionsUnderDevice = entry.getValue();
1✔
1212
      Set<String> queriedDevices = new HashSet<>();
1✔
1213
      for (Expression expression : sourceExpressionsUnderDevice) {
1✔
1214
        queriedDevices.add(ExpressionAnalyzer.getDeviceNameInSourceExpression(expression));
1✔
1215
      }
1✔
1216
      if (queriedDevices.size() > 1) {
1✔
1217
        throw new SemanticException(
×
1218
            "Cross-device queries are not supported in ALIGN BY DEVICE queries.");
1219
      }
1220
      outputDeviceToQueriedDevicesMap.put(deviceName, new ArrayList<>(queriedDevices));
1✔
1221
    }
1✔
1222

1223
    analysis.setDeviceToSourceExpressions(deviceToSourceExpressions);
1✔
1224
    analysis.setOutputDeviceToQueriedDevicesMap(outputDeviceToQueriedDevicesMap);
1✔
1225
  }
1✔
1226

1227
  private void analyzeSource(Analysis analysis, QueryStatement queryStatement) {
1228
    Set<Expression> sourceExpressions = analysis.getSourceExpressions();
1✔
1229
    if (sourceExpressions == null) {
1✔
1230
      sourceExpressions = new HashSet<>();
1✔
1231
      analysis.setSourceExpressions(sourceExpressions);
1✔
1232
    }
1233

1234
    for (Expression expression : analysis.getSourceTransformExpressions()) {
1✔
1235
      sourceExpressions.addAll(searchSourceExpressions(expression));
1✔
1236
    }
1✔
1237
    if (queryStatement.hasWhere()) {
1✔
1238
      sourceExpressions.addAll(searchSourceExpressions(analysis.getWhereExpression()));
1✔
1239
    }
1240
  }
1✔
1241

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

1245
  private void analyzeDeviceToWhere(
1246
      Analysis analysis,
1247
      QueryStatement queryStatement,
1248
      ISchemaTree schemaTree,
1249
      List<PartialPath> deviceSet) {
1250
    if (!queryStatement.hasWhere()) {
1✔
1251
      return;
1✔
1252
    }
1253

1254
    Map<String, Expression> deviceToWhereExpression = new HashMap<>();
1✔
1255
    Iterator<PartialPath> deviceIterator = deviceSet.iterator();
1✔
1256
    while (deviceIterator.hasNext()) {
1✔
1257
      PartialPath devicePath = deviceIterator.next();
1✔
1258
      Expression whereExpression;
1259
      try {
1260
        whereExpression =
1✔
1261
            normalizeExpression(analyzeWhereSplitByDevice(queryStatement, devicePath, schemaTree));
1✔
1262
      } catch (MeasurementNotExistException e) {
×
1263
        logger.warn(
×
1264
            "Meets MeasurementNotExistException in analyzeDeviceToWhere when executing align by device, "
1265
                + "error msg: {}",
1266
            e.getMessage());
×
1267
        deviceIterator.remove();
×
1268
        continue;
×
1269
      }
1✔
1270

1271
      TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
1✔
1272
      if (outputType != TSDataType.BOOLEAN) {
1✔
1273
        throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
1274
      }
1275

1276
      deviceToWhereExpression.put(devicePath.getFullPath(), whereExpression);
1✔
1277
    }
1✔
1278
    analysis.setDeviceToWhereExpression(deviceToWhereExpression);
1✔
1279
  }
1✔
1280

1281
  private void analyzeWhere(
1282
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1283
    if (!queryStatement.hasWhere()) {
1✔
1284
      return;
1✔
1285
    }
1286
    List<Expression> conJunctions =
1✔
1287
        ExpressionAnalyzer.bindSchemaForPredicate(
1✔
1288
            queryStatement.getWhereCondition().getPredicate(),
1✔
1289
            queryStatement.getFromComponent().getPrefixPaths(),
1✔
1290
            schemaTree,
1291
            true);
1292
    Expression whereExpression =
1✔
1293
        ExpressionUtils.constructQueryFilter(
1✔
1294
            conJunctions.stream().distinct().collect(Collectors.toList()));
1✔
1295
    whereExpression = normalizeExpression(whereExpression);
1✔
1296
    TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
1✔
1297
    if (outputType != TSDataType.BOOLEAN) {
1✔
1298
      throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
1299
    }
1300
    analysis.setWhereExpression(whereExpression);
1✔
1301
  }
1✔
1302

1303
  private Expression analyzeWhereSplitByDevice(
1304
      QueryStatement queryStatement, PartialPath devicePath, ISchemaTree schemaTree) {
1305
    List<Expression> conJunctions =
1✔
1306
        ExpressionAnalyzer.concatDeviceAndBindSchemaForPredicate(
1✔
1307
            queryStatement.getWhereCondition().getPredicate(), devicePath, schemaTree, true);
1✔
1308
    return ExpressionUtils.constructQueryFilter(
1✔
1309
        conJunctions.stream().distinct().collect(Collectors.toList()));
1✔
1310
  }
1311

1312
  private void analyzeDeviceViewOutput(Analysis analysis, QueryStatement queryStatement) {
1313
    Set<Expression> selectExpressions = analysis.getSelectExpressions();
1✔
1314
    Set<Expression> deviceViewOutputExpressions = new LinkedHashSet<>();
1✔
1315
    if (queryStatement.isAggregationQuery()) {
1✔
1316
      deviceViewOutputExpressions.add(DEVICE_EXPRESSION);
1✔
1317
      if (queryStatement.isOutputEndTime()) {
1✔
1318
        deviceViewOutputExpressions.add(END_TIME_EXPRESSION);
×
1319
      }
1320
      for (Expression selectExpression : selectExpressions) {
1✔
1321
        deviceViewOutputExpressions.addAll(searchAggregationExpressions(selectExpression));
1✔
1322
      }
1✔
1323
      if (queryStatement.hasHaving()) {
1✔
1324
        deviceViewOutputExpressions.addAll(
1✔
1325
            searchAggregationExpressions(analysis.getHavingExpression()));
1✔
1326
      }
1327
      if (queryStatement.hasOrderByExpression()) {
1✔
1328
        for (Expression orderByExpression : analysis.getOrderByExpressions()) {
1✔
1329
          deviceViewOutputExpressions.addAll(searchAggregationExpressions(orderByExpression));
1✔
1330
        }
1✔
1331
      }
1332
    } else {
1333
      deviceViewOutputExpressions.addAll(selectExpressions);
1✔
1334
      if (queryStatement.hasOrderByExpression()) {
1✔
1335
        deviceViewOutputExpressions.addAll(analysis.getOrderByExpressions());
1✔
1336
      }
1337
    }
1338
    analysis.setDeviceViewOutputExpressions(deviceViewOutputExpressions);
1✔
1339
    analysis.setDeviceViewSpecialProcess(
1✔
1340
        analyzeDeviceViewSpecialProcess(deviceViewOutputExpressions, queryStatement, analysis));
1✔
1341
  }
1✔
1342

1343
  private boolean analyzeDeviceViewSpecialProcess(
1344
      Set<Expression> deviceViewOutputExpressions,
1345
      QueryStatement queryStatement,
1346
      Analysis analysis) {
1347
    if (queryStatement.isAggregationQuery()
1✔
1348
        || queryStatement.hasWhere()
1✔
1349
            && ExpressionAnalyzer.isDeviceViewNeedSpecialProcess(
1✔
1350
                queryStatement.getWhereCondition().getPredicate(), analysis)) {
1✔
1351
      return true;
1✔
1352
    }
1353
    for (Expression expression : deviceViewOutputExpressions) {
1✔
1354
      if (ExpressionAnalyzer.isDeviceViewNeedSpecialProcess(expression, analysis)) {
1✔
1355
        return true;
1✔
1356
      }
1357
    }
1✔
1358
    return false;
1✔
1359
  }
1360

1361
  private void analyzeDeviceViewInput(Analysis analysis, QueryStatement queryStatement) {
1362
    List<String> deviceViewOutputColumns =
1✔
1363
        analysis.getDeviceViewOutputExpressions().stream()
1✔
1364
            .map(Expression::getOutputSymbol)
1✔
1365
            .collect(Collectors.toList());
1✔
1366

1367
    Map<String, Set<String>> deviceToOutputColumnsMap = new LinkedHashMap<>();
1✔
1368
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
1369
        analysis.getDeviceToOutputExpressions();
1✔
1370
    for (Map.Entry<String, Set<Expression>> deviceOutputExpressionEntry :
1371
        deviceToOutputExpressions.entrySet()) {
1✔
1372
      Set<Expression> outputExpressionsUnderDevice = deviceOutputExpressionEntry.getValue();
1✔
1373
      checkDeviceViewInputUniqueness(outputExpressionsUnderDevice);
1✔
1374

1375
      Set<String> outputColumns = new LinkedHashSet<>();
1✔
1376
      if (queryStatement.isOutputEndTime()) {
1✔
1377
        outputColumns.add(ENDTIME);
×
1378
      }
1379
      for (Expression expression : outputExpressionsUnderDevice) {
1✔
1380
        outputColumns.add(getMeasurementExpression(expression, analysis).getOutputSymbol());
1✔
1381
      }
1✔
1382
      deviceToOutputColumnsMap.put(deviceOutputExpressionEntry.getKey(), outputColumns);
1✔
1383
    }
1✔
1384

1385
    Map<String, List<Integer>> deviceViewInputIndexesMap = new HashMap<>();
1✔
1386
    for (Map.Entry<String, Set<String>> deviceOutputColumnsEntry :
1387
        deviceToOutputColumnsMap.entrySet()) {
1✔
1388
      String deviceName = deviceOutputColumnsEntry.getKey();
1✔
1389
      List<String> outputsUnderDevice = new ArrayList<>(deviceOutputColumnsEntry.getValue());
1✔
1390

1391
      List<Integer> indexes = new ArrayList<>();
1✔
1392
      for (String output : outputsUnderDevice) {
1✔
1393
        int index = deviceViewOutputColumns.indexOf(output);
1✔
1394
        checkState(
1✔
1395
            index >= 1, "output column '%s' is not stored in %s", output, deviceViewOutputColumns);
1396
        indexes.add(index);
1✔
1397
      }
1✔
1398
      deviceViewInputIndexesMap.put(deviceName, indexes);
1✔
1399
    }
1✔
1400
    analysis.setDeviceViewInputIndexesMap(deviceViewInputIndexesMap);
1✔
1401
  }
1✔
1402

1403
  private void checkDeviceViewInputUniqueness(Set<Expression> outputExpressionsUnderDevice) {
1404
    Set<Expression> normalizedOutputExpressionsUnderDevice =
1✔
1405
        outputExpressionsUnderDevice.stream()
1✔
1406
            .map(ExpressionAnalyzer::normalizeExpression)
1✔
1407
            .collect(Collectors.toSet());
1✔
1408
    if (normalizedOutputExpressionsUnderDevice.size() < outputExpressionsUnderDevice.size()) {
1✔
1409
      throw new SemanticException(
×
1410
          "Views or measurement aliases representing the same data source "
1411
              + "cannot be queried concurrently in ALIGN BY DEVICE queries.");
1412
    }
1413
  }
1✔
1414

1415
  private void analyzeOutput(
1416
      Analysis analysis,
1417
      QueryStatement queryStatement,
1418
      List<Pair<Expression, String>> outputExpressions) {
1419
    if (queryStatement.isSelectInto()) {
1✔
1420
      analysis.setRespDatasetHeader(
1✔
1421
          DatasetHeaderFactory.getSelectIntoHeader(queryStatement.isAlignByDevice()));
1✔
1422
      return;
1✔
1423
    }
1424

1425
    boolean isIgnoreTimestamp = queryStatement.isAggregationQuery() && !queryStatement.isGroupBy();
1✔
1426
    List<ColumnHeader> columnHeaders = new ArrayList<>();
1✔
1427
    if (queryStatement.isAlignByDevice()) {
1✔
1428
      columnHeaders.add(new ColumnHeader(DEVICE, TSDataType.TEXT, null));
1✔
1429
    }
1430
    if (queryStatement.isOutputEndTime()) {
1✔
1431
      columnHeaders.add(new ColumnHeader(ENDTIME, TSDataType.INT64, null));
×
1432
    }
1433
    for (Pair<Expression, String> expressionAliasPair : outputExpressions) {
1✔
1434
      columnHeaders.add(
1✔
1435
          new ColumnHeader(
1436
              expressionAliasPair.left.getExpressionString(),
1✔
1437
              analysis.getType(expressionAliasPair.left),
1✔
1438
              expressionAliasPair.right));
1439
    }
1✔
1440
    analysis.setRespDatasetHeader(new DatasetHeader(columnHeaders, isIgnoreTimestamp));
1✔
1441
  }
1✔
1442

1443
  // For last query
1444
  private void analyzeLastOrderBy(Analysis analysis, QueryStatement queryStatement) {
1445
    if (!queryStatement.hasOrderBy()) return;
×
1446

1447
    if (queryStatement.onlyOrderByTimeseries()) {
×
1448
      analysis.setTimeseriesOrderingForLastQuery(
×
1449
          queryStatement.getOrderByComponent().getTimeseriesOrder());
×
1450
    }
1451

1452
    for (SortItem sortItem : queryStatement.getSortItemList()) {
×
1453
      String sortKey = sortItem.getSortKey();
×
1454
      if (!lastQueryColumnNames.contains(sortKey.toUpperCase())) {
×
1455
        throw new SemanticException(
×
1456
            String.format(
×
1457
                "%s in order by clause doesn't exist in the result of last query.", sortKey));
1458
      }
1459
    }
×
1460
  }
×
1461

1462
  private void analyzeOrderBy(
1463
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1464
    if (!queryStatement.hasOrderByExpression()) return;
1✔
1465

1466
    Set<Expression> orderByExpressions = new LinkedHashSet<>();
1✔
1467
    for (Expression expressionForItem : queryStatement.getExpressionSortItemList()) {
1✔
1468
      // Expression in a sortItem only indicates one column
1469
      List<Expression> expressions = bindSchemaForExpression(expressionForItem, schemaTree);
1✔
1470
      if (expressions.isEmpty()) {
1✔
1471
        throw new SemanticException(
×
1472
            String.format(
×
1473
                "%s in order by clause doesn't exist.", expressionForItem.getExpressionString()));
×
1474
      }
1475
      if (expressions.size() > 1) {
1✔
1476
        throw new SemanticException(
×
1477
            String.format(
×
1478
                "%s in order by clause shouldn't refer to more than one timeseries.",
1479
                expressionForItem.getExpressionString()));
×
1480
      }
1481
      expressionForItem = normalizeExpression(expressions.get(0));
1✔
1482
      TSDataType dataType = analyzeExpressionType(analysis, expressionForItem);
1✔
1483
      if (!dataType.isComparable()) {
1✔
1484
        throw new SemanticException(
×
1485
            String.format("The data type of %s is not comparable", dataType));
×
1486
      }
1487
      orderByExpressions.add(expressionForItem);
1✔
1488
    }
1✔
1489
    analysis.setOrderByExpressions(orderByExpressions);
1✔
1490
    queryStatement.updateSortItems(orderByExpressions);
1✔
1491
  }
1✔
1492

1493
  private TSDataType analyzeExpressionType(Analysis analysis, Expression expression) {
1494
    return ExpressionTypeAnalyzer.analyzeExpression(analysis, expression);
1✔
1495
  }
1496

1497
  private void analyzeDeviceToGroupBy(
1498
      Analysis analysis,
1499
      QueryStatement queryStatement,
1500
      ISchemaTree schemaTree,
1501
      List<PartialPath> deviceSet) {
1502
    if (queryStatement.getGroupByComponent() == null) {
1✔
1503
      return;
1✔
1504
    }
1505
    GroupByComponent groupByComponent = queryStatement.getGroupByComponent();
×
1506
    WindowType windowType = groupByComponent.getWindowType();
×
1507

1508
    Map<String, Expression> deviceToGroupByExpression = new LinkedHashMap<>();
×
1509
    if (queryStatement.hasGroupByExpression()) {
×
1510
      Expression expression = groupByComponent.getControlColumnExpression();
×
1511
      for (PartialPath device : deviceSet) {
×
1512
        List<Expression> groupByExpressionsOfOneDevice =
×
1513
            concatDeviceAndBindSchemaForExpression(expression, device, schemaTree);
×
1514

1515
        if (groupByExpressionsOfOneDevice.isEmpty()) {
×
1516
          throw new SemanticException(
×
1517
              String.format("%s in group by clause doesn't exist.", expression));
×
1518
        }
1519
        if (groupByExpressionsOfOneDevice.size() > 1) {
×
1520
          throw new SemanticException(
×
1521
              String.format(
×
1522
                  "%s in group by clause shouldn't refer to more than one timeseries.",
1523
                  expression));
1524
        }
1525
        deviceToGroupByExpression.put(
×
1526
            device.getFullPath(), normalizeExpression(groupByExpressionsOfOneDevice.get(0)));
×
1527
      }
×
1528
    }
1529

1530
    GroupByParameter groupByParameter;
1531
    switch (windowType) {
×
1532
      case VARIATION_WINDOW:
1533
        double delta = ((GroupByVariationComponent) groupByComponent).getDelta();
×
1534
        for (Expression expression : deviceToGroupByExpression.values()) {
×
1535
          checkGroupByVariationExpressionType(analysis, expression, delta);
×
1536
        }
×
1537
        groupByParameter = new GroupByVariationParameter(groupByComponent.isIgnoringNull(), delta);
×
1538
        analysis.setDeviceToGroupByExpression(deviceToGroupByExpression);
×
1539
        break;
×
1540
      case CONDITION_WINDOW:
1541
        Expression keepExpression =
×
1542
            ((GroupByConditionComponent) groupByComponent).getKeepExpression();
×
1543
        for (Expression expression : deviceToGroupByExpression.values()) {
×
1544
          checkGroupByConditionExpressionType(analysis, expression, keepExpression);
×
1545
        }
×
1546
        groupByParameter =
×
1547
            new GroupByConditionParameter(groupByComponent.isIgnoringNull(), keepExpression);
×
1548
        analysis.setDeviceToGroupByExpression(deviceToGroupByExpression);
×
1549
        break;
×
1550
      case SESSION_WINDOW:
1551
        groupByParameter =
×
1552
            new GroupBySessionParameter(
1553
                ((GroupBySessionComponent) groupByComponent).getTimeInterval());
×
1554
        break;
×
1555
      case COUNT_WINDOW:
1556
        groupByParameter =
×
1557
            new GroupByCountParameter(
1558
                ((GroupByCountComponent) groupByComponent).getCountNumber(),
×
1559
                groupByComponent.isIgnoringNull());
×
1560
        analysis.setDeviceToGroupByExpression(deviceToGroupByExpression);
×
1561
        break;
×
1562
      default:
1563
        throw new UnsupportedOperationException("Unsupported window type");
×
1564
    }
1565
    analysis.setGroupByParameter(groupByParameter);
×
1566
  }
×
1567

1568
  private void analyzeDeviceToOrderBy(
1569
      Analysis analysis,
1570
      QueryStatement queryStatement,
1571
      ISchemaTree schemaTree,
1572
      List<PartialPath> deviceSet) {
1573
    if (!queryStatement.hasOrderByExpression()) {
1✔
1574
      return;
1✔
1575
    }
1576

1577
    Map<String, Set<Expression>> deviceToOrderByExpressions = new LinkedHashMap<>();
1✔
1578
    Map<String, List<SortItem>> deviceToSortItems = new LinkedHashMap<>();
1✔
1579
    // build the device-view outputColumn for the sortNode above the deviceViewNode
1580
    Set<Expression> deviceViewOrderByExpression = new LinkedHashSet<>();
1✔
1581
    for (PartialPath device : deviceSet) {
1✔
1582
      Set<Expression> orderByExpressionsForOneDevice = new LinkedHashSet<>();
1✔
1583
      for (Expression expressionForItem : queryStatement.getExpressionSortItemList()) {
1✔
1584
        List<Expression> expressions =
1✔
1585
            concatDeviceAndBindSchemaForExpression(expressionForItem, device, schemaTree);
1✔
1586
        if (expressions.isEmpty()) {
1✔
1587
          throw new SemanticException(
×
1588
              String.format(
×
1589
                  "%s in order by clause doesn't exist.", expressionForItem.getExpressionString()));
×
1590
        }
1591
        if (expressions.size() > 1) {
1✔
1592
          throw new SemanticException(
×
1593
              String.format(
×
1594
                  "%s in order by clause shouldn't refer to more than one timeseries.",
1595
                  expressionForItem.getExpressionString()));
×
1596
        }
1597
        expressionForItem = expressions.get(0);
1✔
1598
        TSDataType dataType = analyzeExpressionType(analysis, expressionForItem);
1✔
1599
        if (!dataType.isComparable()) {
1✔
1600
          throw new SemanticException(
×
1601
              String.format("The data type of %s is not comparable", dataType));
×
1602
        }
1603

1604
        Expression deviceViewExpression = getMeasurementExpression(expressionForItem, analysis);
1✔
1605
        analyzeExpressionType(analysis, deviceViewExpression);
1✔
1606

1607
        deviceViewOrderByExpression.add(deviceViewExpression);
1✔
1608
        orderByExpressionsForOneDevice.add(expressionForItem);
1✔
1609
      }
1✔
1610
      deviceToSortItems.put(
1✔
1611
          device.getFullPath(), queryStatement.getUpdatedSortItems(orderByExpressionsForOneDevice));
1✔
1612
      deviceToOrderByExpressions.put(device.getFullPath(), orderByExpressionsForOneDevice);
1✔
1613
    }
1✔
1614

1615
    analysis.setOrderByExpressions(deviceViewOrderByExpression);
1✔
1616
    queryStatement.updateSortItems(deviceViewOrderByExpression);
1✔
1617
    analysis.setDeviceToSortItems(deviceToSortItems);
1✔
1618
    analysis.setDeviceToOrderByExpressions(deviceToOrderByExpressions);
1✔
1619
  }
1✔
1620

1621
  private void analyzeGroupBy(
1622
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1623

1624
    if (queryStatement.getGroupByComponent() == null) {
1✔
1625
      return;
1✔
1626
    }
1627
    GroupByComponent groupByComponent = queryStatement.getGroupByComponent();
×
1628
    WindowType windowType = groupByComponent.getWindowType();
×
1629

1630
    Expression groupByExpression = null;
×
1631
    if (queryStatement.hasGroupByExpression()) {
×
1632
      groupByExpression = groupByComponent.getControlColumnExpression();
×
1633
      // Expression in group by variation clause only indicates one column
1634
      List<Expression> expressions = bindSchemaForExpression(groupByExpression, schemaTree);
×
1635
      if (expressions.isEmpty()) {
×
1636
        throw new SemanticException(
×
1637
            String.format(
×
1638
                "%s in group by clause doesn't exist.", groupByExpression.getExpressionString()));
×
1639
      }
1640
      if (expressions.size() > 1) {
×
1641
        throw new SemanticException(
×
1642
            String.format(
×
1643
                "%s in group by clause shouldn't refer to more than one timeseries.",
1644
                groupByExpression.getExpressionString()));
×
1645
      }
1646
      // Aggregation expression shouldn't exist in group by clause.
1647
      List<Expression> aggregationExpression = searchAggregationExpressions(expressions.get(0));
×
1648
      if (aggregationExpression != null && !aggregationExpression.isEmpty()) {
×
1649
        throw new SemanticException("Aggregation expression shouldn't exist in group by clause");
×
1650
      }
1651
      groupByExpression = normalizeExpression(expressions.get(0));
×
1652
    }
1653

1654
    if (windowType == WindowType.VARIATION_WINDOW) {
×
1655
      double delta = ((GroupByVariationComponent) groupByComponent).getDelta();
×
1656
      checkGroupByVariationExpressionType(analysis, groupByExpression, delta);
×
1657
      GroupByParameter groupByParameter =
×
1658
          new GroupByVariationParameter(groupByComponent.isIgnoringNull(), delta);
×
1659
      analysis.setGroupByExpression(groupByExpression);
×
1660
      analysis.setGroupByParameter(groupByParameter);
×
1661
    } else if (windowType == WindowType.CONDITION_WINDOW) {
×
1662
      Expression keepExpression =
×
1663
          ((GroupByConditionComponent) groupByComponent).getKeepExpression();
×
1664
      checkGroupByConditionExpressionType(analysis, groupByExpression, keepExpression);
×
1665
      GroupByParameter groupByParameter =
×
1666
          new GroupByConditionParameter(groupByComponent.isIgnoringNull(), keepExpression);
×
1667
      analysis.setGroupByExpression(groupByExpression);
×
1668
      analysis.setGroupByParameter(groupByParameter);
×
1669
    } else if (windowType == WindowType.SESSION_WINDOW) {
×
1670
      long interval = ((GroupBySessionComponent) groupByComponent).getTimeInterval();
×
1671
      GroupByParameter groupByParameter = new GroupBySessionParameter(interval);
×
1672
      analysis.setGroupByParameter(groupByParameter);
×
1673
    } else if (windowType == WindowType.COUNT_WINDOW) {
×
1674
      GroupByParameter groupByParameter =
×
1675
          new GroupByCountParameter(
1676
              ((GroupByCountComponent) groupByComponent).getCountNumber(),
×
1677
              groupByComponent.isIgnoringNull());
×
1678
      analyzeExpressionType(analysis, groupByExpression);
×
1679
      analysis.setGroupByExpression(groupByExpression);
×
1680
      analysis.setGroupByParameter(groupByParameter);
×
1681
    } else {
×
1682
      throw new SemanticException("Unsupported window type");
×
1683
    }
1684
  }
×
1685

1686
  private void checkGroupByVariationExpressionType(
1687
      Analysis analysis, Expression groupByExpression, double delta) {
1688
    TSDataType type = analyzeExpressionType(analysis, groupByExpression);
×
1689
    if (delta != 0 && !type.isNumeric()) {
×
1690
      throw new SemanticException("Only support numeric type when delta != 0");
×
1691
    }
1692
  }
×
1693

1694
  private void checkGroupByConditionExpressionType(
1695
      Analysis analysis, Expression groupByExpression, Expression keepExpression) {
1696
    TSDataType type = analyzeExpressionType(analysis, groupByExpression);
×
1697
    if (type != TSDataType.BOOLEAN) {
×
1698
      throw new SemanticException("Only support boolean type in predict of group by series");
×
1699
    }
1700

1701
    // check keep Expression
1702
    if (keepExpression instanceof CompareBinaryExpression) {
×
1703
      Expression leftExpression = ((CompareBinaryExpression) keepExpression).getLeftExpression();
×
1704
      Expression rightExpression = ((CompareBinaryExpression) keepExpression).getRightExpression();
×
1705
      if (!(leftExpression instanceof TimeSeriesOperand
×
1706
          && leftExpression.getExpressionString().equalsIgnoreCase("keep")
×
1707
          && rightExpression instanceof ConstantOperand)) {
1708
        throw new SemanticException(
×
1709
            String.format(
×
1710
                "Please check the keep condition ([%s]),it need to be a constant or a compare expression constructed by 'keep' and a long number.",
1711
                keepExpression.getExpressionString()));
×
1712
      }
1713
      return;
×
1714
    }
1715
    if (!(keepExpression instanceof ConstantOperand)) {
×
1716
      throw new SemanticException(
×
1717
          String.format(
×
1718
              "Please check the keep condition ([%s]),it need to be a constant or a compare expression constructed by 'keep' and a long number.",
1719
              keepExpression.getExpressionString()));
×
1720
    }
1721
  }
×
1722

1723
  private void analyzeGroupByTime(Analysis analysis, QueryStatement queryStatement) {
1724
    if (!queryStatement.isGroupByTime()) {
1✔
1725
      return;
1✔
1726
    }
1727

1728
    if (queryStatement.isResultSetEmpty()) {
1✔
1729
      analysis.setFinishQueryAfterAnalyze(true);
×
1730
    }
1731

1732
    GroupByTimeComponent groupByTimeComponent = queryStatement.getGroupByTimeComponent();
1✔
1733
    if ((groupByTimeComponent.isIntervalByMonth() || groupByTimeComponent.isSlidingStepByMonth())
1✔
1734
        && queryStatement.getResultTimeOrder() == Ordering.DESC) {
×
1735
      throw new SemanticException("Group by month doesn't support order by time desc now.");
×
1736
    }
1737
    if (!queryStatement.isCqQueryBody()
1✔
1738
        && (groupByTimeComponent.getStartTime() == 0 && groupByTimeComponent.getEndTime() == 0)) {
1✔
1739
      throw new SemanticException(
×
1740
          "The query time range should be specified in the GROUP BY TIME clause.");
1741
    }
1742
    analysis.setGroupByTimeParameter(new GroupByTimeParameter(groupByTimeComponent));
1✔
1743

1744
    Filter globalTimeFilter = analysis.getGlobalTimeFilter();
1✔
1745
    Filter groupByFilter = initGroupByFilter(groupByTimeComponent);
1✔
1746
    if (globalTimeFilter == null) {
1✔
1747
      globalTimeFilter = groupByFilter;
1✔
1748
    } else {
1749
      globalTimeFilter = FilterFactory.and(globalTimeFilter, groupByFilter);
1✔
1750
    }
1751
    analysis.setGlobalTimeFilter(globalTimeFilter);
1✔
1752
  }
1✔
1753

1754
  private void analyzeFill(Analysis analysis, QueryStatement queryStatement) {
1755
    if (queryStatement.getFillComponent() == null) {
1✔
1756
      return;
1✔
1757
    }
1758

1759
    FillComponent fillComponent = queryStatement.getFillComponent();
1✔
1760
    analysis.setFillDescriptor(
1✔
1761
        new FillDescriptor(fillComponent.getFillPolicy(), fillComponent.getFillValue()));
1✔
1762
  }
1✔
1763

1764
  private void analyzeDataPartition(
1765
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1766
    Set<String> deviceSet = new HashSet<>();
1✔
1767
    if (queryStatement.isAlignByDevice()) {
1✔
1768
      deviceSet =
1✔
1769
          analysis.getOutputDeviceToQueriedDevicesMap().values().stream()
1✔
1770
              .flatMap(List::stream)
1✔
1771
              .collect(Collectors.toSet());
1✔
1772
    } else {
1773
      for (Expression expression : analysis.getSourceExpressions()) {
1✔
1774
        deviceSet.add(ExpressionAnalyzer.getDeviceNameInSourceExpression(expression));
1✔
1775
      }
1✔
1776
    }
1777
    DataPartition dataPartition =
1✔
1778
        fetchDataPartitionByDevices(deviceSet, schemaTree, analysis.getGlobalTimeFilter());
1✔
1779
    analysis.setDataPartitionInfo(dataPartition);
1✔
1780
  }
1✔
1781

1782
  private DataPartition fetchDataPartitionByDevices(
1783
      Set<String> deviceSet, ISchemaTree schemaTree, Filter globalTimeFilter) {
1784
    long startTime = System.nanoTime();
1✔
1785
    try {
1786
      Pair<List<TTimePartitionSlot>, Pair<Boolean, Boolean>> res =
1✔
1787
          getTimePartitionSlotList(globalTimeFilter);
1✔
1788
      // there is no satisfied time range
1789
      if (res.left.isEmpty() && Boolean.FALSE.equals(res.right.left)) {
1✔
1790
        return new DataPartition(
1✔
1791
            Collections.emptyMap(),
1✔
1792
            CONFIG.getSeriesPartitionExecutorClass(),
1✔
1793
            CONFIG.getSeriesPartitionSlotNum());
1✔
1794
      }
1795
      Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap = new HashMap<>();
1✔
1796
      for (String devicePath : deviceSet) {
1✔
1797
        DataPartitionQueryParam queryParam =
1✔
1798
            new DataPartitionQueryParam(devicePath, res.left, res.right.left, res.right.right);
1✔
1799
        sgNameToQueryParamsMap
1✔
1800
            .computeIfAbsent(schemaTree.getBelongedDatabase(devicePath), key -> new ArrayList<>())
1✔
1801
            .add(queryParam);
1✔
1802
      }
1✔
1803

1804
      if (res.right.left || res.right.right) {
1✔
1805
        return partitionFetcher.getDataPartitionWithUnclosedTimeRange(sgNameToQueryParamsMap);
1✔
1806
      } else {
1807
        return partitionFetcher.getDataPartition(sgNameToQueryParamsMap);
1✔
1808
      }
1809
    } finally {
1810
      QueryPlanCostMetricSet.getInstance()
1✔
1811
          .recordPlanCost(PARTITION_FETCHER, System.nanoTime() - startTime);
1✔
1812
    }
1813
  }
1814

1815
  /**
1816
   * get TTimePartitionSlot list about this time filter
1817
   *
1818
   * @return List<TTimePartitionSlot>, if contains (-oo, XXX] time range, res.right.left = true; if
1819
   *     contains [XX, +oo), res.right.right = true
1820
   */
1821
  @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning
1822
  public static Pair<List<TTimePartitionSlot>, Pair<Boolean, Boolean>> getTimePartitionSlotList(
1823
      Filter timeFilter) {
1824
    if (timeFilter == null) {
1✔
1825
      // (-oo, +oo)
1826
      return new Pair<>(Collections.emptyList(), new Pair<>(true, true));
1✔
1827
    }
1828
    List<TimeRange> timeRangeList = timeFilter.getTimeRanges();
1✔
1829
    if (timeRangeList.isEmpty()) {
1✔
1830
      // no satisfied time range
1831
      return new Pair<>(Collections.emptyList(), new Pair<>(false, false));
1✔
1832
    } else if (timeRangeList.size() == 1
1✔
1833
        && (timeRangeList.get(0).getMin() == Long.MIN_VALUE
1✔
1834
            && timeRangeList.get(timeRangeList.size() - 1).getMax() == Long.MAX_VALUE)) {
1✔
1835
      // (-oo, +oo)
1836
      return new Pair<>(Collections.emptyList(), new Pair<>(true, true));
1✔
1837
    }
1838

1839
    boolean needLeftAll;
1840
    boolean needRightAll;
1841
    long endTime;
1842
    TTimePartitionSlot timePartitionSlot;
1843
    int index = 0;
1✔
1844
    int size = timeRangeList.size();
1✔
1845

1846
    if (timeRangeList.get(0).getMin() == Long.MIN_VALUE) {
1✔
1847
      needLeftAll = true;
1✔
1848
      endTime = TimePartitionUtils.getTimePartitionUpperBound(timeRangeList.get(0).getMax());
1✔
1849
      timePartitionSlot = TimePartitionUtils.getTimePartitionSlot(timeRangeList.get(0).getMax());
1✔
1850
    } else {
1851
      endTime = TimePartitionUtils.getTimePartitionUpperBound(timeRangeList.get(0).getMin());
1✔
1852
      timePartitionSlot = TimePartitionUtils.getTimePartitionSlot(timeRangeList.get(0).getMin());
1✔
1853
      needLeftAll = false;
1✔
1854
    }
1855

1856
    if (timeRangeList.get(size - 1).getMax() == Long.MAX_VALUE) {
1✔
1857
      needRightAll = true;
1✔
1858
      size--;
1✔
1859
    } else {
1860
      needRightAll = false;
1✔
1861
    }
1862

1863
    List<TTimePartitionSlot> result = new ArrayList<>();
1✔
1864
    while (index < size) {
1✔
1865
      long curLeft = timeRangeList.get(index).getMin();
1✔
1866
      long curRight = timeRangeList.get(index).getMax();
1✔
1867
      if (curLeft >= endTime) {
1✔
1868
        result.add(timePartitionSlot);
1✔
1869
        // next init
1870
        endTime = TimePartitionUtils.getTimePartitionUpperBound(curLeft);
1✔
1871
        timePartitionSlot = TimePartitionUtils.getTimePartitionSlot(curLeft);
1✔
1872
      } else if (curRight >= endTime) {
1✔
1873
        result.add(timePartitionSlot);
1✔
1874
        // next init
1875
        timePartitionSlot = new TTimePartitionSlot(endTime);
1✔
1876
        endTime = endTime + TimePartitionUtils.getTimePartitionInterval();
1✔
1877
      } else {
1878
        index++;
1✔
1879
      }
1880
    }
1✔
1881
    result.add(timePartitionSlot);
1✔
1882

1883
    if (needRightAll) {
1✔
1884
      TTimePartitionSlot lastTimePartitionSlot =
1✔
1885
          TimePartitionUtils.getTimePartitionSlot(
1✔
1886
              timeRangeList.get(timeRangeList.size() - 1).getMin());
1✔
1887
      if (lastTimePartitionSlot.startTime != timePartitionSlot.startTime) {
1✔
1888
        result.add(lastTimePartitionSlot);
×
1889
      }
1890
    }
1891
    return new Pair<>(result, new Pair<>(needLeftAll, needRightAll));
1✔
1892
  }
1893

1894
  private void analyzeInto(
1895
      Analysis analysis,
1896
      QueryStatement queryStatement,
1897
      List<PartialPath> deviceSet,
1898
      List<Pair<Expression, String>> outputExpressions) {
1899
    if (!queryStatement.isSelectInto()) {
1✔
1900
      return;
1✔
1901
    }
1902
    queryStatement.setOrderByComponent(null);
1✔
1903

1904
    List<PartialPath> sourceDevices = new ArrayList<>(deviceSet);
1✔
1905
    List<Expression> sourceColumns =
1✔
1906
        outputExpressions.stream()
1✔
1907
            .map(Pair::getLeft)
1✔
1908
            .collect(Collectors.toCollection(ArrayList::new));
1✔
1909

1910
    IntoComponent intoComponent = queryStatement.getIntoComponent();
1✔
1911
    intoComponent.validate(sourceDevices, sourceColumns);
1✔
1912

1913
    DeviceViewIntoPathDescriptor deviceViewIntoPathDescriptor = new DeviceViewIntoPathDescriptor();
1✔
1914
    PathPatternTree targetPathTree = new PathPatternTree();
1✔
1915
    IntoComponent.IntoDeviceMeasurementIterator intoDeviceMeasurementIterator =
1✔
1916
        intoComponent.getIntoDeviceMeasurementIterator();
1✔
1917
    for (PartialPath sourceDevice : sourceDevices) {
1✔
1918
      PartialPath deviceTemplate = intoDeviceMeasurementIterator.getDeviceTemplate();
1✔
1919
      boolean isAlignedDevice = intoDeviceMeasurementIterator.isAlignedDevice();
1✔
1920
      PartialPath targetDevice = constructTargetDevice(sourceDevice, deviceTemplate);
1✔
1921
      deviceViewIntoPathDescriptor.specifyDeviceAlignment(targetDevice.toString(), isAlignedDevice);
1✔
1922

1923
      for (Expression sourceColumn : sourceColumns) {
1✔
1924
        String measurementTemplate = intoDeviceMeasurementIterator.getMeasurementTemplate();
1✔
1925
        String targetMeasurement;
1926
        if (sourceColumn instanceof TimeSeriesOperand) {
1✔
1927
          targetMeasurement =
1✔
1928
              constructTargetMeasurement(
1✔
1929
                  sourceDevice.concatNode(sourceColumn.getExpressionString()), measurementTemplate);
1✔
1930
        } else {
1931
          targetMeasurement = measurementTemplate;
1✔
1932
        }
1933
        deviceViewIntoPathDescriptor.specifyTargetDeviceMeasurement(
1✔
1934
            sourceDevice, targetDevice, sourceColumn.getExpressionString(), targetMeasurement);
1✔
1935

1936
        targetPathTree.appendFullPath(targetDevice, targetMeasurement);
1✔
1937
        deviceViewIntoPathDescriptor.recordSourceColumnDataType(
1✔
1938
            sourceColumn.getExpressionString(), analysis.getType(sourceColumn));
1✔
1939

1940
        intoDeviceMeasurementIterator.nextMeasurement();
1✔
1941
      }
1✔
1942

1943
      intoDeviceMeasurementIterator.nextDevice();
1✔
1944
    }
1✔
1945
    deviceViewIntoPathDescriptor.validate();
1✔
1946

1947
    // fetch schema of target paths
1948
    long startTime = System.nanoTime();
1✔
1949
    ISchemaTree targetSchemaTree = schemaFetcher.fetchSchema(targetPathTree, null);
1✔
1950
    QueryPlanCostMetricSet.getInstance()
1✔
1951
        .recordPlanCost(SCHEMA_FETCHER, System.nanoTime() - startTime);
1✔
1952
    deviceViewIntoPathDescriptor.bindType(targetSchemaTree);
1✔
1953

1954
    analysis.setDeviceViewIntoPathDescriptor(deviceViewIntoPathDescriptor);
1✔
1955
  }
1✔
1956

1957
  private void analyzeInto(
1958
      Analysis analysis,
1959
      QueryStatement queryStatement,
1960
      List<Pair<Expression, String>> outputExpressions) {
1961
    if (!queryStatement.isSelectInto()) {
1✔
1962
      return;
1✔
1963
    }
1964
    queryStatement.setOrderByComponent(null);
1✔
1965

1966
    List<Expression> sourceColumns =
1✔
1967
        outputExpressions.stream()
1✔
1968
            .map(Pair::getLeft)
1✔
1969
            .collect(Collectors.toCollection(ArrayList::new));
1✔
1970

1971
    IntoComponent intoComponent = queryStatement.getIntoComponent();
1✔
1972
    intoComponent.validate(sourceColumns);
1✔
1973

1974
    IntoPathDescriptor intoPathDescriptor = new IntoPathDescriptor();
1✔
1975
    PathPatternTree targetPathTree = new PathPatternTree();
1✔
1976
    IntoComponent.IntoPathIterator intoPathIterator = intoComponent.getIntoPathIterator();
1✔
1977
    for (Pair<Expression, String> pair : outputExpressions) {
1✔
1978
      Expression sourceExpression = pair.left;
1✔
1979
      String viewPath = pair.right;
1✔
1980
      PartialPath deviceTemplate = intoPathIterator.getDeviceTemplate();
1✔
1981
      String measurementTemplate = intoPathIterator.getMeasurementTemplate();
1✔
1982
      boolean isAlignedDevice = intoPathIterator.isAlignedDevice();
1✔
1983

1984
      PartialPath sourcePath;
1985
      String sourceColumn = sourceExpression.getExpressionString();
1✔
1986
      PartialPath targetPath;
1987
      if (sourceExpression instanceof TimeSeriesOperand) {
1✔
1988
        if (viewPath != null) {
1✔
1989
          try {
1990
            sourcePath = new PartialPath(viewPath);
×
1991
          } catch (IllegalPathException e) {
×
1992
            throw new SemanticException(
×
1993
                String.format(
×
1994
                    "View path %s of source column %s is illegal path", viewPath, sourceColumn));
1995
          }
×
1996
        } else {
1997
          sourcePath = ((TimeSeriesOperand) sourceExpression).getPath();
1✔
1998
        }
1999
        targetPath = constructTargetPath(sourcePath, deviceTemplate, measurementTemplate);
1✔
2000
      } else {
2001
        targetPath = deviceTemplate.concatNode(measurementTemplate);
1✔
2002
      }
2003
      intoPathDescriptor.specifyTargetPath(sourceColumn, viewPath, targetPath);
1✔
2004
      intoPathDescriptor.specifyDeviceAlignment(
1✔
2005
          targetPath.getDevicePath().toString(), isAlignedDevice);
1✔
2006

2007
      targetPathTree.appendFullPath(targetPath);
1✔
2008
      intoPathDescriptor.recordSourceColumnDataType(
1✔
2009
          sourceColumn, analysis.getType(sourceExpression));
1✔
2010

2011
      intoPathIterator.next();
1✔
2012
    }
1✔
2013
    intoPathDescriptor.validate();
1✔
2014

2015
    // fetch schema of target paths
2016
    long startTime = System.nanoTime();
1✔
2017
    ISchemaTree targetSchemaTree = schemaFetcher.fetchSchema(targetPathTree, null);
1✔
2018
    updateSchemaTreeByViews(analysis, targetSchemaTree);
1✔
2019
    QueryPlanCostMetricSet.getInstance()
1✔
2020
        .recordPlanCost(SCHEMA_FETCHER, System.nanoTime() - startTime);
1✔
2021
    intoPathDescriptor.bindType(targetSchemaTree);
1✔
2022

2023
    analysis.setIntoPathDescriptor(intoPathDescriptor);
1✔
2024
  }
1✔
2025

2026
  /**
2027
   * Check datatype consistency in ALIGN BY DEVICE.
2028
   *
2029
   * <p>an inconsistent example: select s0 from root.sg1.d1, root.sg1.d2 align by device, return
2030
   * false while root.sg1.d1.s0 is INT32 and root.sg1.d2.s0 is FLOAT.
2031
   */
2032
  private void checkDataTypeConsistencyInAlignByDevice(
2033
      Analysis analysis, List<Expression> expressions) {
2034
    TSDataType checkedDataType = analysis.getType(expressions.get(0));
1✔
2035
    for (Expression expression : expressions) {
1✔
2036
      if (analysis.getType(expression) != checkedDataType) {
1✔
2037
        throw new SemanticException(
×
2038
            "ALIGN BY DEVICE: the data types of the same measurement column should be the same across devices.");
2039
      }
2040
    }
1✔
2041
  }
1✔
2042

2043
  private void checkAliasUniqueness(String alias, Set<String> aliasSet) {
2044
    if (alias != null) {
1✔
2045
      if (aliasSet.contains(alias)) {
1✔
2046
        throw new SemanticException(
1✔
2047
            String.format("alias '%s' can only be matched with one time series", alias));
1✔
2048
      }
2049
      aliasSet.add(alias);
1✔
2050
    }
2051
  }
1✔
2052

2053
  private void checkAliasUniqueness(
2054
      String alias, Map<Expression, Map<String, Expression>> measurementToDeviceSelectExpressions) {
2055
    if (alias != null && measurementToDeviceSelectExpressions.keySet().size() > 1) {
1✔
2056
      throw new SemanticException(
×
2057
          String.format("alias '%s' can only be matched with one time series", alias));
×
2058
    }
2059
  }
1✔
2060

2061
  @Override
2062
  public Analysis visitInsert(InsertStatement insertStatement, MPPQueryContext context) {
2063
    context.setQueryType(QueryType.WRITE);
1✔
2064
    insertStatement.semanticCheck();
1✔
2065
    long[] timeArray = insertStatement.getTimes();
1✔
2066
    PartialPath devicePath = insertStatement.getDevice();
1✔
2067
    String[] measurementList = insertStatement.getMeasurementList();
1✔
2068
    if (timeArray.length == 1) {
1✔
2069
      // construct insert row statement
2070
      InsertRowStatement insertRowStatement = new InsertRowStatement();
×
2071
      insertRowStatement.setDevicePath(devicePath);
×
2072
      insertRowStatement.setTime(timeArray[0]);
×
2073
      insertRowStatement.setMeasurements(measurementList);
×
2074
      insertRowStatement.setDataTypes(new TSDataType[measurementList.length]);
×
2075
      Object[] values = new Object[measurementList.length];
×
2076
      System.arraycopy(insertStatement.getValuesList().get(0), 0, values, 0, values.length);
×
2077
      insertRowStatement.setValues(values);
×
2078
      insertRowStatement.setNeedInferType(true);
×
2079
      insertRowStatement.setAligned(insertStatement.isAligned());
×
2080
      return insertRowStatement.accept(this, context);
×
2081
    } else {
2082
      // construct insert rows statement
2083
      // construct insert statement
2084
      InsertRowsOfOneDeviceStatement insertRowsOfOneDeviceStatement =
1✔
2085
          new InsertRowsOfOneDeviceStatement();
2086
      List<InsertRowStatement> insertRowStatementList = new ArrayList<>();
1✔
2087
      for (int i = 0; i < timeArray.length; i++) {
1✔
2088
        InsertRowStatement statement = new InsertRowStatement();
1✔
2089
        statement.setDevicePath(devicePath);
1✔
2090
        String[] measurements = new String[measurementList.length];
1✔
2091
        System.arraycopy(measurementList, 0, measurements, 0, measurements.length);
1✔
2092
        statement.setMeasurements(measurements);
1✔
2093
        statement.setTime(timeArray[i]);
1✔
2094
        TSDataType[] dataTypes = new TSDataType[measurementList.length];
1✔
2095
        statement.setDataTypes(dataTypes);
1✔
2096
        Object[] values = new Object[measurementList.length];
1✔
2097
        System.arraycopy(insertStatement.getValuesList().get(i), 0, values, 0, values.length);
1✔
2098
        statement.setValues(values);
1✔
2099
        statement.setAligned(insertStatement.isAligned());
1✔
2100
        statement.setNeedInferType(true);
1✔
2101
        insertRowStatementList.add(statement);
1✔
2102
      }
2103
      insertRowsOfOneDeviceStatement.setInsertRowStatementList(insertRowStatementList);
1✔
2104
      return insertRowsOfOneDeviceStatement.accept(this, context);
1✔
2105
    }
2106
  }
2107

2108
  @Override
2109
  public Analysis visitCreateTimeseries(
2110
      CreateTimeSeriesStatement createTimeSeriesStatement, MPPQueryContext context) {
2111
    context.setQueryType(QueryType.WRITE);
1✔
2112
    if (createTimeSeriesStatement.getPath().getNodeLength() < 3) {
1✔
2113
      throw new SemanticException(
×
2114
          new IllegalPathException(createTimeSeriesStatement.getPath().getFullPath()));
×
2115
    }
2116
    analyzeSchemaProps(createTimeSeriesStatement.getProps());
1✔
2117
    if (createTimeSeriesStatement.getTags() != null
1✔
2118
        && !createTimeSeriesStatement.getTags().isEmpty()
1✔
2119
        && createTimeSeriesStatement.getAttributes() != null
1✔
2120
        && !createTimeSeriesStatement.getAttributes().isEmpty()) {
1✔
2121
      for (String tagKey : createTimeSeriesStatement.getTags().keySet()) {
1✔
2122
        if (createTimeSeriesStatement.getAttributes().containsKey(tagKey)) {
1✔
2123
          throw new SemanticException(
1✔
2124
              String.format("Tag and attribute shouldn't have the same property key [%s]", tagKey));
1✔
2125
        }
2126
      }
×
2127
    }
2128

2129
    Analysis analysis = new Analysis();
×
2130
    analysis.setStatement(createTimeSeriesStatement);
×
2131

2132
    checkIsTemplateCompatible(
×
2133
        createTimeSeriesStatement.getPath(), createTimeSeriesStatement.getAlias());
×
2134

2135
    PathPatternTree patternTree = new PathPatternTree();
×
2136
    patternTree.appendFullPath(createTimeSeriesStatement.getPath());
×
2137
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2138
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2139
    return analysis;
×
2140
  }
2141

2142
  private void checkIsTemplateCompatible(PartialPath timeseriesPath, String alias) {
2143
    Pair<Template, PartialPath> templateInfo =
×
2144
        schemaFetcher.checkTemplateSetAndPreSetInfo(timeseriesPath, alias);
×
2145
    if (templateInfo != null) {
×
2146
      throw new SemanticException(
×
2147
          new TemplateIncompatibleException(
2148
              timeseriesPath.getFullPath(), templateInfo.left.getName(), templateInfo.right));
×
2149
    }
2150
  }
×
2151

2152
  private void checkIsTemplateCompatible(
2153
      PartialPath devicePath, List<String> measurements, List<String> aliasList) {
2154
    for (int i = 0; i < measurements.size(); i++) {
×
2155
      Pair<Template, PartialPath> templateInfo =
×
2156
          schemaFetcher.checkTemplateSetAndPreSetInfo(
×
2157
              devicePath.concatNode(measurements.get(i)),
×
2158
              aliasList == null ? null : aliasList.get(i));
×
2159
      if (templateInfo != null) {
×
2160
        throw new SemanticException(
×
2161
            new TemplateIncompatibleException(
2162
                devicePath.getFullPath() + measurements,
×
2163
                templateInfo.left.getName(),
×
2164
                templateInfo.right));
2165
      }
2166
    }
2167
  }
×
2168

2169
  private void analyzeSchemaProps(Map<String, String> props) {
2170
    if (props == null || props.isEmpty()) {
1✔
2171
      return;
1✔
2172
    }
2173
    Map<String, String> caseChangeMap = new HashMap<>();
×
2174
    for (String key : props.keySet()) {
×
2175
      caseChangeMap.put(key.toLowerCase(Locale.ROOT), key);
×
2176
    }
×
2177
    for (Map.Entry<String, String> caseChangeEntry : caseChangeMap.entrySet()) {
×
2178
      String lowerCaseKey = caseChangeEntry.getKey();
×
2179
      if (!ALLOWED_SCHEMA_PROPS.contains(lowerCaseKey)) {
×
2180
        throw new SemanticException(
×
2181
            new MetadataException(
2182
                String.format("%s is not a legal prop.", caseChangeEntry.getValue())));
×
2183
      }
2184
      props.put(lowerCaseKey, props.remove(caseChangeEntry.getValue()));
×
2185
    }
×
2186
    if (props.containsKey(DEADBAND)) {
×
2187
      props.put(LOSS, props.remove(DEADBAND));
×
2188
    }
2189
  }
×
2190

2191
  private void analyzeSchemaProps(List<Map<String, String>> propsList) {
2192
    if (propsList == null) {
×
2193
      return;
×
2194
    }
2195
    for (Map<String, String> props : propsList) {
×
2196
      analyzeSchemaProps(props);
×
2197
    }
×
2198
  }
×
2199

2200
  @Override
2201
  public Analysis visitCreateAlignedTimeseries(
2202
      CreateAlignedTimeSeriesStatement createAlignedTimeSeriesStatement, MPPQueryContext context) {
2203
    context.setQueryType(QueryType.WRITE);
1✔
2204
    if (createAlignedTimeSeriesStatement.getDevicePath().getNodeLength() < 2) {
1✔
2205
      throw new SemanticException(
×
2206
          new IllegalPathException(createAlignedTimeSeriesStatement.getDevicePath().getFullPath()));
×
2207
    }
2208
    List<String> measurements = createAlignedTimeSeriesStatement.getMeasurements();
1✔
2209
    Set<String> measurementsSet = new HashSet<>(measurements);
1✔
2210
    if (measurementsSet.size() < measurements.size()) {
1✔
2211
      throw new SemanticException(
1✔
2212
          "Measurement under an aligned device is not allowed to have the same measurement name");
2213
    }
2214

2215
    Analysis analysis = new Analysis();
×
2216
    analysis.setStatement(createAlignedTimeSeriesStatement);
×
2217

2218
    checkIsTemplateCompatible(
×
2219
        createAlignedTimeSeriesStatement.getDevicePath(),
×
2220
        createAlignedTimeSeriesStatement.getMeasurements(),
×
2221
        createAlignedTimeSeriesStatement.getAliasList());
×
2222

2223
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2224
    for (String measurement : createAlignedTimeSeriesStatement.getMeasurements()) {
×
2225
      pathPatternTree.appendFullPath(createAlignedTimeSeriesStatement.getDevicePath(), measurement);
×
2226
    }
×
2227

2228
    SchemaPartition schemaPartitionInfo;
2229
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2230
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2231
    return analysis;
×
2232
  }
2233

2234
  @Override
2235
  public Analysis visitInternalCreateTimeseries(
2236
      InternalCreateTimeSeriesStatement internalCreateTimeSeriesStatement,
2237
      MPPQueryContext context) {
2238
    context.setQueryType(QueryType.WRITE);
×
2239

2240
    Analysis analysis = new Analysis();
×
2241
    analysis.setStatement(internalCreateTimeSeriesStatement);
×
2242

2243
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2244
    for (String measurement : internalCreateTimeSeriesStatement.getMeasurements()) {
×
2245
      pathPatternTree.appendFullPath(
×
2246
          internalCreateTimeSeriesStatement.getDevicePath(), measurement);
×
2247
    }
×
2248

2249
    SchemaPartition schemaPartitionInfo;
2250
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2251
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2252
    return analysis;
×
2253
  }
2254

2255
  @Override
2256
  public Analysis visitInternalCreateMultiTimeSeries(
2257
      InternalCreateMultiTimeSeriesStatement internalCreateMultiTimeSeriesStatement,
2258
      MPPQueryContext context) {
2259
    context.setQueryType(QueryType.WRITE);
×
2260

2261
    Analysis analysis = new Analysis();
×
2262
    analysis.setStatement(internalCreateMultiTimeSeriesStatement);
×
2263

2264
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2265
    for (PartialPath devicePath : internalCreateMultiTimeSeriesStatement.getDeviceMap().keySet()) {
×
2266
      pathPatternTree.appendFullPath(devicePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
2267
    }
×
2268

2269
    SchemaPartition schemaPartitionInfo;
2270
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2271
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2272
    return analysis;
×
2273
  }
2274

2275
  @Override
2276
  public Analysis visitCreateMultiTimeseries(
2277
      CreateMultiTimeSeriesStatement createMultiTimeSeriesStatement, MPPQueryContext context) {
2278
    context.setQueryType(QueryType.WRITE);
×
2279
    Analysis analysis = new Analysis();
×
2280
    analysis.setStatement(createMultiTimeSeriesStatement);
×
2281

2282
    analyzeSchemaProps(createMultiTimeSeriesStatement.getPropsList());
×
2283

2284
    List<PartialPath> timeseriesPathList = createMultiTimeSeriesStatement.getPaths();
×
2285
    List<String> aliasList = createMultiTimeSeriesStatement.getAliasList();
×
2286
    for (int i = 0; i < timeseriesPathList.size(); i++) {
×
2287
      checkIsTemplateCompatible(
×
2288
          timeseriesPathList.get(i), aliasList == null ? null : aliasList.get(i));
×
2289
    }
2290

2291
    PathPatternTree patternTree = new PathPatternTree();
×
2292
    for (PartialPath path : createMultiTimeSeriesStatement.getPaths()) {
×
2293
      patternTree.appendFullPath(path);
×
2294
    }
×
2295
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2296
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2297
    return analysis;
×
2298
  }
2299

2300
  @Override
2301
  public Analysis visitAlterTimeseries(
2302
      AlterTimeSeriesStatement alterTimeSeriesStatement, MPPQueryContext context) {
2303
    context.setQueryType(QueryType.WRITE);
×
2304
    Analysis analysis = new Analysis();
×
2305
    analysis.setStatement(alterTimeSeriesStatement);
×
2306

2307
    Pair<Template, PartialPath> templateInfo =
×
2308
        schemaFetcher.checkTemplateSetAndPreSetInfo(
×
2309
            alterTimeSeriesStatement.getPath(), alterTimeSeriesStatement.getAlias());
×
2310
    if (templateInfo != null) {
×
2311
      throw new RuntimeException(
×
2312
          new TemplateIncompatibleException(
2313
              String.format(
×
2314
                  "Cannot alter template timeseries [%s] since schema template [%s] already set on path [%s].",
2315
                  alterTimeSeriesStatement.getPath().getFullPath(),
×
2316
                  templateInfo.left.getName(),
×
2317
                  templateInfo.right)));
2318
    }
2319

2320
    PathPatternTree patternTree = new PathPatternTree();
×
2321
    patternTree.appendFullPath(alterTimeSeriesStatement.getPath());
×
2322
    SchemaPartition schemaPartitionInfo;
2323
    schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2324
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2325
    return analysis;
×
2326
  }
2327

2328
  @Override
2329
  public Analysis visitInsertTablet(
2330
      InsertTabletStatement insertTabletStatement, MPPQueryContext context) {
2331
    context.setQueryType(QueryType.WRITE);
×
2332
    Analysis analysis = new Analysis();
×
2333
    validateSchema(analysis, insertTabletStatement, context);
×
2334
    InsertBaseStatement realStatement = removeLogicalView(analysis, insertTabletStatement);
×
2335
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2336
      return analysis;
×
2337
    }
2338
    analysis.setStatement(realStatement);
×
2339

2340
    if (realStatement instanceof InsertTabletStatement) {
×
2341
      InsertTabletStatement realInsertTabletStatement = (InsertTabletStatement) realStatement;
×
2342
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2343
      dataPartitionQueryParam.setDevicePath(
×
2344
          realInsertTabletStatement.getDevicePath().getFullPath());
×
2345
      dataPartitionQueryParam.setTimePartitionSlotList(
×
2346
          realInsertTabletStatement.getTimePartitionSlots());
×
2347

2348
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
×
2349
    } else {
2350
      return computeAnalysisForMultiTablets(analysis, (InsertMultiTabletsStatement) realStatement);
×
2351
    }
2352
  }
2353

2354
  @Override
2355
  public Analysis visitInsertRow(InsertRowStatement insertRowStatement, MPPQueryContext context) {
2356
    context.setQueryType(QueryType.WRITE);
×
2357
    Analysis analysis = new Analysis();
×
2358
    validateSchema(analysis, insertRowStatement, context);
×
2359
    InsertBaseStatement realInsertStatement = removeLogicalView(analysis, insertRowStatement);
×
2360
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2361
      return analysis;
×
2362
    }
2363
    analysis.setStatement(realInsertStatement);
×
2364

2365
    if (realInsertStatement instanceof InsertRowStatement) {
×
2366
      InsertRowStatement realInsertRowStatement = (InsertRowStatement) realInsertStatement;
×
2367
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2368
      dataPartitionQueryParam.setDevicePath(realInsertRowStatement.getDevicePath().getFullPath());
×
2369
      dataPartitionQueryParam.setTimePartitionSlotList(
×
2370
          Collections.singletonList(realInsertRowStatement.getTimePartitionSlot()));
×
2371

2372
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
×
2373
    } else {
2374
      return computeAnalysisForInsertRows(analysis, (InsertRowsStatement) realInsertStatement);
×
2375
    }
2376
  }
2377

2378
  private Analysis computeAnalysisForInsertRows(
2379
      Analysis analysis, InsertRowsStatement insertRowsStatement) {
2380
    Map<String, Set<TTimePartitionSlot>> dataPartitionQueryParamMap = new HashMap<>();
×
2381
    for (InsertRowStatement insertRowStatement : insertRowsStatement.getInsertRowStatementList()) {
×
2382
      Set<TTimePartitionSlot> timePartitionSlotSet =
×
2383
          dataPartitionQueryParamMap.computeIfAbsent(
×
2384
              insertRowStatement.getDevicePath().getFullPath(), k -> new HashSet<>());
×
2385
      timePartitionSlotSet.add(insertRowStatement.getTimePartitionSlot());
×
2386
    }
×
2387

2388
    List<DataPartitionQueryParam> dataPartitionQueryParams = new ArrayList<>();
×
2389
    for (Map.Entry<String, Set<TTimePartitionSlot>> entry : dataPartitionQueryParamMap.entrySet()) {
×
2390
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2391
      dataPartitionQueryParam.setDevicePath(entry.getKey());
×
2392
      dataPartitionQueryParam.setTimePartitionSlotList(new ArrayList<>(entry.getValue()));
×
2393
      dataPartitionQueryParams.add(dataPartitionQueryParam);
×
2394
    }
×
2395

2396
    return getAnalysisForWriting(analysis, dataPartitionQueryParams);
×
2397
  }
2398

2399
  @Override
2400
  public Analysis visitInsertRows(
2401
      InsertRowsStatement insertRowsStatement, MPPQueryContext context) {
2402
    context.setQueryType(QueryType.WRITE);
×
2403
    Analysis analysis = new Analysis();
×
2404
    validateSchema(analysis, insertRowsStatement, context);
×
2405
    InsertRowsStatement realInsertRowsStatement =
×
2406
        (InsertRowsStatement) removeLogicalView(analysis, insertRowsStatement);
×
2407
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2408
      return analysis;
×
2409
    }
2410
    analysis.setStatement(realInsertRowsStatement);
×
2411

2412
    return computeAnalysisForInsertRows(analysis, realInsertRowsStatement);
×
2413
  }
2414

2415
  private Analysis computeAnalysisForMultiTablets(
2416
      Analysis analysis, InsertMultiTabletsStatement insertMultiTabletsStatement) {
2417
    Map<String, Set<TTimePartitionSlot>> dataPartitionQueryParamMap = new HashMap<>();
×
2418
    for (InsertTabletStatement insertTabletStatement :
2419
        insertMultiTabletsStatement.getInsertTabletStatementList()) {
×
2420
      Set<TTimePartitionSlot> timePartitionSlotSet =
×
2421
          dataPartitionQueryParamMap.computeIfAbsent(
×
2422
              insertTabletStatement.getDevicePath().getFullPath(), k -> new HashSet<>());
×
2423
      timePartitionSlotSet.addAll(insertTabletStatement.getTimePartitionSlots());
×
2424
    }
×
2425

2426
    List<DataPartitionQueryParam> dataPartitionQueryParams = new ArrayList<>();
×
2427
    for (Map.Entry<String, Set<TTimePartitionSlot>> entry : dataPartitionQueryParamMap.entrySet()) {
×
2428
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2429
      dataPartitionQueryParam.setDevicePath(entry.getKey());
×
2430
      dataPartitionQueryParam.setTimePartitionSlotList(new ArrayList<>(entry.getValue()));
×
2431
      dataPartitionQueryParams.add(dataPartitionQueryParam);
×
2432
    }
×
2433

2434
    return getAnalysisForWriting(analysis, dataPartitionQueryParams);
×
2435
  }
2436

2437
  @Override
2438
  public Analysis visitInsertMultiTablets(
2439
      InsertMultiTabletsStatement insertMultiTabletsStatement, MPPQueryContext context) {
2440
    context.setQueryType(QueryType.WRITE);
×
2441
    Analysis analysis = new Analysis();
×
2442
    validateSchema(analysis, insertMultiTabletsStatement, context);
×
2443
    InsertMultiTabletsStatement realStatement =
×
2444
        (InsertMultiTabletsStatement) removeLogicalView(analysis, insertMultiTabletsStatement);
×
2445
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2446
      return analysis;
×
2447
    }
2448
    analysis.setStatement(realStatement);
×
2449

2450
    return computeAnalysisForMultiTablets(analysis, realStatement);
×
2451
  }
2452

2453
  @Override
2454
  public Analysis visitInsertRowsOfOneDevice(
2455
      InsertRowsOfOneDeviceStatement insertRowsOfOneDeviceStatement, MPPQueryContext context) {
2456
    context.setQueryType(QueryType.WRITE);
1✔
2457
    Analysis analysis = new Analysis();
1✔
2458
    validateSchema(analysis, insertRowsOfOneDeviceStatement, context);
1✔
2459
    InsertBaseStatement realInsertStatement =
1✔
2460
        removeLogicalView(analysis, insertRowsOfOneDeviceStatement);
1✔
2461
    if (analysis.isFinishQueryAfterAnalyze()) {
1✔
2462
      return analysis;
×
2463
    }
2464
    analysis.setStatement(realInsertStatement);
1✔
2465

2466
    if (realInsertStatement instanceof InsertRowsOfOneDeviceStatement) {
1✔
2467
      InsertRowsOfOneDeviceStatement realStatement =
1✔
2468
          (InsertRowsOfOneDeviceStatement) realInsertStatement;
2469
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
1✔
2470
      dataPartitionQueryParam.setDevicePath(realStatement.getDevicePath().getFullPath());
1✔
2471
      dataPartitionQueryParam.setTimePartitionSlotList(realStatement.getTimePartitionSlots());
1✔
2472

2473
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
1✔
2474
    } else {
2475
      return computeAnalysisForInsertRows(analysis, (InsertRowsStatement) realInsertStatement);
×
2476
    }
2477
  }
2478

2479
  @Override
2480
  public Analysis visitPipeEnrichedInsert(
2481
      PipeEnrichedInsertBaseStatement pipeEnrichedInsertBaseStatement, MPPQueryContext context) {
2482
    Analysis analysis;
2483

2484
    final InsertBaseStatement insertBaseStatement =
×
2485
        pipeEnrichedInsertBaseStatement.getInsertBaseStatement();
×
2486
    if (insertBaseStatement instanceof InsertTabletStatement) {
×
2487
      analysis = visitInsertTablet((InsertTabletStatement) insertBaseStatement, context);
×
2488
    } else if (insertBaseStatement instanceof InsertMultiTabletsStatement) {
×
2489
      analysis =
×
2490
          visitInsertMultiTablets((InsertMultiTabletsStatement) insertBaseStatement, context);
×
2491
    } else if (insertBaseStatement instanceof InsertRowStatement) {
×
2492
      analysis = visitInsertRow((InsertRowStatement) insertBaseStatement, context);
×
2493
    } else if (insertBaseStatement instanceof InsertRowsStatement) {
×
2494
      analysis = visitInsertRows((InsertRowsStatement) insertBaseStatement, context);
×
2495
    } else if (insertBaseStatement instanceof InsertRowsOfOneDeviceStatement) {
×
2496
      analysis =
×
2497
          visitInsertRowsOfOneDevice((InsertRowsOfOneDeviceStatement) insertBaseStatement, context);
×
2498
    } else {
2499
      throw new UnsupportedOperationException(
×
2500
          "Unsupported insert statement type: " + insertBaseStatement.getClass().getName());
×
2501
    }
2502

2503
    // statement may be changed because of logical view
2504
    pipeEnrichedInsertBaseStatement.setInsertBaseStatement(
×
2505
        (InsertBaseStatement) analysis.getStatement());
×
2506
    analysis.setStatement(pipeEnrichedInsertBaseStatement);
×
2507
    return analysis;
×
2508
  }
2509

2510
  private void validateSchema(
2511
      Analysis analysis, InsertBaseStatement insertStatement, MPPQueryContext context) {
2512
    final long startTime = System.nanoTime();
1✔
2513
    try {
2514
      SchemaValidator.validate(schemaFetcher, insertStatement, context);
1✔
2515
    } catch (SemanticException e) {
×
2516
      analysis.setFinishQueryAfterAnalyze(true);
×
2517
      if (e.getCause() instanceof IoTDBException) {
×
2518
        IoTDBException exception = (IoTDBException) e.getCause();
×
2519
        analysis.setFailStatus(
×
2520
            RpcUtils.getStatus(exception.getErrorCode(), exception.getMessage()));
×
2521
      } else {
×
2522
        analysis.setFailStatus(RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage()));
×
2523
      }
2524
    } finally {
2525
      PERFORMANCE_OVERVIEW_METRICS.recordScheduleSchemaValidateCost(System.nanoTime() - startTime);
1✔
2526
    }
2527
    boolean hasFailedMeasurement = insertStatement.hasFailedMeasurements();
1✔
2528
    String partialInsertMessage;
2529
    if (hasFailedMeasurement) {
1✔
2530
      partialInsertMessage =
×
2531
          String.format(
×
2532
              "Fail to insert measurements %s caused by %s",
2533
              insertStatement.getFailedMeasurements(), insertStatement.getFailedMessages());
×
2534
      logger.warn(partialInsertMessage);
×
2535
      analysis.setFailStatus(
×
2536
          RpcUtils.getStatus(TSStatusCode.METADATA_ERROR.getStatusCode(), partialInsertMessage));
×
2537
    }
2538
  }
1✔
2539

2540
  private InsertBaseStatement removeLogicalView(
2541
      Analysis analysis, InsertBaseStatement insertBaseStatement) {
2542
    try {
2543
      return insertBaseStatement.removeLogicalView();
1✔
2544
    } catch (SemanticException e) {
×
2545
      analysis.setFinishQueryAfterAnalyze(true);
×
2546
      if (e.getCause() instanceof IoTDBException) {
×
2547
        IoTDBException exception = (IoTDBException) e.getCause();
×
2548
        analysis.setFailStatus(
×
2549
            RpcUtils.getStatus(exception.getErrorCode(), exception.getMessage()));
×
2550
      } else {
×
2551
        analysis.setFailStatus(RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage()));
×
2552
      }
2553
      return insertBaseStatement;
×
2554
    }
2555
  }
2556

2557
  @Override
2558
  public Analysis visitLoadFile(LoadTsFileStatement loadTsFileStatement, MPPQueryContext context) {
2559
    return new LoadTsfileAnalyzer(loadTsFileStatement, context, partitionFetcher, schemaFetcher)
×
2560
        .analyzeFileByFile();
×
2561
  }
2562

2563
  @Override
2564
  public Analysis visitPipeEnrichedLoadFile(
2565
      PipeEnrichedLoadTsFileStatement pipeEnrichedLoadTsFileStatement, MPPQueryContext context) {
2566
    final Analysis analysis =
×
2567
        visitLoadFile(pipeEnrichedLoadTsFileStatement.getLoadTsFileStatement(), context);
×
2568
    analysis.setStatement(pipeEnrichedLoadTsFileStatement);
×
2569
    return analysis;
×
2570
  }
2571

2572
  /** get analysis according to statement and params */
2573
  private Analysis getAnalysisForWriting(
2574
      Analysis analysis, List<DataPartitionQueryParam> dataPartitionQueryParams) {
2575

2576
    DataPartition dataPartition =
1✔
2577
        partitionFetcher.getOrCreateDataPartition(dataPartitionQueryParams);
1✔
2578
    if (dataPartition.isEmpty()) {
1✔
2579
      analysis.setFinishQueryAfterAnalyze(true);
×
2580
      analysis.setFailStatus(
×
2581
          RpcUtils.getStatus(
×
2582
              TSStatusCode.DATABASE_NOT_EXIST.getStatusCode(),
×
2583
              "Database not exists and failed to create automatically "
2584
                  + "because enable_auto_create_schema is FALSE."));
2585
    }
2586
    analysis.setDataPartitionInfo(dataPartition);
1✔
2587
    return analysis;
1✔
2588
  }
2589

2590
  @Override
2591
  public Analysis visitShowTimeSeries(
2592
      ShowTimeSeriesStatement showTimeSeriesStatement, MPPQueryContext context) {
2593
    Analysis analysis = new Analysis();
×
2594
    analysis.setStatement(showTimeSeriesStatement);
×
2595

2596
    PathPatternTree patternTree = new PathPatternTree();
×
2597
    patternTree.appendPathPattern(showTimeSeriesStatement.getPathPattern());
×
2598
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2599
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2600

2601
    Map<Integer, Template> templateMap =
×
2602
        schemaFetcher.checkAllRelatedTemplate(showTimeSeriesStatement.getPathPattern());
×
2603
    analysis.setRelatedTemplateInfo(templateMap);
×
2604

2605
    if (showTimeSeriesStatement.isOrderByHeat()) {
×
2606
      patternTree.constructTree();
×
2607
      // request schema fetch API
2608
      logger.debug("[StartFetchSchema]");
×
2609
      ISchemaTree schemaTree = schemaFetcher.fetchSchema(patternTree, context);
×
2610
      updateSchemaTreeByViews(analysis, schemaTree);
×
2611
      logger.debug("[EndFetchSchema]]");
×
2612

2613
      analyzeLastSource(
×
2614
          analysis,
2615
          Collections.singletonList(
×
2616
              new TimeSeriesOperand(showTimeSeriesStatement.getPathPattern())),
×
2617
          schemaTree);
2618
      analyzeDataPartition(analysis, new QueryStatement(), schemaTree);
×
2619
    }
2620

2621
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTimeSeriesHeader());
×
2622
    return analysis;
×
2623
  }
2624

2625
  @Override
2626
  public Analysis visitShowStorageGroup(
2627
      ShowDatabaseStatement showDatabaseStatement, MPPQueryContext context) {
2628
    Analysis analysis = new Analysis();
×
2629
    analysis.setStatement(showDatabaseStatement);
×
2630
    analysis.setRespDatasetHeader(
×
2631
        DatasetHeaderFactory.getShowStorageGroupHeader(showDatabaseStatement.isDetailed()));
×
2632
    return analysis;
×
2633
  }
2634

2635
  @Override
2636
  public Analysis visitShowTTL(ShowTTLStatement showTTLStatement, MPPQueryContext context) {
2637
    Analysis analysis = new Analysis();
×
2638
    analysis.setStatement(showTTLStatement);
×
2639
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTTLHeader());
×
2640
    return analysis;
×
2641
  }
2642

2643
  @Override
2644
  public Analysis visitShowDevices(
2645
      ShowDevicesStatement showDevicesStatement, MPPQueryContext context) {
2646
    Analysis analysis = new Analysis();
×
2647
    analysis.setStatement(showDevicesStatement);
×
2648

2649
    PathPatternTree patternTree = new PathPatternTree();
×
2650
    patternTree.appendPathPattern(
×
2651
        showDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD));
×
2652
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2653

2654
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2655
    analysis.setRespDatasetHeader(
×
2656
        showDevicesStatement.hasSgCol()
×
2657
            ? DatasetHeaderFactory.getShowDevicesWithSgHeader()
×
2658
            : DatasetHeaderFactory.getShowDevicesHeader());
×
2659
    return analysis;
×
2660
  }
2661

2662
  @Override
2663
  public Analysis visitShowCluster(
2664
      ShowClusterStatement showClusterStatement, MPPQueryContext context) {
2665
    Analysis analysis = new Analysis();
×
2666
    analysis.setStatement(showClusterStatement);
×
2667
    if (showClusterStatement.isDetails()) {
×
2668
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowClusterDetailsHeader());
×
2669
    } else {
2670
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowClusterHeader());
×
2671
    }
2672
    return analysis;
×
2673
  }
2674

2675
  @Override
2676
  public Analysis visitCountStorageGroup(
2677
      CountDatabaseStatement countDatabaseStatement, MPPQueryContext context) {
2678
    Analysis analysis = new Analysis();
×
2679
    analysis.setStatement(countDatabaseStatement);
×
2680
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountStorageGroupHeader());
×
2681
    return analysis;
×
2682
  }
2683

2684
  @Override
2685
  public Analysis visitSchemaFetch(
2686
      SchemaFetchStatement schemaFetchStatement, MPPQueryContext context) {
2687
    Analysis analysis = new Analysis();
×
2688
    analysis.setStatement(schemaFetchStatement);
×
2689

2690
    SchemaPartition schemaPartition =
×
2691
        partitionFetcher.getSchemaPartition(schemaFetchStatement.getPatternTree());
×
2692
    analysis.setSchemaPartitionInfo(schemaPartition);
×
2693

2694
    if (schemaPartition.isEmpty()) {
×
2695
      analysis.setFinishQueryAfterAnalyze(true);
×
2696
    }
2697

2698
    return analysis;
×
2699
  }
2700

2701
  @Override
2702
  public Analysis visitCountDevices(
2703
      CountDevicesStatement countDevicesStatement, MPPQueryContext context) {
2704
    Analysis analysis = new Analysis();
×
2705
    analysis.setStatement(countDevicesStatement);
×
2706

2707
    PathPatternTree patternTree = new PathPatternTree();
×
2708
    patternTree.appendPathPattern(
×
2709
        countDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD));
×
2710
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2711

2712
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2713
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountDevicesHeader());
×
2714
    return analysis;
×
2715
  }
2716

2717
  @Override
2718
  public Analysis visitCountTimeSeries(
2719
      CountTimeSeriesStatement countTimeSeriesStatement, MPPQueryContext context) {
2720
    Analysis analysis = new Analysis();
×
2721
    analysis.setStatement(countTimeSeriesStatement);
×
2722

2723
    PathPatternTree patternTree = new PathPatternTree();
×
2724
    patternTree.appendPathPattern(countTimeSeriesStatement.getPathPattern());
×
2725
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2726
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2727

2728
    Map<Integer, Template> templateMap =
×
2729
        schemaFetcher.checkAllRelatedTemplate(countTimeSeriesStatement.getPathPattern());
×
2730
    analysis.setRelatedTemplateInfo(templateMap);
×
2731

2732
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountTimeSeriesHeader());
×
2733
    return analysis;
×
2734
  }
2735

2736
  @Override
2737
  public Analysis visitCountLevelTimeSeries(
2738
      CountLevelTimeSeriesStatement countLevelTimeSeriesStatement, MPPQueryContext context) {
2739
    Analysis analysis = new Analysis();
×
2740
    analysis.setStatement(countLevelTimeSeriesStatement);
×
2741

2742
    PathPatternTree patternTree = new PathPatternTree();
×
2743
    patternTree.appendPathPattern(countLevelTimeSeriesStatement.getPathPattern());
×
2744
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2745

2746
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2747
    Map<Integer, Template> templateMap =
×
2748
        schemaFetcher.checkAllRelatedTemplate(countLevelTimeSeriesStatement.getPathPattern());
×
2749
    analysis.setRelatedTemplateInfo(templateMap);
×
2750
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountLevelTimeSeriesHeader());
×
2751
    return analysis;
×
2752
  }
2753

2754
  @Override
2755
  public Analysis visitCountNodes(CountNodesStatement countStatement, MPPQueryContext context) {
2756
    Analysis analysis = new Analysis();
×
2757
    analysis.setStatement(countStatement);
×
2758

2759
    PathPatternTree patternTree = new PathPatternTree();
×
2760
    patternTree.appendPathPattern(countStatement.getPathPattern());
×
2761
    SchemaNodeManagementPartition schemaNodeManagementPartition =
×
2762
        partitionFetcher.getSchemaNodeManagementPartitionWithLevel(
×
2763
            patternTree, countStatement.getLevel());
×
2764

2765
    if (schemaNodeManagementPartition == null) {
×
2766
      return analysis;
×
2767
    }
2768
    if (!schemaNodeManagementPartition.getMatchedNode().isEmpty()
×
2769
        && schemaNodeManagementPartition.getSchemaPartition().getSchemaPartitionMap().size() == 0) {
×
2770
      analysis.setFinishQueryAfterAnalyze(true);
×
2771
    }
2772
    analysis.setMatchedNodes(schemaNodeManagementPartition.getMatchedNode());
×
2773
    analysis.setSchemaPartitionInfo(schemaNodeManagementPartition.getSchemaPartition());
×
2774
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountNodesHeader());
×
2775
    return analysis;
×
2776
  }
2777

2778
  @Override
2779
  public Analysis visitShowChildPaths(
2780
      ShowChildPathsStatement showChildPathsStatement, MPPQueryContext context) {
2781
    return visitSchemaNodeManagementPartition(
×
2782
        showChildPathsStatement,
2783
        showChildPathsStatement.getPartialPath(),
×
2784
        DatasetHeaderFactory.getShowChildPathsHeader());
×
2785
  }
2786

2787
  @Override
2788
  public Analysis visitShowChildNodes(
2789
      ShowChildNodesStatement showChildNodesStatement, MPPQueryContext context) {
2790
    return visitSchemaNodeManagementPartition(
×
2791
        showChildNodesStatement,
2792
        showChildNodesStatement.getPartialPath(),
×
2793
        DatasetHeaderFactory.getShowChildNodesHeader());
×
2794
  }
2795

2796
  @Override
2797
  public Analysis visitShowVersion(
2798
      ShowVersionStatement showVersionStatement, MPPQueryContext context) {
2799
    Analysis analysis = new Analysis();
×
2800
    analysis.setStatement(showVersionStatement);
×
2801
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowVersionHeader());
×
2802
    analysis.setFinishQueryAfterAnalyze(true);
×
2803
    return analysis;
×
2804
  }
2805

2806
  private Analysis visitSchemaNodeManagementPartition(
2807
      Statement statement, PartialPath path, DatasetHeader header) {
2808
    Analysis analysis = new Analysis();
×
2809
    analysis.setStatement(statement);
×
2810

2811
    PathPatternTree patternTree = new PathPatternTree();
×
2812
    patternTree.appendPathPattern(path);
×
2813
    SchemaNodeManagementPartition schemaNodeManagementPartition =
×
2814
        partitionFetcher.getSchemaNodeManagementPartition(patternTree);
×
2815

2816
    if (schemaNodeManagementPartition == null) {
×
2817
      return analysis;
×
2818
    }
2819
    if (!schemaNodeManagementPartition.getMatchedNode().isEmpty()
×
2820
        && schemaNodeManagementPartition.getSchemaPartition().getSchemaPartitionMap().size() == 0) {
×
2821
      analysis.setFinishQueryAfterAnalyze(true);
×
2822
    }
2823
    analysis.setMatchedNodes(schemaNodeManagementPartition.getMatchedNode());
×
2824
    analysis.setSchemaPartitionInfo(schemaNodeManagementPartition.getSchemaPartition());
×
2825
    analysis.setRespDatasetHeader(header);
×
2826
    return analysis;
×
2827
  }
2828

2829
  @Override
2830
  public Analysis visitDeleteData(
2831
      DeleteDataStatement deleteDataStatement, MPPQueryContext context) {
2832
    context.setQueryType(QueryType.WRITE);
×
2833
    Analysis analysis = new Analysis();
×
2834
    analysis.setStatement(deleteDataStatement);
×
2835

2836
    PathPatternTree patternTree = new PathPatternTree();
×
2837
    deleteDataStatement.getPathList().forEach(patternTree::appendPathPattern);
×
2838

2839
    ISchemaTree schemaTree = schemaFetcher.fetchSchema(patternTree, context);
×
2840
    Set<String> deduplicatedDevicePaths = new HashSet<>();
×
2841

2842
    if (schemaTree.hasLogicalViewMeasurement()) {
×
2843
      updateSchemaTreeByViews(analysis, schemaTree);
×
2844

2845
      Set<PartialPath> deletePatternSet = new HashSet<>(deleteDataStatement.getPathList());
×
2846
      IMeasurementSchema measurementSchema;
2847
      LogicalViewSchema logicalViewSchema;
2848
      PartialPath sourcePathOfAliasSeries;
2849
      for (MeasurementPath measurementPath :
2850
          schemaTree.searchMeasurementPaths(SchemaConstant.ALL_MATCH_PATTERN).left) {
×
2851
        measurementSchema = measurementPath.getMeasurementSchema();
×
2852
        if (measurementSchema.isLogicalView()) {
×
2853
          logicalViewSchema = (LogicalViewSchema) measurementSchema;
×
2854
          if (logicalViewSchema.isWritable()) {
×
2855
            sourcePathOfAliasSeries = logicalViewSchema.getSourcePathIfWritable();
×
2856
            deletePatternSet.add(sourcePathOfAliasSeries);
×
2857
            deduplicatedDevicePaths.add(sourcePathOfAliasSeries.getDevice());
×
2858
          }
2859
          deletePatternSet.remove(measurementPath);
×
2860
        } else {
2861
          deduplicatedDevicePaths.add(measurementPath.getDevice());
×
2862
        }
2863
      }
×
2864
      deleteDataStatement.setPathList(new ArrayList<>(deletePatternSet));
×
2865
    } else {
×
2866
      for (PartialPath devicePattern : patternTree.getAllDevicePaths()) {
×
2867
        schemaTree
×
2868
            .getMatchedDevices(devicePattern)
×
2869
            .forEach(
×
2870
                deviceSchemaInfo ->
2871
                    deduplicatedDevicePaths.add(deviceSchemaInfo.getDevicePath().getFullPath()));
×
2872
      }
×
2873
    }
2874
    analysis.setSchemaTree(schemaTree);
×
2875

2876
    Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap = new HashMap<>();
×
2877

2878
    deduplicatedDevicePaths.forEach(
×
2879
        devicePath -> {
2880
          DataPartitionQueryParam queryParam = new DataPartitionQueryParam();
×
2881
          queryParam.setDevicePath(devicePath);
×
2882
          sgNameToQueryParamsMap
×
2883
              .computeIfAbsent(schemaTree.getBelongedDatabase(devicePath), key -> new ArrayList<>())
×
2884
              .add(queryParam);
×
2885
        });
×
2886

2887
    DataPartition dataPartition = partitionFetcher.getDataPartition(sgNameToQueryParamsMap);
×
2888
    analysis.setDataPartitionInfo(dataPartition);
×
2889
    analysis.setFinishQueryAfterAnalyze(dataPartition.isEmpty());
×
2890

2891
    return analysis;
×
2892
  }
2893

2894
  @Override
2895
  public Analysis visitCreateSchemaTemplate(
2896
      CreateSchemaTemplateStatement createTemplateStatement, MPPQueryContext context) {
2897

2898
    context.setQueryType(QueryType.WRITE);
×
2899
    List<String> measurements = createTemplateStatement.getMeasurements();
×
2900
    Set<String> measurementsSet = new HashSet<>(measurements);
×
2901
    if (measurementsSet.size() < measurements.size()) {
×
2902
      throw new SemanticException(
×
2903
          "Measurement under template is not allowed to have the same measurement name");
2904
    }
2905
    Analysis analysis = new Analysis();
×
2906
    analysis.setStatement(createTemplateStatement);
×
2907
    return analysis;
×
2908
  }
2909

2910
  @Override
2911
  public Analysis visitShowNodesInSchemaTemplate(
2912
      ShowNodesInSchemaTemplateStatement showNodesInSchemaTemplateStatement,
2913
      MPPQueryContext context) {
2914
    Analysis analysis = new Analysis();
×
2915
    analysis.setStatement(showNodesInSchemaTemplateStatement);
×
2916
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowNodesInSchemaTemplateHeader());
×
2917
    return analysis;
×
2918
  }
2919

2920
  @Override
2921
  public Analysis visitShowSchemaTemplate(
2922
      ShowSchemaTemplateStatement showSchemaTemplateStatement, MPPQueryContext context) {
2923
    Analysis analysis = new Analysis();
×
2924
    analysis.setStatement(showSchemaTemplateStatement);
×
2925
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowSchemaTemplateHeader());
×
2926
    return analysis;
×
2927
  }
2928

2929
  private GroupByFilter initGroupByFilter(GroupByTimeComponent groupByTimeComponent) {
2930
    if (groupByTimeComponent.isIntervalByMonth() || groupByTimeComponent.isSlidingStepByMonth()) {
1✔
2931
      return new GroupByMonthFilter(
×
2932
          groupByTimeComponent.getInterval(),
×
2933
          groupByTimeComponent.getSlidingStep(),
×
2934
          groupByTimeComponent.getStartTime(),
×
2935
          groupByTimeComponent.getEndTime(),
×
2936
          groupByTimeComponent.isSlidingStepByMonth(),
×
2937
          groupByTimeComponent.isIntervalByMonth(),
×
2938
          TimeZone.getTimeZone("+00:00"));
×
2939
    } else {
2940
      long startTime =
2941
          groupByTimeComponent.isLeftCRightO()
1✔
2942
              ? groupByTimeComponent.getStartTime()
1✔
2943
              : groupByTimeComponent.getStartTime() + 1;
1✔
2944
      long endTime =
2945
          groupByTimeComponent.isLeftCRightO()
1✔
2946
              ? groupByTimeComponent.getEndTime()
1✔
2947
              : groupByTimeComponent.getEndTime() + 1;
1✔
2948
      return new GroupByFilter(
1✔
2949
          groupByTimeComponent.getInterval(),
1✔
2950
          groupByTimeComponent.getSlidingStep(),
1✔
2951
          startTime,
2952
          endTime);
2953
    }
2954
  }
2955

2956
  @Override
2957
  public Analysis visitSetSchemaTemplate(
2958
      SetSchemaTemplateStatement setSchemaTemplateStatement, MPPQueryContext context) {
2959
    context.setQueryType(QueryType.WRITE);
×
2960
    Analysis analysis = new Analysis();
×
2961
    analysis.setStatement(setSchemaTemplateStatement);
×
2962
    return analysis;
×
2963
  }
2964

2965
  @Override
2966
  public Analysis visitShowPathSetTemplate(
2967
      ShowPathSetTemplateStatement showPathSetTemplateStatement, MPPQueryContext context) {
2968
    Analysis analysis = new Analysis();
×
2969
    analysis.setStatement(showPathSetTemplateStatement);
×
2970
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowPathSetTemplateHeader());
×
2971
    return analysis;
×
2972
  }
2973

2974
  @Override
2975
  public Analysis visitActivateTemplate(
2976
      ActivateTemplateStatement activateTemplateStatement, MPPQueryContext context) {
2977
    context.setQueryType(QueryType.WRITE);
×
2978
    Analysis analysis = new Analysis();
×
2979
    analysis.setStatement(activateTemplateStatement);
×
2980

2981
    PartialPath activatePath = activateTemplateStatement.getPath();
×
2982

2983
    Pair<Template, PartialPath> templateSetInfo = schemaFetcher.checkTemplateSetInfo(activatePath);
×
2984
    if (templateSetInfo == null) {
×
2985
      throw new StatementAnalyzeException(
×
2986
          new MetadataException(
2987
              String.format(
×
2988
                  "Path [%s] has not been set any template.", activatePath.getFullPath())));
×
2989
    }
2990
    analysis.setTemplateSetInfo(
×
2991
        new Pair<>(templateSetInfo.left, Collections.singletonList(templateSetInfo.right)));
×
2992

2993
    PathPatternTree patternTree = new PathPatternTree();
×
2994
    patternTree.appendPathPattern(activatePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
2995
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2996

2997
    analysis.setSchemaPartitionInfo(partition);
×
2998

2999
    return analysis;
×
3000
  }
3001

3002
  @Override
3003
  public Analysis visitBatchActivateTemplate(
3004
      BatchActivateTemplateStatement batchActivateTemplateStatement, MPPQueryContext context) {
3005
    context.setQueryType(QueryType.WRITE);
×
3006
    Analysis analysis = new Analysis();
×
3007
    analysis.setStatement(batchActivateTemplateStatement);
×
3008

3009
    Map<PartialPath, Pair<Template, PartialPath>> deviceTemplateSetInfoMap =
×
3010
        new HashMap<>(batchActivateTemplateStatement.getPaths().size());
×
3011
    for (PartialPath devicePath : batchActivateTemplateStatement.getDevicePathList()) {
×
3012
      Pair<Template, PartialPath> templateSetInfo = schemaFetcher.checkTemplateSetInfo(devicePath);
×
3013
      if (templateSetInfo == null) {
×
3014
        throw new StatementAnalyzeException(
×
3015
            new MetadataException(
3016
                String.format(
×
3017
                    "Path [%s] has not been set any template.", devicePath.getFullPath())));
×
3018
      }
3019
      deviceTemplateSetInfoMap.put(devicePath, templateSetInfo);
×
3020
    }
×
3021
    analysis.setDeviceTemplateSetInfoMap(deviceTemplateSetInfoMap);
×
3022

3023
    PathPatternTree patternTree = new PathPatternTree();
×
3024
    for (PartialPath devicePath : batchActivateTemplateStatement.getDevicePathList()) {
×
3025
      // the devicePath is a path without wildcard
3026
      patternTree.appendFullPath(devicePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
3027
    }
×
3028
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3029

3030
    analysis.setSchemaPartitionInfo(partition);
×
3031

3032
    return analysis;
×
3033
  }
3034

3035
  @Override
3036
  public Analysis visitInternalBatchActivateTemplate(
3037
      InternalBatchActivateTemplateStatement internalBatchActivateTemplateStatement,
3038
      MPPQueryContext context) {
3039
    context.setQueryType(QueryType.WRITE);
×
3040
    Analysis analysis = new Analysis();
×
3041
    analysis.setStatement(internalBatchActivateTemplateStatement);
×
3042

3043
    PathPatternTree patternTree = new PathPatternTree();
×
3044
    for (PartialPath activatePath :
3045
        internalBatchActivateTemplateStatement.getDeviceMap().keySet()) {
×
3046
      // the devicePath is a path without wildcard
3047
      patternTree.appendFullPath(activatePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
3048
    }
×
3049
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3050

3051
    analysis.setSchemaPartitionInfo(partition);
×
3052

3053
    return analysis;
×
3054
  }
3055

3056
  @Override
3057
  public Analysis visitShowPathsUsingTemplate(
3058
      ShowPathsUsingTemplateStatement showPathsUsingTemplateStatement, MPPQueryContext context) {
3059
    Analysis analysis = new Analysis();
×
3060
    analysis.setStatement(showPathsUsingTemplateStatement);
×
3061
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowPathsUsingTemplateHeader());
×
3062

3063
    Pair<Template, List<PartialPath>> templateSetInfo =
×
3064
        schemaFetcher.getAllPathsSetTemplate(showPathsUsingTemplateStatement.getTemplateName());
×
3065

3066
    if (templateSetInfo == null
×
3067
        || templateSetInfo.right == null
3068
        || templateSetInfo.right.isEmpty()) {
×
3069
      analysis.setFinishQueryAfterAnalyze(true);
×
3070
      return analysis;
×
3071
    }
3072

3073
    analysis.setTemplateSetInfo(templateSetInfo);
×
3074

3075
    PathPatternTree patternTree = new PathPatternTree();
×
3076
    PartialPath rawPathPattern = showPathsUsingTemplateStatement.getPathPattern();
×
3077
    List<PartialPath> specifiedPatternList = new ArrayList<>();
×
3078
    templateSetInfo.right.forEach(
×
3079
        setPath -> {
3080
          for (PartialPath specifiedPattern : rawPathPattern.alterPrefixPath(setPath)) {
×
3081
            patternTree.appendPathPattern(specifiedPattern);
×
3082
            specifiedPatternList.add(specifiedPattern);
×
3083
          }
×
3084
        });
×
3085

3086
    if (specifiedPatternList.isEmpty()) {
×
3087
      analysis.setFinishQueryAfterAnalyze(true);
×
3088
      return analysis;
×
3089
    }
3090

3091
    analysis.setSpecifiedTemplateRelatedPathPatternList(specifiedPatternList);
×
3092

3093
    SchemaPartition partition = partitionFetcher.getSchemaPartition(patternTree);
×
3094
    analysis.setSchemaPartitionInfo(partition);
×
3095
    if (partition.isEmpty()) {
×
3096
      analysis.setFinishQueryAfterAnalyze(true);
×
3097
      return analysis;
×
3098
    }
3099

3100
    return analysis;
×
3101
  }
3102

3103
  @Override
3104
  public Analysis visitShowQueries(
3105
      ShowQueriesStatement showQueriesStatement, MPPQueryContext context) {
3106
    Analysis analysis = new Analysis();
×
3107
    analysis.setStatement(showQueriesStatement);
×
3108
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowQueriesHeader());
×
3109
    analysis.setVirtualSource(true);
×
3110

3111
    List<TDataNodeLocation> allRunningDataNodeLocations = getRunningDataNodeLocations();
×
3112
    if (allRunningDataNodeLocations.isEmpty()) {
×
3113
      analysis.setFinishQueryAfterAnalyze(true);
×
3114
    }
3115
    // TODO Constant folding optimization for Where Predicate after True/False Constant introduced
3116
    if (allRunningDataNodeLocations.isEmpty()) {
×
3117
      throw new StatementAnalyzeException("no Running DataNodes");
×
3118
    }
3119
    analysis.setRunningDataNodeLocations(allRunningDataNodeLocations);
×
3120

3121
    Set<Expression> sourceExpressions = new HashSet<>();
×
3122
    for (ColumnHeader columnHeader : analysis.getRespDatasetHeader().getColumnHeaders()) {
×
3123
      sourceExpressions.add(
×
3124
          TimeSeriesOperand.constructColumnHeaderExpression(
×
3125
              columnHeader.getColumnName(), columnHeader.getColumnType()));
×
3126
    }
×
3127
    analysis.setSourceExpressions(sourceExpressions);
×
3128
    sourceExpressions.forEach(expression -> analyzeExpressionType(analysis, expression));
×
3129

3130
    analyzeWhere(analysis, showQueriesStatement);
×
3131

3132
    analysis.setMergeOrderParameter(new OrderByParameter(showQueriesStatement.getSortItemList()));
×
3133

3134
    return analysis;
×
3135
  }
3136

3137
  private List<TDataNodeLocation> getRunningDataNodeLocations() {
3138
    try (ConfigNodeClient client =
3139
        ConfigNodeClientManager.getInstance().borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) {
×
3140
      TGetDataNodeLocationsResp showDataNodesResp = client.getRunningDataNodeLocations();
×
3141
      if (showDataNodesResp.getStatus().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
×
3142
        throw new StatementAnalyzeException(
×
3143
            "An error occurred when executing getRunningDataNodeLocations():"
3144
                + showDataNodesResp.getStatus().getMessage());
×
3145
      }
3146
      return showDataNodesResp.getDataNodeLocationList();
×
3147
    } catch (ClientManagerException | TException e) {
×
3148
      throw new StatementAnalyzeException(
×
3149
          "An error occurred when executing getRunningDataNodeLocations():" + e.getMessage());
×
3150
    }
3151
  }
3152

3153
  private void analyzeWhere(Analysis analysis, ShowQueriesStatement showQueriesStatement) {
3154
    WhereCondition whereCondition = showQueriesStatement.getWhereCondition();
×
3155
    if (whereCondition == null) {
×
3156
      return;
×
3157
    }
3158

3159
    Expression whereExpression =
×
3160
        ExpressionAnalyzer.bindTypeForTimeSeriesOperand(
×
3161
            whereCondition.getPredicate(), ColumnHeaderConstant.showQueriesColumnHeaders);
×
3162

3163
    TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
×
3164
    if (outputType != TSDataType.BOOLEAN) {
×
3165
      throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
3166
    }
3167

3168
    analysis.setWhereExpression(whereExpression);
×
3169
  }
×
3170

3171
  // region view
3172

3173
  /**
3174
   * Compute how many paths exist, get the schema tree and the number of existed paths.
3175
   *
3176
   * @return a pair of ISchemaTree, and the number of exist paths.
3177
   */
3178
  private Pair<ISchemaTree, Integer> fetchSchemaOfPathsAndCount(
3179
      List<PartialPath> pathList, Analysis analysis, MPPQueryContext context) {
3180
    ISchemaTree schemaTree = analysis.getSchemaTree();
×
3181
    if (schemaTree == null) {
×
3182
      // source is not represented by query, thus has not done fetch schema.
3183
      PathPatternTree pathPatternTree = new PathPatternTree();
×
3184
      for (PartialPath path : pathList) {
×
3185
        pathPatternTree.appendPathPattern(path);
×
3186
      }
×
3187
      schemaTree = this.schemaFetcher.fetchSchema(pathPatternTree, context);
×
3188
    }
3189

3190
    // search each path, make sure they all exist.
3191
    int numOfExistPaths = 0;
×
3192
    for (PartialPath path : pathList) {
×
3193
      Pair<List<MeasurementPath>, Integer> pathPair = schemaTree.searchMeasurementPaths(path);
×
3194
      numOfExistPaths += !pathPair.left.isEmpty() ? 1 : 0;
×
3195
    }
×
3196
    return new Pair<>(schemaTree, numOfExistPaths);
×
3197
  }
3198

3199
  /**
3200
   * @param pathList the paths you want to check
3201
   * @param schemaTree the given schema tree
3202
   * @return if all paths you give can be found in schema tree, return a pair of view paths and
3203
   *     null; else return view paths and the non-exist path.
3204
   */
3205
  private Pair<List<PartialPath>, PartialPath> findAllViewsInPaths(
3206
      List<PartialPath> pathList, ISchemaTree schemaTree) {
3207
    List<PartialPath> result = new ArrayList<>();
×
3208
    for (PartialPath path : pathList) {
×
3209
      Pair<List<MeasurementPath>, Integer> measurementPathList =
×
3210
          schemaTree.searchMeasurementPaths(path);
×
3211
      if (measurementPathList.left.isEmpty()) {
×
3212
        return new Pair<>(result, path);
×
3213
      }
3214
      for (MeasurementPath measurementPath : measurementPathList.left) {
×
3215
        if (measurementPath.getMeasurementSchema().isLogicalView()) {
×
3216
          result.add(measurementPath);
×
3217
        }
3218
      }
×
3219
    }
×
3220
    return new Pair<>(result, null);
×
3221
  }
3222

3223
  private Pair<List<Expression>, Analysis> analyzeQueryInLogicalViewStatement(
3224
      Analysis analysis, QueryStatement queryStatement, MPPQueryContext context) {
3225
    Analysis queryAnalysis = this.visitQuery(queryStatement, context);
×
3226
    analysis.setSchemaTree(queryAnalysis.getSchemaTree());
×
3227
    // get all expression from resultColumns
3228
    List<Pair<Expression, String>> outputExpressions = queryAnalysis.getOutputExpressions();
×
3229
    if (queryAnalysis.isFailed()) {
×
3230
      analysis.setFinishQueryAfterAnalyze(true);
×
3231
      analysis.setFailStatus(queryAnalysis.getFailStatus());
×
3232
      return new Pair<>(null, analysis);
×
3233
    }
3234
    if (outputExpressions == null) {
×
3235
      analysis.setFinishQueryAfterAnalyze(true);
×
3236
      analysis.setFailStatus(
×
3237
          RpcUtils.getStatus(
×
3238
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3239
              "Columns in the query statement is empty. Please check your SQL."));
3240
      return new Pair<>(null, analysis);
×
3241
    }
3242
    if (queryAnalysis.useLogicalView()) {
×
3243
      analysis.setFinishQueryAfterAnalyze(true);
×
3244
      analysis.setFailStatus(
×
3245
          RpcUtils.getStatus(
×
3246
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3247
              "Can not create a view based on existing views. Check the query in your SQL."));
3248
      return new Pair<>(null, analysis);
×
3249
    }
3250
    List<Expression> expressionList = new ArrayList<>();
×
3251
    for (Pair<Expression, String> thisPair : outputExpressions) {
×
3252
      expressionList.add(thisPair.left);
×
3253
    }
×
3254
    return new Pair<>(expressionList, analysis);
×
3255
  }
3256

3257
  private void checkViewsInSource(
3258
      Analysis analysis, List<Expression> sourceExpressionList, MPPQueryContext context) {
3259
    List<PartialPath> pathsNeedCheck = new ArrayList<>();
×
3260
    for (Expression expression : sourceExpressionList) {
×
3261
      if (expression instanceof TimeSeriesOperand) {
×
3262
        pathsNeedCheck.add(((TimeSeriesOperand) expression).getPath());
×
3263
      }
3264
    }
×
3265
    Pair<ISchemaTree, Integer> schemaOfNeedToCheck =
×
3266
        fetchSchemaOfPathsAndCount(pathsNeedCheck, analysis, context);
×
3267
    if (schemaOfNeedToCheck.right != pathsNeedCheck.size()) {
×
3268
      // some source paths is not exist, and could not fetch schema.
3269
      analysis.setFinishQueryAfterAnalyze(true);
×
3270
      analysis.setFailStatus(
×
3271
          RpcUtils.getStatus(
×
3272
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3273
              "Can not create a view based on non-exist time series."));
3274
      return;
×
3275
    }
3276
    Pair<List<PartialPath>, PartialPath> viewInSourceCheckResult =
×
3277
        findAllViewsInPaths(pathsNeedCheck, schemaOfNeedToCheck.left);
×
3278
    if (viewInSourceCheckResult.right != null) {
×
3279
      // some source paths is not exist
3280
      analysis.setFinishQueryAfterAnalyze(true);
×
3281
      analysis.setFailStatus(
×
3282
          RpcUtils.getStatus(
×
3283
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3284
              "Path "
3285
                  + viewInSourceCheckResult.right.toString()
×
3286
                  + " does not exist! You can not create a view based on non-exist time series."));
3287
      return;
×
3288
    }
3289
    if (!viewInSourceCheckResult.left.isEmpty()) {
×
3290
      // some source paths is logical view
3291
      analysis.setFinishQueryAfterAnalyze(true);
×
3292
      analysis.setFailStatus(
×
3293
          RpcUtils.getStatus(
×
3294
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3295
              "Can not create a view based on existing views."));
3296
    }
3297
  }
×
3298

3299
  private void checkPathsInCreateLogicalView(
3300
      Analysis analysis, CreateLogicalViewStatement createLogicalViewStatement) {
3301
    Pair<Boolean, String> checkResult = createLogicalViewStatement.checkAllPaths();
×
3302
    if (Boolean.FALSE.equals(checkResult.left)) {
×
3303
      analysis.setFinishQueryAfterAnalyze(true);
×
3304
      analysis.setFailStatus(
×
3305
          RpcUtils.getStatus(
×
3306
              TSStatusCode.ILLEGAL_PATH.getStatusCode(),
×
3307
              "The path " + checkResult.right + " is illegal."));
3308
      return;
×
3309
    }
3310
    // make sure there are no redundant paths in targets. Please note that redundant paths in source
3311
    // are legal!
3312
    List<PartialPath> targetPathList = createLogicalViewStatement.getTargetPathList();
×
3313
    Set<String> targetStringSet = new HashSet<>();
×
3314
    for (PartialPath path : targetPathList) {
×
3315
      boolean repeatPathNotExist = targetStringSet.add(path.toString());
×
3316
      if (!repeatPathNotExist) {
×
3317
        analysis.setFinishQueryAfterAnalyze(true);
×
3318
        analysis.setFailStatus(
×
3319
            RpcUtils.getStatus(
×
3320
                TSStatusCode.ILLEGAL_PATH.getStatusCode(),
×
3321
                String.format("Path [%s] is redundant in target paths.", path)));
×
3322
        return;
×
3323
      }
3324
    }
×
3325
    if (createLogicalViewStatement.getSourceExpressionList().size() != targetPathList.size()) {
×
3326
      analysis.setFinishQueryAfterAnalyze(true);
×
3327
      analysis.setFailStatus(
×
3328
          RpcUtils.getStatus(
×
3329
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3330
              String.format(
×
3331
                  "The number of target paths (%d) and sources (%d) are miss matched! Please check your SQL.",
3332
                  createLogicalViewStatement.getTargetPathList().size(),
×
3333
                  createLogicalViewStatement.getSourceExpressionList().size())));
×
3334
      return;
×
3335
    }
3336
    // make sure all paths are NOt under any template
3337
    try {
3338
      for (PartialPath path : createLogicalViewStatement.getTargetPathList()) {
×
3339
        checkIsTemplateCompatible(path, null);
×
3340
      }
×
3341
    } catch (Exception e) {
×
3342
      analysis.setFinishQueryAfterAnalyze(true);
×
3343
      analysis.setFailStatus(
×
3344
          RpcUtils.getStatus(
×
3345
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3346
              "Can not create view under template."));
3347
    }
×
3348
  }
×
3349

3350
  // create Logical View
3351
  @Override
3352
  public Analysis visitCreateLogicalView(
3353
      CreateLogicalViewStatement createLogicalViewStatement, MPPQueryContext context) {
3354
    Analysis analysis = new Analysis();
×
3355
    context.setQueryType(QueryType.WRITE);
×
3356
    analysis.setStatement(createLogicalViewStatement);
×
3357

3358
    if (createLogicalViewStatement.getViewExpression() == null) {
×
3359
      // analyze query in statement
3360
      QueryStatement queryStatement = createLogicalViewStatement.getQueryStatement();
×
3361
      if (queryStatement != null) {
×
3362
        Pair<List<Expression>, Analysis> queryAnalysisPair =
×
3363
            this.analyzeQueryInLogicalViewStatement(analysis, queryStatement, context);
×
3364
        if (queryAnalysisPair.right.isFinishQueryAfterAnalyze()) {
×
3365
          return analysis;
×
3366
        } else if (queryAnalysisPair.left != null) {
×
3367
          try {
3368
            createLogicalViewStatement.setSourceExpressions(queryAnalysisPair.left);
×
3369
          } catch (UnsupportedViewException e) {
×
3370
            analysis.setFinishQueryAfterAnalyze(true);
×
3371
            analysis.setFailStatus(RpcUtils.getStatus(e.getErrorCode(), e.getMessage()));
×
3372
            return analysis;
×
3373
          }
×
3374
        }
3375
      }
3376
    }
3377

3378
    // use source and into item to generate target views
3379
    createLogicalViewStatement.parseIntoItemIfNecessary();
×
3380

3381
    // check target paths; check source expressions.
3382
    checkPathsInCreateLogicalView(analysis, createLogicalViewStatement);
×
3383
    if (analysis.isFinishQueryAfterAnalyze()) {
×
3384
      return analysis;
×
3385
    }
3386

3387
    // make sure there is no view in source
3388
    List<Expression> sourceExpressionList = createLogicalViewStatement.getSourceExpressionList();
×
3389
    checkViewsInSource(analysis, sourceExpressionList, context);
×
3390
    if (analysis.isFinishQueryAfterAnalyze()) {
×
3391
      return analysis;
×
3392
    }
3393

3394
    // set schema partition info, this info will be used to split logical plan node.
3395
    PathPatternTree patternTree = new PathPatternTree();
×
3396
    for (PartialPath thisFullPath : createLogicalViewStatement.getTargetPathList()) {
×
3397
      patternTree.appendFullPath(thisFullPath);
×
3398
    }
×
3399
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3400
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
3401

3402
    return analysis;
×
3403
  }
3404

3405
  @Override
3406
  public Analysis visitShowLogicalView(
3407
      ShowLogicalViewStatement showLogicalViewStatement, MPPQueryContext context) {
3408
    context.setQueryType(QueryType.READ);
×
3409
    Analysis analysis = new Analysis();
×
3410
    analysis.setStatement(showLogicalViewStatement);
×
3411

3412
    PathPatternTree patternTree = new PathPatternTree();
×
3413
    patternTree.appendPathPattern(showLogicalViewStatement.getPathPattern());
×
3414
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
3415
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
3416

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

© 2025 Coveralls, Inc