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);

Reply via email to