This is an automated email from the ASF dual-hosted git repository. Wei-hao-Li pushed a commit to branch fixNot in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit c9e7a7771b731add7ef98501d33f5b8c49f53931 Author: Weihao Li <[email protected]> AuthorDate: Wed May 27 09:48:36 2026 +0800 fix Signed-off-by: Weihao Li <[email protected]> --- .../it/query/IoTDBPredicateConversionTreeIT.java | 50 ++++++++++++++++++++++ .../queryengine/plan/analyze/AnalyzeVisitor.java | 3 ++ .../predicate/PredicatePushIntoScanChecker.java | 4 +- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBPredicateConversionTreeIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBPredicateConversionTreeIT.java index afe09efb481..ba09872897b 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBPredicateConversionTreeIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBPredicateConversionTreeIT.java @@ -34,6 +34,9 @@ import java.sql.Connection; import java.sql.Statement; import static org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTest; +import static org.apache.iotdb.itbase.constant.TestConstant.DEVICE; +import static org.apache.iotdb.itbase.constant.TestConstant.TIMESTAMP_STR; +import static org.apache.iotdb.itbase.constant.TestConstant.count; import static org.junit.Assert.fail; @RunWith(IoTDBTestRunner.class) @@ -290,4 +293,51 @@ public class IoTDBPredicateConversionTreeIT { expectedHeaderInt64, allInt64Rows); } + + @Test + public void testWhereAndHavingWithNot() { + // Non align by device: WHERE with NOT + String[] expectedWhereHeader = new String[] {TIMESTAMP_STR, DEVICE_ID + ".int32_col"}; + String[] whereRetArray = new String[] {"1,20,", "8,1000,", "9,-29,", "10,-30,"}; + resultSetEqualTest( + "SELECT int32_col FROM " + DEVICE_ID + " WHERE NOT (int32_col > 20 AND int32_col < 40)", + expectedWhereHeader, + whereRetArray); + + // Non align by device: HAVING with NOT + String[] expectedHavingHeader = new String[] {TIMESTAMP_STR, count(DEVICE_ID + ".int32_col")}; + String[] havingRetArray = new String[] {"5,1,", "7,1,"}; + resultSetEqualTest( + "SELECT count(int32_col) FROM " + + DEVICE_ID + + " GROUP BY ([1,11),2ms) HAVING NOT (count(int32_col) > 1)", + expectedHavingHeader, + havingRetArray); + + // Align by device: WHERE with NOT + String[] expectedWhereAlignByDeviceHeader = new String[] {TIMESTAMP_STR, DEVICE, "int32_col"}; + String[] whereAlignByDeviceRetArray = + new String[] { + "1,root.test_pred.d1,20,", + "8,root.test_pred.d1,1000,", + "9,root.test_pred.d1,-29,", + "10,root.test_pred.d1,-30,", + }; + resultSetEqualTest( + "SELECT int32_col FROM root.test_pred.* WHERE NOT (int32_col > 20 AND int32_col < 40) ALIGN BY DEVICE", + expectedWhereAlignByDeviceHeader, + whereAlignByDeviceRetArray); + + // Align by device: HAVING with NOT + String[] expectedHavingAlignByDeviceHeader = + new String[] {TIMESTAMP_STR, DEVICE, count("int32_col")}; + String[] havingAlignByDeviceRetArray = + new String[] { + "5,root.test_pred.d1,1,", "7,root.test_pred.d1,1,", + }; + resultSetEqualTest( + "SELECT count(int32_col) FROM root.test_pred.* GROUP BY ([1,11),2ms) HAVING NOT (count(int32_col) > 1) ALIGN BY DEVICE", + expectedHavingAlignByDeviceHeader, + havingAlignByDeviceRetArray); + } } 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 7aa8d1e8636..b58771c4148 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 @@ -994,6 +994,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> Expression havingExpression = PredicateUtils.combineConjuncts( conJunctions.stream().distinct().collect(Collectors.toList())); + havingExpression = PredicateUtils.predicateRemoveNot(havingExpression); havingExpression = havingExpressionAnalyzer.apply(havingExpression); TSDataType outputType = analyzeExpressionType(analysis, havingExpression); @@ -1100,6 +1101,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> } havingExpression = PredicateUtils.combineConjuncts(new ArrayList<>(conJunctions)); + havingExpression = PredicateUtils.predicateRemoveNot(havingExpression); TSDataType outputType = analyzeExpressionType(analysis, havingExpression); if (outputType != TSDataType.BOOLEAN) { throw new SemanticException( @@ -1562,6 +1564,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> Expression predicate = PredicateUtils.combineConjuncts( conJunctions.stream().distinct().collect(Collectors.toList())); + predicate = PredicateUtils.predicateRemoveNot(predicate); predicate = PredicateUtils.simplifyPredicate(predicate); predicate = normalizeExpression(predicate); return predicate; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/predicate/PredicatePushIntoScanChecker.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/predicate/PredicatePushIntoScanChecker.java index 31ae325b328..7cd01314a89 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/predicate/PredicatePushIntoScanChecker.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/predicate/PredicatePushIntoScanChecker.java @@ -39,8 +39,6 @@ import org.apache.iotdb.db.queryengine.plan.expression.unary.LikeExpression; import org.apache.iotdb.db.queryengine.plan.expression.unary.LogicNotExpression; import org.apache.iotdb.db.queryengine.plan.expression.unary.RegularExpression; -import static org.apache.tsfile.read.filter.operator.Not.CONTAIN_NOT_ERR_MSG; - public class PredicatePushIntoScanChecker extends PredicateVisitor<Boolean, Void> { @Override @@ -89,7 +87,7 @@ public class PredicatePushIntoScanChecker extends PredicateVisitor<Boolean, Void @Override public Boolean visitLogicNotExpression(LogicNotExpression logicNotExpression, Void context) { - throw new IllegalArgumentException(CONTAIN_NOT_ERR_MSG); + return Boolean.FALSE; } @Override
