This is an automated email from the ASF dual-hosted git repository.
jackietien pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new c5d7999c9c5 Support agg(*) query in templated align by device situation
c5d7999c9c5 is described below
commit c5d7999c9c5621b607576fadbe889746e59809dd
Author: Beyyes <[email protected]>
AuthorDate: Thu Jun 13 18:29:35 2024 +0800
Support agg(*) query in templated align by device situation
---
...oTDBAlignByDeviceWithTemplateAggregationIT.java | 130 ++++++++++++++++++++-
.../plan/analyze/TemplatedAggregationAnalyze.java | 56 +++++++--
.../plan/expression/multi/FunctionExpression.java | 8 ++
3 files changed, 182 insertions(+), 12 deletions(-)
diff --git
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregationIT.java
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregationIT.java
index 5ec4566c54c..6d5d16a40c4 100644
---
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregationIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregationIT.java
@@ -104,7 +104,7 @@ public class IoTDBAlignByDeviceWithTemplateAggregationIT {
// __endTime result is ambiguous
- // not supported: group by session, condition, agg(*), agg(s1+1),
count(s1+s2), non-aligned
+ // not supported: group by session, condition, agg(s1+1), count(s1+s2),
non-aligned
// template
}
@@ -528,6 +528,134 @@ public class IoTDBAlignByDeviceWithTemplateAggregationIT {
"count(s_null) in order by clause doesn't exist.");
}
+ @Test
+ public void wildCardTest() {
+ String[] expectedHeader =
+ new String[] {
+
"Device,max_time(s3),max_time(s1),max_time(s2),last_value(s1),last_value(s3),last_value(s1),last_value(s2)"
+ };
+ String[] retArray =
+ new String[] {
+
"root.sg1.d1,1314000000000,1314000000000,1314000000000,13.14,1314,13.14,true,",
+
"root.sg1.d2,1314000000001,1314000000001,1314000000001,13.15,1315,13.15,false,",
+
"root.sg1.d3,1314000000002,1314000000002,1314000000002,13.16,1316,13.16,false,",
+
"root.sg1.d4,1314000000003,1314000000003,1314000000003,13.14,1314,13.14,true,",
+ };
+ resultSetEqualTest(
+ "SELECT max_time(*), last_value(s1), last_value(*) FROM root.sg1.**
align by device;",
+ expectedHeader,
+ retArray);
+ retArray =
+ new String[] {
+
"root.sg2.d1,1314000000000,1314000000000,1314000000000,13.14,1314,13.14,true,",
+
"root.sg2.d2,1314000000001,1314000000001,1314000000001,13.15,1315,13.15,false,",
+
"root.sg2.d3,1314000000002,1314000000002,1314000000002,13.16,1316,13.16,false,",
+
"root.sg2.d4,1314000000003,1314000000003,1314000000003,13.14,1314,13.14,true,",
+ };
+ resultSetEqualTest(
+ "SELECT max_time(*), last_value(s1), last_value(*) FROM root.sg2.**
align by device;",
+ expectedHeader,
+ retArray);
+
+ // filter test
+ expectedHeader =
+ new String[]
{"Device,max_time(s1),last_value(s3),last_value(s1),last_value(s2),count(s2)"};
+ retArray =
+ new String[] {
+ "root.sg1.d1,1314000000000,1314,13.14,true,3,",
+ "root.sg1.d2,1314000000001,1315,13.15,false,4,",
+ "root.sg1.d3,1314000000002,1316,13.16,false,3,",
+ "root.sg1.d4,1314000000003,1314,13.14,true,4,",
+ };
+ resultSetEqualTest(
+ "SELECT max_time(s1), last_value(*), count(s2) FROM root.sg1.** where
s3>1 align by device;",
+ expectedHeader,
+ retArray);
+ retArray =
+ new String[] {
+ "root.sg2.d1,1314000000000,1314,13.14,true,3,",
+ "root.sg2.d2,1314000000001,1315,13.15,false,4,",
+ "root.sg2.d3,1314000000002,1316,13.16,false,3,",
+ "root.sg2.d4,1314000000003,1314,13.14,true,4,",
+ };
+ resultSetEqualTest(
+ "SELECT max_time(s1), last_value(*), count(s2) FROM root.sg2.** where
s3>1 align by device;",
+ expectedHeader,
+ retArray);
+
+ // sliding window
+ expectedHeader = new String[]
{"Time,Device,last_value(s1),last_value(s2)"};
+ retArray =
+ new String[] {
+ "1,root.sg1.d1,2.2,false,",
+ "1,root.sg1.d2,22.2,false,",
+ "3,root.sg1.d2,50.0,false,",
+ "5,root.sg1.d2,50.0,false,",
+ "7,root.sg1.d3,8.8,false,",
+ "3,root.sg1.d4,5555.5,false,",
+ "5,root.sg1.d4,5555.5,false,",
+ };
+ resultSetEqualTest(
+ "SELECT last_value(*) FROM root.sg1.** where s3+1=1316 or s2=false
group by ([1,10),3ms,2ms) having avg(s1)>0 soffset 1 slimit 2 align by device;",
+ expectedHeader,
+ retArray);
+ retArray =
+ new String[] {
+ "1,root.sg2.d1,2.2,false,",
+ "1,root.sg2.d2,22.2,false,",
+ "3,root.sg2.d2,50.0,false,",
+ "5,root.sg2.d2,50.0,false,",
+ "7,root.sg2.d3,8.8,false,",
+ "3,root.sg2.d4,5555.5,false,",
+ "5,root.sg2.d4,5555.5,false,",
+ };
+ resultSetEqualTest(
+ "SELECT last_value(*) FROM root.sg2.** where s3+1=1316 or s2=false
group by ([1,10),3ms,2ms) having avg(s1)>0 soffset 1 slimit 2 align by device;",
+ expectedHeader,
+ retArray);
+
+ // having
+ expectedHeader =
+ new String[] {
+
"Device,last_value(s3),last_value(s1),last_value(s2),first_value(s3),first_value(s1),first_value(s2)"
+ };
+ retArray =
+ new String[] {
+ "root.sg1.d2,1315,13.15,false,11,11.1,false,",
+ };
+ resultSetEqualTest(
+ "SELECT last_value(*), first_value(*) FROM root.sg1.** where s2=false
having count(s3+s1) > 2 align by device;",
+ expectedHeader,
+ retArray);
+ retArray =
+ new String[] {
+ "root.sg2.d2,1315,13.15,false,11,11.1,false,",
+ };
+ resultSetEqualTest(
+ "SELECT last_value(*), first_value(*) FROM root.sg2.** where s2=false
having count(s3+s1) > 2 align by device;",
+ expectedHeader,
+ retArray);
+
+ // not supported expression: agg1(*)+agg2(*), agg(*)/2
+ expectedHeader = new String[] {"Device,count(s3) + 1,count(s1) +
1,count(s2) + 1"};
+ retArray =
+ new String[] {
+ "root.sg1.d2,5.0,5.0,5.0,",
+ };
+ resultSetEqualTest(
+ "SELECT count(*)+1 FROM root.sg1.** where s2=false having count(s3+s1)
> 2 align by device;",
+ expectedHeader,
+ retArray);
+ retArray =
+ new String[] {
+ "root.sg2.d2,5.0,5.0,5.0,",
+ };
+ resultSetEqualTest(
+ "SELECT count(*)+1 FROM root.sg2.** where s2=false having count(s3+s1)
> 2 align by device;",
+ expectedHeader,
+ retArray);
+ }
+
protected static void insertData() {
try (Connection connection = EnvFactory.getEnv().getConnection();
Statement statement = connection.createStatement()) {
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAggregationAnalyze.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAggregationAnalyze.java
index 6cdcefc77b9..79f8ba0a8c1 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAggregationAnalyze.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAggregationAnalyze.java
@@ -56,6 +56,7 @@ import static
org.apache.iotdb.db.queryengine.plan.analyze.TemplatedAnalyze.anal
import static
org.apache.iotdb.db.queryengine.plan.analyze.TemplatedAnalyze.analyzeFrom;
import static
org.apache.iotdb.db.queryengine.plan.optimization.LimitOffsetPushDown.canPushDownLimitOffsetInGroupByTimeForDevice;
import static
org.apache.iotdb.db.queryengine.plan.optimization.LimitOffsetPushDown.pushDownLimitOffsetInGroupByTimeForDevice;
+import static org.apache.iotdb.db.utils.constant.SqlConstant.COUNT_TIME;
/** Methods in this class are used for aggregation, templated with align by
device situation. */
public class TemplatedAggregationAnalyze {
@@ -143,24 +144,57 @@ public class TemplatedAggregationAnalyze {
Set<Expression> aggregationExpressions = new LinkedHashSet<>();
for (ResultColumn resultColumn :
queryStatement.getSelectComponent().getResultColumns()) {
- if (paginationController.hasCurOffset()) {
- paginationController.consumeOffset();
- } else if (paginationController.hasCurLimit()) {
- Expression selectExpression = resultColumn.getExpression();
+ Expression selectExpression = resultColumn.getExpression();
+
+ if (selectExpression instanceof FunctionExpression
+ && COUNT_TIME.equalsIgnoreCase(
+ ((FunctionExpression) selectExpression).getFunctionName())) {
outputExpressions.add(new Pair<>(selectExpression,
resultColumn.getAlias()));
selectExpressions.add(selectExpression);
aggregationExpressions.add(selectExpression);
+
+ analysis.getExpressionTypes().put(NodeRef.of(selectExpression),
TSDataType.INT64);
+ ((FunctionExpression) selectExpression)
+ .setExpressions(Collections.singletonList(new TimestampOperand()));
+ continue;
+ }
+
+ List<Expression> subExpressions;
+ if (selectExpression.getOutputSymbol().contains("*")) {
+ // when exist wildcard, only support agg(*) and count_time(*)
if (selectExpression instanceof FunctionExpression
- && "count_time"
- .equalsIgnoreCase(((FunctionExpression)
selectExpression).getFunctionName())) {
- analysis.getExpressionTypes().put(NodeRef.of(selectExpression),
TSDataType.INT64);
- ((FunctionExpression) selectExpression)
- .setExpressions(Collections.singletonList(new
TimestampOperand()));
+ && selectExpression.getExpressions().size() == 1
+ &&
"*".equalsIgnoreCase(selectExpression.getExpressions().get(0).getOutputSymbol()))
{
+ subExpressions = new ArrayList<>();
+ FunctionExpression functionExpression = (FunctionExpression)
selectExpression;
+ for (String measurement : template.getSchemaMap().keySet()) {
+ FunctionExpression subFunctionExpression =
+ new FunctionExpression(
+ functionExpression.getFunctionName(),
+ functionExpression.getFunctionAttributes(),
+ Collections.singletonList(
+ new TimeSeriesOperand(new PartialPath(new String[]
{measurement}))));
+
subFunctionExpression.setFunctionType(functionExpression.getFunctionType());
+ subExpressions.add(subFunctionExpression);
+ }
} else {
- analyzeExpressionType(analysis, selectExpression);
+ return false;
}
} else {
- break;
+ subExpressions = Collections.singletonList(selectExpression);
+ }
+
+ for (Expression expression : subExpressions) {
+ if (paginationController.hasCurOffset()) {
+ paginationController.consumeOffset();
+ } else if (paginationController.hasCurLimit()) {
+ outputExpressions.add(new Pair<>(expression,
resultColumn.getAlias()));
+ selectExpressions.add(expression);
+ aggregationExpressions.add(expression);
+ analyzeExpressionType(analysis, expression);
+ } else {
+ break;
+ }
}
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/multi/FunctionExpression.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/multi/FunctionExpression.java
index a17864ff3be..27ff875efd0 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/multi/FunctionExpression.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/multi/FunctionExpression.java
@@ -193,6 +193,14 @@ public class FunctionExpression extends Expression {
this.expressions = expressions;
}
+ public FunctionType getFunctionType() {
+ return functionType;
+ }
+
+ public void setFunctionType(FunctionType functionType) {
+ this.functionType = functionType;
+ }
+
public String getFunctionName() {
return functionName;
}