This is an automated email from the ASF dual-hosted git repository. ericpai pushed a commit to branch feature/iotdb-4639 in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 04d71fc7f20b07967838e015b1fca84dadfb2eef Author: ericpai <[email protected]> AuthorDate: Wed Oct 19 15:59:12 2022 +0800 Add hard mapping from output expression to result column --- .../db/it/aggregation/IoTDBTagAggregationIT.java | 102 ++++++--- .../apache/iotdb/db/mpp/plan/analyze/Analysis.java | 26 ++- .../iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java | 249 +++++++++++---------- .../db/mpp/plan/analyze/ConcatPathRewriter.java | 43 ++-- .../db/mpp/plan/planner/LogicalPlanBuilder.java | 12 +- .../db/mpp/plan/statement/crud/QueryStatement.java | 2 +- 6 files changed, 256 insertions(+), 178 deletions(-) diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBTagAggregationIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBTagAggregationIT.java index c481ca9718..ac906a3148 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBTagAggregationIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBTagAggregationIT.java @@ -99,7 +99,7 @@ public class IoTDBTagAggregationIT { // Expected result set: // +----+--------+------------------+-----------+-----------+------------+------------+----------+ // | k1|count(t)| - // avg(t)|max_time(t)|min_time(t)|max_value(t)|min_value(t)|extreme(t)| + // AVG(t)|MAX_TIME(t)|MIN_TIME(t)|MAX_VALUE(t)|MIN_VALUE(t)|EXTREME(t)| // +----+--------+------------------+-----------+-----------+------------+------------+----------+ // |k1v1| 6| 2.600000003973643| 10| 1| 6.5| 1.1| // 6.5| @@ -123,13 +123,13 @@ public class IoTDBTagAggregationIT { Assert.assertEquals(6.5F, resultSet.getFloat(8), DELTA); Assert.assertTrue(resultSet.next()); Assert.assertEquals("k1v2", resultSet.getString("k1")); - Assert.assertEquals(4L, resultSet.getLong("count(t)")); - Assert.assertEquals(3.1D, resultSet.getDouble("avg(t)"), DELTA); - Assert.assertEquals(10L, resultSet.getLong("max_time(t)")); - Assert.assertEquals(1L, resultSet.getLong("min_time(t)")); - Assert.assertEquals(5.4F, resultSet.getFloat("max_value(t)"), DELTA); - Assert.assertEquals(1.3F, resultSet.getFloat("min_value(t)"), DELTA); - Assert.assertEquals(5.4F, resultSet.getFloat("extreme(t)"), DELTA); + Assert.assertEquals(4L, resultSet.getLong("COUNT(t)")); + Assert.assertEquals(3.1D, resultSet.getDouble("AVG(t)"), DELTA); + Assert.assertEquals(10L, resultSet.getLong("MAX_TIME(t)")); + Assert.assertEquals(1L, resultSet.getLong("MIN_TIME(t)")); + Assert.assertEquals(5.4F, resultSet.getFloat("MAX_VALUE(t)"), DELTA); + Assert.assertEquals(1.3F, resultSet.getFloat("MIN_VALUE(t)"), DELTA); + Assert.assertEquals(5.4F, resultSet.getFloat("EXTREME(t)"), DELTA); Assert.assertTrue(resultSet.next()); Assert.assertNull(resultSet.getString(1)); Assert.assertEquals(4L, resultSet.getLong(2)); @@ -153,7 +153,7 @@ public class IoTDBTagAggregationIT { String query = "SELECT COUNT(t + 1), AVG(t + 1) FROM root.sg.** GROUP BY TAGS(k1)"; // Expected result set: // +----+------------+------------------+ - // | k1|count(t + 1)| avg(t + 1)| + // | k1|COUNT(t + 1)| AVG(t + 1)| // +----+------------+------------------+ // |k1v1| 6| 3.600000003973643| // |k1v2| 4|3.1000000536441803| @@ -205,8 +205,8 @@ public class IoTDBTagAggregationIT { "SELECT COUNT(t), AVG(t), MAX_TIME(t), MIN_TIME(t), MAX_VALUE(t), MIN_VALUE(t), EXTREME(t) FROM root.sg.** GROUP BY TAGS(k1) HAVING avg(t) > 3"; // Expected result set: // +----+--------+------------------+-----------+-----------+------------+------------+----------+ - // | k1|count(t)| - // avg(t)|max_time(t)|min_time(t)|max_value(t)|min_value(t)|extreme(t)| + // | k1|COUNT(t)| + // AVG(t)|MAX_TIME(t)|MIN_TIME(t)|MAX_VALUE(t)|MIN_VALUE(t)|EXTREME(t)| // +----+--------+------------------+-----------+-----------+------------+------------+----------+ // |k1v2| 4|3.1000000536441803| 10| 1| 5.4| 1.3| // 5.4| @@ -219,13 +219,13 @@ public class IoTDBTagAggregationIT { Assert.assertEquals(8, resultSet.getMetaData().getColumnCount()); Assert.assertTrue(resultSet.next()); Assert.assertEquals("k1v2", resultSet.getString("k1")); - Assert.assertEquals(4L, resultSet.getLong("count(t)")); - Assert.assertEquals(3.1D, resultSet.getDouble("avg(t)"), DELTA); - Assert.assertEquals(10L, resultSet.getLong("max_time(t)")); - Assert.assertEquals(1L, resultSet.getLong("min_time(t)")); - Assert.assertEquals(5.4F, resultSet.getFloat("max_value(t)"), DELTA); - Assert.assertEquals(1.3F, resultSet.getFloat("min_value(t)"), DELTA); - Assert.assertEquals(5.4F, resultSet.getFloat("extreme(t)"), DELTA); + Assert.assertEquals(4L, resultSet.getLong("COUNT(t)")); + Assert.assertEquals(3.1D, resultSet.getDouble("AVG(t)"), DELTA); + Assert.assertEquals(10L, resultSet.getLong("MAX_TIME(t)")); + Assert.assertEquals(1L, resultSet.getLong("MIN_TIME(t)")); + Assert.assertEquals(5.4F, resultSet.getFloat("MAX_VALUE(t)"), DELTA); + Assert.assertEquals(1.3F, resultSet.getFloat("MIN_VALUE(t)"), DELTA); + Assert.assertEquals(5.4F, resultSet.getFloat("EXTREME(t)"), DELTA); Assert.assertTrue(resultSet.next()); Assert.assertNull(resultSet.getString(1)); Assert.assertEquals(4L, resultSet.getLong(2)); @@ -248,7 +248,7 @@ public class IoTDBTagAggregationIT { String query = "SELECT COUNT(t) FROM root.sg.** GROUP BY TAGS(k1, k2)"; // Expected result set: // +----+----+--------+ - // | k1| k2|count(t)| + // | k1| k2|COUNT(t)| // +----+----+--------+ // |k1v1|k2v1| 2| // |k1v1|k2v2| 2| @@ -276,7 +276,7 @@ public class IoTDBTagAggregationIT { Assert.assertTrue(resultSet.next()); Assert.assertEquals(objects[0], resultSet.getString("k1")); Assert.assertEquals(objects[1], resultSet.getString("k2")); - Assert.assertEquals(objects[2], resultSet.getLong("count(t)")); + Assert.assertEquals(objects[2], resultSet.getLong("COUNT(t)")); } Assert.assertFalse(resultSet.next()); } @@ -291,7 +291,49 @@ public class IoTDBTagAggregationIT { String query = "SELECT COUNT(t) from root.sg.** GROUP BY ([0, 20), 10ms), TAGS(k1)"; // Expected result set: // +-----------------------------+----+--------+ - // | Time| k1|count(t)| + // | Time| k1|COUNT(t)| + // +-----------------------------+----+--------+ + // |1970-01-01T08:00:00.000+08:00|k1v1| 3| + // |1970-01-01T08:00:00.000+08:00|k1v2| 2| + // |1970-01-01T08:00:00.000+08:00|null| 2| + // |1970-01-01T08:00:00.010+08:00|k1v1| 3| + // |1970-01-01T08:00:00.010+08:00|k1v2| 2| + // |1970-01-01T08:00:00.010+08:00|null| 2| + // +-----------------------------+----+--------+ + Object[][] expected = + new Object[][] { + {0L, "k1v1", 3L}, + {0L, "k1v2", 2L}, + {0L, null, 2L}, + {10L, "k1v1", 3L}, + {10L, "k1v2", 2L}, + {10L, null, 2L}, + }; + try (Connection connection = EnvFactory.getEnv().getConnection(); + Statement statement = connection.createStatement()) { + try (ResultSet resultSet = statement.executeQuery(query)) { + Assert.assertEquals(3, resultSet.getMetaData().getColumnCount()); + for (Object[] objects : expected) { + Assert.assertTrue(resultSet.next()); + Assert.assertEquals(objects[0], resultSet.getLong("Time")); + Assert.assertEquals(objects[1], resultSet.getString("k1")); + Assert.assertEquals(objects[2], resultSet.getLong("COUNT(t)")); + } + Assert.assertFalse(resultSet.next()); + } + } catch (SQLException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + @Test + public void testAlongWithTimeAggregationWithAlias() { + String query = + "SELECT COUNT(t), COUNT(t), COUNT(t) as a from root.sg.** GROUP BY ([0, 20), 10ms), TAGS(k1)"; + // Expected result set: + // +-----------------------------+----+--------+ + // | Time| k1|COUNT(t)| // +-----------------------------+----+--------+ // |1970-01-01T08:00:00.000+08:00|k1v1| 3| // |1970-01-01T08:00:00.000+08:00|k1v2| 2| @@ -317,7 +359,7 @@ public class IoTDBTagAggregationIT { Assert.assertTrue(resultSet.next()); Assert.assertEquals(objects[0], resultSet.getLong("Time")); Assert.assertEquals(objects[1], resultSet.getString("k1")); - Assert.assertEquals(objects[2], resultSet.getLong("count(t)")); + Assert.assertEquals(objects[2], resultSet.getLong("COUNT(t)")); } Assert.assertFalse(resultSet.next()); } @@ -332,7 +374,7 @@ public class IoTDBTagAggregationIT { String query = "SELECT COUNT(t) from root.sg.** GROUP BY ([0, 20), 15ms, 5ms), TAGS(k1)"; // Expected result set: // +-----------------------------+----+--------+ - // | Time| k1|count(t)| + // | Time| k1|COUNT(t)| // +-----------------------------+----+--------+ // |1970-01-01T08:00:00.000+08:00|k1v1| 6| // |1970-01-01T08:00:00.000+08:00|k1v2| 4| @@ -370,7 +412,7 @@ public class IoTDBTagAggregationIT { Assert.assertTrue(resultSet.next()); Assert.assertEquals(objects[0], resultSet.getLong("Time")); Assert.assertEquals(objects[1], resultSet.getString("k1")); - Assert.assertEquals(objects[2], resultSet.getLong("count(t)")); + Assert.assertEquals(objects[2], resultSet.getLong("COUNT(t)")); } Assert.assertFalse(resultSet.next()); } @@ -386,7 +428,7 @@ public class IoTDBTagAggregationIT { "SELECT COUNT(t) from root.sg.** GROUP BY ([0, 20), 10ms), TAGS(k1) ORDER BY TIME DESC"; // Expected result set: // +-----------------------------+----+--------+ - // | Time| k1|count(t)| + // | Time| k1|COUNT(t)| // +-----------------------------+----+--------+ // |1970-01-01T08:00:00.010+08:00|k1v1| 3| // |1970-01-01T08:00:00.010+08:00|k1v2| 2| @@ -412,7 +454,7 @@ public class IoTDBTagAggregationIT { Assert.assertTrue(resultSet.next()); Assert.assertEquals(objects[0], resultSet.getLong("Time")); Assert.assertEquals(objects[1], resultSet.getString("k1")); - Assert.assertEquals(objects[2], resultSet.getLong("count(t)")); + Assert.assertEquals(objects[2], resultSet.getLong("COUNT(t)")); } Assert.assertFalse(resultSet.next()); } @@ -427,7 +469,7 @@ public class IoTDBTagAggregationIT { String query = "SELECT COUNT(t) FROM root.sg.** WHERE time > 1 GROUP BY TAGS(k1)"; // Expected result set: // +----+--------+ - // | k1|count(t)| + // | k1|COUNT(t)| // +----+--------+ // |k1v1| 3| // |k1v2| 2| @@ -439,13 +481,13 @@ public class IoTDBTagAggregationIT { Assert.assertEquals(2, resultSet.getMetaData().getColumnCount()); Assert.assertTrue(resultSet.next()); Assert.assertEquals("k1v1", resultSet.getString("k1")); - Assert.assertEquals(3, resultSet.getLong("count(t)")); + Assert.assertEquals(3, resultSet.getLong("COUNT(t)")); Assert.assertTrue(resultSet.next()); Assert.assertEquals("k1v2", resultSet.getString("k1")); - Assert.assertEquals(2, resultSet.getLong("count(t)")); + Assert.assertEquals(2, resultSet.getLong("COUNT(t)")); Assert.assertTrue(resultSet.next()); Assert.assertNull(resultSet.getString("k1")); - Assert.assertEquals(2, resultSet.getLong("count(t)")); + Assert.assertEquals(2, resultSet.getLong("COUNT(t)")); Assert.assertFalse(resultSet.next()); } diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java index dec1ba3ba8..5df0de4175 100644 --- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java +++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java @@ -29,6 +29,7 @@ import org.apache.iotdb.db.mpp.common.NodeRef; import org.apache.iotdb.db.mpp.common.header.DatasetHeader; import org.apache.iotdb.db.mpp.common.schematree.ISchemaTree; import org.apache.iotdb.db.mpp.plan.expression.Expression; +import org.apache.iotdb.db.mpp.plan.expression.ResultColumn; import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.DeviceViewIntoPathDescriptor; import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.FillDescriptor; import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.GroupByTimeParameter; @@ -39,6 +40,7 @@ import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; import org.apache.iotdb.tsfile.read.filter.basic.Filter; import org.apache.iotdb.tsfile.utils.Pair; +import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -74,6 +76,14 @@ public class Analysis { // fail. private String failMessage; + // As every result column will be analyzed with path concatenation and wildcard removing to + // generate one or more output expressions. We can maintain a map from output expression to + // original result column for later use. + // Note that if multiple expressions come from one single ResultColumn, the right object's + // REFERENCE should be equal, aka outputExpressions.get(i).right == + // outputExpressions.get(j).right, NOT VALUE equal. + private List<Pair<Expression, ResultColumn>> outputExpressions = new ArrayList<>(); + ///////////////////////////////////////////////////////////////////////////////////////////////// // Query Analysis (used in ALIGN BY TIME) ///////////////////////////////////////////////////////////////////////////////////////////////// @@ -96,7 +106,7 @@ public class Analysis { // tag keys specified in `GROUP BY TAG` clause private List<String> tagKeys; - // {tag values -> {grouped expression -> output expressions}} + // {tag values -> {grouped expression -> source timeseries expressions}} // For different combination of tag keys, the grouped expression may be different. Let's say there // are 3 timeseries root.sg.d1.temperature, root.sg.d1.status, root.sg.d2.temperature, and their // tags are [k1=v1], [k1=v1] and [k1=v2] respectively. For query "SELECT last_value(**) FROM root @@ -105,7 +115,7 @@ public class Analysis { // Thus, the aggregation results of bucket [v1] and [v2] are different. Bucket [v1] has 2 // aggregation results last_value(temperature) and last_value(status), whereas bucket [v2] only // has [last_value(temperature)]. - private Map<List<String>, LinkedHashMap<Expression, List<Expression>>> + private Map<List<String>, LinkedHashMap<Expression, Set<Expression>>> tagValuesToGroupedTimeseriesOperands; ///////////////////////////////////////////////////////////////////////////////////////////////// @@ -486,14 +496,22 @@ public class Analysis { this.tagKeys = tagKeys; } - public Map<List<String>, LinkedHashMap<Expression, List<Expression>>> + public Map<List<String>, LinkedHashMap<Expression, Set<Expression>>> getTagValuesToGroupedTimeseriesOperands() { return tagValuesToGroupedTimeseriesOperands; } public void setTagValuesToGroupedTimeseriesOperands( - Map<List<String>, LinkedHashMap<Expression, List<Expression>>> + Map<List<String>, LinkedHashMap<Expression, Set<Expression>>> tagValuesToGroupedTimeseriesOperands) { this.tagValuesToGroupedTimeseriesOperands = tagValuesToGroupedTimeseriesOperands; } + + public List<Pair<Expression, ResultColumn>> getOutputExpressions() { + return outputExpressions; + } + + public void setOutputExpressions(List<Pair<Expression, ResultColumn>> outputExpressions) { + this.outputExpressions = outputExpressions; + } } diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java index 6cb199c569..250ad76c79 100644 --- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java +++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java @@ -26,6 +26,7 @@ import org.apache.iotdb.commons.partition.DataPartition; import org.apache.iotdb.commons.partition.DataPartitionQueryParam; import org.apache.iotdb.commons.partition.SchemaNodeManagementPartition; import org.apache.iotdb.commons.partition.SchemaPartition; +import org.apache.iotdb.commons.path.AlignedPath; import org.apache.iotdb.commons.path.MeasurementPath; import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathPatternTree; @@ -50,6 +51,7 @@ import org.apache.iotdb.db.mpp.plan.Coordinator; import org.apache.iotdb.db.mpp.plan.execution.ExecutionResult; import org.apache.iotdb.db.mpp.plan.expression.Expression; import org.apache.iotdb.db.mpp.plan.expression.ExpressionType; +import org.apache.iotdb.db.mpp.plan.expression.ResultColumn; import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand; import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression; import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.DeviceViewIntoPathDescriptor; @@ -64,7 +66,6 @@ import org.apache.iotdb.db.mpp.plan.statement.component.FillComponent; import org.apache.iotdb.db.mpp.plan.statement.component.GroupByTimeComponent; import org.apache.iotdb.db.mpp.plan.statement.component.IntoComponent; import org.apache.iotdb.db.mpp.plan.statement.component.Ordering; -import org.apache.iotdb.db.mpp.plan.statement.component.ResultColumn; import org.apache.iotdb.db.mpp.plan.statement.component.SortItem; import org.apache.iotdb.db.mpp.plan.statement.component.SortKey; import org.apache.iotdb.db.mpp.plan.statement.component.WhereCondition; @@ -194,7 +195,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> // concat path and construct path pattern tree PathPatternTree patternTree = new PathPatternTree(); queryStatement = - (QueryStatement) new ConcatPathRewriter().rewrite(queryStatement, patternTree); + (QueryStatement) new ConcatPathRewriter(analysis).rewrite(queryStatement, patternTree); analysis.setStatement(queryStatement); // request schema fetch API @@ -229,11 +230,9 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> analyzeOrderBy(analysis, queryStatement); return analyzeLast(analysis, schemaTree.getAllMeasurement(), schemaTree); } - - List<Pair<Expression, String>> outputExpressions; if (queryStatement.isAlignByDevice()) { Set<PartialPath> deviceSet = analyzeFrom(queryStatement, schemaTree); - outputExpressions = analyzeSelect(analysis, queryStatement, schemaTree, deviceSet); + analyzeSelect(analysis, queryStatement, schemaTree, deviceSet); Map<String, Set<Expression>> deviceToAggregationExpressions = new HashMap<>(); analyzeHaving( @@ -245,17 +244,17 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> analyzeDeviceToSourceTransform(analysis, queryStatement); analyzeDeviceToSource(analysis, queryStatement); - analyzeDeviceView(analysis, queryStatement, outputExpressions); + analyzeDeviceView(analysis, queryStatement); - analyzeInto(analysis, queryStatement, deviceSet, outputExpressions); + analyzeInto(analysis, queryStatement, deviceSet); } else { - outputExpressions = analyzeSelect(analysis, queryStatement, schemaTree); + analyzeSelect(analysis, queryStatement, schemaTree); analyzeHaving(analysis, queryStatement, schemaTree); - analyzeGroupByLevel(analysis, queryStatement, outputExpressions); - analyzeGroupByTag(analysis, queryStatement, outputExpressions, schemaTree); + analyzeGroupByLevel(analysis, queryStatement); + analyzeGroupByTag(analysis, queryStatement, schemaTree); Set<Expression> selectExpressions = - outputExpressions.stream() + analysis.getOutputExpressions().stream() .map(Pair::getLeft) .collect(Collectors.toCollection(LinkedHashSet::new)); analysis.setSelectExpressions(selectExpressions); @@ -267,7 +266,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> analyzeSource(analysis, queryStatement); - analyzeInto(analysis, queryStatement, outputExpressions); + analyzeInto(analysis, queryStatement); } analyzeGroupBy(analysis, queryStatement); @@ -275,7 +274,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> analyzeFill(analysis, queryStatement); // generate result set header according to output expressions - analyzeOutput(analysis, queryStatement, outputExpressions); + analyzeOutput(analysis, queryStatement); // fetch partition information analyzeDataPartition(analysis, queryStatement, schemaTree); @@ -367,27 +366,25 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> return analysis; } - private List<Pair<Expression, String>> analyzeSelect( + private void analyzeSelect( Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) { - List<Pair<Expression, String>> outputExpressions = new ArrayList<>(); + List<Pair<Expression, ResultColumn>> outputExpressions = new ArrayList<>(); boolean isGroupByLevel = queryStatement.isGroupByLevel(); + boolean isGroupByTag = queryStatement.isGroupByTag(); ColumnPaginationController paginationController = new ColumnPaginationController( queryStatement.getSeriesLimit(), queryStatement.getSeriesOffset(), queryStatement.isLastQuery() || isGroupByLevel); - - for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) { - boolean hasAlias = resultColumn.hasAlias(); + for (Pair<Expression, ResultColumn> resultColumn : analysis.getOutputExpressions()) { + boolean hasAlias = resultColumn.getRight().hasAlias(); List<Expression> resultExpressions = - ExpressionAnalyzer.removeWildcardInExpression(resultColumn.getExpression(), schemaTree); - if (hasAlias - && !queryStatement.isGroupByLevel() - && !queryStatement.isGroupByTag() - && resultExpressions.size() > 1) { + ExpressionAnalyzer.removeWildcardInExpression(resultColumn.getLeft(), schemaTree); + if (hasAlias && !isGroupByLevel && !isGroupByTag && resultExpressions.size() > 1) { throw new SemanticException( String.format( - "alias '%s' can only be matched with one time series", resultColumn.getAlias())); + "alias '%s' can only be matched with one time series", + resultColumn.getRight().getAlias())); } for (Expression expression : resultExpressions) { if (paginationController.hasCurOffset()) { @@ -397,20 +394,13 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> if (paginationController.hasCurLimit()) { if (isGroupByLevel) { analyzeExpression(analysis, expression); - outputExpressions.add(new Pair<>(expression, resultColumn.getAlias())); - queryStatement - .getGroupByLevelComponent() - .updateIsCountStar(resultColumn.getExpression()); + outputExpressions.add(new Pair<>(expression, resultColumn.getRight())); + queryStatement.getGroupByLevelComponent().updateIsCountStar(resultColumn.getLeft()); } else { Expression expressionWithoutAlias = ExpressionAnalyzer.removeAliasFromExpression(expression); - String alias = - !Objects.equals(expressionWithoutAlias, expression) - ? expression.getExpressionString() - : null; - alias = hasAlias ? resultColumn.getAlias() : alias; analyzeExpression(analysis, expressionWithoutAlias); - outputExpressions.add(new Pair<>(expressionWithoutAlias, alias)); + outputExpressions.add(new Pair<>(expressionWithoutAlias, resultColumn.getRight())); } paginationController.consumeLimit(); } else { @@ -418,7 +408,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> } } } - return outputExpressions; + analysis.setOutputExpressions(outputExpressions); } private Set<PartialPath> analyzeFrom(QueryStatement queryStatement, ISchemaTree schemaTree) { @@ -436,21 +426,21 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> return deviceSet; } - private List<Pair<Expression, String>> analyzeSelect( + private void analyzeSelect( Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree, Set<PartialPath> deviceSet) { - List<Pair<Expression, String>> outputExpressions = new ArrayList<>(); + List<Pair<Expression, org.apache.iotdb.db.mpp.plan.expression.ResultColumn>> outputExpressions = + new ArrayList<>(); Map<String, Set<Expression>> deviceToSelectExpressions = new HashMap<>(); ColumnPaginationController paginationController = new ColumnPaginationController( queryStatement.getSeriesLimit(), queryStatement.getSeriesOffset(), false); - - for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) { - Expression selectExpression = resultColumn.getExpression(); - boolean hasAlias = resultColumn.hasAlias(); + for (Pair<Expression, ResultColumn> resultColumn : analysis.getOutputExpressions()) { + Expression selectExpression = resultColumn.getLeft(); + boolean hasAlias = resultColumn.getRight().hasAlias(); // select expression after removing wildcard // use LinkedHashMap for order-preserving @@ -471,7 +461,8 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> if (hasAlias && measurementToDeviceSelectExpressions.keySet().size() > 1) { throw new SemanticException( String.format( - "alias '%s' can only be matched with one time series", resultColumn.getAlias())); + "alias '%s' can only be matched with one time series", + resultColumn.getRight().getAlias())); } for (Expression measurementExpression : measurementToDeviceSelectExpressions.keySet()) { @@ -494,13 +485,9 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> // add outputExpressions Expression measurementExpressionWithoutAlias = ExpressionAnalyzer.removeAliasFromExpression(measurementExpression); - String alias = - !Objects.equals(measurementExpressionWithoutAlias, measurementExpression) - ? measurementExpression.getExpressionString() - : null; - alias = hasAlias ? resultColumn.getAlias() : alias; analyzeExpression(analysis, measurementExpressionWithoutAlias); - outputExpressions.add(new Pair<>(measurementExpressionWithoutAlias, alias)); + outputExpressions.add( + new Pair<>(measurementExpressionWithoutAlias, resultColumn.getRight())); // add deviceToSelectExpressions for (String deviceName : deviceToSelectExpressionsOfOneMeasurement.keySet()) { @@ -518,9 +505,8 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> } } } - + analysis.setOutputExpressions(outputExpressions); analysis.setDeviceToSelectExpressions(deviceToSelectExpressions); - return outputExpressions; } private void analyzeHaving( @@ -584,10 +570,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> analysis.setHavingExpression(havingExpression); } - private void analyzeGroupByLevel( - Analysis analysis, - QueryStatement queryStatement, - List<Pair<Expression, String>> outputExpressions) { + private void analyzeGroupByLevel(Analysis analysis, QueryStatement queryStatement) { if (!queryStatement.isGroupByLevel()) { return; } @@ -596,12 +579,12 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> new GroupByLevelController(queryStatement.getGroupByLevelComponent().getLevels()); Set<Expression> groupedSelectExpressions = new LinkedHashSet<>(); - for (int i = 0; i < outputExpressions.size(); i++) { - Pair<Expression, String> expressionAliasPair = outputExpressions.get(i); + for (int i = 0; i < analysis.getOutputExpressions().size(); i++) { + Pair<Expression, ResultColumn> expressionAliasPair = analysis.getOutputExpressions().get(i); boolean isCountStar = queryStatement.getGroupByLevelComponent().isCountStar(i); Expression groupedExpression = groupByLevelController.control( - isCountStar, expressionAliasPair.left, expressionAliasPair.right); + isCountStar, expressionAliasPair.left, expressionAliasPair.right.getAlias()); groupedSelectExpressions.add(groupedExpression); } @@ -617,7 +600,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> groupByLevelController.getGroupedExpressionToRawExpressionsMap()); } - outputExpressions.clear(); + analysis.getOutputExpressions().clear(); ColumnPaginationController paginationController = new ColumnPaginationController( queryStatement.getSeriesLimit(), queryStatement.getSeriesOffset(), false); @@ -633,7 +616,12 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> groupByLevelController.getAlias(groupedExpression.getExpressionString())); Expression groupedExpressionWithoutAlias = outputExpression.left; analyzeExpression(analysis, groupedExpressionWithoutAlias); - outputExpressions.add(outputExpression); + analysis + .getOutputExpressions() + .add( + new Pair<>( + outputExpression.getLeft(), + new ResultColumn(outputExpression.getLeft(), outputExpression.getRight()))); updateGroupByLevelExpressions( groupedExpressionWithoutAlias, groupByLevelExpressions, @@ -693,17 +681,14 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> * <p>TODO: support slimit/soffset/value filter */ private void analyzeGroupByTag( - Analysis analysis, - QueryStatement queryStatement, - List<Pair<Expression, String>> outputExpressions, - ISchemaTree schemaTree) { + Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) { if (!queryStatement.isGroupByTag()) { return; } if (analysis.hasValueFilter()) { throw new SemanticException("Only time filters are supported in GROUP BY TAGS query"); } - Map<List<String>, LinkedHashMap<Expression, List<Expression>>> + Map<List<String>, LinkedHashMap<Expression, Set<Expression>>> tagValuesToGroupedTimeseriesOperands = new HashMap<>(); LinkedHashMap<Expression, Set<Expression>> groupByTagOutputExpressions = new LinkedHashMap<>(); List<String> tagKeys = queryStatement.getGroupByTagComponent().getTagKeys(); @@ -711,62 +696,90 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> Map<MeasurementPath, Map<String, String>> queriedTagMap = new HashMap<>(); allSelectedPath.forEach(v -> queriedTagMap.put(v, v.getTagMap())); - for (Pair<Expression, String> outputExpressionAndAlias : outputExpressions) { - if (!(outputExpressionAndAlias.getLeft() instanceof FunctionExpression - && outputExpressionAndAlias.getLeft().getExpressions().get(0) instanceof TimeSeriesOperand - && outputExpressionAndAlias.getLeft().isBuiltInAggregationFunctionExpression())) { - throw new SemanticException( - outputExpressionAndAlias.getLeft() - + " can't be used in group by tag. It will be supported in the future."); - } - FunctionExpression outputExpression = (FunctionExpression) outputExpressionAndAlias.getLeft(); - MeasurementPath measurementPath = - (MeasurementPath) - ((TimeSeriesOperand) outputExpression.getExpressions().get(0)).getPath(); - MeasurementPath fakePath = null; - try { - fakePath = - new MeasurementPath(measurementPath.getMeasurement(), measurementPath.getSeriesType()); - } catch (IllegalPathException e) { - // do nothing + for (Pair<Expression, ResultColumn> pair : analysis.getOutputExpressions()) { + List<Expression> aggregationExpressions = + ExpressionAnalyzer.searchAggregationExpressions(pair.left); + copySeriesDataTypeToExpression(pair.left, pair.right.getExpression()); + for (Expression exp : aggregationExpressions) { + // TODO: avg(s1 + s2) will be supported in the future + if (exp.getExpressions().size() > 1) { + throw new SemanticException( + pair.left + " can't be used in group by tag. It will be supported in the future."); + } + FunctionExpression outputExpression = (FunctionExpression) exp; + MeasurementPath measurementPath = + (MeasurementPath) + ((TimeSeriesOperand) outputExpression.getExpressions().get(0)).getPath(); + + Expression groupedExpression = pair.getRight().getExpression(); + groupByTagOutputExpressions + .computeIfAbsent(groupedExpression, v -> new HashSet<>()) + .add(exp); + Map<String, String> tagMap = queriedTagMap.get(measurementPath); + List<String> tagValues = new ArrayList<>(); + for (String tagKey : tagKeys) { + tagValues.add(tagMap.get(tagKey)); + } + tagValuesToGroupedTimeseriesOperands + .computeIfAbsent(tagValues, key -> new LinkedHashMap<>()) + .computeIfAbsent(groupedExpression, key -> new HashSet<>()) + .add(outputExpression.getExpressions().get(0)); } - Expression measurementExpression = new TimeSeriesOperand(fakePath); - Expression groupedExpression = - new FunctionExpression( - outputExpression.getFunctionName(), - outputExpression.getFunctionAttributes(), - Collections.singletonList(measurementExpression)); - groupByTagOutputExpressions - .computeIfAbsent(groupedExpression, v -> new HashSet<>()) - .add(outputExpression); - Map<String, String> tagMap = queriedTagMap.get(measurementPath); - List<String> tagValues = new ArrayList<>(); - for (String tagKey : tagKeys) { - tagValues.add(tagMap.get(tagKey)); + } + + // Keep the original output columns to the final data set + List<Pair<Expression, ResultColumn>> outputColumns = new ArrayList<>(); + for (int i = 0; i < analysis.getOutputExpressions().size(); i++) { + // As the expression's equal() compares the expression string instead, if user inputs 2 same + // expressions in the select clause, they may be de-duplicated by the equals() comparison. + ResultColumn curRc = analysis.getOutputExpressions().get(i).right; + if (i == 0 || curRc != analysis.getOutputExpressions().get(i - 1).right) { + analyzeExpression(analysis, curRc.getExpression()); + outputColumns.add( + new Pair<>( + curRc.getExpression(), new ResultColumn(curRc.getExpression(), curRc.getAlias()))); } - tagValuesToGroupedTimeseriesOperands - .computeIfAbsent(tagValues, key -> new LinkedHashMap<>()) - .computeIfAbsent(groupedExpression, key -> new ArrayList<>()) - .add(outputExpression.getExpressions().get(0)); } - outputExpressions.clear(); + analysis.getOutputExpressions().clear(); for (String tagKey : tagKeys) { Expression tagKeyExpression = TimeSeriesOperand.constructColumnHeaderExpression(tagKey, TSDataType.TEXT); analyzeExpression(analysis, tagKeyExpression); - outputExpressions.add(new Pair<>(tagKeyExpression, null)); + analysis + .getOutputExpressions() + .add(new Pair<>(tagKeyExpression, new ResultColumn(tagKeyExpression, null))); } for (Expression groupByTagOutputExpression : groupByTagOutputExpressions.keySet()) { - // TODO: support alias analyzeExpression(analysis, groupByTagOutputExpression); - outputExpressions.add(new Pair<>(groupByTagOutputExpression, null)); } + analysis.getOutputExpressions().addAll(outputColumns); analysis.setTagKeys(queryStatement.getGroupByTagComponent().getTagKeys()); analysis.setTagValuesToGroupedTimeseriesOperands(tagValuesToGroupedTimeseriesOperands); analysis.setCrossGroupByExpressions(groupByTagOutputExpressions); } + /** + * Copy a measurement type from source expression to target expression recursively. The source and + * target expressions should have the same format in expression. e.g. avg(s1) + 1 + sum(s2) has + * the same format with avg(root.sg.d1.s1) + 1 + sum(root.sg.d1.s2), but avg(root.sg.d1.s1) + 1 + + * min_value(root.sg.d1.s2) doesn't. source should be a {@link MeasurementPath} or {@link + * AlignedPath}. + */ + private void copySeriesDataTypeToExpression(Expression source, Expression target) { + if (source instanceof TimeSeriesOperand) { + TimeSeriesOperand sourceExp = (TimeSeriesOperand) source; + TimeSeriesOperand targetExp = (TimeSeriesOperand) target; + targetExp.setPath( + new MeasurementPath(targetExp.getPath(), sourceExp.getPath().getSeriesType())); + return; + } + for (int i = 0; i < source.getExpressions().size(); i++) { + copySeriesDataTypeToExpression( + source.getExpressions().get(i), target.getExpressions().get(i)); + } + } + private void analyzeDeviceToAggregation( Analysis analysis, QueryStatement queryStatement, @@ -942,10 +955,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> conJunctions.stream().distinct().collect(Collectors.toList())); } - private void analyzeDeviceView( - Analysis analysis, - QueryStatement queryStatement, - List<Pair<Expression, String>> outputExpressions) { + private void analyzeDeviceView(Analysis analysis, QueryStatement queryStatement) { Expression deviceExpression = new TimeSeriesOperand( new MeasurementPath(new PartialPath(COLUMN_DEVICE, false), TSDataType.TEXT)); @@ -953,7 +963,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> Set<Expression> selectExpressions = new LinkedHashSet<>(); selectExpressions.add(deviceExpression); selectExpressions.addAll( - outputExpressions.stream() + analysis.getOutputExpressions().stream() .map(Pair::getLeft) .collect(Collectors.toCollection(LinkedHashSet::new))); analysis.setSelectExpressions(selectExpressions); @@ -1008,10 +1018,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> analysis.setDeviceViewInputIndexesMap(deviceViewInputIndexesMap); } - private void analyzeOutput( - Analysis analysis, - QueryStatement queryStatement, - List<Pair<Expression, String>> outputExpressions) { + private void analyzeOutput(Analysis analysis, QueryStatement queryStatement) { if (queryStatement.isSelectInto()) { analysis.setRespDatasetHeader( DatasetHeaderFactory.getSelectIntoHeader(queryStatement.isAlignByDevice())); @@ -1025,11 +1032,11 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> columnHeaders.add(new ColumnHeader(COLUMN_DEVICE, TSDataType.TEXT, null)); } columnHeaders.addAll( - outputExpressions.stream() + analysis.getOutputExpressions().stream() .map( expressionAliasPair -> { String columnName = expressionAliasPair.left.getExpressionString(); - String alias = expressionAliasPair.right; + String alias = expressionAliasPair.right.getAlias(); return new ColumnHeader( columnName, analysis.getType(expressionAliasPair.left), alias); }) @@ -1095,17 +1102,14 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> } private void analyzeInto( - Analysis analysis, - QueryStatement queryStatement, - Set<PartialPath> deviceSet, - List<Pair<Expression, String>> outputExpressions) { + Analysis analysis, QueryStatement queryStatement, Set<PartialPath> deviceSet) { if (!queryStatement.isSelectInto()) { return; } List<PartialPath> sourceDevices = new ArrayList<>(deviceSet); List<Expression> sourceColumns = - outputExpressions.stream() + analysis.getOutputExpressions().stream() .map(Pair::getLeft) .collect(Collectors.toCollection(ArrayList::new)); @@ -1142,16 +1146,13 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> analysis.setDeviceViewIntoPathDescriptor(deviceViewIntoPathDescriptor); } - private void analyzeInto( - Analysis analysis, - QueryStatement queryStatement, - List<Pair<Expression, String>> outputExpressions) { + private void analyzeInto(Analysis analysis, QueryStatement queryStatement) { if (!queryStatement.isSelectInto()) { return; } List<Expression> sourceColumns = - outputExpressions.stream() + analysis.getOutputExpressions().stream() .map(Pair::getLeft) .collect(Collectors.toCollection(ArrayList::new)); diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ConcatPathRewriter.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ConcatPathRewriter.java index 71273d5c12..9a5e6216bc 100644 --- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ConcatPathRewriter.java +++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ConcatPathRewriter.java @@ -27,10 +27,10 @@ import org.apache.iotdb.db.mpp.plan.statement.Statement; import org.apache.iotdb.db.mpp.plan.statement.component.ResultColumn; import org.apache.iotdb.db.mpp.plan.statement.component.SelectComponent; import org.apache.iotdb.db.mpp.plan.statement.crud.QueryStatement; +import org.apache.iotdb.tsfile.utils.Pair; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; /** * This rewriter: @@ -43,6 +43,11 @@ import java.util.stream.Collectors; public class ConcatPathRewriter { private PathPatternTree patternTree; + private final Analysis analysis; + + public ConcatPathRewriter(Analysis analysis) { + this.analysis = analysis; + } public Statement rewrite(Statement statement, PathPatternTree patternTree) throws StatementAnalyzeException { @@ -53,12 +58,21 @@ public class ConcatPathRewriter { List<PartialPath> prefixPaths = queryStatement.getFromComponent().getPrefixPaths(); if (queryStatement.isAlignByDevice()) { - queryStatement.getSelectComponent().getResultColumns().stream() - .map(ResultColumn::getExpression) + queryStatement + .getSelectComponent() + .getResultColumns() .forEach( - expression -> - ExpressionAnalyzer.constructPatternTreeFromExpression( - expression, prefixPaths, patternTree)); + resultColumn -> { + ExpressionAnalyzer.constructPatternTreeFromExpression( + resultColumn.getExpression(), prefixPaths, patternTree); + analysis + .getOutputExpressions() + .add( + new Pair<>( + resultColumn.getExpression(), + new org.apache.iotdb.db.mpp.plan.expression.ResultColumn( + resultColumn.getExpression(), resultColumn.getAlias()))); + }); } else { // concat SELECT with FROM List<ResultColumn> resultColumns = @@ -93,6 +107,9 @@ public class ConcatPathRewriter { List<ResultColumn> resultColumns = new ArrayList<>(); for (ResultColumn resultColumn : selectComponent.getResultColumns()) { boolean needAliasCheck = resultColumn.hasAlias() && !isGroupByLevel; + org.apache.iotdb.db.mpp.plan.expression.ResultColumn originalResultColumn = + new org.apache.iotdb.db.mpp.plan.expression.ResultColumn( + resultColumn.getExpression(), resultColumn.getAlias()); List<Expression> resultExpressions = ExpressionAnalyzer.concatExpressionWithSuffixPaths( resultColumn.getExpression(), prefixPaths, patternTree); @@ -101,13 +118,13 @@ public class ConcatPathRewriter { String.format( "alias '%s' can only be matched with one time series", resultColumn.getAlias())); } - resultColumns.addAll( - resultExpressions.stream() - .map( - expression -> - new ResultColumn( - expression, resultColumn.getAlias(), resultColumn.getColumnType())) - .collect(Collectors.toList())); + resultExpressions.forEach( + expression -> { + resultColumns.add( + new ResultColumn( + expression, resultColumn.getAlias(), resultColumn.getColumnType())); + analysis.getOutputExpressions().add(new Pair<>(expression, originalResultColumn)); + }); } return resultColumns; } diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java index 6f7087c10c..b26276a7c6 100644 --- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java +++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java @@ -223,7 +223,7 @@ public class LogicalPlanBuilder { Set<Expression> sourceTransformExpressions, LinkedHashMap<Expression, Set<Expression>> crossGroupByAggregations, List<String> tagKeys, - Map<List<String>, LinkedHashMap<Expression, List<Expression>>> + Map<List<String>, LinkedHashMap<Expression, Set<Expression>>> tagValuesToGroupedTimeseriesOperands) { boolean needCheckAscending = groupByTimeParameter == null; Map<PartialPath, List<AggregationDescriptor>> ascendingAggregations = new HashMap<>(); @@ -400,7 +400,7 @@ public class LogicalPlanBuilder { Set<Expression> aggregationExpressions, LinkedHashMap<Expression, Set<Expression>> crossGroupByExpressions, List<String> tagKeys, - Map<List<String>, LinkedHashMap<Expression, List<Expression>>> + Map<List<String>, LinkedHashMap<Expression, Set<Expression>>> tagValuesToGroupedTimeseriesOperands) { if (curStep.isOutputPartial()) { if (groupByTimeParameter != null && groupByTimeParameter.hasOverlap()) { @@ -645,7 +645,7 @@ public class LogicalPlanBuilder { private PlanNode createGroupByTagNode( List<String> tagKeys, - Map<List<String>, LinkedHashMap<Expression, List<Expression>>> + Map<List<String>, LinkedHashMap<Expression, Set<Expression>>> tagValuesToGroupedTimeseriesOperands, Collection<Expression> groupByTagOutputExpressions, List<PlanNode> children, @@ -655,7 +655,7 @@ public class LogicalPlanBuilder { SortedMap<List<String>, List<CrossSeriesAggregationDescriptor>> tagValuesToAggregationDescriptors = new TreeMap<>(GroupByTagNode::tagValuesComparator); for (List<String> tagValues : tagValuesToGroupedTimeseriesOperands.keySet()) { - LinkedHashMap<Expression, List<Expression>> groupedTimeseriesOperands = + LinkedHashMap<Expression, Set<Expression>> groupedTimeseriesOperands = tagValuesToGroupedTimeseriesOperands.get(tagValues); List<CrossSeriesAggregationDescriptor> aggregationDescriptors = new ArrayList<>(); @@ -667,12 +667,12 @@ public class LogicalPlanBuilder { } Expression next = iter.next(); if (next.equals(groupByTagOutputExpression)) { - String functionName = ((FunctionExpression) next).getFunctionName().toUpperCase(); + String functionName = ((FunctionExpression) next).getFunctionName().toLowerCase(); CrossSeriesAggregationDescriptor aggregationDescriptor = new CrossSeriesAggregationDescriptor( functionName, curStep, - groupedTimeseriesOperands.get(next), + new ArrayList<>(groupedTimeseriesOperands.get(next)), next.getExpressions().get(0)); aggregationDescriptors.add(aggregationDescriptor); } else { diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java index e894c70d06..f6cfa83493 100644 --- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java +++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java @@ -325,7 +325,7 @@ public class QueryStatement extends Statement { throw new SemanticException("Raw data and aggregation hybrid query is not supported."); } outputColumn.add( - resultColumn.getAlias() != null + resultColumn.hasAlias() ? resultColumn.getAlias() : resultColumn.getExpression().getExpressionString()); }
