From c71625d76486336246045b466593191be91a173b Mon Sep 17 00:00:00 2001 From: Weihao Li <18110526956@163.com> Date: Wed, 27 May 2026 12:53:31 +0800 Subject: [PATCH] fix Signed-off-by: Weihao Li <18110526956@163.com> --- .../query/IoTDBPredicateConversionTreeIT.java | 50 +++++++++++++++++++ .../plan/analyze/AnalyzeVisitor.java | 19 ++++--- .../PredicatePushIntoScanChecker.java | 1 + 3 files changed, 62 insertions(+), 8 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 afe09efb48103..ba09872897bb5 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.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 void testDoubleLiteralOverflow() { 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 7aa8d1e863614..fd8780f5d68f9 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 @@ -983,10 +983,12 @@ private void analyzeHavingBase( ISchemaTree schemaTree, UnaryOperator havingExpressionAnalyzer, MPPQueryContext queryContext) { + Expression havingPredicate = + PredicateUtils.predicateRemoveNot(queryStatement.getHavingCondition().getPredicate()); // get removeWildcard Expressions in Having List conJunctions = ExpressionAnalyzer.bindSchemaForPredicate( - queryStatement.getHavingCondition().getPredicate(), + havingPredicate, queryStatement.getFromComponent().getPrefixPaths(), schemaTree, true, @@ -1062,7 +1064,8 @@ private void analyzeHaving( Map> deviceToOutputExpressions = analysis.getDeviceToOutputExpressions(); - Expression havingExpression = queryStatement.getHavingCondition().getPredicate(); + Expression havingExpression = + PredicateUtils.predicateRemoveNot(queryStatement.getHavingCondition().getPredicate()); Set conJunctions = new HashSet<>(); for (PartialPath device : deviceSet) { @@ -1522,9 +1525,11 @@ private void analyzeWhere( if (!queryStatement.hasWhere()) { return; } + Expression wherePredicate = + PredicateUtils.predicateRemoveNot(queryStatement.getWhereCondition().getPredicate()); List conJunctions = ExpressionAnalyzer.bindSchemaForPredicate( - queryStatement.getWhereCondition().getPredicate(), + wherePredicate, queryStatement.getFromComponent().getPrefixPaths(), schemaTree, true, @@ -1548,13 +1553,11 @@ private Expression analyzeWhereSplitByDevice( final PartialPath devicePath, final ISchemaTree schemaTree, final MPPQueryContext queryContext) { + Expression wherePredicate = + PredicateUtils.predicateRemoveNot(queryStatement.getWhereCondition().getPredicate()); List conJunctions = ExpressionAnalyzer.concatDeviceAndBindSchemaForPredicate( - queryStatement.getWhereCondition().getPredicate(), - devicePath, - schemaTree, - true, - queryContext); + wherePredicate, devicePath, schemaTree, true, queryContext); return convertConJunctionsToWhereExpression(conJunctions); } 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 31ae325b32848..63e9c7f7889a0 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 @@ -89,6 +89,7 @@ public Boolean visitRegularExpression(RegularExpression regularExpression, Void @Override public Boolean visitLogicNotExpression(LogicNotExpression logicNotExpression, Void context) { + // Not should have been removed in analyze stage throw new IllegalArgumentException(CONTAIN_NOT_ERR_MSG); }