This is an automated email from the ASF dual-hosted git repository.
jackietien pushed a commit to branch ty/TableModelGrammar
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/ty/TableModelGrammar by this
push:
new 625269b8a5b Support for group by time sql paser
625269b8a5b is described below
commit 625269b8a5bb3e3f3d5cdb82fcb642a7c3c4e9a2
Author: Jackie Tien <[email protected]>
AuthorDate: Tue Jun 18 19:37:24 2024 +0800
Support for group by time sql paser
---
.../relational/it/schema/IoTDBDatabaseIT.java | 37 ++---
.../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 | 182 ++++++++++++++-------
.../plan/relational/sql/parser/SqlParser.java | 52 +++---
.../relational/sql/util/ReservedIdentifiers.java | 3 +-
.../org/apache/iotdb/db/utils/DateTimeUtils.java | 79 ++++++---
.../plan/relational/analyzer/AnalyzerTest.java | 2 +-
.../db/relational/grammar/sql/RelationalSql.g4 | 13 +-
14 files changed, 432 insertions(+), 173 deletions(-)
diff --git
a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
index cb02608e424..d2450039a70 100644
---
a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
@@ -117,42 +117,39 @@ public class IoTDBDatabaseIT {
// create with strange name
try {
statement.execute("create database 1test");
- fail("create database 1test shouldn't succeed because test1 doesn't
exist");
+ fail(
+ "create database 1test shouldn't succeed because 1test is not a
legal identifier; identifiers must not start with a digit; surround the
identifier with double quotes");
} catch (SQLException e) {
- assertTrue(
- e.getMessage(),
- e.getMessage()
- .endsWith(
- "identifiers must not start with a digit; surround the
identifier with double quotes"));
+ assertTrue(e.getMessage(), e.getMessage().contains("mismatched input
'1'"));
}
statement.execute("create database \"1test\"");
statement.execute("use \"1test\"");
statement.execute("drop database \"1test\"");
- // try {
- // statement.execute("create database 1");
- // fail("create database 1test shouldn't succeed because test1
doesn't exist");
- // } catch (SQLException e) {
- // // TODO add error msg assert
- // }
+ try {
+ statement.execute("create database 1");
+ fail("create database 1 shouldn't succeed because 1 is not a legal
identifier");
+ } catch (SQLException e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("mismatched input
'1'"));
+ }
//
// // TODO fix it, should succeed
// statement.execute("create database \"1\"");
// statement.execute("use \"1\"");
// statement.execute("drop database \"1\"");
//
- // try {
- // statement.execute("create database a.b");
- // fail("create database 1test shouldn't succeed because test1
doesn't exist");
- // } catch (SQLException e) {
- // // TODO add error msg assert
- // }
+ try {
+ statement.execute("create database a.b");
+ fail("create database a.b shouldn't succeed because a.b is not a legal
identifier");
+ } catch (SQLException e) {
+ assertTrue(e.getMessage(), e.getMessage().contains("mismatched input
'.'"));
+ }
//
// // TODO fix it, should succeed
- // statement.execute("create database \"a.b\"");
+ statement.execute("create database \"a.b\"");
// statement.execute("use \"a.b\"");
- // statement.execute("drop database \"a.b\"");
+ statement.execute("drop database \"a.b\"");
} catch (SQLException e) {
e.printStackTrace();
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 77bb797ba50..136ba340e44 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
@@ -337,7 +337,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 db6ae15eed8..34fb4814fdc 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
@@ -2158,8 +2158,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)) {
@@ -3138,7 +3138,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);
@@ -3163,7 +3163,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 26cbe300c2a..98b9f92f341 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..ef2a3dfe5e8 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,115 @@ 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.INTEGER_VALUE() != null) {
+ try {
+ if (ctx.MINUS() != null) {
+ return -Long.parseLong(ctx.INTEGER_VALUE().getText());
+ }
+ return Long.parseLong(ctx.INTEGER_VALUE().getText());
+ } catch (NumberFormatException e) {
+ throw new SemanticException(
+ String.format("Can not parse %s to long value",
ctx.INTEGER_VALUE().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 +915,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 +1468,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..98e0a6f09aa 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");
@@ -781,30 +815,33 @@ public class DateTimeUtils {
long temp = 0;
long monthDuration = 0;
long nonMonthDuration = 0;
- for (int i = 0; i < duration.length(); i++) {
+ int i = 0;
+ for (; i < duration.length(); i++) {
char ch = duration.charAt(i);
if (Character.isDigit(ch)) {
temp *= 10;
temp += (ch - '0');
} else {
- String unit = String.valueOf(duration.charAt(i));
- // This is to identify units with two letters.
- if (i + 1 < duration.length() && !Character.isDigit(duration.charAt(i
+ 1))) {
+ StringBuilder unit = new
StringBuilder(String.valueOf(duration.charAt(i)));
+ i++;
+ // This is to identify units.
+ while (i < duration.length() &&
!Character.isDigit(duration.charAt(i))) {
+ unit.append(duration.charAt(i));
i++;
- unit += duration.charAt(i);
}
- if (unit.equals("y")) {
+ i--;
+ if ("y".contentEquals(unit) || "year".contentEquals(unit)) {
monthDuration += temp * 12;
temp = 0;
continue;
}
- if (unit.equals("mo")) {
+ if ("mo".contentEquals(unit) || "month".contentEquals(unit)) {
monthDuration += temp;
temp = 0;
continue;
}
nonMonthDuration +=
- DateTimeUtils.convertDurationStrToLong(-1, temp, unit,
currTimePrecision);
+ DateTimeUtils.convertDurationStrToLong(-1, temp, unit.toString(),
currTimePrecision);
temp = 0;
}
}
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 03608978707..335d838587e 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
@@ -485,7 +485,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..4e7d8ebff85 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
@@ -419,7 +419,7 @@ 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
@@ -611,7 +611,7 @@ intervalField
;
timeDuration
- : (INTEGER_VALUE+ (intervalField))+
+ : (INTEGER_VALUE intervalField)+
;
type
@@ -693,7 +693,6 @@ identifier
| QUOTED_IDENTIFIER #quotedIdentifier
| nonReserved #unquotedIdentifier
| BACKQUOTED_IDENTIFIER #backQuotedIdentifier
- | DIGIT_IDENTIFIER #digitIdentifier
;
number
@@ -1133,9 +1132,9 @@ IDENTIFIER
: (LETTER | '_') (LETTER | DIGIT | '_')*
;
-DIGIT_IDENTIFIER
- : DIGIT (LETTER | DIGIT | '_')+
- ;
+//DIGIT_IDENTIFIER
+// : DIGIT (LETTER | DIGIT | '_')+
+// ;
QUOTED_IDENTIFIER
: '"' ( ~'"' | '""' )* '"'
@@ -1204,4 +1203,4 @@ WS
// when splitting statements with DelimiterLexer
UNRECOGNIZED
: .
- ;
+ ;
\ No newline at end of file