This is an automated email from the ASF dual-hosted git repository. rong pushed a commit to branch iotdb-2310 in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 24a9c9ff9fca50077ab19564db7cb87e5cf73d8b Author: Steve Yurong Su <[email protected]> AuthorDate: Sat Jan 15 18:52:21 2022 +0800 [IOTDB-2310][IOTDB-2311][IOTDB-2372] Add query type check for REST query API --- .../handler/PhysicalPlanValidationHandler.java | 78 ++++++++++++++++++++++ .../rest/handler/RequestValidationHandler.java | 5 ++ .../db/protocol/rest/impl/RestApiServiceImpl.java | 5 +- .../main/java/org/apache/iotdb/db/qp/Planner.java | 29 ++++++++ 4 files changed, 116 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/org/apache/iotdb/db/protocol/rest/handler/PhysicalPlanValidationHandler.java b/server/src/main/java/org/apache/iotdb/db/protocol/rest/handler/PhysicalPlanValidationHandler.java new file mode 100644 index 0000000..75bb686 --- /dev/null +++ b/server/src/main/java/org/apache/iotdb/db/protocol/rest/handler/PhysicalPlanValidationHandler.java @@ -0,0 +1,78 @@ +/* + * 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.protocol.rest.handler; + +import org.apache.iotdb.db.exception.query.LogicalOperatorException; +import org.apache.iotdb.db.qp.logical.Operator; +import org.apache.iotdb.db.qp.logical.crud.GroupByQueryOperator; +import org.apache.iotdb.db.qp.logical.crud.LastQueryOperator; +import org.apache.iotdb.db.qp.logical.crud.QueryOperator; +import org.apache.iotdb.db.qp.logical.crud.SelectIntoOperator; + +public class PhysicalPlanValidationHandler { + + public static void checkRestQuery(Operator operator) throws LogicalOperatorException { + if (operator instanceof SelectIntoOperator) { + throw new LogicalOperatorException("select into clauses are not supported."); + } + + if (!(operator instanceof QueryOperator)) { + return; + } + QueryOperator queryOperator = (QueryOperator) operator; + + if (queryOperator.isAlignByDevice()) { + throw new LogicalOperatorException("align by device clauses are not supported."); + } + + // disable align + if (!queryOperator.isAlignByTime()) { + throw new LogicalOperatorException("disable align clauses are not supported."); + } + } + + public static void checkGrafanaQuery(Operator operator) throws LogicalOperatorException { + if (!(operator instanceof QueryOperator)) { + return; + } + QueryOperator queryOperator = (QueryOperator) operator; + + if (queryOperator.isAlignByDevice()) { + throw new LogicalOperatorException("align by device clauses are not supported."); + } + + // disable align + if (!queryOperator.isAlignByTime()) { + throw new LogicalOperatorException("disable align clauses are not supported."); + } + + if (queryOperator instanceof LastQueryOperator) { + throw new LogicalOperatorException("last clauses are not supported."); + } + + if (!(queryOperator instanceof GroupByQueryOperator) && queryOperator.isGroupByLevel()) { + throw new LogicalOperatorException( + "group by level without time interval clauses are not supported."); + } + + if (queryOperator.getSpecialClauseComponent() != null + && !queryOperator.getSpecialClauseComponent().isAscending()) { + throw new LogicalOperatorException("order by time desc clauses are not supported."); + } + } +} diff --git a/server/src/main/java/org/apache/iotdb/db/protocol/rest/handler/RequestValidationHandler.java b/server/src/main/java/org/apache/iotdb/db/protocol/rest/handler/RequestValidationHandler.java index 2a98d31..4d04699 100644 --- a/server/src/main/java/org/apache/iotdb/db/protocol/rest/handler/RequestValidationHandler.java +++ b/server/src/main/java/org/apache/iotdb/db/protocol/rest/handler/RequestValidationHandler.java @@ -21,6 +21,8 @@ import org.apache.iotdb.db.protocol.rest.model.ExpressionRequest; import org.apache.iotdb.db.protocol.rest.model.InsertTabletRequest; import org.apache.iotdb.db.protocol.rest.model.SQL; +import org.apache.commons.lang3.Validate; + import java.util.Objects; public class RequestValidationHandler { @@ -29,6 +31,9 @@ public class RequestValidationHandler { public static void validateSQL(SQL sql) { Objects.requireNonNull(sql.getSql(), "sql should not be null"); + Validate.isTrue( + sql.getRowLimit() == null || sql.getRowLimit() <= 0, + "rowLimit can not be null and should be positive"); } public static void validateInsertTabletRequest(InsertTabletRequest insertTabletRequest) { diff --git a/server/src/main/java/org/apache/iotdb/db/protocol/rest/impl/RestApiServiceImpl.java b/server/src/main/java/org/apache/iotdb/db/protocol/rest/impl/RestApiServiceImpl.java index 0549668..1308d2a 100644 --- a/server/src/main/java/org/apache/iotdb/db/protocol/rest/impl/RestApiServiceImpl.java +++ b/server/src/main/java/org/apache/iotdb/db/protocol/rest/impl/RestApiServiceImpl.java @@ -43,6 +43,8 @@ import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; +import java.time.ZoneId; + public class RestApiServiceImpl extends RestApiService { public static ServiceProvider serviceProvider = IoTDB.serviceProvider; @@ -91,7 +93,8 @@ public class RestApiServiceImpl extends RestApiService { try { RequestValidationHandler.validateSQL(sql); - PhysicalPlan physicalPlan = planner.parseSQLToPhysicalPlan(sql.getSql()); + PhysicalPlan physicalPlan = + planner.parseSQLToRestQueryPlan(sql.getSql(), ZoneId.systemDefault()); if (!(physicalPlan instanceof QueryPlan)) { return Response.ok() .entity( diff --git a/server/src/main/java/org/apache/iotdb/db/qp/Planner.java b/server/src/main/java/org/apache/iotdb/db/qp/Planner.java index 02258df..1cfa66a 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/Planner.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/Planner.java @@ -23,6 +23,7 @@ import org.apache.iotdb.db.exception.query.LogicalOperatorException; import org.apache.iotdb.db.exception.query.LogicalOptimizeException; import org.apache.iotdb.db.exception.query.PathNumOverLimitException; import org.apache.iotdb.db.exception.query.QueryProcessException; +import org.apache.iotdb.db.protocol.rest.handler.PhysicalPlanValidationHandler; import org.apache.iotdb.db.qp.logical.Operator; import org.apache.iotdb.db.qp.logical.crud.FilterOperator; import org.apache.iotdb.db.qp.logical.crud.QueryOperator; @@ -150,4 +151,32 @@ public class Planner { // from logical operator to physical plan return new PhysicalGenerator().transformToPhysicalPlan(operator); } + + public PhysicalPlan parseSQLToRestQueryPlan(String sqlStr, ZoneId zoneId) + throws QueryProcessException { + // from SQL to logical operator + Operator operator = LogicalGenerator.generate(sqlStr, zoneId); + // check if there are logical errors + LogicalChecker.check(operator); + // extra check for rest query + PhysicalPlanValidationHandler.checkRestQuery(operator); + // optimize the logical operator + operator = logicalOptimize(operator); + // from logical operator to physical plan + return new PhysicalGenerator().transformToPhysicalPlan(operator); + } + + public PhysicalPlan parseSQLToGrafanaQueryPlan(String sqlStr, ZoneId zoneId) + throws QueryProcessException { + // from SQL to logical operator + Operator operator = LogicalGenerator.generate(sqlStr, zoneId); + // check if there are logical errors + LogicalChecker.check(operator); + // extra check for grafana query + PhysicalPlanValidationHandler.checkGrafanaQuery(operator); + // optimize the logical operator + operator = logicalOptimize(operator); + // from logical operator to physical plan + return new PhysicalGenerator().transformToPhysicalPlan(operator); + } }
