diff --git a/docs/content/querying/sql.md b/docs/content/querying/sql.md index e08ea043cbb..6a42e504546 100644 --- a/docs/content/querying/sql.md +++ b/docs/content/querying/sql.md @@ -167,6 +167,7 @@ over the connection time zone. |`EXTRACT( FROM timestamp_expr)`|Extracts a time part from expr, returning it as a number. Unit can be EPOCH, SECOND, MINUTE, HOUR, DAY (day of month), DOW (day of week), DOY (day of year), WEEK (week of year), MONTH, QUARTER, or YEAR. Units must be provided unquoted, like `EXTRACT(HOUR FROM __time)`.| |`FLOOR(timestamp_expr TO )`|Rounds down a timestamp, returning it as a new timestamp. Unit can be SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, or YEAR.| |`CEIL(timestamp_expr TO )`|Rounds up a timestamp, returning it as a new timestamp. Unit can be SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, or YEAR.| +|`TIMESTAMPADD(, , )`|Equivalent to `timestamp + count * INTERVAL '1' UNIT`.| |`timestamp_expr { + \| - } `|Add or subtract an amount of time from a timestamp. interval_expr can include interval literals like `INTERVAL '2' HOUR`, and may include interval arithmetic as well. This operator treats days as uniformly 86400 seconds long, and does not take into account daylight savings time. To account for daylight savings time, use TIME_SHIFT instead.| ### Comparison operators diff --git a/sql/src/main/java/io/druid/sql/calcite/planner/DruidConvertletTable.java b/sql/src/main/java/io/druid/sql/calcite/planner/DruidConvertletTable.java index 4a66f93c644..ec4eb3c547a 100644 --- a/sql/src/main/java/io/druid/sql/calcite/planner/DruidConvertletTable.java +++ b/sql/src/main/java/io/druid/sql/calcite/planner/DruidConvertletTable.java @@ -67,6 +67,7 @@ public class DruidConvertletTable implements SqlRexConvertletTable .add(SqlStdOperatorTable.SYMMETRIC_BETWEEN) .add(SqlStdOperatorTable.SYMMETRIC_NOT_BETWEEN) .add(SqlStdOperatorTable.ITEM) + .add(SqlStdOperatorTable.TIMESTAMP_ADD) .build(); private final Map table; diff --git a/sql/src/test/java/io/druid/sql/calcite/CalciteQueryTest.java b/sql/src/test/java/io/druid/sql/calcite/CalciteQueryTest.java index b6ad7a8ee58..9f3f431512d 100644 --- a/sql/src/test/java/io/druid/sql/calcite/CalciteQueryTest.java +++ b/sql/src/test/java/io/druid/sql/calcite/CalciteQueryTest.java @@ -5428,6 +5428,54 @@ public class CalciteQueryTest ); } + @Test + public void testTimeseriesUsingTimeFloorWithTimestampAdd() throws Exception + { + testQuery( + "SELECT SUM(cnt), gran FROM (\n" + + " SELECT TIME_FLOOR(TIMESTAMPADD(DAY, -1, __time), 'P1M') AS gran,\n" + + " cnt FROM druid.foo\n" + + ") AS x\n" + + "GROUP BY gran\n" + + "ORDER BY gran", + ImmutableList.of( + GroupByQuery.builder() + .setDataSource(CalciteTests.DATASOURCE1) + .setInterval(QSS(Filtration.eternity())) + .setGranularity(Granularities.ALL) + .setVirtualColumns( + EXPRESSION_VIRTUAL_COLUMN( + "d0:v", + "timestamp_floor((\"__time\" + -86400000),'P1M','','UTC')", + ValueType.LONG + ) + ) + .setDimensions(DIMS(new DefaultDimensionSpec("d0:v", "d0", ValueType.LONG))) + .setAggregatorSpecs(AGGS(new LongSumAggregatorFactory("a0", "cnt"))) + .setLimitSpec( + new DefaultLimitSpec( + ImmutableList.of( + new OrderByColumnSpec( + "d0", + OrderByColumnSpec.Direction.ASCENDING, + StringComparators.NUMERIC + ) + ), + Integer.MAX_VALUE + ) + ) + .setContext(QUERY_CONTEXT_DEFAULT) + .build() + ), + ImmutableList.of( + new Object[]{1L, T("1999-12-01")}, + new Object[]{2L, T("2000-01-01")}, + new Object[]{1L, T("2000-12-01")}, + new Object[]{2L, T("2001-01-01")} + ) + ); + } + @Test public void testTimeseriesUsingTimeFloorWithOrigin() throws Exception {