You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ja...@apache.org on 2026/10/21 06:44:52 UTC
(iotdb) branch master updated: Fix nullable AND results in tree-model CASE (#18875)
This is an automated email from the ASF dual-hosted git repository.
JackieTien97 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 4fceb75dfd8 Fix nullable AND results in tree-model CASE (#18875)
4fceb75dfd8 is described below
commit 4fceb75dfd831369488223c639ee7a8532207792
Author: Colin Lee <10...@users.noreply.github.com>
AuthorDate: Wed Oct 21 14:44:45 2026 +0800
Fix nullable AND results in tree-model CASE (#18875)
---
.../iotdb/db/it/query/IoTDBCaseWhenThenIT.java | 26 +++++++
.../column/binary/LogicAndColumnTransformer.java | 2 +-
.../binary/LogicBinaryColumnTransformerTest.java | 90 ++++++++++++++++++++++
3 files changed, 117 insertions(+), 1 deletion(-)
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBCaseWhenThenIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBCaseWhenThenIT.java
index a88b89e90b5..8a7933ffecf 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBCaseWhenThenIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBCaseWhenThenIT.java
@@ -928,4 +928,30 @@ public class IoTDBCaseWhenThenIT {
new String[] {"0,0.0,", "1000000,11.0,", "20000000,22.0,", "210000000,33.0,"};
resultSetEqualTest(sql, expectedHeader, retArray);
}
+
+ @Test
+ public void testNullableAndInLaterCaseBranch() {
+ prepareData(
+ new String[] {
+ "CREATE TIMESERIES root.sg.case_null.s1 WITH DATATYPE=INT32, ENCODING=PLAIN",
+ "CREATE TIMESERIES root.sg.case_null.s2 WITH DATATYPE=INT32, ENCODING=PLAIN",
+ "INSERT INTO root.sg.case_null(time, s2) VALUES (1, 1)",
+ "INSERT INTO root.sg.case_null(time, s1, s2) VALUES (2, 1, 1), (3, 0, 1), (4, 101, 1)"
+ });
+ resultSetEqualTest(
+ "SELECT CASE WHEN s1 > 100 THEN 1 WHEN s1 > 0 AND s2 > 0 THEN 2 ELSE 3 END AS result "
+ + "FROM root.sg.case_null",
+ new String[] {TIMESTAMP_STR, "result"},
+ new String[] {"1,3.0,", "2,2.0,", "3,3.0,", "4,1.0,"});
+ resultSetEqualTest(
+ "SELECT CASE WHEN s1 > 100 THEN 1 WHEN NOT (s1 > 0 AND s2 > 0) THEN 2 ELSE 3 END AS result "
+ + "FROM root.sg.case_null",
+ new String[] {TIMESTAMP_STR, "result"},
+ new String[] {"1,3.0,", "2,3.0,", "3,2.0,", "4,1.0,"});
+ resultSetEqualTest(
+ "SELECT CASE WHEN s1 > 100 THEN false WHEN s2 > 0 THEN (s1 > 0 AND s2 > 0) END AS result "
+ + "FROM root.sg.case_null",
+ new String[] {TIMESTAMP_STR, "result"},
+ new String[] {"1,null,", "2,true,", "3,false,", "4,false,"});
+ }
}
diff --git a/iotdb-core/calc-commons/src/main/java/org/apache/iotdb/calc/transformation/dag/column/binary/LogicAndColumnTransformer.java b/iotdb-core/calc-commons/src/main/java/org/apache/iotdb/calc/transformation/dag/column/binary/LogicAndColumnTransformer.java
index 5e7197eaab8..69cf49b9644 100644
--- a/iotdb-core/calc-commons/src/main/java/org/apache/iotdb/calc/transformation/dag/column/binary/LogicAndColumnTransformer.java
+++ b/iotdb-core/calc-commons/src/main/java/org/apache/iotdb/calc/transformation/dag/column/binary/LogicAndColumnTransformer.java
@@ -77,7 +77,7 @@ public class LogicAndColumnTransformer extends LogicBinaryColumnTransformer {
}
}
- initializeColumnCache(rightColumn);
+ initializeColumnCache(builder.build());
this.leftTransformer.clearCache();
this.rightTransformer.clearCache();
}
diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/transformation/dag/column/binary/LogicBinaryColumnTransformerTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/transformation/dag/column/binary/LogicBinaryColumnTransformerTest.java
index 086a143c86d..018dcefce5f 100644
--- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/transformation/dag/column/binary/LogicBinaryColumnTransformerTest.java
+++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/transformation/dag/column/binary/LogicBinaryColumnTransformerTest.java
@@ -19,6 +19,7 @@
package org.apache.iotdb.db.queryengine.transformation.dag.column.binary;
+import org.apache.iotdb.calc.transformation.dag.column.ColumnTransformer;
import org.apache.iotdb.calc.transformation.dag.column.binary.BinaryColumnTransformer;
import org.apache.iotdb.calc.transformation.dag.column.binary.LogicAndColumnTransformer;
import org.apache.iotdb.calc.transformation.dag.column.binary.LogicOrColumnTransformer;
@@ -37,6 +38,7 @@ import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
+import java.util.function.BiFunction;
public class LogicBinaryColumnTransformerTest {
@@ -44,6 +46,14 @@ public class LogicBinaryColumnTransformerTest {
private static final int POSITION_COUNT = 4;
+ private static final Boolean[] AND_EXPECTED = {
+ null, false, null, false, false, false, null, false, true
+ };
+
+ private static final Boolean[] OR_EXPECTED = {
+ null, null, true, null, false, true, true, true, true
+ };
+
private static final boolean[] leftInput = new boolean[] {true, false, true, false};
private static final boolean[] rightInput = new boolean[] {true, false, true, false};
@@ -113,4 +123,84 @@ public class LogicBinaryColumnTransformerTest {
}
}
+
+ @Test
+ public void testLogicAndWithNullsAndSelection() {
+ assertSelected(
+ (left, right) -> new LogicAndColumnTransformer(returnType, left, right),
+ AND_EXPECTED,
+ false);
+ }
+
+ @Test
+ public void testLogicAndWithNullsAndPartialSelection() {
+ assertSelected(
+ (left, right) -> new LogicAndColumnTransformer(returnType, left, right),
+ AND_EXPECTED,
+ true);
+ }
+
+ @Test
+ public void testLogicOrWithNullsAndSelection() {
+ assertSelected(
+ (left, right) -> new LogicOrColumnTransformer(returnType, left, right), OR_EXPECTED, false);
+ }
+
+ @Test
+ public void testLogicOrWithNullsAndPartialSelection() {
+ assertSelected(
+ (left, right) -> new LogicOrColumnTransformer(returnType, left, right), OR_EXPECTED, true);
+ }
+
+ private void assertSelected(
+ BiFunction<ColumnTransformer, ColumnTransformer, BinaryColumnTransformer> transformerFactory,
+ Boolean[] expected,
+ boolean partial) {
+ Boolean[] values = {null, false, true};
+ TsBlockBuilder builder =
+ new TsBlockBuilder(9, Arrays.asList(TSDataType.BOOLEAN, TSDataType.BOOLEAN));
+ for (Boolean left : values) {
+ for (Boolean right : values) {
+ builder.getTimeColumnBuilder().writeLong(0);
+ if (left == null) {
+ builder.getColumnBuilder(0).appendNull();
+ } else {
+ builder.getColumnBuilder(0).writeBoolean(left);
+ }
+ if (right == null) {
+ builder.getColumnBuilder(1).appendNull();
+ } else {
+ builder.getColumnBuilder(1).writeBoolean(right);
+ }
+ builder.declarePosition();
+ }
+ }
+ TsBlock block = builder.build();
+ IdentityColumnTransformer left = new IdentityColumnTransformer(returnType, 0);
+ IdentityColumnTransformer right = new IdentityColumnTransformer(returnType, 1);
+ left.addReferenceCount();
+ right.addReferenceCount();
+ left.initFromTsBlock(block);
+ right.initFromTsBlock(block);
+ BinaryColumnTransformer transformer = transformerFactory.apply(left, right);
+ transformer.addReferenceCount();
+ boolean[] selection = new boolean[9];
+ for (int i = 0; i < selection.length; i++) {
+ // Keep the right-FALSE rows (1 and 7) selected while excluding some left-FALSE rows.
+ selection[i] = !partial || (i != 3 && i != 5);
+ }
+ boolean[] selected = selection.clone();
+ transformer.evaluateWithSelection(selection);
+ Assert.assertArrayEquals(selected, selection);
+ Column result = transformer.getColumn();
+ Assert.assertEquals(expected.length, result.getPositionCount());
+ for (int i = 0; i < expected.length; i++) {
+ if (!selected[i] || expected[i] == null) {
+ Assert.assertTrue(result.isNull(i));
+ } else {
+ Assert.assertFalse(result.isNull(i));
+ Assert.assertEquals(expected[i], result.getBoolean(i));
+ }
+ }
+ }
}