This is an automated email from the ASF dual-hosted git repository. hui pushed a commit to branch lmh/orderBySensor in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit c53a1d49ed29dfe73ff725152f2dc3e75fc2857d Author: Minghui Liu <[email protected]> AuthorDate: Tue Jul 19 17:51:01 2022 +0800 refactor Order by in SQL parser & QueryStatement --- .../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 | 24 +++++-- .../iotdb/db/mpp/plan/parser/ASTVisitor.java | 47 ++++++++---- .../{OrderBy.java => OrderByComponent.java} | 32 +++++---- .../db/mpp/plan/statement/component/SortItem.java | 83 ++++++++++++++++++++++ .../db/mpp/plan/statement/crud/QueryStatement.java | 12 ++-- .../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java | 36 +++++++--- 6 files changed, 182 insertions(+), 52 deletions(-) diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 index fe0add2da7..03868d644a 100644 --- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 +++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 @@ -379,11 +379,11 @@ intoPath specialClause : specialLimit #specialLimitStatement - | orderByTimeClause specialLimit? #orderByTimeStatement - | groupByTimeClause orderByTimeClause? specialLimit? #groupByTimeStatement - | groupByFillClause orderByTimeClause? specialLimit? #groupByFillStatement - | groupByLevelClause orderByTimeClause? specialLimit? #groupByLevelStatement - | fillClause orderByTimeClause? specialLimit? #fillStatement + | orderByClause specialLimit? #orderByTimeStatement + | groupByTimeClause orderByClause? specialLimit? #groupByTimeStatement + | groupByFillClause orderByClause? specialLimit? #groupByFillStatement + | groupByLevelClause orderByClause? specialLimit? #groupByLevelStatement + | fillClause orderByClause? specialLimit? #fillStatement ; specialLimit @@ -407,8 +407,18 @@ disableAlign : DISABLE ALIGN ; -orderByTimeClause - : ORDER BY TIME (DESC | ASC)? +orderByClause + : ORDER BY orderByAttributeClause (COMMA orderByAttributeClause)* + ; + +orderByAttributeClause + : sortKey (DESC | ASC) + ; + +sortKey + : TIME + | TIMESERIES + | DEVICE ; groupByTimeClause diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java index 7c8f642936..8d5f002540 100644 --- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java +++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java @@ -64,10 +64,11 @@ import org.apache.iotdb.db.mpp.plan.statement.component.FillPolicy; import org.apache.iotdb.db.mpp.plan.statement.component.FromComponent; import org.apache.iotdb.db.mpp.plan.statement.component.GroupByLevelComponent; import org.apache.iotdb.db.mpp.plan.statement.component.GroupByTimeComponent; -import org.apache.iotdb.db.mpp.plan.statement.component.OrderBy; +import org.apache.iotdb.db.mpp.plan.statement.component.OrderByComponent; import org.apache.iotdb.db.mpp.plan.statement.component.ResultColumn; import org.apache.iotdb.db.mpp.plan.statement.component.ResultSetFormat; import org.apache.iotdb.db.mpp.plan.statement.component.SelectComponent; +import org.apache.iotdb.db.mpp.plan.statement.component.SortItem; import org.apache.iotdb.db.mpp.plan.statement.component.WhereCondition; import org.apache.iotdb.db.mpp.plan.statement.crud.DeleteDataStatement; import org.apache.iotdb.db.mpp.plan.statement.crud.InsertStatement; @@ -142,9 +143,11 @@ import java.net.URISyntaxException; import java.time.ZoneId; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; /** Parse AST to Statement. */ @@ -790,8 +793,8 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> { parseGroupByTimeClause(ctx.groupByTimeClause()); // parse order by time - if (ctx.orderByTimeClause() != null) { - parseOrderByTimeClause(ctx.orderByTimeClause()); + if (ctx.orderByClause() != null) { + parseOrderByClause(ctx.orderByClause()); } // parse limit & offset @@ -808,8 +811,8 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> { parseGroupByTimeClause(ctx.groupByFillClause()); // parse order by time - if (ctx.orderByTimeClause() != null) { - parseOrderByTimeClause(ctx.orderByTimeClause()); + if (ctx.orderByClause() != null) { + parseOrderByClause(ctx.orderByClause()); } // parse limit & offset @@ -938,8 +941,8 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> { parseGroupByLevelClause(ctx.groupByLevelClause()); // parse order by time - if (ctx.orderByTimeClause() != null) { - parseOrderByTimeClause(ctx.orderByTimeClause()); + if (ctx.orderByClause() != null) { + parseOrderByClause(ctx.orderByClause()); } // parse limit & offset @@ -972,8 +975,8 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> { parseFillClause(ctx.fillClause()); // parse order by time - if (ctx.orderByTimeClause() != null) { - parseOrderByTimeClause(ctx.orderByTimeClause()); + if (ctx.orderByClause() != null) { + parseOrderByClause(ctx.orderByClause()); } // parse limit & offset @@ -1182,7 +1185,7 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> { @Override public Statement visitOrderByTimeStatement(IoTDBSqlParser.OrderByTimeStatementContext ctx) { // parse ORDER BY TIME - parseOrderByTimeClause(ctx.orderByTimeClause()); + parseOrderByClause(ctx.orderByClause()); // parse others if (ctx.specialLimit() != null) { @@ -1192,10 +1195,28 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> { } // parse ORDER BY TIME - private void parseOrderByTimeClause(IoTDBSqlParser.OrderByTimeClauseContext ctx) { - if (ctx.DESC() != null) { - queryStatement.setResultOrder(OrderBy.TIMESTAMP_DESC); + private void parseOrderByClause(IoTDBSqlParser.OrderByClauseContext ctx) { + OrderByComponent orderByComponent = new OrderByComponent(); + Set<SortItem.SortKey> sortKeySet = new HashSet<>(); + for (IoTDBSqlParser.OrderByAttributeClauseContext orderByAttributeClauseContext : + ctx.orderByAttributeClause()) { + SortItem sortItem = parseOrderByAttributeClause(orderByAttributeClauseContext); + + SortItem.SortKey sortKey = sortItem.getSortKey(); + if (sortKeySet.contains(sortKey)) { + throw new SemanticException(String.format("ORDER BY: duplicate sort key '%s'", sortKey)); + } else { + sortKeySet.add(sortKey); + orderByComponent.addSortItem(sortItem); + } } + queryStatement.setOrderByComponent(orderByComponent); + } + + private SortItem parseOrderByAttributeClause(IoTDBSqlParser.OrderByAttributeClauseContext ctx) { + return new SortItem( + SortItem.SortKey.valueOf(ctx.sortKey().getText().toUpperCase()), + ctx.DESC() != null ? SortItem.Ordering.DESC : SortItem.Ordering.ASC); } // ResultSetFormat Clause diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/OrderBy.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/OrderByComponent.java similarity index 68% rename from server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/OrderBy.java rename to server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/OrderByComponent.java index e72029b7d4..1aa09bbcae 100644 --- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/OrderBy.java +++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/OrderByComponent.java @@ -19,21 +19,23 @@ package org.apache.iotdb.db.mpp.plan.statement.component; -/** The order of query result set by timestamp */ -public enum OrderBy { - TIMESTAMP_ASC, - TIMESTAMP_DESC, - DEVICE_ASC, - DEVICE_DESC; +import java.util.ArrayList; +import java.util.List; - public OrderBy reverse() { - switch (this) { - case TIMESTAMP_ASC: - return TIMESTAMP_DESC; - case TIMESTAMP_DESC: - return TIMESTAMP_ASC; - default: - throw new UnsupportedOperationException(); - } +/** The order of query result set */ +public class OrderByComponent { + + private final List<SortItem> sortItemList; + + public OrderByComponent() { + this.sortItemList = new ArrayList<>(); + } + + public void addSortItem(SortItem sortItem) { + this.sortItemList.add(sortItem); + } + + public List<SortItem> getSortItemList() { + return sortItemList; } } diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/SortItem.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/SortItem.java new file mode 100644 index 0000000000..bbdff9f01b --- /dev/null +++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/SortItem.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.db.mpp.plan.statement.component; + +import org.apache.iotdb.db.mpp.plan.statement.StatementNode; + +import java.util.Objects; + +public class SortItem extends StatementNode { + + public enum SortKey { + TIME, + TIMESERIES, + DEVICE + } + + public enum Ordering { + ASC, + DESC; + + public Ordering reverse() { + if (this == ASC) { + return DESC; + } else { + return ASC; + } + } + } + + private final SortKey sortKey; + private final Ordering ordering; + + public SortItem(SortKey sortKey, Ordering ordering) { + this.sortKey = sortKey; + this.ordering = ordering; + } + + public SortKey getSortKey() { + return sortKey; + } + + public Ordering getOrdering() { + return ordering; + } + + public SortItem reverse() { + return new SortItem(getSortKey(), getOrdering().reverse()); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SortItem sortItem = (SortItem) o; + return sortKey == sortItem.sortKey && ordering == sortItem.ordering; + } + + @Override + public int hashCode() { + return Objects.hash(sortKey, ordering); + } +} 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 17f433a2e7..2da55d6f42 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 @@ -31,7 +31,7 @@ import org.apache.iotdb.db.mpp.plan.statement.component.FillComponent; import org.apache.iotdb.db.mpp.plan.statement.component.FromComponent; import org.apache.iotdb.db.mpp.plan.statement.component.GroupByLevelComponent; import org.apache.iotdb.db.mpp.plan.statement.component.GroupByTimeComponent; -import org.apache.iotdb.db.mpp.plan.statement.component.OrderBy; +import org.apache.iotdb.db.mpp.plan.statement.component.OrderByComponent; import org.apache.iotdb.db.mpp.plan.statement.component.ResultColumn; import org.apache.iotdb.db.mpp.plan.statement.component.ResultSetFormat; import org.apache.iotdb.db.mpp.plan.statement.component.SelectComponent; @@ -76,7 +76,7 @@ public class QueryStatement extends Statement { protected FillComponent fillComponent; - protected OrderBy resultOrder = OrderBy.TIMESTAMP_ASC; + protected OrderByComponent orderByComponent; protected ResultSetFormat resultSetFormat = ResultSetFormat.ALIGN_BY_TIME; @@ -159,12 +159,12 @@ public class QueryStatement extends Statement { this.fillComponent = fillComponent; } - public OrderBy getResultOrder() { - return resultOrder; + public OrderByComponent getOrderByComponent() { + return orderByComponent; } - public void setResultOrder(OrderBy resultOrder) { - this.resultOrder = resultOrder; + public void setOrderByComponent(OrderByComponent orderByComponent) { + this.orderByComponent = orderByComponent; } public ResultSetFormat getResultSetFormat() { diff --git a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java index 79bb5d9db0..d4c58d998c 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java @@ -53,6 +53,7 @@ import org.apache.iotdb.db.mpp.plan.expression.unary.LikeExpression; import org.apache.iotdb.db.mpp.plan.expression.unary.LogicNotExpression; import org.apache.iotdb.db.mpp.plan.expression.unary.NegationExpression; import org.apache.iotdb.db.mpp.plan.expression.unary.RegularExpression; +import org.apache.iotdb.db.mpp.plan.statement.component.SortItem; import org.apache.iotdb.db.qp.constant.FilterConstant; import org.apache.iotdb.db.qp.constant.FilterConstant.FilterType; import org.apache.iotdb.db.qp.constant.SQLConstant; @@ -1341,7 +1342,7 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> { @Override public Operator visitOrderByTimeStatement(IoTDBSqlParser.OrderByTimeStatementContext ctx) { queryOp = new QueryOperator(); - parseOrderByTimeClause(ctx.orderByTimeClause()); + parseOrderByClause(ctx.orderByClause()); if (ctx.specialLimit() != null) { return visit(ctx.specialLimit()); } @@ -1352,8 +1353,8 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> { public Operator visitGroupByTimeStatement(IoTDBSqlParser.GroupByTimeStatementContext ctx) { queryOp = new GroupByQueryOperator(); parseGroupByTimeClause(ctx.groupByTimeClause()); - if (ctx.orderByTimeClause() != null) { - parseOrderByTimeClause(ctx.orderByTimeClause()); + if (ctx.orderByClause() != null) { + parseOrderByClause(ctx.orderByClause()); } if (ctx.specialLimit() != null) { return visit(ctx.specialLimit()); @@ -1365,8 +1366,8 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> { public Operator visitGroupByFillStatement(IoTDBSqlParser.GroupByFillStatementContext ctx) { queryOp = new GroupByFillQueryOperator(); parseGroupByFillClause(ctx.groupByFillClause()); - if (ctx.orderByTimeClause() != null) { - parseOrderByTimeClause(ctx.orderByTimeClause()); + if (ctx.orderByClause() != null) { + parseOrderByClause(ctx.orderByClause()); } if (ctx.specialLimit() != null) { return visit(ctx.specialLimit()); @@ -1378,8 +1379,8 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> { public Operator visitGroupByLevelStatement(IoTDBSqlParser.GroupByLevelStatementContext ctx) { queryOp = new AggregationQueryOperator(); parseGroupByLevelClause(ctx.groupByLevelClause()); - if (ctx.orderByTimeClause() != null) { - parseOrderByTimeClause(ctx.orderByTimeClause()); + if (ctx.orderByClause() != null) { + parseOrderByClause(ctx.orderByClause()); } if (ctx.specialLimit() != null) { return visit(ctx.specialLimit()); @@ -1391,8 +1392,8 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> { public Operator visitFillStatement(IoTDBSqlParser.FillStatementContext ctx) { queryOp = new FillQueryOperator(); parseFillClause(ctx.fillClause()); - if (ctx.orderByTimeClause() != null) { - parseOrderByTimeClause(ctx.orderByTimeClause()); + if (ctx.orderByClause() != null) { + parseOrderByClause(ctx.orderByClause()); } if (ctx.specialLimit() != null) { return visit(ctx.specialLimit()); @@ -1480,8 +1481,15 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> { specialClauseComponent.setAlignByTime(false); } - private void parseOrderByTimeClause(IoTDBSqlParser.OrderByTimeClauseContext ctx) { - if (ctx.DESC() != null) { + private void parseOrderByClause(IoTDBSqlParser.OrderByClauseContext ctx) { + if (ctx.orderByAttributeClause().size() > 0) { + throw new SQLParserException("Sorting by multiple fields is not supported."); + } + SortItem sortItem = parseOrderByAttributeClause(ctx.orderByAttributeClause(0)); + if (sortItem.getSortKey() != SortItem.SortKey.TIME) { + throw new SQLParserException("It only supports sorting by time."); + } + if (sortItem.getOrdering() == SortItem.Ordering.DESC) { SpecialClauseComponent specialClauseComponent = queryOp.getSpecialClauseComponent(); if (specialClauseComponent == null) { specialClauseComponent = new SpecialClauseComponent(); @@ -1491,6 +1499,12 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> { } } + private SortItem parseOrderByAttributeClause(IoTDBSqlParser.OrderByAttributeClauseContext ctx) { + return new SortItem( + SortItem.SortKey.valueOf(ctx.sortKey().getText().toUpperCase()), + ctx.DESC() != null ? SortItem.Ordering.DESC : SortItem.Ordering.ASC); + } + private void parseGroupByTimeClause(IoTDBSqlParser.GroupByTimeClauseContext ctx) { GroupByClauseComponent groupByClauseComponent = new GroupByClauseComponent(); groupByClauseComponent.setLeftCRightO(ctx.timeRange().LS_BRACKET() != null);
