This is an automated email from the ASF dual-hosted git repository.
qiaojialin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 8db2f32 Support left open and right close range in group by (#1056)
8db2f32 is described below
commit 8db2f328e77aec738ba5f298efdccc34b2ba67fe
Author: Jackie Tien <[email protected]>
AuthorDate: Thu Apr 16 09:21:30 2020 +0800
Support left open and right close range in group by (#1056)
* support left open and right close range in group by
---
.../2-DML Data Manipulation Language.md | 35 +++++++--
.../5-Operation Manual/4-SQL Reference.md | 5 +-
.../2-DML Data Manipulation Language.md | 40 ++++++++---
.../5-Operation Manual/4-SQL Reference.md | 11 +--
.../org/apache/iotdb/db/qp/strategy/SqlBase.g4 | 1 +
.../iotdb/db/qp/logical/crud/QueryOperator.java | 10 +++
.../iotdb/db/qp/physical/crud/GroupByPlan.java | 11 +++
.../iotdb/db/qp/strategy/LogicalGenerator.java | 4 +-
.../iotdb/db/qp/strategy/PhysicalGenerator.java | 20 ++++--
.../dataset/groupby/GroupByEngineDataSet.java | 10 +--
.../groupby/GroupByWithValueFilterDataSet.java | 7 +-
.../groupby/GroupByWithoutValueFilterDataSet.java | 7 +-
.../iotdb/db/integration/IoTDBGroupByFillIT.java | 82 +++++++++++++++++++++-
13 files changed, 210 insertions(+), 33 deletions(-)
diff --git a/docs/UserGuide/5-Operation Manual/2-DML Data Manipulation
Language.md b/docs/UserGuide/5-Operation Manual/2-DML Data Manipulation
Language.md
index e8fe509..cab81ad 100644
--- a/docs/UserGuide/5-Operation Manual/2-DML Data Manipulation Language.md
+++ b/docs/UserGuide/5-Operation Manual/2-DML Data Manipulation Language.md
@@ -177,13 +177,13 @@ and value filtering conditions specified.
The SQL statement is:
```
-select count(status), max_value(temperature) from root.ln.wf01.wt01 group by
([2017-11-01T00:00:00, 2017-11-07T23:00:00],1d);
+select count(status), max_value(temperature) from root.ln.wf01.wt01 group by
([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d);
```
which means:
Since the user does not specify the sliding step length, the GROUP BY
statement will by default set the sliding step same as the time interval which
is `1d`.
-The fist parameter of the GROUP BY statement above is the display window
parameter, which determines the final display range is [2017-11-01T00:00:00,
2017-11-07T23:00:00].
+The fist parameter of the GROUP BY statement above is the display window
parameter, which determines the final display range is [2017-11-01T00:00:00,
2017-11-07T23:00:00).
The second parameter of the GROUP BY statement above is the time interval for
dividing the time axis. Taking this parameter (1d) as time interval and
startTime of the display window as the dividing origin, the time axis is
divided into several continuous intervals, which are [0,1d), [1d, 2d), [2d,
3d), etc.
@@ -198,7 +198,7 @@ Since there is data for each time period in the result
range to be displayed, th
The SQL statement is:
```
-select count(status), max_value(temperature) from root.ln.wf01.wt01 group by
([2017-11-01 00:00:00, 2017-11-07 23:00:00], 3h, 1d);
+select count(status), max_value(temperature) from root.ln.wf01.wt01 group by
([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d);
```
which means:
@@ -207,7 +207,7 @@ Since the user specifies the sliding step parameter as 1d,
the GROUP BY statemen
That means we want to fetch all the data of 00:00:00 to 02:59:59 every day
from 2017-11-01 to 2017-11-07.
-The first parameter of the GROUP BY statement above is the display window
parameter, which determines the final display range is [2017-11-01T00:00:00,
2017-11-07T23:00:00].
+The first parameter of the GROUP BY statement above is the display window
parameter, which determines the final display range is [2017-11-01T00:00:00,
2017-11-07T23:00:00).
The second parameter of the GROUP BY statement above is the time interval for
dividing the time axis. Taking this parameter (3h) as time interval and the
startTime of the display window as the dividing origin, the time axis is
divided into several continuous intervals, which are [2017-11-01T00:00:00,
2017-11-01T03:00:00), [2017-11-02T00:00:00, 2017-11-02T03:00:00),
[2017-11-03T00:00:00, 2017-11-03T03:00:00), etc.
@@ -224,13 +224,13 @@ Since there is data for each time period in the result
range to be displayed, th
The SQL statement is:
```
-select count(status), max_value(temperature) from root.ln.wf01.wt01 where time
> 2017-11-01T01:00:00 and temperature > 20 group by([2017-11-01T00:00:00,
2017-11-07T23:00:00], 3h, 1d);
+select count(status), max_value(temperature) from root.ln.wf01.wt01 where time
> 2017-11-01T01:00:00 and temperature > 20 group by([2017-11-01T00:00:00,
2017-11-07T23:00:00), 3h, 1d);
```
which means:
Since the user specifies the sliding step parameter as 1d, the GROUP BY
statement will move the time interval `1 day` long instead of `3 hours` as
default.
-The first parameter of the GROUP BY statement above is the display window
parameter, which determines the final display range is [2017-11-01T00:00:00,
2017-11-07T23:00:00].
+The first parameter of the GROUP BY statement above is the display window
parameter, which determines the final display range is [2017-11-01T00:00:00,
2017-11-07T23:00:00).
The second parameter of the GROUP BY statement above is the time interval for
dividing the time axis. Taking this parameter (3h) as time interval and the
startTime of the display window as the dividing origin, the time axis is
divided into several continuous intervals, which are [2017-11-01T00:00:00,
2017-11-01T03:00:00), [2017-11-02T00:00:00, 2017-11-02T03:00:00),
[2017-11-03T00:00:00, 2017-11-03T03:00:00), etc.
@@ -240,6 +240,29 @@ Then the system will use the time and value filtering
condition in the WHERE cla
<center><img style="width:100%; max-width:800px; max-height:600px;
margin-left:auto; margin-right:auto; display:block;"
src="https://user-images.githubusercontent.com/16079446/69116088-001e2780-0ac6-11ea-9a01-dc45271d1dad.png"></center>
+#### Left Open And Right Close Range
+
+The SQL statement is:
+
+```
+select count(status) from root.ln.wf01.wt01 group by((5, 40], 5ms);
+```
+
+In this sql, the time interval is left open and right close, so we won't
include the value of timestamp 5 and instead we will include the value of
timestamp 40.
+
+We will get the result like following:
+
+| Time | count(root.ln.wf01.wt01.status) |
+| ------ | ------------------------------- |
+| 10 | 1 |
+| 15 | 2 |
+| 20 | 3 |
+| 25 | 4 |
+| 30 | 4 |
+| 35 | 3 |
+| 40 | 5 |
+
+
#### Down-Frequency Aggregate Query with Fill Clause
In group by fill, sliding step is not supported in group by clause
diff --git a/docs/UserGuide/5-Operation Manual/4-SQL Reference.md
b/docs/UserGuide/5-Operation Manual/4-SQL Reference.md
index 627892a..d8a7237 100644
--- a/docs/UserGuide/5-Operation Manual/4-SQL Reference.md
+++ b/docs/UserGuide/5-Operation Manual/4-SQL Reference.md
@@ -271,12 +271,14 @@ RelativeTimeDurationUnit = Integer
('Y'|'MO'|'W'|'D'|'H'|'M'|'S'|'MS'|'US'|'NS')
RelativeTime : (now() | <TimeValue>) [(+|-) RelativeTimeDurationUnit]+
SensorExpr : (<Timeseries> | <Path>) PrecedenceEqualOperator <PointValue>
GroupByClause : LPAREN <TimeInterval> COMMA <TimeUnit> (COMMA <TimeUnit>)?
RPAREN
-TimeInterval: LBRACKET <TimeValue> COMMA <TimeValue> RBRACKET
+TimeInterval: LSBRACKET <TimeValue> COMMA <TimeValue> RRBRACKET | LRBRACKET
<TimeValue> COMMA <TimeValue> RSBRACKET
TimeUnit : Integer <DurationUnit>
DurationUnit : "ms" | "s" | "m" | "h" | "d" | "w"
Eg: SELECT COUNT(status), COUNT(temperature) FROM root.ln.wf01.wt01 where
temperature < 24 GROUP BY([1509465720000, 1509466380000), 5m)
+Eg: SELECT COUNT(status), COUNT(temperature) FROM root.ln.wf01.wt01 where
temperature < 24 GROUP BY((1509465720000, 1509466380000], 5m)
Eg. SELECT COUNT (status), MAX_VALUE(temperature) FROM root.ln.wf01.wt01 WHERE
time < 1509466500000 GROUP BY([1509465720000, 1509466380000), 5m, 10m)
Eg. SELECT MIN_TIME(status), MIN_VALUE(temperature) FROM root.ln.wf01.wt01
WHERE temperature < 25 GROUP BY ([1509466140000, 1509466380000), 3m, 5ms)
+Eg. SELECT MIN_TIME(status), MIN_VALUE(temperature) FROM root.ln.wf01.wt01
WHERE temperature < 25 GROUP BY ((1509466140000, 1509466380000], 3m, 5ms)
Note: the statement needs to satisfy this constraint: <Path>(SelectClause) +
<PrefixPath>(FromClause) = <Timeseries>
Note: If the <SensorExpr>(WhereClause) is started with <Path> and not with
ROOT, the statement needs to satisfy this constraint: <PrefixPath>(FromClause)
+ <Path>(SensorExpr) = <Timeseries>
Note: <TimeValue>(TimeInterval) needs to be greater than 0
@@ -331,6 +333,7 @@ TextClause: TEXT LBRACKET (<PreviousUntilLastClause> |
<PreviousClause>) RBRACK
PreviousClause : PREVIOUS
PreviousUntilLastClause : PREVIOUSUNTILLAST
Eg: SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([20, 100),
5m) FILL (float[PREVIOUS])
+Eg: SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY((15, 100],
5m) FILL (float[PREVIOUS])
Eg: SELECT last_value(power) FROM root.ln.wf01.wt01 GROUP BY([20, 100), 5m)
FILL (int32[PREVIOUSUNTILLAST])
Eg: SELECT last_value(temperature), last_value(power) FROM root.ln.wf01.wt01
GROUP BY([20, 100), 5m) FILL (ALL[PREVIOUS])
Note: In group by fill, sliding step is not supported in group by clause
diff --git a/docs/zh/UserGuide/5-Operation Manual/2-DML Data Manipulation
Language.md b/docs/zh/UserGuide/5-Operation Manual/2-DML Data Manipulation
Language.md
index 1571bee..f1f05b4 100644
--- a/docs/zh/UserGuide/5-Operation Manual/2-DML Data Manipulation Language.md
+++ b/docs/zh/UserGuide/5-Operation Manual/2-DML Data Manipulation Language.md
@@ -201,17 +201,17 @@ GROUP BY语句为用户提供三类指定参数:
对应的SQL语句是:
```
-select count(status), max_value(temperature) from root.ln.wf01.wt01 group by
([2017-11-01T00:00:00, 2017-11-07T23:00:00],1d);
+select count(status), max_value(temperature) from root.ln.wf01.wt01 group by
([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d);
```
这条查询的含义是:
由于用户没有指定滑动步长,滑动步长将会被默认设置为跟时间间隔参数相同,也就是`1d`。
-上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是[2017-11-01T00:00:00, 2017-11-07T23:00:00]。
+上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是[2017-11-01T00:00:00, 2017-11-07T23:00:00)。
上面这个例子的第二个参数是划分时间轴的时间间隔参数,将`1d`当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[0,1d),
[1d, 2d), [2d, 3d)等等。
-然后系统将会用WHERE子句中的时间和值过滤条件以及GROUP
BY语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在[2017-11-01T00:00:00, 2017-11-07
T23:00:00]这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从2017-11-01T00:00:00到2017-11-07T23:00:00:00的每一天)
+然后系统将会用WHERE子句中的时间和值过滤条件以及GROUP
BY语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在[2017-11-01T00:00:00, 2017-11-07
T23:00:00)这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从2017-11-01T00:00:00到2017-11-07T23:00:00:00的每一天)
每个时间间隔窗口内都有数据,SQL执行后的结果集如下所示:
@@ -222,7 +222,7 @@ select count(status), max_value(temperature) from
root.ln.wf01.wt01 group by ([2
对应的SQL语句是:
```
-select count(status), max_value(temperature) from root.ln.wf01.wt01 group by
([2017-11-01 00:00:00, 2017-11-07 23:00:00], 3h, 1d);
+select count(status), max_value(temperature) from root.ln.wf01.wt01 group by
([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d);
```
这条查询的含义是:
@@ -231,13 +231,13 @@ select count(status), max_value(temperature) from
root.ln.wf01.wt01 group by ([2
也就意味着,我们想要取从2017-11-01到2017-11-07每一天的凌晨0点到凌晨3点的数据。
-上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是[2017-11-01T00:00:00, 2017-11-07T23:00:00]。
+上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是[2017-11-01T00:00:00, 2017-11-07T23:00:00)。
上面这个例子的第二个参数是划分时间轴的时间间隔参数,将`3h`当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[2017-11-01T00:00:00,
2017-11-01T03:00:00), [2017-11-02T00:00:00, 2017-11-02T03:00:00),
[2017-11-03T00:00:00, 2017-11-03T03:00:00)等等。
上面这个例子的第三个参数是每次时间间隔的滑动步长。
-然后系统将会用WHERE子句中的时间和值过滤条件以及GROUP
BY语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在[2017-11-01T00:00:00, 2017-11-07
T23:00:00]这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从2017-11-01T00:00:00到2017-11-07T23:00:00:00的每一天的凌晨0点到凌晨3点)
+然后系统将会用WHERE子句中的时间和值过滤条件以及GROUP
BY语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在[2017-11-01T00:00:00, 2017-11-07
T23:00:00)这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从2017-11-01T00:00:00到2017-11-07T23:00:00:00的每一天的凌晨0点到凌晨3点)
每个时间间隔窗口内都有数据,SQL执行后的结果集如下所示:
@@ -248,7 +248,7 @@ select count(status), max_value(temperature) from
root.ln.wf01.wt01 group by ([2
对应的SQL语句是:
```
-select count(status), max_value(temperature) from root.ln.wf01.wt01 where time
> 2017-11-01T01:00:00 and temperature > 20 group by([2017-11-01T00:00:00,
2017-11-07T23:00:00], 3h, 1d);
+select count(status), max_value(temperature) from root.ln.wf01.wt01 where time
> 2017-11-01T01:00:00 and temperature > 20 group by([2017-11-01T00:00:00,
2017-11-07T23:00:00), 3h, 1d);
```
这条查询的含义是:
@@ -257,13 +257,13 @@ select count(status), max_value(temperature) from
root.ln.wf01.wt01 where time >
也就意味着,我们想要取从2017-11-01到2017-11-07每一天的凌晨0点到凌晨3点的数据。
-上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是[2017-11-01T00:00:00, 2017-11-07T23:00:00]。
+上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是[2017-11-01T00:00:00, 2017-11-07T23:00:00)。
上面这个例子的第二个参数是划分时间轴的时间间隔参数,将`3h`当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[2017-11-01T00:00:00,
2017-11-01T03:00:00), [2017-11-02T00:00:00, 2017-11-02T03:00:00),
[2017-11-03T00:00:00, 2017-11-03T03:00:00)等等。
上面这个例子的第三个参数是每次时间间隔的滑动步长。
-然后系统将会用WHERE子句中的时间和值过滤条件以及GROUP
BY语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在[2017-11-01T00:00:00, 2017-11-07
T23:00:00]这个时间范围的并且满足root.ln.wf01.wt01.temperature >
20的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从2017-11-01T00:00:00到2017-11-07T23:00:00:00的每一天的凌晨0点到凌晨3点)
+然后系统将会用WHERE子句中的时间和值过滤条件以及GROUP
BY语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在[2017-11-01T00:00:00, 2017-11-07
T23:00:00)这个时间范围的并且满足root.ln.wf01.wt01.temperature >
20的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从2017-11-01T00:00:00到2017-11-07T23:00:00:00的每一天的凌晨0点到凌晨3点)
每个时间间隔窗口内都有数据,SQL执行后的结果集如下所示:
@@ -273,6 +273,28 @@ GROUP BY的SELECT子句里的查询路径必须是聚合函数,否则系统将
<center><img style="width:100%; max-width:800px; max-height:600px;
margin-left:auto; margin-right:auto; display:block;"
src="https://user-images.githubusercontent.com/16079446/69116099-0b715300-0ac6-11ea-8074-84e04797b8c7.png"></center>
+#### 左开右闭区间
+
+每个区间的结果时间戳为区间右端点,对应的SQL语句是:
+
+```
+select count(status) from root.ln.wf01.wt01 group by((5, 40], 5ms);
+```
+
+这条查询语句的时间区间是左开右闭的,结果中不会包含时间点5的数据,但是会包含时间点40的数据。
+
+SQL执行后的结果集如下所示:
+
+| Time | count(root.ln.wf01.wt01.status) |
+| ------ | ------------------------------- |
+| 10 | 1 |
+| 15 | 2 |
+| 20 | 3 |
+| 25 | 4 |
+| 30 | 4 |
+| 35 | 3 |
+| 40 | 5 |
+
#### 降频聚合查询补空值
降频聚合出的各个时间段的结果,支持使用前值补空。
diff --git a/docs/zh/UserGuide/5-Operation Manual/4-SQL Reference.md
b/docs/zh/UserGuide/5-Operation Manual/4-SQL Reference.md
index 1a55d08..1cf7a53 100644
--- a/docs/zh/UserGuide/5-Operation Manual/4-SQL Reference.md
+++ b/docs/zh/UserGuide/5-Operation Manual/4-SQL Reference.md
@@ -263,12 +263,14 @@ RelativeTimeDurationUnit = Integer
('Y'|'MO'|'W'|'D'|'H'|'M'|'S'|'MS'|'US'|'NS')
RelativeTime : (now() | <TimeValue>) [(+|-) RelativeTimeDurationUnit]+
SensorExpr : (<Timeseries> | <Path>) PrecedenceEqualOperator <PointValue>
GroupByClause : LPAREN <TimeInterval> COMMA <TimeUnit> (COMMA <TimeUnit>)?
RPAREN
-TimeInterval: LBRACKET <TimeValue> COMMA <TimeValue> RBRACKET
+TimeInterval: LSBRACKET <TimeValue> COMMA <TimeValue> RRBRACKET | LRBRACKET
<TimeValue> COMMA <TimeValue> RSBRACKET
TimeUnit : Integer <DurationUnit>
DurationUnit : "ms" | "s" | "m" | "h" | "d" | "w"
-Eg: SELECT COUNT(status), COUNT(temperature) FROM root.ln.wf01.wt01 where
temperature < 24 GROUP BY([1509465720000, 1509466380000], 5m)
-Eg. SELECT COUNT (status), MAX_VALUE(temperature) FROM root.ln.wf01.wt01 WHERE
time < 1509466500000 GROUP BY([1509465720000, 1509466380000], 5m, 10m)
-Eg. SELECT MIN_TIME(status), MIN_VALUE(temperature) FROM root.ln.wf01.wt01
WHERE temperature < 25 GROUP BY ([1509466140000, 1509466380000], 3m, 5ms)
+Eg: SELECT COUNT(status), COUNT(temperature) FROM root.ln.wf01.wt01 where
temperature < 24 GROUP BY([1509465720000, 1509466380000), 5m)
+Eg: SELECT COUNT(status), COUNT(temperature) FROM root.ln.wf01.wt01 where
temperature < 24 GROUP BY((1509465720000, 1509466380000], 5m)
+Eg. SELECT COUNT (status), MAX_VALUE(temperature) FROM root.ln.wf01.wt01 WHERE
time < 1509466500000 GROUP BY([1509465720000, 1509466380000), 5m, 10m)
+Eg. SELECT MIN_TIME(status), MIN_VALUE(temperature) FROM root.ln.wf01.wt01
WHERE temperature < 25 GROUP BY ([1509466140000, 1509466380000), 3m, 5ms)
+Eg. SELECT MIN_TIME(status), MIN_VALUE(temperature) FROM root.ln.wf01.wt01
WHERE temperature < 25 GROUP BY ((1509466140000, 1509466380000], 3m, 5ms)
Note: the statement needs to satisfy this constraint: <Path>(SelectClause) +
<PrefixPath>(FromClause) = <Timeseries>
Note: If the <SensorExpr>(WhereClause) is started with <Path> and not with
ROOT, the statement needs to satisfy this constraint: <PrefixPath>(FromClause)
+ <Path>(SensorExpr) = <Timeseries>
Note: <TimeValue>(TimeInterval) needs to be greater than 0
@@ -323,6 +325,7 @@ TextClause: TEXT LBRACKET (<PreviousUntilLastClause> |
<PreviousClause>) RBRACK
PreviousClause : PREVIOUS
PreviousUntilLastClause : PREVIOUSUNTILLAST
Eg: SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([20, 100),
5m) FILL (float[PREVIOUS])
+Eg: SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY((15, 100],
5m) FILL (float[PREVIOUS])
Eg: SELECT last_value(power) FROM root.ln.wf01.wt01 GROUP BY([20, 100), 5m)
FILL (int32[PREVIOUSUNTILLAST])
Eg: SELECT last_value(temperature), last_value(power) FROM root.ln.wf01.wt01
GROUP BY([20, 100), 5m) FILL (ALL[PREVIOUS])
Note: In group by fill, sliding step is not supported in group by clause
diff --git a/server/src/main/antlr4/org/apache/iotdb/db/qp/strategy/SqlBase.g4
b/server/src/main/antlr4/org/apache/iotdb/db/qp/strategy/SqlBase.g4
index 114bc5f..28c3441 100644
--- a/server/src/main/antlr4/org/apache/iotdb/db/qp/strategy/SqlBase.g4
+++ b/server/src/main/antlr4/org/apache/iotdb/db/qp/strategy/SqlBase.g4
@@ -274,6 +274,7 @@ rootOrId
timeInterval
: LS_BRACKET startTime=timeValue COMMA endTime=timeValue RR_BRACKET
+ | LR_BRACKET startTime=timeValue COMMA endTime=timeValue RS_BRACKET
;
timeValue
diff --git
a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java
b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java
index 204fffe..a2c18cf 100644
---
a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java
+++
b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java
@@ -36,6 +36,8 @@ public class QueryOperator extends SFWOperator {
// sliding step
private long slidingStep;
private boolean isGroupByTime = false;
+ // if it is left close and right open interval
+ private boolean leftCRightO;
private Map<TSDataType, IFill> fillTypes;
private boolean isFill = false;
@@ -77,6 +79,14 @@ public class QueryOperator extends SFWOperator {
this.isGroupByTime = isGroupBy;
}
+ public boolean isLeftCRightO() {
+ return leftCRightO;
+ }
+
+ public void setLeftCRightO(boolean leftCRightO) {
+ this.leftCRightO = leftCRightO;
+ }
+
public int getRowLimit() {
return rowLimit;
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/GroupByPlan.java
b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/GroupByPlan.java
index f2690ac..e47d248 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/GroupByPlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/GroupByPlan.java
@@ -30,6 +30,9 @@ public class GroupByPlan extends AggregationPlan {
// sliding step
private long slidingStep;
+ // if it is left close and right open interval
+ private boolean leftCRightO = true;
+
public GroupByPlan() {
super();
setOperatorType(Operator.OperatorType.GROUPBY);
@@ -66,4 +69,12 @@ public class GroupByPlan extends AggregationPlan {
public void setSlidingStep(long slidingStep) {
this.slidingStep = slidingStep;
}
+
+ public boolean isLeftCRightO() {
+ return leftCRightO;
+ }
+
+ public void setLeftCRightO(boolean leftCRightO) {
+ this.leftCRightO = leftCRightO;
+ }
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
index 358fbbf..45c7775 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
@@ -563,6 +563,8 @@ public class LogicalGenerator extends SqlBaseBaseListener {
super.enterGroupByFillClause(ctx);
queryOp.setGroupBy(true);
queryOp.setFill(true);
+ queryOp.setLeftCRightO(ctx.timeInterval().LS_BRACKET() != null);
+
// parse timeUnit
queryOp.setUnit(parseDuration(ctx.DURATION().getText()));
@@ -623,7 +625,7 @@ public class LogicalGenerator extends SqlBaseBaseListener {
public void enterGroupByClause(GroupByClauseContext ctx) {
super.enterGroupByClause(ctx);
queryOp.setGroupBy(true);
-
+ queryOp.setLeftCRightO(ctx.timeInterval().LS_BRACKET() != null);
// parse timeUnit
queryOp.setUnit(parseDuration(ctx.DURATION(0).getText()));
queryOp.setSlidingStep(queryOp.getUnit());
diff --git
a/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
b/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
index 96d7e8c..d337d21 100644
---
a/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
+++
b/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
@@ -182,8 +182,14 @@ public class PhysicalGenerator {
queryPlan = new GroupByFillPlan();
((GroupByFillPlan) queryPlan).setInterval(queryOperator.getUnit());
((GroupByFillPlan)
queryPlan).setSlidingStep(queryOperator.getSlidingStep());
- ((GroupByFillPlan) queryPlan).setStartTime(queryOperator.getStartTime());
- ((GroupByFillPlan) queryPlan).setEndTime(queryOperator.getEndTime());
+ ((GroupByFillPlan)
queryPlan).setLeftCRightO(queryOperator.isLeftCRightO());
+ if (!queryOperator.isLeftCRightO()) {
+ ((GroupByPlan) queryPlan).setStartTime(queryOperator.getStartTime()+1);
+ ((GroupByPlan) queryPlan).setEndTime(queryOperator.getEndTime()+1);
+ } else {
+ ((GroupByPlan) queryPlan).setStartTime(queryOperator.getStartTime());
+ ((GroupByPlan) queryPlan).setEndTime(queryOperator.getEndTime());
+ }
((GroupByFillPlan) queryPlan)
.setAggregations(queryOperator.getSelectOperator().getAggregations());
for (String aggregation : queryPlan.getAggregations()) {
@@ -196,8 +202,14 @@ public class PhysicalGenerator {
queryPlan = new GroupByPlan();
((GroupByPlan) queryPlan).setInterval(queryOperator.getUnit());
((GroupByPlan) queryPlan).setSlidingStep(queryOperator.getSlidingStep());
- ((GroupByPlan) queryPlan).setStartTime(queryOperator.getStartTime());
- ((GroupByPlan) queryPlan).setEndTime(queryOperator.getEndTime());
+ ((GroupByPlan) queryPlan).setLeftCRightO(queryOperator.isLeftCRightO());
+ if (!queryOperator.isLeftCRightO()) {
+ ((GroupByPlan) queryPlan).setStartTime(queryOperator.getStartTime()+1);
+ ((GroupByPlan) queryPlan).setEndTime(queryOperator.getEndTime()+1);
+ } else {
+ ((GroupByPlan) queryPlan).setStartTime(queryOperator.getStartTime());
+ ((GroupByPlan) queryPlan).setEndTime(queryOperator.getEndTime());
+ }
((GroupByPlan) queryPlan)
.setAggregations(queryOperator.getSelectOperator().getAggregations());
} else if (queryOperator.isFill()) {
diff --git
a/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByEngineDataSet.java
b/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByEngineDataSet.java
index a377597..eaf9d8a 100644
---
a/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByEngineDataSet.java
+++
b/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByEngineDataSet.java
@@ -39,9 +39,10 @@ public abstract class GroupByEngineDataSet extends
QueryDataSet {
// current interval [curStartTime, curEndTime)
protected long curStartTime;
protected long curEndTime;
- protected int usedIndex;
protected boolean hasCachedTimeInterval;
+ protected boolean leftCRightO;
+
public GroupByEngineDataSet() {
}
@@ -55,10 +56,10 @@ public abstract class GroupByEngineDataSet extends
QueryDataSet {
this.slidingStep = groupByPlan.getSlidingStep();
this.startTime = groupByPlan.getStartTime();
this.endTime = groupByPlan.getEndTime();
-
+ this.leftCRightO = groupByPlan.isLeftCRightO();
// init group by time partition
- this.usedIndex = 0;
this.hasCachedTimeInterval = false;
+ this.curStartTime = this.startTime - slidingStep;
this.curEndTime = -1;
}
@@ -69,8 +70,7 @@ public abstract class GroupByEngineDataSet extends
QueryDataSet {
return true;
}
- curStartTime = usedIndex * slidingStep + startTime;
- usedIndex++;
+ curStartTime += slidingStep;
//This is an open interval , [0-100)
if (curStartTime < endTime) {
hasCachedTimeInterval = true;
diff --git
a/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithValueFilterDataSet.java
b/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithValueFilterDataSet.java
index 47a056f..ce1a39e 100644
---
a/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithValueFilterDataSet.java
+++
b/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithValueFilterDataSet.java
@@ -182,7 +182,12 @@ public class GroupByWithValueFilterDataSet extends
GroupByEngineDataSet {
}
private RowRecord constructRowRecord(List<AggregateResult>
aggregateResultList) {
- RowRecord record = new RowRecord(curStartTime);
+ RowRecord record;
+ if (leftCRightO) {
+ record = new RowRecord(curStartTime);
+ } else {
+ record = new RowRecord(curEndTime-1);
+ }
for (int i = 0; i < paths.size(); i++) {
AggregateResult aggregateResult = aggregateResultList.get(i);
record.addField(aggregateResult.getResult(),
aggregateResult.getResultDataType());
diff --git
a/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithoutValueFilterDataSet.java
b/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithoutValueFilterDataSet.java
index 2ee8df5..264ba42 100644
---
a/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithoutValueFilterDataSet.java
+++
b/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithoutValueFilterDataSet.java
@@ -104,7 +104,12 @@ public class GroupByWithoutValueFilterDataSet extends
GroupByEngineDataSet {
+ "in GroupByWithoutValueFilterDataSet.");
}
hasCachedTimeInterval = false;
- RowRecord record = new RowRecord(curStartTime);
+ RowRecord record;
+ if (leftCRightO) {
+ record = new RowRecord(curStartTime);
+ } else {
+ record = new RowRecord(curEndTime-1);
+ }
AggregateResult[] fields = new AggregateResult[paths.size()];
diff --git
a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupByFillIT.java
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupByFillIT.java
index 94825fc..039dd56 100644
---
a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupByFillIT.java
+++
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupByFillIT.java
@@ -124,7 +124,6 @@ public class IoTDBGroupByFillIT {
+ "root.ln.wf01.wt01 "
+ "GROUP BY ([17, 48), 5ms) FILL(int32[previous])");
} catch (IoTDBSQLException e) {
- System.out.println("error message: " + e.getMessage());
assertTrue(e.getMessage().contains("Group By Fill only support
last_value function"));
} catch (Exception e) {
e.printStackTrace();
@@ -219,6 +218,46 @@ public class IoTDBGroupByFillIT {
}
@Test
+ public void leftORightCPreviousTest() {
+ String[] retArray = new String[] {
+ "10,21",
+ "15,25",
+ "20,25",
+ "25,25",
+ "30,26",
+ "35,26",
+ "40,40",
+ };
+
+ try (Connection connection = DriverManager.
+ getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
+ Statement statement = connection.createStatement()) {
+ boolean hasResultSet = statement.execute(
+ "select last_value(temperature) from "
+ + "root.ln.wf01.wt01 "
+ + "GROUP BY ((5, 40], 5ms) FILL(int32[previous])");
+
+ assertTrue(hasResultSet);
+ int cnt;
+ try (ResultSet resultSet = statement.getResultSet()) {
+ cnt = 0;
+ while (resultSet.next()) {
+ String ans = resultSet.getString(TIMESTAMP_STR) + "," + resultSet
+ .getString(last_value("root.ln.wf01.wt01.temperature"));
+ assertEquals(retArray[cnt], ans);
+ cnt++;
+ }
+ assertEquals(retArray.length, cnt);
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ }
+
+ @Test
public void previousAllTest() {
String[] retArray = new String[] {
"2,null,null",
@@ -406,6 +445,47 @@ public class IoTDBGroupByFillIT {
}
@Test
+ public void leftORightCPreviousUntilLastTest() {
+ String[] retArray = new String[] {
+ "9,null",
+ "14,25",
+ "19,25",
+ "24,25",
+ "29,26",
+ "34,26",
+ "39,40",
+ "44,null"
+ };
+
+ try (Connection connection = DriverManager.
+ getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
+ Statement statement = connection.createStatement()) {
+ boolean hasResultSet = statement.execute(
+ "select last_value(temperature) from "
+ + "root.ln.wf01.wt01 "
+ + "GROUP BY ((4, 44], 5ms)
FILL(int32[previousUntilLast])");
+
+ assertTrue(hasResultSet);
+ int cnt;
+ try (ResultSet resultSet = statement.getResultSet()) {
+ cnt = 0;
+ while (resultSet.next()) {
+ String ans = resultSet.getString(TIMESTAMP_STR) + "," + resultSet
+ .getString(last_value("root.ln.wf01.wt01.temperature"));
+ assertEquals(retArray[cnt], ans);
+ cnt++;
+ }
+ assertEquals(retArray.length, cnt);
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ }
+
+ @Test
public void previousUntilLastAllTest() {
String[] retArray = new String[] {
"2,null,null",