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 7c7e21bbd7 [IOTDB-3600] [IOTDB-3605] [IOTDB-3625] Fix semantic check 
issue about UDF&expression in MPP (#6471)
7c7e21bbd7 is described below

commit 7c7e21bbd74639146f197774ae7f3c6e6ddc8b42
Author: liuminghui233 <[email protected]>
AuthorDate: Mon Jul 4 15:04:27 2022 +0800

    [IOTDB-3600] [IOTDB-3605] [IOTDB-3625] Fix semantic check issue about 
UDF&expression in MPP (#6471)
---
 .../org/apache/iotdb/db/it/IoTDBNestedQueryIT.java |  26 +---
 .../iotdb/db/it/udf/IoTDBUDTFHybridQueryIT.java    | 145 +++++++++++++++++----
 .../db/mpp/plan/analyze/ExpressionAnalyzer.java    |  69 ++++++----
 .../plan/expression/multi/FunctionExpression.java  |   2 +-
 .../iotdb/db/mpp/plan/parser/ASTVisitor.java       |   3 +-
 5 files changed, 168 insertions(+), 77 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBNestedQueryIT.java 
b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBNestedQueryIT.java
index 4f1f57386c..9110a2c7e4 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBNestedQueryIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBNestedQueryIT.java
@@ -128,9 +128,7 @@ public class IoTDBNestedQueryIT {
     }
   }
 
-  // todo: remove ignore after iotdb-3349 is merged
   @Test
-  @Ignore
   public void testNestedArithmeticExpressions() {
     String sqlStr =
         "select d1.s1, d2.s2, d1.s1 + d1.s2 - (d2.s1 + d2.s2), d1.s2 * (d2.s1 
/ d1.s1), d1.s2 + d1.s2 * d2.s1 - d2.s1, d1.s1 - (d1.s1 - (-d1.s1)), (-d2.s1) * 
(-d2.s2) / (-d1.s2) from root.vehicle";
@@ -161,8 +159,6 @@ public class IoTDBNestedQueryIT {
     }
   }
 
-  // todo: remove ignore after iotdb-3349 is merged
-  @Ignore
   @Test
   public void testNestedRowByRowUDFExpressions() {
     String sqlStr =
@@ -194,8 +190,6 @@ public class IoTDBNestedQueryIT {
     }
   }
 
-  // todo: remove ignore after iotdb-3349 is merged
-  @Ignore
   @Test
   public void testUDFTerminateMethodInNestedExpressions() {
     String sqlStr =
@@ -223,8 +217,6 @@ public class IoTDBNestedQueryIT {
     }
   }
 
-  // todo: remove ignore after iotdb-3349 is merged
-  @Ignore
   @Test
   public void testUDFWithMultiInputsInNestedExpressions() {
     String sqlStr =
@@ -372,8 +364,6 @@ public class IoTDBNestedQueryIT {
     }
   }
 
-  // todo: remove ignore after iotdb-3349 is merged
-  @Ignore
   @Test
   public void testInvalidNestedBuiltInAggregation() {
     try (Connection connection = EnvFactory.getEnv().getConnection();
@@ -392,9 +382,7 @@ public class IoTDBNestedQueryIT {
     }
   }
 
-  // todo: Exception: Constant is not supported
   @Test
-  @Ignore
   public void testRawDataQueryWithConstants() {
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
@@ -424,8 +412,6 @@ public class IoTDBNestedQueryIT {
     }
   }
 
-  // todo: remove ignore after iotdb-3349 is merged
-  @Ignore
   @Test
   public void testDuplicatedRawDataQueryWithConstants() {
     try (Connection connection = EnvFactory.getEnv().getConnection();
@@ -447,8 +433,6 @@ public class IoTDBNestedQueryIT {
     }
   }
 
-  // todo: remove ignore after iotdb-3349 is merged
-  @Ignore
   @Test
   public void testCommutativeLaws() {
     try (Connection connection = EnvFactory.getEnv().getConnection();
@@ -473,9 +457,7 @@ public class IoTDBNestedQueryIT {
     }
   }
 
-  // todo: Exception: Constant is not supported
   @Test
-  @Ignore
   public void testAssociativeLaws() {
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
@@ -502,9 +484,7 @@ public class IoTDBNestedQueryIT {
     }
   }
 
-  // todo: Exception: Constant is not supported
   @Test
-  @Ignore
   public void testDistributiveLaw() {
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
@@ -529,9 +509,7 @@ public class IoTDBNestedQueryIT {
     }
   }
 
-  // todo: Exception: Constant is not supported
   @Test
-  @Ignore
   public void testOrderOfArithmeticOperations() {
     // Priority from high to low:
     //   1. exponentiation and root extraction (not supported yet)
@@ -642,8 +620,6 @@ public class IoTDBNestedQueryIT {
     }
   }
 
-  // todo: remove ignore after iotdb-3349 is merged
-  @Ignore
   @Test
   public void testRegularLikeInExpressions() {
     try (Connection connection = EnvFactory.getEnv().getConnection();
@@ -664,7 +640,7 @@ public class IoTDBNestedQueryIT {
   }
 
   @Test
-  @Ignore
+  @Ignore // not supported in 0.13
   public void testTimeExpressions() {
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/udf/IoTDBUDTFHybridQueryIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/udf/IoTDBUDTFHybridQueryIT.java
index 525b641926..e915f455df 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/udf/IoTDBUDTFHybridQueryIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/udf/IoTDBUDTFHybridQueryIT.java
@@ -32,9 +32,12 @@ import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
 import java.sql.Connection;
+import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
 
+import static org.apache.iotdb.itbase.constant.TestConstant.TIMESTAMP_STR;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -56,6 +59,8 @@ public class IoTDBUDTFHybridQueryIT {
       statement.execute("SET STORAGE GROUP TO root.vehicle");
       statement.execute("CREATE TIMESERIES root.vehicle.d1.s1 with 
datatype=INT32,encoding=PLAIN");
       statement.execute("CREATE TIMESERIES root.vehicle.d1.s2 with 
datatype=INT32,encoding=PLAIN");
+      statement.execute("CREATE TIMESERIES root.vehicle.d2.s1 with 
datatype=INT32,encoding=PLAIN");
+      statement.execute("CREATE TIMESERIES root.vehicle.d2.s2 with 
datatype=INT32,encoding=PLAIN");
     } catch (SQLException throwable) {
       fail(throwable.getMessage());
     }
@@ -64,10 +69,21 @@ public class IoTDBUDTFHybridQueryIT {
   private static void generateData() {
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
-      for (int i = 0; i < 10; ++i) {
+      for (int i = 0; i < 5; ++i) {
         statement.execute(
             (String.format(
                 "insert into root.vehicle.d1(timestamp,s1,s2) 
values(%d,%d,%d)", i, i, i)));
+        statement.execute(
+            (String.format(
+                "insert into root.vehicle.d2(timestamp,s1,s2) 
values(%d,%d,%d)", i, i, i)));
+      }
+      for (int i = 2; i < 4; ++i) {
+        statement.execute(
+            (String.format("insert into root.vehicle.d1(timestamp,s3) 
values(%d,%d)", i, i)));
+      }
+      for (int i = 7; i < 10; ++i) {
+        statement.execute(
+            (String.format("insert into root.vehicle.d1(timestamp,s3) 
values(%d,%d)", i, i)));
       }
     } catch (SQLException throwable) {
       fail(throwable.getMessage());
@@ -89,7 +105,6 @@ public class IoTDBUDTFHybridQueryIT {
     EnvFactory.getEnv().cleanAfterClass();
   }
 
-  @Ignore
   @Test
   public void testUserDefinedBuiltInHybridAggregationQuery() {
     String sql =
@@ -101,33 +116,85 @@ public class IoTDBUDTFHybridQueryIT {
         Statement statement = connection.createStatement()) {
       statement.executeQuery(sql);
       fail();
+    } catch (SQLException e) {
+      assertTrue(e.getMessage(), e.getMessage().contains("not supported"));
+    }
+  }
+
+  @Test
+  public void testUserDefinedBuiltInHybridAggregationQuery2() {
+    String[] retArray = new String[] 
{"0,2.0,0.9092974268256817,3.0,-10.0,12.0"};
+
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      try (ResultSet resultSet =
+          statement.executeQuery(
+              "select avg(s1), sin(avg(s2)), avg(s1) + 1, -sum(s2), avg(s1) + 
sum(s2) from root.vehicle.d1")) {
+        int cnt = 0;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString("avg(root.vehicle.d1.s1)")
+                  + ","
+                  + resultSet.getString("sin(avg(root.vehicle.d1.s2))")
+                  + ","
+                  + resultSet.getString("avg(root.vehicle.d1.s1) + 1")
+                  + ","
+                  + resultSet.getString("-sum(root.vehicle.d1.s2)")
+                  + ","
+                  + resultSet.getString("avg(root.vehicle.d1.s1) + 
sum(root.vehicle.d1.s2)");
+          assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        assertEquals(retArray.length, cnt);
+      }
     } catch (SQLException throwable) {
-      assertTrue(
-          throwable
-              .getMessage()
-              .contains("User-defined and built-in hybrid aggregation is not 
supported together."));
+      throwable.printStackTrace();
+      fail(throwable.getMessage());
     }
   }
 
-  @Ignore
   @Test
+  @Ignore // TODO fill function incompatible
   public void testUserDefinedFunctionFillFunctionHybridQuery() {
-    String sql =
-        String.format(
-            "select temperature, counter(temperature, '%s'='%s') from 
root.sgcc.wf03.wt01 where time = 2017-11-01T16:37:50.000 fill(float [linear, 
1m, 1m])",
-            UDFTestConstant.ACCESS_STRATEGY_KEY, 
UDFTestConstant.ACCESS_STRATEGY_ROW_BY_ROW);
+    String[] retArray =
+        new String[] {
+          "0,0.0,1.0,3.14",
+          "1,0.8414709848078965,2.0,3.14",
+          "2,0.9092974268256817,3.0,2.0",
+          "3,0.1411200080598672,4.0,3.0",
+          "4,-0.7568024953079282,5.0,3.14",
+          "7,3.14,3.14,7.0",
+          "8,3.14,3.14,8.0",
+          "9,3.14,3.14,9.0"
+        };
 
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
-      statement.executeQuery(sql);
-      fail();
+      try (ResultSet resultSet =
+          statement.executeQuery("select sin(s1), s1 + 1, s3 from 
root.vehicle.d1 fill(3.14)")) {
+        int cnt = 0;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString("sin(root.vehicle.d1.s1)")
+                  + ","
+                  + resultSet.getString("root.vehicle.d1.s1 + 1")
+                  + ","
+                  + resultSet.getString("root.vehicle.d1.s3");
+          assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        assertEquals(retArray.length, cnt);
+      }
     } catch (SQLException throwable) {
-      assertTrue(
-          throwable.getMessage().contains("Fill functions are not supported in 
UDF queries."));
+      throwable.printStackTrace();
+      fail(throwable.getMessage());
     }
   }
 
-  @Ignore
   @Test
   public void testLastUserDefinedFunctionQuery() {
     String sql =
@@ -145,23 +212,45 @@ public class IoTDBUDTFHybridQueryIT {
     }
   }
 
-  @Ignore
   @Test
+  @Ignore // TODO remove after IOTDB-3674
   public void testUserDefinedFunctionAlignByDeviceQuery() {
-    String sql =
-        String.format(
-            "select adder(temperature), counter(temperature, '%s'='%s') from 
root.sgcc.wf03.wt01 align by device",
-            UDFTestConstant.ACCESS_STRATEGY_KEY, 
UDFTestConstant.ACCESS_STRATEGY_ROW_BY_ROW);
+    String[] retArray =
+        new String[] {
+          "0,root.vehicle.d1,1.0,0.0",
+          "1,root.vehicle.d1,2.0,0.8414709848078965",
+          "2,root.vehicle.d1,3.0,0.9092974268256817",
+          "3,root.vehicle.d1,4.0,0.1411200080598672",
+          "4,root.vehicle.d1,5.0,0.1411200080598672",
+          "0,root.vehicle.d2,1.0,0.0",
+          "1,root.vehicle.d2,2.0,0.8414709848078965",
+          "2,root.vehicle.d2,3.0,0.9092974268256817",
+          "3,root.vehicle.d2,4.0,0.1411200080598672",
+          "4,root.vehicle.d2,5.0,0.1411200080598672"
+        };
 
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
-      statement.executeQuery(sql);
-      fail();
-    } catch (SQLException throwable) {
-      assertTrue(
-          throwable
-              .getMessage()
-              .contains("ALIGN BY DEVICE clause is not supported in UDF 
queries."));
+      try (ResultSet resultSet =
+          statement.executeQuery("select s1 + 1, sin(s2) from root.vehicle.* 
align by device")) {
+        int cnt = 0;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString("Device")
+                  + ","
+                  + resultSet.getString("s1 + 1")
+                  + ","
+                  + resultSet.getString("sin(s2)");
+          assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        assertEquals(retArray.length, cnt);
+      }
+    } catch (SQLException e) {
+      e.printStackTrace();
+      fail(e.getMessage());
     }
   }
 }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionAnalyzer.java
 
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionAnalyzer.java
index 100e8f2390..3569ba75f1 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionAnalyzer.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionAnalyzer.java
@@ -118,14 +118,15 @@ public class ExpressionAnalyzer {
    * @param expression expression to be checked
    * @return true if this expression is valid
    */
-  public static ResultColumn.ColumnType identifyOutputColumnType(Expression 
expression) {
+  public static ResultColumn.ColumnType identifyOutputColumnType(
+      Expression expression, boolean isRoot) {
     if (expression instanceof TernaryExpression) {
       ResultColumn.ColumnType firstType =
-          identifyOutputColumnType(((TernaryExpression) 
expression).getFirstExpression());
+          identifyOutputColumnType(((TernaryExpression) 
expression).getFirstExpression(), false);
       ResultColumn.ColumnType secondType =
-          identifyOutputColumnType(((TernaryExpression) 
expression).getSecondExpression());
+          identifyOutputColumnType(((TernaryExpression) 
expression).getSecondExpression(), false);
       ResultColumn.ColumnType thirdType =
-          identifyOutputColumnType(((TernaryExpression) 
expression).getThirdExpression());
+          identifyOutputColumnType(((TernaryExpression) 
expression).getThirdExpression(), false);
       boolean rawFlag = false, aggregationFlag = false;
       if (firstType == ResultColumn.ColumnType.RAW
           || secondType == ResultColumn.ColumnType.RAW
@@ -146,9 +147,9 @@ public class ExpressionAnalyzer {
       return thirdType;
     } else if (expression instanceof BinaryExpression) {
       ResultColumn.ColumnType leftType =
-          identifyOutputColumnType(((BinaryExpression) 
expression).getLeftExpression());
+          identifyOutputColumnType(((BinaryExpression) 
expression).getLeftExpression(), false);
       ResultColumn.ColumnType rightType =
-          identifyOutputColumnType(((BinaryExpression) 
expression).getRightExpression());
+          identifyOutputColumnType(((BinaryExpression) 
expression).getRightExpression(), false);
       if ((leftType == ResultColumn.ColumnType.RAW
               && rightType == ResultColumn.ColumnType.AGGREGATION)
           || (leftType == ResultColumn.ColumnType.AGGREGATION
@@ -156,7 +157,8 @@ public class ExpressionAnalyzer {
         throw new SemanticException(
             "Raw data and aggregation result hybrid calculation is not 
supported.");
       }
-      if (leftType == ResultColumn.ColumnType.CONSTANT
+      if (isRoot
+          && leftType == ResultColumn.ColumnType.CONSTANT
           && rightType == ResultColumn.ColumnType.CONSTANT) {
         throw new SemanticException("Constant column is not supported.");
       }
@@ -165,18 +167,48 @@ public class ExpressionAnalyzer {
       }
       return rightType;
     } else if (expression instanceof UnaryExpression) {
-      return identifyOutputColumnType(((UnaryExpression) 
expression).getExpression());
+      return identifyOutputColumnType(((UnaryExpression) 
expression).getExpression(), false);
     } else if (expression instanceof FunctionExpression) {
-      if (!expression.isBuiltInAggregationFunctionExpression()) {
-        return ResultColumn.ColumnType.RAW;
-      }
-      for (Expression childExpression : expression.getExpressions()) {
-        if (identifyOutputColumnType(childExpression) == 
ResultColumn.ColumnType.AGGREGATION) {
+      List<Expression> inputExpressions = expression.getExpressions();
+      if (expression.isBuiltInAggregationFunctionExpression()) {
+        for (Expression inputExpression : inputExpressions) {
+          if (identifyOutputColumnType(inputExpression, false)
+              == ResultColumn.ColumnType.AGGREGATION) {
+            throw new SemanticException(
+                "Aggregation results cannot be as input of the aggregation 
function.");
+          }
+        }
+        return ResultColumn.ColumnType.AGGREGATION;
+      } else {
+        ResultColumn.ColumnType checkedType = null;
+        int lastCheckedIndex = 0;
+        for (int i = 0; i < inputExpressions.size(); i++) {
+          ResultColumn.ColumnType columnType =
+              identifyOutputColumnType(inputExpressions.get(i), false);
+          if (columnType != ResultColumn.ColumnType.CONSTANT) {
+            checkedType = columnType;
+            lastCheckedIndex = i;
+            break;
+          }
+        }
+        if (checkedType == null) {
           throw new SemanticException(
-              "Aggregation results cannot be as input of the aggregation 
function.");
+              String.format(
+                  "Input of '%s' is illegal.",
+                  ((FunctionExpression) expression).getFunctionName()));
+        }
+        for (int i = lastCheckedIndex; i < inputExpressions.size(); i++) {
+          ResultColumn.ColumnType columnType =
+              identifyOutputColumnType(inputExpressions.get(i), false);
+          if (columnType != ResultColumn.ColumnType.CONSTANT && columnType != 
checkedType) {
+            throw new SemanticException(
+                String.format(
+                    "Raw data and aggregation result hybrid input of '%s' is 
not supported.",
+                    ((FunctionExpression) expression).getFunctionName()));
+          }
         }
+        return checkedType;
       }
-      return ResultColumn.ColumnType.AGGREGATION;
     } else if (expression instanceof TimeSeriesOperand || expression 
instanceof TimestampOperand) {
       return ResultColumn.ColumnType.RAW;
     } else if (expression instanceof ConstantOperand) {
@@ -278,13 +310,6 @@ public class ExpressionAnalyzer {
           ((BinaryExpression) predicate).getLeftExpression(), prefixPaths, 
patternTree);
       constructPatternTreeFromExpression(
           ((BinaryExpression) predicate).getRightExpression(), prefixPaths, 
patternTree);
-    } else if (predicate instanceof TernaryExpression) {
-      constructPatternTreeFromExpression(
-          ((TernaryExpression) predicate).getFirstExpression(), prefixPaths, 
patternTree);
-      constructPatternTreeFromExpression(
-          ((TernaryExpression) predicate).getSecondExpression(), prefixPaths, 
patternTree);
-      constructPatternTreeFromExpression(
-          ((TernaryExpression) predicate).getThirdExpression(), prefixPaths, 
patternTree);
     } else if (predicate instanceof UnaryExpression) {
       constructPatternTreeFromExpression(
           ((UnaryExpression) predicate).getExpression(), prefixPaths, 
patternTree);
diff --git 
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionExpression.java
 
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionExpression.java
index 88d38aebd3..870b91d47f 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionExpression.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionExpression.java
@@ -259,7 +259,7 @@ public class FunctionExpression extends Expression {
         expression.inferTypes(typeProvider);
       }
 
-      if (isTimeSeriesGeneratingFunctionExpression()) {
+      if (!isBuiltInAggregationFunctionExpression()) {
         typeProvider.setType(
             expressionString,
             new UDTFTypeInferrer(functionName)
diff --git 
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java 
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
index 04d50329f9..affb77b9ae 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
@@ -747,7 +747,8 @@ public class ASTVisitor extends 
IoTDBSqlParserBaseVisitor<Statement> {
     if (resultColumnContext.AS() != null) {
       alias = parseAlias(resultColumnContext.alias());
     }
-    ResultColumn.ColumnType columnType = 
ExpressionAnalyzer.identifyOutputColumnType(expression);
+    ResultColumn.ColumnType columnType =
+        ExpressionAnalyzer.identifyOutputColumnType(expression, true);
     return new ResultColumn(expression, alias, columnType);
   }
 

Reply via email to