jt2594838 commented on a change in pull request #366: upgrade from antlr3 to 
antlr4
URL: https://github.com/apache/incubator-iotdb/pull/366#discussion_r319944961
 
 

 ##########
 File path: 
server/src/main/java/org/apache/iotdb/db/qp/strategy/ExecuteSqlVisitor.java
 ##########
 @@ -0,0 +1,1288 @@
+/**
+ * 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.qp.strategy;
+
+import main.antlr4.org.apache.iotdb.db.sql.parse.TSParser;
+import main.antlr4.org.apache.iotdb.db.sql.parse.TSParserBaseVisitor;
+import org.antlr.v4.runtime.tree.TerminalNode;
+import org.apache.iotdb.db.exception.qp.IllegalASTFormatException;
+import org.apache.iotdb.db.exception.qp.LogicalOperatorException;
+import org.apache.iotdb.db.qp.constant.DatetimeUtils;
+import org.apache.iotdb.db.qp.constant.SQLConstant;
+import org.apache.iotdb.db.qp.constant.TSParserConstant;
+import org.apache.iotdb.db.qp.logical.RootOperator;
+import org.apache.iotdb.db.qp.logical.crud.*;
+import org.apache.iotdb.db.qp.logical.sys.AuthorOperator;
+import org.apache.iotdb.db.qp.logical.sys.LoadDataOperator;
+import org.apache.iotdb.db.qp.logical.sys.MetadataOperator;
+import org.apache.iotdb.db.qp.logical.sys.PropertyOperator;
+import org.apache.iotdb.db.query.fill.IFill;
+import org.apache.iotdb.db.query.fill.LinearFill;
+import org.apache.iotdb.db.query.fill.PreviousFill;
+import org.apache.iotdb.db.sql.parse.SqlParseException;
+import org.apache.iotdb.tsfile.common.conf.TSFileConfig;
+import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
+import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.iotdb.tsfile.read.common.Path;
+import org.apache.iotdb.tsfile.utils.Pair;
+import org.apache.iotdb.tsfile.utils.StringContainer;
+
+import java.time.ZoneId;
+import java.util.*;
+
+import static org.apache.iotdb.db.qp.constant.SQLConstant.*;
+
+public class ExecuteSqlVisitor extends TSParserBaseVisitor {
+  private static final String ERR_INCORRECT_AUTHOR_COMMAND = "illegal ast tree 
in grant author "
+          + "command, please check you SQL statement";
+
+  private RootOperator initializedOperator = null;
+  private SelectOperator selectOp;
+  private FilterOperator whereOp;
+  private ZoneId zoneId;
+  private Map<TSDataType, IFill> fillTypes;
+  private TSDataType fillClauseDataType;
+  private Path whereSeriesPath;
+
+  private boolean isAndWhereClause = false;
+  private boolean isOrWhereClause = false;
+  private boolean isNotWhereClause = false;
+
+  public ExecuteSqlVisitor(ZoneId zoneId) {
+    this.zoneId = zoneId;
+  }
+
+
+  @Override
+  public Object visitStatement(TSParser.StatementContext ctx) {
+    return visit(ctx.execStatement());
+  }
+
+  @Override
+  public RootOperator visitQueryStatement(TSParser.QueryStatementContext ctx) {
+    initializedOperator = new QueryOperator(SQLConstant.TOK_QUERY);
+    visit(ctx.selectClause());
+    if (ctx.whereClause() != null) {
+      visit(ctx.whereClause());
+    }
+    if (ctx.specialClause() != null) {
+
+      visit(ctx.specialClause());
+    }
+    return initializedOperator;
+  }
+
+  @Override
+  public Object visitX_positiveFloat(TSParser.X_positiveFloatContext ctx) {
+    return ctx.PositiveFloat().getText();
+  }
+
+  @Override
+  public Object visitX_negativeInteger(TSParser.X_negativeIntegerContext ctx) {
+    return ctx.NegativeFloat().getText();
+  }
+
+  @Override
+  public Object visitX_positiveIntegerDot(TSParser.X_positiveIntegerDotContext 
ctx) {
+    return ctx.PositiveInteger().getText();
+  }
+
+  @Override
+  public Object visitX_negativeIntegerDot(TSParser.X_negativeIntegerDotContext 
ctx) {
+    return ctx.NegativeInteger().getText();
+  }
+
+  @Override
+  public Object 
visitX_unsignedIntegerDotUnsignedInteger(TSParser.X_unsignedIntegerDotUnsignedIntegerContext
 ctx) {
+    return ctx.getText();
+  }
+
+  @Override
+  public Object visitX_unsignedIntegerDot(TSParser.X_unsignedIntegerDotContext 
ctx) {
+    return ctx.UnsignedInteger().getText();
+  }
+
+  @Override
+  public Object visitX_dotUnsignedInteger(TSParser.X_dotUnsignedIntegerContext 
ctx) {
+    return ctx.getText();
+  }
+
+  @Override
+  public Object 
visitX_unsignedIntegerDoubleInScientificNotationSuffix(TSParser.X_unsignedIntegerDoubleInScientificNotationSuffixContext
 ctx) {
+    return ctx.getText();
+  }
+
+  @Override
+  public Object 
visitX_doubleInScientificNotationSuffix(TSParser.X_doubleInScientificNotationSuffixContext
 ctx) {
+    return ctx.getText();
+  }
+
+
+  @Override
+  public Object visitIntegerString(TSParser.IntegerStringContext ctx) {
+    return ctx.integer().getText();
+  }
+
+  @Override
+  public Object visitFloatString(TSParser.FloatStringContext ctx) {
+    return visit(ctx.floatValue());
+  }
+
+  @Override
+  public Object visitBooleanString(TSParser.BooleanStringContext ctx) {
+    return ctx.getText();
+  }
+
+  @Override
+  public RootOperator visitInsertStatement(TSParser.InsertStatementContext 
ctx) {
+    InsertOperator insertOp = new InsertOperator(SQLConstant.TOK_INSERT);
+    initializedOperator = insertOp;
+
+    // set select path
+    Path selectPath = parsePrefixPath(ctx.prefixPath());
+    selectOp = new SelectOperator(SQLConstant.TOK_SELECT);
+    selectOp.addSelectPath(selectPath);
+    ((SFWOperator) initializedOperator).setSelectOperator(selectOp);
+
+    // set time
+    long timestamp = (long) visit(ctx.multiValue().time);
+    insertOp.setTime(timestamp);
+
+    // set measurement list
+    String[] measurementList = new 
String[ctx.multidentifier().identifier().size()];
+    for (int i = 0; i < measurementList.length; i++) {
+      measurementList[i] = ctx.multidentifier().identifier(i).getText();
+    }
+    insertOp.setMeasurementList(measurementList);
+
+    // set value list
+    String[] valueList = new 
String[ctx.multiValue().numberOrStringWidely().size()];
+    for (int i = 0; i < valueList.length; i++) {
+      valueList[i] = ctx.multiValue().numberOrStringWidely(i).getText();
+    }
+    insertOp.setValueList(valueList);
+
+    return initializedOperator;
+  }
+
+  public long parseTimeFormat(String timestampStr) {
+    if (timestampStr == null || timestampStr.trim().equals("")) {
+      throw new SqlParseException("input timestamp cannot be empty");
+    }
+    if (timestampStr.equalsIgnoreCase(SQLConstant.NOW_FUNC)) {
+      return System.currentTimeMillis();
+    }
+    try {
+      return DatetimeUtils.convertDatetimeStrToLong(timestampStr, zoneId);
+    } catch (Exception e) {
+      throw new SqlParseException(String
+              .format("Input time format %s error. "
+                      + "Input like yyyy-MM-dd HH:mm:ss, yyyy-MM-ddTHH:mm:ss 
or "
+                      + "refer to user document for more info.", 
timestampStr));
+    }
+  }
+
+
+  @Override
+  public Object visitSelectIndex(TSParser.SelectIndexContext ctx) {
+    throw new SqlParseException("Not supported TSParser type SELECT_INDEX");
+  }
+
+  @Override
+  public Object visitSelectSimple(TSParser.SelectSimpleContext ctx) {
+    selectOp = new SelectOperator(SQLConstant.TOK_SELECT);
+    for (TSParser.ClusteredPathContext cp : ctx.clusteredPath()) {
+      visit(cp);
+    }
+    visit(ctx.fromClause());
+    ((SFWOperator) initializedOperator).setSelectOperator(selectOp);
+    return initializedOperator;
+  }
+
+  @Override
+  public Object visitClusteredCommandPath(TSParser.ClusteredCommandPathContext 
ctx) {
+    Path path = parseSuffixPath(ctx.suffixPath());
+    String aggregation = ctx.identifier().getText();
+    selectOp.addClusterPath(path, aggregation);
+    return selectOp;
+  }
+
+  @Override
+  public Object visitSimpleSuffixPath(TSParser.SimpleSuffixPathContext ctx) {
+    Path path = parseSuffixPath(ctx.suffixPath());
+    selectOp.addSelectPath(path);
+    return selectOp;
+  }
+
+  @Override
+  public Object visitFromClause(TSParser.FromClauseContext ctx) {
+    FromOperator from = new FromOperator(SQLConstant.TOK_FROM);
+    for (TSParser.PrefixPathContext prefixPathContext : ctx.prefixPath()) {
+      Path path = parsePrefixPath(prefixPathContext);
+      from.addPrefixTablePath(path);
+    }
+    ((SFWOperator) initializedOperator).setFromOperator(from);
+    return initializedOperator;
+  }
+
+  @Override
+  public Object visitWhereClause(TSParser.WhereClauseContext ctx) {
+    whereOp = new FilterOperator(SQLConstant.TOK_WHERE);
+    visit(ctx.searchCondition());
+    ((SFWOperator) 
initializedOperator).setFilterOperator(whereOp.getChildren().get(0));
+    return initializedOperator;
+  }
+
+  @Override
+  public Object visitSearchCondition(TSParser.SearchConditionContext ctx) {
+    return visit(ctx.expression());
+  }
+
+  @Override
+  public Object visitExpression(TSParser.ExpressionContext ctx) {
+    return visit(ctx.precedenceOrExpression());
+  }
+
+  @Override
+  public Object 
visitPrecedenceOrExpression(TSParser.PrecedenceOrExpressionContext ctx) {
+    if (ctx.precedenceAndExpression().size() == 1) {
+      isOrWhereClause = false;
+      return visit(ctx.precedenceAndExpression(0));
+    }
+    isOrWhereClause = true;
+
+    FilterOperator binaryOp = new FilterOperator(
+            TSParserConstant.getTSTokenIntType(TSParser.KW_OR));
+    int size = ctx.precedenceAndExpression().size();
+    if (size > 2) {
+
+      binaryOp.addChildOperator((FilterOperator) 
visit(ctx.precedenceAndExpression(0)));
+      binaryOp.addChildOperator((FilterOperator) 
visit(ctx.precedenceAndExpression(1)));
+      for (int i = 2; i < size; i++) {
+        FilterOperator op = new 
FilterOperator(TSParserConstant.getTSTokenIntType(TSParser.KW_OR));
+        op.addChildOperator(binaryOp);
+        op.addChildOperator((FilterOperator) 
visit(ctx.precedenceAndExpression(i)));
+        binaryOp = op;
+      }
+    } else {
+      for (TSParser.PrecedenceAndExpressionContext 
precedenceAndExpressionContext : ctx.precedenceAndExpression()) {
+        binaryOp.addChildOperator((FilterOperator) 
visit(precedenceAndExpressionContext));
+      }
+    }
+    whereOp.addChildOperator(binaryOp);
+    return binaryOp;
+  }
+
+
+  @Override
+  public Object 
visitPrecedenceAndExpression(TSParser.PrecedenceAndExpressionContext ctx) {
+
+    if (ctx.precedenceNotExpression().size() == 1) {
+      isAndWhereClause = false;
+      return visit(ctx.precedenceNotExpression(0));
+    }
+    isAndWhereClause = true;
+    FilterOperator binaryOp = new FilterOperator(
+            TSParserConstant.getTSTokenIntType(TSParser.KW_AND));
+    int size = ctx.precedenceNotExpression().size();
+    if (size > 2) {
+
+      binaryOp.addChildOperator((FilterOperator) 
visit(ctx.precedenceNotExpression(0)));
+      binaryOp.addChildOperator((FilterOperator) 
visit(ctx.precedenceNotExpression(1)));
+
+      for (int i = 2; i < size; i++) {
+        FilterOperator op = new FilterOperator(
+                TSParserConstant.getTSTokenIntType(TSParser.KW_AND));
+        op.addChildOperator(binaryOp);
+        op.addChildOperator((FilterOperator) 
visit(ctx.precedenceNotExpression(i)));
+        binaryOp = op;
+      }
+
+    } else {
+      for (TSParser.PrecedenceNotExpressionContext 
precedenceNotExpressionContext : ctx.precedenceNotExpression()) {
+        binaryOp.addChildOperator((FilterOperator) 
visit(precedenceNotExpressionContext));
+      }
+    }
+    if (!isOrWhereClause) {
+      whereOp.addChildOperator(binaryOp);
+    }
+    return binaryOp;
+  }
+
+  @Override
+  public Object visitWithNot(TSParser.WithNotContext ctx) {
+    isNotWhereClause = true;
+    FilterOperator notOp = new FilterOperator(SQLConstant.KW_NOT);
+    if (!isAndWhereClause) {
+      whereOp.addChildOperator(notOp);
+    }
+    notOp.addChildOperator((FilterOperator) 
visit(ctx.precedenceNotExpression()));
+    return notOp;
+  }
+
+  @Override
+  public Object visitWithoutNot(TSParser.WithoutNotContext ctx) {
+    return visit(ctx.precedenceEqualExpressionSingle());
+  }
+
+  @Override
+  public Object visitSlimitClause(TSParser.SlimitClauseContext ctx) {
+    int seriesLimit;
+    try {
+      seriesLimit = 
Integer.parseInt(ctx.nonNegativeInteger().getText().trim());
+    } catch (NumberFormatException e) {
+      throw new SqlParseException("SLIMIT <SN>: SN should be Int32.");
+    }
+    if (seriesLimit <= 0) {
+      // seriesLimit is ensured to be a non negative integer after the lexical 
examination,
+      // and seriesLimit is further required to be a positive integer here.
+      throw new SqlParseException(
+              "SLIMIT <SN>: SN must be a positive integer and can not be 
zero.");
+    }
+    if (ctx.soffsetClause() != null) {
+      visit(ctx.soffsetClause());
+    }
+    ((QueryOperator) initializedOperator).setSeriesLimit(seriesLimit);
+    return initializedOperator;
+  }
+
+  @Override
+  public Object visitSoffsetClause(TSParser.SoffsetClauseContext ctx) {
+    try {
+      ((QueryOperator) initializedOperator)
+              
.setSeriesOffset(Integer.parseInt(ctx.nonNegativeInteger().getText().trim()));
+    } catch (NumberFormatException e) {
+      throw new SqlParseException("SOFFSET <SOFFSETValue>: SOFFSETValue should 
be Int32.");
+    }
+    return initializedOperator;
+  }
+
+
+  @Override
+  public Object visitLimitClause(TSParser.LimitClauseContext ctx) {
+    int rowsLimit;
+    try {
+      rowsLimit = Integer.parseInt(ctx.nonNegativeInteger().getText().trim());
+    } catch (NumberFormatException e) {
+      throw new SqlParseException("LIMIT <N>: N should be Int32.");
+    }
+    if (rowsLimit <= 0) {
+//      // seriesLimit is ensured to be a non negative integer after the 
lexical examination,
+//      // and seriesLimit is further required to be a positive integer here.
+      throw new SqlParseException(
+              "LIMIT <N>: N must be a positive integer and can not be zero.");
+    }
+    if (ctx.offsetClause() != null) {
+      visit(ctx.offsetClause());
+    }
+    return initializedOperator;
+  }
+
+  @Override
+  public Object visitOffsetClause(TSParser.OffsetClauseContext ctx) {
+//    throw new SqlParseException("Not supported TSParser type KW_OFFSET");
+    return null;
+  }
+
+  @Override
+  public Object visitGroupbyClause(TSParser.GroupbyClauseContext ctx) {
+    selectOp = ((QueryOperator) initializedOperator).getSelectOperator();
+    if (selectOp.getSuffixPaths().size() != selectOp.getAggregations().size()) 
{
+      throw new SqlParseException(
+              "Group by must bind each seriesPath with an aggregation 
function");
+    }
+    ((QueryOperator) initializedOperator).setGroupBy(true);
+    long value = parseTimeUnit(ctx.value.getText(), ctx.unit.getText());
+    ((QueryOperator) initializedOperator).setUnit(value);
+
+    List<Pair<Long, Long>> intervals = new ArrayList<>();
+    for (TSParser.TimeIntervalContext interval : ctx.timeInterval()) {
+      intervals.add((Pair<Long, Long>) visit(interval));
+    }
+    ((QueryOperator) initializedOperator).setIntervals(intervals);
+
+    long originTime = 0;
+    if (ctx.timeOrigin == null) {
+      originTime = parseTimeFormat(SQLConstant.START_TIME_STR);
+    } else {
+      originTime = (long) visit(ctx.timeOrigin);
+    }
+    ((QueryOperator) initializedOperator).setOrigin(originTime);
+    return initializedOperator;
+  }
+
+  @Override
+  public Object visitTimeInterval(TSParser.TimeIntervalContext ctx) {
+    long startTime = (long) visit(ctx.dateFormatWithNumber(0));
+    long endTime = (long) visit(ctx.dateFormatWithNumber(1));
+    return new Pair<>(startTime, endTime);
+  }
+
+  @Override
+  public Long 
visitGetDateTimeFromDateFormat(TSParser.GetDateTimeFromDateFormatContext ctx) {
+    return parseTimeFormat((String) visit(ctx.dateFormat()));
+  }
+
+
+  @Override
+  public String visitGetDateTime(TSParser.GetDateTimeContext ctx) {
+    return ctx.DATETIME().getText();
+  }
+
+  @Override
+  public String visitGetIdentifier(TSParser.GetIdentifierContext ctx) {
+    return ctx.Identifier().getText();
+  }
+
+  @Override
+  public Object visitFillClause(TSParser.FillClauseContext ctx) {
+    FilterOperator filterOperator = ((SFWOperator) 
initializedOperator).getFilterOperator();
+    fillTypes = new EnumMap<>(TSDataType.class);
+    for (TSParser.TypeClauseContext typeClauseContext : ctx.typeClause()) {
+      try {
+        fillClauseDataType = 
parseType(typeClauseContext.Identifier().getText());
+        visit(typeClauseContext.interTypeClause());
+      } catch (LogicalOperatorException e) {
+        e.printStackTrace();
+      }
+    }
+    ((QueryOperator) initializedOperator).setFillTypes(fillTypes);
+    ((QueryOperator) initializedOperator).setFill(true);
+    return initializedOperator;
+  }
+
+//  "select sensor1 from root.vehicle.device1 where time = 50 
Fill(int32[linear, 5m, 5m], boolean[previous, 5m])"
+
+  @Override
+  public Object visitLinear(TSParser.LinearContext ctx) {
+    if (fillClauseDataType == TSDataType.BOOLEAN || fillClauseDataType == 
TSDataType.TEXT) {
+      throw new SqlParseException(String.format("type %s cannot use %s fill 
function", fillClauseDataType,
+              "KW_LINEAR"));
+    }
+    if (!ctx.integer().isEmpty()) {
+      long beforeRange = 0;
+      long afterRange = 0;
+      beforeRange = parseTimeUnit(ctx.value1.getText(), ctx.unit1.getText());
+      afterRange = parseTimeUnit(ctx.value2.getText(), ctx.unit2.getText());
+      fillTypes.put(fillClauseDataType, new LinearFill(beforeRange, 
afterRange));
+    } else {
+      fillTypes.put(fillClauseDataType, new LinearFill(-1, -1));
+    }
+    return initializedOperator;
+  }
+
+  @Override
+  public Object visitPrevious(TSParser.PreviousContext ctx) {
+    if (ctx.value1 != null) {
+      long preRange = parseTimeUnit(ctx.value1.getText(), ctx.unit1.getText());
+      fillTypes.put(fillClauseDataType, new PreviousFill(preRange));
+    } else {
+      fillTypes.put(fillClauseDataType, new PreviousFill(-1));
+    }
+    return initializedOperator;
+  }
+
+  private long parseTimeUnit(String time, String unit) {
+    long timeInterval = Long.parseLong(time);
+    if (timeInterval <= 0) {
+      throw new SqlParseException("Interval must more than 0.");
+    }
+    switch (unit) {
 
 Review comment:
   Optional: add toLowerCase() to increase usability.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to