This is an automated email from the ASF dual-hosted git repository. xiangweiwei pushed a commit to branch updateGroupby in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 299731c3aa64c39ccb24a998f99138506cca992e Author: Alima777 <[email protected]> AuthorDate: Mon Jun 21 10:16:01 2021 +0800 Sync 0.12 with master --- .../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java | 95 ++++++---------------- .../apache/iotdb/db/qp/utils/DatetimeUtils.java | 33 ++++++-- .../iotdb/db/integration/IoTDBGroupByMonthIT.java | 3 +- .../db/qp/utils/DatetimeQueryDataSetUtilsTest.java | 28 +++++++ 4 files changed, 81 insertions(+), 78 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 4684111..ae7f473 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 @@ -1479,7 +1479,7 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { queryOp.setLeftCRightO(ctx.timeInterval().LS_BRACKET() != null); // parse timeUnit - queryOp.setUnit(parseDuration(ctx.DURATION().getText())); + queryOp.setUnit(DatetimeUtils.convertDurationStrToLong(ctx.DURATION().getText())); queryOp.setSlidingStep(queryOp.getUnit()); parseTimeInterval(ctx.timeInterval(), queryOp); @@ -1497,7 +1497,9 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { if (typeClause.previousUntilLastClause() != null) { long preRange; if (typeClause.previousUntilLastClause().DURATION() != null) { - preRange = parseDuration(typeClause.previousUntilLastClause().DURATION().getText()); + preRange = + DatetimeUtils.convertDurationStrToLong( + typeClause.previousUntilLastClause().DURATION().getText()); } else { preRange = IoTDBDescriptor.getInstance().getConfig().getDefaultFillInterval(); } @@ -1505,7 +1507,9 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { } else { long preRange; if (typeClause.previousClause().DURATION() != null) { - preRange = parseDuration(typeClause.previousClause().DURATION().getText()); + preRange = + DatetimeUtils.convertDurationStrToLong( + typeClause.previousClause().DURATION().getText()); } else { preRange = IoTDBDescriptor.getInstance().getConfig().getDefaultFillInterval(); } @@ -1536,22 +1540,27 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { if (ctx.linearClause() != null) { // linear if (ctx.linearClause().DURATION(0) != null) { - long beforeRange = parseDuration(ctx.linearClause().DURATION(0).getText()); - long afterRange = parseDuration(ctx.linearClause().DURATION(1).getText()); + long beforeRange = + DatetimeUtils.convertDurationStrToLong(ctx.linearClause().DURATION(0).getText()); + long afterRange = + DatetimeUtils.convertDurationStrToLong(ctx.linearClause().DURATION(1).getText()); fillTypes.put(dataType, new LinearFill(beforeRange, afterRange)); } else { fillTypes.put(dataType, new LinearFill(defaultFillInterval, defaultFillInterval)); } } else if (ctx.previousClause() != null) { // previous if (ctx.previousClause().DURATION() != null) { - long preRange = parseDuration(ctx.previousClause().DURATION().getText()); + long preRange = + DatetimeUtils.convertDurationStrToLong(ctx.previousClause().DURATION().getText()); fillTypes.put(dataType, new PreviousFill(preRange)); } else { fillTypes.put(dataType, new PreviousFill(defaultFillInterval)); } } else { // previous until last if (ctx.previousUntilLastClause().DURATION() != null) { - long preRange = parseDuration(ctx.previousUntilLastClause().DURATION().getText()); + long preRange = + DatetimeUtils.convertDurationStrToLong( + ctx.previousUntilLastClause().DURATION().getText()); fillTypes.put(dataType, new PreviousFill(preRange, true)); } else { fillTypes.put(dataType, new PreviousFill(defaultFillInterval, true)); @@ -1834,85 +1843,31 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { time = parseTimeFormat(ctx.getChild(0).getText()); for (int i = 1; i < ctx.getChildCount(); i = i + 2) { if (ctx.getChild(i).getText().equals("+")) { - time += parseDuration(ctx.getChild(i + 1).getText()); + time += DatetimeUtils.convertDurationStrToLong(time, ctx.getChild(i + 1).getText()); } else { - time -= parseDuration(ctx.getChild(i + 1).getText()); + time -= DatetimeUtils.convertDurationStrToLong(time, ctx.getChild(i + 1).getText()); } } return time; } /** - * parse duration to time value. - * - * @param durationStr represent duration string like: 12d8m9ns, 1y1mo, etc. - * @return time in milliseconds, microseconds, or nanoseconds depending on the profile - */ - private Long parseDuration(String durationStr) { - String timestampPrecision = IoTDBDescriptor.getInstance().getConfig().getTimestampPrecision(); - - long total = 0; - long tmp = 0; - for (int i = 0; i < durationStr.length(); i++) { - char ch = durationStr.charAt(i); - if (Character.isDigit(ch)) { - tmp *= 10; - tmp += (ch - '0'); - } else { - 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); - } - total += - DatetimeUtils.convertDurationStrToLong(tmp, unit.toLowerCase(), timestampPrecision); - tmp = 0; - } - } - if (total <= 0) { - throw new SQLParserException("Interval must more than 0."); - } - 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. + * @param durationStr represent duration string like: 12d8m9ns, 1y1d, 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 (durationStr.toLowerCase().contains("mo")) { + if (isParsingTimeUnit) { + queryOp.setIntervalByMonth(true); + } else { + queryOp.setSlidingStepByMonth(true); } } - if (hasMonthUnit && hasOtherUnits) { - throw new SQLParserException( - "Natural month unit can not be used with other time units together now."); - } - return parseDuration(durationStr); + return DatetimeUtils.convertDurationStrToLong(durationStr); } private PartialPath parseSuffixPath(SuffixPathContext ctx) { diff --git a/server/src/main/java/org/apache/iotdb/db/qp/utils/DatetimeUtils.java b/server/src/main/java/org/apache/iotdb/db/qp/utils/DatetimeUtils.java index 80035d36..264fe6b 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/utils/DatetimeUtils.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/utils/DatetimeUtils.java @@ -31,6 +31,7 @@ import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; import java.time.format.SignStyle; import java.time.temporal.ChronoField; +import java.util.Calendar; public class DatetimeUtils { @@ -506,14 +507,15 @@ public class DatetimeUtils { } /** - * convert duration string to time value. + * convert duration string to time value. CurrentTime is used to calculate the days of natural * + * month. If it's set as -1, which means a context free situation, then '1mo' will be thought as * + * 30 days. * * @param duration represent duration string like: 12d8m9ns, 1y1mo, etc. * @return time in milliseconds, microseconds, or nanoseconds depending on the profile */ public static long convertDurationStrToLong(String duration) { - String timestampPrecision = IoTDBDescriptor.getInstance().getConfig().getTimestampPrecision(); - return convertDurationStrToLong(duration, timestampPrecision); + return convertDurationStrToLong(-1, duration); } /** @@ -522,7 +524,8 @@ public class DatetimeUtils { * @param duration represent duration string like: 12d8m9ns, 1y1mo, etc. * @return time in milliseconds, microseconds, or nanoseconds depending on the profile */ - public static long convertDurationStrToLong(String duration, String timestampPrecision) { + public static long convertDurationStrToLong(long currentTime, String duration) { + String timestampPrecision = IoTDBDescriptor.getInstance().getConfig().getTimestampPrecision(); long total = 0; long temp = 0; for (int i = 0; i < duration.length(); i++) { @@ -538,15 +541,24 @@ public class DatetimeUtils { unit += duration.charAt(i); } total += - DatetimeUtils.convertDurationStrToLong(temp, unit.toLowerCase(), timestampPrecision); + DatetimeUtils.convertDurationStrToLong( + currentTime == -1 ? -1 : currentTime + total, + temp, + unit.toLowerCase(), + timestampPrecision); temp = 0; } } return total; } - /** convert duration string to millisecond, microsecond or nanosecond. */ public static long convertDurationStrToLong(long value, String unit, String timestampPrecision) { + return convertDurationStrToLong(-1, value, unit, timestampPrecision); + } + + /** convert duration string to millisecond, microsecond or nanosecond. */ + public static long convertDurationStrToLong( + long currentTime, long value, String unit, String timestampPrecision) { DurationUnit durationUnit = DurationUnit.valueOf(unit); long res = value; switch (durationUnit) { @@ -554,7 +566,14 @@ public class DatetimeUtils { res *= 365 * 86_400_000L; break; case mo: - res *= 30 * 86_400_000L; + if (currentTime == -1) { + res *= 30 * 86_400_000L; + } else { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(currentTime); + calendar.add(Calendar.MONTH, (int) (value)); + res = calendar.getTimeInMillis() - currentTime; + } break; case w: res *= 7 * 86_400_000L; 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 fdfb216..76e0dba 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 @@ -244,7 +244,8 @@ public class IoTDBGroupByMonthIT { cnt++; } } - Assert.assertEquals(30, cnt); + Assert.assertTrue(cnt >= 28); + Assert.assertTrue(cnt <= 31); } } catch (Exception e) { e.printStackTrace(); diff --git a/server/src/test/java/org/apache/iotdb/db/qp/utils/DatetimeQueryDataSetUtilsTest.java b/server/src/test/java/org/apache/iotdb/db/qp/utils/DatetimeQueryDataSetUtilsTest.java index 8987830..999a590 100644 --- a/server/src/test/java/org/apache/iotdb/db/qp/utils/DatetimeQueryDataSetUtilsTest.java +++ b/server/src/test/java/org/apache/iotdb/db/qp/utils/DatetimeQueryDataSetUtilsTest.java @@ -130,6 +130,34 @@ public class DatetimeQueryDataSetUtilsTest { Assert.assertEquals(7L, DatetimeUtils.convertDurationStrToLong(7, "ns", "ns")); } + /** Test convert duration including natural month unit. Time includes: 1970-01-01 ~ 1970-12-01 */ + @Test + public void getConvertDurationIncludingMonthUnit() { + Assert.assertEquals(31 * 86400000L, DatetimeUtils.convertDurationStrToLong(0, 1, "mo", "ms")); + Assert.assertEquals( + 28 * 86400000L, DatetimeUtils.convertDurationStrToLong(2678400000L, 1, "mo", "ms")); + Assert.assertEquals( + 31 * 86400000L, DatetimeUtils.convertDurationStrToLong(5097600000L, 1, "mo", "ms")); + Assert.assertEquals( + 30 * 86400000L, DatetimeUtils.convertDurationStrToLong(7776000000L, 1, "mo", "ms")); + Assert.assertEquals( + 31 * 86400000L, DatetimeUtils.convertDurationStrToLong(10368000000L, 1, "mo", "ms")); + Assert.assertEquals( + 30 * 86400000L, DatetimeUtils.convertDurationStrToLong(13046400000L, 1, "mo", "ms")); + Assert.assertEquals( + 31 * 86400000L, DatetimeUtils.convertDurationStrToLong(15638400000L, 1, "mo", "ms")); + Assert.assertEquals( + 31 * 86400000L, DatetimeUtils.convertDurationStrToLong(18316800000L, 1, "mo", "ms")); + Assert.assertEquals( + 30 * 86400000L, DatetimeUtils.convertDurationStrToLong(20995200000L, 1, "mo", "ms")); + Assert.assertEquals( + 31 * 86400000L, DatetimeUtils.convertDurationStrToLong(23587200000L, 1, "mo", "ms")); + Assert.assertEquals( + 30 * 86400000L, DatetimeUtils.convertDurationStrToLong(26265600000L, 1, "mo", "ms")); + Assert.assertEquals( + 31 * 86400000L, DatetimeUtils.convertDurationStrToLong(28857600000L, 1, "mo", "ms")); + } + public void testConvertDatetimeStrToLongWithoutMS(ZoneOffset zoneOffset, ZoneId zoneId, long res) throws LogicalOperatorException { String[] timeFormatWithoutMs =
