You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by hu...@apache.org on 2023/02/28 06:45:18 UTC

[iotdb] branch master updated: [IOTDB-5592] Fix unexpected error when use full path in having/where (#9157)

This is an automated email from the ASF dual-hosted git repository.

hui 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 4ae7b3ab89 [IOTDB-5592] Fix unexpected error when use full path in having/where (#9157)
4ae7b3ab89 is described below

commit 4ae7b3ab8964e84103d2f8a8385821d34be551dd
Author: Weihao Li <60...@users.noreply.github.com>
AuthorDate: Tue Feb 28 14:45:12 2023 +0800

    [IOTDB-5592] Fix unexpected error when use full path in having/where (#9157)
    
    Signed-off-by: Weihao Li <18...@163.com>
---
 .../apache/iotdb/db/it/path/IoTDBFullPathIT.java   | 82 ++++++++++++++++++++++
 .../iotdb/db/it/{ => path}/IoTDBQuotedPathIT.java  |  2 +-
 .../iotdb/db/mpp/plan/parser/ASTVisitor.java       | 75 +++++++++-----------
 3 files changed, 118 insertions(+), 41 deletions(-)

diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/path/IoTDBFullPathIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/path/IoTDBFullPathIT.java
new file mode 100644
index 0000000000..a0d914919f
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/path/IoTDBFullPathIT.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.it.path;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import static org.apache.iotdb.db.it.utils.TestUtils.assertTestFail;
+import static org.apache.iotdb.db.it.utils.TestUtils.prepareData;
+import static org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTest;
+import static org.apache.iotdb.itbase.constant.TestConstant.TIMESTAMP_STR;
+import static org.apache.iotdb.itbase.constant.TestConstant.count;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBFullPathIT {
+  private static final String[] SQLs = new String[] {"INSERT INTO root.test(time,s1) VALUES(1,1)"};
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvFactory.getEnv().getConfig().getCommonConfig().setPartitionInterval(1000);
+    EnvFactory.getEnv().initClusterEnvironment();
+    prepareData(SQLs);
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  @Test
+  public void testUnsatisfiedRuleQuery() {
+    assertTestFail(
+        "select root.test.s1 from root.**",
+        TSStatusCode.SEMANTIC_ERROR.getStatusCode()
+            + ": Path can not start with root in select clause.");
+  }
+
+  @Test
+  public void testSatisfiedRuleQuery() {
+    String[] expectedHeader = new String[] {TIMESTAMP_STR, "root.test.s1"};
+    String[] retArray = new String[] {"1,1.0,"};
+    resultSetEqualTest(
+        "select s1 from root.** " + "where root.test.s1 is not null", expectedHeader, retArray);
+
+    resultSetEqualTest(
+        "select s1 from root.** " + "where root.test.s1 not in (2,3)", expectedHeader, retArray);
+
+    expectedHeader = new String[] {count("root.test.s1")};
+    retArray = new String[] {};
+    resultSetEqualTest(
+        "select count(s1) from root.** " + "having count(root.test.s1) not in (1,2)",
+        expectedHeader,
+        retArray);
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBQuotedPathIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/path/IoTDBQuotedPathIT.java
similarity index 99%
rename from integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBQuotedPathIT.java
rename to integration-test/src/test/java/org/apache/iotdb/db/it/path/IoTDBQuotedPathIT.java
index 5379bdf243..0c788782f2 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBQuotedPathIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/path/IoTDBQuotedPathIT.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.it;
+package org.apache.iotdb.db.it.path;
 
 import org.apache.iotdb.it.env.EnvFactory;
 import org.apache.iotdb.it.framework.IoTDBTestRunner;
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 08791b8217..dcb9d0d173 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
@@ -1133,8 +1133,7 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
 
   // ---- Where Clause
   private WhereCondition parseWhereClause(IoTDBSqlParser.WhereClauseContext ctx) {
-    Expression predicate =
-        parseExpression(ctx.expression(), ctx.expression().OPERATOR_NOT() == null);
+    Expression predicate = parseExpression(ctx.expression(), true);
     return new WhereCondition(predicate);
   }
 
@@ -1214,7 +1213,7 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
       ExpressionContext expressionContext = expressions.get(0);
       GroupByVariationComponent groupByVariationComponent = new GroupByVariationComponent();
       groupByVariationComponent.setControlColumnExpression(
-          parseExpression(expressionContext, expressionContext.OPERATOR_NOT() == null));
+          parseExpression(expressionContext, true));
       groupByVariationComponent.setDelta(
           ctx.delta == null ? 0 : Double.parseDouble(ctx.delta.getText()));
       groupByVariationComponent.setIgnoringNull(ignoringNull);
@@ -1223,11 +1222,9 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
       ExpressionContext conditionExpressionContext = expressions.get(0);
       GroupBySeriesComponent groupBySeriesComponent = new GroupBySeriesComponent();
       groupBySeriesComponent.setControlColumnExpression(
-          parseExpression(
-              conditionExpressionContext, conditionExpressionContext.OPERATOR_NOT() == null));
+          parseExpression(conditionExpressionContext, true));
       if (expressions.size() == 2) {
-        groupBySeriesComponent.setKeepExpression(
-            parseExpression(expressions.get(1), expressions.get(1).OPERATOR_NOT() == null));
+        groupBySeriesComponent.setKeepExpression(parseExpression(expressions.get(1), true));
       }
       groupBySeriesComponent.setIgnoringNull(ignoringNull);
       return groupBySeriesComponent;
@@ -1265,8 +1262,7 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
 
   // ---- Having Clause
   private HavingCondition parseHavingClause(IoTDBSqlParser.HavingClauseContext ctx) {
-    Expression predicate =
-        parseExpression(ctx.expression(), ctx.expression().OPERATOR_NOT() == null);
+    Expression predicate = parseExpression(ctx.expression(), true);
     return new HavingCondition(predicate);
   }
 
@@ -1537,13 +1533,13 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
     return new PartialPath(path);
   }
 
-  /** path of expression in withoutNull clause can start with root. */
   private PartialPath parseFullPathInExpression(
-      IoTDBSqlParser.FullPathInExpressionContext ctx, boolean inWithoutNull) {
+      IoTDBSqlParser.FullPathInExpressionContext ctx, boolean canUseFullPath) {
     List<IoTDBSqlParser.NodeNameContext> nodeNames = ctx.nodeName();
     int size = nodeNames.size();
     if (ctx.ROOT() != null) {
-      if (!inWithoutNull) {
+      if (!canUseFullPath) {
+        // now full path cannot occur in SELECT only
         throw new SemanticException("Path can not start with root in select clause.");
       }
       size++;
@@ -2200,26 +2196,26 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
   // Expression & Predicate ========================================================================
 
   private Expression parseExpression(
-      IoTDBSqlParser.ExpressionContext context, boolean inWithoutNull) {
+      IoTDBSqlParser.ExpressionContext context, boolean canUseFullPath) {
     if (context.unaryInBracket != null) {
-      return parseExpression(context.unaryInBracket, inWithoutNull);
+      return parseExpression(context.unaryInBracket, canUseFullPath);
     }
 
     if (context.expressionAfterUnaryOperator != null) {
       if (context.MINUS() != null) {
         return new NegationExpression(
-            parseExpression(context.expressionAfterUnaryOperator, inWithoutNull));
+            parseExpression(context.expressionAfterUnaryOperator, canUseFullPath));
       }
       if (context.OPERATOR_NOT() != null) {
         return new LogicNotExpression(
-            parseExpression(context.expressionAfterUnaryOperator, inWithoutNull));
+            parseExpression(context.expressionAfterUnaryOperator, canUseFullPath));
       }
-      return parseExpression(context.expressionAfterUnaryOperator, inWithoutNull);
+      return parseExpression(context.expressionAfterUnaryOperator, canUseFullPath);
     }
 
     if (context.leftExpression != null && context.rightExpression != null) {
-      Expression leftExpression = parseExpression(context.leftExpression, inWithoutNull);
-      Expression rightExpression = parseExpression(context.rightExpression, inWithoutNull);
+      Expression leftExpression = parseExpression(context.leftExpression, canUseFullPath);
+      Expression rightExpression = parseExpression(context.rightExpression, canUseFullPath);
       if (context.STAR() != null) {
         return new MultiplicationExpression(leftExpression, rightExpression);
       }
@@ -2264,24 +2260,24 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
 
     if (context.unaryBeforeRegularOrLikeExpression != null) {
       if (context.REGEXP() != null) {
-        return parseRegularExpression(context, inWithoutNull);
+        return parseRegularExpression(context, canUseFullPath);
       }
       if (context.LIKE() != null) {
-        return parseLikeExpression(context, inWithoutNull);
+        return parseLikeExpression(context, canUseFullPath);
       }
       throw new UnsupportedOperationException();
     }
 
     if (context.unaryBeforeIsNullExpression != null) {
-      return parseIsNullExpression(context, inWithoutNull);
+      return parseIsNullExpression(context, canUseFullPath);
     }
 
     if (context.firstExpression != null
         && context.secondExpression != null
         && context.thirdExpression != null) {
-      Expression firstExpression = parseExpression(context.firstExpression, inWithoutNull);
-      Expression secondExpression = parseExpression(context.secondExpression, inWithoutNull);
-      Expression thirdExpression = parseExpression(context.thirdExpression, inWithoutNull);
+      Expression firstExpression = parseExpression(context.firstExpression, canUseFullPath);
+      Expression secondExpression = parseExpression(context.secondExpression, canUseFullPath);
+      Expression thirdExpression = parseExpression(context.thirdExpression, canUseFullPath);
 
       if (context.OPERATOR_BETWEEN() != null) {
         return new BetweenExpression(
@@ -2291,16 +2287,16 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
     }
 
     if (context.unaryBeforeInExpression != null) {
-      return parseInExpression(context, inWithoutNull);
+      return parseInExpression(context, canUseFullPath);
     }
 
     if (context.functionName() != null) {
-      return parseFunctionExpression(context, inWithoutNull);
+      return parseFunctionExpression(context, canUseFullPath);
     }
 
     if (context.fullPathInExpression() != null) {
       return new TimeSeriesOperand(
-          parseFullPathInExpression(context.fullPathInExpression(), inWithoutNull));
+          parseFullPathInExpression(context.fullPathInExpression(), canUseFullPath));
     }
 
     if (context.time != null) {
@@ -2315,14 +2311,14 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
   }
 
   private Expression parseFunctionExpression(
-      IoTDBSqlParser.ExpressionContext functionClause, boolean inWithoutNull) {
+      IoTDBSqlParser.ExpressionContext functionClause, boolean canUseFullPath) {
     FunctionExpression functionExpression =
         new FunctionExpression(parseIdentifier(functionClause.functionName().getText()));
 
     // expressions
     boolean hasNonPureConstantSubExpression = false;
     for (IoTDBSqlParser.ExpressionContext expression : functionClause.expression()) {
-      Expression subexpression = parseExpression(expression, inWithoutNull);
+      Expression subexpression = parseExpression(expression, canUseFullPath);
       if (!subexpression.isConstantOperand()) {
         hasNonPureConstantSubExpression = true;
       }
@@ -2423,26 +2419,26 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
             expressionString, actual, Arrays.toString(expected)));
   }
 
-  private Expression parseRegularExpression(ExpressionContext context, boolean inWithoutNull) {
+  private Expression parseRegularExpression(ExpressionContext context, boolean canUseFullPath) {
     return new RegularExpression(
-        parseExpression(context.unaryBeforeRegularOrLikeExpression, inWithoutNull),
+        parseExpression(context.unaryBeforeRegularOrLikeExpression, canUseFullPath),
         parseStringLiteral(context.STRING_LITERAL().getText()));
   }
 
-  private Expression parseLikeExpression(ExpressionContext context, boolean inWithoutNull) {
+  private Expression parseLikeExpression(ExpressionContext context, boolean canUseFullPath) {
     return new LikeExpression(
-        parseExpression(context.unaryBeforeRegularOrLikeExpression, inWithoutNull),
+        parseExpression(context.unaryBeforeRegularOrLikeExpression, canUseFullPath),
         parseStringLiteral(context.STRING_LITERAL().getText()));
   }
 
-  private Expression parseIsNullExpression(ExpressionContext context, boolean inWithoutNull) {
+  private Expression parseIsNullExpression(ExpressionContext context, boolean canUseFullPath) {
     return new IsNullExpression(
-        parseExpression(context.unaryBeforeIsNullExpression, inWithoutNull),
+        parseExpression(context.unaryBeforeIsNullExpression, canUseFullPath),
         context.OPERATOR_NOT() != null);
   }
 
-  private Expression parseInExpression(ExpressionContext context, boolean inWithoutNull) {
-    Expression childExpression = parseExpression(context.unaryBeforeInExpression, inWithoutNull);
+  private Expression parseInExpression(ExpressionContext context, boolean canUseFullPath) {
+    Expression childExpression = parseExpression(context.unaryBeforeInExpression, canUseFullPath);
     LinkedHashSet<String> values = new LinkedHashSet<>();
     for (ConstantContext constantContext : context.constant()) {
       values.add(parseConstant(constantContext));
@@ -3051,8 +3047,7 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
     // parse where
     IoTDBSqlParser.WhereClauseContext whereCtx = ctx.whereClause();
     if (whereCtx != null) {
-      Expression predicate =
-          parseExpression(whereCtx.expression(), whereCtx.expression().OPERATOR_NOT() == null);
+      Expression predicate = parseExpression(whereCtx.expression(), true);
       if (!((predicate instanceof GreaterThanExpression)
           || (predicate instanceof GreaterEqualExpression))) {
         throw new SemanticException(UNSUPPORTED_CLAUSE_IN_PIPE);