This is an automated email from the ASF dual-hosted git repository. geniuspig pushed a commit to branch change_listener_to_visitor_0.11 in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit b5eff27d78dddac52e7ec2b2b275e3169429313e Author: Boris <[email protected]> AuthorDate: Thu Nov 12 17:06:00 2020 +0800 finish query --- .../antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 | 30 +- .../main/java/org/apache/iotdb/db/qp/Planner.java | 8 +- .../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java | 350 ++++++++++++++++++++- .../{ParseDriver.java => LogicalGenerator.java} | 8 +- .../iotdb/db/qp/plan/LogicalPlanSmallTest.java | 110 +++---- 5 files changed, 417 insertions(+), 89 deletions(-) diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 index 27bca32..29cccbe 100644 --- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 +++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 @@ -157,7 +157,7 @@ alterClause | DROP ID (COMMA ID)* | ADD TAGS property (COMMA property)* | ADD ATTRIBUTES property (COMMA property)* - | UPSERT aliasClause tagClause attributeClause + | UPSERT aliasClause tagClause attributeClause? ; aliasClause @@ -168,8 +168,8 @@ attributeClauses : DATATYPE OPERATOR_EQ dataType (COMMA ENCODING OPERATOR_EQ encoding)? (COMMA (COMPRESSOR | COMPRESSION) OPERATOR_EQ compressor)? (COMMA property)* - tagClause - attributeClause + tagClause? + attributeClause? ; compressor @@ -184,11 +184,11 @@ compressor ; attributeClause - : (ATTRIBUTES LR_BRACKET property (COMMA property)* RR_BRACKET)? + : ATTRIBUTES LR_BRACKET property (COMMA property)* RR_BRACKET ; tagClause - : (TAGS LR_BRACKET property (COMMA property)* RR_BRACKET)? + : TAGS LR_BRACKET property (COMMA property)* RR_BRACKET ; setClause @@ -229,19 +229,19 @@ fromClause ; specialClause - : specialLimit - | orderByTimeClause specialLimit? - | groupByTimeClause orderByTimeClause? specialLimit? - | groupByFillClause orderByTimeClause? specialLimit? - | fillClause slimitClause? alignByDeviceClauseOrDisableAlign? - | alignByDeviceClauseOrDisableAlign - | groupByLevelClause orderByTimeClause? specialLimit? + : specialLimit #specialLimitStatement + | orderByTimeClause specialLimit? #orderByTimeStatement + | groupByTimeClause orderByTimeClause? specialLimit? #groupByTimeStatement + | groupByFillClause orderByTimeClause? specialLimit? #groupByFillStatement + | fillClause slimitClause? alignByDeviceClauseOrDisableAlign? #fillStatement + | alignByDeviceClauseOrDisableAlign #alignByDeviceStatementOrDisableAlignInSpecialClause + | groupByLevelClause orderByTimeClause? specialLimit? #groupByLevelStatement ; specialLimit - : limitClause slimitClause? alignByDeviceClauseOrDisableAlign? - | slimitClause limitClause? alignByDeviceClauseOrDisableAlign? - | alignByDeviceClauseOrDisableAlign + : limitClause slimitClause? alignByDeviceClauseOrDisableAlign? #limitStatement + | slimitClause limitClause? alignByDeviceClauseOrDisableAlign? #slimitStatement + | alignByDeviceClauseOrDisableAlign #alignByDeviceClauseOrDisableAlignInSpecialLimit ; orderByTimeClause 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 48bb90e..4b6e79c 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 @@ -41,7 +41,7 @@ import org.apache.iotdb.db.qp.logical.crud.QueryOperator; import org.apache.iotdb.db.qp.logical.crud.SFWOperator; import org.apache.iotdb.db.qp.logical.crud.SelectOperator; import org.apache.iotdb.db.qp.physical.PhysicalPlan; -import org.apache.iotdb.db.qp.strategy.ParseDriver; +import org.apache.iotdb.db.qp.strategy.LogicalGenerator; import org.apache.iotdb.db.qp.strategy.PhysicalGenerator; import org.apache.iotdb.db.qp.strategy.optimizer.ConcatPathOptimizer; import org.apache.iotdb.db.qp.strategy.optimizer.DnfFilterOptimizer; @@ -56,10 +56,10 @@ import org.apache.iotdb.service.rpc.thrift.TSRawDataQueryReq; */ public class Planner { - protected ParseDriver parseDriver; + protected LogicalGenerator logicalGenerator; public Planner() { - this.parseDriver = new ParseDriver(); + this.logicalGenerator = new LogicalGenerator(); } @TestOnly @@ -73,7 +73,7 @@ public class Planner { */ public PhysicalPlan parseSQLToPhysicalPlan(String sqlStr, ZoneId zoneId, int fetchSize) throws QueryProcessException { - Operator operator = parseDriver.parse(sqlStr, zoneId); + Operator operator = logicalGenerator.generate(sqlStr, zoneId); int maxDeduplicatedPathNum = QueryResourceManager.getInstance() .getMaxDeduplicatedPathNum(fetchSize); if (operator instanceof SFWOperator && ((SFWOperator) operator).isLastQuery()) { 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 f701c82..9213b84 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 @@ -58,11 +58,16 @@ import org.apache.iotdb.db.qp.logical.sys.ShowStorageGroupOperator; import org.apache.iotdb.db.qp.logical.sys.ShowTTLOperator; import org.apache.iotdb.db.qp.logical.sys.ShowTimeSeriesOperator; import org.apache.iotdb.db.qp.logical.sys.TracingOperator; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlignByDeviceClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AliasClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlignByDeviceClauseOrDisableAlignInSpecialLimitContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlignByDeviceStatementOrDisableAlignInSpecialClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlterClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlterTimeseriesContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlterUserContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.AndExpressionContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AsClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AsElementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AttributeClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.AttributeClausesContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.ClearcacheContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.ConstantContext; @@ -81,21 +86,34 @@ import org.apache.iotdb.db.qp.sql.SqlBaseParser.DeleteStorageGroupContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.DeleteTimeseriesContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.DropRoleContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.DropUserContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FillClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FillStatementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.FlushContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.FromClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.FullMergeContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.FullPathContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FunctionAsClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FunctionAsElementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FunctionCallContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FunctionElementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.GrantRoleContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.GrantRoleToUserContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.GrantUserContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.GrantWatermarkEmbeddingContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.GroupByFillClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.GroupByFillStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.GroupByLevelClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.GroupByLevelStatementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.GroupByTimeClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.GroupByTimeStatementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.InClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.InsertColumnSpecContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.InsertStatementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.InsertValuesSpecContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.LastClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.LastElementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.LimitClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.LimitStatementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.ListAllRoleOfUserContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.ListAllUserOfRoleContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.ListPrivilegesRoleContext; @@ -111,8 +129,10 @@ import org.apache.iotdb.db.qp.sql.SqlBaseParser.MergeContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.MoveFileContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.NodeNameContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.NodeNameWithoutStarContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.OffsetClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.OrExpressionContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.OrderByTimeClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.OrderByTimeStatementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.PredicateContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.PrefixPathContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.PrivilegesContext; @@ -141,8 +161,12 @@ import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowVersionContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowWhereClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.SingleStatementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.SlimitClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.SlimitStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.SoffsetClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.SpecialLimitStatementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.StringLiteralContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.SuffixPathContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.TagClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.TimeIntervalContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.TracingOffContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.TracingOnContext; @@ -166,6 +190,7 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { "For delete statement, where clause can only contain atomic expressions like : " + "time > XXX, time <= XXX, or two atomic expressions connected by 'AND'"; private ZoneId zoneId; + QueryOperator queryOp; public void setZoneId(ZoneId zoneId) { this.zoneId = zoneId; @@ -218,7 +243,7 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { insertOp.setSelectOperator(selectOp); parseInsertColumnSpec(ctx.insertColumnSpec(), insertOp); parseInsertValuesSpec(ctx.insertValuesSpec(), insertOp); - return insertOp; + return insertOp; } @Override @@ -566,7 +591,9 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { if(ctx.showWhereClause() != null) { parseShowWhereClause(ctx.showWhereClause(), showTimeSeriesOperator); } - showTimeSeriesOperator.setLimit(parseLimitClause(ctx.limitClause())); + if(ctx.limitClause() != null) { + parseLimitClause(ctx.limitClause(), showTimeSeriesOperator); + } return showTimeSeriesOperator; } @@ -717,13 +744,200 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { @Override public Operator visitSelectStatement(SelectStatementContext ctx) { - QueryOperator queryOp = new QueryOperator(SQLConstant.TOK_QUERY); + queryOp = new QueryOperator(SQLConstant.TOK_QUERY); SelectOperator selectOp = (SelectOperator) visit(ctx.selectElements()); + queryOp.setSelectOperator(selectOp); FromOperator fromOp = (FromOperator) visit(ctx.fromClause()); - FilterOperator whereOp = (FilterOperator) visit(ctx.whereClause()); queryOp.setFromOperator(fromOp); - queryOp.setFilterOperator(whereOp.getChildren().get(0)); - queryOp.setSelectOperator(selectOp); + if(ctx.whereClause() != null) { + FilterOperator whereOp = (FilterOperator) visit(ctx.whereClause()); + queryOp.setFilterOperator(whereOp.getChildren().get(0)); + } + if(ctx.specialClause() != null) { + visit(ctx.specialClause()); + } + return queryOp; + } + + @Override + public Operator visitFunctionElement(FunctionElementContext ctx) { + SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT); + List<FunctionCallContext> functionCallContextList = ctx.functionCall(); + for (FunctionCallContext functionCallContext : functionCallContextList) { + PartialPath path = parseSuffixPath(functionCallContext.suffixPath()); + selectOp.addClusterPath(path, functionCallContext.functionName().getText()); + } + return selectOp; + } + + @Override + public Operator visitLastElement(LastElementContext ctx) { + SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT); + selectOp.setLastQuery(); + LastClauseContext lastClauseContext = ctx.lastClause(); + if (lastClauseContext.asClause().size() != 0) { + parseAsClause(lastClauseContext.asClause(), selectOp); + } else { + List<SuffixPathContext> suffixPaths = lastClauseContext.suffixPath(); + for (SuffixPathContext suffixPath : suffixPaths) { + PartialPath path = parseSuffixPath(suffixPath); + selectOp.addSelectPath(path); + } + } + return selectOp; + } + + @Override + public Operator visitAsElement(AsElementContext ctx) { + SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT); + parseAsClause(ctx.asClause(), selectOp); + return selectOp; + } + + @Override + public Operator visitFunctionAsElement(FunctionAsElementContext ctx) { + SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT); + List<FunctionAsClauseContext> functionAsClauseContexts = ctx.functionAsClause(); + for (FunctionAsClauseContext functionAsClauseContext : functionAsClauseContexts) { + FunctionCallContext functionCallContext = functionAsClauseContext.functionCall(); + PartialPath path = parseSuffixPath(functionCallContext.suffixPath()); + if (functionAsClauseContext.ID() != null) { + path.setTsAlias(functionAsClauseContext.ID().toString()); + } + selectOp.addClusterPath(path, functionCallContext.functionName().getText()); + } + return selectOp; + } + + public void parseAsClause(List<AsClauseContext> asClauseContexts, SelectOperator selectOp) { + for (AsClauseContext asClauseContext : asClauseContexts) { + PartialPath path = parseSuffixPath(asClauseContext.suffixPath()); + if (asClauseContext.ID() != null) { + path.setTsAlias(asClauseContext.ID().toString()); + } + selectOp.addSelectPath(path); + } + } + + @Override + public Operator visitSpecialLimitStatement(SpecialLimitStatementContext ctx) { + return visit(ctx.specialLimit()); + } + + @Override + public Operator visitLimitStatement(LimitStatementContext ctx) { + parseLimitClause(ctx.limitClause(), queryOp); + if(ctx.slimitClause() != null) { + parseSlimitClause(ctx.slimitClause(), queryOp); + } + if(ctx.alignByDeviceClauseOrDisableAlign() != null) { + if(ctx.alignByDeviceClauseOrDisableAlign().alignByDeviceClause() != null) { + parseAlignByDeviceClause(queryOp); + } else { + parseDisableAlign(queryOp); + } + } + return queryOp; + } + + @Override + public Operator visitSlimitStatement(SlimitStatementContext ctx) { + parseSlimitClause(ctx.slimitClause(), queryOp); + if(ctx.limitClause() != null) { + parseLimitClause(ctx.limitClause(), queryOp); + } + if(ctx.alignByDeviceClauseOrDisableAlign() != null) { + if(ctx.alignByDeviceClauseOrDisableAlign().alignByDeviceClause() != null) { + parseAlignByDeviceClause(queryOp); + } else { + parseDisableAlign(queryOp); + } + } + return queryOp; + } + + @Override + public Operator visitAlignByDeviceClauseOrDisableAlignInSpecialLimit( + AlignByDeviceClauseOrDisableAlignInSpecialLimitContext ctx) { + if(ctx.alignByDeviceClauseOrDisableAlign().alignByDeviceClause() != null) { + parseAlignByDeviceClause(queryOp); + } else { + parseDisableAlign(queryOp); + } + return queryOp; + } + + @Override + public Operator visitOrderByTimeStatement(OrderByTimeStatementContext ctx) { + parseOrderByTimeClause(ctx.orderByTimeClause(), queryOp); + if(ctx.specialLimit() != null) { + return visit(ctx.specialLimit()); + } + return queryOp; + } + + @Override + public Operator visitGroupByTimeStatement(GroupByTimeStatementContext ctx) { + parseGroupByTimeClause(ctx.groupByTimeClause(), queryOp); + if(ctx.orderByTimeClause() != null) { + parseOrderByTimeClause(ctx.orderByTimeClause(), queryOp); + } + if(ctx.specialLimit() != null) { + return visit(ctx.specialLimit()); + } + return queryOp; + } + + @Override + public Operator visitGroupByFillStatement(GroupByFillStatementContext ctx) { + parseGroupByFillClause(ctx.groupByFillClause(), queryOp); + if(ctx.orderByTimeClause() != null) { + parseOrderByTimeClause(ctx.orderByTimeClause(), queryOp); + } + if(ctx.specialLimit() != null) { + return visit(ctx.specialLimit()); + } + return queryOp; + } + + @Override + public Operator visitFillStatement(FillStatementContext ctx) { + parseFillClause(ctx.fillClause(), queryOp); + if(ctx.slimitClause() != null) { + queryOp = (QueryOperator) visit(ctx.slimitClause()); + } + if(ctx.alignByDeviceClauseOrDisableAlign() != null) { + if(ctx.alignByDeviceClauseOrDisableAlign().alignByDeviceClause() != null) { + parseAlignByDeviceClause(queryOp); + } else { + parseDisableAlign(queryOp); + } + } + return queryOp; + } + + @Override + public Operator visitAlignByDeviceStatementOrDisableAlignInSpecialClause( + AlignByDeviceStatementOrDisableAlignInSpecialClauseContext ctx) { + if(ctx.alignByDeviceClauseOrDisableAlign() != null) { + if(ctx.alignByDeviceClauseOrDisableAlign().alignByDeviceClause() != null) { + parseAlignByDeviceClause(queryOp); + } else { + parseDisableAlign(queryOp); + } + } + return queryOp; + } + + @Override + public Operator visitGroupByLevelStatement(GroupByLevelStatementContext ctx) { + parseGroupByLevelClause(ctx.groupByLevelClause(), queryOp); + if(ctx.orderByTimeClause() != null) { + parseOrderByTimeClause(ctx.orderByTimeClause(), queryOp); + } + if(ctx.specialLimit() != null) { + return visit(ctx.specialLimit()); + } return queryOp; } @@ -754,7 +968,26 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { return fromOp; } - private int parseLimitClause(LimitClauseContext ctx) { + public void parseGroupByLevelClause(GroupByLevelClauseContext ctx, QueryOperator queryOp) { + queryOp.setGroupByLevel(true); + queryOp.setLevel(Integer.parseInt(ctx.INT().getText())); + } + + public void parseFillClause(FillClauseContext ctx, QueryOperator queryOp) { + FilterOperator filterOperator = queryOp.getFilterOperator(); + if (!filterOperator.isLeaf() || filterOperator.getTokenIntType() != SQLConstant.EQUAL) { + throw new SQLParserException("Only \"=\" can be used in fill function"); + } + List<TypeClauseContext> list = ctx.typeClause(); + Map<TSDataType, IFill> fillTypes = new EnumMap<>(TSDataType.class); + for (TypeClauseContext typeClause : list) { + parseTypeClause(typeClause, fillTypes); + } + queryOp.setFill(true); + queryOp.setFillTypes(fillTypes); + } + + private void parseLimitClause(LimitClauseContext ctx, Operator operator) { int limit; try { limit = Integer.parseInt(ctx.INT().getText()); @@ -764,10 +997,35 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { if (limit <= 0) { throw new SQLParserException("LIMIT <N>: N should be greater than 0."); } - return limit; + if(operator instanceof ShowTimeSeriesOperator) { + ((ShowTimeSeriesOperator) operator).setLimit(limit); + } else { + ((QueryOperator) operator).setRowLimit(limit); + } + if(ctx.offsetClause() != null) { + parseOffsetClause(ctx.offsetClause(), operator); + } } - private int parseSlimitClause(SlimitClauseContext ctx) { + private void parseOffsetClause(OffsetClauseContext ctx, Operator operator) { + int offset; + try { + offset = Integer.parseInt(ctx.INT().getText()); + } catch (NumberFormatException e) { + throw new SQLParserException( + "Out of range. OFFSET <OFFSETValue>: OFFSETValue should be Int32."); + } + if (offset < 0) { + throw new SQLParserException("OFFSET <OFFSETValue>: OFFSETValue should >= 0."); + } + if (operator instanceof ShowTimeSeriesOperator) { + ((ShowTimeSeriesOperator) operator).setOffset(offset); + } else { + ((QueryOperator) operator).setRowOffset(offset); + } + } + + private void parseSlimitClause(SlimitClauseContext ctx, QueryOperator queryOp) { int slimit; try { slimit = Integer.parseInt(ctx.INT().getText()); @@ -778,7 +1036,25 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { if (slimit <= 0) { throw new SQLParserException("SLIMIT <SN>: SN should be greater than 0."); } - return slimit; + queryOp.setSeriesLimit(slimit); + if(ctx.soffsetClause() != null) { + parseSoffsetClause(ctx.soffsetClause(), queryOp); + } + } + + public void parseSoffsetClause(SoffsetClauseContext ctx, QueryOperator queryOp) { + int soffset; + try { + soffset = Integer.parseInt(ctx.INT().getText()); + } catch (NumberFormatException e) { + throw new SQLParserException( + "Out of range. SOFFSET <SOFFSETValue>: SOFFSETValue should be Int32."); + } + if (soffset < 0) { + throw new SQLParserException( + "SOFFSET <SOFFSETValue>: SOFFSETValue should >= 0."); + } + queryOp.setSeriesOffset(soffset); } private void parseGroupByTimeClause(GroupByTimeClauseContext ctx, QueryOperator queryOp) { @@ -1271,10 +1547,21 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { } else { // upsert alterTimeSeriesOperator.setAlterType(AlterType.UPSERT); + parseAliasClause(ctx.aliasClause(), alterTimeSeriesOperator); + parseTagClause(ctx.tagClause(), alterTimeSeriesOperator); + if(ctx.attributeClause() != null) { + parseAttributeClause(ctx.attributeClause(), alterTimeSeriesOperator); + } } alterTimeSeriesOperator.setAlterMap(alterMap); } + public void parseAliasClause(AliasClauseContext ctx, AlterTimeSeriesOperator alterTimeSeriesOperator) { + if (alterTimeSeriesOperator != null && ctx.ID() != null) { + alterTimeSeriesOperator.setAlias(ctx.ID().getText()); + } + } + private void setMap(SqlBaseParser.AlterClauseContext ctx, Map<String, String> alterMap) { List<PropertyContext> tagsList = ctx.property(); if (ctx.property(0) != null) { @@ -1340,6 +1627,47 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { } createTimeSeriesOperator.setCompressor(compressor); createTimeSeriesOperator.setProps(props); + if(ctx.tagClause() != null) { + parseTagClause(ctx.tagClause(), createTimeSeriesOperator); + } + if(ctx.attributeClause() != null) { + parseAttributeClause(ctx.attributeClause(), createTimeSeriesOperator); + } + } + + public void parseAttributeClause(AttributeClauseContext ctx, Operator operator) { + Map<String, String> attributes = extractMap(ctx.property(), ctx.property(0)); + if (operator instanceof CreateTimeSeriesOperator) { + ((CreateTimeSeriesOperator) operator).setAttributes(attributes); + } else if (operator instanceof AlterTimeSeriesOperator) { + ((AlterTimeSeriesOperator) operator).setAttributesMap(attributes); + } + } + + public void parseTagClause(TagClauseContext ctx, Operator operator) { + Map<String, String> tags = extractMap(ctx.property(), ctx.property(0)); + if (operator instanceof CreateTimeSeriesOperator) { + ((CreateTimeSeriesOperator) operator).setTags(tags); + } else if (operator instanceof AlterTimeSeriesOperator) { + ((AlterTimeSeriesOperator) operator).setTagsMap(tags); + } + } + + private Map<String, String> extractMap(List<PropertyContext> property2, + PropertyContext property3) { + String value; + Map<String, String> tags = new HashMap<>(property2.size()); + if (property3 != null) { + for (PropertyContext property : property2) { + if (property.propertyValue().stringLiteral() != null) { + value = removeStringQuote(property.propertyValue().getText()); + } else { + value = property.propertyValue().getText(); + } + tags.put(property.ID().getText(), value); + } + } + return tags; } private PartialPath parseFullPath(FullPathContext ctx) { diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/ParseDriver.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java similarity index 93% rename from server/src/main/java/org/apache/iotdb/db/qp/strategy/ParseDriver.java rename to server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java index 37b9467..057e4bc 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/ParseDriver.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java @@ -31,14 +31,14 @@ import org.apache.iotdb.db.qp.sql.SqlBaseLexer; import org.apache.iotdb.db.qp.sql.SqlBaseParser; /** - * ParseDriver. + * LogicalGenerator. * */ -public class ParseDriver { +public class LogicalGenerator { - public ParseDriver() { } + public LogicalGenerator() { } - public Operator parse(String sql, ZoneId zoneId) throws ParseCancellationException { + public Operator generate(String sql, ZoneId zoneId) throws ParseCancellationException { IoTDBSqlVisitor ioTDBSqlVisitor = new IoTDBSqlVisitor(); ioTDBSqlVisitor.setZoneId(zoneId); CharStream charStream1 = CharStreams.fromString(sql); diff --git a/server/src/test/java/org/apache/iotdb/db/qp/plan/LogicalPlanSmallTest.java b/server/src/test/java/org/apache/iotdb/db/qp/plan/LogicalPlanSmallTest.java index 614117e..f048a28 100644 --- a/server/src/test/java/org/apache/iotdb/db/qp/plan/LogicalPlanSmallTest.java +++ b/server/src/test/java/org/apache/iotdb/db/qp/plan/LogicalPlanSmallTest.java @@ -32,7 +32,7 @@ import org.apache.iotdb.db.qp.logical.crud.DeleteDataOperator; import org.apache.iotdb.db.qp.logical.crud.QueryOperator; import org.apache.iotdb.db.qp.logical.sys.DeleteStorageGroupOperator; import org.apache.iotdb.db.qp.logical.sys.SetStorageGroupOperator; -import org.apache.iotdb.db.qp.strategy.ParseDriver; +import org.apache.iotdb.db.qp.strategy.LogicalGenerator; import org.apache.iotdb.db.qp.strategy.optimizer.ConcatPathOptimizer; import org.apache.iotdb.db.service.IoTDB; import org.junit.Assert; @@ -41,18 +41,18 @@ import org.junit.Test; public class LogicalPlanSmallTest { - private ParseDriver parseDriver; + private LogicalGenerator logicalGenerator; @Before public void before() { - parseDriver = new ParseDriver(); + logicalGenerator = new LogicalGenerator(); } @Test public void testLimit() { String sqlStr = "select * from root.vehicle.d1 limit 10"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); Assert.assertEquals(QueryOperator.class, operator.getClass()); Assert.assertEquals(10, ((QueryOperator) operator).getRowLimit()); Assert.assertEquals(0, ((QueryOperator) operator).getRowOffset()); @@ -63,8 +63,8 @@ public class LogicalPlanSmallTest { @Test public void testOffset() { String sqlStr = "select * from root.vehicle.d1 limit 10 offset 20"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); Assert.assertEquals(QueryOperator.class, operator.getClass()); Assert.assertEquals(10, ((QueryOperator) operator).getRowLimit()); Assert.assertEquals(20, ((QueryOperator) operator).getRowOffset()); @@ -75,8 +75,8 @@ public class LogicalPlanSmallTest { @Test public void testSlimit() { String sqlStr = "select * from root.vehicle.d1 limit 10 slimit 1"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); Assert.assertEquals(QueryOperator.class, operator.getClass()); Assert.assertEquals(10, ((QueryOperator) operator).getRowLimit()); Assert.assertEquals(0, ((QueryOperator) operator).getRowOffset()); @@ -87,8 +87,8 @@ public class LogicalPlanSmallTest { @Test public void testSOffset() { String sqlStr = "select * from root.vehicle.d1 where s1 < 20 and time <= now() limit 50 slimit 10 soffset 100"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); Assert.assertEquals(QueryOperator.class, operator.getClass()); Assert.assertEquals(50, ((QueryOperator) operator).getRowLimit()); Assert.assertEquals(0, ((QueryOperator) operator).getRowOffset()); @@ -99,8 +99,8 @@ public class LogicalPlanSmallTest { @Test public void testSOffsetTimestamp() { String sqlStr = "select * from root.vehicle.d1 where s1 < 20 and timestamp <= now() limit 50 slimit 10 soffset 100"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); Assert.assertEquals(QueryOperator.class, operator.getClass()); Assert.assertEquals(50, ((QueryOperator) operator).getRowLimit()); Assert.assertEquals(0, ((QueryOperator) operator).getRowOffset()); @@ -111,16 +111,16 @@ public class LogicalPlanSmallTest { @Test(expected = SQLParserException.class) public void testLimitOutOfRange() { String sqlStr = "select * from root.vehicle.d1 where s1 < 20 and time <= now() limit 1111111111111111111111"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); // expected to throw SQLParserException: Out of range. LIMIT <N>: N should be Int32. } @Test(expected = SQLParserException.class) public void testLimitNotPositive() { String sqlStr = "select * from root.vehicle.d1 where s1 < 20 and time <= now() limit 0"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); // expected to throw SQLParserException: LIMIT <N>: N should be greater than 0. } @@ -128,32 +128,32 @@ public class LogicalPlanSmallTest { public void testOffsetOutOfRange() { String sqlStr = "select * from root.vehicle.d1 where s1 < 20 and time <= now() " + "limit 1 offset 1111111111111111111111"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); // expected to throw SQLParserException: Out of range. OFFSET <OFFSETValue>: OFFSETValue should be Int32. } @Test(expected = ParseCancellationException.class) public void testOffsetNotPositive() { String sqlStr = "select * from root.vehicle.d1 where s1 < 20 and time <= now() limit 1 offset -1"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); // expected to throw SQLParserException: OFFSET <OFFSETValue>: OFFSETValue should >= 0. } @Test(expected = SQLParserException.class) public void testSlimitOutOfRange() { String sqlStr = "select * from root.vehicle.d1 where s1 < 20 and time <= now() slimit 1111111111111111111111"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); // expected to throw SQLParserException: Out of range. SLIMIT <SN>: SN should be Int32. } @Test(expected = SQLParserException.class) public void testSlimitNotPositive() { String sqlStr = "select * from root.vehicle.d1 where s1 < 20 and time <= now() slimit 0"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); // expected to throw SQLParserException: SLIMIT <SN>: SN should be greater than 0. } @@ -161,16 +161,16 @@ public class LogicalPlanSmallTest { public void testSoffsetOutOfRange() { String sqlStr = "select * from root.vehicle.d1 where s1 < 20 and time <= now() " + "slimit 1 soffset 1111111111111111111111"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); // expected to throw SQLParserException: Out of range. SOFFSET <SOFFSETValue>: SOFFSETValue should be Int32. } @Test public void testSoffsetNotPositive() { String sqlStr = "select * from root.vehicle.d1 where s1 < 20 and time <= now() slimit 1 soffset 1"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); Assert.assertEquals(1, ((QueryOperator) operator).getSeriesOffset()); Assert.assertEquals(1, ((QueryOperator) operator).getSeriesLimit()); } @@ -178,8 +178,8 @@ public class LogicalPlanSmallTest { @Test(expected = LogicalOptimizeException.class) public void testSoffsetExceedColumnNum() throws QueryProcessException { String sqlStr = "select s1 from root.vehicle.d1 where s1 < 20 and time <= now() slimit 2 soffset 1"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); IoTDB.metaManager.init(); ConcatPathOptimizer concatPathOptimizer = new ConcatPathOptimizer(); concatPathOptimizer.transform(operator, 1000); @@ -190,8 +190,8 @@ public class LogicalPlanSmallTest { @Test public void testDeleteStorageGroup() throws IllegalPathException { String sqlStr = "delete storage group root.vehicle.d1"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); Assert.assertEquals(DeleteStorageGroupOperator.class, operator.getClass()); PartialPath path = new PartialPath("root.vehicle.d1"); Assert.assertEquals(path, ((DeleteStorageGroupOperator) operator).getDeletePathList().get(0)); @@ -200,8 +200,8 @@ public class LogicalPlanSmallTest { @Test public void testDisableAlign() { String sqlStr = "select * from root.vehicle disable align"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); Assert.assertEquals(QueryOperator.class, operator.getClass()); Assert.assertFalse(((QueryOperator) operator).isAlignByTime()); } @@ -209,8 +209,8 @@ public class LogicalPlanSmallTest { @Test public void testNotDisableAlign() { String sqlStr = "select * from root.vehicle"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); Assert.assertEquals(QueryOperator.class, operator.getClass()); Assert.assertTrue(((QueryOperator) operator).isAlignByTime()); } @@ -218,21 +218,21 @@ public class LogicalPlanSmallTest { @Test(expected = ParseCancellationException.class) public void testDisableAlignConflictAlignByDevice() { String sqlStr = "select * from root.vehicle disable align align by device"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr, ZoneId.systemDefault()); } @Test public void testChineseCharacter() throws IllegalPathException { String sqlStr1 = "set storage group to root.一级"; - RootOperator operator = (RootOperator) parseDriver - .parse(sqlStr1, ZoneId.systemDefault()); + RootOperator operator = (RootOperator) logicalGenerator + .generate(sqlStr1, ZoneId.systemDefault()); Assert.assertEquals(SetStorageGroupOperator.class, operator.getClass()); Assert.assertEquals(new PartialPath("root.一级"), ((SetStorageGroupOperator) operator).getPath()); String sqlStr2 = "select * from root.一级.设备1 limit 10 offset 20"; - operator = (RootOperator) parseDriver - .parse(sqlStr2, ZoneId.systemDefault()); + operator = (RootOperator) logicalGenerator + .generate(sqlStr2, ZoneId.systemDefault()); Assert.assertEquals(QueryOperator.class, operator.getClass()); ArrayList<PartialPath> paths = new ArrayList<>(); paths.add(new PartialPath("*")); @@ -252,7 +252,7 @@ public class LogicalPlanSmallTest { + "FIRST_VALUE.SUM.LAST_VALUE.LAST.DISABLE.ALIGN.COMPRESSION.TIME.ATTRIBUTES.TAGS.RENAME.FULL.CLEAR.CACHE." + "SNAPSHOT.FOR.SCHEMA.TRACING.OFF where time>=1 and time < 3"; - Operator op = parseDriver.parse(sql, ZoneId.systemDefault()); + Operator op = logicalGenerator.generate(sql, ZoneId.systemDefault()); Assert.assertEquals(DeleteDataOperator.class, op.getClass()); } catch (ParseCancellationException ignored) { } @@ -261,7 +261,7 @@ public class LogicalPlanSmallTest { @Test public void testRangeDelete() throws IllegalPathException { String sql1 = "delete from root.d1.s1 where time>=1 and time < 3"; - Operator op = parseDriver.parse(sql1, ZoneId.systemDefault()); + Operator op = logicalGenerator.generate(sql1, ZoneId.systemDefault()); Assert.assertEquals(DeleteDataOperator.class, op.getClass()); ArrayList<PartialPath> paths = new ArrayList<>(); paths.add(new PartialPath("root.d1.s1")); @@ -270,37 +270,37 @@ public class LogicalPlanSmallTest { Assert.assertEquals(2, ((DeleteDataOperator) op).getEndTime()); String sql2 = "delete from root.d1.s1 where time>=1"; - op = parseDriver.parse(sql2, ZoneId.systemDefault()); + op = logicalGenerator.generate(sql2, ZoneId.systemDefault()); Assert.assertEquals(paths, ((DeleteDataOperator) op).getSelectedPaths()); Assert.assertEquals(1, ((DeleteDataOperator) op).getStartTime()); Assert.assertEquals(Long.MAX_VALUE, ((DeleteDataOperator) op).getEndTime()); String sql3 = "delete from root.d1.s1 where time>1"; - op = parseDriver.parse(sql3, ZoneId.systemDefault()); + op = logicalGenerator.generate(sql3, ZoneId.systemDefault()); Assert.assertEquals(paths, ((DeleteDataOperator) op).getSelectedPaths()); Assert.assertEquals(2, ((DeleteDataOperator) op).getStartTime()); Assert.assertEquals(Long.MAX_VALUE, ((DeleteDataOperator) op).getEndTime()); String sql4 = "delete from root.d1.s1 where time <= 1"; - op = parseDriver.parse(sql4, ZoneId.systemDefault()); + op = logicalGenerator.generate(sql4, ZoneId.systemDefault()); Assert.assertEquals(paths, ((DeleteDataOperator) op).getSelectedPaths()); Assert.assertEquals(Long.MIN_VALUE, ((DeleteDataOperator) op).getStartTime()); Assert.assertEquals(1, ((DeleteDataOperator) op).getEndTime()); String sql5 = "delete from root.d1.s1 where time<1"; - op = parseDriver.parse(sql5, ZoneId.systemDefault()); + op = logicalGenerator.generate(sql5, ZoneId.systemDefault()); Assert.assertEquals(paths, ((DeleteDataOperator) op).getSelectedPaths()); Assert.assertEquals(Long.MIN_VALUE, ((DeleteDataOperator) op).getStartTime()); Assert.assertEquals(0, ((DeleteDataOperator) op).getEndTime()); String sql6 = "delete from root.d1.s1 where time = 3"; - op = parseDriver.parse(sql6, ZoneId.systemDefault()); + op = logicalGenerator.generate(sql6, ZoneId.systemDefault()); Assert.assertEquals(paths, ((DeleteDataOperator) op).getSelectedPaths()); Assert.assertEquals(3, ((DeleteDataOperator) op).getStartTime()); Assert.assertEquals(3, ((DeleteDataOperator) op).getEndTime()); String sql7 = "delete from root.d1.s1 where time > 5 and time >= 2"; - op = parseDriver.parse(sql7, ZoneId.systemDefault()); + op = logicalGenerator.generate(sql7, ZoneId.systemDefault()); Assert.assertEquals(paths, ((DeleteDataOperator) op).getSelectedPaths()); Assert.assertEquals(6, ((DeleteDataOperator) op).getStartTime()); Assert.assertEquals(Long.MAX_VALUE, ((DeleteDataOperator) op).getEndTime()); @@ -311,7 +311,7 @@ public class LogicalPlanSmallTest { String sql = "delete from root.d1.s1 where time>=1 and time < 3 or time >1"; String errorMsg = null; try { - parseDriver.parse(sql, ZoneId.systemDefault()); + logicalGenerator.generate(sql, ZoneId.systemDefault()); } catch (SQLParserException e) { errorMsg = e.getMessage(); } @@ -323,7 +323,7 @@ public class LogicalPlanSmallTest { sql = "delete from root.d1.s1 where time>=1 or time < 3"; errorMsg = null; try { - parseDriver.parse(sql, ZoneId.systemDefault()); + logicalGenerator.generate(sql, ZoneId.systemDefault()); } catch (SQLParserException e) { errorMsg = e.getMessage(); } @@ -335,7 +335,7 @@ public class LogicalPlanSmallTest { String sql7 = "delete from root.d1.s1 where time = 1 and time < -1"; errorMsg = null; try { - parseDriver.parse(sql7, ZoneId.systemDefault()); + logicalGenerator.generate(sql7, ZoneId.systemDefault()); } catch (RuntimeException e) { errorMsg = e.getMessage(); } @@ -344,7 +344,7 @@ public class LogicalPlanSmallTest { sql = "delete from root.d1.s1 where time > 5 and time <= 0"; errorMsg = null; try { - parseDriver.parse(sql, ZoneId.systemDefault()); + logicalGenerator.generate(sql, ZoneId.systemDefault()); } catch (SQLParserException e) { errorMsg = e.getMessage(); }
