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

apache / iotdb / #9610

pending completion
#9610

push

travis_ci

web-flow
Fix the bug when delete view meets statement error

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

78946 of 164800 relevant lines covered (47.9%)

0.48 hits per line

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

40.1
/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.LoadFileException;
43
import org.apache.iotdb.db.exception.VerifyMetadataException;
44
import org.apache.iotdb.db.exception.metadata.template.TemplateIncompatibleException;
45
import org.apache.iotdb.db.exception.metadata.view.UnsupportedViewException;
46
import org.apache.iotdb.db.exception.sql.MeasurementNotExistException;
47
import org.apache.iotdb.db.exception.sql.SemanticException;
48
import org.apache.iotdb.db.exception.sql.StatementAnalyzeException;
49
import org.apache.iotdb.db.protocol.client.ConfigNodeClient;
50
import org.apache.iotdb.db.protocol.client.ConfigNodeClientManager;
51
import org.apache.iotdb.db.protocol.client.ConfigNodeInfo;
52
import org.apache.iotdb.db.protocol.session.SessionManager;
53
import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
54
import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
55
import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant;
56
import org.apache.iotdb.db.queryengine.common.header.DatasetHeader;
57
import org.apache.iotdb.db.queryengine.common.header.DatasetHeaderFactory;
58
import org.apache.iotdb.db.queryengine.common.schematree.DeviceSchemaInfo;
59
import org.apache.iotdb.db.queryengine.common.schematree.ISchemaTree;
60
import org.apache.iotdb.db.queryengine.execution.operator.window.WindowType;
61
import org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet;
62
import org.apache.iotdb.db.queryengine.plan.Coordinator;
63
import org.apache.iotdb.db.queryengine.plan.analyze.schema.ISchemaFetcher;
64
import org.apache.iotdb.db.queryengine.plan.analyze.schema.SchemaValidator;
65
import org.apache.iotdb.db.queryengine.plan.execution.ExecutionResult;
66
import org.apache.iotdb.db.queryengine.plan.expression.Expression;
67
import org.apache.iotdb.db.queryengine.plan.expression.ExpressionType;
68
import org.apache.iotdb.db.queryengine.plan.expression.binary.CompareBinaryExpression;
69
import org.apache.iotdb.db.queryengine.plan.expression.leaf.ConstantOperand;
70
import org.apache.iotdb.db.queryengine.plan.expression.leaf.TimeSeriesOperand;
71
import org.apache.iotdb.db.queryengine.plan.expression.multi.FunctionExpression;
72
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.DeviceViewIntoPathDescriptor;
73
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.FillDescriptor;
74
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.GroupByConditionParameter;
75
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.GroupByCountParameter;
76
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.GroupByParameter;
77
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.GroupBySessionParameter;
78
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.GroupByTimeParameter;
79
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.GroupByVariationParameter;
80
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.IntoPathDescriptor;
81
import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.OrderByParameter;
82
import org.apache.iotdb.db.queryengine.plan.statement.Statement;
83
import org.apache.iotdb.db.queryengine.plan.statement.StatementNode;
84
import org.apache.iotdb.db.queryengine.plan.statement.StatementVisitor;
85
import org.apache.iotdb.db.queryengine.plan.statement.component.FillComponent;
86
import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByComponent;
87
import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByConditionComponent;
88
import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByCountComponent;
89
import org.apache.iotdb.db.queryengine.plan.statement.component.GroupBySessionComponent;
90
import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByTimeComponent;
91
import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByVariationComponent;
92
import org.apache.iotdb.db.queryengine.plan.statement.component.IntoComponent;
93
import org.apache.iotdb.db.queryengine.plan.statement.component.Ordering;
94
import org.apache.iotdb.db.queryengine.plan.statement.component.ResultColumn;
95
import org.apache.iotdb.db.queryengine.plan.statement.component.SortItem;
96
import org.apache.iotdb.db.queryengine.plan.statement.component.WhereCondition;
97
import org.apache.iotdb.db.queryengine.plan.statement.crud.DeleteDataStatement;
98
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertBaseStatement;
99
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertMultiTabletsStatement;
100
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowStatement;
101
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsOfOneDeviceStatement;
102
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsStatement;
103
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertStatement;
104
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement;
105
import org.apache.iotdb.db.queryengine.plan.statement.crud.LoadTsFileStatement;
106
import org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement;
107
import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalBatchActivateTemplateStatement;
108
import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalCreateMultiTimeSeriesStatement;
109
import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalCreateTimeSeriesStatement;
110
import org.apache.iotdb.db.queryengine.plan.statement.internal.SchemaFetchStatement;
111
import org.apache.iotdb.db.queryengine.plan.statement.metadata.AlterTimeSeriesStatement;
112
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountDatabaseStatement;
113
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountDevicesStatement;
114
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountLevelTimeSeriesStatement;
115
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountNodesStatement;
116
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountTimeSeriesStatement;
117
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateAlignedTimeSeriesStatement;
118
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateMultiTimeSeriesStatement;
119
import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateTimeSeriesStatement;
120
import org.apache.iotdb.db.queryengine.plan.statement.metadata.DatabaseSchemaStatement;
121
import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildNodesStatement;
122
import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildPathsStatement;
123
import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterStatement;
124
import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDatabaseStatement;
125
import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDevicesStatement;
126
import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTTLStatement;
127
import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTimeSeriesStatement;
128
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ActivateTemplateStatement;
129
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.BatchActivateTemplateStatement;
130
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.CreateSchemaTemplateStatement;
131
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.SetSchemaTemplateStatement;
132
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ShowNodesInSchemaTemplateStatement;
133
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ShowPathSetTemplateStatement;
134
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ShowPathsUsingTemplateStatement;
135
import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ShowSchemaTemplateStatement;
136
import org.apache.iotdb.db.queryengine.plan.statement.metadata.view.CreateLogicalViewStatement;
137
import org.apache.iotdb.db.queryengine.plan.statement.metadata.view.ShowLogicalViewStatement;
138
import org.apache.iotdb.db.queryengine.plan.statement.sys.ExplainStatement;
139
import org.apache.iotdb.db.queryengine.plan.statement.sys.ShowQueriesStatement;
140
import org.apache.iotdb.db.queryengine.plan.statement.sys.ShowVersionStatement;
141
import org.apache.iotdb.db.schemaengine.SchemaConstant;
142
import org.apache.iotdb.db.schemaengine.template.Template;
143
import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource;
144
import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResourceStatus;
145
import org.apache.iotdb.db.utils.FileLoaderUtils;
146
import org.apache.iotdb.db.utils.TimePartitionUtils;
147
import org.apache.iotdb.rpc.RpcUtils;
148
import org.apache.iotdb.rpc.TSStatusCode;
149
import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
150
import org.apache.iotdb.tsfile.file.metadata.TimeseriesMetadata;
151
import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
152
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
153
import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
154
import org.apache.iotdb.tsfile.read.TsFileSequenceReader;
155
import org.apache.iotdb.tsfile.read.common.TimeRange;
156
import org.apache.iotdb.tsfile.read.filter.GroupByFilter;
157
import org.apache.iotdb.tsfile.read.filter.GroupByMonthFilter;
158
import org.apache.iotdb.tsfile.read.filter.PredicateRemoveNotRewriter;
159
import org.apache.iotdb.tsfile.read.filter.basic.Filter;
160
import org.apache.iotdb.tsfile.read.filter.factory.FilterFactory;
161
import org.apache.iotdb.tsfile.utils.Pair;
162
import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
163
import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
164

165
import org.apache.thrift.TException;
166
import org.slf4j.Logger;
167
import org.slf4j.LoggerFactory;
168

169
import java.io.File;
170
import java.io.IOException;
171
import java.util.ArrayList;
172
import java.util.Arrays;
173
import java.util.Collections;
174
import java.util.HashMap;
175
import java.util.HashSet;
176
import java.util.Iterator;
177
import java.util.LinkedHashMap;
178
import java.util.LinkedHashSet;
179
import java.util.LinkedList;
180
import java.util.List;
181
import java.util.Locale;
182
import java.util.Map;
183
import java.util.Objects;
184
import java.util.Set;
185
import java.util.TimeZone;
186
import java.util.stream.Collectors;
187

188
import static com.google.common.base.Preconditions.checkState;
189
import static org.apache.iotdb.commons.conf.IoTDBConstant.ALLOWED_SCHEMA_PROPS;
190
import static org.apache.iotdb.commons.conf.IoTDBConstant.DEADBAND;
191
import static org.apache.iotdb.commons.conf.IoTDBConstant.LOSS;
192
import static org.apache.iotdb.commons.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCARD;
193
import static org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant.DEVICE;
194
import static org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant.ENDTIME;
195
import static org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet.PARTITION_FETCHER;
196
import static org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet.SCHEMA_FETCHER;
197
import static org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetDevice;
198
import static org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetMeasurement;
199
import static org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetPath;
200
import static org.apache.iotdb.db.schemaengine.schemaregion.view.visitor.GetSourcePathsVisitor.getSourcePaths;
201

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

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

207
  private static final IoTDBConfig CONFIG = IoTDBDescriptor.getInstance().getConfig();
1✔
208

209
  private static final Expression deviceExpression =
1✔
210
      TimeSeriesOperand.constructColumnHeaderExpression(DEVICE, TSDataType.TEXT);
1✔
211

212
  private static final Expression endTimeExpression =
1✔
213
      TimeSeriesOperand.constructColumnHeaderExpression(ENDTIME, TSDataType.INT64);
1✔
214

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

218
  private final IPartitionFetcher partitionFetcher;
219
  private final ISchemaFetcher schemaFetcher;
220

221
  private static final PerformanceOverviewMetrics PERFORMANCE_OVERVIEW_METRICS =
1✔
222
      PerformanceOverviewMetrics.getInstance();
1✔
223

224
  public AnalyzeVisitor(IPartitionFetcher partitionFetcher, ISchemaFetcher schemaFetcher) {
1✔
225
    this.partitionFetcher = partitionFetcher;
1✔
226
    this.schemaFetcher = schemaFetcher;
1✔
227
  }
1✔
228

229
  @Override
230
  public Analysis visitNode(StatementNode node, MPPQueryContext context) {
231
    throw new UnsupportedOperationException(
×
232
        "Unsupported statement type: " + node.getClass().getName());
×
233
  }
234

235
  @Override
236
  public Analysis visitExplain(ExplainStatement explainStatement, MPPQueryContext context) {
237
    Analysis analysis = visitQuery(explainStatement.getQueryStatement(), context);
×
238
    analysis.setStatement(explainStatement);
×
239
    analysis.setFinishQueryAfterAnalyze(true);
×
240
    return analysis;
×
241
  }
242

243
  @Override
244
  public Analysis visitQuery(QueryStatement queryStatement, MPPQueryContext context) {
245
    Analysis analysis = new Analysis();
1✔
246
    try {
247
      // check for semantic errors
248
      queryStatement.semanticCheck();
1✔
249

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

256
      // extract global time filter from query filter and determine if there is a value filter
257
      analyzeGlobalTimeFilter(analysis, queryStatement);
1✔
258

259
      if (queryStatement.isLastQuery()) {
1✔
260
        return analyzeLastQuery(queryStatement, analysis, schemaTree);
×
261
      }
262

263
      List<Pair<Expression, String>> outputExpressions;
264
      if (queryStatement.isAlignByDevice()) {
1✔
265
        Set<PartialPath> deviceSet = analyzeFrom(queryStatement, schemaTree);
1✔
266

267
        analyzeDeviceToWhere(analysis, queryStatement, schemaTree, deviceSet);
1✔
268
        outputExpressions = analyzeSelect(analysis, queryStatement, schemaTree, deviceSet);
1✔
269
        if (deviceSet.isEmpty()) {
1✔
270
          return finishQuery(queryStatement, analysis);
×
271
        }
272

273
        analyzeDeviceToGroupBy(analysis, queryStatement, schemaTree, deviceSet);
1✔
274
        analyzeDeviceToOrderBy(analysis, queryStatement, schemaTree, deviceSet);
1✔
275
        analyzeHaving(analysis, queryStatement, schemaTree, deviceSet);
1✔
276

277
        analyzeDeviceToAggregation(analysis, queryStatement);
1✔
278
        analyzeDeviceToSourceTransform(analysis, queryStatement);
1✔
279
        analyzeDeviceToSource(analysis, queryStatement);
1✔
280

281
        analyzeDeviceViewOutput(analysis, queryStatement);
1✔
282
        analyzeDeviceViewInput(analysis, queryStatement);
1✔
283

284
        analyzeInto(analysis, queryStatement, deviceSet, outputExpressions);
1✔
285
      } else {
1✔
286
        Map<Integer, List<Pair<Expression, String>>> outputExpressionMap =
1✔
287
            analyzeSelect(analysis, queryStatement, schemaTree);
1✔
288

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

296
        analyzeGroupBy(analysis, queryStatement, schemaTree);
1✔
297
        analyzeHaving(analysis, queryStatement, schemaTree);
1✔
298
        analyzeOrderBy(analysis, queryStatement, schemaTree);
1✔
299

300
        analyzeGroupByLevel(analysis, queryStatement, outputExpressionMap, outputExpressions);
1✔
301
        analyzeGroupByTag(analysis, queryStatement, outputExpressions);
1✔
302

303
        Set<Expression> selectExpressions = new LinkedHashSet<>();
1✔
304
        if (queryStatement.isOutputEndTime()) {
1✔
305
          selectExpressions.add(endTimeExpression);
×
306
        }
307
        for (Pair<Expression, String> outputExpressionAndAlias : outputExpressions) {
1✔
308
          selectExpressions.add(outputExpressionAndAlias.left);
1✔
309
        }
1✔
310
        analysis.setSelectExpressions(selectExpressions);
1✔
311

312
        analyzeAggregation(analysis, queryStatement);
1✔
313

314
        analyzeWhere(analysis, queryStatement, schemaTree);
1✔
315
        analyzeSourceTransform(analysis, queryStatement);
1✔
316

317
        analyzeSource(analysis, queryStatement);
1✔
318

319
        analyzeInto(analysis, queryStatement, outputExpressions);
1✔
320
      }
321

322
      analyzeGroupByTime(analysis, queryStatement);
1✔
323

324
      analyzeFill(analysis, queryStatement);
1✔
325

326
      // generate result set header according to output expressions
327
      analyzeOutput(analysis, queryStatement, outputExpressions);
1✔
328

329
      // fetch partition information
330
      analyzeDataPartition(analysis, queryStatement, schemaTree);
1✔
331

332
    } catch (StatementAnalyzeException e) {
×
333
      throw new StatementAnalyzeException(
×
334
          "Meet error when analyzing the query statement: " + e.getMessage());
×
335
    }
1✔
336
    return analysis;
1✔
337
  }
338

339
  private ISchemaTree analyzeSchema(
340
      QueryStatement queryStatement, Analysis analysis, MPPQueryContext context) {
341
    // concat path and construct path pattern tree
342
    PathPatternTree patternTree = new PathPatternTree(queryStatement.useWildcard());
1✔
343
    queryStatement = (QueryStatement) new ConcatPathRewriter().rewrite(queryStatement, patternTree);
1✔
344
    analysis.setStatement(queryStatement);
1✔
345

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

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

368
  private Analysis finishQuery(QueryStatement queryStatement, Analysis analysis) {
369
    if (queryStatement.isSelectInto()) {
×
370
      analysis.setRespDatasetHeader(
×
371
          DatasetHeaderFactory.getSelectIntoHeader(queryStatement.isAlignByDevice()));
×
372
    }
373
    if (queryStatement.isLastQuery()) {
×
374
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getLastQueryHeader());
×
375
    }
376
    analysis.setFinishQueryAfterAnalyze(true);
×
377
    return analysis;
×
378
  }
379

380
  private void analyzeGlobalTimeFilter(Analysis analysis, QueryStatement queryStatement) {
381
    Filter globalTimeFilter = null;
1✔
382
    boolean hasValueFilter = false;
1✔
383
    if (queryStatement.getWhereCondition() != null) {
1✔
384
      WhereCondition whereCondition = queryStatement.getWhereCondition();
1✔
385
      Expression predicate = whereCondition.getPredicate();
1✔
386

387
      Pair<Filter, Boolean> resultPair =
1✔
388
          ExpressionAnalyzer.extractGlobalTimeFilter(predicate, true, true);
1✔
389
      globalTimeFilter = resultPair.left;
1✔
390
      if (globalTimeFilter != null) {
1✔
391
        globalTimeFilter = PredicateRemoveNotRewriter.rewrite(globalTimeFilter);
1✔
392
      }
393
      hasValueFilter = resultPair.right;
1✔
394

395
      predicate = ExpressionAnalyzer.evaluatePredicate(predicate);
1✔
396

397
      // set where condition to null if predicate is true or time filter.
398
      if (!hasValueFilter
1✔
399
          || (predicate.getExpressionType().equals(ExpressionType.CONSTANT)
1✔
400
              && Boolean.parseBoolean(predicate.getExpressionString()))) {
×
401
        queryStatement.setWhereCondition(null);
1✔
402
      } else {
403
        whereCondition.setPredicate(predicate);
1✔
404
      }
405
    }
406
    if (queryStatement.isGroupByTime()) {
1✔
407
      GroupByTimeComponent groupByTimeComponent = queryStatement.getGroupByTimeComponent();
1✔
408
      Filter groupByFilter = initGroupByFilter(groupByTimeComponent);
1✔
409
      if (globalTimeFilter == null) {
1✔
410
        globalTimeFilter = groupByFilter;
1✔
411
      } else {
412
        globalTimeFilter = FilterFactory.and(globalTimeFilter, groupByFilter);
1✔
413
      }
414
    }
415
    analysis.setGlobalTimeFilter(globalTimeFilter);
1✔
416
    analysis.setHasValueFilter(hasValueFilter);
1✔
417
  }
1✔
418

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

426
    List<Expression> selectExpressions = new ArrayList<>();
×
427
    for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) {
×
428
      selectExpressions.add(resultColumn.getExpression());
×
429
    }
×
430
    analyzeLastSource(analysis, selectExpressions, schemaTree);
×
431

432
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getLastQueryHeader());
×
433

434
    // fetch partition information
435
    analyzeDataPartition(analysis, queryStatement, schemaTree);
×
436

437
    return analysis;
×
438
  }
439

440
  private void analyzeLastSource(
441
      Analysis analysis, List<Expression> selectExpressions, ISchemaTree schemaTree) {
442
    Set<Expression> sourceExpressions;
443

444
    sourceExpressions = new LinkedHashSet<>();
×
445

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

459
  private void updateSchemaTreeByViews(Analysis analysis, ISchemaTree originSchemaTree) {
460
    if (!originSchemaTree.hasLogicalViewMeasurement()) {
1✔
461
      return;
1✔
462
    }
463

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

493
    if (needToReFetch) {
×
494
      ISchemaTree viewSchemaTree = this.schemaFetcher.fetchSchema(patternTree, null);
×
495
      originSchemaTree.mergeSchemaTree(viewSchemaTree);
×
496
      Set<String> allDatabases = viewSchemaTree.getDatabases();
×
497
      allDatabases.addAll(originSchemaTree.getDatabases());
×
498
      originSchemaTree.setDatabases(allDatabases);
×
499
    }
500
  }
×
501

502
  private Map<Integer, List<Pair<Expression, String>>> analyzeSelect(
503
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
504
    Map<Integer, List<Pair<Expression, String>>> outputExpressionMap = new HashMap<>();
1✔
505

506
    boolean isGroupByLevel = queryStatement.isGroupByLevel();
1✔
507
    ColumnPaginationController paginationController =
1✔
508
        new ColumnPaginationController(
509
            queryStatement.getSeriesLimit(),
1✔
510
            queryStatement.getSeriesOffset(),
1✔
511
            queryStatement.isLastQuery() || isGroupByLevel);
1✔
512

513
    Set<String> aliasSet = new HashSet<>();
1✔
514

515
    int columnIndex = 0;
1✔
516

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

520
      List<Expression> resultExpressions =
1✔
521
          ExpressionAnalyzer.bindSchemaForExpression(resultColumn.getExpression(), schemaTree);
1✔
522
      for (Expression expression : resultExpressions) {
1✔
523
        if (paginationController.hasCurOffset()) {
1✔
524
          paginationController.consumeOffset();
×
525
        } else if (paginationController.hasCurLimit()) {
1✔
526
          if (isGroupByLevel) {
1✔
527
            analyzeExpressionType(analysis, expression);
×
528
            outputExpressions.add(new Pair<>(expression, resultColumn.getAlias()));
×
529
            queryStatement
×
530
                .getGroupByLevelComponent()
×
531
                .updateIsCountStar(resultColumn.getExpression());
×
532
          } else {
533
            Expression normalizedExpression = ExpressionAnalyzer.normalizeExpression(expression);
1✔
534
            analyzeExpressionType(analysis, normalizedExpression);
1✔
535

536
            checkAliasUniqueness(resultColumn.getAlias(), aliasSet);
1✔
537

538
            outputExpressions.add(
1✔
539
                new Pair<>(
540
                    normalizedExpression,
541
                    analyzeAlias(resultColumn.getAlias(), expression, normalizedExpression)));
1✔
542
          }
543
          paginationController.consumeLimit();
1✔
544
        } else {
545
          break;
546
        }
547
      }
1✔
548
      outputExpressionMap.put(columnIndex++, outputExpressions);
1✔
549
    }
1✔
550
    return outputExpressionMap;
1✔
551
  }
552

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

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

568
  private List<Pair<Expression, String>> analyzeSelect(
569
      Analysis analysis,
570
      QueryStatement queryStatement,
571
      ISchemaTree schemaTree,
572
      Set<PartialPath> deviceSet) {
573
    List<Pair<Expression, String>> outputExpressions = new ArrayList<>();
1✔
574
    Map<String, Set<Expression>> deviceToSelectExpressions = new HashMap<>();
1✔
575

576
    ColumnPaginationController paginationController =
1✔
577
        new ColumnPaginationController(
578
            queryStatement.getSeriesLimit(), queryStatement.getSeriesOffset(), false);
1✔
579
    Set<PartialPath> noMeasurementDevices = new HashSet<>(deviceSet);
1✔
580

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

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

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

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

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

619
          // add outputExpressions
620
          Expression normalizedMeasurementExpression =
1✔
621
              ExpressionAnalyzer.toLowerCaseExpression(measurementExpression);
1✔
622
          analyzeExpressionType(analysis, normalizedMeasurementExpression);
1✔
623
          outputExpressions.add(
1✔
624
              new Pair<>(
625
                  normalizedMeasurementExpression,
626
                  analyzeAlias(
1✔
627
                      resultColumn.getAlias(),
1✔
628
                      measurementExpression,
629
                      normalizedMeasurementExpression)));
630

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

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

642
    // remove devices without measurements to compute
643
    deviceSet.removeAll(noMeasurementDevices);
1✔
644

645
    // when the select expression of any device is empty,
646
    // the where expression map also need remove this device
647
    if (analysis.getDeviceToWhereExpression() != null) {
1✔
648
      noMeasurementDevices.forEach(
1✔
649
          devicePath -> analysis.getDeviceToWhereExpression().remove(devicePath.getFullPath()));
×
650
    }
651

652
    analysis.setDeviceToSelectExpressions(deviceToSelectExpressions);
1✔
653

654
    // set selectExpressions
655
    Set<Expression> selectExpressions = new LinkedHashSet<>();
1✔
656
    selectExpressions.add(deviceExpression);
1✔
657
    if (queryStatement.isOutputEndTime()) {
1✔
658
      selectExpressions.add(endTimeExpression);
×
659
    }
660
    selectExpressions.addAll(
1✔
661
        outputExpressions.stream()
1✔
662
            .map(Pair::getLeft)
1✔
663
            .collect(Collectors.toCollection(LinkedHashSet::new)));
1✔
664
    analysis.setSelectExpressions(selectExpressions);
1✔
665

666
    return outputExpressions;
1✔
667
  }
668

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

683
  private void updateDeviceToSelectExpressions(
684
      Analysis analysis,
685
      Map<String, Set<Expression>> deviceToSelectExpressions,
686
      Map<String, Expression> deviceToSelectExpressionsOfOneMeasurement) {
687
    for (Map.Entry<String, Expression> deviceNameSelectExpressionEntry :
688
        deviceToSelectExpressionsOfOneMeasurement.entrySet()) {
1✔
689
      String deviceName = deviceNameSelectExpressionEntry.getKey();
1✔
690
      Expression expression = deviceNameSelectExpressionEntry.getValue();
1✔
691

692
      Expression normalizedExpression = ExpressionAnalyzer.toLowerCaseExpression(expression);
1✔
693
      analyzeExpressionType(analysis, normalizedExpression);
1✔
694
      deviceToSelectExpressions
1✔
695
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
696
          .add(normalizedExpression);
1✔
697
    }
1✔
698
  }
1✔
699

700
  private String analyzeAlias(
701
      String resultColumnAlias, Expression rawExpression, Expression normalizedExpression) {
702
    if (resultColumnAlias != null) {
1✔
703
      // use alias as output symbol
704
      return resultColumnAlias;
1✔
705
    }
706

707
    if (!Objects.equals(normalizedExpression, rawExpression)) {
1✔
708
      return rawExpression.getOutputSymbol();
1✔
709
    }
710
    return null;
1✔
711
  }
712

713
  private void analyzeHaving(
714
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
715
    if (!queryStatement.hasHaving()) {
1✔
716
      return;
1✔
717
    }
718

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

740
  private void analyzeHaving(
741
      Analysis analysis,
742
      QueryStatement queryStatement,
743
      ISchemaTree schemaTree,
744
      Set<PartialPath> deviceSet) {
745
    if (!queryStatement.hasHaving()) {
1✔
746
      return;
1✔
747
    }
748

749
    // two maps to be updated
750
    Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
751
        analysis.getDeviceToAggregationExpressions();
1✔
752
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
753
        analysis.getDeviceToOutputExpressions();
1✔
754

755
    Expression havingExpression = queryStatement.getHavingCondition().getPredicate();
1✔
756
    Set<Expression> conJunctions = new HashSet<>();
1✔
757

758
    for (PartialPath device : deviceSet) {
1✔
759
      List<Expression> expressionsInHaving =
1✔
760
          ExpressionAnalyzer.concatDeviceAndBindSchemaForExpression(
1✔
761
              havingExpression, device, schemaTree);
762

763
      conJunctions.addAll(
1✔
764
          expressionsInHaving.stream()
1✔
765
              .map(expression -> ExpressionAnalyzer.getMeasurementExpression(expression, analysis))
1✔
766
              .collect(Collectors.toList()));
1✔
767

768
      for (Expression expression : expressionsInHaving) {
1✔
769
        Set<Expression> aggregationExpressions = new LinkedHashSet<>();
1✔
770
        Set<Expression> normalizedAggregationExpressions = new LinkedHashSet<>();
1✔
771
        for (Expression aggregationExpression :
772
            ExpressionAnalyzer.searchAggregationExpressions(expression)) {
1✔
773
          Expression normalizedAggregationExpression =
1✔
774
              ExpressionAnalyzer.normalizeExpression(aggregationExpression);
1✔
775

776
          analyzeExpressionType(analysis, aggregationExpression);
1✔
777
          analyzeExpressionType(analysis, normalizedAggregationExpression);
1✔
778

779
          aggregationExpressions.add(aggregationExpression);
1✔
780
          normalizedAggregationExpressions.add(normalizedAggregationExpression);
1✔
781
        }
1✔
782
        deviceToOutputExpressions
1✔
783
            .computeIfAbsent(device.getFullPath(), key -> new LinkedHashSet<>())
1✔
784
            .addAll(aggregationExpressions);
1✔
785
        deviceToAggregationExpressions
1✔
786
            .computeIfAbsent(device.getFullPath(), key -> new LinkedHashSet<>())
1✔
787
            .addAll(normalizedAggregationExpressions);
1✔
788
      }
1✔
789
    }
1✔
790

791
    havingExpression = ExpressionUtils.constructQueryFilter(new ArrayList<>(conJunctions));
1✔
792
    TSDataType outputType = analyzeExpressionType(analysis, havingExpression);
1✔
793
    if (outputType != TSDataType.BOOLEAN) {
1✔
794
      throw new SemanticException(
×
795
          String.format(
×
796
              "The output type of the expression in HAVING clause should be BOOLEAN, actual data type: %s.",
797
              outputType));
798
    }
799
    analysis.setDeviceToAggregationExpressions(deviceToAggregationExpressions);
1✔
800
    analysis.setHavingExpression(havingExpression);
1✔
801
  }
1✔
802

803
  private void analyzeGroupByLevel(
804
      Analysis analysis,
805
      QueryStatement queryStatement,
806
      Map<Integer, List<Pair<Expression, String>>> outputExpressionMap,
807
      List<Pair<Expression, String>> outputExpressions) {
808
    if (!queryStatement.isGroupByLevel()) {
1✔
809
      return;
1✔
810
    }
811

812
    GroupByLevelController groupByLevelController =
×
813
        new GroupByLevelController(queryStatement.getGroupByLevelComponent().getLevels());
×
814

815
    List<Expression> groupedSelectExpressions = new LinkedList<>();
×
816

817
    for (List<Pair<Expression, String>> outputExpressionList : outputExpressionMap.values()) {
×
818
      Set<Expression> groupedSelectExpressionSet = new LinkedHashSet<>();
×
819
      for (int i = 0; i < outputExpressionList.size(); i++) {
×
820
        Pair<Expression, String> expressionAliasPair = outputExpressionList.get(i);
×
821
        boolean isCountStar = queryStatement.getGroupByLevelComponent().isCountStar(i);
×
822
        Expression groupedExpression =
×
823
            groupByLevelController.control(
×
824
                isCountStar, expressionAliasPair.left, expressionAliasPair.right);
825
        groupedSelectExpressionSet.add(groupedExpression);
×
826
      }
827
      groupedSelectExpressions.addAll(groupedSelectExpressionSet);
×
828
    }
×
829

830
    LinkedHashMap<Expression, Set<Expression>> groupByLevelExpressions = new LinkedHashMap<>();
×
831
    if (queryStatement.hasHaving()) {
×
832
      // update havingExpression
833
      Expression havingExpression = groupByLevelController.control(analysis.getHavingExpression());
×
834
      analyzeExpressionType(analysis, havingExpression);
×
835
      analysis.setHavingExpression(havingExpression);
×
836
      updateGroupByLevelExpressions(
×
837
          analysis,
838
          havingExpression,
839
          groupByLevelExpressions,
840
          groupByLevelController.getGroupedExpressionToRawExpressionsMap());
×
841
    }
842

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

872
    checkDataTypeConsistencyInGroupByLevel(analysis, groupByLevelExpressions);
×
873
    analysis.setCrossGroupByExpressions(groupByLevelExpressions);
×
874
  }
×
875

876
  private void checkDataTypeConsistencyInGroupByLevel(
877
      Analysis analysis, Map<Expression, Set<Expression>> groupByLevelExpressions) {
878
    for (Map.Entry<Expression, Set<Expression>> groupedExpressionRawExpressionsEntry :
879
        groupByLevelExpressions.entrySet()) {
×
880
      Expression groupedAggregationExpression = groupedExpressionRawExpressionsEntry.getKey();
×
881
      Set<Expression> rawAggregationExpressions = groupedExpressionRawExpressionsEntry.getValue();
×
882

883
      TSDataType checkedDataType = analysis.getType(groupedAggregationExpression);
×
884
      for (Expression rawAggregationExpression : rawAggregationExpressions) {
×
885
        if (analysis.getType(rawAggregationExpression) != checkedDataType) {
×
886
          throw new SemanticException(
×
887
              String.format(
×
888
                  "GROUP BY LEVEL: the data types of the same output column[%s] should be the same.",
889
                  groupedAggregationExpression));
890
        }
891
      }
×
892
    }
×
893
  }
×
894

895
  private void updateGroupByLevelExpressions(
896
      Analysis analysis,
897
      Expression expression,
898
      Map<Expression, Set<Expression>> groupByLevelExpressions,
899
      Map<Expression, Set<Expression>> groupedExpressionToRawExpressionsMap) {
900
    for (Expression groupedAggregationExpression :
901
        ExpressionAnalyzer.searchAggregationExpressions(expression)) {
×
902
      Set<Expression> groupedExpressionSet =
×
903
          groupedExpressionToRawExpressionsMap.get(groupedAggregationExpression).stream()
×
904
              .map(ExpressionAnalyzer::normalizeExpression)
×
905
              .collect(Collectors.toSet());
×
906
      Expression groupedAggregationExpressionWithoutAlias =
×
907
          ExpressionAnalyzer.normalizeExpression(groupedAggregationExpression);
×
908

909
      analyzeExpressionType(analysis, groupedAggregationExpressionWithoutAlias);
×
910
      groupedExpressionSet.forEach(
×
911
          groupedExpression -> analyzeExpressionType(analysis, groupedExpression));
×
912

913
      groupByLevelExpressions
×
914
          .computeIfAbsent(groupedAggregationExpressionWithoutAlias, key -> new HashSet<>())
×
915
          .addAll(groupedExpressionSet);
×
916
    }
×
917
  }
×
918

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

935
    List<String> tagKeys = queryStatement.getGroupByTagComponent().getTagKeys();
×
936
    Map<List<String>, LinkedHashMap<Expression, List<Expression>>>
937
        tagValuesToGroupedTimeseriesOperands = new HashMap<>();
×
938
    LinkedHashMap<Expression, Set<Expression>> outputExpressionToRawExpressionsMap =
×
939
        new LinkedHashMap<>();
940

941
    for (Pair<Expression, String> outputExpressionAndAlias : outputExpressions) {
×
942
      FunctionExpression rawExpression = (FunctionExpression) outputExpressionAndAlias.getLeft();
×
943
      FunctionExpression measurementExpression =
×
944
          (FunctionExpression) ExpressionAnalyzer.getMeasurementExpression(rawExpression, analysis);
×
945
      outputExpressionToRawExpressionsMap
×
946
          .computeIfAbsent(measurementExpression, v -> new HashSet<>())
×
947
          .add(rawExpression);
×
948

949
      Map<String, String> tagMap =
×
950
          ((MeasurementPath)
951
                  ((TimeSeriesOperand) measurementExpression.getExpressions().get(0)).getPath())
×
952
              .getTagMap();
×
953
      List<String> tagValues = new ArrayList<>();
×
954
      for (String tagKey : tagKeys) {
×
955
        tagValues.add(tagMap.get(tagKey));
×
956
      }
×
957
      tagValuesToGroupedTimeseriesOperands
×
958
          .computeIfAbsent(tagValues, key -> new LinkedHashMap<>())
×
959
          .computeIfAbsent(measurementExpression, key -> new ArrayList<>())
×
960
          .add(rawExpression.getExpressions().get(0));
×
961
    }
×
962

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

981
  private void analyzeDeviceToAggregation(Analysis analysis, QueryStatement queryStatement) {
982
    if (!queryStatement.isAggregationQuery()) {
1✔
983
      return;
1✔
984
    }
985

986
    updateDeviceToAggregationAndOutputExpressions(
1✔
987
        analysis, analysis.getDeviceToSelectExpressions());
1✔
988
    if (queryStatement.hasOrderByExpression()) {
1✔
989
      updateDeviceToAggregationAndOutputExpressions(
1✔
990
          analysis, analysis.getDeviceToOrderByExpressions());
1✔
991
    }
992
  }
1✔
993

994
  private void updateDeviceToAggregationAndOutputExpressions(
995
      Analysis analysis, Map<String, Set<Expression>> deviceToExpressions) {
996
    // two maps to be updated
997
    Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
998
        analysis.getDeviceToAggregationExpressions();
1✔
999
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
1000
        analysis.getDeviceToOutputExpressions();
1✔
1001

1002
    for (Map.Entry<String, Set<Expression>> deviceExpressionsEntry :
1003
        deviceToExpressions.entrySet()) {
1✔
1004
      String deviceName = deviceExpressionsEntry.getKey();
1✔
1005
      Set<Expression> expressionSet = deviceExpressionsEntry.getValue();
1✔
1006

1007
      Set<Expression> aggregationExpressions = new LinkedHashSet<>();
1✔
1008
      Set<Expression> normalizedAggregationExpressions = new LinkedHashSet<>();
1✔
1009
      for (Expression expression : expressionSet) {
1✔
1010
        for (Expression aggregationExpression :
1011
            ExpressionAnalyzer.searchAggregationExpressions(expression)) {
1✔
1012
          Expression normalizedAggregationExpression =
1✔
1013
              ExpressionAnalyzer.normalizeExpression(aggregationExpression);
1✔
1014
          analyzeExpressionType(analysis, normalizedAggregationExpression);
1✔
1015

1016
          aggregationExpressions.add(aggregationExpression);
1✔
1017
          normalizedAggregationExpressions.add(normalizedAggregationExpression);
1✔
1018
        }
1✔
1019
      }
1✔
1020
      deviceToOutputExpressions
1✔
1021
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1022
          .addAll(aggregationExpressions);
1✔
1023
      deviceToAggregationExpressions
1✔
1024
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1025
          .addAll(normalizedAggregationExpressions);
1✔
1026
    }
1✔
1027
  }
1✔
1028

1029
  private void analyzeAggregation(Analysis analysis, QueryStatement queryStatement) {
1030
    if (!queryStatement.isAggregationQuery()) {
1✔
1031
      return;
1✔
1032
    }
1033

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

1059
  private void analyzeDeviceToSourceTransform(Analysis analysis, QueryStatement queryStatement) {
1060
    if (queryStatement.isAggregationQuery()) {
1✔
1061
      Map<String, Set<Expression>> deviceToSourceTransformExpressions = new HashMap<>();
1✔
1062

1063
      Map<String, Set<Expression>> deviceToAggregationExpressions =
1✔
1064
          analysis.getDeviceToAggregationExpressions();
1✔
1065
      for (Map.Entry<String, Set<Expression>> deviceAggregationExpressionsEntry :
1066
          deviceToAggregationExpressions.entrySet()) {
1✔
1067
        String deviceName = deviceAggregationExpressionsEntry.getKey();
1✔
1068
        Set<Expression> aggregationExpressions = deviceAggregationExpressionsEntry.getValue();
1✔
1069

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

1094
  private void updateDeviceToSourceTransformAndOutputExpressions(
1095
      Analysis analysis, Map<String, Set<Expression>> deviceToExpressions) {
1096
    // two maps to be updated
1097
    Map<String, Set<Expression>> deviceToSourceTransformExpressions =
1✔
1098
        analysis.getDeviceToSourceTransformExpressions();
1✔
1099
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
1100
        analysis.getDeviceToOutputExpressions();
1✔
1101

1102
    for (Map.Entry<String, Set<Expression>> deviceExpressionsEntry :
1103
        deviceToExpressions.entrySet()) {
1✔
1104
      String deviceName = deviceExpressionsEntry.getKey();
1✔
1105
      Set<Expression> expressions = deviceExpressionsEntry.getValue();
1✔
1106

1107
      Set<Expression> normalizedExpressions = new LinkedHashSet<>();
1✔
1108
      for (Expression expression : expressions) {
1✔
1109
        Expression normalizedExpression = ExpressionAnalyzer.normalizeExpression(expression);
1✔
1110
        analyzeExpressionType(analysis, normalizedExpression);
1✔
1111

1112
        normalizedExpressions.add(normalizedExpression);
1✔
1113
      }
1✔
1114
      deviceToOutputExpressions
1✔
1115
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1116
          .addAll(expressions);
1✔
1117
      deviceToSourceTransformExpressions
1✔
1118
          .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1119
          .addAll(normalizedExpressions);
1✔
1120
    }
1✔
1121
  }
1✔
1122

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

1142
  private void analyzeDeviceToSource(Analysis analysis, QueryStatement queryStatement) {
1143
    Map<String, Set<Expression>> deviceToSourceExpressions = new HashMap<>();
1✔
1144
    Map<String, Set<Expression>> deviceToSourceTransformExpressions =
1✔
1145
        analysis.getDeviceToSourceTransformExpressions();
1✔
1146
    for (Map.Entry<String, Set<Expression>> deviceSourceTransformExpressionsEntry :
1147
        deviceToSourceTransformExpressions.entrySet()) {
1✔
1148
      String deviceName = deviceSourceTransformExpressionsEntry.getKey();
1✔
1149
      Set<Expression> sourceTransformExpressions = deviceSourceTransformExpressionsEntry.getValue();
1✔
1150

1151
      Set<Expression> sourceExpressions = new LinkedHashSet<>();
1✔
1152
      for (Expression expression : sourceTransformExpressions) {
1✔
1153
        sourceExpressions.addAll(ExpressionAnalyzer.searchSourceExpressions(expression));
1✔
1154
      }
1✔
1155
      deviceToSourceExpressions.put(deviceName, sourceExpressions);
1✔
1156
    }
1✔
1157
    if (queryStatement.hasWhere()) {
1✔
1158
      Map<String, Expression> deviceToWhereExpression = analysis.getDeviceToWhereExpression();
1✔
1159
      for (Map.Entry<String, Expression> deviceWhereExpressionEntry :
1160
          deviceToWhereExpression.entrySet()) {
1✔
1161
        String deviceName = deviceWhereExpressionEntry.getKey();
1✔
1162
        Expression whereExpression = deviceWhereExpressionEntry.getValue();
1✔
1163
        deviceToSourceExpressions
1✔
1164
            .computeIfAbsent(deviceName, key -> new LinkedHashSet<>())
1✔
1165
            .addAll(ExpressionAnalyzer.searchSourceExpressions(whereExpression));
1✔
1166
      }
1✔
1167
    }
1168

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

1185
    analysis.setDeviceToSourceExpressions(deviceToSourceExpressions);
1✔
1186
    analysis.setOutputDeviceToQueriedDevicesMap(outputDeviceToQueriedDevicesMap);
1✔
1187
  }
1✔
1188

1189
  private void analyzeSource(Analysis analysis, QueryStatement queryStatement) {
1190
    Set<Expression> sourceExpressions = new HashSet<>();
1✔
1191
    for (Expression expression : analysis.getSourceTransformExpressions()) {
1✔
1192
      sourceExpressions.addAll(ExpressionAnalyzer.searchSourceExpressions(expression));
1✔
1193
    }
1✔
1194
    if (queryStatement.hasWhere()) {
1✔
1195
      sourceExpressions.addAll(
1✔
1196
          ExpressionAnalyzer.searchSourceExpressions(analysis.getWhereExpression()));
1✔
1197
    }
1198
    analysis.setSourceExpressions(sourceExpressions);
1✔
1199
  }
1✔
1200

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

1204
  private void analyzeDeviceToWhere(
1205
      Analysis analysis,
1206
      QueryStatement queryStatement,
1207
      ISchemaTree schemaTree,
1208
      Set<PartialPath> deviceSet) {
1209
    if (!queryStatement.hasWhere()) {
1✔
1210
      return;
1✔
1211
    }
1212

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

1231
      TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
1✔
1232
      if (outputType != TSDataType.BOOLEAN) {
1✔
1233
        throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
1234
      }
1235

1236
      deviceToWhereExpression.put(devicePath.getFullPath(), whereExpression);
1✔
1237
    }
1✔
1238
    analysis.setDeviceToWhereExpression(deviceToWhereExpression);
1✔
1239
  }
1✔
1240

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

1263
  private Expression analyzeWhereSplitByDevice(
1264
      QueryStatement queryStatement, PartialPath devicePath, ISchemaTree schemaTree) {
1265
    List<Expression> conJunctions =
1✔
1266
        ExpressionAnalyzer.concatDeviceAndBindSchemaForPredicate(
1✔
1267
            queryStatement.getWhereCondition().getPredicate(), devicePath, schemaTree, true);
1✔
1268
    return ExpressionUtils.constructQueryFilter(
1✔
1269
        conJunctions.stream().distinct().collect(Collectors.toList()));
1✔
1270
  }
1271

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

1305
  private boolean analyzeDeviceViewSpecialProcess(
1306
      Set<Expression> deviceViewOutputExpressions,
1307
      QueryStatement queryStatement,
1308
      Analysis analysis) {
1309
    if (queryStatement.isAggregationQuery()
1✔
1310
        || queryStatement.hasWhere()
1✔
1311
            && ExpressionAnalyzer.isDeviceViewNeedSpecialProcess(
1✔
1312
                queryStatement.getWhereCondition().getPredicate(), analysis)) {
1✔
1313
      return true;
1✔
1314
    }
1315
    for (Expression expression : deviceViewOutputExpressions) {
1✔
1316
      if (ExpressionAnalyzer.isDeviceViewNeedSpecialProcess(expression, analysis)) {
1✔
1317
        return true;
1✔
1318
      }
1319
    }
1✔
1320
    return false;
1✔
1321
  }
1322

1323
  private void analyzeDeviceViewInput(Analysis analysis, QueryStatement queryStatement) {
1324
    List<String> deviceViewOutputColumns =
1✔
1325
        analysis.getDeviceViewOutputExpressions().stream()
1✔
1326
            .map(Expression::getOutputSymbol)
1✔
1327
            .collect(Collectors.toList());
1✔
1328

1329
    Map<String, Set<String>> deviceToOutputColumnsMap = new LinkedHashMap<>();
1✔
1330
    Map<String, Set<Expression>> deviceToOutputExpressions =
1✔
1331
        analysis.getDeviceToOutputExpressions();
1✔
1332
    for (Map.Entry<String, Set<Expression>> deviceOutputExpressionEntry :
1333
        deviceToOutputExpressions.entrySet()) {
1✔
1334
      Set<Expression> outputExpressionsUnderDevice = deviceOutputExpressionEntry.getValue();
1✔
1335
      checkDeviceViewInputUniqueness(outputExpressionsUnderDevice);
1✔
1336

1337
      Set<String> outputColumns = new LinkedHashSet<>();
1✔
1338
      if (queryStatement.isOutputEndTime()) {
1✔
1339
        outputColumns.add(ENDTIME);
×
1340
      }
1341
      for (Expression expression : outputExpressionsUnderDevice) {
1✔
1342
        outputColumns.add(
1✔
1343
            ExpressionAnalyzer.getMeasurementExpression(expression, analysis).getOutputSymbol());
1✔
1344
      }
1✔
1345
      deviceToOutputColumnsMap.put(deviceOutputExpressionEntry.getKey(), outputColumns);
1✔
1346
    }
1✔
1347

1348
    Map<String, List<Integer>> deviceViewInputIndexesMap = new HashMap<>();
1✔
1349
    for (Map.Entry<String, Set<String>> deviceOutputColumnsEntry :
1350
        deviceToOutputColumnsMap.entrySet()) {
1✔
1351
      String deviceName = deviceOutputColumnsEntry.getKey();
1✔
1352
      List<String> outputsUnderDevice = new ArrayList<>(deviceOutputColumnsEntry.getValue());
1✔
1353

1354
      List<Integer> indexes = new ArrayList<>();
1✔
1355
      for (String output : outputsUnderDevice) {
1✔
1356
        int index = deviceViewOutputColumns.indexOf(output);
1✔
1357
        checkState(
1✔
1358
            index >= 1, "output column '%s' is not stored in %s", output, deviceViewOutputColumns);
1359
        indexes.add(index);
1✔
1360
      }
1✔
1361
      deviceViewInputIndexesMap.put(deviceName, indexes);
1✔
1362
    }
1✔
1363
    analysis.setDeviceViewInputIndexesMap(deviceViewInputIndexesMap);
1✔
1364
  }
1✔
1365

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

1378
  private void analyzeOutput(
1379
      Analysis analysis,
1380
      QueryStatement queryStatement,
1381
      List<Pair<Expression, String>> outputExpressions) {
1382
    if (queryStatement.isSelectInto()) {
1✔
1383
      analysis.setRespDatasetHeader(
1✔
1384
          DatasetHeaderFactory.getSelectIntoHeader(queryStatement.isAlignByDevice()));
1✔
1385
      return;
1✔
1386
    }
1387

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

1406
  // For last query
1407
  private void analyzeLastOrderBy(Analysis analysis, QueryStatement queryStatement) {
1408
    if (!queryStatement.hasOrderBy()) return;
×
1409

1410
    if (queryStatement.onlyOrderByTimeseries()) {
×
1411
      analysis.setTimeseriesOrderingForLastQuery(
×
1412
          queryStatement.getOrderByComponent().getTimeseriesOrder());
×
1413
    }
1414

1415
    for (SortItem sortItem : queryStatement.getSortItemList()) {
×
1416
      String sortKey = sortItem.getSortKey();
×
1417
      if (!lastQueryColumnNames.contains(sortKey.toUpperCase())) {
×
1418
        throw new SemanticException(
×
1419
            String.format(
×
1420
                "%s in order by clause doesn't exist in the result of last query.", sortKey));
1421
      }
1422
    }
×
1423
  }
×
1424

1425
  private void analyzeOrderBy(
1426
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1427
    if (!queryStatement.hasOrderByExpression()) return;
1✔
1428

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

1457
  private TSDataType analyzeExpressionType(Analysis analysis, Expression expression) {
1458
    return ExpressionTypeAnalyzer.analyzeExpression(analysis, expression);
1✔
1459
  }
1460

1461
  private void analyzeDeviceToGroupBy(
1462
      Analysis analysis,
1463
      QueryStatement queryStatement,
1464
      ISchemaTree schemaTree,
1465
      Set<PartialPath> deviceSet) {
1466
    if (queryStatement.getGroupByComponent() == null) {
1✔
1467
      return;
1✔
1468
    }
1469
    GroupByComponent groupByComponent = queryStatement.getGroupByComponent();
×
1470
    WindowType windowType = groupByComponent.getWindowType();
×
1471

1472
    Map<String, Expression> deviceToGroupByExpression = new LinkedHashMap<>();
×
1473
    if (queryStatement.hasGroupByExpression()) {
×
1474
      Expression expression = groupByComponent.getControlColumnExpression();
×
1475
      for (PartialPath device : deviceSet) {
×
1476
        List<Expression> groupByExpressionsOfOneDevice =
×
1477
            ExpressionAnalyzer.concatDeviceAndBindSchemaForExpression(
×
1478
                expression, device, schemaTree);
1479

1480
        if (groupByExpressionsOfOneDevice.isEmpty()) {
×
1481
          throw new SemanticException(
×
1482
              String.format("%s in group by clause doesn't exist.", expression));
×
1483
        }
1484
        if (groupByExpressionsOfOneDevice.size() > 1) {
×
1485
          throw new SemanticException(
×
1486
              String.format(
×
1487
                  "%s in group by clause shouldn't refer to more than one timeseries.",
1488
                  expression));
1489
        }
1490
        deviceToGroupByExpression.put(
×
1491
            device.getFullPath(),
×
1492
            ExpressionAnalyzer.normalizeExpression(groupByExpressionsOfOneDevice.get(0)));
×
1493
      }
×
1494
    }
1495

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

1534
  private void analyzeDeviceToOrderBy(
1535
      Analysis analysis,
1536
      QueryStatement queryStatement,
1537
      ISchemaTree schemaTree,
1538
      Set<PartialPath> deviceSet) {
1539
    if (!queryStatement.hasOrderByExpression()) {
1✔
1540
      return;
1✔
1541
    }
1542

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

1571
        Expression deviceViewExpression =
1✔
1572
            ExpressionAnalyzer.getMeasurementExpression(expressionForItem, analysis);
1✔
1573
        analyzeExpressionType(analysis, deviceViewExpression);
1✔
1574

1575
        deviceViewOrderByExpression.add(deviceViewExpression);
1✔
1576
        orderByExpressionsForOneDevice.add(expressionForItem);
1✔
1577
      }
1✔
1578
      deviceToSortItems.put(
1✔
1579
          device.getFullPath(), queryStatement.getUpdatedSortItems(orderByExpressionsForOneDevice));
1✔
1580
      deviceToOrderByExpressions.put(device.getFullPath(), orderByExpressionsForOneDevice);
1✔
1581
    }
1✔
1582

1583
    analysis.setOrderByExpressions(deviceViewOrderByExpression);
1✔
1584
    queryStatement.updateSortItems(deviceViewOrderByExpression);
1✔
1585
    analysis.setDeviceToSortItems(deviceToSortItems);
1✔
1586
    analysis.setDeviceToOrderByExpressions(deviceToOrderByExpressions);
1✔
1587
  }
1✔
1588

1589
  private void analyzeGroupBy(
1590
      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
1591

1592
    if (queryStatement.getGroupByComponent() == null) {
1✔
1593
      return;
1✔
1594
    }
1595
    GroupByComponent groupByComponent = queryStatement.getGroupByComponent();
×
1596
    WindowType windowType = groupByComponent.getWindowType();
×
1597

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

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

1656
  private void checkGroupByVariationExpressionType(
1657
      Analysis analysis, Expression groupByExpression, double delta) {
1658
    TSDataType type = analyzeExpressionType(analysis, groupByExpression);
×
1659
    if (delta != 0 && !type.isNumeric()) {
×
1660
      throw new SemanticException("Only support numeric type when delta != 0");
×
1661
    }
1662
  }
×
1663

1664
  private void checkGroupByConditionExpressionType(
1665
      Analysis analysis, Expression groupByExpression, Expression keepExpression) {
1666
    TSDataType type = analyzeExpressionType(analysis, groupByExpression);
×
1667
    if (type != TSDataType.BOOLEAN) {
×
1668
      throw new SemanticException("Only support boolean type in predict of group by series");
×
1669
    }
1670

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

1693
  private void analyzeGroupByTime(Analysis analysis, QueryStatement queryStatement) {
1694
    if (!queryStatement.isGroupByTime()) {
1✔
1695
      return;
1✔
1696
    }
1697

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

1711
  private void analyzeFill(Analysis analysis, QueryStatement queryStatement) {
1712
    if (queryStatement.getFillComponent() == null) {
1✔
1713
      return;
1✔
1714
    }
1715

1716
    FillComponent fillComponent = queryStatement.getFillComponent();
1✔
1717
    analysis.setFillDescriptor(
1✔
1718
        new FillDescriptor(fillComponent.getFillPolicy(), fillComponent.getFillValue()));
1✔
1719
  }
1✔
1720

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

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

1761
      if (res.right.left || res.right.right) {
1✔
1762
        return partitionFetcher.getDataPartitionWithUnclosedTimeRange(sgNameToQueryParamsMap);
1✔
1763
      } else {
1764
        return partitionFetcher.getDataPartition(sgNameToQueryParamsMap);
1✔
1765
      }
1766
    } finally {
1767
      QueryPlanCostMetricSet.getInstance()
1✔
1768
          .recordPlanCost(PARTITION_FETCHER, System.nanoTime() - startTime);
1✔
1769
    }
1770
  }
1771

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

1796
    boolean needLeftAll;
1797
    boolean needRightAll;
1798
    long startTime;
1799
    long endTime;
1800
    TTimePartitionSlot timePartitionSlot;
1801
    int index = 0;
1✔
1802
    int size = timeRangeList.size();
1✔
1803

1804
    if (timeRangeList.get(0).getMin() == Long.MIN_VALUE) {
1✔
1805
      needLeftAll = true;
1✔
1806
      startTime =
1✔
1807
          (timeRangeList.get(0).getMax() / TimePartitionUtils.timePartitionInterval)
1✔
1808
              * TimePartitionUtils.timePartitionInterval; // included
1809
      endTime = startTime + TimePartitionUtils.timePartitionInterval; // excluded
1✔
1810
      timePartitionSlot = TimePartitionUtils.getTimePartition(timeRangeList.get(0).getMax());
1✔
1811
    } else {
1812
      startTime =
1✔
1813
          (timeRangeList.get(0).getMin() / TimePartitionUtils.timePartitionInterval)
1✔
1814
              * TimePartitionUtils.timePartitionInterval; // included
1815
      endTime = startTime + TimePartitionUtils.timePartitionInterval; // excluded
1✔
1816
      timePartitionSlot = TimePartitionUtils.getTimePartition(timeRangeList.get(0).getMin());
1✔
1817
      needLeftAll = false;
1✔
1818
    }
1819

1820
    if (timeRangeList.get(size - 1).getMax() == Long.MAX_VALUE) {
1✔
1821
      needRightAll = true;
1✔
1822
      size--;
1✔
1823
    } else {
1824
      needRightAll = false;
1✔
1825
    }
1826

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

1849
    if (needRightAll) {
1✔
1850
      TTimePartitionSlot lastTimePartitionSlot =
1✔
1851
          TimePartitionUtils.getTimePartition(timeRangeList.get(timeRangeList.size() - 1).getMin());
1✔
1852
      if (lastTimePartitionSlot.startTime != timePartitionSlot.startTime) {
1✔
1853
        result.add(lastTimePartitionSlot);
×
1854
      }
1855
    }
1856
    return new Pair<>(result, new Pair<>(needLeftAll, needRightAll));
1✔
1857
  }
1858

1859
  private void analyzeInto(
1860
      Analysis analysis,
1861
      QueryStatement queryStatement,
1862
      Set<PartialPath> deviceSet,
1863
      List<Pair<Expression, String>> outputExpressions) {
1864
    if (!queryStatement.isSelectInto()) {
1✔
1865
      return;
1✔
1866
    }
1867
    queryStatement.setOrderByComponent(null);
1✔
1868

1869
    List<PartialPath> sourceDevices = new ArrayList<>(deviceSet);
1✔
1870
    List<Expression> sourceColumns =
1✔
1871
        outputExpressions.stream()
1✔
1872
            .map(Pair::getLeft)
1✔
1873
            .collect(Collectors.toCollection(ArrayList::new));
1✔
1874

1875
    IntoComponent intoComponent = queryStatement.getIntoComponent();
1✔
1876
    intoComponent.validate(sourceDevices, sourceColumns);
1✔
1877

1878
    DeviceViewIntoPathDescriptor deviceViewIntoPathDescriptor = new DeviceViewIntoPathDescriptor();
1✔
1879
    PathPatternTree targetPathTree = new PathPatternTree();
1✔
1880
    IntoComponent.IntoDeviceMeasurementIterator intoDeviceMeasurementIterator =
1✔
1881
        intoComponent.getIntoDeviceMeasurementIterator();
1✔
1882
    for (PartialPath sourceDevice : sourceDevices) {
1✔
1883
      PartialPath deviceTemplate = intoDeviceMeasurementIterator.getDeviceTemplate();
1✔
1884
      boolean isAlignedDevice = intoDeviceMeasurementIterator.isAlignedDevice();
1✔
1885
      PartialPath targetDevice = constructTargetDevice(sourceDevice, deviceTemplate);
1✔
1886
      deviceViewIntoPathDescriptor.specifyDeviceAlignment(targetDevice.toString(), isAlignedDevice);
1✔
1887

1888
      for (Expression sourceColumn : sourceColumns) {
1✔
1889
        String measurementTemplate = intoDeviceMeasurementIterator.getMeasurementTemplate();
1✔
1890
        String targetMeasurement;
1891
        if (sourceColumn instanceof TimeSeriesOperand) {
1✔
1892
          targetMeasurement =
1✔
1893
              constructTargetMeasurement(
1✔
1894
                  sourceDevice.concatNode(sourceColumn.getExpressionString()), measurementTemplate);
1✔
1895
        } else {
1896
          targetMeasurement = measurementTemplate;
1✔
1897
        }
1898
        deviceViewIntoPathDescriptor.specifyTargetDeviceMeasurement(
1✔
1899
            sourceDevice, targetDevice, sourceColumn.getExpressionString(), targetMeasurement);
1✔
1900

1901
        targetPathTree.appendFullPath(targetDevice, targetMeasurement);
1✔
1902
        deviceViewIntoPathDescriptor.recordSourceColumnDataType(
1✔
1903
            sourceColumn.getExpressionString(), analysis.getType(sourceColumn));
1✔
1904

1905
        intoDeviceMeasurementIterator.nextMeasurement();
1✔
1906
      }
1✔
1907

1908
      intoDeviceMeasurementIterator.nextDevice();
1✔
1909
    }
1✔
1910
    deviceViewIntoPathDescriptor.validate();
1✔
1911

1912
    // fetch schema of target paths
1913
    long startTime = System.nanoTime();
1✔
1914
    ISchemaTree targetSchemaTree = schemaFetcher.fetchSchema(targetPathTree, null);
1✔
1915
    QueryPlanCostMetricSet.getInstance()
1✔
1916
        .recordPlanCost(SCHEMA_FETCHER, System.nanoTime() - startTime);
1✔
1917
    deviceViewIntoPathDescriptor.bindType(targetSchemaTree);
1✔
1918

1919
    analysis.setDeviceViewIntoPathDescriptor(deviceViewIntoPathDescriptor);
1✔
1920
  }
1✔
1921

1922
  private void analyzeInto(
1923
      Analysis analysis,
1924
      QueryStatement queryStatement,
1925
      List<Pair<Expression, String>> outputExpressions) {
1926
    if (!queryStatement.isSelectInto()) {
1✔
1927
      return;
1✔
1928
    }
1929
    queryStatement.setOrderByComponent(null);
1✔
1930

1931
    List<Expression> sourceColumns =
1✔
1932
        outputExpressions.stream()
1✔
1933
            .map(Pair::getLeft)
1✔
1934
            .collect(Collectors.toCollection(ArrayList::new));
1✔
1935

1936
    IntoComponent intoComponent = queryStatement.getIntoComponent();
1✔
1937
    intoComponent.validate(sourceColumns);
1✔
1938

1939
    IntoPathDescriptor intoPathDescriptor = new IntoPathDescriptor();
1✔
1940
    PathPatternTree targetPathTree = new PathPatternTree();
1✔
1941
    IntoComponent.IntoPathIterator intoPathIterator = intoComponent.getIntoPathIterator();
1✔
1942
    for (Pair<Expression, String> pair : outputExpressions) {
1✔
1943
      Expression sourceExpression = pair.left;
1✔
1944
      String viewPath = pair.right;
1✔
1945
      PartialPath deviceTemplate = intoPathIterator.getDeviceTemplate();
1✔
1946
      String measurementTemplate = intoPathIterator.getMeasurementTemplate();
1✔
1947
      boolean isAlignedDevice = intoPathIterator.isAlignedDevice();
1✔
1948

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

1972
      targetPathTree.appendFullPath(targetPath);
1✔
1973
      intoPathDescriptor.recordSourceColumnDataType(
1✔
1974
          sourceColumn, analysis.getType(sourceExpression));
1✔
1975

1976
      intoPathIterator.next();
1✔
1977
    }
1✔
1978
    intoPathDescriptor.validate();
1✔
1979

1980
    // fetch schema of target paths
1981
    long startTime = System.nanoTime();
1✔
1982
    ISchemaTree targetSchemaTree = schemaFetcher.fetchSchema(targetPathTree, null);
1✔
1983
    updateSchemaTreeByViews(analysis, targetSchemaTree);
1✔
1984
    QueryPlanCostMetricSet.getInstance()
1✔
1985
        .recordPlanCost(SCHEMA_FETCHER, System.nanoTime() - startTime);
1✔
1986
    intoPathDescriptor.bindType(targetSchemaTree);
1✔
1987

1988
    analysis.setIntoPathDescriptor(intoPathDescriptor);
1✔
1989
  }
1✔
1990

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

2008
  private void checkAliasUniqueness(String alias, Set<String> aliasSet) {
2009
    if (alias != null) {
1✔
2010
      if (aliasSet.contains(alias)) {
1✔
2011
        throw new SemanticException(
1✔
2012
            String.format("alias '%s' can only be matched with one time series", alias));
1✔
2013
      }
2014
      aliasSet.add(alias);
1✔
2015
    }
2016
  }
1✔
2017

2018
  private void checkAliasUniqueness(
2019
      String alias, Map<Expression, Map<String, Expression>> measurementToDeviceSelectExpressions) {
2020
    if (alias != null && measurementToDeviceSelectExpressions.keySet().size() > 1) {
1✔
2021
      throw new SemanticException(
×
2022
          String.format("alias '%s' can only be matched with one time series", alias));
×
2023
    }
2024
  }
1✔
2025

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

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

2094
    Analysis analysis = new Analysis();
×
2095
    analysis.setStatement(createTimeSeriesStatement);
×
2096

2097
    checkIsTemplateCompatible(
×
2098
        createTimeSeriesStatement.getPath(), createTimeSeriesStatement.getAlias());
×
2099

2100
    PathPatternTree patternTree = new PathPatternTree();
×
2101
    patternTree.appendFullPath(createTimeSeriesStatement.getPath());
×
2102
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2103
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2104
    return analysis;
×
2105
  }
2106

2107
  private void checkIsTemplateCompatible(PartialPath timeseriesPath, String alias) {
2108
    Pair<Template, PartialPath> templateInfo =
×
2109
        schemaFetcher.checkTemplateSetAndPreSetInfo(timeseriesPath, alias);
×
2110
    if (templateInfo != null) {
×
2111
      throw new SemanticException(
×
2112
          new TemplateIncompatibleException(
2113
              timeseriesPath.getFullPath(), templateInfo.left.getName(), templateInfo.right));
×
2114
    }
2115
  }
×
2116

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

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

2156
  private void analyzeSchemaProps(List<Map<String, String>> propsList) {
2157
    if (propsList == null) {
×
2158
      return;
×
2159
    }
2160
    for (Map<String, String> props : propsList) {
×
2161
      analyzeSchemaProps(props);
×
2162
    }
×
2163
  }
×
2164

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

2180
    Analysis analysis = new Analysis();
×
2181
    analysis.setStatement(createAlignedTimeSeriesStatement);
×
2182

2183
    checkIsTemplateCompatible(
×
2184
        createAlignedTimeSeriesStatement.getDevicePath(),
×
2185
        createAlignedTimeSeriesStatement.getMeasurements(),
×
2186
        createAlignedTimeSeriesStatement.getAliasList());
×
2187

2188
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2189
    for (String measurement : createAlignedTimeSeriesStatement.getMeasurements()) {
×
2190
      pathPatternTree.appendFullPath(createAlignedTimeSeriesStatement.getDevicePath(), measurement);
×
2191
    }
×
2192

2193
    SchemaPartition schemaPartitionInfo;
2194
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2195
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2196
    return analysis;
×
2197
  }
2198

2199
  @Override
2200
  public Analysis visitInternalCreateTimeseries(
2201
      InternalCreateTimeSeriesStatement internalCreateTimeSeriesStatement,
2202
      MPPQueryContext context) {
2203
    context.setQueryType(QueryType.WRITE);
×
2204

2205
    Analysis analysis = new Analysis();
×
2206
    analysis.setStatement(internalCreateTimeSeriesStatement);
×
2207

2208
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2209
    for (String measurement : internalCreateTimeSeriesStatement.getMeasurements()) {
×
2210
      pathPatternTree.appendFullPath(
×
2211
          internalCreateTimeSeriesStatement.getDevicePath(), measurement);
×
2212
    }
×
2213

2214
    SchemaPartition schemaPartitionInfo;
2215
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2216
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2217
    return analysis;
×
2218
  }
2219

2220
  @Override
2221
  public Analysis visitInternalCreateMultiTimeSeries(
2222
      InternalCreateMultiTimeSeriesStatement internalCreateMultiTimeSeriesStatement,
2223
      MPPQueryContext context) {
2224
    context.setQueryType(QueryType.WRITE);
×
2225

2226
    Analysis analysis = new Analysis();
×
2227
    analysis.setStatement(internalCreateMultiTimeSeriesStatement);
×
2228

2229
    PathPatternTree pathPatternTree = new PathPatternTree();
×
2230
    for (PartialPath devicePath : internalCreateMultiTimeSeriesStatement.getDeviceMap().keySet()) {
×
2231
      pathPatternTree.appendFullPath(devicePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
2232
    }
×
2233

2234
    SchemaPartition schemaPartitionInfo;
2235
    schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(pathPatternTree);
×
2236
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2237
    return analysis;
×
2238
  }
2239

2240
  @Override
2241
  public Analysis visitCreateMultiTimeseries(
2242
      CreateMultiTimeSeriesStatement createMultiTimeSeriesStatement, MPPQueryContext context) {
2243
    context.setQueryType(QueryType.WRITE);
×
2244
    Analysis analysis = new Analysis();
×
2245
    analysis.setStatement(createMultiTimeSeriesStatement);
×
2246

2247
    analyzeSchemaProps(createMultiTimeSeriesStatement.getPropsList());
×
2248

2249
    List<PartialPath> timeseriesPathList = createMultiTimeSeriesStatement.getPaths();
×
2250
    List<String> aliasList = createMultiTimeSeriesStatement.getAliasList();
×
2251
    for (int i = 0; i < timeseriesPathList.size(); i++) {
×
2252
      checkIsTemplateCompatible(
×
2253
          timeseriesPathList.get(i), aliasList == null ? null : aliasList.get(i));
×
2254
    }
2255

2256
    PathPatternTree patternTree = new PathPatternTree();
×
2257
    for (PartialPath path : createMultiTimeSeriesStatement.getPaths()) {
×
2258
      patternTree.appendFullPath(path);
×
2259
    }
×
2260
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
2261
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2262
    return analysis;
×
2263
  }
2264

2265
  @Override
2266
  public Analysis visitAlterTimeseries(
2267
      AlterTimeSeriesStatement alterTimeSeriesStatement, MPPQueryContext context) {
2268
    context.setQueryType(QueryType.WRITE);
×
2269
    Analysis analysis = new Analysis();
×
2270
    analysis.setStatement(alterTimeSeriesStatement);
×
2271

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

2285
    PathPatternTree patternTree = new PathPatternTree();
×
2286
    patternTree.appendFullPath(alterTimeSeriesStatement.getPath());
×
2287
    SchemaPartition schemaPartitionInfo;
2288
    schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2289
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2290
    return analysis;
×
2291
  }
2292

2293
  @Override
2294
  public Analysis visitInsertTablet(
2295
      InsertTabletStatement insertTabletStatement, MPPQueryContext context) {
2296
    context.setQueryType(QueryType.WRITE);
×
2297
    Analysis analysis = new Analysis();
×
2298
    validateSchema(analysis, insertTabletStatement, context);
×
2299
    InsertBaseStatement realStatement = removeLogicalView(analysis, insertTabletStatement);
×
2300
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2301
      return analysis;
×
2302
    }
2303
    analysis.setStatement(realStatement);
×
2304

2305
    if (realStatement instanceof InsertTabletStatement) {
×
2306
      InsertTabletStatement realInsertTabletStatement = (InsertTabletStatement) realStatement;
×
2307
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2308
      dataPartitionQueryParam.setDevicePath(
×
2309
          realInsertTabletStatement.getDevicePath().getFullPath());
×
2310
      dataPartitionQueryParam.setTimePartitionSlotList(
×
2311
          realInsertTabletStatement.getTimePartitionSlots());
×
2312

2313
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
×
2314
    } else {
2315
      return computeAnalysisForMultiTablets(analysis, (InsertMultiTabletsStatement) realStatement);
×
2316
    }
2317
  }
2318

2319
  @Override
2320
  public Analysis visitInsertRow(InsertRowStatement insertRowStatement, MPPQueryContext context) {
2321
    context.setQueryType(QueryType.WRITE);
×
2322
    Analysis analysis = new Analysis();
×
2323
    validateSchema(analysis, insertRowStatement, context);
×
2324
    InsertBaseStatement realInsertStatement = removeLogicalView(analysis, insertRowStatement);
×
2325
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2326
      return analysis;
×
2327
    }
2328
    analysis.setStatement(realInsertStatement);
×
2329

2330
    if (realInsertStatement instanceof InsertRowStatement) {
×
2331
      InsertRowStatement realInsertRowStatement = (InsertRowStatement) realInsertStatement;
×
2332
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2333
      dataPartitionQueryParam.setDevicePath(realInsertRowStatement.getDevicePath().getFullPath());
×
2334
      dataPartitionQueryParam.setTimePartitionSlotList(
×
2335
          Collections.singletonList(realInsertRowStatement.getTimePartitionSlot()));
×
2336

2337
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
×
2338
    } else {
2339
      return computeAnalysisForInsertRows(analysis, (InsertRowsStatement) realInsertStatement);
×
2340
    }
2341
  }
2342

2343
  private Analysis computeAnalysisForInsertRows(
2344
      Analysis analysis, InsertRowsStatement insertRowsStatement) {
2345
    Map<String, Set<TTimePartitionSlot>> dataPartitionQueryParamMap = new HashMap<>();
×
2346
    for (InsertRowStatement insertRowStatement : insertRowsStatement.getInsertRowStatementList()) {
×
2347
      Set<TTimePartitionSlot> timePartitionSlotSet =
×
2348
          dataPartitionQueryParamMap.computeIfAbsent(
×
2349
              insertRowStatement.getDevicePath().getFullPath(), k -> new HashSet<>());
×
2350
      timePartitionSlotSet.add(insertRowStatement.getTimePartitionSlot());
×
2351
    }
×
2352

2353
    List<DataPartitionQueryParam> dataPartitionQueryParams = new ArrayList<>();
×
2354
    for (Map.Entry<String, Set<TTimePartitionSlot>> entry : dataPartitionQueryParamMap.entrySet()) {
×
2355
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
×
2356
      dataPartitionQueryParam.setDevicePath(entry.getKey());
×
2357
      dataPartitionQueryParam.setTimePartitionSlotList(new ArrayList<>(entry.getValue()));
×
2358
      dataPartitionQueryParams.add(dataPartitionQueryParam);
×
2359
    }
×
2360

2361
    return getAnalysisForWriting(analysis, dataPartitionQueryParams);
×
2362
  }
2363

2364
  @Override
2365
  public Analysis visitInsertRows(
2366
      InsertRowsStatement insertRowsStatement, MPPQueryContext context) {
2367
    context.setQueryType(QueryType.WRITE);
×
2368
    Analysis analysis = new Analysis();
×
2369
    validateSchema(analysis, insertRowsStatement, context);
×
2370
    InsertRowsStatement realInsertRowsStatement =
×
2371
        (InsertRowsStatement) removeLogicalView(analysis, insertRowsStatement);
×
2372
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2373
      return analysis;
×
2374
    }
2375
    analysis.setStatement(realInsertRowsStatement);
×
2376

2377
    return computeAnalysisForInsertRows(analysis, realInsertRowsStatement);
×
2378
  }
2379

2380
  private Analysis computeAnalysisForMultiTablets(
2381
      Analysis analysis, InsertMultiTabletsStatement insertMultiTabletsStatement) {
2382
    Map<String, Set<TTimePartitionSlot>> dataPartitionQueryParamMap = new HashMap<>();
×
2383
    for (InsertTabletStatement insertTabletStatement :
2384
        insertMultiTabletsStatement.getInsertTabletStatementList()) {
×
2385
      Set<TTimePartitionSlot> timePartitionSlotSet =
×
2386
          dataPartitionQueryParamMap.computeIfAbsent(
×
2387
              insertTabletStatement.getDevicePath().getFullPath(), k -> new HashSet<>());
×
2388
      timePartitionSlotSet.addAll(insertTabletStatement.getTimePartitionSlots());
×
2389
    }
×
2390

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

2399
    return getAnalysisForWriting(analysis, dataPartitionQueryParams);
×
2400
  }
2401

2402
  @Override
2403
  public Analysis visitInsertMultiTablets(
2404
      InsertMultiTabletsStatement insertMultiTabletsStatement, MPPQueryContext context) {
2405
    context.setQueryType(QueryType.WRITE);
×
2406
    Analysis analysis = new Analysis();
×
2407
    validateSchema(analysis, insertMultiTabletsStatement, context);
×
2408
    InsertMultiTabletsStatement realStatement =
×
2409
        (InsertMultiTabletsStatement) removeLogicalView(analysis, insertMultiTabletsStatement);
×
2410
    if (analysis.isFinishQueryAfterAnalyze()) {
×
2411
      return analysis;
×
2412
    }
2413
    analysis.setStatement(realStatement);
×
2414

2415
    return computeAnalysisForMultiTablets(analysis, realStatement);
×
2416
  }
2417

2418
  @Override
2419
  public Analysis visitInsertRowsOfOneDevice(
2420
      InsertRowsOfOneDeviceStatement insertRowsOfOneDeviceStatement, MPPQueryContext context) {
2421
    context.setQueryType(QueryType.WRITE);
1✔
2422
    Analysis analysis = new Analysis();
1✔
2423
    validateSchema(analysis, insertRowsOfOneDeviceStatement, context);
1✔
2424
    InsertBaseStatement realInsertStatement =
1✔
2425
        removeLogicalView(analysis, insertRowsOfOneDeviceStatement);
1✔
2426
    if (analysis.isFinishQueryAfterAnalyze()) {
1✔
2427
      return analysis;
×
2428
    }
2429
    analysis.setStatement(realInsertStatement);
1✔
2430

2431
    if (realInsertStatement instanceof InsertRowsOfOneDeviceStatement) {
1✔
2432
      InsertRowsOfOneDeviceStatement realStatement =
1✔
2433
          (InsertRowsOfOneDeviceStatement) realInsertStatement;
2434
      DataPartitionQueryParam dataPartitionQueryParam = new DataPartitionQueryParam();
1✔
2435
      dataPartitionQueryParam.setDevicePath(realStatement.getDevicePath().getFullPath());
1✔
2436
      dataPartitionQueryParam.setTimePartitionSlotList(realStatement.getTimePartitionSlots());
1✔
2437

2438
      return getAnalysisForWriting(analysis, Collections.singletonList(dataPartitionQueryParam));
1✔
2439
    } else {
2440
      return computeAnalysisForInsertRows(analysis, (InsertRowsStatement) realInsertStatement);
×
2441
    }
2442
  }
2443

2444
  private void validateSchema(
2445
      Analysis analysis, InsertBaseStatement insertStatement, MPPQueryContext context) {
2446
    final long startTime = System.nanoTime();
1✔
2447
    try {
2448
      SchemaValidator.validate(schemaFetcher, insertStatement, context);
1✔
2449
    } catch (SemanticException e) {
×
2450
      analysis.setFinishQueryAfterAnalyze(true);
×
2451
      if (e.getCause() instanceof IoTDBException) {
×
2452
        IoTDBException exception = (IoTDBException) e.getCause();
×
2453
        analysis.setFailStatus(
×
2454
            RpcUtils.getStatus(exception.getErrorCode(), exception.getMessage()));
×
2455
      } else {
×
2456
        analysis.setFailStatus(RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage()));
×
2457
      }
2458
    } finally {
2459
      PERFORMANCE_OVERVIEW_METRICS.recordScheduleSchemaValidateCost(System.nanoTime() - startTime);
1✔
2460
    }
2461
    boolean hasFailedMeasurement = insertStatement.hasFailedMeasurements();
1✔
2462
    String partialInsertMessage;
2463
    if (hasFailedMeasurement) {
1✔
2464
      partialInsertMessage =
×
2465
          String.format(
×
2466
              "Fail to insert measurements %s caused by %s",
2467
              insertStatement.getFailedMeasurements(), insertStatement.getFailedMessages());
×
2468
      logger.warn(partialInsertMessage);
×
2469
      analysis.setFailStatus(
×
2470
          RpcUtils.getStatus(TSStatusCode.METADATA_ERROR.getStatusCode(), partialInsertMessage));
×
2471
    }
2472
  }
1✔
2473

2474
  private InsertBaseStatement removeLogicalView(
2475
      Analysis analysis, InsertBaseStatement insertBaseStatement) {
2476
    try {
2477
      return insertBaseStatement.removeLogicalView();
1✔
2478
    } catch (SemanticException e) {
×
2479
      analysis.setFinishQueryAfterAnalyze(true);
×
2480
      if (e.getCause() instanceof IoTDBException) {
×
2481
        IoTDBException exception = (IoTDBException) e.getCause();
×
2482
        analysis.setFailStatus(
×
2483
            RpcUtils.getStatus(exception.getErrorCode(), exception.getMessage()));
×
2484
      } else {
×
2485
        analysis.setFailStatus(RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, e.getMessage()));
×
2486
      }
2487
      return insertBaseStatement;
×
2488
    }
2489
  }
2490

2491
  @Override
2492
  public Analysis visitLoadFile(LoadTsFileStatement loadTsFileStatement, MPPQueryContext context) {
2493
    context.setQueryType(QueryType.WRITE);
×
2494

2495
    Map<String, Map<MeasurementSchema, File>> device2Schemas = new HashMap<>();
×
2496
    Map<String, Pair<Boolean, File>> device2IsAligned = new HashMap<>();
×
2497

2498
    // analyze tsfile metadata
2499
    for (File tsFile : loadTsFileStatement.getTsFiles()) {
×
2500
      if (tsFile.length() == 0) {
×
2501
        if (logger.isWarnEnabled()) {
×
2502
          logger.warn(String.format("TsFile %s is empty.", tsFile.getPath()));
×
2503
        }
2504
        throw new SemanticException(
×
2505
            String.format(
×
2506
                "TsFile %s is empty, please check it be flushed to disk correctly.",
2507
                tsFile.getPath()));
×
2508
      }
2509
      try {
2510
        TsFileResource resource =
×
2511
            analyzeTsFile(loadTsFileStatement, tsFile, device2Schemas, device2IsAligned);
×
2512
        loadTsFileStatement.addTsFileResource(resource);
×
2513
      } catch (IllegalArgumentException e) {
×
2514
        logger.warn(
×
2515
            String.format(
×
2516
                "Parse file %s to resource error, this TsFile maybe empty.", tsFile.getPath()),
×
2517
            e);
2518
        throw new SemanticException(
×
2519
            String.format("TsFile %s is empty or incomplete.", tsFile.getPath()));
×
2520
      } catch (Exception e) {
×
2521
        logger.warn(String.format("Parse file %s to resource error.", tsFile.getPath()), e);
×
2522
        throw new SemanticException(
×
2523
            String.format("Parse file %s to resource error", tsFile.getPath()));
×
2524
      }
×
2525
      if (device2Schemas.size() > CONFIG.getMaxLoadingDeviceNumber()) {
×
2526
        autoCreateAndVerifySchema(loadTsFileStatement, device2Schemas, device2IsAligned, context);
×
2527
      }
2528
    }
×
2529

2530
    autoCreateAndVerifySchema(loadTsFileStatement, device2Schemas, device2IsAligned, context);
×
2531

2532
    // load function will query data partition in scheduler
2533
    Analysis analysis = new Analysis();
×
2534
    analysis.setStatement(loadTsFileStatement);
×
2535
    return analysis;
×
2536
  }
2537

2538
  private void autoCreateAndVerifySchema(
2539
      LoadTsFileStatement loadTsFileStatement,
2540
      Map<String, Map<MeasurementSchema, File>> device2Schemas,
2541
      Map<String, Pair<Boolean, File>> device2IsAligned,
2542
      MPPQueryContext context)
2543
      throws SemanticException {
2544
    if (device2Schemas.isEmpty()) {
×
2545
      return;
×
2546
    }
2547
    try {
2548
      if (loadTsFileStatement.isVerifySchema()) {
×
2549
        verifyLoadingMeasurements(device2Schemas);
×
2550
      }
2551
      if (loadTsFileStatement.isAutoCreateDatabase()) {
×
2552
        autoCreateSg(loadTsFileStatement.getSgLevel(), device2Schemas);
×
2553
      }
2554
      ISchemaTree schemaTree =
×
2555
          autoCreateSchema(
×
2556
              device2Schemas,
2557
              device2IsAligned,
2558
              context); // schema fetcher will not auto create if config set
2559
      // isAutoCreateSchemaEnabled is false.
2560
      if (loadTsFileStatement.isVerifySchema()) {
×
2561
        verifySchema(schemaTree, device2Schemas, device2IsAligned);
×
2562
      }
2563
    } catch (Exception e) {
×
2564
      logger.warn("Auto create or verify schema error.", e);
×
2565
      throw new SemanticException(
×
2566
          String.format(
×
2567
              "Auto create or verify schema error when executing statement %s.",
2568
              loadTsFileStatement));
2569
    } finally {
2570
      device2Schemas.clear();
×
2571
      device2IsAligned.clear();
×
2572
    }
2573
  }
×
2574

2575
  /** get analysis according to statement and params */
2576
  private Analysis getAnalysisForWriting(
2577
      Analysis analysis, List<DataPartitionQueryParam> dataPartitionQueryParams) {
2578

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

2593
  private TsFileResource analyzeTsFile(
2594
      LoadTsFileStatement statement,
2595
      File tsFile,
2596
      Map<String, Map<MeasurementSchema, File>> device2Schemas,
2597
      Map<String, Pair<Boolean, File>> device2IsAligned)
2598
      throws IOException, VerifyMetadataException {
2599
    try (TsFileSequenceReader reader = new TsFileSequenceReader(tsFile.getAbsolutePath())) {
×
2600
      Map<String, List<TimeseriesMetadata>> device2Metadata = reader.getAllTimeseriesMetadata(true);
×
2601

2602
      if (IoTDBDescriptor.getInstance().getConfig().isAutoCreateSchemaEnabled()
×
2603
          || statement.isVerifySchema()) {
×
2604
        // construct schema
2605
        for (Map.Entry<String, List<TimeseriesMetadata>> entry : device2Metadata.entrySet()) {
×
2606
          String device = entry.getKey();
×
2607
          List<TimeseriesMetadata> timeseriesMetadataList = entry.getValue();
×
2608
          boolean isAligned = false;
×
2609
          for (TimeseriesMetadata timeseriesMetadata : timeseriesMetadataList) {
×
2610
            TSDataType dataType = timeseriesMetadata.getTsDataType();
×
2611
            if (!dataType.equals(TSDataType.VECTOR)) {
×
2612
              Pair<CompressionType, TSEncoding> pair =
×
2613
                  reader.readTimeseriesCompressionTypeAndEncoding(timeseriesMetadata);
×
2614
              MeasurementSchema measurementSchema =
×
2615
                  new MeasurementSchema(
2616
                      timeseriesMetadata.getMeasurementId(),
×
2617
                      dataType,
2618
                      pair.getRight(),
×
2619
                      pair.getLeft());
×
2620
              device2Schemas
×
2621
                  .computeIfAbsent(device, o -> new HashMap<>())
×
2622
                  .put(measurementSchema, tsFile);
×
2623
            } else {
×
2624
              isAligned = true;
×
2625
            }
2626
          }
×
2627
          boolean finalIsAligned = isAligned;
×
2628
          if (!device2IsAligned
×
2629
              .computeIfAbsent(device, o -> new Pair<>(finalIsAligned, tsFile))
×
2630
              .left
2631
              .equals(isAligned)) {
×
2632
            throw new VerifyMetadataException(
×
2633
                String.format(
×
2634
                    "Device %s has different aligned definition in tsFile %s and other TsFile.",
2635
                    device, tsFile.getParentFile()));
×
2636
          }
2637
        }
×
2638
      }
2639
      return constructTsFileResource(tsFile, device2Metadata, reader);
×
2640
    }
2641
  }
2642

2643
  private TsFileResource constructTsFileResource(
2644
      File tsFile,
2645
      Map<String, List<TimeseriesMetadata>> device2Metadata,
2646
      TsFileSequenceReader reader)
2647
      throws IOException {
2648
    TsFileResource resource = new TsFileResource(tsFile);
×
2649
    if (!resource.resourceFileExists()) {
×
2650
      FileLoaderUtils.updateTsFileResource(
×
2651
          device2Metadata, resource); // serialize it in LoadSingleTsFileNode
2652
      resource.updatePlanIndexes(reader.getMinPlanIndex());
×
2653
      resource.updatePlanIndexes(reader.getMaxPlanIndex());
×
2654
    } else {
2655
      resource.deserialize();
×
2656
    }
2657

2658
    resource.setStatus(TsFileResourceStatus.NORMAL);
×
2659
    return resource;
×
2660
  }
2661

2662
  private void autoCreateSg(int sgLevel, Map<String, Map<MeasurementSchema, File>> device2Schemas)
2663
      throws VerifyMetadataException, LoadFileException, IllegalPathException {
2664
    sgLevel += 1; // e.g. "root.sg" means sgLevel = 1, "root.sg.test" means sgLevel=2
×
2665
    Set<PartialPath> sgSet = new HashSet<>();
×
2666
    for (String device : device2Schemas.keySet()) {
×
2667
      PartialPath devicePath = new PartialPath(device);
×
2668

2669
      String[] nodes = devicePath.getNodes();
×
2670
      String[] sgNodes = new String[sgLevel];
×
2671
      if (nodes.length < sgLevel) {
×
2672
        throw new VerifyMetadataException(
×
2673
            String.format("Sg level %d is longer than device %s.", sgLevel, device));
×
2674
      }
2675
      System.arraycopy(nodes, 0, sgNodes, 0, sgLevel);
×
2676
      PartialPath sgPath = new PartialPath(sgNodes);
×
2677
      sgSet.add(sgPath);
×
2678
    }
×
2679

2680
    for (PartialPath sgPath : sgSet) {
×
2681
      DatabaseSchemaStatement statement =
×
2682
          new DatabaseSchemaStatement(DatabaseSchemaStatement.DatabaseSchemaStatementType.CREATE);
2683
      statement.setDatabasePath(sgPath);
×
2684
      executeSetStorageGroupStatement(statement);
×
2685
    }
×
2686
  }
×
2687

2688
  private void executeSetStorageGroupStatement(Statement statement) throws LoadFileException {
2689
    long queryId = SessionManager.getInstance().requestQueryId();
×
2690
    ExecutionResult result =
2691
        Coordinator.getInstance()
×
2692
            .execute(
×
2693
                statement,
2694
                queryId,
2695
                null,
2696
                "",
2697
                partitionFetcher,
2698
                schemaFetcher,
2699
                IoTDBDescriptor.getInstance().getConfig().getQueryTimeoutThreshold());
×
2700
    if (result.status.code != TSStatusCode.SUCCESS_STATUS.getStatusCode()
×
2701
        && result.status.code != TSStatusCode.DATABASE_ALREADY_EXISTS.getStatusCode()) {
×
2702
      logger.warn(
×
2703
          "Create Database error, statement: {}, result status is: {}", statement, result.status);
2704
      throw new LoadFileException(
×
2705
          String.format("Can not execute create database statement: %s", statement));
×
2706
    }
2707
  }
×
2708

2709
  private ISchemaTree autoCreateSchema(
2710
      Map<String, Map<MeasurementSchema, File>> device2Schemas,
2711
      Map<String, Pair<Boolean, File>> device2IsAligned,
2712
      MPPQueryContext context)
2713
      throws IllegalPathException {
2714
    List<PartialPath> deviceList = new ArrayList<>();
×
2715
    List<String[]> measurementList = new ArrayList<>();
×
2716
    List<TSDataType[]> dataTypeList = new ArrayList<>();
×
2717
    List<TSEncoding[]> encodingsList = new ArrayList<>();
×
2718
    List<CompressionType[]> compressionTypesList = new ArrayList<>();
×
2719
    List<Boolean> isAlignedList = new ArrayList<>();
×
2720

2721
    for (Map.Entry<String, Map<MeasurementSchema, File>> entry : device2Schemas.entrySet()) {
×
2722
      int measurementSize = entry.getValue().size();
×
2723
      String[] measurements = new String[measurementSize];
×
2724
      TSDataType[] tsDataTypes = new TSDataType[measurementSize];
×
2725
      TSEncoding[] encodings = new TSEncoding[measurementSize];
×
2726
      CompressionType[] compressionTypes = new CompressionType[measurementSize];
×
2727

2728
      int index = 0;
×
2729
      for (MeasurementSchema measurementSchema : entry.getValue().keySet()) {
×
2730
        measurements[index] = measurementSchema.getMeasurementId();
×
2731
        tsDataTypes[index] = measurementSchema.getType();
×
2732
        encodings[index] = measurementSchema.getEncodingType();
×
2733
        compressionTypes[index++] = measurementSchema.getCompressor();
×
2734
      }
×
2735

2736
      deviceList.add(new PartialPath(entry.getKey()));
×
2737
      measurementList.add(measurements);
×
2738
      dataTypeList.add(tsDataTypes);
×
2739
      encodingsList.add(encodings);
×
2740
      compressionTypesList.add(compressionTypes);
×
2741
      isAlignedList.add(device2IsAligned.get(entry.getKey()).left);
×
2742
    }
×
2743

2744
    return SchemaValidator.validate(
×
2745
        schemaFetcher,
2746
        deviceList,
2747
        measurementList,
2748
        dataTypeList,
2749
        encodingsList,
2750
        compressionTypesList,
2751
        isAlignedList,
2752
        context);
2753
  }
2754

2755
  private void verifyLoadingMeasurements(Map<String, Map<MeasurementSchema, File>> device2Schemas)
2756
      throws VerifyMetadataException {
2757
    for (Map.Entry<String, Map<MeasurementSchema, File>> deviceEntry : device2Schemas.entrySet()) {
×
2758
      Map<String, MeasurementSchema> id2Schema = new HashMap<>();
×
2759
      Map<MeasurementSchema, File> schema2TsFile = deviceEntry.getValue();
×
2760
      for (Map.Entry<MeasurementSchema, File> entry : schema2TsFile.entrySet()) {
×
2761
        String measurementId = entry.getKey().getMeasurementId();
×
2762
        if (!id2Schema.containsKey(measurementId)) {
×
2763
          id2Schema.put(measurementId, entry.getKey());
×
2764
        } else {
2765
          MeasurementSchema conflictSchema = id2Schema.get(measurementId);
×
2766
          String msg =
×
2767
              String.format(
×
2768
                  "Measurement %s Conflict, TsFile %s has measurement: %s, TsFile %s has measurement %s.",
2769
                  deviceEntry.getKey() + measurementId,
×
2770
                  entry.getValue().getPath(),
×
2771
                  entry.getKey(),
×
2772
                  schema2TsFile.get(conflictSchema).getPath(),
×
2773
                  conflictSchema);
2774
          logger.warn(msg);
×
2775
          throw new VerifyMetadataException(msg);
×
2776
        }
2777
      }
×
2778
    }
×
2779
  }
×
2780

2781
  private void verifySchema(
2782
      ISchemaTree schemaTree,
2783
      Map<String, Map<MeasurementSchema, File>> device2Schemas,
2784
      Map<String, Pair<Boolean, File>> device2IsAligned)
2785
      throws VerifyMetadataException, IllegalPathException {
2786
    for (Map.Entry<String, Map<MeasurementSchema, File>> entry : device2Schemas.entrySet()) {
×
2787
      String device = entry.getKey();
×
2788
      MeasurementSchema[] tsFileSchemas =
×
2789
          entry.getValue().keySet().toArray(new MeasurementSchema[0]);
×
2790
      DeviceSchemaInfo schemaInfo =
×
2791
          schemaTree.searchDeviceSchemaInfo(
×
2792
              new PartialPath(device),
2793
              Arrays.stream(tsFileSchemas)
×
2794
                  .map(MeasurementSchema::getMeasurementId)
×
2795
                  .collect(Collectors.toList()));
×
2796
      if (schemaInfo.isAligned() != Boolean.TRUE.equals(device2IsAligned.get(device).left)) {
×
2797
        throw new VerifyMetadataException(
×
2798
            device,
2799
            "Is aligned",
2800
            device2IsAligned.get(device).left.toString(),
×
2801
            device2IsAligned.get(device).right.getPath(),
×
2802
            String.valueOf(schemaInfo.isAligned()));
×
2803
      }
2804
      List<MeasurementSchema> originSchemaList = schemaInfo.getMeasurementSchemaList();
×
2805
      int measurementSize = originSchemaList.size();
×
2806
      for (int j = 0; j < measurementSize; j++) {
×
2807
        MeasurementSchema originSchema = originSchemaList.get(j);
×
2808
        MeasurementSchema tsFileSchema = tsFileSchemas[j];
×
2809
        String measurementPath =
×
2810
            device + TsFileConstant.PATH_SEPARATOR + originSchema.getMeasurementId();
×
2811
        if (!tsFileSchema.getType().equals(originSchema.getType())) {
×
2812
          throw new VerifyMetadataException(
×
2813
              measurementPath,
2814
              "Datatype",
2815
              tsFileSchema.getType().name(),
×
2816
              entry.getValue().get(tsFileSchema).getPath(),
×
2817
              originSchema.getType().name());
×
2818
        }
2819
        if (!tsFileSchema.getEncodingType().equals(originSchema.getEncodingType())) {
×
2820
          throw new VerifyMetadataException(
×
2821
              measurementPath,
2822
              "Encoding",
2823
              tsFileSchema.getEncodingType().name(),
×
2824
              entry.getValue().get(tsFileSchema).getPath(),
×
2825
              originSchema.getEncodingType().name());
×
2826
        }
2827
        if (!tsFileSchema.getCompressor().equals(originSchema.getCompressor())) {
×
2828
          throw new VerifyMetadataException(
×
2829
              measurementPath,
2830
              "Compress type",
2831
              tsFileSchema.getCompressor().name(),
×
2832
              entry.getValue().get(tsFileSchema).getPath(),
×
2833
              originSchema.getCompressor().name());
×
2834
        }
2835
      }
2836
    }
×
2837
  }
×
2838

2839
  @Override
2840
  public Analysis visitShowTimeSeries(
2841
      ShowTimeSeriesStatement showTimeSeriesStatement, MPPQueryContext context) {
2842
    Analysis analysis = new Analysis();
×
2843
    analysis.setStatement(showTimeSeriesStatement);
×
2844

2845
    PathPatternTree patternTree = new PathPatternTree();
×
2846
    patternTree.appendPathPattern(showTimeSeriesStatement.getPathPattern());
×
2847
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2848
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2849

2850
    Map<Integer, Template> templateMap =
×
2851
        schemaFetcher.checkAllRelatedTemplate(showTimeSeriesStatement.getPathPattern());
×
2852
    analysis.setRelatedTemplateInfo(templateMap);
×
2853

2854
    if (showTimeSeriesStatement.isOrderByHeat()) {
×
2855
      patternTree.constructTree();
×
2856
      // request schema fetch API
2857
      logger.debug("[StartFetchSchema]");
×
2858
      ISchemaTree schemaTree = schemaFetcher.fetchSchema(patternTree, context);
×
2859
      updateSchemaTreeByViews(analysis, schemaTree);
×
2860
      logger.debug("[EndFetchSchema]]");
×
2861

2862
      analyzeLastSource(
×
2863
          analysis,
2864
          Collections.singletonList(
×
2865
              new TimeSeriesOperand(showTimeSeriesStatement.getPathPattern())),
×
2866
          schemaTree);
2867
      analyzeDataPartition(analysis, new QueryStatement(), schemaTree);
×
2868
    }
2869

2870
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTimeSeriesHeader());
×
2871
    return analysis;
×
2872
  }
2873

2874
  @Override
2875
  public Analysis visitShowStorageGroup(
2876
      ShowDatabaseStatement showDatabaseStatement, MPPQueryContext context) {
2877
    Analysis analysis = new Analysis();
×
2878
    analysis.setStatement(showDatabaseStatement);
×
2879
    analysis.setRespDatasetHeader(
×
2880
        DatasetHeaderFactory.getShowStorageGroupHeader(showDatabaseStatement.isDetailed()));
×
2881
    return analysis;
×
2882
  }
2883

2884
  @Override
2885
  public Analysis visitShowTTL(ShowTTLStatement showTTLStatement, MPPQueryContext context) {
2886
    Analysis analysis = new Analysis();
×
2887
    analysis.setStatement(showTTLStatement);
×
2888
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTTLHeader());
×
2889
    return analysis;
×
2890
  }
2891

2892
  @Override
2893
  public Analysis visitShowDevices(
2894
      ShowDevicesStatement showDevicesStatement, MPPQueryContext context) {
2895
    Analysis analysis = new Analysis();
×
2896
    analysis.setStatement(showDevicesStatement);
×
2897

2898
    PathPatternTree patternTree = new PathPatternTree();
×
2899
    patternTree.appendPathPattern(
×
2900
        showDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD));
×
2901
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2902

2903
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2904
    analysis.setRespDatasetHeader(
×
2905
        showDevicesStatement.hasSgCol()
×
2906
            ? DatasetHeaderFactory.getShowDevicesWithSgHeader()
×
2907
            : DatasetHeaderFactory.getShowDevicesHeader());
×
2908
    return analysis;
×
2909
  }
2910

2911
  @Override
2912
  public Analysis visitShowCluster(
2913
      ShowClusterStatement showClusterStatement, MPPQueryContext context) {
2914
    Analysis analysis = new Analysis();
×
2915
    analysis.setStatement(showClusterStatement);
×
2916
    if (showClusterStatement.isDetails()) {
×
2917
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowClusterDetailsHeader());
×
2918
    } else {
2919
      analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowClusterHeader());
×
2920
    }
2921
    return analysis;
×
2922
  }
2923

2924
  @Override
2925
  public Analysis visitCountStorageGroup(
2926
      CountDatabaseStatement countDatabaseStatement, MPPQueryContext context) {
2927
    Analysis analysis = new Analysis();
×
2928
    analysis.setStatement(countDatabaseStatement);
×
2929
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountStorageGroupHeader());
×
2930
    return analysis;
×
2931
  }
2932

2933
  @Override
2934
  public Analysis visitSchemaFetch(
2935
      SchemaFetchStatement schemaFetchStatement, MPPQueryContext context) {
2936
    Analysis analysis = new Analysis();
×
2937
    analysis.setStatement(schemaFetchStatement);
×
2938

2939
    SchemaPartition schemaPartition =
×
2940
        partitionFetcher.getSchemaPartition(schemaFetchStatement.getPatternTree());
×
2941
    analysis.setSchemaPartitionInfo(schemaPartition);
×
2942

2943
    if (schemaPartition.isEmpty()) {
×
2944
      analysis.setFinishQueryAfterAnalyze(true);
×
2945
    }
2946

2947
    return analysis;
×
2948
  }
2949

2950
  @Override
2951
  public Analysis visitCountDevices(
2952
      CountDevicesStatement countDevicesStatement, MPPQueryContext context) {
2953
    Analysis analysis = new Analysis();
×
2954
    analysis.setStatement(countDevicesStatement);
×
2955

2956
    PathPatternTree patternTree = new PathPatternTree();
×
2957
    patternTree.appendPathPattern(
×
2958
        countDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD));
×
2959
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2960

2961
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2962
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountDevicesHeader());
×
2963
    return analysis;
×
2964
  }
2965

2966
  @Override
2967
  public Analysis visitCountTimeSeries(
2968
      CountTimeSeriesStatement countTimeSeriesStatement, MPPQueryContext context) {
2969
    Analysis analysis = new Analysis();
×
2970
    analysis.setStatement(countTimeSeriesStatement);
×
2971

2972
    PathPatternTree patternTree = new PathPatternTree();
×
2973
    patternTree.appendPathPattern(countTimeSeriesStatement.getPathPattern());
×
2974
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2975
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2976

2977
    Map<Integer, Template> templateMap =
×
2978
        schemaFetcher.checkAllRelatedTemplate(countTimeSeriesStatement.getPathPattern());
×
2979
    analysis.setRelatedTemplateInfo(templateMap);
×
2980

2981
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountTimeSeriesHeader());
×
2982
    return analysis;
×
2983
  }
2984

2985
  @Override
2986
  public Analysis visitCountLevelTimeSeries(
2987
      CountLevelTimeSeriesStatement countLevelTimeSeriesStatement, MPPQueryContext context) {
2988
    Analysis analysis = new Analysis();
×
2989
    analysis.setStatement(countLevelTimeSeriesStatement);
×
2990

2991
    PathPatternTree patternTree = new PathPatternTree();
×
2992
    patternTree.appendPathPattern(countLevelTimeSeriesStatement.getPathPattern());
×
2993
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
2994

2995
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
2996
    Map<Integer, Template> templateMap =
×
2997
        schemaFetcher.checkAllRelatedTemplate(countLevelTimeSeriesStatement.getPathPattern());
×
2998
    analysis.setRelatedTemplateInfo(templateMap);
×
2999
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountLevelTimeSeriesHeader());
×
3000
    return analysis;
×
3001
  }
3002

3003
  @Override
3004
  public Analysis visitCountNodes(CountNodesStatement countStatement, MPPQueryContext context) {
3005
    Analysis analysis = new Analysis();
×
3006
    analysis.setStatement(countStatement);
×
3007

3008
    PathPatternTree patternTree = new PathPatternTree();
×
3009
    patternTree.appendPathPattern(countStatement.getPathPattern());
×
3010
    SchemaNodeManagementPartition schemaNodeManagementPartition =
×
3011
        partitionFetcher.getSchemaNodeManagementPartitionWithLevel(
×
3012
            patternTree, countStatement.getLevel());
×
3013

3014
    if (schemaNodeManagementPartition == null) {
×
3015
      return analysis;
×
3016
    }
3017
    if (!schemaNodeManagementPartition.getMatchedNode().isEmpty()
×
3018
        && schemaNodeManagementPartition.getSchemaPartition().getSchemaPartitionMap().size() == 0) {
×
3019
      analysis.setFinishQueryAfterAnalyze(true);
×
3020
    }
3021
    analysis.setMatchedNodes(schemaNodeManagementPartition.getMatchedNode());
×
3022
    analysis.setSchemaPartitionInfo(schemaNodeManagementPartition.getSchemaPartition());
×
3023
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountNodesHeader());
×
3024
    return analysis;
×
3025
  }
3026

3027
  @Override
3028
  public Analysis visitShowChildPaths(
3029
      ShowChildPathsStatement showChildPathsStatement, MPPQueryContext context) {
3030
    return visitSchemaNodeManagementPartition(
×
3031
        showChildPathsStatement,
3032
        showChildPathsStatement.getPartialPath(),
×
3033
        DatasetHeaderFactory.getShowChildPathsHeader());
×
3034
  }
3035

3036
  @Override
3037
  public Analysis visitShowChildNodes(
3038
      ShowChildNodesStatement showChildNodesStatement, MPPQueryContext context) {
3039
    return visitSchemaNodeManagementPartition(
×
3040
        showChildNodesStatement,
3041
        showChildNodesStatement.getPartialPath(),
×
3042
        DatasetHeaderFactory.getShowChildNodesHeader());
×
3043
  }
3044

3045
  @Override
3046
  public Analysis visitShowVersion(
3047
      ShowVersionStatement showVersionStatement, MPPQueryContext context) {
3048
    Analysis analysis = new Analysis();
×
3049
    analysis.setStatement(showVersionStatement);
×
3050
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowVersionHeader());
×
3051
    analysis.setFinishQueryAfterAnalyze(true);
×
3052
    return analysis;
×
3053
  }
3054

3055
  private Analysis visitSchemaNodeManagementPartition(
3056
      Statement statement, PartialPath path, DatasetHeader header) {
3057
    Analysis analysis = new Analysis();
×
3058
    analysis.setStatement(statement);
×
3059

3060
    PathPatternTree patternTree = new PathPatternTree();
×
3061
    patternTree.appendPathPattern(path);
×
3062
    SchemaNodeManagementPartition schemaNodeManagementPartition =
×
3063
        partitionFetcher.getSchemaNodeManagementPartition(patternTree);
×
3064

3065
    if (schemaNodeManagementPartition == null) {
×
3066
      return analysis;
×
3067
    }
3068
    if (!schemaNodeManagementPartition.getMatchedNode().isEmpty()
×
3069
        && schemaNodeManagementPartition.getSchemaPartition().getSchemaPartitionMap().size() == 0) {
×
3070
      analysis.setFinishQueryAfterAnalyze(true);
×
3071
    }
3072
    analysis.setMatchedNodes(schemaNodeManagementPartition.getMatchedNode());
×
3073
    analysis.setSchemaPartitionInfo(schemaNodeManagementPartition.getSchemaPartition());
×
3074
    analysis.setRespDatasetHeader(header);
×
3075
    return analysis;
×
3076
  }
3077

3078
  @Override
3079
  public Analysis visitDeleteData(
3080
      DeleteDataStatement deleteDataStatement, MPPQueryContext context) {
3081
    context.setQueryType(QueryType.WRITE);
×
3082
    Analysis analysis = new Analysis();
×
3083
    analysis.setStatement(deleteDataStatement);
×
3084

3085
    PathPatternTree patternTree = new PathPatternTree();
×
3086
    deleteDataStatement.getPathList().forEach(patternTree::appendPathPattern);
×
3087

3088
    ISchemaTree schemaTree = schemaFetcher.fetchSchema(patternTree, context);
×
3089
    Set<String> deduplicatedDevicePaths = new HashSet<>();
×
3090

3091
    if (schemaTree.hasLogicalViewMeasurement()) {
×
3092
      updateSchemaTreeByViews(analysis, schemaTree);
×
3093

3094
      Set<PartialPath> deletePatternSet = new HashSet<>(deleteDataStatement.getPathList());
×
3095
      IMeasurementSchema measurementSchema;
3096
      LogicalViewSchema logicalViewSchema;
3097
      PartialPath sourcePathOfAliasSeries;
3098
      for (MeasurementPath measurementPath :
3099
          schemaTree.searchMeasurementPaths(SchemaConstant.ALL_MATCH_PATTERN).left) {
×
3100
        measurementSchema = measurementPath.getMeasurementSchema();
×
3101
        if (measurementSchema.isLogicalView()) {
×
3102
          logicalViewSchema = (LogicalViewSchema) measurementSchema;
×
3103
          if (logicalViewSchema.isWritable()) {
×
3104
            sourcePathOfAliasSeries = logicalViewSchema.getSourcePathIfWritable();
×
3105
            deletePatternSet.add(sourcePathOfAliasSeries);
×
3106
            deduplicatedDevicePaths.add(sourcePathOfAliasSeries.getDevice());
×
3107
          } else {
3108
            deletePatternSet.remove(measurementPath);
×
3109
          }
3110
        } else {
3111
          deduplicatedDevicePaths.add(measurementPath.getDevice());
×
3112
        }
3113
      }
×
3114
      deleteDataStatement.setPathList(new ArrayList<>(deletePatternSet));
×
3115
    } else {
×
3116
      for (PartialPath devicePattern : patternTree.getAllDevicePaths()) {
×
3117
        schemaTree
×
3118
            .getMatchedDevices(devicePattern)
×
3119
            .forEach(
×
3120
                deviceSchemaInfo ->
3121
                    deduplicatedDevicePaths.add(deviceSchemaInfo.getDevicePath().getFullPath()));
×
3122
      }
×
3123
    }
3124
    analysis.setSchemaTree(schemaTree);
×
3125

3126
    Map<String, List<DataPartitionQueryParam>> sgNameToQueryParamsMap = new HashMap<>();
×
3127

3128
    deduplicatedDevicePaths.forEach(
×
3129
        devicePath -> {
3130
          DataPartitionQueryParam queryParam = new DataPartitionQueryParam();
×
3131
          queryParam.setDevicePath(devicePath);
×
3132
          sgNameToQueryParamsMap
×
3133
              .computeIfAbsent(schemaTree.getBelongedDatabase(devicePath), key -> new ArrayList<>())
×
3134
              .add(queryParam);
×
3135
        });
×
3136

3137
    DataPartition dataPartition = partitionFetcher.getDataPartition(sgNameToQueryParamsMap);
×
3138
    analysis.setDataPartitionInfo(dataPartition);
×
3139
    analysis.setFinishQueryAfterAnalyze(dataPartition.isEmpty());
×
3140

3141
    return analysis;
×
3142
  }
3143

3144
  @Override
3145
  public Analysis visitCreateSchemaTemplate(
3146
      CreateSchemaTemplateStatement createTemplateStatement, MPPQueryContext context) {
3147

3148
    context.setQueryType(QueryType.WRITE);
×
3149
    List<String> measurements = createTemplateStatement.getMeasurements();
×
3150
    Set<String> measurementsSet = new HashSet<>(measurements);
×
3151
    if (measurementsSet.size() < measurements.size()) {
×
3152
      throw new SemanticException(
×
3153
          "Measurement under template is not allowed to have the same measurement name");
3154
    }
3155
    Analysis analysis = new Analysis();
×
3156
    analysis.setStatement(createTemplateStatement);
×
3157
    return analysis;
×
3158
  }
3159

3160
  @Override
3161
  public Analysis visitShowNodesInSchemaTemplate(
3162
      ShowNodesInSchemaTemplateStatement showNodesInSchemaTemplateStatement,
3163
      MPPQueryContext context) {
3164
    Analysis analysis = new Analysis();
×
3165
    analysis.setStatement(showNodesInSchemaTemplateStatement);
×
3166
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowNodesInSchemaTemplateHeader());
×
3167
    return analysis;
×
3168
  }
3169

3170
  @Override
3171
  public Analysis visitShowSchemaTemplate(
3172
      ShowSchemaTemplateStatement showSchemaTemplateStatement, MPPQueryContext context) {
3173
    Analysis analysis = new Analysis();
×
3174
    analysis.setStatement(showSchemaTemplateStatement);
×
3175
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowSchemaTemplateHeader());
×
3176
    return analysis;
×
3177
  }
3178

3179
  private GroupByFilter initGroupByFilter(GroupByTimeComponent groupByTimeComponent) {
3180
    if (groupByTimeComponent.isIntervalByMonth() || groupByTimeComponent.isSlidingStepByMonth()) {
1✔
3181
      return new GroupByMonthFilter(
×
3182
          groupByTimeComponent.getInterval(),
×
3183
          groupByTimeComponent.getSlidingStep(),
×
3184
          groupByTimeComponent.getStartTime(),
×
3185
          groupByTimeComponent.getEndTime(),
×
3186
          groupByTimeComponent.isSlidingStepByMonth(),
×
3187
          groupByTimeComponent.isIntervalByMonth(),
×
3188
          TimeZone.getTimeZone("+00:00"));
×
3189
    } else {
3190
      long startTime =
3191
          groupByTimeComponent.isLeftCRightO()
1✔
3192
              ? groupByTimeComponent.getStartTime()
1✔
3193
              : groupByTimeComponent.getStartTime() + 1;
1✔
3194
      long endTime =
3195
          groupByTimeComponent.isLeftCRightO()
1✔
3196
              ? groupByTimeComponent.getEndTime()
1✔
3197
              : groupByTimeComponent.getEndTime() + 1;
1✔
3198
      return new GroupByFilter(
1✔
3199
          groupByTimeComponent.getInterval(),
1✔
3200
          groupByTimeComponent.getSlidingStep(),
1✔
3201
          startTime,
3202
          endTime);
3203
    }
3204
  }
3205

3206
  @Override
3207
  public Analysis visitSetSchemaTemplate(
3208
      SetSchemaTemplateStatement setSchemaTemplateStatement, MPPQueryContext context) {
3209
    context.setQueryType(QueryType.WRITE);
×
3210
    Analysis analysis = new Analysis();
×
3211
    analysis.setStatement(setSchemaTemplateStatement);
×
3212
    return analysis;
×
3213
  }
3214

3215
  @Override
3216
  public Analysis visitShowPathSetTemplate(
3217
      ShowPathSetTemplateStatement showPathSetTemplateStatement, MPPQueryContext context) {
3218
    Analysis analysis = new Analysis();
×
3219
    analysis.setStatement(showPathSetTemplateStatement);
×
3220
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowPathSetTemplateHeader());
×
3221
    return analysis;
×
3222
  }
3223

3224
  @Override
3225
  public Analysis visitActivateTemplate(
3226
      ActivateTemplateStatement activateTemplateStatement, MPPQueryContext context) {
3227
    context.setQueryType(QueryType.WRITE);
×
3228
    Analysis analysis = new Analysis();
×
3229
    analysis.setStatement(activateTemplateStatement);
×
3230

3231
    PartialPath activatePath = activateTemplateStatement.getPath();
×
3232

3233
    Pair<Template, PartialPath> templateSetInfo = schemaFetcher.checkTemplateSetInfo(activatePath);
×
3234
    if (templateSetInfo == null) {
×
3235
      throw new StatementAnalyzeException(
×
3236
          new MetadataException(
3237
              String.format(
×
3238
                  "Path [%s] has not been set any template.", activatePath.getFullPath())));
×
3239
    }
3240
    analysis.setTemplateSetInfo(
×
3241
        new Pair<>(templateSetInfo.left, Collections.singletonList(templateSetInfo.right)));
×
3242

3243
    PathPatternTree patternTree = new PathPatternTree();
×
3244
    patternTree.appendPathPattern(activatePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
3245
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3246

3247
    analysis.setSchemaPartitionInfo(partition);
×
3248

3249
    return analysis;
×
3250
  }
3251

3252
  @Override
3253
  public Analysis visitBatchActivateTemplate(
3254
      BatchActivateTemplateStatement batchActivateTemplateStatement, MPPQueryContext context) {
3255
    context.setQueryType(QueryType.WRITE);
×
3256
    Analysis analysis = new Analysis();
×
3257
    analysis.setStatement(batchActivateTemplateStatement);
×
3258

3259
    Map<PartialPath, Pair<Template, PartialPath>> deviceTemplateSetInfoMap =
×
3260
        new HashMap<>(batchActivateTemplateStatement.getPaths().size());
×
3261
    for (PartialPath devicePath : batchActivateTemplateStatement.getDevicePathList()) {
×
3262
      Pair<Template, PartialPath> templateSetInfo = schemaFetcher.checkTemplateSetInfo(devicePath);
×
3263
      if (templateSetInfo == null) {
×
3264
        throw new StatementAnalyzeException(
×
3265
            new MetadataException(
3266
                String.format(
×
3267
                    "Path [%s] has not been set any template.", devicePath.getFullPath())));
×
3268
      }
3269
      deviceTemplateSetInfoMap.put(devicePath, templateSetInfo);
×
3270
    }
×
3271
    analysis.setDeviceTemplateSetInfoMap(deviceTemplateSetInfoMap);
×
3272

3273
    PathPatternTree patternTree = new PathPatternTree();
×
3274
    for (PartialPath devicePath : batchActivateTemplateStatement.getDevicePathList()) {
×
3275
      // the devicePath is a path without wildcard
3276
      patternTree.appendFullPath(devicePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
3277
    }
×
3278
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3279

3280
    analysis.setSchemaPartitionInfo(partition);
×
3281

3282
    return analysis;
×
3283
  }
3284

3285
  @Override
3286
  public Analysis visitInternalBatchActivateTemplate(
3287
      InternalBatchActivateTemplateStatement internalBatchActivateTemplateStatement,
3288
      MPPQueryContext context) {
3289
    context.setQueryType(QueryType.WRITE);
×
3290
    Analysis analysis = new Analysis();
×
3291
    analysis.setStatement(internalBatchActivateTemplateStatement);
×
3292

3293
    PathPatternTree patternTree = new PathPatternTree();
×
3294
    for (PartialPath activatePath :
3295
        internalBatchActivateTemplateStatement.getDeviceMap().keySet()) {
×
3296
      // the devicePath is a path without wildcard
3297
      patternTree.appendFullPath(activatePath.concatNode(ONE_LEVEL_PATH_WILDCARD));
×
3298
    }
×
3299
    SchemaPartition partition = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3300

3301
    analysis.setSchemaPartitionInfo(partition);
×
3302

3303
    return analysis;
×
3304
  }
3305

3306
  @Override
3307
  public Analysis visitShowPathsUsingTemplate(
3308
      ShowPathsUsingTemplateStatement showPathsUsingTemplateStatement, MPPQueryContext context) {
3309
    Analysis analysis = new Analysis();
×
3310
    analysis.setStatement(showPathsUsingTemplateStatement);
×
3311
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowPathsUsingTemplateHeader());
×
3312

3313
    Pair<Template, List<PartialPath>> templateSetInfo =
×
3314
        schemaFetcher.getAllPathsSetTemplate(showPathsUsingTemplateStatement.getTemplateName());
×
3315

3316
    if (templateSetInfo == null
×
3317
        || templateSetInfo.right == null
3318
        || templateSetInfo.right.isEmpty()) {
×
3319
      analysis.setFinishQueryAfterAnalyze(true);
×
3320
      return analysis;
×
3321
    }
3322

3323
    analysis.setTemplateSetInfo(templateSetInfo);
×
3324

3325
    PathPatternTree patternTree = new PathPatternTree();
×
3326
    PartialPath rawPathPattern = showPathsUsingTemplateStatement.getPathPattern();
×
3327
    List<PartialPath> specifiedPatternList = new ArrayList<>();
×
3328
    templateSetInfo.right.forEach(
×
3329
        setPath -> {
3330
          for (PartialPath specifiedPattern : rawPathPattern.alterPrefixPath(setPath)) {
×
3331
            patternTree.appendPathPattern(specifiedPattern);
×
3332
            specifiedPatternList.add(specifiedPattern);
×
3333
          }
×
3334
        });
×
3335

3336
    if (specifiedPatternList.isEmpty()) {
×
3337
      analysis.setFinishQueryAfterAnalyze(true);
×
3338
      return analysis;
×
3339
    }
3340

3341
    analysis.setSpecifiedTemplateRelatedPathPatternList(specifiedPatternList);
×
3342

3343
    SchemaPartition partition = partitionFetcher.getSchemaPartition(patternTree);
×
3344
    analysis.setSchemaPartitionInfo(partition);
×
3345
    if (partition.isEmpty()) {
×
3346
      analysis.setFinishQueryAfterAnalyze(true);
×
3347
      return analysis;
×
3348
    }
3349

3350
    return analysis;
×
3351
  }
3352

3353
  @Override
3354
  public Analysis visitShowQueries(
3355
      ShowQueriesStatement showQueriesStatement, MPPQueryContext context) {
3356
    Analysis analysis = new Analysis();
×
3357
    analysis.setStatement(showQueriesStatement);
×
3358
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowQueriesHeader());
×
3359
    analysis.setVirtualSource(true);
×
3360

3361
    List<TDataNodeLocation> allRunningDataNodeLocations = getRunningDataNodeLocations();
×
3362
    if (allRunningDataNodeLocations.isEmpty()) {
×
3363
      analysis.setFinishQueryAfterAnalyze(true);
×
3364
    }
3365
    // TODO Constant folding optimization for Where Predicate after True/False Constant introduced
3366
    if (allRunningDataNodeLocations.isEmpty()) {
×
3367
      throw new StatementAnalyzeException("no Running DataNodes");
×
3368
    }
3369
    analysis.setRunningDataNodeLocations(allRunningDataNodeLocations);
×
3370

3371
    Set<Expression> sourceExpressions = new HashSet<>();
×
3372
    for (ColumnHeader columnHeader : analysis.getRespDatasetHeader().getColumnHeaders()) {
×
3373
      sourceExpressions.add(
×
3374
          TimeSeriesOperand.constructColumnHeaderExpression(
×
3375
              columnHeader.getColumnName(), columnHeader.getColumnType()));
×
3376
    }
×
3377
    analysis.setSourceExpressions(sourceExpressions);
×
3378
    sourceExpressions.forEach(expression -> analyzeExpressionType(analysis, expression));
×
3379

3380
    analyzeWhere(analysis, showQueriesStatement);
×
3381

3382
    analysis.setMergeOrderParameter(new OrderByParameter(showQueriesStatement.getSortItemList()));
×
3383

3384
    return analysis;
×
3385
  }
3386

3387
  private List<TDataNodeLocation> getRunningDataNodeLocations() {
3388
    try (ConfigNodeClient client =
3389
        ConfigNodeClientManager.getInstance().borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) {
×
3390
      TGetDataNodeLocationsResp showDataNodesResp = client.getRunningDataNodeLocations();
×
3391
      if (showDataNodesResp.getStatus().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
×
3392
        throw new StatementAnalyzeException(
×
3393
            "An error occurred when executing getRunningDataNodeLocations():"
3394
                + showDataNodesResp.getStatus().getMessage());
×
3395
      }
3396
      return showDataNodesResp.getDataNodeLocationList();
×
3397
    } catch (ClientManagerException | TException e) {
×
3398
      throw new StatementAnalyzeException(
×
3399
          "An error occurred when executing getRunningDataNodeLocations():" + e.getMessage());
×
3400
    }
3401
  }
3402

3403
  private void analyzeWhere(Analysis analysis, ShowQueriesStatement showQueriesStatement) {
3404
    WhereCondition whereCondition = showQueriesStatement.getWhereCondition();
×
3405
    if (whereCondition == null) {
×
3406
      return;
×
3407
    }
3408

3409
    Expression whereExpression =
×
3410
        ExpressionAnalyzer.bindTypeForTimeSeriesOperand(
×
3411
            whereCondition.getPredicate(), ColumnHeaderConstant.showQueriesColumnHeaders);
×
3412

3413
    TSDataType outputType = analyzeExpressionType(analysis, whereExpression);
×
3414
    if (outputType != TSDataType.BOOLEAN) {
×
3415
      throw new SemanticException(String.format(WHERE_WRONG_TYPE_ERROR_MSG, outputType));
×
3416
    }
3417

3418
    analysis.setWhereExpression(whereExpression);
×
3419
  }
×
3420

3421
  // region view
3422

3423
  /**
3424
   * Compute how many paths exist, get the schema tree and the number of existed paths.
3425
   *
3426
   * @return a pair of ISchemaTree, and the number of exist paths.
3427
   */
3428
  private Pair<ISchemaTree, Integer> fetchSchemaOfPathsAndCount(
3429
      List<PartialPath> pathList, Analysis analysis, MPPQueryContext context) {
3430
    ISchemaTree schemaTree = analysis.getSchemaTree();
×
3431
    if (schemaTree == null) {
×
3432
      // source is not represented by query, thus has not done fetch schema.
3433
      PathPatternTree pathPatternTree = new PathPatternTree();
×
3434
      for (PartialPath path : pathList) {
×
3435
        pathPatternTree.appendPathPattern(path);
×
3436
      }
×
3437
      schemaTree = this.schemaFetcher.fetchSchema(pathPatternTree, context);
×
3438
    }
3439

3440
    // search each path, make sure they all exist.
3441
    int numOfExistPaths = 0;
×
3442
    for (PartialPath path : pathList) {
×
3443
      Pair<List<MeasurementPath>, Integer> pathPair = schemaTree.searchMeasurementPaths(path);
×
3444
      numOfExistPaths += !pathPair.left.isEmpty() ? 1 : 0;
×
3445
    }
×
3446
    return new Pair<>(schemaTree, numOfExistPaths);
×
3447
  }
3448

3449
  /**
3450
   * @param pathList the paths you want to check
3451
   * @param schemaTree the given schema tree
3452
   * @return if all paths you give can be found in schema tree, return a pair of view paths and
3453
   *     null; else return view paths and the non-exist path.
3454
   */
3455
  private Pair<List<PartialPath>, PartialPath> findAllViewsInPaths(
3456
      List<PartialPath> pathList, ISchemaTree schemaTree) {
3457
    List<PartialPath> result = new ArrayList<>();
×
3458
    for (PartialPath path : pathList) {
×
3459
      Pair<List<MeasurementPath>, Integer> measurementPathList =
×
3460
          schemaTree.searchMeasurementPaths(path);
×
3461
      if (measurementPathList.left.isEmpty()) {
×
3462
        return new Pair<>(result, path);
×
3463
      }
3464
      for (MeasurementPath measurementPath : measurementPathList.left) {
×
3465
        if (measurementPath.getMeasurementSchema().isLogicalView()) {
×
3466
          result.add(measurementPath);
×
3467
        }
3468
      }
×
3469
    }
×
3470
    return new Pair<>(result, null);
×
3471
  }
3472

3473
  private Pair<List<Expression>, Analysis> analyzeQueryInLogicalViewStatement(
3474
      Analysis analysis, QueryStatement queryStatement, MPPQueryContext context) {
3475
    Analysis queryAnalysis = this.visitQuery(queryStatement, context);
×
3476
    analysis.setSchemaTree(queryAnalysis.getSchemaTree());
×
3477
    // get all expression from resultColumns
3478
    List<Pair<Expression, String>> outputExpressions = queryAnalysis.getOutputExpressions();
×
3479
    if (queryAnalysis.isFailed()) {
×
3480
      analysis.setFinishQueryAfterAnalyze(true);
×
3481
      analysis.setFailStatus(queryAnalysis.getFailStatus());
×
3482
      return new Pair<>(null, analysis);
×
3483
    }
3484
    if (outputExpressions == null) {
×
3485
      analysis.setFinishQueryAfterAnalyze(true);
×
3486
      analysis.setFailStatus(
×
3487
          RpcUtils.getStatus(
×
3488
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3489
              "Columns in the query statement is empty. Please check your SQL."));
3490
      return new Pair<>(null, analysis);
×
3491
    }
3492
    if (queryAnalysis.useLogicalView()) {
×
3493
      analysis.setFinishQueryAfterAnalyze(true);
×
3494
      analysis.setFailStatus(
×
3495
          RpcUtils.getStatus(
×
3496
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3497
              "Can not create a view based on existing views. Check the query in your SQL."));
3498
      return new Pair<>(null, analysis);
×
3499
    }
3500
    List<Expression> expressionList = new ArrayList<>();
×
3501
    for (Pair<Expression, String> thisPair : outputExpressions) {
×
3502
      expressionList.add(thisPair.left);
×
3503
    }
×
3504
    return new Pair<>(expressionList, analysis);
×
3505
  }
3506

3507
  private void checkViewsInSource(
3508
      Analysis analysis, List<Expression> sourceExpressionList, MPPQueryContext context) {
3509
    List<PartialPath> pathsNeedCheck = new ArrayList<>();
×
3510
    for (Expression expression : sourceExpressionList) {
×
3511
      if (expression instanceof TimeSeriesOperand) {
×
3512
        pathsNeedCheck.add(((TimeSeriesOperand) expression).getPath());
×
3513
      }
3514
    }
×
3515
    Pair<ISchemaTree, Integer> schemaOfNeedToCheck =
×
3516
        fetchSchemaOfPathsAndCount(pathsNeedCheck, analysis, context);
×
3517
    if (schemaOfNeedToCheck.right != pathsNeedCheck.size()) {
×
3518
      // some source paths is not exist, and could not fetch schema.
3519
      analysis.setFinishQueryAfterAnalyze(true);
×
3520
      analysis.setFailStatus(
×
3521
          RpcUtils.getStatus(
×
3522
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3523
              "Can not create a view based on non-exist time series."));
3524
      return;
×
3525
    }
3526
    Pair<List<PartialPath>, PartialPath> viewInSourceCheckResult =
×
3527
        findAllViewsInPaths(pathsNeedCheck, schemaOfNeedToCheck.left);
×
3528
    if (viewInSourceCheckResult.right != null) {
×
3529
      // some source paths is not exist
3530
      analysis.setFinishQueryAfterAnalyze(true);
×
3531
      analysis.setFailStatus(
×
3532
          RpcUtils.getStatus(
×
3533
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3534
              "Path "
3535
                  + viewInSourceCheckResult.right.toString()
×
3536
                  + " does not exist! You can not create a view based on non-exist time series."));
3537
      return;
×
3538
    }
3539
    if (!viewInSourceCheckResult.left.isEmpty()) {
×
3540
      // some source paths is logical view
3541
      analysis.setFinishQueryAfterAnalyze(true);
×
3542
      analysis.setFailStatus(
×
3543
          RpcUtils.getStatus(
×
3544
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3545
              "Can not create a view based on existing views."));
3546
    }
3547
  }
×
3548

3549
  private void checkPathsInCreateLogicalView(
3550
      Analysis analysis, CreateLogicalViewStatement createLogicalViewStatement) {
3551
    Pair<Boolean, String> checkResult = createLogicalViewStatement.checkAllPaths();
×
3552
    if (Boolean.FALSE.equals(checkResult.left)) {
×
3553
      analysis.setFinishQueryAfterAnalyze(true);
×
3554
      analysis.setFailStatus(
×
3555
          RpcUtils.getStatus(
×
3556
              TSStatusCode.ILLEGAL_PATH.getStatusCode(),
×
3557
              "The path " + checkResult.right + " is illegal."));
3558
      return;
×
3559
    }
3560
    // make sure there are no redundant paths in targets. Please note that redundant paths in source
3561
    // are legal!
3562
    List<PartialPath> targetPathList = createLogicalViewStatement.getTargetPathList();
×
3563
    Set<String> targetStringSet = new HashSet<>();
×
3564
    for (PartialPath path : targetPathList) {
×
3565
      boolean repeatPathNotExist = targetStringSet.add(path.toString());
×
3566
      if (!repeatPathNotExist) {
×
3567
        analysis.setFinishQueryAfterAnalyze(true);
×
3568
        analysis.setFailStatus(
×
3569
            RpcUtils.getStatus(
×
3570
                TSStatusCode.ILLEGAL_PATH.getStatusCode(),
×
3571
                String.format("Path [%s] is redundant in target paths.", path)));
×
3572
        return;
×
3573
      }
3574
    }
×
3575
    if (createLogicalViewStatement.getSourceExpressionList().size() != targetPathList.size()) {
×
3576
      analysis.setFinishQueryAfterAnalyze(true);
×
3577
      analysis.setFailStatus(
×
3578
          RpcUtils.getStatus(
×
3579
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3580
              String.format(
×
3581
                  "The number of target paths (%d) and sources (%d) are miss matched! Please check your SQL.",
3582
                  createLogicalViewStatement.getTargetPathList().size(),
×
3583
                  createLogicalViewStatement.getSourceExpressionList().size())));
×
3584
      return;
×
3585
    }
3586
    // make sure all paths are NOt under any template
3587
    try {
3588
      for (PartialPath path : createLogicalViewStatement.getTargetPathList()) {
×
3589
        checkIsTemplateCompatible(path, null);
×
3590
      }
×
3591
    } catch (Exception e) {
×
3592
      analysis.setFinishQueryAfterAnalyze(true);
×
3593
      analysis.setFailStatus(
×
3594
          RpcUtils.getStatus(
×
3595
              TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
×
3596
              "Can not create view under template."));
3597
    }
×
3598
  }
×
3599

3600
  // create Logical View
3601
  @Override
3602
  public Analysis visitCreateLogicalView(
3603
      CreateLogicalViewStatement createLogicalViewStatement, MPPQueryContext context) {
3604
    Analysis analysis = new Analysis();
×
3605
    context.setQueryType(QueryType.WRITE);
×
3606
    analysis.setStatement(createLogicalViewStatement);
×
3607

3608
    if (createLogicalViewStatement.getViewExpression() == null) {
×
3609
      // analyze query in statement
3610
      QueryStatement queryStatement = createLogicalViewStatement.getQueryStatement();
×
3611
      if (queryStatement != null) {
×
3612
        Pair<List<Expression>, Analysis> queryAnalysisPair =
×
3613
            this.analyzeQueryInLogicalViewStatement(analysis, queryStatement, context);
×
3614
        if (queryAnalysisPair.right.isFinishQueryAfterAnalyze()) {
×
3615
          return analysis;
×
3616
        } else if (queryAnalysisPair.left != null) {
×
3617
          try {
3618
            createLogicalViewStatement.setSourceExpressions(queryAnalysisPair.left);
×
3619
          } catch (UnsupportedViewException e) {
×
3620
            analysis.setFinishQueryAfterAnalyze(true);
×
3621
            analysis.setFailStatus(RpcUtils.getStatus(e.getErrorCode(), e.getMessage()));
×
3622
            return analysis;
×
3623
          }
×
3624
        }
3625
      }
3626
    }
3627

3628
    // use source and into item to generate target views
3629
    createLogicalViewStatement.parseIntoItemIfNecessary();
×
3630

3631
    // check target paths; check source expressions.
3632
    checkPathsInCreateLogicalView(analysis, createLogicalViewStatement);
×
3633
    if (analysis.isFinishQueryAfterAnalyze()) {
×
3634
      return analysis;
×
3635
    }
3636

3637
    // make sure there is no view in source
3638
    List<Expression> sourceExpressionList = createLogicalViewStatement.getSourceExpressionList();
×
3639
    checkViewsInSource(analysis, sourceExpressionList, context);
×
3640
    if (analysis.isFinishQueryAfterAnalyze()) {
×
3641
      return analysis;
×
3642
    }
3643

3644
    // set schema partition info, this info will be used to split logical plan node.
3645
    PathPatternTree patternTree = new PathPatternTree();
×
3646
    for (PartialPath thisFullPath : createLogicalViewStatement.getTargetPathList()) {
×
3647
      patternTree.appendFullPath(thisFullPath);
×
3648
    }
×
3649
    SchemaPartition schemaPartitionInfo = partitionFetcher.getOrCreateSchemaPartition(patternTree);
×
3650
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
3651

3652
    return analysis;
×
3653
  }
3654

3655
  @Override
3656
  public Analysis visitShowLogicalView(
3657
      ShowLogicalViewStatement showLogicalViewStatement, MPPQueryContext context) {
3658
    context.setQueryType(QueryType.READ);
×
3659
    Analysis analysis = new Analysis();
×
3660
    analysis.setStatement(showLogicalViewStatement);
×
3661

3662
    PathPatternTree patternTree = new PathPatternTree();
×
3663
    patternTree.appendPathPattern(showLogicalViewStatement.getPathPattern());
×
3664
    SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree);
×
3665
    analysis.setSchemaPartitionInfo(schemaPartitionInfo);
×
3666

3667
    analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowLogicalViewHeader());
×
3668
    return analysis;
×
3669
  }
3670
  // endregion view
3671
}
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