This is an automated email from the ASF dual-hosted git repository.
caogaofei pushed a commit to branch beyyes/count_time_fe
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/beyyes/count_time_fe by this
push:
new 3803e514e3a add support for count time
3803e514e3a is described below
commit 3803e514e3a8367d90d638ce82013946235d908f
Author: Beyyes <[email protected]>
AuthorDate: Sun Jul 30 14:03:56 2023 +0800
add support for count time
---
.../queryengine/plan/analyze/AnalyzeVisitor.java | 48 +++++++++++++++++++++-
.../plan/analyze/ExpressionAnalyzer.java | 2 +
.../cartesian/BindSchemaForExpressionVisitor.java | 1 +
.../plan/planner/OperatorTreeGenerator.java | 18 +++++---
.../plan/statement/crud/QueryStatement.java | 23 +++++++++++
.../queryengine/plan/analyze/AnalyzeFailTest.java | 13 ++++++
.../datanode1conf/iotdb-common.properties | 1 +
.../datanode2conf/iotdb-common.properties | 1 +
.../datanode3conf/iotdb-common.properties | 1 +
.../udf/builtin/BuiltinAggregationFunction.java | 1 +
10 files changed, 103 insertions(+), 6 deletions(-)
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
index 66f6628b4df..c2abcc27336 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
@@ -51,6 +51,7 @@ import
org.apache.iotdb.db.protocol.client.ConfigNodeClientManager;
import org.apache.iotdb.db.protocol.client.ConfigNodeInfo;
import org.apache.iotdb.db.protocol.session.SessionManager;
import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
+import org.apache.iotdb.db.queryengine.common.NodeRef;
import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant;
import org.apache.iotdb.db.queryengine.common.header.DatasetHeader;
@@ -68,6 +69,7 @@ import
org.apache.iotdb.db.queryengine.plan.expression.ExpressionType;
import
org.apache.iotdb.db.queryengine.plan.expression.binary.CompareBinaryExpression;
import org.apache.iotdb.db.queryengine.plan.expression.leaf.ConstantOperand;
import org.apache.iotdb.db.queryengine.plan.expression.leaf.TimeSeriesOperand;
+import org.apache.iotdb.db.queryengine.plan.expression.leaf.TimestampOperand;
import
org.apache.iotdb.db.queryengine.plan.expression.multi.FunctionExpression;
import
org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.DeviceViewIntoPathDescriptor;
import
org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.FillDescriptor;
@@ -197,6 +199,7 @@ import static
org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet.SCHE
import static
org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetDevice;
import static
org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetMeasurement;
import static
org.apache.iotdb.db.queryengine.plan.analyze.SelectIntoUtils.constructTargetPath;
+import static
org.apache.iotdb.db.queryengine.plan.statement.component.ResultColumn.ColumnType.AGGREGATION;
import static
org.apache.iotdb.db.schemaengine.schemaregion.view.visitor.GetSourcePathsVisitor.getSourcePaths;
/** This visitor is used to analyze each type of Statement and returns the
{@link Analysis}. */
@@ -517,6 +520,46 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
for (ResultColumn resultColumn :
queryStatement.getSelectComponent().getResultColumns()) {
List<Pair<Expression, String>> outputExpressions = new ArrayList<>();
+ if (AGGREGATION.equals(resultColumn.getColumnType())) {
+ if (resultColumn.getExpression() instanceof FunctionExpression) {
+ FunctionExpression fc = (FunctionExpression)
resultColumn.getExpression();
+ if ("count_time".equals(fc.getFunctionName())) {
+
+ List<Expression> resultExpressions =
+ ExpressionAnalyzer.bindSchemaForExpression(
+ resultColumn.getExpression().getExpressions().get(0),
schemaTree);
+
+ Set<Expression> source = analysis.getSourceExpressions();
+ if (source == null) {
+ source = new HashSet<>();
+ }
+ for (Expression e : resultExpressions) {
+ TimeSeriesOperand ts = (TimeSeriesOperand) e;
+ Expression normalizedExpression =
ExpressionAnalyzer.normalizeExpression(e);
+ analyzeExpressionType(analysis, normalizedExpression);
+
+ checkAliasUniqueness(resultColumn.getAlias(), aliasSet);
+ source.add(normalizedExpression);
+ }
+ analysis.setSourceExpressions(source);
+
+ Expression expression =
+ new FunctionExpression(
+ "count_time",
+ new LinkedHashMap<>(),
+ Collections.singletonList(new TimestampOperand()));
+
+ Map<NodeRef<Expression>, TSDataType> dataTypeMap = new HashMap<>();
+ dataTypeMap.put(new NodeRef<>(expression), TSDataType.INT64);
+ analysis.addTypes(dataTypeMap);
+
+ outputExpressions.add(new Pair<>(expression,
resultColumn.getAlias()));
+ outputExpressionMap.put(columnIndex++, outputExpressions);
+ continue;
+ }
+ }
+ }
+
List<Expression> resultExpressions =
ExpressionAnalyzer.bindSchemaForExpression(resultColumn.getExpression(),
schemaTree);
for (Expression expression : resultExpressions) {
@@ -1187,7 +1230,10 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
}
private void analyzeSource(Analysis analysis, QueryStatement queryStatement)
{
- Set<Expression> sourceExpressions = new HashSet<>();
+ Set<Expression> sourceExpressions = analysis.getSourceExpressions();
+ if (sourceExpressions == null) {
+ sourceExpressions = new HashSet<>();
+ }
for (Expression expression : analysis.getSourceTransformExpressions()) {
sourceExpressions.addAll(ExpressionAnalyzer.searchSourceExpressions(expression));
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ExpressionAnalyzer.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ExpressionAnalyzer.java
index 886d284edd2..28b86e4a3d4 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ExpressionAnalyzer.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ExpressionAnalyzer.java
@@ -698,6 +698,8 @@ public class ExpressionAnalyzer {
return true;
} else if (expression instanceof CaseWhenThenExpression) {
return true;
+ } else if (expression instanceof TimestampOperand) {
+ return false;
} else {
throw new UnknownExpressionTypeException(expression.getExpressionType());
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/cartesian/BindSchemaForExpressionVisitor.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/cartesian/BindSchemaForExpressionVisitor.java
index 4c49886e509..e756206e98d 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/cartesian/BindSchemaForExpressionVisitor.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/cartesian/BindSchemaForExpressionVisitor.java
@@ -47,6 +47,7 @@ public class BindSchemaForExpressionVisitor extends
CartesianProductVisitor<ISch
@Override
public List<Expression> visitFunctionExpression(
FunctionExpression functionExpression, ISchemaTree schemaTree) {
+
// One by one, remove the wildcards from the input expressions. In most
cases, an expression
// will produce multiple expressions after removing the wildcards. We use
extendedExpressions
// to collect the produced expressions.
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
index 53c0b850e89..e036c87f2db 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
@@ -1561,7 +1561,14 @@ public class OperatorTreeGenerator extends
PlanVisitor<Operator, LocalExecutionP
for (List<String> inputColumnNamesOfOneInput : inputColumnNames) {
// it may include double parts
List<List<InputLocation>> inputLocationParts = new ArrayList<>();
- inputColumnNamesOfOneInput.forEach(o ->
inputLocationParts.add(layout.get(o)));
+ // inputColumnNamesOfOneInput.forEach(o ->
inputLocationParts.add(layout.get(o)));
+ for (String input : inputColumnNamesOfOneInput) {
+ if ("Time".equals(input)) {
+ inputLocationParts.addAll(layout.values());
+ } else {
+ inputLocationParts.add(layout.get(input));
+ }
+ }
for (int i = 0; i < inputLocationParts.get(0).size(); i++) {
if (inputColumnNamesOfOneInput.size() == 1) {
inputLocationList.add(new InputLocation[]
{inputLocationParts.get(0).get(i)});
@@ -2392,11 +2399,12 @@ public class OperatorTreeGenerator extends
PlanVisitor<Operator, LocalExecutionP
Map<String, List<InputLocation>> outputMappings = new LinkedHashMap<>();
int tsBlockIndex = 0;
for (PlanNode childNode : node.getChildren()) {
- outputMappings
- .computeIfAbsent(TimestampOperand.TIMESTAMP_EXPRESSION_STRING, key
-> new ArrayList<>())
- .add(new InputLocation(tsBlockIndex, -1));
+ // outputMappings
+ //
.computeIfAbsent(TimestampOperand.TIMESTAMP_EXPRESSION_STRING, key -> new
+ // ArrayList<>())
+ // .add(new InputLocation(tsBlockIndex, -1));
int valueColumnIndex = 0;
- valueColumnIndex++;
+ // valueColumnIndex++;
for (String columnName : childNode.getOutputColumnNames()) {
outputMappings
.computeIfAbsent(columnName, key -> new ArrayList<>())
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/QueryStatement.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/QueryStatement.java
index 973414be8e1..6339bcb30e7 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/QueryStatement.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/QueryStatement.java
@@ -468,6 +468,12 @@ public class QueryStatement extends Statement {
public static final String RAW_AGGREGATION_HYBRID_QUERY_ERROR_MSG =
"Raw data and aggregation hybrid query is not supported.";
+ public static final String COUNT_TIME_NOT_SUPPORT_GROUP_BY_LEVEL =
+ "Count_time aggregation function using with group by level is not
supported.";
+
+ public static final String COUNT_TIME_NOT_SUPPORT_GROUP_BY_TAG =
+ "Count_time aggregation function using with group by tag is not
supported.";
+
@SuppressWarnings({"squid:S3776", "squid:S6541"}) // Suppress high Cognitive
Complexity warning
public void semanticCheck() {
if (isAggregationQuery()) {
@@ -480,16 +486,33 @@ public class QueryStatement extends Statement {
if (isGroupByTag() && isAlignByDevice()) {
throw new SemanticException("GROUP BY TAGS does not support align by
device now.");
}
+ boolean hasCountTimeAggregation = false;
Set<String> outputColumn = new HashSet<>();
for (ResultColumn resultColumn : selectComponent.getResultColumns()) {
if (resultColumn.getColumnType() !=
ResultColumn.ColumnType.AGGREGATION) {
throw new SemanticException(RAW_AGGREGATION_HYBRID_QUERY_ERROR_MSG);
}
+ if (resultColumn.getExpression() instanceof FunctionExpression
+ && "count_time"
+ .equalsIgnoreCase(
+ ((FunctionExpression)
resultColumn.getExpression()).getFunctionName())) {
+ hasCountTimeAggregation = true;
+ }
outputColumn.add(
resultColumn.getAlias() != null
? resultColumn.getAlias()
: resultColumn.getExpression().getExpressionString());
}
+
+ if (hasCountTimeAggregation) {
+ if (isGroupByLevel()) {
+ throw new SemanticException(COUNT_TIME_NOT_SUPPORT_GROUP_BY_LEVEL);
+ }
+ if (isGroupByTag()) {
+ throw new SemanticException(COUNT_TIME_NOT_SUPPORT_GROUP_BY_TAG);
+ }
+ }
+
for (Expression expression : getExpressionSortItemList()) {
if (!hasAggregationFunction(expression)) {
throw new SemanticException(RAW_AGGREGATION_HYBRID_QUERY_ERROR_MSG);
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeFailTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeFailTest.java
index b287fa723c9..c587000d70d 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeFailTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeFailTest.java
@@ -35,6 +35,8 @@ import static
org.apache.iotdb.db.queryengine.plan.statement.component.IntoCompo
import static
org.apache.iotdb.db.queryengine.plan.statement.component.IntoComponent.FORBID_PLACEHOLDER_ERROR_MSG;
import static
org.apache.iotdb.db.queryengine.plan.statement.component.IntoComponent.PATH_NUM_MISMATCH_ERROR_MSG;
import static
org.apache.iotdb.db.queryengine.plan.statement.component.IntoComponent.PLACEHOLDER_MISMATCH_ERROR_MSG;
+import static
org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement.COUNT_TIME_NOT_SUPPORT_GROUP_BY_LEVEL;
+import static
org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement.COUNT_TIME_NOT_SUPPORT_GROUP_BY_TAG;
import static org.junit.Assert.fail;
public class AnalyzeFailTest {
@@ -150,6 +152,17 @@ public class AnalyzeFailTest {
PLACEHOLDER_MISMATCH_ERROR_MSG);
}
+ @Test
+ public void countTimeTest() {
+ assertAnalyzeSemanticException(
+ "select count_time(*) from root.sg.* group by level=1;",
+ COUNT_TIME_NOT_SUPPORT_GROUP_BY_LEVEL);
+
+ assertAnalyzeSemanticException(
+ "select count_time(*) from root.sg.* group by tags(key);",
+ COUNT_TIME_NOT_SUPPORT_GROUP_BY_TAG);
+ }
+
private void assertAnalyzeSemanticException(String sql, String message) {
try {
Analyzer analyzer =
diff --git
a/iotdb-core/datanode/src/test/resources/datanode1conf/iotdb-common.properties
b/iotdb-core/datanode/src/test/resources/datanode1conf/iotdb-common.properties
index 81deacc7880..cdaa6ea06e4 100644
---
a/iotdb-core/datanode/src/test/resources/datanode1conf/iotdb-common.properties
+++
b/iotdb-core/datanode/src/test/resources/datanode1conf/iotdb-common.properties
@@ -22,3 +22,4 @@ udf_lib_dir=target/datanode1/ext/udf
trigger_lib_dir=target/datanode1/ext/trigger
pipe_lib_dir=target/datanode1/ext/pipe
enable_data_partition_inherit_policy=false
+query_timeout_threshold=60000000
diff --git
a/iotdb-core/datanode/src/test/resources/datanode2conf/iotdb-common.properties
b/iotdb-core/datanode/src/test/resources/datanode2conf/iotdb-common.properties
index 9226f2b261d..21cb2ca5079 100644
---
a/iotdb-core/datanode/src/test/resources/datanode2conf/iotdb-common.properties
+++
b/iotdb-core/datanode/src/test/resources/datanode2conf/iotdb-common.properties
@@ -22,3 +22,4 @@ udf_lib_dir=target/datanode2/ext/udf
trigger_lib_dir=target/datanode2/ext/trigger
pipe_lib_dir=target/datanode2/ext/pipe
enable_data_partition_inherit_policy=false
+query_timeout_threshold=60000000
diff --git
a/iotdb-core/datanode/src/test/resources/datanode3conf/iotdb-common.properties
b/iotdb-core/datanode/src/test/resources/datanode3conf/iotdb-common.properties
index 3098cb6ae22..f6038243dc6 100644
---
a/iotdb-core/datanode/src/test/resources/datanode3conf/iotdb-common.properties
+++
b/iotdb-core/datanode/src/test/resources/datanode3conf/iotdb-common.properties
@@ -22,4 +22,5 @@ udf_lib_dir=target/datanode3/ext/udf
trigger_lib_dir=target/datanode3/ext/trigger
pipe_lib_dir=target/datanode3/ext/pipe
enable_data_partition_inherit_policy=false
+query_timeout_threshold=60000000
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinAggregationFunction.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinAggregationFunction.java
index a1b8a6560e9..1afda7f2a53 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinAggregationFunction.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinAggregationFunction.java
@@ -105,6 +105,7 @@ public enum BuiltinAggregationFunction {
case "mode":
return true;
case "count_if":
+ case "count_time":
return false;
default:
throw new IllegalArgumentException("Invalid Aggregation function: " +
name);