You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ja...@apache.org on 2024/06/14 09:16:14 UTC
(iotdb) 01/01: Support for group by time sql paser
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 <ja...@gmail.com>
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