This is an automated email from the ASF dual-hosted git repository.

jackietien pushed a commit to branch ty/groupByTimeParser
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit cde52a00fc23104dfe8e7fa5488e77224a62f54b
Author: JackieTien97 <[email protected]>
AuthorDate: Fri Jun 14 17:15:30 2024 +0800

    Support for group by time sql paser
---
 .../protocol/thrift/impl/ClientRPCServiceImpl.java |   2 +-
 .../db/queryengine/plan/parser/ASTVisitor.java     |   8 +-
 .../plan/relational/metadata/MetadataUtil.java     |   2 +-
 .../plan/relational/sql/ast/AstVisitor.java        |   4 +
 .../plan/relational/sql/ast/GroupByTime.java       | 145 ++++++++++++++++
 .../plan/relational/sql/ast/SimpleGroupBy.java     |   2 +-
 .../sql/ast/{SimpleGroupBy.java => TimeRange.java} |  74 +++++----
 .../plan/relational/sql/parser/AstBuilder.java     | 183 ++++++++++++++-------
 .../plan/relational/sql/parser/SqlParser.java      |  52 +++---
 .../relational/sql/util/ReservedIdentifiers.java   |   3 +-
 .../org/apache/iotdb/db/utils/DateTimeUtils.java   |  64 +++++--
 .../plan/relational/analyzer/AnalyzerTest.java     |   2 +-
 .../db/relational/grammar/sql/RelationalSql.g4     |  56 +++++--
 13 files changed, 444 insertions(+), 153 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java
index b66b2dd4f35..9829d41513b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java
@@ -336,7 +336,7 @@ public class ClientRPCServiceImpl implements 
IClientRPCServiceWithHandler {
                 req.getTimeout());
       } else {
         org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Statement s =
-            relationSqlParser.createStatement(statement);
+            relationSqlParser.createStatement(statement, 
clientSession.getZoneId());
 
         if (s == null) {
           return RpcUtils.getTSExecuteStatementResp(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
index 261f3bb7ed9..24413ba8c50 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
@@ -2157,8 +2157,8 @@ public class ASTVisitor extends 
IoTDBSqlParserBaseVisitor<Statement> {
     }
   }
 
-  public long parseDateTimeFormat(String timestampStr, long currentTime) {
-    if (timestampStr == null || "".equals(timestampStr.trim())) {
+  public static long parseDateTimeFormat(String timestampStr, long 
currentTime, ZoneId zoneId) {
+    if (timestampStr == null || timestampStr.trim().isEmpty()) {
       throw new SemanticException("input timestamp cannot be empty");
     }
     if (timestampStr.equalsIgnoreCase(SqlConstant.NOW_FUNC)) {
@@ -3137,7 +3137,7 @@ public class ASTVisitor extends 
IoTDBSqlParserBaseVisitor<Statement> {
 
   private Long parseDateExpression(IoTDBSqlParser.DateExpressionContext ctx, 
long currentTime) {
     long time;
-    time = parseDateTimeFormat(ctx.getChild(0).getText(), currentTime);
+    time = parseDateTimeFormat(ctx.getChild(0).getText(), currentTime, zoneId);
     for (int i = 1; i < ctx.getChildCount(); i = i + 2) {
       if ("+".equals(ctx.getChild(i).getText())) {
         time += DateTimeUtils.convertDurationStrToLong(time, ctx.getChild(i + 
1).getText(), false);
@@ -3162,7 +3162,7 @@ public class ASTVisitor extends 
IoTDBSqlParserBaseVisitor<Statement> {
     } else if (ctx.dateExpression() != null) {
       return parseDateExpression(ctx.dateExpression(), currentTime);
     } else {
-      return parseDateTimeFormat(ctx.datetimeLiteral().getText(), currentTime);
+      return parseDateTimeFormat(ctx.datetimeLiteral().getText(), currentTime, 
zoneId);
     }
   }
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/MetadataUtil.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/MetadataUtil.java
index d625807b57e..b97141817b0 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/MetadataUtil.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/MetadataUtil.java
@@ -84,7 +84,7 @@ public class MetadataUtil {
                 .orElseThrow(
                     () ->
                         new SemanticException(
-                            "Catalog must be specified when session catalog is 
not set"));
+                            "Database must be specified when session database 
is not set"));
 
     return new QualifiedObjectName(databaseName, objectName);
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java
index d2c1e487458..fa590cfca61 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java
@@ -391,6 +391,10 @@ public abstract class AstVisitor<R, C> {
     return visitNode(node, context);
   }
 
+  protected R visitGroupByTime(GroupByTime node, C context) {
+    return visitGroupingElement(node, context);
+  }
+
   protected R visitGroupingSets(GroupingSets node, C context) {
     return visitGroupingElement(node, context);
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/GroupByTime.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/GroupByTime.java
new file mode 100644
index 00000000000..2d4068e6c27
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/GroupByTime.java
@@ -0,0 +1,145 @@
+/*
+ * 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.queryengine.plan.relational.sql.ast;
+
+import org.apache.tsfile.utils.TimeDuration;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+public class GroupByTime extends GroupingElement {
+
+  // [startTime, endTime)
+  private final long startTime;
+  private final long endTime;
+  // time interval
+  private final TimeDuration interval;
+  // sliding step
+  private final TimeDuration slidingStep;
+  // if it is left close and right open interval
+  private final boolean leftCRightO;
+
+  public GroupByTime(
+      long startTime,
+      long endTime,
+      TimeDuration interval,
+      TimeDuration slidingStep,
+      boolean leftCRightO) {
+    super(null);
+    this.startTime = startTime;
+    this.endTime = endTime;
+    this.interval = interval;
+    this.slidingStep = slidingStep;
+    this.leftCRightO = leftCRightO;
+  }
+
+  public GroupByTime(
+      NodeLocation location,
+      long startTime,
+      long endTime,
+      TimeDuration interval,
+      TimeDuration slidingStep,
+      boolean leftCRightO) {
+    super(location);
+    this.startTime = startTime;
+    this.endTime = endTime;
+    this.interval = interval;
+    this.slidingStep = slidingStep;
+    this.leftCRightO = leftCRightO;
+  }
+
+  @Override
+  public List<Expression> getExpressions() {
+    return Collections.emptyList();
+  }
+
+  @Override
+  protected <R, C> R accept(AstVisitor<R, C> visitor, C context) {
+    return visitor.visitGroupByTime(this, context);
+  }
+
+  @Override
+  public List<? extends Node> getChildren() {
+    return Collections.emptyList();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    GroupByTime that = (GroupByTime) o;
+    return startTime == that.startTime
+        && endTime == that.endTime
+        && leftCRightO == that.leftCRightO
+        && Objects.equals(interval, that.interval)
+        && Objects.equals(slidingStep, that.slidingStep);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(startTime, endTime, interval, slidingStep, 
leftCRightO);
+  }
+
+  @Override
+  public String toString() {
+    return "GroupByTime{"
+        + "startTime="
+        + startTime
+        + ", endTime="
+        + endTime
+        + ", interval="
+        + interval
+        + ", slidingStep="
+        + slidingStep
+        + ", leftCRightO="
+        + leftCRightO
+        + '}';
+  }
+
+  @Override
+  public boolean shallowEquals(Node other) {
+    return sameClass(this, other);
+  }
+
+  public long getStartTime() {
+    return startTime;
+  }
+
+  public long getEndTime() {
+    return endTime;
+  }
+
+  public TimeDuration getInterval() {
+    return interval;
+  }
+
+  public TimeDuration getSlidingStep() {
+    return slidingStep;
+  }
+
+  public boolean isLeftCRightO() {
+    return leftCRightO;
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/SimpleGroupBy.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/SimpleGroupBy.java
index 88193960f7d..88b80a6072b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/SimpleGroupBy.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/SimpleGroupBy.java
@@ -57,7 +57,7 @@ public final class SimpleGroupBy extends GroupingElement {
 
   @Override
   public List<? extends Node> getChildren() {
-    return columns;
+    return getExpressions();
   }
 
   @Override
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/SimpleGroupBy.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/TimeRange.java
similarity index 50%
copy from 
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/SimpleGroupBy.java
copy to 
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/TimeRange.java
index 88193960f7d..c1fe213ff14 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/SimpleGroupBy.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/TimeRange.java
@@ -19,45 +19,35 @@
 
 package org.apache.iotdb.db.queryengine.plan.relational.sql.ast;
 
-import com.google.common.collect.ImmutableList;
-
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
-import static com.google.common.base.MoreObjects.toStringHelper;
-import static java.util.Objects.requireNonNull;
-
-public final class SimpleGroupBy extends GroupingElement {
+public class TimeRange extends Node {
 
-  private final List<Expression> columns;
+  // [startTime, endTime)
+  private final long startTime;
+  private final long endTime;
+  // if it is left close and right open interval
+  private final boolean leftCRightO;
 
-  public SimpleGroupBy(List<Expression> simpleGroupByExpressions) {
+  public TimeRange(long startTime, long endTime, boolean leftCRightO) {
     super(null);
-    this.columns =
-        ImmutableList.copyOf(
-            requireNonNull(simpleGroupByExpressions, "simpleGroupByExpressions 
is null"));
+    this.startTime = startTime;
+    this.endTime = endTime;
+    this.leftCRightO = leftCRightO;
   }
 
-  public SimpleGroupBy(NodeLocation location, List<Expression> 
simpleGroupByExpressions) {
-    super(requireNonNull(location, "location is null"));
-    this.columns =
-        ImmutableList.copyOf(
-            requireNonNull(simpleGroupByExpressions, "simpleGroupByExpressions 
is null"));
-  }
-
-  @Override
-  public List<Expression> getExpressions() {
-    return columns;
-  }
-
-  @Override
-  protected <R, C> R accept(AstVisitor<R, C> visitor, C context) {
-    return visitor.visitSimpleGroupBy(this, context);
+  public TimeRange(NodeLocation location, long startTime, long endTime, 
boolean leftCRightO) {
+    super(location);
+    this.startTime = startTime;
+    this.endTime = endTime;
+    this.leftCRightO = leftCRightO;
   }
 
   @Override
   public List<? extends Node> getChildren() {
-    return columns;
+    return Collections.emptyList();
   }
 
   @Override
@@ -68,22 +58,38 @@ public final class SimpleGroupBy extends GroupingElement {
     if (o == null || getClass() != o.getClass()) {
       return false;
     }
-    SimpleGroupBy that = (SimpleGroupBy) o;
-    return Objects.equals(columns, that.columns);
+    TimeRange timeRange = (TimeRange) o;
+    return startTime == timeRange.startTime
+        && endTime == timeRange.endTime
+        && leftCRightO == timeRange.leftCRightO;
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(columns);
+    return Objects.hash(startTime, endTime, leftCRightO);
   }
 
   @Override
   public String toString() {
-    return toStringHelper(this).add("columns", columns).toString();
+    return "TimeRange{"
+        + "startTime="
+        + startTime
+        + ", endTime="
+        + endTime
+        + ", leftCRightO="
+        + leftCRightO
+        + '}';
   }
 
-  @Override
-  public boolean shallowEquals(Node other) {
-    return sameClass(this, other);
+  public long getStartTime() {
+    return startTime;
+  }
+
+  public long getEndTime() {
+    return endTime;
+  }
+
+  public boolean isLeftCRightO() {
+    return leftCRightO;
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
index 52fa55f87be..f50fb72866d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
@@ -20,6 +20,8 @@
 package org.apache.iotdb.db.queryengine.plan.relational.sql.parser;
 
 import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
+import org.apache.iotdb.commons.utils.CommonDateTimeUtils;
+import org.apache.iotdb.db.exception.sql.SemanticException;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AddColumn;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AliasedRelation;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AllColumns;
@@ -56,6 +58,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.FunctionCall;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.GenericDataType;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.GroupBy;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.GroupByTime;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.GroupingElement;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.GroupingSets;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Identifier;
@@ -110,6 +113,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.StringLiteral;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SubqueryExpression;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Table;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.TableSubquery;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.TimeRange;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Trim;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.TypeParameter;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Union;
@@ -123,15 +127,18 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.WithQuery;
 import org.apache.iotdb.db.relational.grammar.sql.RelationalSqlBaseVisitor;
 import org.apache.iotdb.db.relational.grammar.sql.RelationalSqlLexer;
 import org.apache.iotdb.db.relational.grammar.sql.RelationalSqlParser;
+import org.apache.iotdb.db.utils.DateTimeUtils;
 
 import com.google.common.collect.ImmutableList;
 import org.antlr.v4.runtime.ParserRuleContext;
 import org.antlr.v4.runtime.Token;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.antlr.v4.runtime.tree.TerminalNode;
+import org.apache.tsfile.utils.TimeDuration;
 
 import javax.annotation.Nullable;
 
+import java.time.ZoneId;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Deque;
@@ -147,6 +154,7 @@ import static 
org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory
 import static 
org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory.ID;
 import static 
org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory.MEASUREMENT;
 import static 
org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory.TIME;
+import static 
org.apache.iotdb.db.queryengine.plan.parser.ASTVisitor.parseDateTimeFormat;
 import static 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.GroupingSets.Type.CUBE;
 import static 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.GroupingSets.Type.EXPLICIT;
 import static 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.GroupingSets.Type.ROLLUP;
@@ -157,8 +165,11 @@ public class AstBuilder extends 
RelationalSqlBaseVisitor<Node> {
 
   @Nullable private final NodeLocation baseLocation;
 
-  AstBuilder(@Nullable NodeLocation baseLocation) {
+  private final ZoneId zoneId;
+
+  AstBuilder(@Nullable NodeLocation baseLocation, ZoneId zoneId) {
     this.baseLocation = baseLocation;
+    this.zoneId = zoneId;
   }
 
   @Override
@@ -685,6 +696,116 @@ public class AstBuilder extends 
RelationalSqlBaseVisitor<Node> {
         visit(ctx.groupingElement(), GroupingElement.class));
   }
 
+  @Override
+  public Node visitTimenGrouping(RelationalSqlParser.TimenGroupingContext ctx) 
{
+    long startTime = 0;
+    long endTime = 0;
+    boolean leftCRightO = true;
+    if (ctx.timeRange() != null) {
+      TimeRange timeRange = (TimeRange) visit(ctx.timeRange());
+      startTime = timeRange.getStartTime();
+      endTime = timeRange.getEndTime();
+      leftCRightO = timeRange.isLeftCRightO();
+    }
+    // Parse time interval
+    TimeDuration interval = 
DateTimeUtils.constructTimeDuration(ctx.windowInterval.getText());
+    TimeDuration slidingStep = interval;
+    if (ctx.windowStep != null) {
+      slidingStep = 
DateTimeUtils.constructTimeDuration(ctx.windowStep.getText());
+    }
+
+    if (interval.monthDuration <= 0 && interval.nonMonthDuration <= 0) {
+      throw new SemanticException(
+          "The second parameter time interval should be a positive integer.");
+    }
+
+    if (slidingStep.monthDuration <= 0 && slidingStep.nonMonthDuration <= 0) {
+      throw new SemanticException(
+          "The third parameter time slidingStep should be a positive 
integer.");
+    }
+    return new GroupByTime(
+        getLocation(ctx), startTime, endTime, interval, slidingStep, 
leftCRightO);
+  }
+
+  @Override
+  public Node 
visitLeftClosedRightOpen(RelationalSqlParser.LeftClosedRightOpenContext ctx) {
+    return getTimeRange(ctx.timeValue(0), ctx.timeValue(1), true);
+  }
+
+  @Override
+  public Node 
visitLeftOpenRightClosed(RelationalSqlParser.LeftOpenRightClosedContext ctx) {
+    return getTimeRange(ctx.timeValue(0), ctx.timeValue(1), false);
+  }
+
+  private TimeRange getTimeRange(
+      RelationalSqlParser.TimeValueContext left,
+      RelationalSqlParser.TimeValueContext right,
+      boolean leftCRightO) {
+    long currentTime = CommonDateTimeUtils.currentTime();
+    long startTime = parseTimeValue(left, currentTime);
+    long endTime = parseTimeValue(right, currentTime);
+    if (startTime >= endTime) {
+      throw new SemanticException("Start time should be smaller than endTime 
in GroupBy");
+    }
+    return new TimeRange(startTime, endTime, leftCRightO);
+  }
+
+  private long parseTimeValue(RelationalSqlParser.TimeValueContext ctx, long 
currentTime) {
+    if (ctx.DECIMAL_INTEGER_LITERAL() != null) {
+      try {
+        if (ctx.MINUS() != null) {
+          return -Long.parseLong(ctx.DECIMAL_INTEGER_LITERAL().getText());
+        }
+        return Long.parseLong(ctx.DECIMAL_INTEGER_LITERAL().getText());
+      } catch (NumberFormatException e) {
+        throw new SemanticException(
+            String.format(
+                "Can not parse %s to long value", 
ctx.DECIMAL_INTEGER_LITERAL().getText()));
+      }
+    } else {
+      return parseDateExpression(ctx.dateExpression(), currentTime);
+    }
+  }
+
+  private Long parseDateExpression(
+      RelationalSqlParser.DateExpressionContext ctx, long currentTime) {
+    long time;
+    time = parseDateTimeFormat(ctx.getChild(0).getText(), currentTime, zoneId);
+    for (int i = 1; i < ctx.getChildCount(); i = i + 2) {
+      if ("+".equals(ctx.getChild(i).getText())) {
+        time += DateTimeUtils.convertDurationStrToLong(time, ctx.getChild(i + 
1).getText(), false);
+      } else {
+        time -= DateTimeUtils.convertDurationStrToLong(time, ctx.getChild(i + 
1).getText(), false);
+      }
+    }
+    return time;
+  }
+
+  @Override
+  public Node 
visitVariationGrouping(RelationalSqlParser.VariationGroupingContext ctx) {
+    return super.visitVariationGrouping(ctx);
+  }
+
+  @Override
+  public Node 
visitConditionGrouping(RelationalSqlParser.ConditionGroupingContext ctx) {
+    return super.visitConditionGrouping(ctx);
+  }
+
+  @Override
+  public Node visitSessionGrouping(RelationalSqlParser.SessionGroupingContext 
ctx) {
+    return super.visitSessionGrouping(ctx);
+  }
+
+  @Override
+  public Node visitCountGrouping(RelationalSqlParser.CountGroupingContext ctx) 
{
+    return super.visitCountGrouping(ctx);
+  }
+
+  @Override
+  public Node visitKeepExpression(RelationalSqlParser.KeepExpressionContext 
ctx) {
+    return super.visitKeepExpression(ctx);
+  }
+
   @Override
   public Node 
visitSingleGroupingSet(RelationalSqlParser.SingleGroupingSetContext ctx) {
     return new SimpleGroupBy(
@@ -795,61 +916,6 @@ public class AstBuilder extends 
RelationalSqlBaseVisitor<Node> {
     return new Identifier(getLocation(ctx), identifier, true);
   }
 
-  @Override
-  public Node visitTimenGrouping(RelationalSqlParser.TimenGroupingContext ctx) 
{
-    return super.visitTimenGrouping(ctx);
-  }
-
-  @Override
-  public Node 
visitVariationGrouping(RelationalSqlParser.VariationGroupingContext ctx) {
-    return super.visitVariationGrouping(ctx);
-  }
-
-  @Override
-  public Node 
visitConditionGrouping(RelationalSqlParser.ConditionGroupingContext ctx) {
-    return super.visitConditionGrouping(ctx);
-  }
-
-  @Override
-  public Node visitSessionGrouping(RelationalSqlParser.SessionGroupingContext 
ctx) {
-    return super.visitSessionGrouping(ctx);
-  }
-
-  @Override
-  public Node visitCountGrouping(RelationalSqlParser.CountGroupingContext ctx) 
{
-    return super.visitCountGrouping(ctx);
-  }
-
-  @Override
-  public Node 
visitLeftClosedRightOpen(RelationalSqlParser.LeftClosedRightOpenContext ctx) {
-    return super.visitLeftClosedRightOpen(ctx);
-  }
-
-  @Override
-  public Node 
visitLeftOpenRightClosed(RelationalSqlParser.LeftOpenRightClosedContext ctx) {
-    return super.visitLeftOpenRightClosed(ctx);
-  }
-
-  @Override
-  public Node visitTimeValue(RelationalSqlParser.TimeValueContext ctx) {
-    return super.visitTimeValue(ctx);
-  }
-
-  @Override
-  public Node visitDateExpression(RelationalSqlParser.DateExpressionContext 
ctx) {
-    return super.visitDateExpression(ctx);
-  }
-
-  @Override
-  public Node visitDatetimeLiteral(RelationalSqlParser.DatetimeLiteralContext 
ctx) {
-    return super.visitDatetimeLiteral(ctx);
-  }
-
-  @Override
-  public Node visitKeepExpression(RelationalSqlParser.KeepExpressionContext 
ctx) {
-    return super.visitKeepExpression(ctx);
-  }
-
   // ***************** boolean expressions ******************
   @Override
   public Node visitLogicalNot(RelationalSqlParser.LogicalNotContext ctx) {
@@ -1403,11 +1469,6 @@ public class AstBuilder extends 
RelationalSqlBaseVisitor<Node> {
     return super.visitIntervalField(ctx);
   }
 
-  @Override
-  public Node visitTimeDuration(RelationalSqlParser.TimeDurationContext ctx) {
-    return super.visitTimeDuration(ctx);
-  }
-
   // ***************** arguments *****************
   @Override
   public Node visitGenericType(RelationalSqlParser.GenericTypeContext ctx) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/SqlParser.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/SqlParser.java
index c82e1f8a56f..b20fb829326 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/SqlParser.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/SqlParser.java
@@ -44,6 +44,7 @@ import org.antlr.v4.runtime.atn.PredictionMode;
 import org.antlr.v4.runtime.misc.Pair;
 import org.antlr.v4.runtime.tree.TerminalNode;
 
+import java.time.ZoneId;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
@@ -93,35 +94,43 @@ public class SqlParser {
     this.initializer = requireNonNull(initializer, "initializer is null");
   }
 
-  public Statement createStatement(String sql) {
-    return (Statement) invokeParser("statement", sql, 
RelationalSqlParser::singleStatement);
+  public Statement createStatement(String sql, ZoneId zoneId) {
+    return (Statement) invokeParser("statement", sql, 
RelationalSqlParser::singleStatement, zoneId);
   }
 
-  public Statement createStatement(String sql, NodeLocation location) {
+  public Statement createStatement(String sql, NodeLocation location, ZoneId 
zoneId) {
     return (Statement)
         invokeParser(
-            "statement", sql, Optional.ofNullable(location), 
RelationalSqlParser::singleStatement);
+            "statement",
+            sql,
+            Optional.ofNullable(location),
+            RelationalSqlParser::singleStatement,
+            zoneId);
   }
 
-  public Expression createExpression(String expression) {
+  public Expression createExpression(String expression, ZoneId zoneId) {
     return (Expression)
-        invokeParser("expression", expression, 
RelationalSqlParser::standaloneExpression);
+        invokeParser("expression", expression, 
RelationalSqlParser::standaloneExpression, zoneId);
   }
 
-  public DataType createType(String expression) {
-    return (DataType) invokeParser("type", expression, 
RelationalSqlParser::standaloneType);
+  public DataType createType(String expression, ZoneId zoneId) {
+    return (DataType) invokeParser("type", expression, 
RelationalSqlParser::standaloneType, zoneId);
   }
 
   private Node invokeParser(
-      String name, String sql, Function<RelationalSqlParser, 
ParserRuleContext> parseFunction) {
-    return invokeParser(name, sql, Optional.empty(), parseFunction);
+      String name,
+      String sql,
+      Function<RelationalSqlParser, ParserRuleContext> parseFunction,
+      ZoneId zoneId) {
+    return invokeParser(name, sql, Optional.empty(), parseFunction, zoneId);
   }
 
   private Node invokeParser(
       String name,
       String sql,
       Optional<NodeLocation> location,
-      Function<RelationalSqlParser, ParserRuleContext> parseFunction) {
+      Function<RelationalSqlParser, ParserRuleContext> parseFunction,
+      ZoneId zoneId) {
     try {
       RelationalSqlLexer lexer =
           new RelationalSqlLexer(new 
CaseInsensitiveStream(CharStreams.fromString(sql)));
@@ -178,7 +187,7 @@ public class SqlParser {
         throw e;
       }
 
-      return new AstBuilder(location.orElse(null)).visit(tree);
+      return new AstBuilder(location.orElse(null), zoneId).visit(tree);
     } catch (StackOverflowError e) {
       throw new ParsingException(name + " is too large (stack overflow while 
parsing)");
     }
@@ -215,15 +224,16 @@ public class SqlParser {
           token.getCharPositionInLine() + 1);
     }
 
-    @Override
-    public void exitDigitIdentifier(RelationalSqlParser.DigitIdentifierContext 
context) {
-      Token token = context.DIGIT_IDENTIFIER().getSymbol();
-      throw new ParsingException(
-          "identifiers must not start with a digit; surround the identifier 
with double quotes",
-          null,
-          token.getLine(),
-          token.getCharPositionInLine() + 1);
-    }
+    //    @Override
+    //    public void 
exitDigitIdentifier(RelationalSqlParser.DigitIdentifierContext context) {
+    //      Token token = context.DIGIT_IDENTIFIER().getSymbol();
+    //      throw new ParsingException(
+    //          "identifiers must not start with a digit; surround the 
identifier with double
+    // quotes",
+    //          null,
+    //          token.getLine(),
+    //          token.getCharPositionInLine() + 1);
+    //    }
 
     @Override
     public void exitNonReserved(RelationalSqlParser.NonReservedContext 
context) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/ReservedIdentifiers.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/ReservedIdentifiers.java
index d40f6880b9b..2fde6ee0d31 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/ReservedIdentifiers.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/ReservedIdentifiers.java
@@ -23,6 +23,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Identifier;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.parser.ParsingException;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.parser.SqlParser;
 
+import java.time.ZoneId;
 import java.util.Set;
 
 import static com.google.common.collect.ImmutableSet.toImmutableSet;
@@ -40,7 +41,7 @@ public final class ReservedIdentifiers {
 
   public static boolean reserved(String name) {
     try {
-      return !(PARSER.createExpression(name) instanceof Identifier);
+      return !(PARSER.createExpression(name, ZoneId.systemDefault()) 
instanceof Identifier);
     } catch (ParsingException ignored) {
       return true;
     }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/DateTimeUtils.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/DateTimeUtils.java
index 1a3c394af7d..dc24893f32a 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/DateTimeUtils.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/DateTimeUtils.java
@@ -61,12 +61,15 @@ public class DateTimeUtils {
   static {
     switch 
(CommonDescriptor.getInstance().getConfig().getTimestampPrecision()) {
       case "us":
+      case "microsecond":
         CAST_TIMESTAMP_TO_MS = timestamp -> timestamp / 1000;
         break;
       case "ns":
+      case "nanosecond":
         CAST_TIMESTAMP_TO_MS = timestamp -> timestamp / 1000000;
         break;
       case "ms":
+      case "millisecond":
       default:
         CAST_TIMESTAMP_TO_MS = timestamp -> timestamp;
         break;
@@ -501,7 +504,7 @@ public class DateTimeUtils {
     try {
       ZonedDateTime zonedDateTime = ZonedDateTime.parse(str, formatter);
       Instant instant = zonedDateTime.toInstant();
-      if ("us".equals(timestampPrecision)) {
+      if ("us".equals(timestampPrecision) || 
"microsecond".equals(timestampPrecision)) {
         if (instant.getEpochSecond() < 0 && instant.getNano() > 0) {
           // adjustment can reduce the loss of the division
           long millis = Math.multiplyExact(instant.getEpochSecond() + 1, 
1000_000L);
@@ -511,7 +514,7 @@ public class DateTimeUtils {
           long millis = Math.multiplyExact(instant.getEpochSecond(), 
1000_000L);
           return Math.addExact(millis, instant.getNano() / 1000);
         }
-      } else if ("ns".equals(timestampPrecision)) {
+      } else if ("ns".equals(timestampPrecision) || 
"nanosecond".equals(timestampPrecision)) {
         long millis = Math.multiplyExact(instant.getEpochSecond(), 
1000_000_000L);
         return Math.addExact(millis, instant.getNano());
       }
@@ -629,9 +632,11 @@ public class DateTimeUtils {
     long res = value;
     switch (durationUnit) {
       case y:
+      case year:
         res *= 365 * 86_400_000L;
         break;
       case mo:
+      case month:
         if (currentTime == -1) {
           res *= 30 * 86_400_000L;
         } else {
@@ -643,44 +648,55 @@ public class DateTimeUtils {
         }
         break;
       case w:
+      case week:
         res *= 7 * 86_400_000L;
         break;
       case d:
+      case day:
         res *= 86_400_000L;
         break;
       case h:
+      case hour:
         res *= 3_600_000L;
         break;
       case m:
+      case minute:
         res *= 60_000L;
         break;
       case s:
+      case second:
         res *= 1_000L;
         break;
       default:
         break;
     }
 
-    if ("us".equals(timestampPrecision)) {
-      if (unit.equals(DurationUnit.ns.toString())) {
+    if ("us".equals(timestampPrecision) || 
"microsecond".equals(timestampPrecision)) {
+      if (unit.equals(DurationUnit.ns.toString())
+          || unit.equals(DurationUnit.nanosecond.toString())) {
         return value / 1000;
-      } else if (unit.equals(DurationUnit.us.toString())) {
+      } else if (unit.equals(DurationUnit.us.toString())
+          || unit.equals(DurationUnit.microsecond.toString())) {
         return value;
       } else {
         return res * 1000;
       }
-    } else if ("ns".equals(timestampPrecision)) {
-      if (unit.equals(DurationUnit.ns.toString())) {
+    } else if ("ns".equals(timestampPrecision) || 
"nanosecond".equals(timestampPrecision)) {
+      if (unit.equals(DurationUnit.ns.toString())
+          || unit.equals(DurationUnit.nanosecond.toString())) {
         return value;
-      } else if (unit.equals(DurationUnit.us.toString())) {
+      } else if (unit.equals(DurationUnit.us.toString())
+          || unit.equals(DurationUnit.microsecond.toString())) {
         return value * 1000;
       } else {
         return res * 1000_000;
       }
     } else {
-      if (unit.equals(DurationUnit.ns.toString())) {
+      if (unit.equals(DurationUnit.ns.toString())
+          || unit.equals(DurationUnit.nanosecond.toString())) {
         return value / 1000_000;
-      } else if (unit.equals(DurationUnit.us.toString())) {
+      } else if (unit.equals(DurationUnit.us.toString())
+          || unit.equals(DurationUnit.microsecond.toString())) {
         return value / 1000;
       } else {
         return res;
@@ -689,9 +705,9 @@ public class DateTimeUtils {
   }
 
   public static TimeUnit timestampPrecisionStringToTimeUnit(String 
timestampPrecision) {
-    if ("us".equals(timestampPrecision)) {
+    if ("us".equals(timestampPrecision) || 
"microsecond".equals(timestampPrecision)) {
       return TimeUnit.MICROSECONDS;
-    } else if ("ns".equals(timestampPrecision)) {
+    } else if ("ns".equals(timestampPrecision) || 
"nanosecond".equals(timestampPrecision)) {
       return TimeUnit.NANOSECONDS;
     } else {
       return TimeUnit.MILLISECONDS;
@@ -706,9 +722,11 @@ public class DateTimeUtils {
   public static String convertLongToDate(long timestamp, String 
sourcePrecision) {
     switch (sourcePrecision) {
       case "ns":
+      case "nanosecond":
         timestamp /= 1000_000;
         break;
       case "us":
+      case "microsecond":
         timestamp /= 1000;
         break;
     }
@@ -726,30 +744,46 @@ public class DateTimeUtils {
 
   public enum DurationUnit {
     y,
+    year,
     mo,
+    month,
     w,
+    week,
     d,
+    day,
     h,
+    hour,
     m,
+    minute,
     s,
+    second,
     ms,
+    millisecond,
     us,
-    ns
+    microsecond,
+    ns,
+    nanosecond
   }
 
   public static TimeUnit toTimeUnit(String t) {
     switch (t) {
       case "h":
+      case "hour":
         return TimeUnit.HOURS;
       case "m":
+      case "minute":
         return TimeUnit.MINUTES;
       case "s":
+      case "second":
         return TimeUnit.SECONDS;
       case "ms":
+      case "millisecond":
         return TimeUnit.MILLISECONDS;
       case "u":
+      case "microsecond":
         return TimeUnit.MICROSECONDS;
       case "n":
+      case "nanosecond":
         return TimeUnit.NANOSECONDS;
       default:
         throw new IllegalArgumentException("time precision must be one of: 
h,m,s,ms,u,n");
@@ -793,12 +827,12 @@ public class DateTimeUtils {
           i++;
           unit += duration.charAt(i);
         }
-        if (unit.equals("y")) {
+        if ("y".equals(unit) || "year".equals(unit)) {
           monthDuration += temp * 12;
           temp = 0;
           continue;
         }
-        if (unit.equals("mo")) {
+        if ("mo".equals(unit) || "month".equals(unit)) {
           monthDuration += temp;
           temp = 0;
           continue;
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
index f59af819f8f..b36e7a784b2 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
@@ -484,7 +484,7 @@ public class AnalyzerTest {
   public static Analysis analyzeSQL(String sql, Metadata metadata) {
     try {
       SqlParser sqlParser = new SqlParser();
-      Statement statement = sqlParser.createStatement(sql);
+      Statement statement = sqlParser.createStatement(sql, 
ZoneId.systemDefault());
       SessionInfo session =
           new SessionInfo(
               0, "test", ZoneId.systemDefault(), "testdb", 
IClientSession.SqlDialect.TABLE);
diff --git 
a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
 
b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
index 26cd32456e6..86244da3fe2 100644
--- 
a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
+++ 
b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
@@ -375,7 +375,7 @@ propertyValue
 queryNoWith
     : queryTerm
       (ORDER BY sortItem (',' sortItem)*)?
-      (FILL '(' (LINEAR | PREVIOUS | literalExpression) (',' 
duration=timeDuration)? ')')?
+      (FILL '(' (LINEAR | PREVIOUS | literalExpression) (',' 
duration=timeduration)? ')')?
       (OFFSET offset=rowCount)?
       (LIMIT limit=limitRowCount)?
     ;
@@ -419,11 +419,11 @@ groupBy
     ;
 
 groupingElement
-    : TIME? '(' (timeRange ',')? windowInterval=timeDuration (',' 
windowStep=timeDuration)?')'     #timenGrouping
+    : TIME '(' (timeRange ',')? windowInterval=timeduration (',' 
windowStep=timeduration)?')'      #timenGrouping
     | VARIATION '(' expression (',' delta=number)? (',' propertyAssignments)? 
')'                  #variationGrouping
     | CONDITION '(' expression (',' keepExpression)? (',' 
propertyAssignments)? ')'                #conditionGrouping
-    | SESSION '(' timeInterval=timeDuration ')'                                
                    #sessionGrouping
-    | COUNT '(' expression ',' countNumber=INTEGER_VALUE (',' 
propertyAssignments)? ')'            #countGrouping
+    | SESSION '(' timeInterval=timeduration ')'                                
                    #sessionGrouping
+    | COUNT '(' expression ',' countNumber=DECIMAL_INTEGER_LITERAL (',' 
propertyAssignments)? ')'  #countGrouping
     | groupingSet                                                              
                    #singleGroupingSet
     // the following three haven't been supported yet
     | ROLLUP '(' (groupingSet (',' groupingSet)*)? ')'                         
                    #rollup
@@ -438,11 +438,11 @@ timeRange
 
 timeValue
     : dateExpression
-    | (PLUS | MINUS)? INTEGER_VALUE
+    | (PLUS | MINUS)? DECIMAL_INTEGER_LITERAL
     ;
 
 dateExpression
-    : datetimeLiteral ((PLUS | MINUS) timeDuration)*
+    : datetimeLiteral ((PLUS | MINUS) timeduration)*
     ;
 
 datetimeLiteral
@@ -451,7 +451,7 @@ datetimeLiteral
     ;
 
 keepExpression
-    : (KEEP (EQ | LT | LTE | GT | GTE))? INTEGER_VALUE
+    : (KEEP (EQ | LT | LTE | GT | GTE))? DECIMAL_INTEGER_LITERAL
     ;
 
 groupingSet
@@ -610,8 +610,12 @@ intervalField
     : YEAR | MONTH | WEEK | DAY | HOUR | MINUTE | SECOND | MILLISECOND | 
MICROSECOND | NANOSECOND
     ;
 
-timeDuration
-    : (INTEGER_VALUE+ (intervalField))+
+timeduration
+    : (DECIMAL_INTEGER_LITERAL intervalField)+
+    ;
+
+DECIMAL_INTEGER_LITERAL
+    : DECIMAL_INTEGER
     ;
 
 type
@@ -693,7 +697,6 @@ identifier
     | QUOTED_IDENTIFIER      #quotedIdentifier
     | nonReserved            #unquotedIdentifier
     | BACKQUOTED_IDENTIFIER  #backQuotedIdentifier
-    | DIGIT_IDENTIFIER       #digitIdentifier
     ;
 
 number
@@ -1133,9 +1136,9 @@ IDENTIFIER
     : (LETTER | '_') (LETTER | DIGIT | '_')*
     ;
 
-DIGIT_IDENTIFIER
-    : DIGIT (LETTER | DIGIT | '_')+
-    ;
+//DIGIT_IDENTIFIER
+//    : DIGIT (LETTER | DIGIT | '_')+
+//    ;
 
 QUOTED_IDENTIFIER
     : '"' ( ~'"' | '""' )* '"'
@@ -1205,3 +1208,30 @@ WS
 UNRECOGNIZED
     : .
     ;
+
+fragment A: [a];
+fragment B: [b];
+fragment C: [c];
+fragment D: [d];
+fragment E: [e];
+fragment F: [f];
+fragment G: [g];
+fragment H: [h];
+fragment I: [i];
+fragment J: [j];
+fragment K: [k];
+fragment L: [l];
+fragment M: [m];
+fragment N: [n];
+fragment O: [o];
+fragment P: [p];
+fragment Q: [q];
+fragment R: [r];
+fragment S: [s];
+fragment T: [t];
+fragment U: [u];
+fragment V: [v];
+fragment W: [w];
+fragment X: [x];
+fragment Y: [y];
+fragment Z: [z];
\ No newline at end of file


Reply via email to