You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ha...@apache.org on 2021/05/14 06:09:41 UTC

[iotdb] branch rel/0.12 updated: [To rel/0.12] [ISSUE-3116] Bug when using natural month unit in time interval in group by query (#3141)

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

haonan pushed a commit to branch rel/0.12
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/rel/0.12 by this push:
     new 39f85a8  [To rel/0.12] [ISSUE-3116] Bug when using natural month unit in time interval in group by query (#3141)
39f85a8 is described below

commit 39f85a84736fa2e9a9f9e8f0727ee6b67ecac86e
Author: Xiangwei Wei <34...@users.noreply.github.com>
AuthorDate: Fri May 14 14:07:44 2021 +0800

    [To rel/0.12] [ISSUE-3116] Bug when using natural month unit in time interval in group by query (#3141)
---
 .../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java    | 60 ++++++++++++++++------
 .../iotdb/db/integration/IoTDBGroupByMonthIT.java  | 28 ++++++++++
 2 files changed, 72 insertions(+), 16 deletions(-)

diff --git a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
index 4a8373b..acb84fb 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
@@ -252,7 +252,6 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
           + "time > XXX, time <= XXX, or two atomic expressions connected by 'AND'";
   private ZoneId zoneId;
   QueryOperator queryOp;
-  private boolean isParsingSlidingStep;
 
   public void setZoneId(ZoneId zoneId) {
     this.zoneId = zoneId;
@@ -1437,17 +1436,17 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
     queryOp.setGroupByTime(true);
     queryOp.setLeftCRightO(ctx.timeInterval().LS_BRACKET() != null);
     // parse timeUnit
-    queryOp.setUnit(parseDuration(ctx.DURATION(0).getText()));
-    queryOp.setSlidingStep(queryOp.getUnit());
+    queryOp.setUnit(parseTimeUnitOrSlidingStep(queryOp, ctx.DURATION(0).getText(), true));
     // parse sliding step
     if (ctx.DURATION().size() == 2) {
-      isParsingSlidingStep = true;
-      queryOp.setSlidingStep(parseDuration(ctx.DURATION(1).getText()));
-      isParsingSlidingStep = false;
+      queryOp.setSlidingStep(parseTimeUnitOrSlidingStep(queryOp, ctx.DURATION(1).getText(), false));
       if (queryOp.getSlidingStep() < queryOp.getUnit()) {
         throw new SQLParserException(
             "The third parameter sliding step shouldn't be smaller than the second parameter time interval.");
       }
+    } else {
+      queryOp.setSlidingStep(queryOp.getUnit());
+      queryOp.setSlidingStepByMonth(queryOp.isIntervalByMonth());
     }
 
     parseTimeInterval(ctx.timeInterval(), queryOp);
@@ -1853,16 +1852,6 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
           i++;
           unit += durationStr.charAt(i);
         }
-        if (unit.equalsIgnoreCase("mo")) {
-          // interval is by month, sliding step by default equals to interval
-          if (!isParsingSlidingStep) {
-            queryOp.setIntervalByMonth(true);
-          }
-          queryOp.setSlidingStepByMonth(true);
-        } else if (isParsingSlidingStep) {
-          // parsing sliding step value, and unit is not by month
-          queryOp.setSlidingStepByMonth(false);
-        }
         total +=
             DatetimeUtils.convertDurationStrToLong(tmp, unit.toLowerCase(), timestampPrecision);
         tmp = 0;
@@ -1874,6 +1863,45 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
     return total;
   }
 
+  /**
+   * parse time unit or sliding step in group by query. If 'mo' is used, then other units can not be
+   * used together, like '1mo1d'.
+   *
+   * @param durationStr represent duration string like: 12d8m9ns, 1y1mo, etc.
+   * @return time in milliseconds, microseconds, or nanoseconds depending on the profile
+   */
+  private long parseTimeUnitOrSlidingStep(
+      QueryOperator queryOp, String durationStr, boolean isParsingTimeUnit) {
+    boolean hasMonthUnit = false;
+    boolean hasOtherUnits = false;
+    for (int i = 0; i < durationStr.length(); i++) {
+      char ch = durationStr.charAt(i);
+      if (!Character.isDigit(ch)) {
+        String unit = durationStr.charAt(i) + "";
+        // This is to identify units with two letters.
+        if (i + 1 < durationStr.length() && !Character.isDigit(durationStr.charAt(i + 1))) {
+          i++;
+          unit += durationStr.charAt(i);
+        }
+        if (unit.equalsIgnoreCase("mo")) {
+          if (isParsingTimeUnit) {
+            queryOp.setIntervalByMonth(true);
+          } else {
+            queryOp.setSlidingStepByMonth(true);
+          }
+          hasMonthUnit = true;
+        } else {
+          hasOtherUnits = true;
+        }
+      }
+    }
+    if (hasMonthUnit && hasOtherUnits) {
+      throw new SQLParserException(
+          "Natural month unit can not be used with other time units together now.");
+    }
+    return parseDuration(durationStr);
+  }
+
   private PartialPath parseSuffixPath(SuffixPathContext ctx) {
     List<NodeNameContext> nodeNames = ctx.nodeName();
     String[] path = new String[nodeNames.size()];
diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupByMonthIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupByMonthIT.java
index 5ff2236..fdfb216 100644
--- a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupByMonthIT.java
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupByMonthIT.java
@@ -224,6 +224,34 @@ public class IoTDBGroupByMonthIT {
     }
   }
 
+  /** StartTime: now() - 1mo, EndTime: now(). */
+  @Test
+  public void groupByNaturalMonth6() {
+    try (Connection connection =
+            DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
+        Statement statement = connection.createStatement()) {
+
+      boolean hasResultSet =
+          statement.execute(
+              "select sum(temperature) from root.sg1.d1 GROUP BY ([now() - 1mo, now()), 1d)");
+
+      Assert.assertTrue(hasResultSet);
+      int cnt = 0;
+      try (ResultSet resultSet = statement.getResultSet()) {
+        while (resultSet.next()) {
+          String ans = resultSet.getString(sum("root.sg1.d1.temperature"));
+          if (ans.equals("0.0")) {
+            cnt++;
+          }
+        }
+        Assert.assertEquals(30, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
   private void prepareData() {
     try (Connection connection =
             DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");