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

apache / iotdb / #9890

22 Aug 2023 09:07AM UTC coverage: 47.922% (-0.07%) from 47.992%
#9890

push

travis_ci

web-flow
[IOTDB-6114] Pipe: Support multi-cluster data sync (#10868)(#10926)

306 of 306 new or added lines in 33 files covered. (100.0%)

79862 of 166649 relevant lines covered (47.92%)

0.48 hits per line

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

43.69
/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.HashMap;
160
import java.util.HashSet;
161
import java.util.Iterator;
162
import java.util.LinkedHashMap;
163
import java.util.LinkedHashSet;
164
import java.util.LinkedList;
165
import java.util.List;
166
import java.util.Locale;
167
import java.util.Map;
168
import java.util.Objects;
169
import java.util.Set;
170
import java.util.TimeZone;
171
import java.util.stream.Collectors;
172

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

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

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

192
  private static final IoTDBConfig CONFIG = IoTDBDescriptor.getInstance().getConfig();
1✔
193

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

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

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

203
  private final IPartitionFetcher partitionFetcher;
204
  private final ISchemaFetcher schemaFetcher;
205

206
  private static final PerformanceOverviewMetrics PERFORMANCE_OVERVIEW_METRICS =
1✔
207
      PerformanceOverviewMetrics.getInstance();
1✔
208

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

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

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

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

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

242
      // extract global time filter from query filter and determine if there is a value filter
243
      analyzeGlobalTimeFilter(analysis, queryStatement);
1✔
244

245
      if (queryStatement.isLastQuery()) {
1✔
246
        return analyzeLastQuery(queryStatement, analysis, schemaTree);
×
247
      }
248

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

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

259
        analyzeDeviceToGroupBy(analysis, queryStatement, schemaTree, deviceSet);
1✔
260
        analyzeDeviceToOrderBy(analysis, queryStatement, schemaTree, deviceSet);
1✔
261
        analyzeHaving(analysis, queryStatement, schemaTree, deviceSet);
1✔
262

263
        analyzeDeviceToAggregation(analysis, queryStatement);
1✔
264
        analyzeDeviceToSourceTransform(analysis, queryStatement);
1✔
265
        analyzeDeviceToSource(analysis, queryStatement);
1✔
266

267
        analyzeDeviceViewOutput(analysis, queryStatement);
1✔
268
        analyzeDeviceViewInput(analysis, queryStatement);
1✔
269

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

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

282
        analyzeGroupBy(analysis, queryStatement, schemaTree);
1✔
283
        analyzeHaving(analysis, queryStatement, schemaTree);
1✔
284
        analyzeOrderBy(analysis, queryStatement, schemaTree);
1✔
285

286
        analyzeGroupByLevel(analysis, queryStatement, outputExpressionMap, outputExpressions);
1✔
287
        analyzeGroupByTag(analysis, queryStatement, outputExpressions);
1✔
288

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

298
        analyzeAggregation(analysis, queryStatement);
1✔
299

300
        analyzeWhere(analysis, queryStatement, schemaTree);
1✔
301
        analyzeSourceTransform(analysis, queryStatement);
1✔
302

303
        analyzeSource(analysis, queryStatement);
1✔
304

305
        analyzeInto(analysis, queryStatement, outputExpressions);
1✔
306
      }
307

308
      analyzeGroupByTime(analysis, queryStatement);
1✔
309

310
      analyzeFill(analysis, queryStatement);
1✔
311

312
      // generate result set header according to output expressions
313
      analyzeOutput(analysis, queryStatement, outputExpressions);
1✔
314

315
      // fetch partition information
316
      analyzeDataPartition(analysis, queryStatement, schemaTree);
1✔
317

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

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

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

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

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

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

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

381
      predicate = ExpressionAnalyzer.evaluatePredicate(predicate);
1✔
382

383
      // set where condition to null if predicate is true or time filter.
384
      if (!hasValueFilter
1✔
385
          || (predicate.getExpressionType().equals(ExpressionType.CONSTANT)
1✔
386
              && Boolean.parseBoolean(predicate.getExpressionString()))) {
×
387
        queryStatement.setWhereCondition(null);
1✔
388
      } else {
389
        whereCondition.setPredicate(predicate);
1✔
390
      }
391
    }
392
    if (queryStatement.isGroupByTime()) {
1✔
393
      GroupByTimeComponent groupByTimeComponent = queryStatement.getGroupByTimeComponent();
1✔
394
      Filter groupByFilter = initGroupByFilter(groupByTimeComponent);
1✔
395
      if (globalTimeFilter == null) {
1✔
396
        globalTimeFilter = groupByFilter;
1✔
397
      } else {
398
        globalTimeFilter = FilterFactory.and(globalTimeFilter, groupByFilter);
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 Set<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 LinkedHashSet<>();
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
    return deviceSet;
1✔
552
  }
553

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

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

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

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

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

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

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

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

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

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

628
    // remove devices without measurements to compute
629
    deviceSet.removeAll(noMeasurementDevices);
1✔
630

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

638
    analysis.setDeviceToSelectExpressions(deviceToSelectExpressions);
1✔
639

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

652
    return outputExpressions;
1✔
653
  }
654

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

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

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

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

693
    if (!Objects.equals(normalizedExpression, rawExpression)) {
1✔
694
      return rawExpression.getOutputSymbol();
1✔
695
    }
696
    return null;
1✔
697
  }
698

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

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

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

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

741
    Expression havingExpression = queryStatement.getHavingCondition().getPredicate();
1✔
742
    Set<Expression> conJunctions = new HashSet<>();
1✔
743

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

749
      conJunctions.addAll(
1✔
750
          expressionsInHaving.stream()
1✔
751
              .map(expression -> ExpressionAnalyzer.getMeasurementExpression(expression, analysis))
1✔
752
              .collect(Collectors.toList()));
1✔
753

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

762
          analyzeExpressionType(analysis, aggregationExpression);
1✔
763
          analyzeExpressionType(analysis, normalizedAggregationExpression);
1✔
764

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

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

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

798
    GroupByLevelController groupByLevelController =
×
799
        new GroupByLevelController(queryStatement.getGroupByLevelComponent().getLevels());
×
800

801
    List<Expression> groupedSelectExpressions = new LinkedList<>();
×
802

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

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

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

858
    checkDataTypeConsistencyInGroupByLevel(analysis, groupByLevelExpressions);
×
859
    analysis.setCrossGroupByExpressions(groupByLevelExpressions);
×
860
  }
×
861

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

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

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

895
      analyzeExpressionType(analysis, groupedAggregationExpressionWithoutAlias);
×
896
      groupedExpressionSet.forEach(
×
897
          groupedExpression -> analyzeExpressionType(analysis, groupedExpression));
×
898

899
      groupByLevelExpressions
×
900
          .computeIfAbsent(groupedAggregationExpressionWithoutAlias, key -> new HashSet<>())
×
901
          .addAll(groupedExpressionSet);
×
902
    }
×
903
  }
×
904

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

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

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

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

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

967
  private void analyzeDeviceToAggregation(Analysis analysis, QueryStatement queryStatement) {
968
    if (!queryStatement.isAggregationQuery()) {
1✔
969
      return;
1✔
970
    }
971

972
    updateDeviceToAggregationAndOutputExpressions(
1✔
973
        analysis, analysis.getDeviceToSelectExpressions());
1✔
974
    if (queryStatement.hasOrderByExpression()) {
1✔
975
      updateDeviceToAggregationAndOutputExpressions(
1✔
976
          analysis, analysis.getDeviceToOrderByExpressions());
1✔
977
    }
978
  }
1✔
979

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

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

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

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

1015
  private void analyzeAggregation(Analysis analysis, QueryStatement queryStatement) {
1016
    if (!queryStatement.isAggregationQuery()) {
1✔
1017
      return;
1✔
1018
    }
1019

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

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

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

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

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

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

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

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

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

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

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

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

1171
    analysis.setDeviceToSourceExpressions(deviceToSourceExpressions);
1✔
1172
    analysis.setOutputDeviceToQueriedDevicesMap(outputDeviceToQueriedDevicesMap);
1✔
1173
  }
1✔
1174

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

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

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

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

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

1222
      deviceToWhereExpression.put(devicePath.getFullPath(), whereExpression);
1✔
1223
    }
1✔
1224
    analysis.setDeviceToWhereExpression(deviceToWhereExpression);
1✔
1225
  }
1✔
1226

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

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

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

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

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

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

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

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

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

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

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

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

1392
  // For last query
1393
  private void analyzeLastOrderBy(Analysis analysis, QueryStatement queryStatement) {
1394
    if (!queryStatement.hasOrderBy()) return;
×
1395

1396
    if (queryStatement.onlyOrderByTimeseries()) {
×
1397
      analysis.setTimeseriesOrderingForLastQuery(
×
1398
          queryStatement.getOrderByComponent().getTimeseriesOrder());
×
1399
    }
1400

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

1411
  private void analyzeOrderBy(
1412
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1413
    if (!queryStatement.hasOrderByExpression()) return;
1✔
1414

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

1443
  private TSDataType analyzeExpressionType(Analysis analysis, Expression expression) {
1444
    return ExpressionTypeAnalyzer.analyzeExpression(analysis, expression);
1✔
1445
  }
1446

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

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

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

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

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

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

1557
        Expression deviceViewExpression =
1✔
1558
            ExpressionAnalyzer.getMeasurementExpression(expressionForItem, analysis);
1✔
1559
        analyzeExpressionType(analysis, deviceViewExpression);
1✔
1560

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

1569
    analysis.setOrderByExpressions(deviceViewOrderByExpression);
1✔
1570
    queryStatement.updateSortItems(deviceViewOrderByExpression);
1✔
1571
    analysis.setDeviceToSortItems(deviceToSortItems);
1✔
1572
    analysis.setDeviceToOrderByExpressions(deviceToOrderByExpressions);
1✔
1573
  }
1✔
1574

1575
  private void analyzeGroupBy(
1576
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1577

1578
    if (queryStatement.getGroupByComponent() == null) {
1✔
1579
      return;
1✔
1580
    }
1581
    GroupByComponent groupByComponent = queryStatement.getGroupByComponent();
×
1582
    WindowType windowType = groupByComponent.getWindowType();
×
1583

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

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

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

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

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

1679
  private void analyzeGroupByTime(Analysis analysis, QueryStatement queryStatement) {
1680
    if (!queryStatement.isGroupByTime()) {
1✔
1681
      return;
1✔
1682
    }
1683

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

1697
  private void analyzeFill(Analysis analysis, QueryStatement queryStatement) {
1698
    if (queryStatement.getFillComponent() == null) {
1✔
1699
      return;
1✔
1700
    }
1701

1702
    FillComponent fillComponent = queryStatement.getFillComponent();
1✔
1703
    analysis.setFillDescriptor(
1✔
1704
        new FillDescriptor(fillComponent.getFillPolicy(), fillComponent.getFillValue()));
1✔
1705
  }
1✔
1706

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

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

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

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

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

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

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

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

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

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

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

1861
    IntoComponent intoComponent = queryStatement.getIntoComponent();
1✔
1862
    intoComponent.validate(sourceDevices, sourceColumns);
1✔
1863

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

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

1887
        targetPathTree.appendFullPath(targetDevice, targetMeasurement);
1✔
1888
        deviceViewIntoPathDescriptor.recordSourceColumnDataType(
1✔
1889
            sourceColumn.getExpressionString(), analysis.getType(sourceColumn));
1✔
1890

1891
        intoDeviceMeasurementIterator.nextMeasurement();
1✔
1892
      }
1✔
1893

1894
      intoDeviceMeasurementIterator.nextDevice();
1✔
1895
    }
1✔
1896
    deviceViewIntoPathDescriptor.validate();
1✔
1897

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

1905
    analysis.setDeviceViewIntoPathDescriptor(deviceViewIntoPathDescriptor);
1✔
1906
  }
1✔
1907

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

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

1922
    IntoComponent intoComponent = queryStatement.getIntoComponent();
1✔
1923
    intoComponent.validate(sourceColumns);
1✔
1924

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

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

1958
      targetPathTree.appendFullPath(targetPath);
1✔
1959
      intoPathDescriptor.recordSourceColumnDataType(
1✔
1960
          sourceColumn, analysis.getType(sourceExpression));
1✔
1961

1962
      intoPathIterator.next();
1✔
1963
    }
1✔
1964
    intoPathDescriptor.validate();
1✔
1965

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

1974
    analysis.setIntoPathDescriptor(intoPathDescriptor);
1✔
1975
  }
1✔
1976

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

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

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

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

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

2080
    Analysis analysis = new Analysis();
×
2081
    analysis.setStatement(createTimeSeriesStatement);
×
2082

2083
    checkIsTemplateCompatible(
×
2084
        createTimeSeriesStatement.getPath(), createTimeSeriesStatement.getAlias());
×
2085

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

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

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

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

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

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

2166
    Analysis analysis = new Analysis();
×
2167
    analysis.setStatement(createAlignedTimeSeriesStatement);
×
2168

2169
    checkIsTemplateCompatible(
×
2170
        createAlignedTimeSeriesStatement.getDevicePath(),
×
2171
        createAlignedTimeSeriesStatement.getMeasurements(),
×
2172
        createAlignedTimeSeriesStatement.getAliasList());
×
2173

2174
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2175
    for (String measurement : createAlignedTimeSeriesStatement.getMeasurements()) {
×
2176
      pathPatternTree.appendFullPath(createAlignedTimeSeriesStatement.getDevicePath(), measurement);
×
2177
    }
×
2178

2179
    SchemaPartition schemaPartitionInfo;
2180
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2181
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2182
    return analysis;
×
2183
  }
2184

2185
  @Override
2186
  public Analysis visitInternalCreateTimeseries(
2187
      InternalCreateTimeSeriesStatement internalCreateTimeSeriesStatement,
2188
      MPPQueryContext context) {
2189
    context.setQueryType(QueryType.WRITE);
×
2190

2191
    Analysis analysis = new Analysis();
×
2192
    analysis.setStatement(internalCreateTimeSeriesStatement);
×
2193

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

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

2206
  @Override
2207
  public Analysis visitInternalCreateMultiTimeSeries(
2208
      InternalCreateMultiTimeSeriesStatement internalCreateMultiTimeSeriesStatement,
2209
      MPPQueryContext context) {
2210
    context.setQueryType(QueryType.WRITE);
×
2211

2212
    Analysis analysis = new Analysis();
×
2213
    analysis.setStatement(internalCreateMultiTimeSeriesStatement);
×
2214

2215
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2216
    for (PartialPath devicePath : internalCreateMultiTimeSeriesStatement.getDeviceMap().keySet()) {
×
2217
      pathPatternTree.appendFullPath(devicePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
2218
    }
×
2219

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

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

2233
    analyzeSchemaProps(createMultiTimeSeriesStatement.getPropsList());
×
2234

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

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

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

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

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

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

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

2299
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
×
2300
    } else {
2301
      return computeAnalysisForMultiTablets(analysis, (InsertMultiTabletsStatement) realStatement);
×
2302
    }
2303
  }
2304

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

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

2323
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
×
2324
    } else {
2325
      return computeAnalysisForInsertRows(analysis, (InsertRowsStatement) realInsertStatement);
×
2326
    }
2327
  }
2328

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

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

2347
    return getAnalysisForWriting(analysis, dataPartitionQueryParams);
×
2348
  }
2349

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

2363
    return computeAnalysisForInsertRows(analysis, realInsertRowsStatement);
×
2364
  }
2365

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

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

2385
    return getAnalysisForWriting(analysis, dataPartitionQueryParams);
×
2386
  }
2387

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

2401
    return computeAnalysisForMultiTablets(analysis, realStatement);
×
2402
  }
2403

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

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

2424
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
1✔
2425
    } else {
2426
      return computeAnalysisForInsertRows(analysis, (InsertRowsStatement) realInsertStatement);
×
2427
    }
2428
  }
2429

2430
  @Override
2431
  public Analysis visitPipeEnrichedInsert(
2432
      PipeEnrichedInsertBaseStatement pipeEnrichedInsertBaseStatement, MPPQueryContext context) {
2433
    Analysis analysis;
2434

2435
    final InsertBaseStatement insertBaseStatement =
×
2436
        pipeEnrichedInsertBaseStatement.getInsertBaseStatement();
×
2437
    if (insertBaseStatement instanceof InsertTabletStatement) {
×
2438
      analysis = visitInsertTablet((InsertTabletStatement) insertBaseStatement, context);
×
2439
    } else if (insertBaseStatement instanceof InsertMultiTabletsStatement) {
×
2440
      analysis =
×
2441
          visitInsertMultiTablets((InsertMultiTabletsStatement) insertBaseStatement, context);
×
2442
    } else if (insertBaseStatement instanceof InsertRowStatement) {
×
2443
      analysis = visitInsertRow((InsertRowStatement) insertBaseStatement, context);
×
2444
    } else if (insertBaseStatement instanceof InsertRowsStatement) {
×
2445
      analysis = visitInsertRows((InsertRowsStatement) insertBaseStatement, context);
×
2446
    } else if (insertBaseStatement instanceof InsertRowsOfOneDeviceStatement) {
×
2447
      analysis =
×
2448
          visitInsertRowsOfOneDevice((InsertRowsOfOneDeviceStatement) insertBaseStatement, context);
×
2449
    } else {
2450
      throw new UnsupportedOperationException(
×
2451
          "Unsupported insert statement type: " + insertBaseStatement.getClass().getName());
×
2452
    }
2453

2454
    // statement may be changed because of logical view
2455
    pipeEnrichedInsertBaseStatement.setInsertBaseStatement(
×
2456
        (InsertBaseStatement) analysis.getStatement());
×
2457
    analysis.setStatement(pipeEnrichedInsertBaseStatement);
×
2458
    return analysis;
×
2459
  }
2460

2461
  private void validateSchema(
2462
      Analysis analysis, InsertBaseStatement insertStatement, MPPQueryContext context) {
2463
    final long startTime = System.nanoTime();
1✔
2464
    try {
2465
      SchemaValidator.validate(schemaFetcher, insertStatement, context);
1✔
2466
    } catch (SemanticException e) {
×
2467
      analysis.setFinishQueryAfterAnalyze(true);
×
2468
      if (e.getCause() instanceof IoTDBException) {
×
2469
        IoTDBException exception = (IoTDBException) e.getCause();
×
2470
        analysis.setFailStatus(
×
2471
            RpcUtils.getStatus(exception.getErrorCode(), exception.getMessage()));
×
2472
      } else {
×
2473
        analysis.setFailStatus(RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage()));
×
2474
      }
2475
    } finally {
2476
      PERFORMANCE_OVERVIEW_METRICS.recordScheduleSchemaValidateCost(System.nanoTime() - startTime);
1✔
2477
    }
2478
    boolean hasFailedMeasurement = insertStatement.hasFailedMeasurements();
1✔
2479
    String partialInsertMessage;
2480
    if (hasFailedMeasurement) {
1✔
2481
      partialInsertMessage =
×
2482
          String.format(
×
2483
              "Fail to insert measurements %s caused by %s",
2484
              insertStatement.getFailedMeasurements(), insertStatement.getFailedMessages());
×
2485
      logger.warn(partialInsertMessage);
×
2486
      analysis.setFailStatus(
×
2487
          RpcUtils.getStatus(TSStatusCode.METADATA_ERROR.getStatusCode(), partialInsertMessage));
×
2488
    }
2489
  }
1✔
2490

2491
  private InsertBaseStatement removeLogicalView(
2492
      Analysis analysis, InsertBaseStatement insertBaseStatement) {
2493
    try {
2494
      return insertBaseStatement.removeLogicalView();
1✔
2495
    } catch (SemanticException e) {
×
2496
      analysis.setFinishQueryAfterAnalyze(true);
×
2497
      if (e.getCause() instanceof IoTDBException) {
×
2498
        IoTDBException exception = (IoTDBException) e.getCause();
×
2499
        analysis.setFailStatus(
×
2500
            RpcUtils.getStatus(exception.getErrorCode(), exception.getMessage()));
×
2501
      } else {
×
2502
        analysis.setFailStatus(RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage()));
×
2503
      }
2504
      return insertBaseStatement;
×
2505
    }
2506
  }
2507

2508
  @Override
2509
  public Analysis visitLoadFile(LoadTsFileStatement loadTsFileStatement, MPPQueryContext context) {
2510
    return new LoadTsfileAnalyzer(loadTsFileStatement, context, partitionFetcher, schemaFetcher)
×
2511
        .analyzeFileByFile();
×
2512
  }
2513

2514
  @Override
2515
  public Analysis visitPipeEnrichedLoadFile(
2516
      PipeEnrichedLoadTsFileStatement pipeEnrichedLoadTsFileStatement, MPPQueryContext context) {
2517
    final Analysis analysis =
×
2518
        visitLoadFile(pipeEnrichedLoadTsFileStatement.getLoadTsFileStatement(), context);
×
2519
    analysis.setStatement(pipeEnrichedLoadTsFileStatement);
×
2520
    return analysis;
×
2521
  }
2522

2523
  /** get analysis according to statement and params */
2524
  private Analysis getAnalysisForWriting(
2525
      Analysis analysis, List<DataPartitionQueryParam> dataPartitionQueryParams) {
2526

2527
    DataPartition dataPartition =
1✔
2528
        partitionFetcher.getOrCreateDataPartition(dataPartitionQueryParams);
1✔
2529
    if (dataPartition.isEmpty()) {
1✔
2530
      analysis.setFinishQueryAfterAnalyze(true);
×
2531
      analysis.setFailStatus(
×
2532
          RpcUtils.getStatus(
×
2533
              TSStatusCode.DATABASE_NOT_EXIST.getStatusCode(),
×
2534
              "Database not exists and failed to create automatically "
2535
                  + "because enable_auto_create_schema is FALSE."));
2536
    }
2537
    analysis.setDataPartitionInfo(dataPartition);
1✔
2538
    return analysis;
1✔
2539
  }
2540

2541
  @Override
2542
  public Analysis visitShowTimeSeries(
2543
      ShowTimeSeriesStatement showTimeSeriesStatement, MPPQueryContext context) {
2544
    Analysis analysis = new Analysis();
×
2545
    analysis.setStatement(showTimeSeriesStatement);
×
2546

2547
    PathPatternTree patternTree = new PathPatternTree();
×
2548
    patternTree.appendPathPattern(showTimeSeriesStatement.getPathPattern());
×
2549
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2550
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2551

2552
    Map<Integer, Template> templateMap =
×
2553
        schemaFetcher.checkAllRelatedTemplate(showTimeSeriesStatement.getPathPattern());
×
2554
    analysis.setRelatedTemplateInfo(templateMap);
×
2555

2556
    if (showTimeSeriesStatement.isOrderByHeat()) {
×
2557
      patternTree.constructTree();
×
2558
      // request schema fetch API
2559
      logger.debug("[StartFetchSchema]");
×
2560
      ISchemaTree schemaTree = schemaFetcher.fetchSchema(patternTree, context);
×
2561
      updateSchemaTreeByViews(analysis, schemaTree);
×
2562
      logger.debug("[EndFetchSchema]]");
×
2563

2564
      analyzeLastSource(
×
2565
          analysis,
2566
          Collections.singletonList(
×
2567
              new TimeSeriesOperand(showTimeSeriesStatement.getPathPattern())),
×
2568
          schemaTree);
2569
      analyzeDataPartition(analysis, new QueryStatement(), schemaTree);
×
2570
    }
2571

2572
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTimeSeriesHeader());
×
2573
    return analysis;
×
2574
  }
2575

2576
  @Override
2577
  public Analysis visitShowStorageGroup(
2578
      ShowDatabaseStatement showDatabaseStatement, MPPQueryContext context) {
2579
    Analysis analysis = new Analysis();
×
2580
    analysis.setStatement(showDatabaseStatement);
×
2581
    analysis.setRespDatasetHeader(
×
2582
        DatasetHeaderFactory.getShowStorageGroupHeader(showDatabaseStatement.isDetailed()));
×
2583
    return analysis;
×
2584
  }
2585

2586
  @Override
2587
  public Analysis visitShowTTL(ShowTTLStatement showTTLStatement, MPPQueryContext context) {
2588
    Analysis analysis = new Analysis();
×
2589
    analysis.setStatement(showTTLStatement);
×
2590
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTTLHeader());
×
2591
    return analysis;
×
2592
  }
2593

2594
  @Override
2595
  public Analysis visitShowDevices(
2596
      ShowDevicesStatement showDevicesStatement, MPPQueryContext context) {
2597
    Analysis analysis = new Analysis();
×
2598
    analysis.setStatement(showDevicesStatement);
×
2599

2600
    PathPatternTree patternTree = new PathPatternTree();
×
2601
    patternTree.appendPathPattern(
×
2602
        showDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD));
×
2603
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2604

2605
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2606
    analysis.setRespDatasetHeader(
×
2607
        showDevicesStatement.hasSgCol()
×
2608
            ? DatasetHeaderFactory.getShowDevicesWithSgHeader()
×
2609
            : DatasetHeaderFactory.getShowDevicesHeader());
×
2610
    return analysis;
×
2611
  }
2612

2613
  @Override
2614
  public Analysis visitShowCluster(
2615
      ShowClusterStatement showClusterStatement, MPPQueryContext context) {
2616
    Analysis analysis = new Analysis();
×
2617
    analysis.setStatement(showClusterStatement);
×
2618
    if (showClusterStatement.isDetails()) {
×
2619
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowClusterDetailsHeader());
×
2620
    } else {
2621
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowClusterHeader());
×
2622
    }
2623
    return analysis;
×
2624
  }
2625

2626
  @Override
2627
  public Analysis visitCountStorageGroup(
2628
      CountDatabaseStatement countDatabaseStatement, MPPQueryContext context) {
2629
    Analysis analysis = new Analysis();
×
2630
    analysis.setStatement(countDatabaseStatement);
×
2631
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountStorageGroupHeader());
×
2632
    return analysis;
×
2633
  }
2634

2635
  @Override
2636
  public Analysis visitSchemaFetch(
2637
      SchemaFetchStatement schemaFetchStatement, MPPQueryContext context) {
2638
    Analysis analysis = new Analysis();
×
2639
    analysis.setStatement(schemaFetchStatement);
×
2640

2641
    SchemaPartition schemaPartition =
×
2642
        partitionFetcher.getSchemaPartition(schemaFetchStatement.getPatternTree());
×
2643
    analysis.setSchemaPartitionInfo(schemaPartition);
×
2644

2645
    if (schemaPartition.isEmpty()) {
×
2646
      analysis.setFinishQueryAfterAnalyze(true);
×
2647
    }
2648

2649
    return analysis;
×
2650
  }
2651

2652
  @Override
2653
  public Analysis visitCountDevices(
2654
      CountDevicesStatement countDevicesStatement, MPPQueryContext context) {
2655
    Analysis analysis = new Analysis();
×
2656
    analysis.setStatement(countDevicesStatement);
×
2657

2658
    PathPatternTree patternTree = new PathPatternTree();
×
2659
    patternTree.appendPathPattern(
×
2660
        countDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD));
×
2661
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2662

2663
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2664
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountDevicesHeader());
×
2665
    return analysis;
×
2666
  }
2667

2668
  @Override
2669
  public Analysis visitCountTimeSeries(
2670
      CountTimeSeriesStatement countTimeSeriesStatement, MPPQueryContext context) {
2671
    Analysis analysis = new Analysis();
×
2672
    analysis.setStatement(countTimeSeriesStatement);
×
2673

2674
    PathPatternTree patternTree = new PathPatternTree();
×
2675
    patternTree.appendPathPattern(countTimeSeriesStatement.getPathPattern());
×
2676
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2677
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2678

2679
    Map<Integer, Template> templateMap =
×
2680
        schemaFetcher.checkAllRelatedTemplate(countTimeSeriesStatement.getPathPattern());
×
2681
    analysis.setRelatedTemplateInfo(templateMap);
×
2682

2683
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountTimeSeriesHeader());
×
2684
    return analysis;
×
2685
  }
2686

2687
  @Override
2688
  public Analysis visitCountLevelTimeSeries(
2689
      CountLevelTimeSeriesStatement countLevelTimeSeriesStatement, MPPQueryContext context) {
2690
    Analysis analysis = new Analysis();
×
2691
    analysis.setStatement(countLevelTimeSeriesStatement);
×
2692

2693
    PathPatternTree patternTree = new PathPatternTree();
×
2694
    patternTree.appendPathPattern(countLevelTimeSeriesStatement.getPathPattern());
×
2695
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2696

2697
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2698
    Map<Integer, Template> templateMap =
×
2699
        schemaFetcher.checkAllRelatedTemplate(countLevelTimeSeriesStatement.getPathPattern());
×
2700
    analysis.setRelatedTemplateInfo(templateMap);
×
2701
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountLevelTimeSeriesHeader());
×
2702
    return analysis;
×
2703
  }
2704

2705
  @Override
2706
  public Analysis visitCountNodes(CountNodesStatement countStatement, MPPQueryContext context) {
2707
    Analysis analysis = new Analysis();
×
2708
    analysis.setStatement(countStatement);
×
2709

2710
    PathPatternTree patternTree = new PathPatternTree();
×
2711
    patternTree.appendPathPattern(countStatement.getPathPattern());
×
2712
    SchemaNodeManagementPartition schemaNodeManagementPartition =
×
2713
        partitionFetcher.getSchemaNodeManagementPartitionWithLevel(
×
2714
            patternTree, countStatement.getLevel());
×
2715

2716
    if (schemaNodeManagementPartition == null) {
×
2717
      return analysis;
×
2718
    }
2719
    if (!schemaNodeManagementPartition.getMatchedNode().isEmpty()
×
2720
        && schemaNodeManagementPartition.getSchemaPartition().getSchemaPartitionMap().size() == 0) {
×
2721
      analysis.setFinishQueryAfterAnalyze(true);
×
2722
    }
2723
    analysis.setMatchedNodes(schemaNodeManagementPartition.getMatchedNode());
×
2724
    analysis.setSchemaPartitionInfo(schemaNodeManagementPartition.getSchemaPartition());
×
2725
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountNodesHeader());
×
2726
    return analysis;
×
2727
  }
2728

2729
  @Override
2730
  public Analysis visitShowChildPaths(
2731
      ShowChildPathsStatement showChildPathsStatement, MPPQueryContext context) {
2732
    return visitSchemaNodeManagementPartition(
×
2733
        showChildPathsStatement,
2734
        showChildPathsStatement.getPartialPath(),
×
2735
        DatasetHeaderFactory.getShowChildPathsHeader());
×
2736
  }
2737

2738
  @Override
2739
  public Analysis visitShowChildNodes(
2740
      ShowChildNodesStatement showChildNodesStatement, MPPQueryContext context) {
2741
    return visitSchemaNodeManagementPartition(
×
2742
        showChildNodesStatement,
2743
        showChildNodesStatement.getPartialPath(),
×
2744
        DatasetHeaderFactory.getShowChildNodesHeader());
×
2745
  }
2746

2747
  @Override
2748
  public Analysis visitShowVersion(
2749
      ShowVersionStatement showVersionStatement, MPPQueryContext context) {
2750
    Analysis analysis = new Analysis();
×
2751
    analysis.setStatement(showVersionStatement);
×
2752
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowVersionHeader());
×
2753
    analysis.setFinishQueryAfterAnalyze(true);
×
2754
    return analysis;
×
2755
  }
2756

2757
  private Analysis visitSchemaNodeManagementPartition(
2758
      Statement statement, PartialPath path, DatasetHeader header) {
2759
    Analysis analysis = new Analysis();
×
2760
    analysis.setStatement(statement);
×
2761

2762
    PathPatternTree patternTree = new PathPatternTree();
×
2763
    patternTree.appendPathPattern(path);
×
2764
    SchemaNodeManagementPartition schemaNodeManagementPartition =
×
2765
        partitionFetcher.getSchemaNodeManagementPartition(patternTree);
×
2766

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

2780
  @Override
2781
  public Analysis visitDeleteData(
2782
      DeleteDataStatement deleteDataStatement, MPPQueryContext context) {
2783
    context.setQueryType(QueryType.WRITE);
×
2784
    Analysis analysis = new Analysis();
×
2785
    analysis.setStatement(deleteDataStatement);
×
2786

2787
    PathPatternTree patternTree = new PathPatternTree();
×
2788
    deleteDataStatement.getPathList().forEach(patternTree::appendPathPattern);
×
2789

2790
    ISchemaTree schemaTree = schemaFetcher.fetchSchema(patternTree, context);
×
2791
    Set<String> deduplicatedDevicePaths = new HashSet<>();
×
2792

2793
    if (schemaTree.hasLogicalViewMeasurement()) {
×
2794
      updateSchemaTreeByViews(analysis, schemaTree);
×
2795

2796
      Set<PartialPath> deletePatternSet = new HashSet<>(deleteDataStatement.getPathList());
×
2797
      IMeasurementSchema measurementSchema;
2798
      LogicalViewSchema logicalViewSchema;
2799
      PartialPath sourcePathOfAliasSeries;
2800
      for (MeasurementPath measurementPath :
2801
          schemaTree.searchMeasurementPaths(SchemaConstant.ALL_MATCH_PATTERN).left) {
×
2802
        measurementSchema = measurementPath.getMeasurementSchema();
×
2803
        if (measurementSchema.isLogicalView()) {
×
2804
          logicalViewSchema = (LogicalViewSchema) measurementSchema;
×
2805
          if (logicalViewSchema.isWritable()) {
×
2806
            sourcePathOfAliasSeries = logicalViewSchema.getSourcePathIfWritable();
×
2807
            deletePatternSet.add(sourcePathOfAliasSeries);
×
2808
            deduplicatedDevicePaths.add(sourcePathOfAliasSeries.getDevice());
×
2809
          } else {
2810
            deletePatternSet.remove(measurementPath);
×
2811
          }
2812
        } else {
2813
          deduplicatedDevicePaths.add(measurementPath.getDevice());
×
2814
        }
2815
      }
×
2816
      deleteDataStatement.setPathList(new ArrayList<>(deletePatternSet));
×
2817
    } else {
×
2818
      for (PartialPath devicePattern : patternTree.getAllDevicePaths()) {
×
2819
        schemaTree
×
2820
            .getMatchedDevices(devicePattern)
×
2821
            .forEach(
×
2822
                deviceSchemaInfo ->
2823
                    deduplicatedDevicePaths.add(deviceSchemaInfo.getDevicePath().getFullPath()));
×
2824
      }
×
2825
    }
2826
    analysis.setSchemaTree(schemaTree);
×
2827

2828
    Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap = new HashMap<>();
×
2829

2830
    deduplicatedDevicePaths.forEach(
×
2831
        devicePath -> {
2832
          DataPartitionQueryParam queryParam = new DataPartitionQueryParam();
×
2833
          queryParam.setDevicePath(devicePath);
×
2834
          sgNameToQueryParamsMap
×
2835
              .computeIfAbsent(schemaTree.getBelongedDatabase(devicePath), key -> new ArrayList<>())
×
2836
              .add(queryParam);
×
2837
        });
×
2838

2839
    DataPartition dataPartition = partitionFetcher.getDataPartition(sgNameToQueryParamsMap);
×
2840
    analysis.setDataPartitionInfo(dataPartition);
×
2841
    analysis.setFinishQueryAfterAnalyze(dataPartition.isEmpty());
×
2842

2843
    return analysis;
×
2844
  }
2845

2846
  @Override
2847
  public Analysis visitCreateSchemaTemplate(
2848
      CreateSchemaTemplateStatement createTemplateStatement, MPPQueryContext context) {
2849

2850
    context.setQueryType(QueryType.WRITE);
×
2851
    List<String> measurements = createTemplateStatement.getMeasurements();
×
2852
    Set<String> measurementsSet = new HashSet<>(measurements);
×
2853
    if (measurementsSet.size() < measurements.size()) {
×
2854
      throw new SemanticException(
×
2855
          "Measurement under template is not allowed to have the same measurement name");
2856
    }
2857
    Analysis analysis = new Analysis();
×
2858
    analysis.setStatement(createTemplateStatement);
×
2859
    return analysis;
×
2860
  }
2861

2862
  @Override
2863
  public Analysis visitShowNodesInSchemaTemplate(
2864
      ShowNodesInSchemaTemplateStatement showNodesInSchemaTemplateStatement,
2865
      MPPQueryContext context) {
2866
    Analysis analysis = new Analysis();
×
2867
    analysis.setStatement(showNodesInSchemaTemplateStatement);
×
2868
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowNodesInSchemaTemplateHeader());
×
2869
    return analysis;
×
2870
  }
2871

2872
  @Override
2873
  public Analysis visitShowSchemaTemplate(
2874
      ShowSchemaTemplateStatement showSchemaTemplateStatement, MPPQueryContext context) {
2875
    Analysis analysis = new Analysis();
×
2876
    analysis.setStatement(showSchemaTemplateStatement);
×
2877
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowSchemaTemplateHeader());
×
2878
    return analysis;
×
2879
  }
2880

2881
  private GroupByFilter initGroupByFilter(GroupByTimeComponent groupByTimeComponent) {
2882
    if (groupByTimeComponent.isIntervalByMonth() || groupByTimeComponent.isSlidingStepByMonth()) {
1✔
2883
      return new GroupByMonthFilter(
×
2884
          groupByTimeComponent.getInterval(),
×
2885
          groupByTimeComponent.getSlidingStep(),
×
2886
          groupByTimeComponent.getStartTime(),
×
2887
          groupByTimeComponent.getEndTime(),
×
2888
          groupByTimeComponent.isSlidingStepByMonth(),
×
2889
          groupByTimeComponent.isIntervalByMonth(),
×
2890
          TimeZone.getTimeZone("+00:00"));
×
2891
    } else {
2892
      long startTime =
2893
          groupByTimeComponent.isLeftCRightO()
1✔
2894
              ? groupByTimeComponent.getStartTime()
1✔
2895
              : groupByTimeComponent.getStartTime() + 1;
1✔
2896
      long endTime =
2897
          groupByTimeComponent.isLeftCRightO()
1✔
2898
              ? groupByTimeComponent.getEndTime()
1✔
2899
              : groupByTimeComponent.getEndTime() + 1;
1✔
2900
      return new GroupByFilter(
1✔
2901
          groupByTimeComponent.getInterval(),
1✔
2902
          groupByTimeComponent.getSlidingStep(),
1✔
2903
          startTime,
2904
          endTime);
2905
    }
2906
  }
2907

2908
  @Override
2909
  public Analysis visitSetSchemaTemplate(
2910
      SetSchemaTemplateStatement setSchemaTemplateStatement, MPPQueryContext context) {
2911
    context.setQueryType(QueryType.WRITE);
×
2912
    Analysis analysis = new Analysis();
×
2913
    analysis.setStatement(setSchemaTemplateStatement);
×
2914
    return analysis;
×
2915
  }
2916

2917
  @Override
2918
  public Analysis visitShowPathSetTemplate(
2919
      ShowPathSetTemplateStatement showPathSetTemplateStatement, MPPQueryContext context) {
2920
    Analysis analysis = new Analysis();
×
2921
    analysis.setStatement(showPathSetTemplateStatement);
×
2922
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowPathSetTemplateHeader());
×
2923
    return analysis;
×
2924
  }
2925

2926
  @Override
2927
  public Analysis visitActivateTemplate(
2928
      ActivateTemplateStatement activateTemplateStatement, MPPQueryContext context) {
2929
    context.setQueryType(QueryType.WRITE);
×
2930
    Analysis analysis = new Analysis();
×
2931
    analysis.setStatement(activateTemplateStatement);
×
2932

2933
    PartialPath activatePath = activateTemplateStatement.getPath();
×
2934

2935
    Pair<Template, PartialPath> templateSetInfo = schemaFetcher.checkTemplateSetInfo(activatePath);
×
2936
    if (templateSetInfo == null) {
×
2937
      throw new StatementAnalyzeException(
×
2938
          new MetadataException(
2939
              String.format(
×
2940
                  "Path [%s] has not been set any template.", activatePath.getFullPath())));
×
2941
    }
2942
    analysis.setTemplateSetInfo(
×
2943
        new Pair<>(templateSetInfo.left, Collections.singletonList(templateSetInfo.right)));
×
2944

2945
    PathPatternTree patternTree = new PathPatternTree();
×
2946
    patternTree.appendPathPattern(activatePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
2947
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2948

2949
    analysis.setSchemaPartitionInfo(partition);
×
2950

2951
    return analysis;
×
2952
  }
2953

2954
  @Override
2955
  public Analysis visitBatchActivateTemplate(
2956
      BatchActivateTemplateStatement batchActivateTemplateStatement, MPPQueryContext context) {
2957
    context.setQueryType(QueryType.WRITE);
×
2958
    Analysis analysis = new Analysis();
×
2959
    analysis.setStatement(batchActivateTemplateStatement);
×
2960

2961
    Map<PartialPath, Pair<Template, PartialPath>> deviceTemplateSetInfoMap =
×
2962
        new HashMap<>(batchActivateTemplateStatement.getPaths().size());
×
2963
    for (PartialPath devicePath : batchActivateTemplateStatement.getDevicePathList()) {
×
2964
      Pair<Template, PartialPath> templateSetInfo = schemaFetcher.checkTemplateSetInfo(devicePath);
×
2965
      if (templateSetInfo == null) {
×
2966
        throw new StatementAnalyzeException(
×
2967
            new MetadataException(
2968
                String.format(
×
2969
                    "Path [%s] has not been set any template.", devicePath.getFullPath())));
×
2970
      }
2971
      deviceTemplateSetInfoMap.put(devicePath, templateSetInfo);
×
2972
    }
×
2973
    analysis.setDeviceTemplateSetInfoMap(deviceTemplateSetInfoMap);
×
2974

2975
    PathPatternTree patternTree = new PathPatternTree();
×
2976
    for (PartialPath devicePath : batchActivateTemplateStatement.getDevicePathList()) {
×
2977
      // the devicePath is a path without wildcard
2978
      patternTree.appendFullPath(devicePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
2979
    }
×
2980
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2981

2982
    analysis.setSchemaPartitionInfo(partition);
×
2983

2984
    return analysis;
×
2985
  }
2986

2987
  @Override
2988
  public Analysis visitInternalBatchActivateTemplate(
2989
      InternalBatchActivateTemplateStatement internalBatchActivateTemplateStatement,
2990
      MPPQueryContext context) {
2991
    context.setQueryType(QueryType.WRITE);
×
2992
    Analysis analysis = new Analysis();
×
2993
    analysis.setStatement(internalBatchActivateTemplateStatement);
×
2994

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

3003
    analysis.setSchemaPartitionInfo(partition);
×
3004

3005
    return analysis;
×
3006
  }
3007

3008
  @Override
3009
  public Analysis visitShowPathsUsingTemplate(
3010
      ShowPathsUsingTemplateStatement showPathsUsingTemplateStatement, MPPQueryContext context) {
3011
    Analysis analysis = new Analysis();
×
3012
    analysis.setStatement(showPathsUsingTemplateStatement);
×
3013
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowPathsUsingTemplateHeader());
×
3014

3015
    Pair<Template, List<PartialPath>> templateSetInfo =
×
3016
        schemaFetcher.getAllPathsSetTemplate(showPathsUsingTemplateStatement.getTemplateName());
×
3017

3018
    if (templateSetInfo == null
×
3019
        || templateSetInfo.right == null
3020
        || templateSetInfo.right.isEmpty()) {
×
3021
      analysis.setFinishQueryAfterAnalyze(true);
×
3022
      return analysis;
×
3023
    }
3024

3025
    analysis.setTemplateSetInfo(templateSetInfo);
×
3026

3027
    PathPatternTree patternTree = new PathPatternTree();
×
3028
    PartialPath rawPathPattern = showPathsUsingTemplateStatement.getPathPattern();
×
3029
    List<PartialPath> specifiedPatternList = new ArrayList<>();
×
3030
    templateSetInfo.right.forEach(
×
3031
        setPath -> {
3032
          for (PartialPath specifiedPattern : rawPathPattern.alterPrefixPath(setPath)) {
×
3033
            patternTree.appendPathPattern(specifiedPattern);
×
3034
            specifiedPatternList.add(specifiedPattern);
×
3035
          }
×
3036
        });
×
3037

3038
    if (specifiedPatternList.isEmpty()) {
×
3039
      analysis.setFinishQueryAfterAnalyze(true);
×
3040
      return analysis;
×
3041
    }
3042

3043
    analysis.setSpecifiedTemplateRelatedPathPatternList(specifiedPatternList);
×
3044

3045
    SchemaPartition partition = partitionFetcher.getSchemaPartition(patternTree);
×
3046
    analysis.setSchemaPartitionInfo(partition);
×
3047
    if (partition.isEmpty()) {
×
3048
      analysis.setFinishQueryAfterAnalyze(true);
×
3049
      return analysis;
×
3050
    }
3051

3052
    return analysis;
×
3053
  }
3054

3055
  @Override
3056
  public Analysis visitShowQueries(
3057
      ShowQueriesStatement showQueriesStatement, MPPQueryContext context) {
3058
    Analysis analysis = new Analysis();
×
3059
    analysis.setStatement(showQueriesStatement);
×
3060
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowQueriesHeader());
×
3061
    analysis.setVirtualSource(true);
×
3062

3063
    List<TDataNodeLocation> allRunningDataNodeLocations = getRunningDataNodeLocations();
×
3064
    if (allRunningDataNodeLocations.isEmpty()) {
×
3065
      analysis.setFinishQueryAfterAnalyze(true);
×
3066
    }
3067
    // TODO Constant folding optimization for Where Predicate after True/False Constant introduced
3068
    if (allRunningDataNodeLocations.isEmpty()) {
×
3069
      throw new StatementAnalyzeException("no Running DataNodes");
×
3070
    }
3071
    analysis.setRunningDataNodeLocations(allRunningDataNodeLocations);
×
3072

3073
    Set<Expression> sourceExpressions = new HashSet<>();
×
3074
    for (ColumnHeader columnHeader : analysis.getRespDatasetHeader().getColumnHeaders()) {
×
3075
      sourceExpressions.add(
×
3076
          TimeSeriesOperand.constructColumnHeaderExpression(
×
3077
              columnHeader.getColumnName(), columnHeader.getColumnType()));
×
3078
    }
×
3079
    analysis.setSourceExpressions(sourceExpressions);
×
3080
    sourceExpressions.forEach(expression -> analyzeExpressionType(analysis, expression));
×
3081

3082
    analyzeWhere(analysis, showQueriesStatement);
×
3083

3084
    analysis.setMergeOrderParameter(new OrderByParameter(showQueriesStatement.getSortItemList()));
×
3085

3086
    return analysis;
×
3087
  }
3088

3089
  private List<TDataNodeLocation> getRunningDataNodeLocations() {
3090
    try (ConfigNodeClient client =
3091
        ConfigNodeClientManager.getInstance().borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) {
×
3092
      TGetDataNodeLocationsResp showDataNodesResp = client.getRunningDataNodeLocations();
×
3093
      if (showDataNodesResp.getStatus().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
×
3094
        throw new StatementAnalyzeException(
×
3095
            "An error occurred when executing getRunningDataNodeLocations():"
3096
                + showDataNodesResp.getStatus().getMessage());
×
3097
      }
3098
      return showDataNodesResp.getDataNodeLocationList();
×
3099
    } catch (ClientManagerException | TException e) {
×
3100
      throw new StatementAnalyzeException(
×
3101
          "An error occurred when executing getRunningDataNodeLocations():" + e.getMessage());
×
3102
    }
3103
  }
3104

3105
  private void analyzeWhere(Analysis analysis, ShowQueriesStatement showQueriesStatement) {
3106
    WhereCondition whereCondition = showQueriesStatement.getWhereCondition();
×
3107
    if (whereCondition == null) {
×
3108
      return;
×
3109
    }
3110

3111
    Expression whereExpression =
×
3112
        ExpressionAnalyzer.bindTypeForTimeSeriesOperand(
×
3113
            whereCondition.getPredicate(), ColumnHeaderConstant.showQueriesColumnHeaders);
×
3114

3115
    TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
×
3116
    if (outputType != TSDataType.BOOLEAN) {
×
3117
      throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
3118
    }
3119

3120
    analysis.setWhereExpression(whereExpression);
×
3121
  }
×
3122

3123
  // region view
3124

3125
  /**
3126
   * Compute how many paths exist, get the schema tree and the number of existed paths.
3127
   *
3128
   * @return a pair of ISchemaTree, and the number of exist paths.
3129
   */
3130
  private Pair<ISchemaTree, Integer> fetchSchemaOfPathsAndCount(
3131
      List<PartialPath> pathList, Analysis analysis, MPPQueryContext context) {
3132
    ISchemaTree schemaTree = analysis.getSchemaTree();
×
3133
    if (schemaTree == null) {
×
3134
      // source is not represented by query, thus has not done fetch schema.
3135
      PathPatternTree pathPatternTree = new PathPatternTree();
×
3136
      for (PartialPath path : pathList) {
×
3137
        pathPatternTree.appendPathPattern(path);
×
3138
      }
×
3139
      schemaTree = this.schemaFetcher.fetchSchema(pathPatternTree, context);
×
3140
    }
3141

3142
    // search each path, make sure they all exist.
3143
    int numOfExistPaths = 0;
×
3144
    for (PartialPath path : pathList) {
×
3145
      Pair<List<MeasurementPath>, Integer> pathPair = schemaTree.searchMeasurementPaths(path);
×
3146
      numOfExistPaths += !pathPair.left.isEmpty() ? 1 : 0;
×
3147
    }
×
3148
    return new Pair<>(schemaTree, numOfExistPaths);
×
3149
  }
3150

3151
  /**
3152
   * @param pathList the paths you want to check
3153
   * @param schemaTree the given schema tree
3154
   * @return if all paths you give can be found in schema tree, return a pair of view paths and
3155
   *     null; else return view paths and the non-exist path.
3156
   */
3157
  private Pair<List<PartialPath>, PartialPath> findAllViewsInPaths(
3158
      List<PartialPath> pathList, ISchemaTree schemaTree) {
3159
    List<PartialPath> result = new ArrayList<>();
×
3160
    for (PartialPath path : pathList) {
×
3161
      Pair<List<MeasurementPath>, Integer> measurementPathList =
×
3162
          schemaTree.searchMeasurementPaths(path);
×
3163
      if (measurementPathList.left.isEmpty()) {
×
3164
        return new Pair<>(result, path);
×
3165
      }
3166
      for (MeasurementPath measurementPath : measurementPathList.left) {
×
3167
        if (measurementPath.getMeasurementSchema().isLogicalView()) {
×
3168
          result.add(measurementPath);
×
3169
        }
3170
      }
×
3171
    }
×
3172
    return new Pair<>(result, null);
×
3173
  }
3174

3175
  private Pair<List<Expression>, Analysis> analyzeQueryInLogicalViewStatement(
3176
      Analysis analysis, QueryStatement queryStatement, MPPQueryContext context) {
3177
    Analysis queryAnalysis = this.visitQuery(queryStatement, context);
×
3178
    analysis.setSchemaTree(queryAnalysis.getSchemaTree());
×
3179
    // get all expression from resultColumns
3180
    List<Pair<Expression, String>> outputExpressions = queryAnalysis.getOutputExpressions();
×
3181
    if (queryAnalysis.isFailed()) {
×
3182
      analysis.setFinishQueryAfterAnalyze(true);
×
3183
      analysis.setFailStatus(queryAnalysis.getFailStatus());
×
3184
      return new Pair<>(null, analysis);
×
3185
    }
3186
    if (outputExpressions == null) {
×
3187
      analysis.setFinishQueryAfterAnalyze(true);
×
3188
      analysis.setFailStatus(
×
3189
          RpcUtils.getStatus(
×
3190
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3191
              "Columns in the query statement is empty. Please check your SQL."));
3192
      return new Pair<>(null, analysis);
×
3193
    }
3194
    if (queryAnalysis.useLogicalView()) {
×
3195
      analysis.setFinishQueryAfterAnalyze(true);
×
3196
      analysis.setFailStatus(
×
3197
          RpcUtils.getStatus(
×
3198
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3199
              "Can not create a view based on existing views. Check the query in your SQL."));
3200
      return new Pair<>(null, analysis);
×
3201
    }
3202
    List<Expression> expressionList = new ArrayList<>();
×
3203
    for (Pair<Expression, String> thisPair : outputExpressions) {
×
3204
      expressionList.add(thisPair.left);
×
3205
    }
×
3206
    return new Pair<>(expressionList, analysis);
×
3207
  }
3208

3209
  private void checkViewsInSource(
3210
      Analysis analysis, List<Expression> sourceExpressionList, MPPQueryContext context) {
3211
    List<PartialPath> pathsNeedCheck = new ArrayList<>();
×
3212
    for (Expression expression : sourceExpressionList) {
×
3213
      if (expression instanceof TimeSeriesOperand) {
×
3214
        pathsNeedCheck.add(((TimeSeriesOperand) expression).getPath());
×
3215
      }
3216
    }
×
3217
    Pair<ISchemaTree, Integer> schemaOfNeedToCheck =
×
3218
        fetchSchemaOfPathsAndCount(pathsNeedCheck, analysis, context);
×
3219
    if (schemaOfNeedToCheck.right != pathsNeedCheck.size()) {
×
3220
      // some source paths is not exist, and could not fetch schema.
3221
      analysis.setFinishQueryAfterAnalyze(true);
×
3222
      analysis.setFailStatus(
×
3223
          RpcUtils.getStatus(
×
3224
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3225
              "Can not create a view based on non-exist time series."));
3226
      return;
×
3227
    }
3228
    Pair<List<PartialPath>, PartialPath> viewInSourceCheckResult =
×
3229
        findAllViewsInPaths(pathsNeedCheck, schemaOfNeedToCheck.left);
×
3230
    if (viewInSourceCheckResult.right != null) {
×
3231
      // some source paths is not exist
3232
      analysis.setFinishQueryAfterAnalyze(true);
×
3233
      analysis.setFailStatus(
×
3234
          RpcUtils.getStatus(
×
3235
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3236
              "Path "
3237
                  + viewInSourceCheckResult.right.toString()
×
3238
                  + " does not exist! You can not create a view based on non-exist time series."));
3239
      return;
×
3240
    }
3241
    if (!viewInSourceCheckResult.left.isEmpty()) {
×
3242
      // some source paths is logical view
3243
      analysis.setFinishQueryAfterAnalyze(true);
×
3244
      analysis.setFailStatus(
×
3245
          RpcUtils.getStatus(
×
3246
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3247
              "Can not create a view based on existing views."));
3248
    }
3249
  }
×
3250

3251
  private void checkPathsInCreateLogicalView(
3252
      Analysis analysis, CreateLogicalViewStatement createLogicalViewStatement) {
3253
    Pair<Boolean, String> checkResult = createLogicalViewStatement.checkAllPaths();
×
3254
    if (Boolean.FALSE.equals(checkResult.left)) {
×
3255
      analysis.setFinishQueryAfterAnalyze(true);
×
3256
      analysis.setFailStatus(
×
3257
          RpcUtils.getStatus(
×
3258
              TSStatusCode.ILLEGAL_PATH.getStatusCode(),
×
3259
              "The path " + checkResult.right + " is illegal."));
3260
      return;
×
3261
    }
3262
    // make sure there are no redundant paths in targets. Please note that redundant paths in source
3263
    // are legal!
3264
    List<PartialPath> targetPathList = createLogicalViewStatement.getTargetPathList();
×
3265
    Set<String> targetStringSet = new HashSet<>();
×
3266
    for (PartialPath path : targetPathList) {
×
3267
      boolean repeatPathNotExist = targetStringSet.add(path.toString());
×
3268
      if (!repeatPathNotExist) {
×
3269
        analysis.setFinishQueryAfterAnalyze(true);
×
3270
        analysis.setFailStatus(
×
3271
            RpcUtils.getStatus(
×
3272
                TSStatusCode.ILLEGAL_PATH.getStatusCode(),
×
3273
                String.format("Path [%s] is redundant in target paths.", path)));
×
3274
        return;
×
3275
      }
3276
    }
×
3277
    if (createLogicalViewStatement.getSourceExpressionList().size() != targetPathList.size()) {
×
3278
      analysis.setFinishQueryAfterAnalyze(true);
×
3279
      analysis.setFailStatus(
×
3280
          RpcUtils.getStatus(
×
3281
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3282
              String.format(
×
3283
                  "The number of target paths (%d) and sources (%d) are miss matched! Please check your SQL.",
3284
                  createLogicalViewStatement.getTargetPathList().size(),
×
3285
                  createLogicalViewStatement.getSourceExpressionList().size())));
×
3286
      return;
×
3287
    }
3288
    // make sure all paths are NOt under any template
3289
    try {
3290
      for (PartialPath path : createLogicalViewStatement.getTargetPathList()) {
×
3291
        checkIsTemplateCompatible(path, null);
×
3292
      }
×
3293
    } catch (Exception e) {
×
3294
      analysis.setFinishQueryAfterAnalyze(true);
×
3295
      analysis.setFailStatus(
×
3296
          RpcUtils.getStatus(
×
3297
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3298
              "Can not create view under template."));
3299
    }
×
3300
  }
×
3301

3302
  // create Logical View
3303
  @Override
3304
  public Analysis visitCreateLogicalView(
3305
      CreateLogicalViewStatement createLogicalViewStatement, MPPQueryContext context) {
3306
    Analysis analysis = new Analysis();
×
3307
    context.setQueryType(QueryType.WRITE);
×
3308
    analysis.setStatement(createLogicalViewStatement);
×
3309

3310
    if (createLogicalViewStatement.getViewExpression() == null) {
×
3311
      // analyze query in statement
3312
      QueryStatement queryStatement = createLogicalViewStatement.getQueryStatement();
×
3313
      if (queryStatement != null) {
×
3314
        Pair<List<Expression>, Analysis> queryAnalysisPair =
×
3315
            this.analyzeQueryInLogicalViewStatement(analysis, queryStatement, context);
×
3316
        if (queryAnalysisPair.right.isFinishQueryAfterAnalyze()) {
×
3317
          return analysis;
×
3318
        } else if (queryAnalysisPair.left != null) {
×
3319
          try {
3320
            createLogicalViewStatement.setSourceExpressions(queryAnalysisPair.left);
×
3321
          } catch (UnsupportedViewException e) {
×
3322
            analysis.setFinishQueryAfterAnalyze(true);
×
3323
            analysis.setFailStatus(RpcUtils.getStatus(e.getErrorCode(), e.getMessage()));
×
3324
            return analysis;
×
3325
          }
×
3326
        }
3327
      }
3328
    }
3329

3330
    // use source and into item to generate target views
3331
    createLogicalViewStatement.parseIntoItemIfNecessary();
×
3332

3333
    // check target paths; check source expressions.
3334
    checkPathsInCreateLogicalView(analysis, createLogicalViewStatement);
×
3335
    if (analysis.isFinishQueryAfterAnalyze()) {
×
3336
      return analysis;
×
3337
    }
3338

3339
    // make sure there is no view in source
3340
    List<Expression> sourceExpressionList = createLogicalViewStatement.getSourceExpressionList();
×
3341
    checkViewsInSource(analysis, sourceExpressionList, context);
×
3342
    if (analysis.isFinishQueryAfterAnalyze()) {
×
3343
      return analysis;
×
3344
    }
3345

3346
    // set schema partition info, this info will be used to split logical plan node.
3347
    PathPatternTree patternTree = new PathPatternTree();
×
3348
    for (PartialPath thisFullPath : createLogicalViewStatement.getTargetPathList()) {
×
3349
      patternTree.appendFullPath(thisFullPath);
×
3350
    }
×
3351
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3352
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
3353

3354
    return analysis;
×
3355
  }
3356

3357
  @Override
3358
  public Analysis visitShowLogicalView(
3359
      ShowLogicalViewStatement showLogicalViewStatement, MPPQueryContext context) {
3360
    context.setQueryType(QueryType.READ);
×
3361
    Analysis analysis = new Analysis();
×
3362
    analysis.setStatement(showLogicalViewStatement);
×
3363

3364
    PathPatternTree patternTree = new PathPatternTree();
×
3365
    patternTree.appendPathPattern(showLogicalViewStatement.getPathPattern());
×
3366
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
3367
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
3368

3369
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowLogicalViewHeader());
×
3370
    return analysis;
×
3371
  }
3372
  // endregion view
3373
}
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