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

apache / iotdb / #9907

23 Aug 2023 07:42AM UTC coverage: 47.816% (+0.03%) from 47.785%
#9907

push

travis_ci

web-flow
[To rel/1.2][IOTDB-6120] Push down limit/offset in query with group by time

112 of 112 new or added lines in 7 files covered. (100.0%)

79945 of 167192 relevant lines covered (47.82%)

0.48 hits per line

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

43.87
/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.SelectIntoUtils.constructTargetDevice;
184
import static org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetMeasurement;
185
import static org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetPath;
186
import static org.apache.iotdb.db.queryengine.plan.optimization.LimitOffsetPushDown.canPushDownLimitOffsetInGroupByTimeForDevice;
187
import static org.apache.iotdb.db.queryengine.plan.optimization.LimitOffsetPushDown.pushDownLimitOffsetInGroupByTimeForDevice;
188
import static org.apache.iotdb.db.schemaengine.schemaregion.view.visitor.GetSourcePathsVisitor.getSourcePaths;
189

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

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

195
  private static final IoTDBConfig CONFIG = IoTDBDescriptor.getInstance().getConfig();
1✔
196

197
  private static final Expression deviceExpression =
1✔
198
      TimeSeriesOperand.constructColumnHeaderExpression(DEVICE, TSDataType.TEXT);
1✔
199

200
  private static final Expression endTimeExpression =
1✔
201
      TimeSeriesOperand.constructColumnHeaderExpression(ENDTIME, TSDataType.INT64);
1✔
202

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

206
  private final IPartitionFetcher partitionFetcher;
207
  private final ISchemaFetcher schemaFetcher;
208

209
  private static final PerformanceOverviewMetrics PERFORMANCE_OVERVIEW_METRICS =
1✔
210
      PerformanceOverviewMetrics.getInstance();
1✔
211

212
  public AnalyzeVisitor(IPartitionFetcher partitionFetcher, ISchemaFetcher schemaFetcher) {
1✔
213
    this.partitionFetcher = partitionFetcher;
1✔
214
    this.schemaFetcher = schemaFetcher;
1✔
215
  }
1✔
216

217
  @Override
218
  public Analysis visitNode(StatementNode node, MPPQueryContext context) {
219
    throw new UnsupportedOperationException(
×
220
        "Unsupported statement type: " + node.getClass().getName());
×
221
  }
222

223
  @Override
224
  public Analysis visitExplain(ExplainStatement explainStatement, MPPQueryContext context) {
225
    Analysis analysis = visitQuery(explainStatement.getQueryStatement(), context);
×
226
    analysis.setStatement(explainStatement);
×
227
    analysis.setFinishQueryAfterAnalyze(true);
×
228
    return analysis;
×
229
  }
230

231
  @Override
232
  public Analysis visitQuery(QueryStatement queryStatement, MPPQueryContext context) {
233
    Analysis analysis = new Analysis();
1✔
234
    analysis.setLastLevelUseWildcard(queryStatement.isLastLevelUseWildcard());
1✔
235
    try {
236
      // check for semantic errors
237
      queryStatement.semanticCheck();
1✔
238

239
      ISchemaTree schemaTree = analyzeSchema(queryStatement, analysis, context);
1✔
240
      // If there is no leaf node in the schema tree, the query should be completed immediately
241
      if (schemaTree.isEmpty()) {
1✔
242
        return finishQuery(queryStatement, analysis);
×
243
      }
244

245
      // extract global time filter from query filter and determine if there is a value filter
246
      analyzeGlobalTimeFilter(analysis, queryStatement);
1✔
247

248
      if (queryStatement.isLastQuery()) {
1✔
249
        return analyzeLastQuery(queryStatement, analysis, schemaTree);
×
250
      }
251

252
      List<Pair<Expression, String>> outputExpressions;
253
      if (queryStatement.isAlignByDevice()) {
1✔
254
        List<PartialPath> deviceList = analyzeFrom(queryStatement, schemaTree);
1✔
255

256
        if (canPushDownLimitOffsetInGroupByTimeForDevice(queryStatement)) {
1✔
257
          // remove the device which won't appear in resultSet after limit/offset
258
          deviceList = pushDownLimitOffsetInGroupByTimeForDevice(deviceList, queryStatement);
1✔
259
        }
260

261
        analyzeDeviceToWhere(analysis, queryStatement, schemaTree, deviceList);
1✔
262
        outputExpressions = analyzeSelect(analysis, queryStatement, schemaTree, deviceList);
1✔
263
        if (deviceList.isEmpty()) {
1✔
264
          return finishQuery(queryStatement, analysis);
×
265
        }
266
        analysis.setDeviceList(deviceList);
1✔
267

268
        analyzeDeviceToGroupBy(analysis, queryStatement, schemaTree, deviceList);
1✔
269
        analyzeDeviceToOrderBy(analysis, queryStatement, schemaTree, deviceList);
1✔
270
        analyzeHaving(analysis, queryStatement, schemaTree, deviceList);
1✔
271

272
        analyzeDeviceToAggregation(analysis, queryStatement);
1✔
273
        analyzeDeviceToSourceTransform(analysis, queryStatement);
1✔
274
        analyzeDeviceToSource(analysis, queryStatement);
1✔
275

276
        analyzeDeviceViewOutput(analysis, queryStatement);
1✔
277
        analyzeDeviceViewInput(analysis, queryStatement);
1✔
278

279
        analyzeInto(analysis, queryStatement, deviceList, outputExpressions);
1✔
280
      } else {
1✔
281
        Map<Integer, List<Pair<Expression, String>>> outputExpressionMap =
1✔
282
            analyzeSelect(analysis, queryStatement, schemaTree);
1✔
283

284
        outputExpressions = new ArrayList<>();
1✔
285
        outputExpressionMap.values().forEach(outputExpressions::addAll);
1✔
286
        analysis.setOutputExpressions(outputExpressions);
1✔
287
        if (outputExpressions.isEmpty()) {
1✔
288
          return finishQuery(queryStatement, analysis);
×
289
        }
290

291
        analyzeGroupBy(analysis, queryStatement, schemaTree);
1✔
292
        analyzeHaving(analysis, queryStatement, schemaTree);
1✔
293
        analyzeOrderBy(analysis, queryStatement, schemaTree);
1✔
294

295
        analyzeGroupByLevel(analysis, queryStatement, outputExpressionMap, outputExpressions);
1✔
296
        analyzeGroupByTag(analysis, queryStatement, outputExpressions);
1✔
297

298
        Set<Expression> selectExpressions = new LinkedHashSet<>();
1✔
299
        if (queryStatement.isOutputEndTime()) {
1✔
300
          selectExpressions.add(endTimeExpression);
×
301
        }
302
        for (Pair<Expression, String> outputExpressionAndAlias : outputExpressions) {
1✔
303
          selectExpressions.add(outputExpressionAndAlias.left);
1✔
304
        }
1✔
305
        analysis.setSelectExpressions(selectExpressions);
1✔
306

307
        analyzeAggregation(analysis, queryStatement);
1✔
308

309
        analyzeWhere(analysis, queryStatement, schemaTree);
1✔
310
        analyzeSourceTransform(analysis, queryStatement);
1✔
311

312
        analyzeSource(analysis, queryStatement);
1✔
313

314
        analyzeInto(analysis, queryStatement, outputExpressions);
1✔
315
      }
316

317
      analyzeGroupByTime(analysis, queryStatement);
1✔
318

319
      analyzeFill(analysis, queryStatement);
1✔
320

321
      // generate result set header according to output expressions
322
      analyzeOutput(analysis, queryStatement, outputExpressions);
1✔
323

324
      // fetch partition information
325
      analyzeDataPartition(analysis, queryStatement, schemaTree);
1✔
326

327
    } catch (StatementAnalyzeException e) {
×
328
      throw new StatementAnalyzeException(
×
329
          "Meet error when analyzing the query statement: " + e.getMessage());
×
330
    }
1✔
331
    return analysis;
1✔
332
  }
333

334
  private ISchemaTree analyzeSchema(
335
      QueryStatement queryStatement, Analysis analysis, MPPQueryContext context) {
336
    // concat path and construct path pattern tree
337
    PathPatternTree patternTree = new PathPatternTree(queryStatement.useWildcard());
1✔
338
    queryStatement = (QueryStatement) new ConcatPathRewriter().rewrite(queryStatement, patternTree);
1✔
339
    analysis.setStatement(queryStatement);
1✔
340

341
    // request schema fetch API
342
    long startTime = System.nanoTime();
1✔
343
    ISchemaTree schemaTree;
344
    try {
345
      logger.debug("[StartFetchSchema]");
1✔
346
      if (queryStatement.isGroupByTag()) {
1✔
347
        schemaTree = schemaFetcher.fetchSchemaWithTags(patternTree, context);
×
348
      } else {
349
        schemaTree = schemaFetcher.fetchSchema(patternTree, context);
1✔
350
      }
351

352
      // make sure paths in logical view is fetched
353
      updateSchemaTreeByViews(analysis, schemaTree);
1✔
354
    } finally {
355
      logger.debug("[EndFetchSchema]");
1✔
356
      QueryPlanCostMetricSet.getInstance()
1✔
357
          .recordPlanCost(SCHEMA_FETCHER, System.nanoTime() - startTime);
1✔
358
    }
359
    analysis.setSchemaTree(schemaTree);
1✔
360
    return schemaTree;
1✔
361
  }
362

363
  private Analysis finishQuery(QueryStatement queryStatement, Analysis analysis) {
364
    if (queryStatement.isSelectInto()) {
×
365
      analysis.setRespDatasetHeader(
×
366
          DatasetHeaderFactory.getSelectIntoHeader(queryStatement.isAlignByDevice()));
×
367
    }
368
    if (queryStatement.isLastQuery()) {
×
369
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getLastQueryHeader());
×
370
    }
371
    analysis.setFinishQueryAfterAnalyze(true);
×
372
    return analysis;
×
373
  }
374

375
  private void analyzeGlobalTimeFilter(Analysis analysis, QueryStatement queryStatement) {
376
    Filter globalTimeFilter = null;
1✔
377
    boolean hasValueFilter = false;
1✔
378
    if (queryStatement.getWhereCondition() != null) {
1✔
379
      WhereCondition whereCondition = queryStatement.getWhereCondition();
1✔
380
      Expression predicate = whereCondition.getPredicate();
1✔
381

382
      Pair<Filter, Boolean> resultPair =
1✔
383
          ExpressionAnalyzer.extractGlobalTimeFilter(predicate, true, true);
1✔
384
      globalTimeFilter = resultPair.left;
1✔
385
      if (globalTimeFilter != null) {
1✔
386
        globalTimeFilter = PredicateRemoveNotRewriter.rewrite(globalTimeFilter);
1✔
387
      }
388
      hasValueFilter = resultPair.right;
1✔
389

390
      predicate = ExpressionAnalyzer.evaluatePredicate(predicate);
1✔
391

392
      // set where condition to null if predicate is true or time filter.
393
      if (!hasValueFilter
1✔
394
          || (predicate.getExpressionType().equals(ExpressionType.CONSTANT)
1✔
395
              && Boolean.parseBoolean(predicate.getExpressionString()))) {
×
396
        queryStatement.setWhereCondition(null);
1✔
397
      } else {
398
        whereCondition.setPredicate(predicate);
1✔
399
      }
400
    }
401
    analysis.setGlobalTimeFilter(globalTimeFilter);
1✔
402
    analysis.setHasValueFilter(hasValueFilter);
1✔
403
  }
1✔
404

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

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

418
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getLastQueryHeader());
×
419

420
    // fetch partition information
421
    analyzeDataPartition(analysis, queryStatement, schemaTree);
×
422

423
    return analysis;
×
424
  }
425

426
  private void analyzeLastSource(
427
      Analysis analysis, List<Expression> selectExpressions, ISchemaTree schemaTree) {
428
    Set<Expression> sourceExpressions;
429

430
    sourceExpressions = new LinkedHashSet<>();
×
431

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

445
  private void updateSchemaTreeByViews(Analysis analysis, ISchemaTree originSchemaTree) {
446
    if (!originSchemaTree.hasLogicalViewMeasurement()) {
1✔
447
      return;
1✔
448
    }
449

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

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

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

492
    boolean isGroupByLevel = queryStatement.isGroupByLevel();
1✔
493
    ColumnPaginationController paginationController =
1✔
494
        new ColumnPaginationController(
495
            queryStatement.getSeriesLimit(),
1✔
496
            queryStatement.getSeriesOffset(),
1✔
497
            queryStatement.isLastQuery() || isGroupByLevel);
1✔
498

499
    Set<String> aliasSet = new HashSet<>();
1✔
500

501
    int columnIndex = 0;
1✔
502

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

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

522
            checkAliasUniqueness(resultColumn.getAlias(), aliasSet);
1✔
523

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

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

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

552
    return queryStatement.getResultDeviceOrder() == Ordering.ASC
1✔
553
        ? deviceSet.stream().sorted().collect(Collectors.toList())
1✔
554
        : deviceSet.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
1✔
555
  }
556

557
  private List<Pair<Expression, String>> analyzeSelect(
558
      Analysis analysis,
559
      QueryStatement queryStatement,
560
      ISchemaTree schemaTree,
561
      List<PartialPath> deviceSet) {
562
    List<Pair<Expression, String>> outputExpressions = new ArrayList<>();
1✔
563
    Map<String, Set<Expression>> deviceToSelectExpressions = new HashMap<>();
1✔
564

565
    ColumnPaginationController paginationController =
1✔
566
        new ColumnPaginationController(
567
            queryStatement.getSeriesLimit(), queryStatement.getSeriesOffset(), false);
1✔
568

569
    for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) {
1✔
570
      Expression selectExpression = resultColumn.getExpression();
1✔
571

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

587
      checkAliasUniqueness(resultColumn.getAlias(), measurementToDeviceSelectExpressions);
1✔
588

589
      for (Map.Entry<Expression, Map<String, Expression>> measurementDeviceSelectExpressionsEntry :
590
          measurementToDeviceSelectExpressions.entrySet()) {
1✔
591
        Expression measurementExpression = measurementDeviceSelectExpressionsEntry.getKey();
1✔
592
        Map<String, Expression> deviceToSelectExpressionsOfOneMeasurement =
1✔
593
            measurementDeviceSelectExpressionsEntry.getValue();
1✔
594

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

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

618
          // add deviceToSelectExpressions
619
          updateDeviceToSelectExpressions(
1✔
620
              analysis, deviceToSelectExpressions, deviceToSelectExpressionsOfOneMeasurement);
621

622
          paginationController.consumeLimit();
1✔
623
        } else {
624
          break;
625
        }
626
      }
1✔
627
    }
1✔
628

629
    // remove devices without measurements to compute
630
    Set<PartialPath> noMeasurementDevices = new HashSet<>();
1✔
631
    for (PartialPath device : deviceSet) {
1✔
632
      if (!deviceToSelectExpressions.containsKey(device.getFullPath())) {
1✔
633
        noMeasurementDevices.add(device);
×
634
      }
635
    }
1✔
636
    deviceSet.removeAll(noMeasurementDevices);
1✔
637

638
    // when the select expression of any device is empty,
639
    // the where expression map also need remove this device
640
    if (analysis.getDeviceToWhereExpression() != null) {
1✔
641
      noMeasurementDevices.forEach(
1✔
642
          devicePath -> analysis.getDeviceToWhereExpression().remove(devicePath.getFullPath()));
×
643
    }
644

645
    analysis.setDeviceToSelectExpressions(deviceToSelectExpressions);
1✔
646

647
    // set selectExpressions
648
    Set<Expression> selectExpressions = new LinkedHashSet<>();
1✔
649
    selectExpressions.add(deviceExpression);
1✔
650
    if (queryStatement.isOutputEndTime()) {
1✔
651
      selectExpressions.add(endTimeExpression);
×
652
    }
653
    selectExpressions.addAll(
1✔
654
        outputExpressions.stream()
1✔
655
            .map(Pair::getLeft)
1✔
656
            .collect(Collectors.toCollection(LinkedHashSet::new)));
1✔
657
    analysis.setSelectExpressions(selectExpressions);
1✔
658

659
    return outputExpressions;
1✔
660
  }
661

662
  private void updateMeasurementToDeviceSelectExpressions(
663
      Analysis analysis,
664
      Map<Expression, Map<String, Expression>> measurementToDeviceSelectExpressions,
665
      PartialPath device,
666
      List<Expression> selectExpressionsOfOneDevice) {
667
    for (Expression expression : selectExpressionsOfOneDevice) {
1✔
668
      Expression measurementExpression =
1✔
669
          ExpressionAnalyzer.getMeasurementExpression(expression, analysis);
1✔
670
      measurementToDeviceSelectExpressions
1✔
671
          .computeIfAbsent(measurementExpression, key -> new LinkedHashMap<>())
1✔
672
          .put(device.getFullPath(), ExpressionAnalyzer.toLowerCaseExpression(expression));
1✔
673
    }
1✔
674
  }
1✔
675

676
  private void updateDeviceToSelectExpressions(
677
      Analysis analysis,
678
      Map<String, Set<Expression>> deviceToSelectExpressions,
679
      Map<String, Expression> deviceToSelectExpressionsOfOneMeasurement) {
680
    for (Map.Entry<String, Expression> deviceNameSelectExpressionEntry :
681
        deviceToSelectExpressionsOfOneMeasurement.entrySet()) {
1✔
682
      String deviceName = deviceNameSelectExpressionEntry.getKey();
1✔
683
      Expression expression = deviceNameSelectExpressionEntry.getValue();
1✔
684

685
      Expression normalizedExpression = ExpressionAnalyzer.toLowerCaseExpression(expression);
1✔
686
      analyzeExpressionType(analysis, normalizedExpression);
1✔
687
      deviceToSelectExpressions
1✔
688
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
689
          .add(normalizedExpression);
1✔
690
    }
1✔
691
  }
1✔
692

693
  private String analyzeAlias(
694
      String resultColumnAlias, Expression rawExpression, Expression normalizedExpression) {
695
    if (resultColumnAlias != null) {
1✔
696
      // use alias as output symbol
697
      return resultColumnAlias;
1✔
698
    }
699

700
    if (!Objects.equals(normalizedExpression, rawExpression)) {
1✔
701
      return rawExpression.getOutputSymbol();
1✔
702
    }
703
    return null;
1✔
704
  }
705

706
  private void analyzeHaving(
707
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
708
    if (!queryStatement.hasHaving()) {
1✔
709
      return;
1✔
710
    }
711

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

733
  private void analyzeHaving(
734
      Analysis analysis,
735
      QueryStatement queryStatement,
736
      ISchemaTree schemaTree,
737
      List<PartialPath> deviceSet) {
738
    if (!queryStatement.hasHaving()) {
1✔
739
      return;
1✔
740
    }
741

742
    // two maps to be updated
743
    Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
744
        analysis.getDeviceToAggregationExpressions();
1✔
745
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
746
        analysis.getDeviceToOutputExpressions();
1✔
747

748
    Expression havingExpression = queryStatement.getHavingCondition().getPredicate();
1✔
749
    Set<Expression> conJunctions = new HashSet<>();
1✔
750

751
    for (PartialPath device : deviceSet) {
1✔
752
      List<Expression> expressionsInHaving =
1✔
753
          ExpressionAnalyzer.concatDeviceAndBindSchemaForExpression(
1✔
754
              havingExpression, device, schemaTree);
755

756
      conJunctions.addAll(
1✔
757
          expressionsInHaving.stream()
1✔
758
              .map(expression -> ExpressionAnalyzer.getMeasurementExpression(expression, analysis))
1✔
759
              .collect(Collectors.toList()));
1✔
760

761
      for (Expression expression : expressionsInHaving) {
1✔
762
        Set<Expression> aggregationExpressions = new LinkedHashSet<>();
1✔
763
        Set<Expression> normalizedAggregationExpressions = new LinkedHashSet<>();
1✔
764
        for (Expression aggregationExpression :
765
            ExpressionAnalyzer.searchAggregationExpressions(expression)) {
1✔
766
          Expression normalizedAggregationExpression =
1✔
767
              ExpressionAnalyzer.normalizeExpression(aggregationExpression);
1✔
768

769
          analyzeExpressionType(analysis, aggregationExpression);
1✔
770
          analyzeExpressionType(analysis, normalizedAggregationExpression);
1✔
771

772
          aggregationExpressions.add(aggregationExpression);
1✔
773
          normalizedAggregationExpressions.add(normalizedAggregationExpression);
1✔
774
        }
1✔
775
        deviceToOutputExpressions
1✔
776
            .computeIfAbsent(device.getFullPath(), key -> new LinkedHashSet<>())
1✔
777
            .addAll(aggregationExpressions);
1✔
778
        deviceToAggregationExpressions
1✔
779
            .computeIfAbsent(device.getFullPath(), key -> new LinkedHashSet<>())
1✔
780
            .addAll(normalizedAggregationExpressions);
1✔
781
      }
1✔
782
    }
1✔
783

784
    havingExpression = ExpressionUtils.constructQueryFilter(new ArrayList<>(conJunctions));
1✔
785
    TSDataType outputType = analyzeExpressionType(analysis, havingExpression);
1✔
786
    if (outputType != TSDataType.BOOLEAN) {
1✔
787
      throw new SemanticException(
×
788
          String.format(
×
789
              "The output type of the expression in HAVING clause should be BOOLEAN, actual data type: %s.",
790
              outputType));
791
    }
792
    analysis.setDeviceToAggregationExpressions(deviceToAggregationExpressions);
1✔
793
    analysis.setHavingExpression(havingExpression);
1✔
794
  }
1✔
795

796
  private void analyzeGroupByLevel(
797
      Analysis analysis,
798
      QueryStatement queryStatement,
799
      Map<Integer, List<Pair<Expression, String>>> outputExpressionMap,
800
      List<Pair<Expression, String>> outputExpressions) {
801
    if (!queryStatement.isGroupByLevel()) {
1✔
802
      return;
1✔
803
    }
804

805
    GroupByLevelController groupByLevelController =
×
806
        new GroupByLevelController(queryStatement.getGroupByLevelComponent().getLevels());
×
807

808
    List<Expression> groupedSelectExpressions = new LinkedList<>();
×
809

810
    for (List<Pair<Expression, String>> outputExpressionList : outputExpressionMap.values()) {
×
811
      Set<Expression> groupedSelectExpressionSet = new LinkedHashSet<>();
×
812
      for (int i = 0; i < outputExpressionList.size(); i++) {
×
813
        Pair<Expression, String> expressionAliasPair = outputExpressionList.get(i);
×
814
        boolean isCountStar = queryStatement.getGroupByLevelComponent().isCountStar(i);
×
815
        Expression groupedExpression =
×
816
            groupByLevelController.control(
×
817
                isCountStar, expressionAliasPair.left, expressionAliasPair.right);
818
        groupedSelectExpressionSet.add(groupedExpression);
×
819
      }
820
      groupedSelectExpressions.addAll(groupedSelectExpressionSet);
×
821
    }
×
822

823
    LinkedHashMap<Expression, Set<Expression>> groupByLevelExpressions = new LinkedHashMap<>();
×
824
    if (queryStatement.hasHaving()) {
×
825
      // update havingExpression
826
      Expression havingExpression = groupByLevelController.control(analysis.getHavingExpression());
×
827
      analyzeExpressionType(analysis, havingExpression);
×
828
      analysis.setHavingExpression(havingExpression);
×
829
      updateGroupByLevelExpressions(
×
830
          analysis,
831
          havingExpression,
832
          groupByLevelExpressions,
833
          groupByLevelController.getGroupedExpressionToRawExpressionsMap());
×
834
    }
835

836
    outputExpressions.clear();
×
837
    ColumnPaginationController paginationController =
×
838
        new ColumnPaginationController(
839
            queryStatement.getSeriesLimit(), queryStatement.getSeriesOffset(), false);
×
840
    for (Expression groupedExpression : groupedSelectExpressions) {
×
841
      if (paginationController.hasCurOffset()) {
×
842
        paginationController.consumeOffset();
×
843
      } else if (paginationController.hasCurLimit()) {
×
844
        Expression normalizedGroupedExpression =
×
845
            ExpressionAnalyzer.normalizeExpression(groupedExpression);
×
846
        analyzeExpressionType(analysis, normalizedGroupedExpression);
×
847
        outputExpressions.add(
×
848
            new Pair<>(
849
                normalizedGroupedExpression,
850
                analyzeAlias(
×
851
                    groupByLevelController.getAlias(groupedExpression.getExpressionString()),
×
852
                    groupedExpression,
853
                    normalizedGroupedExpression)));
854
        updateGroupByLevelExpressions(
×
855
            analysis,
856
            groupedExpression,
857
            groupByLevelExpressions,
858
            groupByLevelController.getGroupedExpressionToRawExpressionsMap());
×
859
        paginationController.consumeLimit();
×
860
      } else {
861
        break;
862
      }
863
    }
×
864

865
    checkDataTypeConsistencyInGroupByLevel(analysis, groupByLevelExpressions);
×
866
    analysis.setCrossGroupByExpressions(groupByLevelExpressions);
×
867
  }
×
868

869
  private void checkDataTypeConsistencyInGroupByLevel(
870
      Analysis analysis, Map<Expression, Set<Expression>> groupByLevelExpressions) {
871
    for (Map.Entry<Expression, Set<Expression>> groupedExpressionRawExpressionsEntry :
872
        groupByLevelExpressions.entrySet()) {
×
873
      Expression groupedAggregationExpression = groupedExpressionRawExpressionsEntry.getKey();
×
874
      Set<Expression> rawAggregationExpressions = groupedExpressionRawExpressionsEntry.getValue();
×
875

876
      TSDataType checkedDataType = analysis.getType(groupedAggregationExpression);
×
877
      for (Expression rawAggregationExpression : rawAggregationExpressions) {
×
878
        if (analysis.getType(rawAggregationExpression) != checkedDataType) {
×
879
          throw new SemanticException(
×
880
              String.format(
×
881
                  "GROUP BY LEVEL: the data types of the same output column[%s] should be the same.",
882
                  groupedAggregationExpression));
883
        }
884
      }
×
885
    }
×
886
  }
×
887

888
  private void updateGroupByLevelExpressions(
889
      Analysis analysis,
890
      Expression expression,
891
      Map<Expression, Set<Expression>> groupByLevelExpressions,
892
      Map<Expression, Set<Expression>> groupedExpressionToRawExpressionsMap) {
893
    for (Expression groupedAggregationExpression :
894
        ExpressionAnalyzer.searchAggregationExpressions(expression)) {
×
895
      Set<Expression> groupedExpressionSet =
×
896
          groupedExpressionToRawExpressionsMap.get(groupedAggregationExpression).stream()
×
897
              .map(ExpressionAnalyzer::normalizeExpression)
×
898
              .collect(Collectors.toSet());
×
899
      Expression groupedAggregationExpressionWithoutAlias =
×
900
          ExpressionAnalyzer.normalizeExpression(groupedAggregationExpression);
×
901

902
      analyzeExpressionType(analysis, groupedAggregationExpressionWithoutAlias);
×
903
      groupedExpressionSet.forEach(
×
904
          groupedExpression -> analyzeExpressionType(analysis, groupedExpression));
×
905

906
      groupByLevelExpressions
×
907
          .computeIfAbsent(groupedAggregationExpressionWithoutAlias, key -> new HashSet<>())
×
908
          .addAll(groupedExpressionSet);
×
909
    }
×
910
  }
×
911

912
  /**
913
   * This method is used to analyze GROUP BY TAGS query.
914
   *
915
   * <p>TODO: support slimit/soffset/value filter
916
   */
917
  private void analyzeGroupByTag(
918
      Analysis analysis,
919
      QueryStatement queryStatement,
920
      List<Pair<Expression, String>> outputExpressions) {
921
    if (!queryStatement.isGroupByTag()) {
1✔
922
      return;
1✔
923
    }
924
    if (analysis.hasValueFilter()) {
×
925
      throw new SemanticException("Only time filters are supported in GROUP BY TAGS query");
×
926
    }
927

928
    List<String> tagKeys = queryStatement.getGroupByTagComponent().getTagKeys();
×
929
    Map<List<String>, LinkedHashMap<Expression, List<Expression>>>
930
        tagValuesToGroupedTimeseriesOperands = new HashMap<>();
×
931
    LinkedHashMap<Expression, Set<Expression>> outputExpressionToRawExpressionsMap =
×
932
        new LinkedHashMap<>();
933

934
    for (Pair<Expression, String> outputExpressionAndAlias : outputExpressions) {
×
935
      FunctionExpression rawExpression = (FunctionExpression) outputExpressionAndAlias.getLeft();
×
936
      FunctionExpression measurementExpression =
×
937
          (FunctionExpression) ExpressionAnalyzer.getMeasurementExpression(rawExpression, analysis);
×
938
      outputExpressionToRawExpressionsMap
×
939
          .computeIfAbsent(measurementExpression, v -> new HashSet<>())
×
940
          .add(rawExpression);
×
941

942
      Map<String, String> tagMap =
×
943
          ((MeasurementPath)
944
                  ((TimeSeriesOperand) measurementExpression.getExpressions().get(0)).getPath())
×
945
              .getTagMap();
×
946
      List<String> tagValues = new ArrayList<>();
×
947
      for (String tagKey : tagKeys) {
×
948
        tagValues.add(tagMap.get(tagKey));
×
949
      }
×
950
      tagValuesToGroupedTimeseriesOperands
×
951
          .computeIfAbsent(tagValues, key -> new LinkedHashMap<>())
×
952
          .computeIfAbsent(measurementExpression, key -> new ArrayList<>())
×
953
          .add(rawExpression.getExpressions().get(0));
×
954
    }
×
955

956
    // update outputExpressions
957
    outputExpressions.clear();
×
958
    for (String tagKey : tagKeys) {
×
959
      Expression tagKeyExpression =
×
960
          TimeSeriesOperand.constructColumnHeaderExpression(tagKey, TSDataType.TEXT);
×
961
      analyzeExpressionType(analysis, tagKeyExpression);
×
962
      outputExpressions.add(new Pair<>(tagKeyExpression, null));
×
963
    }
×
964
    for (Expression outputExpression : outputExpressionToRawExpressionsMap.keySet()) {
×
965
      // TODO: support alias
966
      analyzeExpressionType(analysis, outputExpression);
×
967
      outputExpressions.add(new Pair<>(outputExpression, null));
×
968
    }
×
969
    analysis.setTagKeys(queryStatement.getGroupByTagComponent().getTagKeys());
×
970
    analysis.setTagValuesToGroupedTimeseriesOperands(tagValuesToGroupedTimeseriesOperands);
×
971
    analysis.setCrossGroupByExpressions(outputExpressionToRawExpressionsMap);
×
972
  }
×
973

974
  private void analyzeDeviceToAggregation(Analysis analysis, QueryStatement queryStatement) {
975
    if (!queryStatement.isAggregationQuery()) {
1✔
976
      return;
1✔
977
    }
978

979
    updateDeviceToAggregationAndOutputExpressions(
1✔
980
        analysis, analysis.getDeviceToSelectExpressions());
1✔
981
    if (queryStatement.hasOrderByExpression()) {
1✔
982
      updateDeviceToAggregationAndOutputExpressions(
1✔
983
          analysis, analysis.getDeviceToOrderByExpressions());
1✔
984
    }
985
  }
1✔
986

987
  private void updateDeviceToAggregationAndOutputExpressions(
988
      Analysis analysis, Map<String, Set<Expression>> deviceToExpressions) {
989
    // two maps to be updated
990
    Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
991
        analysis.getDeviceToAggregationExpressions();
1✔
992
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
993
        analysis.getDeviceToOutputExpressions();
1✔
994

995
    for (Map.Entry<String, Set<Expression>> deviceExpressionsEntry :
996
        deviceToExpressions.entrySet()) {
1✔
997
      String deviceName = deviceExpressionsEntry.getKey();
1✔
998
      Set<Expression> expressionSet = deviceExpressionsEntry.getValue();
1✔
999

1000
      Set<Expression> aggregationExpressions = new LinkedHashSet<>();
1✔
1001
      Set<Expression> normalizedAggregationExpressions = new LinkedHashSet<>();
1✔
1002
      for (Expression expression : expressionSet) {
1✔
1003
        for (Expression aggregationExpression :
1004
            ExpressionAnalyzer.searchAggregationExpressions(expression)) {
1✔
1005
          Expression normalizedAggregationExpression =
1✔
1006
              ExpressionAnalyzer.normalizeExpression(aggregationExpression);
1✔
1007
          analyzeExpressionType(analysis, normalizedAggregationExpression);
1✔
1008

1009
          aggregationExpressions.add(aggregationExpression);
1✔
1010
          normalizedAggregationExpressions.add(normalizedAggregationExpression);
1✔
1011
        }
1✔
1012
      }
1✔
1013
      deviceToOutputExpressions
1✔
1014
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1015
          .addAll(aggregationExpressions);
1✔
1016
      deviceToAggregationExpressions
1✔
1017
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1018
          .addAll(normalizedAggregationExpressions);
1✔
1019
    }
1✔
1020
  }
1✔
1021

1022
  private void analyzeAggregation(Analysis analysis, QueryStatement queryStatement) {
1023
    if (!queryStatement.isAggregationQuery()) {
1✔
1024
      return;
1✔
1025
    }
1026

1027
    if (queryStatement.isGroupByLevel() || queryStatement.isGroupByTag()) {
1✔
1028
      Set<Expression> aggregationExpressions =
×
1029
          analysis.getCrossGroupByExpressions().values().stream()
×
1030
              .flatMap(Set::stream)
×
1031
              .collect(Collectors.toSet());
×
1032
      analysis.setAggregationExpressions(aggregationExpressions);
×
1033
    } else {
×
1034
      Set<Expression> aggregationExpressions = new HashSet<>();
1✔
1035
      for (Expression expression : analysis.getSelectExpressions()) {
1✔
1036
        aggregationExpressions.addAll(ExpressionAnalyzer.searchAggregationExpressions(expression));
1✔
1037
      }
1✔
1038
      if (queryStatement.hasHaving()) {
1✔
1039
        aggregationExpressions.addAll(
1✔
1040
            ExpressionAnalyzer.searchAggregationExpressions(analysis.getHavingExpression()));
1✔
1041
      }
1042
      if (queryStatement.hasOrderByExpression()) {
1✔
1043
        for (Expression expression : analysis.getOrderByExpressions()) {
1✔
1044
          aggregationExpressions.addAll(
1✔
1045
              ExpressionAnalyzer.searchAggregationExpressions(expression));
1✔
1046
        }
1✔
1047
      }
1048
      analysis.setAggregationExpressions(aggregationExpressions);
1✔
1049
    }
1050
  }
1✔
1051

1052
  private void analyzeDeviceToSourceTransform(Analysis analysis, QueryStatement queryStatement) {
1053
    if (queryStatement.isAggregationQuery()) {
1✔
1054
      Map<String, Set<Expression>> deviceToSourceTransformExpressions = new HashMap<>();
1✔
1055

1056
      Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
1057
          analysis.getDeviceToAggregationExpressions();
1✔
1058
      for (Map.Entry<String, Set<Expression>> deviceAggregationExpressionsEntry :
1059
          deviceToAggregationExpressions.entrySet()) {
1✔
1060
        String deviceName = deviceAggregationExpressionsEntry.getKey();
1✔
1061
        Set<Expression> aggregationExpressions = deviceAggregationExpressionsEntry.getValue();
1✔
1062

1063
        Set<Expression> sourceTransformExpressions = new LinkedHashSet<>();
1✔
1064
        for (Expression expression : aggregationExpressions) {
1✔
1065
          // We just process first input Expression of AggregationFunction,
1066
          // keep other input Expressions as origin
1067
          // If AggregationFunction need more than one input series,
1068
          // we need to reconsider the process of it
1069
          sourceTransformExpressions.add(expression.getExpressions().get(0));
1✔
1070
        }
1✔
1071
        if (queryStatement.hasGroupByExpression()) {
1✔
1072
          sourceTransformExpressions.add(analysis.getDeviceToGroupByExpression().get(deviceName));
×
1073
        }
1074
        deviceToSourceTransformExpressions.put(deviceName, sourceTransformExpressions);
1✔
1075
      }
1✔
1076
      analysis.setDeviceToSourceTransformExpressions(deviceToSourceTransformExpressions);
1✔
1077
    } else {
1✔
1078
      updateDeviceToSourceTransformAndOutputExpressions(
1✔
1079
          analysis, analysis.getDeviceToSelectExpressions());
1✔
1080
      if (queryStatement.hasOrderByExpression()) {
1✔
1081
        updateDeviceToSourceTransformAndOutputExpressions(
1✔
1082
            analysis, analysis.getDeviceToOrderByExpressions());
1✔
1083
      }
1084
    }
1085
  }
1✔
1086

1087
  private void updateDeviceToSourceTransformAndOutputExpressions(
1088
      Analysis analysis, Map<String, Set<Expression>> deviceToExpressions) {
1089
    // two maps to be updated
1090
    Map<String, Set<Expression>> deviceToSourceTransformExpressions =
1✔
1091
        analysis.getDeviceToSourceTransformExpressions();
1✔
1092
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
1093
        analysis.getDeviceToOutputExpressions();
1✔
1094

1095
    for (Map.Entry<String, Set<Expression>> deviceExpressionsEntry :
1096
        deviceToExpressions.entrySet()) {
1✔
1097
      String deviceName = deviceExpressionsEntry.getKey();
1✔
1098
      Set<Expression> expressions = deviceExpressionsEntry.getValue();
1✔
1099

1100
      Set<Expression> normalizedExpressions = new LinkedHashSet<>();
1✔
1101
      for (Expression expression : expressions) {
1✔
1102
        Expression normalizedExpression = ExpressionAnalyzer.normalizeExpression(expression);
1✔
1103
        analyzeExpressionType(analysis, normalizedExpression);
1✔
1104

1105
        normalizedExpressions.add(normalizedExpression);
1✔
1106
      }
1✔
1107
      deviceToOutputExpressions
1✔
1108
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1109
          .addAll(expressions);
1✔
1110
      deviceToSourceTransformExpressions
1✔
1111
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1112
          .addAll(normalizedExpressions);
1✔
1113
    }
1✔
1114
  }
1✔
1115

1116
  private void analyzeSourceTransform(Analysis analysis, QueryStatement queryStatement) {
1117
    Set<Expression> sourceTransformExpressions = new HashSet<>();
1✔
1118
    if (queryStatement.isAggregationQuery()) {
1✔
1119
      for (Expression expression : analysis.getAggregationExpressions()) {
1✔
1120
        // for AggregationExpression, only the first Expression of input need to transform
1121
        sourceTransformExpressions.add(expression.getExpressions().get(0));
1✔
1122
      }
1✔
1123
      if (queryStatement.hasGroupByExpression()) {
1✔
1124
        sourceTransformExpressions.add(analysis.getGroupByExpression());
×
1125
      }
1126
    } else {
1127
      sourceTransformExpressions.addAll(analysis.getSelectExpressions());
1✔
1128
      if (queryStatement.hasOrderByExpression()) {
1✔
1129
        sourceTransformExpressions.addAll(analysis.getOrderByExpressions());
1✔
1130
      }
1131
    }
1132
    analysis.setSourceTransformExpressions(sourceTransformExpressions);
1✔
1133
  }
1✔
1134

1135
  private void analyzeDeviceToSource(Analysis analysis, QueryStatement queryStatement) {
1136
    Map<String, Set<Expression>> deviceToSourceExpressions = new HashMap<>();
1✔
1137
    Map<String, Set<Expression>> deviceToSourceTransformExpressions =
1✔
1138
        analysis.getDeviceToSourceTransformExpressions();
1✔
1139
    for (Map.Entry<String, Set<Expression>> deviceSourceTransformExpressionsEntry :
1140
        deviceToSourceTransformExpressions.entrySet()) {
1✔
1141
      String deviceName = deviceSourceTransformExpressionsEntry.getKey();
1✔
1142
      Set<Expression> sourceTransformExpressions = deviceSourceTransformExpressionsEntry.getValue();
1✔
1143

1144
      Set<Expression> sourceExpressions = new LinkedHashSet<>();
1✔
1145
      for (Expression expression : sourceTransformExpressions) {
1✔
1146
        sourceExpressions.addAll(ExpressionAnalyzer.searchSourceExpressions(expression));
1✔
1147
      }
1✔
1148
      deviceToSourceExpressions.put(deviceName, sourceExpressions);
1✔
1149
    }
1✔
1150
    if (queryStatement.hasWhere()) {
1✔
1151
      Map<String, Expression> deviceToWhereExpression = analysis.getDeviceToWhereExpression();
1✔
1152
      for (Map.Entry<String, Expression> deviceWhereExpressionEntry :
1153
          deviceToWhereExpression.entrySet()) {
1✔
1154
        String deviceName = deviceWhereExpressionEntry.getKey();
1✔
1155
        Expression whereExpression = deviceWhereExpressionEntry.getValue();
1✔
1156
        deviceToSourceExpressions
1✔
1157
            .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1158
            .addAll(ExpressionAnalyzer.searchSourceExpressions(whereExpression));
1✔
1159
      }
1✔
1160
    }
1161

1162
    Map<String, List<String>> outputDeviceToQueriedDevicesMap = new LinkedHashMap<>();
1✔
1163
    for (Map.Entry<String, Set<Expression>> deviceSourceExpressionsEntry :
1164
        deviceToSourceExpressions.entrySet()) {
1✔
1165
      Set<Expression> sourceExpressionsUnderDevice = deviceSourceExpressionsEntry.getValue();
1✔
1166
      Set<String> queriedDevices = new HashSet<>();
1✔
1167
      for (Expression expression : sourceExpressionsUnderDevice) {
1✔
1168
        queriedDevices.add(ExpressionAnalyzer.getDeviceNameInSourceExpression(expression));
1✔
1169
      }
1✔
1170
      if (queriedDevices.size() > 1) {
1✔
1171
        throw new SemanticException(
×
1172
            "Cross-device queries are not supported in ALIGN BY DEVICE queries.");
1173
      }
1174
      outputDeviceToQueriedDevicesMap.put(
1✔
1175
          deviceSourceExpressionsEntry.getKey(), new ArrayList<>(queriedDevices));
1✔
1176
    }
1✔
1177

1178
    analysis.setDeviceToSourceExpressions(deviceToSourceExpressions);
1✔
1179
    analysis.setOutputDeviceToQueriedDevicesMap(outputDeviceToQueriedDevicesMap);
1✔
1180
  }
1✔
1181

1182
  private void analyzeSource(Analysis analysis, QueryStatement queryStatement) {
1183
    Set<Expression> sourceExpressions = new HashSet<>();
1✔
1184
    for (Expression expression : analysis.getSourceTransformExpressions()) {
1✔
1185
      sourceExpressions.addAll(ExpressionAnalyzer.searchSourceExpressions(expression));
1✔
1186
    }
1✔
1187
    if (queryStatement.hasWhere()) {
1✔
1188
      sourceExpressions.addAll(
1✔
1189
          ExpressionAnalyzer.searchSourceExpressions(analysis.getWhereExpression()));
1✔
1190
    }
1191
    analysis.setSourceExpressions(sourceExpressions);
1✔
1192
  }
1✔
1193

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

1197
  private void analyzeDeviceToWhere(
1198
      Analysis analysis,
1199
      QueryStatement queryStatement,
1200
      ISchemaTree schemaTree,
1201
      List<PartialPath> deviceSet) {
1202
    if (!queryStatement.hasWhere()) {
1✔
1203
      return;
1✔
1204
    }
1205

1206
    Map<String, Expression> deviceToWhereExpression = new HashMap<>();
1✔
1207
    Iterator<PartialPath> deviceIterator = deviceSet.iterator();
1✔
1208
    while (deviceIterator.hasNext()) {
1✔
1209
      PartialPath devicePath = deviceIterator.next();
1✔
1210
      Expression whereExpression;
1211
      try {
1212
        whereExpression =
1✔
1213
            ExpressionAnalyzer.normalizeExpression(
1✔
1214
                analyzeWhereSplitByDevice(queryStatement, devicePath, schemaTree));
1✔
1215
      } catch (MeasurementNotExistException e) {
×
1216
        logger.warn(
×
1217
            "Meets MeasurementNotExistException in analyzeDeviceToWhere when executing align by device, "
1218
                + "error msg: {}",
1219
            e.getMessage());
×
1220
        deviceIterator.remove();
×
1221
        continue;
×
1222
      }
1✔
1223

1224
      TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
1✔
1225
      if (outputType != TSDataType.BOOLEAN) {
1✔
1226
        throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
1227
      }
1228

1229
      deviceToWhereExpression.put(devicePath.getFullPath(), whereExpression);
1✔
1230
    }
1✔
1231
    analysis.setDeviceToWhereExpression(deviceToWhereExpression);
1✔
1232
  }
1✔
1233

1234
  private void analyzeWhere(
1235
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1236
    if (!queryStatement.hasWhere()) {
1✔
1237
      return;
1✔
1238
    }
1239
    List<Expression> conJunctions =
1✔
1240
        ExpressionAnalyzer.bindSchemaForPredicate(
1✔
1241
            queryStatement.getWhereCondition().getPredicate(),
1✔
1242
            queryStatement.getFromComponent().getPrefixPaths(),
1✔
1243
            schemaTree,
1244
            true);
1245
    Expression whereExpression =
1✔
1246
        ExpressionUtils.constructQueryFilter(
1✔
1247
            conJunctions.stream().distinct().collect(Collectors.toList()));
1✔
1248
    whereExpression = ExpressionAnalyzer.normalizeExpression(whereExpression);
1✔
1249
    TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
1✔
1250
    if (outputType != TSDataType.BOOLEAN) {
1✔
1251
      throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
1252
    }
1253
    analysis.setWhereExpression(whereExpression);
1✔
1254
  }
1✔
1255

1256
  private Expression analyzeWhereSplitByDevice(
1257
      QueryStatement queryStatement, PartialPath devicePath, ISchemaTree schemaTree) {
1258
    List<Expression> conJunctions =
1✔
1259
        ExpressionAnalyzer.concatDeviceAndBindSchemaForPredicate(
1✔
1260
            queryStatement.getWhereCondition().getPredicate(), devicePath, schemaTree, true);
1✔
1261
    return ExpressionUtils.constructQueryFilter(
1✔
1262
        conJunctions.stream().distinct().collect(Collectors.toList()));
1✔
1263
  }
1264

1265
  private void analyzeDeviceViewOutput(Analysis analysis, QueryStatement queryStatement) {
1266
    Set<Expression> selectExpressions = analysis.getSelectExpressions();
1✔
1267
    Set<Expression> deviceViewOutputExpressions = new LinkedHashSet<>();
1✔
1268
    if (queryStatement.isAggregationQuery()) {
1✔
1269
      deviceViewOutputExpressions.add(deviceExpression);
1✔
1270
      if (queryStatement.isOutputEndTime()) {
1✔
1271
        deviceViewOutputExpressions.add(endTimeExpression);
×
1272
      }
1273
      for (Expression selectExpression : selectExpressions) {
1✔
1274
        deviceViewOutputExpressions.addAll(
1✔
1275
            ExpressionAnalyzer.searchAggregationExpressions(selectExpression));
1✔
1276
      }
1✔
1277
      if (queryStatement.hasHaving()) {
1✔
1278
        deviceViewOutputExpressions.addAll(
1✔
1279
            ExpressionAnalyzer.searchAggregationExpressions(analysis.getHavingExpression()));
1✔
1280
      }
1281
      if (queryStatement.hasOrderByExpression()) {
1✔
1282
        for (Expression orderByExpression : analysis.getOrderByExpressions()) {
1✔
1283
          deviceViewOutputExpressions.addAll(
1✔
1284
              ExpressionAnalyzer.searchAggregationExpressions(orderByExpression));
1✔
1285
        }
1✔
1286
      }
1287
    } else {
1288
      deviceViewOutputExpressions.addAll(selectExpressions);
1✔
1289
      if (queryStatement.hasOrderByExpression()) {
1✔
1290
        deviceViewOutputExpressions.addAll(analysis.getOrderByExpressions());
1✔
1291
      }
1292
    }
1293
    analysis.setDeviceViewOutputExpressions(deviceViewOutputExpressions);
1✔
1294
    analysis.setDeviceViewSpecialProcess(
1✔
1295
        analyzeDeviceViewSpecialProcess(deviceViewOutputExpressions, queryStatement, analysis));
1✔
1296
  }
1✔
1297

1298
  private boolean analyzeDeviceViewSpecialProcess(
1299
      Set<Expression> deviceViewOutputExpressions,
1300
      QueryStatement queryStatement,
1301
      Analysis analysis) {
1302
    if (queryStatement.isAggregationQuery()
1✔
1303
        || queryStatement.hasWhere()
1✔
1304
            && ExpressionAnalyzer.isDeviceViewNeedSpecialProcess(
1✔
1305
                queryStatement.getWhereCondition().getPredicate(), analysis)) {
1✔
1306
      return true;
1✔
1307
    }
1308
    for (Expression expression : deviceViewOutputExpressions) {
1✔
1309
      if (ExpressionAnalyzer.isDeviceViewNeedSpecialProcess(expression, analysis)) {
1✔
1310
        return true;
1✔
1311
      }
1312
    }
1✔
1313
    return false;
1✔
1314
  }
1315

1316
  private void analyzeDeviceViewInput(Analysis analysis, QueryStatement queryStatement) {
1317
    List<String> deviceViewOutputColumns =
1✔
1318
        analysis.getDeviceViewOutputExpressions().stream()
1✔
1319
            .map(Expression::getOutputSymbol)
1✔
1320
            .collect(Collectors.toList());
1✔
1321

1322
    Map<String, Set<String>> deviceToOutputColumnsMap = new LinkedHashMap<>();
1✔
1323
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
1324
        analysis.getDeviceToOutputExpressions();
1✔
1325
    for (Map.Entry<String, Set<Expression>> deviceOutputExpressionEntry :
1326
        deviceToOutputExpressions.entrySet()) {
1✔
1327
      Set<Expression> outputExpressionsUnderDevice = deviceOutputExpressionEntry.getValue();
1✔
1328
      checkDeviceViewInputUniqueness(outputExpressionsUnderDevice);
1✔
1329

1330
      Set<String> outputColumns = new LinkedHashSet<>();
1✔
1331
      if (queryStatement.isOutputEndTime()) {
1✔
1332
        outputColumns.add(ENDTIME);
×
1333
      }
1334
      for (Expression expression : outputExpressionsUnderDevice) {
1✔
1335
        outputColumns.add(
1✔
1336
            ExpressionAnalyzer.getMeasurementExpression(expression, analysis).getOutputSymbol());
1✔
1337
      }
1✔
1338
      deviceToOutputColumnsMap.put(deviceOutputExpressionEntry.getKey(), outputColumns);
1✔
1339
    }
1✔
1340

1341
    Map<String, List<Integer>> deviceViewInputIndexesMap = new HashMap<>();
1✔
1342
    for (Map.Entry<String, Set<String>> deviceOutputColumnsEntry :
1343
        deviceToOutputColumnsMap.entrySet()) {
1✔
1344
      String deviceName = deviceOutputColumnsEntry.getKey();
1✔
1345
      List<String> outputsUnderDevice = new ArrayList<>(deviceOutputColumnsEntry.getValue());
1✔
1346

1347
      List<Integer> indexes = new ArrayList<>();
1✔
1348
      for (String output : outputsUnderDevice) {
1✔
1349
        int index = deviceViewOutputColumns.indexOf(output);
1✔
1350
        checkState(
1✔
1351
            index >= 1, "output column '%s' is not stored in %s", output, deviceViewOutputColumns);
1352
        indexes.add(index);
1✔
1353
      }
1✔
1354
      deviceViewInputIndexesMap.put(deviceName, indexes);
1✔
1355
    }
1✔
1356
    analysis.setDeviceViewInputIndexesMap(deviceViewInputIndexesMap);
1✔
1357
  }
1✔
1358

1359
  private void checkDeviceViewInputUniqueness(Set<Expression> outputExpressionsUnderDevice) {
1360
    Set<Expression> normalizedOutputExpressionsUnderDevice =
1✔
1361
        outputExpressionsUnderDevice.stream()
1✔
1362
            .map(ExpressionAnalyzer::normalizeExpression)
1✔
1363
            .collect(Collectors.toSet());
1✔
1364
    if (normalizedOutputExpressionsUnderDevice.size() < outputExpressionsUnderDevice.size()) {
1✔
1365
      throw new SemanticException(
×
1366
          "Views or measurement aliases representing the same data source "
1367
              + "cannot be queried concurrently in ALIGN BY DEVICE queries.");
1368
    }
1369
  }
1✔
1370

1371
  private void analyzeOutput(
1372
      Analysis analysis,
1373
      QueryStatement queryStatement,
1374
      List<Pair<Expression, String>> outputExpressions) {
1375
    if (queryStatement.isSelectInto()) {
1✔
1376
      analysis.setRespDatasetHeader(
1✔
1377
          DatasetHeaderFactory.getSelectIntoHeader(queryStatement.isAlignByDevice()));
1✔
1378
      return;
1✔
1379
    }
1380

1381
    boolean isIgnoreTimestamp = queryStatement.isAggregationQuery() && !queryStatement.isGroupBy();
1✔
1382
    List<ColumnHeader> columnHeaders = new ArrayList<>();
1✔
1383
    if (queryStatement.isAlignByDevice()) {
1✔
1384
      columnHeaders.add(new ColumnHeader(DEVICE, TSDataType.TEXT, null));
1✔
1385
    }
1386
    if (queryStatement.isOutputEndTime()) {
1✔
1387
      columnHeaders.add(new ColumnHeader(ENDTIME, TSDataType.INT64, null));
×
1388
    }
1389
    for (Pair<Expression, String> expressionAliasPair : outputExpressions) {
1✔
1390
      columnHeaders.add(
1✔
1391
          new ColumnHeader(
1392
              expressionAliasPair.left.getExpressionString(),
1✔
1393
              analysis.getType(expressionAliasPair.left),
1✔
1394
              expressionAliasPair.right));
1395
    }
1✔
1396
    analysis.setRespDatasetHeader(new DatasetHeader(columnHeaders, isIgnoreTimestamp));
1✔
1397
  }
1✔
1398

1399
  // For last query
1400
  private void analyzeLastOrderBy(Analysis analysis, QueryStatement queryStatement) {
1401
    if (!queryStatement.hasOrderBy()) return;
×
1402

1403
    if (queryStatement.onlyOrderByTimeseries()) {
×
1404
      analysis.setTimeseriesOrderingForLastQuery(
×
1405
          queryStatement.getOrderByComponent().getTimeseriesOrder());
×
1406
    }
1407

1408
    for (SortItem sortItem : queryStatement.getSortItemList()) {
×
1409
      String sortKey = sortItem.getSortKey();
×
1410
      if (!lastQueryColumnNames.contains(sortKey.toUpperCase())) {
×
1411
        throw new SemanticException(
×
1412
            String.format(
×
1413
                "%s in order by clause doesn't exist in the result of last query.", sortKey));
1414
      }
1415
    }
×
1416
  }
×
1417

1418
  private void analyzeOrderBy(
1419
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1420
    if (!queryStatement.hasOrderByExpression()) return;
1✔
1421

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

1450
  private TSDataType analyzeExpressionType(Analysis analysis, Expression expression) {
1451
    return ExpressionTypeAnalyzer.analyzeExpression(analysis, expression);
1✔
1452
  }
1453

1454
  private void analyzeDeviceToGroupBy(
1455
      Analysis analysis,
1456
      QueryStatement queryStatement,
1457
      ISchemaTree schemaTree,
1458
      List<PartialPath> deviceSet) {
1459
    if (queryStatement.getGroupByComponent() == null) {
1✔
1460
      return;
1✔
1461
    }
1462
    GroupByComponent groupByComponent = queryStatement.getGroupByComponent();
×
1463
    WindowType windowType = groupByComponent.getWindowType();
×
1464

1465
    Map<String, Expression> deviceToGroupByExpression = new LinkedHashMap<>();
×
1466
    if (queryStatement.hasGroupByExpression()) {
×
1467
      Expression expression = groupByComponent.getControlColumnExpression();
×
1468
      for (PartialPath device : deviceSet) {
×
1469
        List<Expression> groupByExpressionsOfOneDevice =
×
1470
            ExpressionAnalyzer.concatDeviceAndBindSchemaForExpression(
×
1471
                expression, device, schemaTree);
1472

1473
        if (groupByExpressionsOfOneDevice.isEmpty()) {
×
1474
          throw new SemanticException(
×
1475
              String.format("%s in group by clause doesn't exist.", expression));
×
1476
        }
1477
        if (groupByExpressionsOfOneDevice.size() > 1) {
×
1478
          throw new SemanticException(
×
1479
              String.format(
×
1480
                  "%s in group by clause shouldn't refer to more than one timeseries.",
1481
                  expression));
1482
        }
1483
        deviceToGroupByExpression.put(
×
1484
            device.getFullPath(),
×
1485
            ExpressionAnalyzer.normalizeExpression(groupByExpressionsOfOneDevice.get(0)));
×
1486
      }
×
1487
    }
1488

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

1527
  private void analyzeDeviceToOrderBy(
1528
      Analysis analysis,
1529
      QueryStatement queryStatement,
1530
      ISchemaTree schemaTree,
1531
      List<PartialPath> deviceSet) {
1532
    if (!queryStatement.hasOrderByExpression()) {
1✔
1533
      return;
1✔
1534
    }
1535

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

1564
        Expression deviceViewExpression =
1✔
1565
            ExpressionAnalyzer.getMeasurementExpression(expressionForItem, analysis);
1✔
1566
        analyzeExpressionType(analysis, deviceViewExpression);
1✔
1567

1568
        deviceViewOrderByExpression.add(deviceViewExpression);
1✔
1569
        orderByExpressionsForOneDevice.add(expressionForItem);
1✔
1570
      }
1✔
1571
      deviceToSortItems.put(
1✔
1572
          device.getFullPath(), queryStatement.getUpdatedSortItems(orderByExpressionsForOneDevice));
1✔
1573
      deviceToOrderByExpressions.put(device.getFullPath(), orderByExpressionsForOneDevice);
1✔
1574
    }
1✔
1575

1576
    analysis.setOrderByExpressions(deviceViewOrderByExpression);
1✔
1577
    queryStatement.updateSortItems(deviceViewOrderByExpression);
1✔
1578
    analysis.setDeviceToSortItems(deviceToSortItems);
1✔
1579
    analysis.setDeviceToOrderByExpressions(deviceToOrderByExpressions);
1✔
1580
  }
1✔
1581

1582
  private void analyzeGroupBy(
1583
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1584

1585
    if (queryStatement.getGroupByComponent() == null) {
1✔
1586
      return;
1✔
1587
    }
1588
    GroupByComponent groupByComponent = queryStatement.getGroupByComponent();
×
1589
    WindowType windowType = groupByComponent.getWindowType();
×
1590

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

1617
    if (windowType == WindowType.VARIATION_WINDOW) {
×
1618
      double delta = ((GroupByVariationComponent) groupByComponent).getDelta();
×
1619
      checkGroupByVariationExpressionType(analysis, groupByExpression, delta);
×
1620
      GroupByParameter groupByParameter =
×
1621
          new GroupByVariationParameter(groupByComponent.isIgnoringNull(), delta);
×
1622
      analysis.setGroupByExpression(groupByExpression);
×
1623
      analysis.setGroupByParameter(groupByParameter);
×
1624
    } else if (windowType == WindowType.CONDITION_WINDOW) {
×
1625
      Expression keepExpression =
×
1626
          ((GroupByConditionComponent) groupByComponent).getKeepExpression();
×
1627
      checkGroupByConditionExpressionType(analysis, groupByExpression, keepExpression);
×
1628
      GroupByParameter groupByParameter =
×
1629
          new GroupByConditionParameter(groupByComponent.isIgnoringNull(), keepExpression);
×
1630
      analysis.setGroupByExpression(groupByExpression);
×
1631
      analysis.setGroupByParameter(groupByParameter);
×
1632
    } else if (windowType == WindowType.SESSION_WINDOW) {
×
1633
      long interval = ((GroupBySessionComponent) groupByComponent).getTimeInterval();
×
1634
      GroupByParameter groupByParameter = new GroupBySessionParameter(interval);
×
1635
      analysis.setGroupByParameter(groupByParameter);
×
1636
    } else if (windowType == WindowType.COUNT_WINDOW) {
×
1637
      GroupByParameter groupByParameter =
×
1638
          new GroupByCountParameter(
1639
              ((GroupByCountComponent) groupByComponent).getCountNumber(),
×
1640
              groupByComponent.isIgnoringNull());
×
1641
      analyzeExpressionType(analysis, groupByExpression);
×
1642
      analysis.setGroupByExpression(groupByExpression);
×
1643
      analysis.setGroupByParameter(groupByParameter);
×
1644
    } else {
×
1645
      throw new SemanticException("Unsupported window type");
×
1646
    }
1647
  }
×
1648

1649
  private void checkGroupByVariationExpressionType(
1650
      Analysis analysis, Expression groupByExpression, double delta) {
1651
    TSDataType type = analyzeExpressionType(analysis, groupByExpression);
×
1652
    if (delta != 0 && !type.isNumeric()) {
×
1653
      throw new SemanticException("Only support numeric type when delta != 0");
×
1654
    }
1655
  }
×
1656

1657
  private void checkGroupByConditionExpressionType(
1658
      Analysis analysis, Expression groupByExpression, Expression keepExpression) {
1659
    TSDataType type = analyzeExpressionType(analysis, groupByExpression);
×
1660
    if (type != TSDataType.BOOLEAN) {
×
1661
      throw new SemanticException("Only support boolean type in predict of group by series");
×
1662
    }
1663

1664
    // check keep Expression
1665
    if (keepExpression instanceof CompareBinaryExpression) {
×
1666
      Expression leftExpression = ((CompareBinaryExpression) keepExpression).getLeftExpression();
×
1667
      Expression rightExpression = ((CompareBinaryExpression) keepExpression).getRightExpression();
×
1668
      if (!(leftExpression instanceof TimeSeriesOperand
×
1669
          && leftExpression.getExpressionString().equalsIgnoreCase("keep")
×
1670
          && rightExpression instanceof ConstantOperand)) {
1671
        throw new SemanticException(
×
1672
            String.format(
×
1673
                "Please check the keep condition ([%s]),it need to be a constant or a compare expression constructed by 'keep' and a long number.",
1674
                keepExpression.getExpressionString()));
×
1675
      }
1676
      return;
×
1677
    }
1678
    if (!(keepExpression instanceof ConstantOperand)) {
×
1679
      throw new SemanticException(
×
1680
          String.format(
×
1681
              "Please check the keep condition ([%s]),it need to be a constant or a compare expression constructed by 'keep' and a long number.",
1682
              keepExpression.getExpressionString()));
×
1683
    }
1684
  }
×
1685

1686
  private void analyzeGroupByTime(Analysis analysis, QueryStatement queryStatement) {
1687
    if (!queryStatement.isGroupByTime()) {
1✔
1688
      return;
1✔
1689
    }
1690

1691
    if (queryStatement.isResultSetEmpty()) {
1✔
1692
      analysis.setFinishQueryAfterAnalyze(true);
×
1693
    }
1694

1695
    GroupByTimeComponent groupByTimeComponent = queryStatement.getGroupByTimeComponent();
1✔
1696
    if ((groupByTimeComponent.isIntervalByMonth() || groupByTimeComponent.isSlidingStepByMonth())
1✔
1697
        && queryStatement.getResultTimeOrder() == Ordering.DESC) {
×
1698
      throw new SemanticException("Group by month doesn't support order by time desc now.");
×
1699
    }
1700
    if (!queryStatement.isCqQueryBody()
1✔
1701
        && (groupByTimeComponent.getStartTime() == 0 && groupByTimeComponent.getEndTime() == 0)) {
1✔
1702
      throw new SemanticException(
×
1703
          "The query time range should be specified in the GROUP BY TIME clause.");
1704
    }
1705
    analysis.setGroupByTimeParameter(new GroupByTimeParameter(groupByTimeComponent));
1✔
1706

1707
    Filter globalTimeFilter = analysis.getGlobalTimeFilter();
1✔
1708
    Filter groupByFilter = initGroupByFilter(groupByTimeComponent);
1✔
1709
    if (globalTimeFilter == null) {
1✔
1710
      globalTimeFilter = groupByFilter;
1✔
1711
    } else {
1712
      globalTimeFilter = FilterFactory.and(globalTimeFilter, groupByFilter);
1✔
1713
    }
1714
    analysis.setGlobalTimeFilter(globalTimeFilter);
1✔
1715
  }
1✔
1716

1717
  private void analyzeFill(Analysis analysis, QueryStatement queryStatement) {
1718
    if (queryStatement.getFillComponent() == null) {
1✔
1719
      return;
1✔
1720
    }
1721

1722
    FillComponent fillComponent = queryStatement.getFillComponent();
1✔
1723
    analysis.setFillDescriptor(
1✔
1724
        new FillDescriptor(fillComponent.getFillPolicy(), fillComponent.getFillValue()));
1✔
1725
  }
1✔
1726

1727
  private void analyzeDataPartition(
1728
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1729
    Set<String> deviceSet = new HashSet<>();
1✔
1730
    if (queryStatement.isAlignByDevice()) {
1✔
1731
      deviceSet =
1✔
1732
          analysis.getOutputDeviceToQueriedDevicesMap().values().stream()
1✔
1733
              .flatMap(List::stream)
1✔
1734
              .collect(Collectors.toSet());
1✔
1735
    } else {
1736
      for (Expression expression : analysis.getSourceExpressions()) {
1✔
1737
        deviceSet.add(ExpressionAnalyzer.getDeviceNameInSourceExpression(expression));
1✔
1738
      }
1✔
1739
    }
1740
    DataPartition dataPartition =
1✔
1741
        fetchDataPartitionByDevices(deviceSet, schemaTree, analysis.getGlobalTimeFilter());
1✔
1742
    analysis.setDataPartitionInfo(dataPartition);
1✔
1743
  }
1✔
1744

1745
  private DataPartition fetchDataPartitionByDevices(
1746
      Set<String> deviceSet, ISchemaTree schemaTree, Filter globalTimeFilter) {
1747
    long startTime = System.nanoTime();
1✔
1748
    try {
1749
      Pair<List<TTimePartitionSlot>, Pair<Boolean, Boolean>> res =
1✔
1750
          getTimePartitionSlotList(globalTimeFilter);
1✔
1751
      // there is no satisfied time range
1752
      if (res.left.isEmpty() && Boolean.FALSE.equals(res.right.left)) {
1✔
1753
        return new DataPartition(
1✔
1754
            Collections.emptyMap(),
1✔
1755
            CONFIG.getSeriesPartitionExecutorClass(),
1✔
1756
            CONFIG.getSeriesPartitionSlotNum());
1✔
1757
      }
1758
      Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap = new HashMap<>();
1✔
1759
      for (String devicePath : deviceSet) {
1✔
1760
        DataPartitionQueryParam queryParam =
1✔
1761
            new DataPartitionQueryParam(devicePath, res.left, res.right.left, res.right.right);
1✔
1762
        sgNameToQueryParamsMap
1✔
1763
            .computeIfAbsent(schemaTree.getBelongedDatabase(devicePath), key -> new ArrayList<>())
1✔
1764
            .add(queryParam);
1✔
1765
      }
1✔
1766

1767
      if (res.right.left || res.right.right) {
1✔
1768
        return partitionFetcher.getDataPartitionWithUnclosedTimeRange(sgNameToQueryParamsMap);
1✔
1769
      } else {
1770
        return partitionFetcher.getDataPartition(sgNameToQueryParamsMap);
1✔
1771
      }
1772
    } finally {
1773
      QueryPlanCostMetricSet.getInstance()
1✔
1774
          .recordPlanCost(PARTITION_FETCHER, System.nanoTime() - startTime);
1✔
1775
    }
1776
  }
1777

1778
  /**
1779
   * get TTimePartitionSlot list about this time filter
1780
   *
1781
   * @return List<TTimePartitionSlot>, if contains (-oo, XXX] time range, res.right.left = true; if
1782
   *     contains [XX, +oo), res.right.right = true
1783
   */
1784
  @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning
1785
  public static Pair<List<TTimePartitionSlot>, Pair<Boolean, Boolean>> getTimePartitionSlotList(
1786
      Filter timeFilter) {
1787
    if (timeFilter == null) {
1✔
1788
      // (-oo, +oo)
1789
      return new Pair<>(Collections.emptyList(), new Pair<>(true, true));
1✔
1790
    }
1791
    List<TimeRange> timeRangeList = timeFilter.getTimeRanges();
1✔
1792
    if (timeRangeList.isEmpty()) {
1✔
1793
      // no satisfied time range
1794
      return new Pair<>(Collections.emptyList(), new Pair<>(false, false));
1✔
1795
    } else if (timeRangeList.size() == 1
1✔
1796
        && (timeRangeList.get(0).getMin() == Long.MIN_VALUE
1✔
1797
            && timeRangeList.get(timeRangeList.size() - 1).getMax() == Long.MAX_VALUE)) {
1✔
1798
      // (-oo, +oo)
1799
      return new Pair<>(Collections.emptyList(), new Pair<>(true, true));
1✔
1800
    }
1801

1802
    boolean needLeftAll;
1803
    boolean needRightAll;
1804
    long startTime;
1805
    long endTime;
1806
    TTimePartitionSlot timePartitionSlot;
1807
    int index = 0;
1✔
1808
    int size = timeRangeList.size();
1✔
1809

1810
    if (timeRangeList.get(0).getMin() == Long.MIN_VALUE) {
1✔
1811
      needLeftAll = true;
1✔
1812
      startTime =
1✔
1813
          (timeRangeList.get(0).getMax() / TimePartitionUtils.timePartitionInterval)
1✔
1814
              * TimePartitionUtils.timePartitionInterval; // included
1815
      endTime = startTime + TimePartitionUtils.timePartitionInterval; // excluded
1✔
1816
      timePartitionSlot = TimePartitionUtils.getTimePartition(timeRangeList.get(0).getMax());
1✔
1817
    } else {
1818
      startTime =
1✔
1819
          (timeRangeList.get(0).getMin() / TimePartitionUtils.timePartitionInterval)
1✔
1820
              * TimePartitionUtils.timePartitionInterval; // included
1821
      endTime = startTime + TimePartitionUtils.timePartitionInterval; // excluded
1✔
1822
      timePartitionSlot = TimePartitionUtils.getTimePartition(timeRangeList.get(0).getMin());
1✔
1823
      needLeftAll = false;
1✔
1824
    }
1825

1826
    if (timeRangeList.get(size - 1).getMax() == Long.MAX_VALUE) {
1✔
1827
      needRightAll = true;
1✔
1828
      size--;
1✔
1829
    } else {
1830
      needRightAll = false;
1✔
1831
    }
1832

1833
    List<TTimePartitionSlot> result = new ArrayList<>();
1✔
1834
    while (index < size) {
1✔
1835
      long curLeft = timeRangeList.get(index).getMin();
1✔
1836
      long curRight = timeRangeList.get(index).getMax();
1✔
1837
      if (curLeft >= endTime) {
1✔
1838
        result.add(timePartitionSlot);
1✔
1839
        // next init
1840
        endTime =
1✔
1841
            (curLeft / TimePartitionUtils.timePartitionInterval + 1)
1842
                * TimePartitionUtils.timePartitionInterval;
1843
        timePartitionSlot = TimePartitionUtils.getTimePartition(curLeft);
1✔
1844
      } else if (curRight >= endTime) {
1✔
1845
        result.add(timePartitionSlot);
1✔
1846
        // next init
1847
        timePartitionSlot = new TTimePartitionSlot(endTime);
1✔
1848
        endTime = endTime + TimePartitionUtils.timePartitionInterval;
1✔
1849
      } else {
1850
        index++;
1✔
1851
      }
1852
    }
1✔
1853
    result.add(timePartitionSlot);
1✔
1854

1855
    if (needRightAll) {
1✔
1856
      TTimePartitionSlot lastTimePartitionSlot =
1✔
1857
          TimePartitionUtils.getTimePartition(timeRangeList.get(timeRangeList.size() - 1).getMin());
1✔
1858
      if (lastTimePartitionSlot.startTime != timePartitionSlot.startTime) {
1✔
1859
        result.add(lastTimePartitionSlot);
×
1860
      }
1861
    }
1862
    return new Pair<>(result, new Pair<>(needLeftAll, needRightAll));
1✔
1863
  }
1864

1865
  private void analyzeInto(
1866
      Analysis analysis,
1867
      QueryStatement queryStatement,
1868
      List<PartialPath> deviceSet,
1869
      List<Pair<Expression, String>> outputExpressions) {
1870
    if (!queryStatement.isSelectInto()) {
1✔
1871
      return;
1✔
1872
    }
1873
    queryStatement.setOrderByComponent(null);
1✔
1874

1875
    List<PartialPath> sourceDevices = new ArrayList<>(deviceSet);
1✔
1876
    List<Expression> sourceColumns =
1✔
1877
        outputExpressions.stream()
1✔
1878
            .map(Pair::getLeft)
1✔
1879
            .collect(Collectors.toCollection(ArrayList::new));
1✔
1880

1881
    IntoComponent intoComponent = queryStatement.getIntoComponent();
1✔
1882
    intoComponent.validate(sourceDevices, sourceColumns);
1✔
1883

1884
    DeviceViewIntoPathDescriptor deviceViewIntoPathDescriptor = new DeviceViewIntoPathDescriptor();
1✔
1885
    PathPatternTree targetPathTree = new PathPatternTree();
1✔
1886
    IntoComponent.IntoDeviceMeasurementIterator intoDeviceMeasurementIterator =
1✔
1887
        intoComponent.getIntoDeviceMeasurementIterator();
1✔
1888
    for (PartialPath sourceDevice : sourceDevices) {
1✔
1889
      PartialPath deviceTemplate = intoDeviceMeasurementIterator.getDeviceTemplate();
1✔
1890
      boolean isAlignedDevice = intoDeviceMeasurementIterator.isAlignedDevice();
1✔
1891
      PartialPath targetDevice = constructTargetDevice(sourceDevice, deviceTemplate);
1✔
1892
      deviceViewIntoPathDescriptor.specifyDeviceAlignment(targetDevice.toString(), isAlignedDevice);
1✔
1893

1894
      for (Expression sourceColumn : sourceColumns) {
1✔
1895
        String measurementTemplate = intoDeviceMeasurementIterator.getMeasurementTemplate();
1✔
1896
        String targetMeasurement;
1897
        if (sourceColumn instanceof TimeSeriesOperand) {
1✔
1898
          targetMeasurement =
1✔
1899
              constructTargetMeasurement(
1✔
1900
                  sourceDevice.concatNode(sourceColumn.getExpressionString()), measurementTemplate);
1✔
1901
        } else {
1902
          targetMeasurement = measurementTemplate;
1✔
1903
        }
1904
        deviceViewIntoPathDescriptor.specifyTargetDeviceMeasurement(
1✔
1905
            sourceDevice, targetDevice, sourceColumn.getExpressionString(), targetMeasurement);
1✔
1906

1907
        targetPathTree.appendFullPath(targetDevice, targetMeasurement);
1✔
1908
        deviceViewIntoPathDescriptor.recordSourceColumnDataType(
1✔
1909
            sourceColumn.getExpressionString(), analysis.getType(sourceColumn));
1✔
1910

1911
        intoDeviceMeasurementIterator.nextMeasurement();
1✔
1912
      }
1✔
1913

1914
      intoDeviceMeasurementIterator.nextDevice();
1✔
1915
    }
1✔
1916
    deviceViewIntoPathDescriptor.validate();
1✔
1917

1918
    // fetch schema of target paths
1919
    long startTime = System.nanoTime();
1✔
1920
    ISchemaTree targetSchemaTree = schemaFetcher.fetchSchema(targetPathTree, null);
1✔
1921
    QueryPlanCostMetricSet.getInstance()
1✔
1922
        .recordPlanCost(SCHEMA_FETCHER, System.nanoTime() - startTime);
1✔
1923
    deviceViewIntoPathDescriptor.bindType(targetSchemaTree);
1✔
1924

1925
    analysis.setDeviceViewIntoPathDescriptor(deviceViewIntoPathDescriptor);
1✔
1926
  }
1✔
1927

1928
  private void analyzeInto(
1929
      Analysis analysis,
1930
      QueryStatement queryStatement,
1931
      List<Pair<Expression, String>> outputExpressions) {
1932
    if (!queryStatement.isSelectInto()) {
1✔
1933
      return;
1✔
1934
    }
1935
    queryStatement.setOrderByComponent(null);
1✔
1936

1937
    List<Expression> sourceColumns =
1✔
1938
        outputExpressions.stream()
1✔
1939
            .map(Pair::getLeft)
1✔
1940
            .collect(Collectors.toCollection(ArrayList::new));
1✔
1941

1942
    IntoComponent intoComponent = queryStatement.getIntoComponent();
1✔
1943
    intoComponent.validate(sourceColumns);
1✔
1944

1945
    IntoPathDescriptor intoPathDescriptor = new IntoPathDescriptor();
1✔
1946
    PathPatternTree targetPathTree = new PathPatternTree();
1✔
1947
    IntoComponent.IntoPathIterator intoPathIterator = intoComponent.getIntoPathIterator();
1✔
1948
    for (Pair<Expression, String> pair : outputExpressions) {
1✔
1949
      Expression sourceExpression = pair.left;
1✔
1950
      String viewPath = pair.right;
1✔
1951
      PartialPath deviceTemplate = intoPathIterator.getDeviceTemplate();
1✔
1952
      String measurementTemplate = intoPathIterator.getMeasurementTemplate();
1✔
1953
      boolean isAlignedDevice = intoPathIterator.isAlignedDevice();
1✔
1954

1955
      PartialPath sourcePath;
1956
      String sourceColumn = sourceExpression.getExpressionString();
1✔
1957
      PartialPath targetPath;
1958
      if (sourceExpression instanceof TimeSeriesOperand) {
1✔
1959
        if (viewPath != null) {
1✔
1960
          try {
1961
            sourcePath = new PartialPath(viewPath);
×
1962
          } catch (IllegalPathException e) {
×
1963
            throw new SemanticException(
×
1964
                String.format(
×
1965
                    "View path %s of source column %s is illegal path", viewPath, sourceColumn));
1966
          }
×
1967
        } else {
1968
          sourcePath = ((TimeSeriesOperand) sourceExpression).getPath();
1✔
1969
        }
1970
        targetPath = constructTargetPath(sourcePath, deviceTemplate, measurementTemplate);
1✔
1971
      } else {
1972
        targetPath = deviceTemplate.concatNode(measurementTemplate);
1✔
1973
      }
1974
      intoPathDescriptor.specifyTargetPath(sourceColumn, viewPath, targetPath);
1✔
1975
      intoPathDescriptor.specifyDeviceAlignment(
1✔
1976
          targetPath.getDevicePath().toString(), isAlignedDevice);
1✔
1977

1978
      targetPathTree.appendFullPath(targetPath);
1✔
1979
      intoPathDescriptor.recordSourceColumnDataType(
1✔
1980
          sourceColumn, analysis.getType(sourceExpression));
1✔
1981

1982
      intoPathIterator.next();
1✔
1983
    }
1✔
1984
    intoPathDescriptor.validate();
1✔
1985

1986
    // fetch schema of target paths
1987
    long startTime = System.nanoTime();
1✔
1988
    ISchemaTree targetSchemaTree = schemaFetcher.fetchSchema(targetPathTree, null);
1✔
1989
    updateSchemaTreeByViews(analysis, targetSchemaTree);
1✔
1990
    QueryPlanCostMetricSet.getInstance()
1✔
1991
        .recordPlanCost(SCHEMA_FETCHER, System.nanoTime() - startTime);
1✔
1992
    intoPathDescriptor.bindType(targetSchemaTree);
1✔
1993

1994
    analysis.setIntoPathDescriptor(intoPathDescriptor);
1✔
1995
  }
1✔
1996

1997
  /**
1998
   * Check datatype consistency in ALIGN BY DEVICE.
1999
   *
2000
   * <p>an inconsistent example: select s0 from root.sg1.d1, root.sg1.d2 align by device, return
2001
   * false while root.sg1.d1.s0 is INT32 and root.sg1.d2.s0 is FLOAT.
2002
   */
2003
  private void checkDataTypeConsistencyInAlignByDevice(
2004
      Analysis analysis, List<Expression> expressions) {
2005
    TSDataType checkedDataType = analysis.getType(expressions.get(0));
1✔
2006
    for (Expression expression : expressions) {
1✔
2007
      if (analysis.getType(expression) != checkedDataType) {
1✔
2008
        throw new SemanticException(
×
2009
            "ALIGN BY DEVICE: the data types of the same measurement column should be the same across devices.");
2010
      }
2011
    }
1✔
2012
  }
1✔
2013

2014
  private void checkAliasUniqueness(String alias, Set<String> aliasSet) {
2015
    if (alias != null) {
1✔
2016
      if (aliasSet.contains(alias)) {
1✔
2017
        throw new SemanticException(
1✔
2018
            String.format("alias '%s' can only be matched with one time series", alias));
1✔
2019
      }
2020
      aliasSet.add(alias);
1✔
2021
    }
2022
  }
1✔
2023

2024
  private void checkAliasUniqueness(
2025
      String alias, Map<Expression, Map<String, Expression>> measurementToDeviceSelectExpressions) {
2026
    if (alias != null && measurementToDeviceSelectExpressions.keySet().size() > 1) {
1✔
2027
      throw new SemanticException(
×
2028
          String.format("alias '%s' can only be matched with one time series", alias));
×
2029
    }
2030
  }
1✔
2031

2032
  @Override
2033
  public Analysis visitInsert(InsertStatement insertStatement, MPPQueryContext context) {
2034
    context.setQueryType(QueryType.WRITE);
1✔
2035
    insertStatement.semanticCheck();
1✔
2036
    long[] timeArray = insertStatement.getTimes();
1✔
2037
    PartialPath devicePath = insertStatement.getDevice();
1✔
2038
    String[] measurementList = insertStatement.getMeasurementList();
1✔
2039
    if (timeArray.length == 1) {
1✔
2040
      // construct insert row statement
2041
      InsertRowStatement insertRowStatement = new InsertRowStatement();
×
2042
      insertRowStatement.setDevicePath(devicePath);
×
2043
      insertRowStatement.setTime(timeArray[0]);
×
2044
      insertRowStatement.setMeasurements(measurementList);
×
2045
      insertRowStatement.setDataTypes(new TSDataType[measurementList.length]);
×
2046
      Object[] values = new Object[measurementList.length];
×
2047
      System.arraycopy(insertStatement.getValuesList().get(0), 0, values, 0, values.length);
×
2048
      insertRowStatement.setValues(values);
×
2049
      insertRowStatement.setNeedInferType(true);
×
2050
      insertRowStatement.setAligned(insertStatement.isAligned());
×
2051
      return insertRowStatement.accept(this, context);
×
2052
    } else {
2053
      // construct insert rows statement
2054
      // construct insert statement
2055
      InsertRowsOfOneDeviceStatement insertRowsOfOneDeviceStatement =
1✔
2056
          new InsertRowsOfOneDeviceStatement();
2057
      List<InsertRowStatement> insertRowStatementList = new ArrayList<>();
1✔
2058
      for (int i = 0; i < timeArray.length; i++) {
1✔
2059
        InsertRowStatement statement = new InsertRowStatement();
1✔
2060
        statement.setDevicePath(devicePath);
1✔
2061
        String[] measurements = new String[measurementList.length];
1✔
2062
        System.arraycopy(measurementList, 0, measurements, 0, measurements.length);
1✔
2063
        statement.setMeasurements(measurements);
1✔
2064
        statement.setTime(timeArray[i]);
1✔
2065
        TSDataType[] dataTypes = new TSDataType[measurementList.length];
1✔
2066
        statement.setDataTypes(dataTypes);
1✔
2067
        Object[] values = new Object[measurementList.length];
1✔
2068
        System.arraycopy(insertStatement.getValuesList().get(i), 0, values, 0, values.length);
1✔
2069
        statement.setValues(values);
1✔
2070
        statement.setAligned(insertStatement.isAligned());
1✔
2071
        statement.setNeedInferType(true);
1✔
2072
        insertRowStatementList.add(statement);
1✔
2073
      }
2074
      insertRowsOfOneDeviceStatement.setInsertRowStatementList(insertRowStatementList);
1✔
2075
      return insertRowsOfOneDeviceStatement.accept(this, context);
1✔
2076
    }
2077
  }
2078

2079
  @Override
2080
  public Analysis visitCreateTimeseries(
2081
      CreateTimeSeriesStatement createTimeSeriesStatement, MPPQueryContext context) {
2082
    context.setQueryType(QueryType.WRITE);
1✔
2083
    if (createTimeSeriesStatement.getPath().getNodeLength() < 3) {
1✔
2084
      throw new SemanticException(
×
2085
          new IllegalPathException(createTimeSeriesStatement.getPath().getFullPath()));
×
2086
    }
2087
    analyzeSchemaProps(createTimeSeriesStatement.getProps());
1✔
2088
    if (createTimeSeriesStatement.getTags() != null
1✔
2089
        && !createTimeSeriesStatement.getTags().isEmpty()
1✔
2090
        && createTimeSeriesStatement.getAttributes() != null
1✔
2091
        && !createTimeSeriesStatement.getAttributes().isEmpty()) {
1✔
2092
      for (String tagKey : createTimeSeriesStatement.getTags().keySet()) {
1✔
2093
        if (createTimeSeriesStatement.getAttributes().containsKey(tagKey)) {
1✔
2094
          throw new SemanticException(
1✔
2095
              String.format("Tag and attribute shouldn't have the same property key [%s]", tagKey));
1✔
2096
        }
2097
      }
×
2098
    }
2099

2100
    Analysis analysis = new Analysis();
×
2101
    analysis.setStatement(createTimeSeriesStatement);
×
2102

2103
    checkIsTemplateCompatible(
×
2104
        createTimeSeriesStatement.getPath(), createTimeSeriesStatement.getAlias());
×
2105

2106
    PathPatternTree patternTree = new PathPatternTree();
×
2107
    patternTree.appendFullPath(createTimeSeriesStatement.getPath());
×
2108
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2109
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2110
    return analysis;
×
2111
  }
2112

2113
  private void checkIsTemplateCompatible(PartialPath timeseriesPath, String alias) {
2114
    Pair<Template, PartialPath> templateInfo =
×
2115
        schemaFetcher.checkTemplateSetAndPreSetInfo(timeseriesPath, alias);
×
2116
    if (templateInfo != null) {
×
2117
      throw new SemanticException(
×
2118
          new TemplateIncompatibleException(
2119
              timeseriesPath.getFullPath(), templateInfo.left.getName(), templateInfo.right));
×
2120
    }
2121
  }
×
2122

2123
  private void checkIsTemplateCompatible(
2124
      PartialPath devicePath, List<String> measurements, List<String> aliasList) {
2125
    for (int i = 0; i < measurements.size(); i++) {
×
2126
      Pair<Template, PartialPath> templateInfo =
×
2127
          schemaFetcher.checkTemplateSetAndPreSetInfo(
×
2128
              devicePath.concatNode(measurements.get(i)),
×
2129
              aliasList == null ? null : aliasList.get(i));
×
2130
      if (templateInfo != null) {
×
2131
        throw new SemanticException(
×
2132
            new TemplateIncompatibleException(
2133
                devicePath.getFullPath() + measurements,
×
2134
                templateInfo.left.getName(),
×
2135
                templateInfo.right));
2136
      }
2137
    }
2138
  }
×
2139

2140
  private void analyzeSchemaProps(Map<String, String> props) {
2141
    if (props == null || props.isEmpty()) {
1✔
2142
      return;
1✔
2143
    }
2144
    Map<String, String> caseChangeMap = new HashMap<>();
×
2145
    for (String key : props.keySet()) {
×
2146
      caseChangeMap.put(key.toLowerCase(Locale.ROOT), key);
×
2147
    }
×
2148
    for (Map.Entry<String, String> caseChangeEntry : caseChangeMap.entrySet()) {
×
2149
      String lowerCaseKey = caseChangeEntry.getKey();
×
2150
      if (!ALLOWED_SCHEMA_PROPS.contains(lowerCaseKey)) {
×
2151
        throw new SemanticException(
×
2152
            new MetadataException(
2153
                String.format("%s is not a legal prop.", caseChangeEntry.getValue())));
×
2154
      }
2155
      props.put(lowerCaseKey, props.remove(caseChangeEntry.getValue()));
×
2156
    }
×
2157
    if (props.containsKey(DEADBAND)) {
×
2158
      props.put(LOSS, props.remove(DEADBAND));
×
2159
    }
2160
  }
×
2161

2162
  private void analyzeSchemaProps(List<Map<String, String>> propsList) {
2163
    if (propsList == null) {
×
2164
      return;
×
2165
    }
2166
    for (Map<String, String> props : propsList) {
×
2167
      analyzeSchemaProps(props);
×
2168
    }
×
2169
  }
×
2170

2171
  @Override
2172
  public Analysis visitCreateAlignedTimeseries(
2173
      CreateAlignedTimeSeriesStatement createAlignedTimeSeriesStatement, MPPQueryContext context) {
2174
    context.setQueryType(QueryType.WRITE);
1✔
2175
    if (createAlignedTimeSeriesStatement.getDevicePath().getNodeLength() < 2) {
1✔
2176
      throw new SemanticException(
×
2177
          new IllegalPathException(createAlignedTimeSeriesStatement.getDevicePath().getFullPath()));
×
2178
    }
2179
    List<String> measurements = createAlignedTimeSeriesStatement.getMeasurements();
1✔
2180
    Set<String> measurementsSet = new HashSet<>(measurements);
1✔
2181
    if (measurementsSet.size() < measurements.size()) {
1✔
2182
      throw new SemanticException(
1✔
2183
          "Measurement under an aligned device is not allowed to have the same measurement name");
2184
    }
2185

2186
    Analysis analysis = new Analysis();
×
2187
    analysis.setStatement(createAlignedTimeSeriesStatement);
×
2188

2189
    checkIsTemplateCompatible(
×
2190
        createAlignedTimeSeriesStatement.getDevicePath(),
×
2191
        createAlignedTimeSeriesStatement.getMeasurements(),
×
2192
        createAlignedTimeSeriesStatement.getAliasList());
×
2193

2194
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2195
    for (String measurement : createAlignedTimeSeriesStatement.getMeasurements()) {
×
2196
      pathPatternTree.appendFullPath(createAlignedTimeSeriesStatement.getDevicePath(), measurement);
×
2197
    }
×
2198

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

2205
  @Override
2206
  public Analysis visitInternalCreateTimeseries(
2207
      InternalCreateTimeSeriesStatement internalCreateTimeSeriesStatement,
2208
      MPPQueryContext context) {
2209
    context.setQueryType(QueryType.WRITE);
×
2210

2211
    Analysis analysis = new Analysis();
×
2212
    analysis.setStatement(internalCreateTimeSeriesStatement);
×
2213

2214
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2215
    for (String measurement : internalCreateTimeSeriesStatement.getMeasurements()) {
×
2216
      pathPatternTree.appendFullPath(
×
2217
          internalCreateTimeSeriesStatement.getDevicePath(), measurement);
×
2218
    }
×
2219

2220
    SchemaPartition schemaPartitionInfo;
2221
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2222
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2223
    return analysis;
×
2224
  }
2225

2226
  @Override
2227
  public Analysis visitInternalCreateMultiTimeSeries(
2228
      InternalCreateMultiTimeSeriesStatement internalCreateMultiTimeSeriesStatement,
2229
      MPPQueryContext context) {
2230
    context.setQueryType(QueryType.WRITE);
×
2231

2232
    Analysis analysis = new Analysis();
×
2233
    analysis.setStatement(internalCreateMultiTimeSeriesStatement);
×
2234

2235
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2236
    for (PartialPath devicePath : internalCreateMultiTimeSeriesStatement.getDeviceMap().keySet()) {
×
2237
      pathPatternTree.appendFullPath(devicePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
2238
    }
×
2239

2240
    SchemaPartition schemaPartitionInfo;
2241
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2242
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2243
    return analysis;
×
2244
  }
2245

2246
  @Override
2247
  public Analysis visitCreateMultiTimeseries(
2248
      CreateMultiTimeSeriesStatement createMultiTimeSeriesStatement, MPPQueryContext context) {
2249
    context.setQueryType(QueryType.WRITE);
×
2250
    Analysis analysis = new Analysis();
×
2251
    analysis.setStatement(createMultiTimeSeriesStatement);
×
2252

2253
    analyzeSchemaProps(createMultiTimeSeriesStatement.getPropsList());
×
2254

2255
    List<PartialPath> timeseriesPathList = createMultiTimeSeriesStatement.getPaths();
×
2256
    List<String> aliasList = createMultiTimeSeriesStatement.getAliasList();
×
2257
    for (int i = 0; i < timeseriesPathList.size(); i++) {
×
2258
      checkIsTemplateCompatible(
×
2259
          timeseriesPathList.get(i), aliasList == null ? null : aliasList.get(i));
×
2260
    }
2261

2262
    PathPatternTree patternTree = new PathPatternTree();
×
2263
    for (PartialPath path : createMultiTimeSeriesStatement.getPaths()) {
×
2264
      patternTree.appendFullPath(path);
×
2265
    }
×
2266
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2267
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2268
    return analysis;
×
2269
  }
2270

2271
  @Override
2272
  public Analysis visitAlterTimeseries(
2273
      AlterTimeSeriesStatement alterTimeSeriesStatement, MPPQueryContext context) {
2274
    context.setQueryType(QueryType.WRITE);
×
2275
    Analysis analysis = new Analysis();
×
2276
    analysis.setStatement(alterTimeSeriesStatement);
×
2277

2278
    Pair<Template, PartialPath> templateInfo =
×
2279
        schemaFetcher.checkTemplateSetAndPreSetInfo(
×
2280
            alterTimeSeriesStatement.getPath(), alterTimeSeriesStatement.getAlias());
×
2281
    if (templateInfo != null) {
×
2282
      throw new RuntimeException(
×
2283
          new TemplateIncompatibleException(
2284
              String.format(
×
2285
                  "Cannot alter template timeseries [%s] since schema template [%s] already set on path [%s].",
2286
                  alterTimeSeriesStatement.getPath().getFullPath(),
×
2287
                  templateInfo.left.getName(),
×
2288
                  templateInfo.right)));
2289
    }
2290

2291
    PathPatternTree patternTree = new PathPatternTree();
×
2292
    patternTree.appendFullPath(alterTimeSeriesStatement.getPath());
×
2293
    SchemaPartition schemaPartitionInfo;
2294
    schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2295
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2296
    return analysis;
×
2297
  }
2298

2299
  @Override
2300
  public Analysis visitInsertTablet(
2301
      InsertTabletStatement insertTabletStatement, MPPQueryContext context) {
2302
    context.setQueryType(QueryType.WRITE);
×
2303
    Analysis analysis = new Analysis();
×
2304
    validateSchema(analysis, insertTabletStatement, context);
×
2305
    InsertBaseStatement realStatement = removeLogicalView(analysis, insertTabletStatement);
×
2306
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2307
      return analysis;
×
2308
    }
2309
    analysis.setStatement(realStatement);
×
2310

2311
    if (realStatement instanceof InsertTabletStatement) {
×
2312
      InsertTabletStatement realInsertTabletStatement = (InsertTabletStatement) realStatement;
×
2313
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2314
      dataPartitionQueryParam.setDevicePath(
×
2315
          realInsertTabletStatement.getDevicePath().getFullPath());
×
2316
      dataPartitionQueryParam.setTimePartitionSlotList(
×
2317
          realInsertTabletStatement.getTimePartitionSlots());
×
2318

2319
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
×
2320
    } else {
2321
      return computeAnalysisForMultiTablets(analysis, (InsertMultiTabletsStatement) realStatement);
×
2322
    }
2323
  }
2324

2325
  @Override
2326
  public Analysis visitInsertRow(InsertRowStatement insertRowStatement, MPPQueryContext context) {
2327
    context.setQueryType(QueryType.WRITE);
×
2328
    Analysis analysis = new Analysis();
×
2329
    validateSchema(analysis, insertRowStatement, context);
×
2330
    InsertBaseStatement realInsertStatement = removeLogicalView(analysis, insertRowStatement);
×
2331
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2332
      return analysis;
×
2333
    }
2334
    analysis.setStatement(realInsertStatement);
×
2335

2336
    if (realInsertStatement instanceof InsertRowStatement) {
×
2337
      InsertRowStatement realInsertRowStatement = (InsertRowStatement) realInsertStatement;
×
2338
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2339
      dataPartitionQueryParam.setDevicePath(realInsertRowStatement.getDevicePath().getFullPath());
×
2340
      dataPartitionQueryParam.setTimePartitionSlotList(
×
2341
          Collections.singletonList(realInsertRowStatement.getTimePartitionSlot()));
×
2342

2343
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
×
2344
    } else {
2345
      return computeAnalysisForInsertRows(analysis, (InsertRowsStatement) realInsertStatement);
×
2346
    }
2347
  }
2348

2349
  private Analysis computeAnalysisForInsertRows(
2350
      Analysis analysis, InsertRowsStatement insertRowsStatement) {
2351
    Map<String, Set<TTimePartitionSlot>> dataPartitionQueryParamMap = new HashMap<>();
×
2352
    for (InsertRowStatement insertRowStatement : insertRowsStatement.getInsertRowStatementList()) {
×
2353
      Set<TTimePartitionSlot> timePartitionSlotSet =
×
2354
          dataPartitionQueryParamMap.computeIfAbsent(
×
2355
              insertRowStatement.getDevicePath().getFullPath(), k -> new HashSet<>());
×
2356
      timePartitionSlotSet.add(insertRowStatement.getTimePartitionSlot());
×
2357
    }
×
2358

2359
    List<DataPartitionQueryParam> dataPartitionQueryParams = new ArrayList<>();
×
2360
    for (Map.Entry<String, Set<TTimePartitionSlot>> entry : dataPartitionQueryParamMap.entrySet()) {
×
2361
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2362
      dataPartitionQueryParam.setDevicePath(entry.getKey());
×
2363
      dataPartitionQueryParam.setTimePartitionSlotList(new ArrayList<>(entry.getValue()));
×
2364
      dataPartitionQueryParams.add(dataPartitionQueryParam);
×
2365
    }
×
2366

2367
    return getAnalysisForWriting(analysis, dataPartitionQueryParams);
×
2368
  }
2369

2370
  @Override
2371
  public Analysis visitInsertRows(
2372
      InsertRowsStatement insertRowsStatement, MPPQueryContext context) {
2373
    context.setQueryType(QueryType.WRITE);
×
2374
    Analysis analysis = new Analysis();
×
2375
    validateSchema(analysis, insertRowsStatement, context);
×
2376
    InsertRowsStatement realInsertRowsStatement =
×
2377
        (InsertRowsStatement) removeLogicalView(analysis, insertRowsStatement);
×
2378
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2379
      return analysis;
×
2380
    }
2381
    analysis.setStatement(realInsertRowsStatement);
×
2382

2383
    return computeAnalysisForInsertRows(analysis, realInsertRowsStatement);
×
2384
  }
2385

2386
  private Analysis computeAnalysisForMultiTablets(
2387
      Analysis analysis, InsertMultiTabletsStatement insertMultiTabletsStatement) {
2388
    Map<String, Set<TTimePartitionSlot>> dataPartitionQueryParamMap = new HashMap<>();
×
2389
    for (InsertTabletStatement insertTabletStatement :
2390
        insertMultiTabletsStatement.getInsertTabletStatementList()) {
×
2391
      Set<TTimePartitionSlot> timePartitionSlotSet =
×
2392
          dataPartitionQueryParamMap.computeIfAbsent(
×
2393
              insertTabletStatement.getDevicePath().getFullPath(), k -> new HashSet<>());
×
2394
      timePartitionSlotSet.addAll(insertTabletStatement.getTimePartitionSlots());
×
2395
    }
×
2396

2397
    List<DataPartitionQueryParam> dataPartitionQueryParams = new ArrayList<>();
×
2398
    for (Map.Entry<String, Set<TTimePartitionSlot>> entry : dataPartitionQueryParamMap.entrySet()) {
×
2399
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2400
      dataPartitionQueryParam.setDevicePath(entry.getKey());
×
2401
      dataPartitionQueryParam.setTimePartitionSlotList(new ArrayList<>(entry.getValue()));
×
2402
      dataPartitionQueryParams.add(dataPartitionQueryParam);
×
2403
    }
×
2404

2405
    return getAnalysisForWriting(analysis, dataPartitionQueryParams);
×
2406
  }
2407

2408
  @Override
2409
  public Analysis visitInsertMultiTablets(
2410
      InsertMultiTabletsStatement insertMultiTabletsStatement, MPPQueryContext context) {
2411
    context.setQueryType(QueryType.WRITE);
×
2412
    Analysis analysis = new Analysis();
×
2413
    validateSchema(analysis, insertMultiTabletsStatement, context);
×
2414
    InsertMultiTabletsStatement realStatement =
×
2415
        (InsertMultiTabletsStatement) removeLogicalView(analysis, insertMultiTabletsStatement);
×
2416
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2417
      return analysis;
×
2418
    }
2419
    analysis.setStatement(realStatement);
×
2420

2421
    return computeAnalysisForMultiTablets(analysis, realStatement);
×
2422
  }
2423

2424
  @Override
2425
  public Analysis visitInsertRowsOfOneDevice(
2426
      InsertRowsOfOneDeviceStatement insertRowsOfOneDeviceStatement, MPPQueryContext context) {
2427
    context.setQueryType(QueryType.WRITE);
1✔
2428
    Analysis analysis = new Analysis();
1✔
2429
    validateSchema(analysis, insertRowsOfOneDeviceStatement, context);
1✔
2430
    InsertBaseStatement realInsertStatement =
1✔
2431
        removeLogicalView(analysis, insertRowsOfOneDeviceStatement);
1✔
2432
    if (analysis.isFinishQueryAfterAnalyze()) {
1✔
2433
      return analysis;
×
2434
    }
2435
    analysis.setStatement(realInsertStatement);
1✔
2436

2437
    if (realInsertStatement instanceof InsertRowsOfOneDeviceStatement) {
1✔
2438
      InsertRowsOfOneDeviceStatement realStatement =
1✔
2439
          (InsertRowsOfOneDeviceStatement) realInsertStatement;
2440
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
1✔
2441
      dataPartitionQueryParam.setDevicePath(realStatement.getDevicePath().getFullPath());
1✔
2442
      dataPartitionQueryParam.setTimePartitionSlotList(realStatement.getTimePartitionSlots());
1✔
2443

2444
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
1✔
2445
    } else {
2446
      return computeAnalysisForInsertRows(analysis, (InsertRowsStatement) realInsertStatement);
×
2447
    }
2448
  }
2449

2450
  @Override
2451
  public Analysis visitPipeEnrichedInsert(
2452
      PipeEnrichedInsertBaseStatement pipeEnrichedInsertBaseStatement, MPPQueryContext context) {
2453
    Analysis analysis;
2454

2455
    final InsertBaseStatement insertBaseStatement =
×
2456
        pipeEnrichedInsertBaseStatement.getInsertBaseStatement();
×
2457
    if (insertBaseStatement instanceof InsertTabletStatement) {
×
2458
      analysis = visitInsertTablet((InsertTabletStatement) insertBaseStatement, context);
×
2459
    } else if (insertBaseStatement instanceof InsertMultiTabletsStatement) {
×
2460
      analysis =
×
2461
          visitInsertMultiTablets((InsertMultiTabletsStatement) insertBaseStatement, context);
×
2462
    } else if (insertBaseStatement instanceof InsertRowStatement) {
×
2463
      analysis = visitInsertRow((InsertRowStatement) insertBaseStatement, context);
×
2464
    } else if (insertBaseStatement instanceof InsertRowsStatement) {
×
2465
      analysis = visitInsertRows((InsertRowsStatement) insertBaseStatement, context);
×
2466
    } else if (insertBaseStatement instanceof InsertRowsOfOneDeviceStatement) {
×
2467
      analysis =
×
2468
          visitInsertRowsOfOneDevice((InsertRowsOfOneDeviceStatement) insertBaseStatement, context);
×
2469
    } else {
2470
      throw new UnsupportedOperationException(
×
2471
          "Unsupported insert statement type: " + insertBaseStatement.getClass().getName());
×
2472
    }
2473

2474
    // statement may be changed because of logical view
2475
    pipeEnrichedInsertBaseStatement.setInsertBaseStatement(
×
2476
        (InsertBaseStatement) analysis.getStatement());
×
2477
    analysis.setStatement(pipeEnrichedInsertBaseStatement);
×
2478
    return analysis;
×
2479
  }
2480

2481
  private void validateSchema(
2482
      Analysis analysis, InsertBaseStatement insertStatement, MPPQueryContext context) {
2483
    final long startTime = System.nanoTime();
1✔
2484
    try {
2485
      SchemaValidator.validate(schemaFetcher, insertStatement, context);
1✔
2486
    } catch (SemanticException e) {
×
2487
      analysis.setFinishQueryAfterAnalyze(true);
×
2488
      if (e.getCause() instanceof IoTDBException) {
×
2489
        IoTDBException exception = (IoTDBException) e.getCause();
×
2490
        analysis.setFailStatus(
×
2491
            RpcUtils.getStatus(exception.getErrorCode(), exception.getMessage()));
×
2492
      } else {
×
2493
        analysis.setFailStatus(RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage()));
×
2494
      }
2495
    } finally {
2496
      PERFORMANCE_OVERVIEW_METRICS.recordScheduleSchemaValidateCost(System.nanoTime() - startTime);
1✔
2497
    }
2498
    boolean hasFailedMeasurement = insertStatement.hasFailedMeasurements();
1✔
2499
    String partialInsertMessage;
2500
    if (hasFailedMeasurement) {
1✔
2501
      partialInsertMessage =
×
2502
          String.format(
×
2503
              "Fail to insert measurements %s caused by %s",
2504
              insertStatement.getFailedMeasurements(), insertStatement.getFailedMessages());
×
2505
      logger.warn(partialInsertMessage);
×
2506
      analysis.setFailStatus(
×
2507
          RpcUtils.getStatus(TSStatusCode.METADATA_ERROR.getStatusCode(), partialInsertMessage));
×
2508
    }
2509
  }
1✔
2510

2511
  private InsertBaseStatement removeLogicalView(
2512
      Analysis analysis, InsertBaseStatement insertBaseStatement) {
2513
    try {
2514
      return insertBaseStatement.removeLogicalView();
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
      return insertBaseStatement;
×
2525
    }
2526
  }
2527

2528
  @Override
2529
  public Analysis visitLoadFile(LoadTsFileStatement loadTsFileStatement, MPPQueryContext context) {
2530
    return new LoadTsfileAnalyzer(loadTsFileStatement, context, partitionFetcher, schemaFetcher)
×
2531
        .analyzeFileByFile();
×
2532
  }
2533

2534
  @Override
2535
  public Analysis visitPipeEnrichedLoadFile(
2536
      PipeEnrichedLoadTsFileStatement pipeEnrichedLoadTsFileStatement, MPPQueryContext context) {
2537
    final Analysis analysis =
×
2538
        visitLoadFile(pipeEnrichedLoadTsFileStatement.getLoadTsFileStatement(), context);
×
2539
    analysis.setStatement(pipeEnrichedLoadTsFileStatement);
×
2540
    return analysis;
×
2541
  }
2542

2543
  /** get analysis according to statement and params */
2544
  private Analysis getAnalysisForWriting(
2545
      Analysis analysis, List<DataPartitionQueryParam> dataPartitionQueryParams) {
2546

2547
    DataPartition dataPartition =
1✔
2548
        partitionFetcher.getOrCreateDataPartition(dataPartitionQueryParams);
1✔
2549
    if (dataPartition.isEmpty()) {
1✔
2550
      analysis.setFinishQueryAfterAnalyze(true);
×
2551
      analysis.setFailStatus(
×
2552
          RpcUtils.getStatus(
×
2553
              TSStatusCode.DATABASE_NOT_EXIST.getStatusCode(),
×
2554
              "Database not exists and failed to create automatically "
2555
                  + "because enable_auto_create_schema is FALSE."));
2556
    }
2557
    analysis.setDataPartitionInfo(dataPartition);
1✔
2558
    return analysis;
1✔
2559
  }
2560

2561
  @Override
2562
  public Analysis visitShowTimeSeries(
2563
      ShowTimeSeriesStatement showTimeSeriesStatement, MPPQueryContext context) {
2564
    Analysis analysis = new Analysis();
×
2565
    analysis.setStatement(showTimeSeriesStatement);
×
2566

2567
    PathPatternTree patternTree = new PathPatternTree();
×
2568
    patternTree.appendPathPattern(showTimeSeriesStatement.getPathPattern());
×
2569
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2570
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2571

2572
    Map<Integer, Template> templateMap =
×
2573
        schemaFetcher.checkAllRelatedTemplate(showTimeSeriesStatement.getPathPattern());
×
2574
    analysis.setRelatedTemplateInfo(templateMap);
×
2575

2576
    if (showTimeSeriesStatement.isOrderByHeat()) {
×
2577
      patternTree.constructTree();
×
2578
      // request schema fetch API
2579
      logger.debug("[StartFetchSchema]");
×
2580
      ISchemaTree schemaTree = schemaFetcher.fetchSchema(patternTree, context);
×
2581
      updateSchemaTreeByViews(analysis, schemaTree);
×
2582
      logger.debug("[EndFetchSchema]]");
×
2583

2584
      analyzeLastSource(
×
2585
          analysis,
2586
          Collections.singletonList(
×
2587
              new TimeSeriesOperand(showTimeSeriesStatement.getPathPattern())),
×
2588
          schemaTree);
2589
      analyzeDataPartition(analysis, new QueryStatement(), schemaTree);
×
2590
    }
2591

2592
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTimeSeriesHeader());
×
2593
    return analysis;
×
2594
  }
2595

2596
  @Override
2597
  public Analysis visitShowStorageGroup(
2598
      ShowDatabaseStatement showDatabaseStatement, MPPQueryContext context) {
2599
    Analysis analysis = new Analysis();
×
2600
    analysis.setStatement(showDatabaseStatement);
×
2601
    analysis.setRespDatasetHeader(
×
2602
        DatasetHeaderFactory.getShowStorageGroupHeader(showDatabaseStatement.isDetailed()));
×
2603
    return analysis;
×
2604
  }
2605

2606
  @Override
2607
  public Analysis visitShowTTL(ShowTTLStatement showTTLStatement, MPPQueryContext context) {
2608
    Analysis analysis = new Analysis();
×
2609
    analysis.setStatement(showTTLStatement);
×
2610
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTTLHeader());
×
2611
    return analysis;
×
2612
  }
2613

2614
  @Override
2615
  public Analysis visitShowDevices(
2616
      ShowDevicesStatement showDevicesStatement, MPPQueryContext context) {
2617
    Analysis analysis = new Analysis();
×
2618
    analysis.setStatement(showDevicesStatement);
×
2619

2620
    PathPatternTree patternTree = new PathPatternTree();
×
2621
    patternTree.appendPathPattern(
×
2622
        showDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD));
×
2623
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2624

2625
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2626
    analysis.setRespDatasetHeader(
×
2627
        showDevicesStatement.hasSgCol()
×
2628
            ? DatasetHeaderFactory.getShowDevicesWithSgHeader()
×
2629
            : DatasetHeaderFactory.getShowDevicesHeader());
×
2630
    return analysis;
×
2631
  }
2632

2633
  @Override
2634
  public Analysis visitShowCluster(
2635
      ShowClusterStatement showClusterStatement, MPPQueryContext context) {
2636
    Analysis analysis = new Analysis();
×
2637
    analysis.setStatement(showClusterStatement);
×
2638
    if (showClusterStatement.isDetails()) {
×
2639
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowClusterDetailsHeader());
×
2640
    } else {
2641
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowClusterHeader());
×
2642
    }
2643
    return analysis;
×
2644
  }
2645

2646
  @Override
2647
  public Analysis visitCountStorageGroup(
2648
      CountDatabaseStatement countDatabaseStatement, MPPQueryContext context) {
2649
    Analysis analysis = new Analysis();
×
2650
    analysis.setStatement(countDatabaseStatement);
×
2651
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountStorageGroupHeader());
×
2652
    return analysis;
×
2653
  }
2654

2655
  @Override
2656
  public Analysis visitSchemaFetch(
2657
      SchemaFetchStatement schemaFetchStatement, MPPQueryContext context) {
2658
    Analysis analysis = new Analysis();
×
2659
    analysis.setStatement(schemaFetchStatement);
×
2660

2661
    SchemaPartition schemaPartition =
×
2662
        partitionFetcher.getSchemaPartition(schemaFetchStatement.getPatternTree());
×
2663
    analysis.setSchemaPartitionInfo(schemaPartition);
×
2664

2665
    if (schemaPartition.isEmpty()) {
×
2666
      analysis.setFinishQueryAfterAnalyze(true);
×
2667
    }
2668

2669
    return analysis;
×
2670
  }
2671

2672
  @Override
2673
  public Analysis visitCountDevices(
2674
      CountDevicesStatement countDevicesStatement, MPPQueryContext context) {
2675
    Analysis analysis = new Analysis();
×
2676
    analysis.setStatement(countDevicesStatement);
×
2677

2678
    PathPatternTree patternTree = new PathPatternTree();
×
2679
    patternTree.appendPathPattern(
×
2680
        countDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD));
×
2681
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2682

2683
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2684
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountDevicesHeader());
×
2685
    return analysis;
×
2686
  }
2687

2688
  @Override
2689
  public Analysis visitCountTimeSeries(
2690
      CountTimeSeriesStatement countTimeSeriesStatement, MPPQueryContext context) {
2691
    Analysis analysis = new Analysis();
×
2692
    analysis.setStatement(countTimeSeriesStatement);
×
2693

2694
    PathPatternTree patternTree = new PathPatternTree();
×
2695
    patternTree.appendPathPattern(countTimeSeriesStatement.getPathPattern());
×
2696
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2697
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2698

2699
    Map<Integer, Template> templateMap =
×
2700
        schemaFetcher.checkAllRelatedTemplate(countTimeSeriesStatement.getPathPattern());
×
2701
    analysis.setRelatedTemplateInfo(templateMap);
×
2702

2703
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountTimeSeriesHeader());
×
2704
    return analysis;
×
2705
  }
2706

2707
  @Override
2708
  public Analysis visitCountLevelTimeSeries(
2709
      CountLevelTimeSeriesStatement countLevelTimeSeriesStatement, MPPQueryContext context) {
2710
    Analysis analysis = new Analysis();
×
2711
    analysis.setStatement(countLevelTimeSeriesStatement);
×
2712

2713
    PathPatternTree patternTree = new PathPatternTree();
×
2714
    patternTree.appendPathPattern(countLevelTimeSeriesStatement.getPathPattern());
×
2715
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2716

2717
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2718
    Map<Integer, Template> templateMap =
×
2719
        schemaFetcher.checkAllRelatedTemplate(countLevelTimeSeriesStatement.getPathPattern());
×
2720
    analysis.setRelatedTemplateInfo(templateMap);
×
2721
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountLevelTimeSeriesHeader());
×
2722
    return analysis;
×
2723
  }
2724

2725
  @Override
2726
  public Analysis visitCountNodes(CountNodesStatement countStatement, MPPQueryContext context) {
2727
    Analysis analysis = new Analysis();
×
2728
    analysis.setStatement(countStatement);
×
2729

2730
    PathPatternTree patternTree = new PathPatternTree();
×
2731
    patternTree.appendPathPattern(countStatement.getPathPattern());
×
2732
    SchemaNodeManagementPartition schemaNodeManagementPartition =
×
2733
        partitionFetcher.getSchemaNodeManagementPartitionWithLevel(
×
2734
            patternTree, countStatement.getLevel());
×
2735

2736
    if (schemaNodeManagementPartition == null) {
×
2737
      return analysis;
×
2738
    }
2739
    if (!schemaNodeManagementPartition.getMatchedNode().isEmpty()
×
2740
        && schemaNodeManagementPartition.getSchemaPartition().getSchemaPartitionMap().size() == 0) {
×
2741
      analysis.setFinishQueryAfterAnalyze(true);
×
2742
    }
2743
    analysis.setMatchedNodes(schemaNodeManagementPartition.getMatchedNode());
×
2744
    analysis.setSchemaPartitionInfo(schemaNodeManagementPartition.getSchemaPartition());
×
2745
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountNodesHeader());
×
2746
    return analysis;
×
2747
  }
2748

2749
  @Override
2750
  public Analysis visitShowChildPaths(
2751
      ShowChildPathsStatement showChildPathsStatement, MPPQueryContext context) {
2752
    return visitSchemaNodeManagementPartition(
×
2753
        showChildPathsStatement,
2754
        showChildPathsStatement.getPartialPath(),
×
2755
        DatasetHeaderFactory.getShowChildPathsHeader());
×
2756
  }
2757

2758
  @Override
2759
  public Analysis visitShowChildNodes(
2760
      ShowChildNodesStatement showChildNodesStatement, MPPQueryContext context) {
2761
    return visitSchemaNodeManagementPartition(
×
2762
        showChildNodesStatement,
2763
        showChildNodesStatement.getPartialPath(),
×
2764
        DatasetHeaderFactory.getShowChildNodesHeader());
×
2765
  }
2766

2767
  @Override
2768
  public Analysis visitShowVersion(
2769
      ShowVersionStatement showVersionStatement, MPPQueryContext context) {
2770
    Analysis analysis = new Analysis();
×
2771
    analysis.setStatement(showVersionStatement);
×
2772
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowVersionHeader());
×
2773
    analysis.setFinishQueryAfterAnalyze(true);
×
2774
    return analysis;
×
2775
  }
2776

2777
  private Analysis visitSchemaNodeManagementPartition(
2778
      Statement statement, PartialPath path, DatasetHeader header) {
2779
    Analysis analysis = new Analysis();
×
2780
    analysis.setStatement(statement);
×
2781

2782
    PathPatternTree patternTree = new PathPatternTree();
×
2783
    patternTree.appendPathPattern(path);
×
2784
    SchemaNodeManagementPartition schemaNodeManagementPartition =
×
2785
        partitionFetcher.getSchemaNodeManagementPartition(patternTree);
×
2786

2787
    if (schemaNodeManagementPartition == null) {
×
2788
      return analysis;
×
2789
    }
2790
    if (!schemaNodeManagementPartition.getMatchedNode().isEmpty()
×
2791
        && schemaNodeManagementPartition.getSchemaPartition().getSchemaPartitionMap().size() == 0) {
×
2792
      analysis.setFinishQueryAfterAnalyze(true);
×
2793
    }
2794
    analysis.setMatchedNodes(schemaNodeManagementPartition.getMatchedNode());
×
2795
    analysis.setSchemaPartitionInfo(schemaNodeManagementPartition.getSchemaPartition());
×
2796
    analysis.setRespDatasetHeader(header);
×
2797
    return analysis;
×
2798
  }
2799

2800
  @Override
2801
  public Analysis visitDeleteData(
2802
      DeleteDataStatement deleteDataStatement, MPPQueryContext context) {
2803
    context.setQueryType(QueryType.WRITE);
×
2804
    Analysis analysis = new Analysis();
×
2805
    analysis.setStatement(deleteDataStatement);
×
2806

2807
    PathPatternTree patternTree = new PathPatternTree();
×
2808
    deleteDataStatement.getPathList().forEach(patternTree::appendPathPattern);
×
2809

2810
    ISchemaTree schemaTree = schemaFetcher.fetchSchema(patternTree, context);
×
2811
    Set<String> deduplicatedDevicePaths = new HashSet<>();
×
2812

2813
    if (schemaTree.hasLogicalViewMeasurement()) {
×
2814
      updateSchemaTreeByViews(analysis, schemaTree);
×
2815

2816
      Set<PartialPath> deletePatternSet = new HashSet<>(deleteDataStatement.getPathList());
×
2817
      IMeasurementSchema measurementSchema;
2818
      LogicalViewSchema logicalViewSchema;
2819
      PartialPath sourcePathOfAliasSeries;
2820
      for (MeasurementPath measurementPath :
2821
          schemaTree.searchMeasurementPaths(SchemaConstant.ALL_MATCH_PATTERN).left) {
×
2822
        measurementSchema = measurementPath.getMeasurementSchema();
×
2823
        if (measurementSchema.isLogicalView()) {
×
2824
          logicalViewSchema = (LogicalViewSchema) measurementSchema;
×
2825
          if (logicalViewSchema.isWritable()) {
×
2826
            sourcePathOfAliasSeries = logicalViewSchema.getSourcePathIfWritable();
×
2827
            deletePatternSet.add(sourcePathOfAliasSeries);
×
2828
            deduplicatedDevicePaths.add(sourcePathOfAliasSeries.getDevice());
×
2829
          } else {
2830
            deletePatternSet.remove(measurementPath);
×
2831
          }
2832
        } else {
2833
          deduplicatedDevicePaths.add(measurementPath.getDevice());
×
2834
        }
2835
      }
×
2836
      deleteDataStatement.setPathList(new ArrayList<>(deletePatternSet));
×
2837
    } else {
×
2838
      for (PartialPath devicePattern : patternTree.getAllDevicePaths()) {
×
2839
        schemaTree
×
2840
            .getMatchedDevices(devicePattern)
×
2841
            .forEach(
×
2842
                deviceSchemaInfo ->
2843
                    deduplicatedDevicePaths.add(deviceSchemaInfo.getDevicePath().getFullPath()));
×
2844
      }
×
2845
    }
2846
    analysis.setSchemaTree(schemaTree);
×
2847

2848
    Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap = new HashMap<>();
×
2849

2850
    deduplicatedDevicePaths.forEach(
×
2851
        devicePath -> {
2852
          DataPartitionQueryParam queryParam = new DataPartitionQueryParam();
×
2853
          queryParam.setDevicePath(devicePath);
×
2854
          sgNameToQueryParamsMap
×
2855
              .computeIfAbsent(schemaTree.getBelongedDatabase(devicePath), key -> new ArrayList<>())
×
2856
              .add(queryParam);
×
2857
        });
×
2858

2859
    DataPartition dataPartition = partitionFetcher.getDataPartition(sgNameToQueryParamsMap);
×
2860
    analysis.setDataPartitionInfo(dataPartition);
×
2861
    analysis.setFinishQueryAfterAnalyze(dataPartition.isEmpty());
×
2862

2863
    return analysis;
×
2864
  }
2865

2866
  @Override
2867
  public Analysis visitCreateSchemaTemplate(
2868
      CreateSchemaTemplateStatement createTemplateStatement, MPPQueryContext context) {
2869

2870
    context.setQueryType(QueryType.WRITE);
×
2871
    List<String> measurements = createTemplateStatement.getMeasurements();
×
2872
    Set<String> measurementsSet = new HashSet<>(measurements);
×
2873
    if (measurementsSet.size() < measurements.size()) {
×
2874
      throw new SemanticException(
×
2875
          "Measurement under template is not allowed to have the same measurement name");
2876
    }
2877
    Analysis analysis = new Analysis();
×
2878
    analysis.setStatement(createTemplateStatement);
×
2879
    return analysis;
×
2880
  }
2881

2882
  @Override
2883
  public Analysis visitShowNodesInSchemaTemplate(
2884
      ShowNodesInSchemaTemplateStatement showNodesInSchemaTemplateStatement,
2885
      MPPQueryContext context) {
2886
    Analysis analysis = new Analysis();
×
2887
    analysis.setStatement(showNodesInSchemaTemplateStatement);
×
2888
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowNodesInSchemaTemplateHeader());
×
2889
    return analysis;
×
2890
  }
2891

2892
  @Override
2893
  public Analysis visitShowSchemaTemplate(
2894
      ShowSchemaTemplateStatement showSchemaTemplateStatement, MPPQueryContext context) {
2895
    Analysis analysis = new Analysis();
×
2896
    analysis.setStatement(showSchemaTemplateStatement);
×
2897
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowSchemaTemplateHeader());
×
2898
    return analysis;
×
2899
  }
2900

2901
  private GroupByFilter initGroupByFilter(GroupByTimeComponent groupByTimeComponent) {
2902
    if (groupByTimeComponent.isIntervalByMonth() || groupByTimeComponent.isSlidingStepByMonth()) {
1✔
2903
      return new GroupByMonthFilter(
×
2904
          groupByTimeComponent.getInterval(),
×
2905
          groupByTimeComponent.getSlidingStep(),
×
2906
          groupByTimeComponent.getStartTime(),
×
2907
          groupByTimeComponent.getEndTime(),
×
2908
          groupByTimeComponent.isSlidingStepByMonth(),
×
2909
          groupByTimeComponent.isIntervalByMonth(),
×
2910
          TimeZone.getTimeZone("+00:00"));
×
2911
    } else {
2912
      long startTime =
2913
          groupByTimeComponent.isLeftCRightO()
1✔
2914
              ? groupByTimeComponent.getStartTime()
1✔
2915
              : groupByTimeComponent.getStartTime() + 1;
1✔
2916
      long endTime =
2917
          groupByTimeComponent.isLeftCRightO()
1✔
2918
              ? groupByTimeComponent.getEndTime()
1✔
2919
              : groupByTimeComponent.getEndTime() + 1;
1✔
2920
      return new GroupByFilter(
1✔
2921
          groupByTimeComponent.getInterval(),
1✔
2922
          groupByTimeComponent.getSlidingStep(),
1✔
2923
          startTime,
2924
          endTime);
2925
    }
2926
  }
2927

2928
  @Override
2929
  public Analysis visitSetSchemaTemplate(
2930
      SetSchemaTemplateStatement setSchemaTemplateStatement, MPPQueryContext context) {
2931
    context.setQueryType(QueryType.WRITE);
×
2932
    Analysis analysis = new Analysis();
×
2933
    analysis.setStatement(setSchemaTemplateStatement);
×
2934
    return analysis;
×
2935
  }
2936

2937
  @Override
2938
  public Analysis visitShowPathSetTemplate(
2939
      ShowPathSetTemplateStatement showPathSetTemplateStatement, MPPQueryContext context) {
2940
    Analysis analysis = new Analysis();
×
2941
    analysis.setStatement(showPathSetTemplateStatement);
×
2942
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowPathSetTemplateHeader());
×
2943
    return analysis;
×
2944
  }
2945

2946
  @Override
2947
  public Analysis visitActivateTemplate(
2948
      ActivateTemplateStatement activateTemplateStatement, MPPQueryContext context) {
2949
    context.setQueryType(QueryType.WRITE);
×
2950
    Analysis analysis = new Analysis();
×
2951
    analysis.setStatement(activateTemplateStatement);
×
2952

2953
    PartialPath activatePath = activateTemplateStatement.getPath();
×
2954

2955
    Pair<Template, PartialPath> templateSetInfo = schemaFetcher.checkTemplateSetInfo(activatePath);
×
2956
    if (templateSetInfo == null) {
×
2957
      throw new StatementAnalyzeException(
×
2958
          new MetadataException(
2959
              String.format(
×
2960
                  "Path [%s] has not been set any template.", activatePath.getFullPath())));
×
2961
    }
2962
    analysis.setTemplateSetInfo(
×
2963
        new Pair<>(templateSetInfo.left, Collections.singletonList(templateSetInfo.right)));
×
2964

2965
    PathPatternTree patternTree = new PathPatternTree();
×
2966
    patternTree.appendPathPattern(activatePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
2967
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2968

2969
    analysis.setSchemaPartitionInfo(partition);
×
2970

2971
    return analysis;
×
2972
  }
2973

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

2981
    Map<PartialPath, Pair<Template, PartialPath>> deviceTemplateSetInfoMap =
×
2982
        new HashMap<>(batchActivateTemplateStatement.getPaths().size());
×
2983
    for (PartialPath devicePath : batchActivateTemplateStatement.getDevicePathList()) {
×
2984
      Pair<Template, PartialPath> templateSetInfo = schemaFetcher.checkTemplateSetInfo(devicePath);
×
2985
      if (templateSetInfo == null) {
×
2986
        throw new StatementAnalyzeException(
×
2987
            new MetadataException(
2988
                String.format(
×
2989
                    "Path [%s] has not been set any template.", devicePath.getFullPath())));
×
2990
      }
2991
      deviceTemplateSetInfoMap.put(devicePath, templateSetInfo);
×
2992
    }
×
2993
    analysis.setDeviceTemplateSetInfoMap(deviceTemplateSetInfoMap);
×
2994

2995
    PathPatternTree patternTree = new PathPatternTree();
×
2996
    for (PartialPath devicePath : batchActivateTemplateStatement.getDevicePathList()) {
×
2997
      // the devicePath is a path without wildcard
2998
      patternTree.appendFullPath(devicePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
2999
    }
×
3000
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3001

3002
    analysis.setSchemaPartitionInfo(partition);
×
3003

3004
    return analysis;
×
3005
  }
3006

3007
  @Override
3008
  public Analysis visitInternalBatchActivateTemplate(
3009
      InternalBatchActivateTemplateStatement internalBatchActivateTemplateStatement,
3010
      MPPQueryContext context) {
3011
    context.setQueryType(QueryType.WRITE);
×
3012
    Analysis analysis = new Analysis();
×
3013
    analysis.setStatement(internalBatchActivateTemplateStatement);
×
3014

3015
    PathPatternTree patternTree = new PathPatternTree();
×
3016
    for (PartialPath activatePath :
3017
        internalBatchActivateTemplateStatement.getDeviceMap().keySet()) {
×
3018
      // the devicePath is a path without wildcard
3019
      patternTree.appendFullPath(activatePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
3020
    }
×
3021
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3022

3023
    analysis.setSchemaPartitionInfo(partition);
×
3024

3025
    return analysis;
×
3026
  }
3027

3028
  @Override
3029
  public Analysis visitShowPathsUsingTemplate(
3030
      ShowPathsUsingTemplateStatement showPathsUsingTemplateStatement, MPPQueryContext context) {
3031
    Analysis analysis = new Analysis();
×
3032
    analysis.setStatement(showPathsUsingTemplateStatement);
×
3033
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowPathsUsingTemplateHeader());
×
3034

3035
    Pair<Template, List<PartialPath>> templateSetInfo =
×
3036
        schemaFetcher.getAllPathsSetTemplate(showPathsUsingTemplateStatement.getTemplateName());
×
3037

3038
    if (templateSetInfo == null
×
3039
        || templateSetInfo.right == null
3040
        || templateSetInfo.right.isEmpty()) {
×
3041
      analysis.setFinishQueryAfterAnalyze(true);
×
3042
      return analysis;
×
3043
    }
3044

3045
    analysis.setTemplateSetInfo(templateSetInfo);
×
3046

3047
    PathPatternTree patternTree = new PathPatternTree();
×
3048
    PartialPath rawPathPattern = showPathsUsingTemplateStatement.getPathPattern();
×
3049
    List<PartialPath> specifiedPatternList = new ArrayList<>();
×
3050
    templateSetInfo.right.forEach(
×
3051
        setPath -> {
3052
          for (PartialPath specifiedPattern : rawPathPattern.alterPrefixPath(setPath)) {
×
3053
            patternTree.appendPathPattern(specifiedPattern);
×
3054
            specifiedPatternList.add(specifiedPattern);
×
3055
          }
×
3056
        });
×
3057

3058
    if (specifiedPatternList.isEmpty()) {
×
3059
      analysis.setFinishQueryAfterAnalyze(true);
×
3060
      return analysis;
×
3061
    }
3062

3063
    analysis.setSpecifiedTemplateRelatedPathPatternList(specifiedPatternList);
×
3064

3065
    SchemaPartition partition = partitionFetcher.getSchemaPartition(patternTree);
×
3066
    analysis.setSchemaPartitionInfo(partition);
×
3067
    if (partition.isEmpty()) {
×
3068
      analysis.setFinishQueryAfterAnalyze(true);
×
3069
      return analysis;
×
3070
    }
3071

3072
    return analysis;
×
3073
  }
3074

3075
  @Override
3076
  public Analysis visitShowQueries(
3077
      ShowQueriesStatement showQueriesStatement, MPPQueryContext context) {
3078
    Analysis analysis = new Analysis();
×
3079
    analysis.setStatement(showQueriesStatement);
×
3080
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowQueriesHeader());
×
3081
    analysis.setVirtualSource(true);
×
3082

3083
    List<TDataNodeLocation> allRunningDataNodeLocations = getRunningDataNodeLocations();
×
3084
    if (allRunningDataNodeLocations.isEmpty()) {
×
3085
      analysis.setFinishQueryAfterAnalyze(true);
×
3086
    }
3087
    // TODO Constant folding optimization for Where Predicate after True/False Constant introduced
3088
    if (allRunningDataNodeLocations.isEmpty()) {
×
3089
      throw new StatementAnalyzeException("no Running DataNodes");
×
3090
    }
3091
    analysis.setRunningDataNodeLocations(allRunningDataNodeLocations);
×
3092

3093
    Set<Expression> sourceExpressions = new HashSet<>();
×
3094
    for (ColumnHeader columnHeader : analysis.getRespDatasetHeader().getColumnHeaders()) {
×
3095
      sourceExpressions.add(
×
3096
          TimeSeriesOperand.constructColumnHeaderExpression(
×
3097
              columnHeader.getColumnName(), columnHeader.getColumnType()));
×
3098
    }
×
3099
    analysis.setSourceExpressions(sourceExpressions);
×
3100
    sourceExpressions.forEach(expression -> analyzeExpressionType(analysis, expression));
×
3101

3102
    analyzeWhere(analysis, showQueriesStatement);
×
3103

3104
    analysis.setMergeOrderParameter(new OrderByParameter(showQueriesStatement.getSortItemList()));
×
3105

3106
    return analysis;
×
3107
  }
3108

3109
  private List<TDataNodeLocation> getRunningDataNodeLocations() {
3110
    try (ConfigNodeClient client =
3111
        ConfigNodeClientManager.getInstance().borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) {
×
3112
      TGetDataNodeLocationsResp showDataNodesResp = client.getRunningDataNodeLocations();
×
3113
      if (showDataNodesResp.getStatus().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
×
3114
        throw new StatementAnalyzeException(
×
3115
            "An error occurred when executing getRunningDataNodeLocations():"
3116
                + showDataNodesResp.getStatus().getMessage());
×
3117
      }
3118
      return showDataNodesResp.getDataNodeLocationList();
×
3119
    } catch (ClientManagerException | TException e) {
×
3120
      throw new StatementAnalyzeException(
×
3121
          "An error occurred when executing getRunningDataNodeLocations():" + e.getMessage());
×
3122
    }
3123
  }
3124

3125
  private void analyzeWhere(Analysis analysis, ShowQueriesStatement showQueriesStatement) {
3126
    WhereCondition whereCondition = showQueriesStatement.getWhereCondition();
×
3127
    if (whereCondition == null) {
×
3128
      return;
×
3129
    }
3130

3131
    Expression whereExpression =
×
3132
        ExpressionAnalyzer.bindTypeForTimeSeriesOperand(
×
3133
            whereCondition.getPredicate(), ColumnHeaderConstant.showQueriesColumnHeaders);
×
3134

3135
    TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
×
3136
    if (outputType != TSDataType.BOOLEAN) {
×
3137
      throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
3138
    }
3139

3140
    analysis.setWhereExpression(whereExpression);
×
3141
  }
×
3142

3143
  // region view
3144

3145
  /**
3146
   * Compute how many paths exist, get the schema tree and the number of existed paths.
3147
   *
3148
   * @return a pair of ISchemaTree, and the number of exist paths.
3149
   */
3150
  private Pair<ISchemaTree, Integer> fetchSchemaOfPathsAndCount(
3151
      List<PartialPath> pathList, Analysis analysis, MPPQueryContext context) {
3152
    ISchemaTree schemaTree = analysis.getSchemaTree();
×
3153
    if (schemaTree == null) {
×
3154
      // source is not represented by query, thus has not done fetch schema.
3155
      PathPatternTree pathPatternTree = new PathPatternTree();
×
3156
      for (PartialPath path : pathList) {
×
3157
        pathPatternTree.appendPathPattern(path);
×
3158
      }
×
3159
      schemaTree = this.schemaFetcher.fetchSchema(pathPatternTree, context);
×
3160
    }
3161

3162
    // search each path, make sure they all exist.
3163
    int numOfExistPaths = 0;
×
3164
    for (PartialPath path : pathList) {
×
3165
      Pair<List<MeasurementPath>, Integer> pathPair = schemaTree.searchMeasurementPaths(path);
×
3166
      numOfExistPaths += !pathPair.left.isEmpty() ? 1 : 0;
×
3167
    }
×
3168
    return new Pair<>(schemaTree, numOfExistPaths);
×
3169
  }
3170

3171
  /**
3172
   * @param pathList the paths you want to check
3173
   * @param schemaTree the given schema tree
3174
   * @return if all paths you give can be found in schema tree, return a pair of view paths and
3175
   *     null; else return view paths and the non-exist path.
3176
   */
3177
  private Pair<List<PartialPath>, PartialPath> findAllViewsInPaths(
3178
      List<PartialPath> pathList, ISchemaTree schemaTree) {
3179
    List<PartialPath> result = new ArrayList<>();
×
3180
    for (PartialPath path : pathList) {
×
3181
      Pair<List<MeasurementPath>, Integer> measurementPathList =
×
3182
          schemaTree.searchMeasurementPaths(path);
×
3183
      if (measurementPathList.left.isEmpty()) {
×
3184
        return new Pair<>(result, path);
×
3185
      }
3186
      for (MeasurementPath measurementPath : measurementPathList.left) {
×
3187
        if (measurementPath.getMeasurementSchema().isLogicalView()) {
×
3188
          result.add(measurementPath);
×
3189
        }
3190
      }
×
3191
    }
×
3192
    return new Pair<>(result, null);
×
3193
  }
3194

3195
  private Pair<List<Expression>, Analysis> analyzeQueryInLogicalViewStatement(
3196
      Analysis analysis, QueryStatement queryStatement, MPPQueryContext context) {
3197
    Analysis queryAnalysis = this.visitQuery(queryStatement, context);
×
3198
    analysis.setSchemaTree(queryAnalysis.getSchemaTree());
×
3199
    // get all expression from resultColumns
3200
    List<Pair<Expression, String>> outputExpressions = queryAnalysis.getOutputExpressions();
×
3201
    if (queryAnalysis.isFailed()) {
×
3202
      analysis.setFinishQueryAfterAnalyze(true);
×
3203
      analysis.setFailStatus(queryAnalysis.getFailStatus());
×
3204
      return new Pair<>(null, analysis);
×
3205
    }
3206
    if (outputExpressions == null) {
×
3207
      analysis.setFinishQueryAfterAnalyze(true);
×
3208
      analysis.setFailStatus(
×
3209
          RpcUtils.getStatus(
×
3210
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3211
              "Columns in the query statement is empty. Please check your SQL."));
3212
      return new Pair<>(null, analysis);
×
3213
    }
3214
    if (queryAnalysis.useLogicalView()) {
×
3215
      analysis.setFinishQueryAfterAnalyze(true);
×
3216
      analysis.setFailStatus(
×
3217
          RpcUtils.getStatus(
×
3218
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3219
              "Can not create a view based on existing views. Check the query in your SQL."));
3220
      return new Pair<>(null, analysis);
×
3221
    }
3222
    List<Expression> expressionList = new ArrayList<>();
×
3223
    for (Pair<Expression, String> thisPair : outputExpressions) {
×
3224
      expressionList.add(thisPair.left);
×
3225
    }
×
3226
    return new Pair<>(expressionList, analysis);
×
3227
  }
3228

3229
  private void checkViewsInSource(
3230
      Analysis analysis, List<Expression> sourceExpressionList, MPPQueryContext context) {
3231
    List<PartialPath> pathsNeedCheck = new ArrayList<>();
×
3232
    for (Expression expression : sourceExpressionList) {
×
3233
      if (expression instanceof TimeSeriesOperand) {
×
3234
        pathsNeedCheck.add(((TimeSeriesOperand) expression).getPath());
×
3235
      }
3236
    }
×
3237
    Pair<ISchemaTree, Integer> schemaOfNeedToCheck =
×
3238
        fetchSchemaOfPathsAndCount(pathsNeedCheck, analysis, context);
×
3239
    if (schemaOfNeedToCheck.right != pathsNeedCheck.size()) {
×
3240
      // some source paths is not exist, and could not fetch schema.
3241
      analysis.setFinishQueryAfterAnalyze(true);
×
3242
      analysis.setFailStatus(
×
3243
          RpcUtils.getStatus(
×
3244
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3245
              "Can not create a view based on non-exist time series."));
3246
      return;
×
3247
    }
3248
    Pair<List<PartialPath>, PartialPath> viewInSourceCheckResult =
×
3249
        findAllViewsInPaths(pathsNeedCheck, schemaOfNeedToCheck.left);
×
3250
    if (viewInSourceCheckResult.right != null) {
×
3251
      // some source paths is not exist
3252
      analysis.setFinishQueryAfterAnalyze(true);
×
3253
      analysis.setFailStatus(
×
3254
          RpcUtils.getStatus(
×
3255
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3256
              "Path "
3257
                  + viewInSourceCheckResult.right.toString()
×
3258
                  + " does not exist! You can not create a view based on non-exist time series."));
3259
      return;
×
3260
    }
3261
    if (!viewInSourceCheckResult.left.isEmpty()) {
×
3262
      // some source paths is logical view
3263
      analysis.setFinishQueryAfterAnalyze(true);
×
3264
      analysis.setFailStatus(
×
3265
          RpcUtils.getStatus(
×
3266
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3267
              "Can not create a view based on existing views."));
3268
    }
3269
  }
×
3270

3271
  private void checkPathsInCreateLogicalView(
3272
      Analysis analysis, CreateLogicalViewStatement createLogicalViewStatement) {
3273
    Pair<Boolean, String> checkResult = createLogicalViewStatement.checkAllPaths();
×
3274
    if (Boolean.FALSE.equals(checkResult.left)) {
×
3275
      analysis.setFinishQueryAfterAnalyze(true);
×
3276
      analysis.setFailStatus(
×
3277
          RpcUtils.getStatus(
×
3278
              TSStatusCode.ILLEGAL_PATH.getStatusCode(),
×
3279
              "The path " + checkResult.right + " is illegal."));
3280
      return;
×
3281
    }
3282
    // make sure there are no redundant paths in targets. Please note that redundant paths in source
3283
    // are legal!
3284
    List<PartialPath> targetPathList = createLogicalViewStatement.getTargetPathList();
×
3285
    Set<String> targetStringSet = new HashSet<>();
×
3286
    for (PartialPath path : targetPathList) {
×
3287
      boolean repeatPathNotExist = targetStringSet.add(path.toString());
×
3288
      if (!repeatPathNotExist) {
×
3289
        analysis.setFinishQueryAfterAnalyze(true);
×
3290
        analysis.setFailStatus(
×
3291
            RpcUtils.getStatus(
×
3292
                TSStatusCode.ILLEGAL_PATH.getStatusCode(),
×
3293
                String.format("Path [%s] is redundant in target paths.", path)));
×
3294
        return;
×
3295
      }
3296
    }
×
3297
    if (createLogicalViewStatement.getSourceExpressionList().size() != targetPathList.size()) {
×
3298
      analysis.setFinishQueryAfterAnalyze(true);
×
3299
      analysis.setFailStatus(
×
3300
          RpcUtils.getStatus(
×
3301
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3302
              String.format(
×
3303
                  "The number of target paths (%d) and sources (%d) are miss matched! Please check your SQL.",
3304
                  createLogicalViewStatement.getTargetPathList().size(),
×
3305
                  createLogicalViewStatement.getSourceExpressionList().size())));
×
3306
      return;
×
3307
    }
3308
    // make sure all paths are NOt under any template
3309
    try {
3310
      for (PartialPath path : createLogicalViewStatement.getTargetPathList()) {
×
3311
        checkIsTemplateCompatible(path, null);
×
3312
      }
×
3313
    } catch (Exception e) {
×
3314
      analysis.setFinishQueryAfterAnalyze(true);
×
3315
      analysis.setFailStatus(
×
3316
          RpcUtils.getStatus(
×
3317
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3318
              "Can not create view under template."));
3319
    }
×
3320
  }
×
3321

3322
  // create Logical View
3323
  @Override
3324
  public Analysis visitCreateLogicalView(
3325
      CreateLogicalViewStatement createLogicalViewStatement, MPPQueryContext context) {
3326
    Analysis analysis = new Analysis();
×
3327
    context.setQueryType(QueryType.WRITE);
×
3328
    analysis.setStatement(createLogicalViewStatement);
×
3329

3330
    if (createLogicalViewStatement.getViewExpression() == null) {
×
3331
      // analyze query in statement
3332
      QueryStatement queryStatement = createLogicalViewStatement.getQueryStatement();
×
3333
      if (queryStatement != null) {
×
3334
        Pair<List<Expression>, Analysis> queryAnalysisPair =
×
3335
            this.analyzeQueryInLogicalViewStatement(analysis, queryStatement, context);
×
3336
        if (queryAnalysisPair.right.isFinishQueryAfterAnalyze()) {
×
3337
          return analysis;
×
3338
        } else if (queryAnalysisPair.left != null) {
×
3339
          try {
3340
            createLogicalViewStatement.setSourceExpressions(queryAnalysisPair.left);
×
3341
          } catch (UnsupportedViewException e) {
×
3342
            analysis.setFinishQueryAfterAnalyze(true);
×
3343
            analysis.setFailStatus(RpcUtils.getStatus(e.getErrorCode(), e.getMessage()));
×
3344
            return analysis;
×
3345
          }
×
3346
        }
3347
      }
3348
    }
3349

3350
    // use source and into item to generate target views
3351
    createLogicalViewStatement.parseIntoItemIfNecessary();
×
3352

3353
    // check target paths; check source expressions.
3354
    checkPathsInCreateLogicalView(analysis, createLogicalViewStatement);
×
3355
    if (analysis.isFinishQueryAfterAnalyze()) {
×
3356
      return analysis;
×
3357
    }
3358

3359
    // make sure there is no view in source
3360
    List<Expression> sourceExpressionList = createLogicalViewStatement.getSourceExpressionList();
×
3361
    checkViewsInSource(analysis, sourceExpressionList, context);
×
3362
    if (analysis.isFinishQueryAfterAnalyze()) {
×
3363
      return analysis;
×
3364
    }
3365

3366
    // set schema partition info, this info will be used to split logical plan node.
3367
    PathPatternTree patternTree = new PathPatternTree();
×
3368
    for (PartialPath thisFullPath : createLogicalViewStatement.getTargetPathList()) {
×
3369
      patternTree.appendFullPath(thisFullPath);
×
3370
    }
×
3371
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3372
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
3373

3374
    return analysis;
×
3375
  }
3376

3377
  @Override
3378
  public Analysis visitShowLogicalView(
3379
      ShowLogicalViewStatement showLogicalViewStatement, MPPQueryContext context) {
3380
    context.setQueryType(QueryType.READ);
×
3381
    Analysis analysis = new Analysis();
×
3382
    analysis.setStatement(showLogicalViewStatement);
×
3383

3384
    PathPatternTree patternTree = new PathPatternTree();
×
3385
    patternTree.appendPathPattern(showLogicalViewStatement.getPathPattern());
×
3386
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
3387
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
3388

3389
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowLogicalViewHeader());
×
3390
    return analysis;
×
3391
  }
3392
  // endregion view
3393
}
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