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 2022/11/09 08:00:55 UTC

[iotdb] branch master updated: [IOTDB-4576]Add NULL Operand and modify operations about it & Use False if the series in the predicate does not exist (#7924)

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 9ac112433e [IOTDB-4576]Add NULL Operand and modify operations about it  & Use False if the series in the predicate does not exist (#7924)
9ac112433e is described below

commit 9ac112433ef056a9e3a6e01cc26de9b6c325943c
Author: Weihao Li <60...@users.noreply.github.com>
AuthorDate: Wed Nov 9 16:00:48 2022 +0800

    [IOTDB-4576]Add NULL Operand and modify operations about it  & Use False if the series in the predicate does not exist (#7924)
---
 .../iotdb/db/it/query/IoTDBNullOperandIT.java      | 242 +++++++++++++++++++++
 .../withoutNull/IoTDBWithoutNullAllFilterIT.java   |  39 ++--
 .../withoutNull/IoTDBWithoutNullAnyFilterIT.java   |  55 ++---
 .../operator/process/FilterAndProjectOperator.java |  10 +-
 .../apache/iotdb/db/mpp/plan/analyze/Analysis.java |   5 +
 .../db/mpp/plan/analyze/ExpressionAnalyzer.java    |  31 ++-
 .../mpp/plan/analyze/ExpressionTypeAnalyzer.java   |  12 +-
 .../iotdb/db/mpp/plan/expression/Expression.java   |   5 +
 .../db/mpp/plan/expression/ExpressionType.java     |   2 +
 .../db/mpp/plan/expression/leaf/NullOperand.java   | 101 +++++++++
 .../plan/expression/unary/NegationExpression.java  |   2 +
 .../visitor/ColumnTransformerVisitor.java          |  17 ++
 .../plan/expression/visitor/ExpressionVisitor.java |   5 +
 .../iotdb/db/mpp/plan/parser/ASTVisitor.java       |   3 +
 .../dag/column/ColumnTransformer.java              |  31 +++
 .../binary/CompareBinaryColumnTransformer.java     |   7 +-
 .../binary/CompareEqualToColumnTransformer.java    |   2 +-
 .../column/binary/LogicAndColumnTransformer.java   |  30 +++
 .../binary/LogicBinaryColumnTransformer.java       |  24 --
 .../column/binary/LogicOrColumnTransformer.java    |  30 +++
 .../NullColumnTransformer.java}                    |  21 +-
 .../ternary/CompareTernaryColumnTransformer.java   |  17 +-
 .../dag/column/unary/InColumnTransformer.java      |   8 +-
 .../column/unary/LogicNotColumnTransformer.java    |   2 +-
 .../dag/column/unary/RegularColumnTransformer.java |   2 +-
 .../read/common/block/column/NullColumn.java       |  87 +++++++-
 26 files changed, 664 insertions(+), 126 deletions(-)

diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBNullOperandIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBNullOperandIT.java
new file mode 100644
index 0000000000..73d9dd73d9
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBNullOperandIT.java
@@ -0,0 +1,242 @@
+/*
+ * 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.query;
+
+import org.apache.iotdb.it.env.ConfigFactory;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+
+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.prepareData;
+import static org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTest;
+import static org.apache.iotdb.itbase.constant.TestConstant.TIMESTAMP_STR;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({ClusterIT.class}) // TODO After old StandAlone remove
+public class IoTDBNullOperandIT {
+  private static final String[] SQLs =
+      new String[] {
+        "SET STORAGE GROUP TO root.test",
+        "CREATE TIMESERIES root.test.sg1.s1 WITH DATATYPE=INT32, ENCODING=PLAIN",
+        "CREATE TIMESERIES root.test.sg1.s2 WITH DATATYPE=INT32, ENCODING=PLAIN",
+        "CREATE TIMESERIES root.test.sg1.s3 WITH DATATYPE=BOOLEAN, ENCODING=PLAIN",
+        "CREATE TIMESERIES root.test.sg1.s4 WITH DATATYPE=BOOLEAN, ENCODING=PLAIN",
+        "CREATE TIMESERIES root.test.sg1.s5 WITH DATATYPE=TEXT, ENCODING=PLAIN",
+        "INSERT INTO root.test.sg1(timestamp,s1,s3,s4) values(1, 1, true, false)",
+        "INSERT INTO root.test.sg1(timestamp,s1,s3) values(2, 2, true)",
+        "INSERT INTO root.test.sg1(timestamp,s1,s4) values(3, 3, false)",
+        "flush",
+      };
+
+  private static long prevPartitionInterval;
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    prevPartitionInterval = ConfigFactory.getConfig().getPartitionInterval();
+    ConfigFactory.getConfig().setPartitionInterval(1000);
+    EnvFactory.getEnv().initBeforeClass();
+    prepareData(SQLs);
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanAfterClass();
+    ConfigFactory.getConfig().setPartitionInterval(prevPartitionInterval);
+  }
+
+  /**
+   * ArithmeticOperations: +, -, *, /, %
+   *
+   * <p>The result will be NULL if any Operand of ArithmeticOperations is NULL.
+   */
+  @Test
+  public void testArithmeticOperations() {
+    String[] expectedHeader =
+        new String[] {
+          TIMESTAMP_STR,
+          "root.test.sg1.s1 + root.test.sg1.s2",
+          "root.test.sg1.s1 - root.test.sg1.s2",
+          "root.test.sg1.s1 * root.test.sg1.s2",
+          "root.test.sg1.s1 / root.test.sg1.s2",
+          "root.test.sg1.s1 % root.test.sg1.s2",
+          "root.test.sg1.s2 % root.test.sg1.s2",
+        };
+    String[] retArray =
+        new String[] {
+          "1,null,null,null,null,null,null,",
+          "2,null,null,null,null,null,null,",
+          "3,null,null,null,null,null,null,",
+        };
+    resultSetEqualTest(
+        "select s1+s2, s1-s2, s1*s2, s1/s2, s1%s2, s2%s2 from root.test.sg1",
+        expectedHeader, retArray);
+  }
+
+  /**
+   * CompareOperations: =, >, <, like, in, between...(don't include `is null`)
+   *
+   * <p>The result will be NULL if any Operand of CompareOperations is NULL.
+   */
+  @Test
+  public void testCompareOperations() {
+    String[] expectedHeader =
+        new String[] {
+          TIMESTAMP_STR,
+          "root.test.sg1.s1 = root.test.sg1.s2",
+          "root.test.sg1.s1 > root.test.sg1.s2",
+          "root.test.sg1.s1 < root.test.sg1.s2",
+          "root.test.sg1.s5 LIKE '^test$'",
+          "root.test.sg1.s2 IN (1,2)",
+          "root.test.sg1.s2 BETWEEN 1 AND 3",
+        };
+    String[] retArray =
+        new String[] {
+          "1,null,null,null,null,null,null,",
+          "2,null,null,null,null,null,null,",
+          "3,null,null,null,null,null,null,",
+        };
+    resultSetEqualTest(
+        "select s1=s2, s1>s2, s1<s2, s5 like \"test\" , s2 in (1,2), s2 between 1 and 3 from root.test.sg1",
+        expectedHeader,
+        retArray);
+  }
+
+  @Test
+  public void testIsNullOperation() {
+    // Currently, if one predicate in SELECT contains not existed series, we won't show this column.
+    // So we test IS_NULL in WHERE.
+    String[] expectedHeader =
+        new String[] {
+          TIMESTAMP_STR,
+          "root.test.sg1.s1",
+          "root.test.sg1.s2 IS NULL",
+          "root.test.sg1.s2 IS NOT NULL",
+          "root.test.sg1.s5 IS NULL",
+          "root.test.sg1.s5 IS NOT NULL",
+        };
+    String[] retArray =
+        new String[] {
+          "1,1,true,false,true,false,", "2,2,true,false,true,false,", "3,3,true,false,true,false,",
+        };
+    resultSetEqualTest(
+        "select s1,s2 is null, s2 is not null, s5 is null, s5 is not null from root.test.sg1",
+        expectedHeader,
+        retArray);
+  }
+
+  /**
+   * LogicOperations: !, &&, ||
+   *
+   * <p>See
+   * 'https://learn.microsoft.com/zh-cn/sql/connect/ado-net/sql/handle-null-values?view=sql-server-ver16'
+   */
+  @Test
+  public void testLogicOperations() {
+    String[] expectedHeader =
+        new String[] {
+          TIMESTAMP_STR,
+          "root.test.sg1.s3 | root.test.sg1.s3",
+          "root.test.sg1.s4 & root.test.sg1.s4",
+          "root.test.sg1.s3 | root.test.sg1.s4",
+          "root.test.sg1.s3 & root.test.sg1.s4",
+        };
+    String[] retArray =
+        new String[] {
+          "1,true,false,true,false,", "2,true,null,true,null,", "3,null,false,null,false,",
+        };
+    resultSetEqualTest(
+        "select s3||s3, s4&&s4, s3||s4, s3&&s4  from root.test.sg1", expectedHeader, retArray);
+  }
+
+  @Test
+  public void testWhere() {
+    String[] expectedHeader =
+        new String[] {
+          TIMESTAMP_STR, "root.test.sg1.s1", "root.test.sg1.s3", "root.test.sg1.s4",
+        };
+    String[] retArray = new String[] {};
+    resultSetEqualTest("select s1, s3, s4 from root.** where s2>0", expectedHeader, retArray);
+
+    resultSetEqualTest("select s1, s3, s4 from root.** where s2", expectedHeader, retArray);
+
+    retArray =
+        new String[] {
+          "1,1,true,false,", "2,2,true,null,", "3,3,null,false,",
+        };
+    resultSetEqualTest(
+        "select s1, s3, s4 from root.** where s2 is null && s5 is null", expectedHeader, retArray);
+
+    retArray =
+        new String[] {
+          "1,root.test.sg1,1,true,false,",
+          "2,root.test.sg1,2,true,null,",
+          "3,root.test.sg1,3,null,false,",
+        };
+    expectedHeader =
+        new String[] {
+          TIMESTAMP_STR, "Device", "s1", "s3", "s4",
+        };
+    resultSetEqualTest(
+        "select s1, s3, s4 from root.** where s2 is null && s5 is null align by device",
+        expectedHeader,
+        retArray);
+  }
+
+  @Test
+  public void testHaving() {
+    String[] expectedHeader =
+        new String[] {
+          TIMESTAMP_STR, "count(root.test.sg1.s1)", "count(root.test.sg1.s2)",
+        };
+    String[] retArray = new String[] {};
+    resultSetEqualTest(
+        "select count(s1), count(s2) from root.** group by ([1,4),1ms) having count(s2)>0",
+        expectedHeader,
+        retArray);
+
+    retArray =
+        new String[] {
+          "1,1,0,", "2,1,0,", "3,1,0,",
+        };
+    resultSetEqualTest(
+        "select count(s1), count(s2) from root.** group by ([1,4),1ms) having count(s2)>=0",
+        expectedHeader,
+        retArray);
+
+    retArray =
+        new String[] {
+          "1,root.test.sg1,1,0,", "2,root.test.sg1,1,0,", "3,root.test.sg1,1,0,",
+        };
+    expectedHeader =
+        new String[] {
+          TIMESTAMP_STR, "Device", "count(s1)", "count(s2)",
+        };
+    resultSetEqualTest(
+        "select count(s1), count(s2) from root.** group by ([1,4),1ms) having count(s2)>=0 align by device",
+        expectedHeader,
+        retArray);
+  }
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/withoutNull/IoTDBWithoutNullAllFilterIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/withoutNull/IoTDBWithoutNullAllFilterIT.java
index 632acc2cbd..7cdf3af402 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/withoutNull/IoTDBWithoutNullAllFilterIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/withoutNull/IoTDBWithoutNullAllFilterIT.java
@@ -37,6 +37,8 @@ import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.Statement;
 
+import static org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTest;
+import static org.apache.iotdb.itbase.constant.TestConstant.TIMESTAMP_STR;
 import static org.junit.Assert.fail;
 
 @RunWith(IoTDBTestRunner.class)
@@ -1179,25 +1181,28 @@ public class IoTDBWithoutNullAllFilterIT {
   @Test
   public void withoutNullColumnsMisMatchSelectedQueryTest() {
     System.out.println("withoutNullColumnsMisMatchSelectedQueryTest");
-    String[] retArray1 =
+    String[] expectedHeader =
         new String[] {
-          "1,true,1,1.0,1",
-          "3,false,null,null,null",
-          "6,true,6,6.0,6",
-          "7,true,null,7.0,null",
-          "8,true,8,8.0,null",
-          "9,false,9,9.0,9",
-          "10,true,10,10.0,10"
+          TIMESTAMP_STR,
+          "root.test.sg1.s1",
+          "root.test.sg1.s2",
+          "root.test.sg1.s3",
+          "root.test.sg1.s4",
         };
-    try (Connection connection = EnvFactory.getEnv().getConnection();
-        Statement statement = connection.createStatement()) {
-
-      statement.executeQuery(
-          "select * from root.test.sg1 where s1 is not null || usage is not null");
-      fail();
-
-    } catch (Exception e) {
-    }
+    String[] retArray =
+        new String[] {
+          "1,true,1,1.0,1,",
+          "3,false,null,null,null,",
+          "6,true,6,6.0,6,",
+          "7,true,null,7.0,null,",
+          "8,true,8,8.0,null,",
+          "9,false,9,9.0,9,",
+          "10,true,10,10.0,10,"
+        };
+    resultSetEqualTest(
+        "select s1, s2, s3, s4 from root.test.sg1 where s1 is not null || usage is not null",
+        expectedHeader,
+        retArray);
   }
 
   @Ignore
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/withoutNull/IoTDBWithoutNullAnyFilterIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/withoutNull/IoTDBWithoutNullAnyFilterIT.java
index e83214ac15..c8b87825e2 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/withoutNull/IoTDBWithoutNullAnyFilterIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/withoutNull/IoTDBWithoutNullAnyFilterIT.java
@@ -36,6 +36,7 @@ import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.Statement;
 
+import static org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTest;
 import static org.junit.Assert.fail;
 
 @RunWith(IoTDBTestRunner.class)
@@ -1125,42 +1126,28 @@ public class IoTDBWithoutNullAnyFilterIT {
   @Test
   public void withoutNullColumnsMisMatchSelectedQueryTest() {
     System.out.println("withoutNullColumnsMisMatchSelectedQueryTest");
-    String[] retArray1 =
+    String[] expectedHeader =
         new String[] {
-          "1,true,1,1.0,1",
-          "3,false,null,null,null",
-          "6,true,6,6.0,6",
-          "7,true,null,7.0,null",
-          "8,true,8,8.0,null",
-          "9,false,9,9.0,9",
-          "10,true,10,10.0,10"
+          TIMESTAMP_STR,
+          "root.test.sg1.s1",
+          "root.test.sg1.s2",
+          "root.test.sg1.s3",
+          "root.test.sg1.s4",
         };
-    try (Connection connection = EnvFactory.getEnv().getConnection();
-        Statement statement = connection.createStatement()) {
-
-      statement.executeQuery(
-          "select * from root.test.sg1 where s1 is not null && usag is not null");
-      fail();
-    } catch (Exception e) {
-    }
-
-    try (Connection connection = EnvFactory.getEnv().getConnection();
-        Statement statement = connection.createStatement()) {
-
-      statement.executeQuery(
-          "select s1 + s2, s1 - s2, s1 * s2, s1 / s2, s1 % s2 from root.test.sg1 where s1+s2 is not null && s2 is not null");
-      fail();
-    } catch (Exception e) {
-    }
-
-    try (Connection connection = EnvFactory.getEnv().getConnection();
-        Statement statement = connection.createStatement()) {
-
-      statement.executeQuery(
-          "select s1 as d, sin(s1), cos(s1), tan(s1) as t, s2 from root.test.sg1 where d is not null && tan(s1) is not null && t is not null limit 5");
-      fail();
-    } catch (Exception e) {
-    }
+    String[] retArray =
+        new String[] {
+          "1,true,1,1.0,1,",
+          "3,false,null,null,null,",
+          "6,true,6,6.0,6,",
+          "7,true,null,7.0,null,",
+          "8,true,8,8.0,null,",
+          "9,false,9,9.0,9,",
+          "10,true,10,10.0,10,"
+        };
+    resultSetEqualTest(
+        "select s1, s2, s3, s4 from root.test.sg1 where s1 is not null && usage is null",
+        expectedHeader,
+        retArray);
   }
 
   @Ignore
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/process/FilterAndProjectOperator.java b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/process/FilterAndProjectOperator.java
index eed0895a47..fcb03660a8 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/process/FilterAndProjectOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/process/FilterAndProjectOperator.java
@@ -23,9 +23,8 @@ import org.apache.iotdb.db.mpp.execution.operator.Operator;
 import org.apache.iotdb.db.mpp.execution.operator.OperatorContext;
 import org.apache.iotdb.db.mpp.transformation.dag.column.ColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.binary.BinaryColumnTransformer;
-import org.apache.iotdb.db.mpp.transformation.dag.column.leaf.ConstantColumnTransformer;
+import org.apache.iotdb.db.mpp.transformation.dag.column.leaf.IdentityColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.leaf.LeafColumnTransformer;
-import org.apache.iotdb.db.mpp.transformation.dag.column.leaf.TimeColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.multi.MappableUDFColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.ternary.TernaryColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.unary.UnaryColumnTransformer;
@@ -272,11 +271,10 @@ public class FilterAndProjectOperator implements ProcessOperator {
   private int getMaxLevelOfColumnTransformerTree(ColumnTransformer columnTransformer) {
     if (columnTransformer instanceof LeafColumnTransformer) {
       // Time column is always calculated, we ignore it here. Constant column is ignored.
-      if (columnTransformer instanceof ConstantColumnTransformer
-          || columnTransformer instanceof TimeColumnTransformer) {
-        return 0;
-      } else {
+      if (columnTransformer instanceof IdentityColumnTransformer) {
         return 1;
+      } else {
+        return 0;
       }
     } else if (columnTransformer instanceof UnaryColumnTransformer) {
       return Math.max(
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java
index dec1ba3ba8..180ac1d5c7 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java
@@ -29,6 +29,7 @@ import org.apache.iotdb.db.mpp.common.NodeRef;
 import org.apache.iotdb.db.mpp.common.header.DatasetHeader;
 import org.apache.iotdb.db.mpp.common.schematree.ISchemaTree;
 import org.apache.iotdb.db.mpp.plan.expression.Expression;
+import org.apache.iotdb.db.mpp.plan.expression.ExpressionType;
 import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.DeviceViewIntoPathDescriptor;
 import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.FillDescriptor;
 import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.GroupByTimeParameter;
@@ -247,6 +248,10 @@ public class Analysis {
   }
 
   public TSDataType getType(Expression expression) {
+    // NULL_Operand needn't check
+    if (expression.getExpressionType() == ExpressionType.NULL) {
+      return null;
+    }
     TSDataType type = expressionTypes.get(NodeRef.of(expression));
     checkArgument(type != null, "Expression not analyzed: %s", expression);
     return type;
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 3446e164e1..d0be42611a 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
@@ -23,7 +23,6 @@ import org.apache.iotdb.commons.conf.IoTDBConstant;
 import org.apache.iotdb.commons.path.MeasurementPath;
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.path.PathPatternTree;
-import org.apache.iotdb.db.exception.sql.MeasurementNotExistException;
 import org.apache.iotdb.db.exception.sql.SemanticException;
 import org.apache.iotdb.db.mpp.common.schematree.ISchemaTree;
 import org.apache.iotdb.db.mpp.plan.expression.Expression;
@@ -31,6 +30,7 @@ import org.apache.iotdb.db.mpp.plan.expression.ExpressionType;
 import org.apache.iotdb.db.mpp.plan.expression.binary.BinaryExpression;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.ConstantOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.LeafOperand;
+import org.apache.iotdb.db.mpp.plan.expression.leaf.NullOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimestampOperand;
 import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
@@ -558,19 +558,14 @@ public class ExpressionAnalyzer {
       for (PartialPath concatPath : concatPaths) {
         List<MeasurementPath> actualPaths = schemaTree.searchMeasurementPaths(concatPath).left;
         if (actualPaths.size() == 0) {
-          throw new SemanticException(
-              String.format(
-                  "the path '%s' in %s clause does not exist",
-                  concatPath, isWhere ? "WHERE" : "HAVING"));
+          return Collections.singletonList(new NullOperand());
         }
         noStarPaths.addAll(actualPaths);
       }
       return reconstructTimeSeriesOperands(noStarPaths);
-    } else if (predicate instanceof TimestampOperand) {
+    } else if (predicate instanceof LeafOperand) {
       // do nothing in the case of "where time > 5"
       return Collections.singletonList(predicate);
-    } else if (predicate instanceof ConstantOperand) {
-      return Collections.singletonList(predicate);
     } else {
       throw new IllegalArgumentException(
           "unsupported expression type: " + predicate.getExpressionType());
@@ -679,7 +674,7 @@ public class ExpressionAnalyzer {
 
       List<MeasurementPath> actualPaths = schemaTree.searchMeasurementPaths(concatPath).left;
       if (actualPaths.isEmpty()) {
-        return new ArrayList<>();
+        return Collections.emptyList();
       }
       List<PartialPath> noStarPaths = new ArrayList<>(actualPaths);
       return reconstructTimeSeriesOperands(noStarPaths);
@@ -760,10 +755,7 @@ public class ExpressionAnalyzer {
 
       List<MeasurementPath> noStarPaths = schemaTree.searchMeasurementPaths(concatPath).left;
       if (noStarPaths.size() == 0) {
-        throw new MeasurementNotExistException(
-            String.format(
-                "ALIGN BY DEVICE: Measurement '%s' does not exist in device '%s'",
-                measurement, devicePath));
+        return Collections.singletonList(new NullOperand());
       }
       return reconstructTimeSeriesOperands(noStarPaths);
     } else if (predicate instanceof TimestampOperand) {
@@ -842,7 +834,10 @@ public class ExpressionAnalyzer {
       Pair<Filter, Boolean> childResultPair =
           extractGlobalTimeFilter(
               ((UnaryExpression) predicate).getExpression(), canRewrite, isFirstOr);
-      return new Pair<>(FilterFactory.not(childResultPair.left), childResultPair.right);
+      if (childResultPair.left != null) {
+        return new Pair<>(FilterFactory.not(childResultPair.left), childResultPair.right);
+      }
+      return new Pair<>(null, true);
     } else if (predicate.isCompareBinaryExpression()) {
       Filter timeInLeftFilter =
           constructTimeFilter(
@@ -965,7 +960,7 @@ public class ExpressionAnalyzer {
       return resultExpressions;
     } else if (expression instanceof TimeSeriesOperand) {
       return Collections.singletonList(expression);
-    } else if (expression instanceof TimestampOperand || expression instanceof ConstantOperand) {
+    } else if (expression instanceof LeafOperand) {
       return Collections.emptyList();
     } else {
       throw new IllegalArgumentException(
@@ -1074,7 +1069,7 @@ public class ExpressionAnalyzer {
         return new TimeSeriesOperand(newPath);
       }
       return expression;
-    } else if (expression instanceof ConstantOperand || expression instanceof TimestampOperand) {
+    } else if (expression instanceof LeafOperand) {
       // do nothing
       return expression;
     } else {
@@ -1097,6 +1092,8 @@ public class ExpressionAnalyzer {
       return false;
     } else if (expression instanceof ConstantOperand) {
       return false;
+    } else if (expression instanceof NullOperand) {
+      return true;
     } else {
       throw new IllegalArgumentException(
           "unsupported expression type: " + expression.getExpressionType());
@@ -1189,7 +1186,7 @@ public class ExpressionAnalyzer {
         measurementWithSchema.setMeasurementAlias(rawPath.getMeasurementAlias());
       }
       return new TimeSeriesOperand(measurementWithSchema);
-    } else if (expression instanceof TimestampOperand || expression instanceof ConstantOperand) {
+    } else if (expression instanceof LeafOperand) {
       return expression;
     } else {
       throw new IllegalArgumentException(
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionTypeAnalyzer.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionTypeAnalyzer.java
index 0214997897..83f61afd46 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionTypeAnalyzer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionTypeAnalyzer.java
@@ -26,6 +26,7 @@ import org.apache.iotdb.db.mpp.plan.expression.binary.ArithmeticBinaryExpression
 import org.apache.iotdb.db.mpp.plan.expression.binary.CompareBinaryExpression;
 import org.apache.iotdb.db.mpp.plan.expression.binary.LogicBinaryExpression;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.ConstantOperand;
+import org.apache.iotdb.db.mpp.plan.expression.leaf.NullOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimestampOperand;
 import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
@@ -195,7 +196,9 @@ public class ExpressionTypeAnalyzer {
       final TSDataType rightExpressionDataType =
           process(compareBinaryExpression.getRightExpression(), null);
 
-      if (!leftExpressionDataType.equals(rightExpressionDataType)) {
+      if (leftExpressionDataType != null
+          && rightExpressionDataType != null
+          && !leftExpressionDataType.equals(rightExpressionDataType)) {
         final String leftExpressionString = compareBinaryExpression.getLeftExpression().toString();
         final String rightExpressionString =
             compareBinaryExpression.getRightExpression().toString();
@@ -289,6 +292,11 @@ public class ExpressionTypeAnalyzer {
       return setExpressionType(constantOperand, constantOperand.getDataType());
     }
 
+    @Override
+    public TSDataType visitNullOperand(NullOperand nullOperand, Void context) {
+      return null;
+    }
+
     private TSDataType setExpressionType(Expression expression, TSDataType type) {
       expressionTypes.put(NodeRef.of(expression), type);
       return type;
@@ -297,7 +305,7 @@ public class ExpressionTypeAnalyzer {
     private void checkInputExpressionDataType(
         String expressionString, TSDataType actual, TSDataType... expected) {
       for (TSDataType type : expected) {
-        if (actual.equals(type)) {
+        if (actual == null || actual.equals(type)) {
           return;
         }
       }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/Expression.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/Expression.java
index 3847412f71..60c8d6364a 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/Expression.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/Expression.java
@@ -36,6 +36,7 @@ import org.apache.iotdb.db.mpp.plan.expression.binary.MultiplicationExpression;
 import org.apache.iotdb.db.mpp.plan.expression.binary.NonEqualExpression;
 import org.apache.iotdb.db.mpp.plan.expression.binary.SubtractionExpression;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.ConstantOperand;
+import org.apache.iotdb.db.mpp.plan.expression.leaf.NullOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimestampOperand;
 import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
@@ -339,6 +340,10 @@ public abstract class Expression extends StatementNode {
         expression = new LogicOrExpression(byteBuffer);
         break;
 
+      case 20:
+        expression = new NullOperand();
+        break;
+
       default:
         throw new IllegalArgumentException("Invalid expression type: " + type);
     }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/ExpressionType.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/ExpressionType.java
index 0bcec3a15c..5bc43e40a0 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/ExpressionType.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/ExpressionType.java
@@ -54,6 +54,8 @@ public enum ExpressionType {
   LOGIC_AND((short) 18, (short) 300),
 
   LOGIC_OR((short) 19, (short) 200),
+
+  NULL((short) 20, (short) 1400),
   ;
 
   private final short expressionType;
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/leaf/NullOperand.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/leaf/NullOperand.java
new file mode 100644
index 0000000000..e157ddcbeb
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/leaf/NullOperand.java
@@ -0,0 +1,101 @@
+/*
+ * 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.mpp.plan.expression.leaf;
+
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
+import org.apache.iotdb.db.mpp.plan.expression.Expression;
+import org.apache.iotdb.db.mpp.plan.expression.ExpressionType;
+import org.apache.iotdb.db.mpp.plan.expression.visitor.ExpressionVisitor;
+import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.InputLocation;
+import org.apache.iotdb.db.mpp.transformation.dag.memory.LayerMemoryAssigner;
+import org.apache.iotdb.db.qp.physical.crud.UDTFPlan;
+import org.apache.iotdb.db.qp.utils.WildcardsRemover;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class NullOperand extends LeafOperand {
+  @Override
+  public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+    return visitor.visitNullOperand(this, context);
+  }
+
+  @Override
+  public ExpressionType getExpressionType() {
+    return ExpressionType.NULL;
+  }
+
+  @Override
+  protected boolean isConstantOperandInternal() {
+    return true;
+  }
+
+  @Override
+  public void concat(List<PartialPath> prefixPaths, List<Expression> resultExpressions) {
+    resultExpressions.add(this);
+  }
+
+  @Override
+  public void removeWildcards(WildcardsRemover wildcardsRemover, List<Expression> resultExpressions)
+      throws LogicalOptimizeException {
+    resultExpressions.add(this);
+  }
+
+  @Override
+  public void collectPaths(Set<PartialPath> pathSet) {
+    // do nothing
+  }
+
+  @Override
+  public void bindInputLayerColumnIndexWithExpression(UDTFPlan udtfPlan) {
+    // do nothing
+  }
+
+  @Override
+  public void bindInputLayerColumnIndexWithExpression(
+      Map<String, List<InputLocation>> inputLocations) {
+    // do nothing
+  }
+
+  @Override
+  public void updateStatisticsForMemoryAssigner(LayerMemoryAssigner memoryAssigner) {
+    // do nothing
+  }
+
+  @Override
+  protected String getExpressionStringInternal() {
+    return "NULL";
+  }
+
+  @Override
+  protected void serialize(ByteBuffer byteBuffer) {
+    // do nothing
+  }
+
+  @Override
+  protected void serialize(DataOutputStream stream) throws IOException {
+    // do nothing
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/unary/NegationExpression.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/unary/NegationExpression.java
index 7f279cd626..b213d31528 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/unary/NegationExpression.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/unary/NegationExpression.java
@@ -22,6 +22,7 @@ package org.apache.iotdb.db.mpp.plan.expression.unary;
 import org.apache.iotdb.db.mpp.plan.expression.Expression;
 import org.apache.iotdb.db.mpp.plan.expression.ExpressionType;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.ConstantOperand;
+import org.apache.iotdb.db.mpp.plan.expression.leaf.NullOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
 import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
 import org.apache.iotdb.db.mpp.plan.expression.visitor.ExpressionVisitor;
@@ -47,6 +48,7 @@ public class NegationExpression extends UnaryExpression {
   public String getExpressionStringInternal() {
     return expression instanceof TimeSeriesOperand
             || expression instanceof FunctionExpression
+            || expression instanceof NullOperand
             || (expression instanceof ConstantOperand
                 && !((ConstantOperand) expression).isNegativeNumber())
         ? "-" + expression
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/ColumnTransformerVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/ColumnTransformerVisitor.java
index 148e4009e7..d559ef1840 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/ColumnTransformerVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/ColumnTransformerVisitor.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.db.mpp.common.NodeRef;
 import org.apache.iotdb.db.mpp.plan.expression.Expression;
 import org.apache.iotdb.db.mpp.plan.expression.binary.BinaryExpression;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.ConstantOperand;
+import org.apache.iotdb.db.mpp.plan.expression.leaf.NullOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimestampOperand;
 import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
@@ -51,6 +52,7 @@ import org.apache.iotdb.db.mpp.transformation.dag.column.binary.LogicOrColumnTra
 import org.apache.iotdb.db.mpp.transformation.dag.column.leaf.ConstantColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.leaf.IdentityColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.leaf.LeafColumnTransformer;
+import org.apache.iotdb.db.mpp.transformation.dag.column.leaf.NullColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.leaf.TimeColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.multi.MappableUDFColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.ternary.BetweenColumnTransformer;
@@ -306,6 +308,21 @@ public class ColumnTransformerVisitor
     return res;
   }
 
+  @Override
+  public ColumnTransformer visitNullOperand(
+      NullOperand nullOperand, ColumnTransformerVisitorContext context) {
+    ColumnTransformer res =
+        context.cache.computeIfAbsent(
+            nullOperand,
+            e -> {
+              NullColumnTransformer columnTransformer = new NullColumnTransformer();
+              context.leafList.add(columnTransformer);
+              return columnTransformer;
+            });
+    res.addReferenceCount();
+    return res;
+  }
+
   private ColumnTransformer getConcreteUnaryColumnTransformer(
       Expression expression, ColumnTransformer childColumnTransformer, Type returnType) {
     switch (expression.getExpressionType()) {
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/ExpressionVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/ExpressionVisitor.java
index 7ebc074a99..d44306fc67 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/ExpressionVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/ExpressionVisitor.java
@@ -26,6 +26,7 @@ import org.apache.iotdb.db.mpp.plan.expression.binary.CompareBinaryExpression;
 import org.apache.iotdb.db.mpp.plan.expression.binary.LogicBinaryExpression;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.ConstantOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.LeafOperand;
+import org.apache.iotdb.db.mpp.plan.expression.leaf.NullOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimestampOperand;
 import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
@@ -127,4 +128,8 @@ public abstract class ExpressionVisitor<R, C> {
   public R visitConstantOperand(ConstantOperand constantOperand, C context) {
     return visitLeafOperand(constantOperand, context);
   }
+
+  public R visitNullOperand(NullOperand nullOperand, C context) {
+    return visitLeafOperand(nullOperand, context);
+  }
 }
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 033aaf3dd5..46eb80eadc 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
@@ -55,6 +55,7 @@ import org.apache.iotdb.db.mpp.plan.expression.binary.MultiplicationExpression;
 import org.apache.iotdb.db.mpp.plan.expression.binary.NonEqualExpression;
 import org.apache.iotdb.db.mpp.plan.expression.binary.SubtractionExpression;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.ConstantOperand;
+import org.apache.iotdb.db.mpp.plan.expression.leaf.NullOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimestampOperand;
 import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
@@ -2554,6 +2555,8 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
     } else if (constantContext.dateExpression() != null) {
       return new ConstantOperand(
           TSDataType.INT64, String.valueOf(parseDateExpression(constantContext.dateExpression())));
+    } else if (constantContext.NULL_LITERAL() != null) {
+      return new NullOperand();
     } else {
       throw new SQLParserException("Unsupported constant operand: " + text);
     }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/ColumnTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/ColumnTransformer.java
index 18a0e8a9f4..93b37217b2 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/ColumnTransformer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/ColumnTransformer.java
@@ -19,6 +19,7 @@
 
 package org.apache.iotdb.db.mpp.transformation.dag.column;
 
+import org.apache.iotdb.db.mpp.transformation.dag.column.leaf.NullColumnTransformer;
 import org.apache.iotdb.tsfile.read.common.block.column.Column;
 import org.apache.iotdb.tsfile.read.common.type.Type;
 import org.apache.iotdb.tsfile.read.common.type.TypeEnum;
@@ -64,6 +65,9 @@ public abstract class ColumnTransformer {
   }
 
   public boolean isReturnTypeNumeric() {
+    if (returnType == null) {
+      return true;
+    }
     TypeEnum typeEnum = returnType.getTypeEnum();
     return typeEnum.equals(TypeEnum.INT32)
         || typeEnum.equals(TypeEnum.INT64)
@@ -71,6 +75,33 @@ public abstract class ColumnTransformer {
         || typeEnum.equals(TypeEnum.DOUBLE);
   }
 
+  /**
+   * Return whether the types of two ColumnTransformer are equal. If one ColumnTransformer is {@link
+   * NullColumnTransformer} (Only the Type of NullColumnTransformer is null), return {@code true}
+   */
+  public static boolean typeEquals(ColumnTransformer a, ColumnTransformer b) {
+    if (a.getType() == null || b.getType() == null) {
+      return true;
+    }
+    return a.getType().getTypeEnum().equals(b.getType().getTypeEnum());
+  }
+
+  /**
+   * Return whether the type of this ColumnTransformer is equal to certain type. If this
+   * ColumnTransformer is {@link NullColumnTransformer}, return {@code true}
+   */
+  public boolean typeEquals(TypeEnum typeEnum) {
+    return returnType == null || returnType.getTypeEnum().equals(typeEnum);
+  }
+
+  /**
+   * Return whether the type of this ColumnTransformer is not equal to certain type. If this
+   * ColumnTransformer is {@link NullColumnTransformer}, return {@code true}
+   */
+  public boolean typeNotEquals(TypeEnum typeEnum) {
+    return returnType == null || !returnType.getTypeEnum().equals(typeEnum);
+  }
+
   /** Responsible for the calculation */
   protected abstract void evaluate();
 
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/CompareBinaryColumnTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/CompareBinaryColumnTransformer.java
index 3055275213..0efc6b2ab3 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/CompareBinaryColumnTransformer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/CompareBinaryColumnTransformer.java
@@ -71,10 +71,11 @@ public abstract class CompareBinaryColumnTransformer extends BinaryColumnTransfo
   @Override
   protected void checkType() {
     // Boolean type can only be compared by == or !=
-    if (leftTransformer.getType().getTypeEnum().equals(TypeEnum.BOOLEAN)
-        || rightTransformer.getType().getTypeEnum().equals(TypeEnum.BOOLEAN)) {
-      throw new UnsupportedOperationException("Unsupported Type");
+    if (leftTransformer.typeNotEquals(TypeEnum.BOOLEAN)
+        && rightTransformer.typeNotEquals(TypeEnum.BOOLEAN)) {
+      return;
     }
+    throw new UnsupportedOperationException("Unsupported Type");
   }
 
   protected int compare(double d1, double d2) {
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/CompareEqualToColumnTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/CompareEqualToColumnTransformer.java
index 3c91fd6c2a..e12a5e9d12 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/CompareEqualToColumnTransformer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/CompareEqualToColumnTransformer.java
@@ -30,7 +30,7 @@ public class CompareEqualToColumnTransformer extends CompareBinaryColumnTransfor
 
   @Override
   protected final void checkType() {
-    if (leftTransformer.getType().getTypeEnum().equals(rightTransformer.getType().getTypeEnum())) {
+    if (typeEquals(leftTransformer, rightTransformer)) {
       return;
     }
 
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicAndColumnTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicAndColumnTransformer.java
index c64725522e..e7e734acc8 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicAndColumnTransformer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicAndColumnTransformer.java
@@ -20,6 +20,8 @@
 package org.apache.iotdb.db.mpp.transformation.dag.column.binary;
 
 import org.apache.iotdb.db.mpp.transformation.dag.column.ColumnTransformer;
+import org.apache.iotdb.tsfile.read.common.block.column.Column;
+import org.apache.iotdb.tsfile.read.common.block.column.ColumnBuilder;
 import org.apache.iotdb.tsfile.read.common.type.Type;
 
 public class LogicAndColumnTransformer extends LogicBinaryColumnTransformer {
@@ -28,6 +30,34 @@ public class LogicAndColumnTransformer extends LogicBinaryColumnTransformer {
     super(returnType, leftTransformer, rightTransformer);
   }
 
+  @Override
+  protected void doTransform(
+      Column leftColumn, Column rightColumn, ColumnBuilder builder, int positionCount) {
+    for (int i = 0; i < positionCount; i++) {
+      if (!leftColumn.isNull(i) && !rightColumn.isNull(i)) {
+        returnType.writeBoolean(
+            builder,
+            transform(
+                leftTransformer.getType().getBoolean(leftColumn, i),
+                rightTransformer.getType().getBoolean(rightColumn, i)));
+      } else if (!leftColumn.isNull(i)) {
+        if (leftTransformer.getType().getBoolean(leftColumn, i)) {
+          builder.appendNull();
+        } else {
+          returnType.writeBoolean(builder, false);
+        }
+      } else if (!rightColumn.isNull(i)) {
+        if (rightTransformer.getType().getBoolean(rightColumn, i)) {
+          builder.appendNull();
+        } else {
+          returnType.writeBoolean(builder, false);
+        }
+      } else {
+        builder.appendNull();
+      }
+    }
+  }
+
   @Override
   protected boolean transform(boolean left, boolean right) {
     return left && right;
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicBinaryColumnTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicBinaryColumnTransformer.java
index c6edc42c20..c8263616ca 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicBinaryColumnTransformer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicBinaryColumnTransformer.java
@@ -20,8 +20,6 @@
 package org.apache.iotdb.db.mpp.transformation.dag.column.binary;
 
 import org.apache.iotdb.db.mpp.transformation.dag.column.ColumnTransformer;
-import org.apache.iotdb.tsfile.read.common.block.column.Column;
-import org.apache.iotdb.tsfile.read.common.block.column.ColumnBuilder;
 import org.apache.iotdb.tsfile.read.common.type.Type;
 import org.apache.iotdb.tsfile.read.common.type.TypeEnum;
 
@@ -31,28 +29,6 @@ public abstract class LogicBinaryColumnTransformer extends BinaryColumnTransform
     super(returnType, leftTransformer, rightTransformer);
   }
 
-  @Override
-  protected void doTransform(
-      Column leftColumn, Column rightColumn, ColumnBuilder builder, int positionCount) {
-    for (int i = 0; i < positionCount; i++) {
-      if (!leftColumn.isNull(i) && !rightColumn.isNull(i)) {
-        returnType.writeBoolean(
-            builder,
-            transform(
-                leftTransformer.getType().getBoolean(leftColumn, i),
-                rightTransformer.getType().getBoolean(rightColumn, i)));
-      } else if (!leftColumn.isNull(i)) {
-        returnType.writeBoolean(
-            builder, transform(leftTransformer.getType().getBoolean(leftColumn, i), false));
-      } else if (!rightColumn.isNull(i)) {
-        returnType.writeBoolean(
-            builder, transform(false, rightTransformer.getType().getBoolean(rightColumn, i)));
-      } else {
-        builder.appendNull();
-      }
-    }
-  }
-
   @Override
   protected void checkType() {
     if (!leftTransformer.getType().getTypeEnum().equals(TypeEnum.BOOLEAN)
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicOrColumnTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicOrColumnTransformer.java
index 135a8ff348..5f11a3811e 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicOrColumnTransformer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicOrColumnTransformer.java
@@ -20,6 +20,8 @@
 package org.apache.iotdb.db.mpp.transformation.dag.column.binary;
 
 import org.apache.iotdb.db.mpp.transformation.dag.column.ColumnTransformer;
+import org.apache.iotdb.tsfile.read.common.block.column.Column;
+import org.apache.iotdb.tsfile.read.common.block.column.ColumnBuilder;
 import org.apache.iotdb.tsfile.read.common.type.Type;
 
 public class LogicOrColumnTransformer extends LogicBinaryColumnTransformer {
@@ -28,6 +30,34 @@ public class LogicOrColumnTransformer extends LogicBinaryColumnTransformer {
     super(returnType, leftTransformer, rightTransformer);
   }
 
+  @Override
+  protected void doTransform(
+      Column leftColumn, Column rightColumn, ColumnBuilder builder, int positionCount) {
+    for (int i = 0; i < positionCount; i++) {
+      if (!leftColumn.isNull(i) && !rightColumn.isNull(i)) {
+        returnType.writeBoolean(
+            builder,
+            transform(
+                leftTransformer.getType().getBoolean(leftColumn, i),
+                rightTransformer.getType().getBoolean(rightColumn, i)));
+      } else if (!leftColumn.isNull(i)) {
+        if (leftTransformer.getType().getBoolean(leftColumn, i)) {
+          returnType.writeBoolean(builder, true);
+        } else {
+          builder.appendNull();
+        }
+      } else if (!rightColumn.isNull(i)) {
+        if (rightTransformer.getType().getBoolean(rightColumn, i)) {
+          returnType.writeBoolean(builder, true);
+        } else {
+          builder.appendNull();
+        }
+      } else {
+        builder.appendNull();
+      }
+    }
+  }
+
   @Override
   protected boolean transform(boolean left, boolean right) {
     return left || right;
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicOrColumnTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/leaf/NullColumnTransformer.java
similarity index 60%
copy from server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicOrColumnTransformer.java
copy to server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/leaf/NullColumnTransformer.java
index 135a8ff348..139a8b165d 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/binary/LogicOrColumnTransformer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/leaf/NullColumnTransformer.java
@@ -17,19 +17,22 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.mpp.transformation.dag.column.binary;
+package org.apache.iotdb.db.mpp.transformation.dag.column.leaf;
 
-import org.apache.iotdb.db.mpp.transformation.dag.column.ColumnTransformer;
-import org.apache.iotdb.tsfile.read.common.type.Type;
+import org.apache.iotdb.tsfile.read.common.block.TsBlock;
+import org.apache.iotdb.tsfile.read.common.block.column.NullColumn;
 
-public class LogicOrColumnTransformer extends LogicBinaryColumnTransformer {
-  public LogicOrColumnTransformer(
-      Type returnType, ColumnTransformer leftTransformer, ColumnTransformer rightTransformer) {
-    super(returnType, leftTransformer, rightTransformer);
+public class NullColumnTransformer extends LeafColumnTransformer {
+
+  public NullColumnTransformer() {
+    super(null);
   }
 
   @Override
-  protected boolean transform(boolean left, boolean right) {
-    return left || right;
+  public void tryEvaluate() {}
+
+  @Override
+  public void initFromTsBlock(TsBlock input) {
+    initializeColumnCache(new NullColumn(input.getPositionCount()));
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/ternary/CompareTernaryColumnTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/ternary/CompareTernaryColumnTransformer.java
index 41c1e1ddbf..9b09e77ac9 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/ternary/CompareTernaryColumnTransformer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/ternary/CompareTernaryColumnTransformer.java
@@ -51,18 +51,17 @@ public abstract class CompareTernaryColumnTransformer extends TernaryColumnTrans
 
   @Override
   protected final void checkType() {
-    if ((firstColumnTransformer.getType().getTypeEnum())
-            .equals(secondColumnTransformer.getType().getTypeEnum())
-        && (firstColumnTransformer.getType().getTypeEnum())
-            .equals(thirdColumnTransformer.getType().getTypeEnum())) {
+    if (firstColumnTransformer.isReturnTypeNumeric()
+            && secondColumnTransformer.isReturnTypeNumeric()
+            && thirdColumnTransformer.isReturnTypeNumeric()
+        || firstColumnTransformer.typeEquals(TypeEnum.BINARY)
+            && secondColumnTransformer.typeEquals(TypeEnum.BINARY)
+            && thirdColumnTransformer.typeEquals(TypeEnum.BINARY)) {
       return;
     }
 
-    if (firstColumnTransformer.getType().getTypeEnum().equals(TypeEnum.BOOLEAN)
-        || secondColumnTransformer.getType().getTypeEnum().equals(TypeEnum.BOOLEAN)
-        || thirdColumnTransformer.getType().getTypeEnum().equals(TypeEnum.BOOLEAN)) {
-      throw new UnsupportedOperationException("Unsupported Type");
-    }
+    throw new UnsupportedOperationException(
+        String.format("The Type of three subExpression should be all Numeric or Text"));
   }
 
   protected abstract void doTransform(
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/InColumnTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/InColumnTransformer.java
index 994c8c6c95..b53e02e59b 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/InColumnTransformer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/InColumnTransformer.java
@@ -47,7 +47,10 @@ public class InColumnTransformer extends UnaryColumnTransformer {
       Set<String> values) {
     super(returnType, childColumnTransformer);
     satisfy = isNotIn ? new NotInSatisfy() : new InSatisfy();
-    this.childType = childColumnTransformer.getType().getTypeEnum();
+    this.childType =
+        childColumnTransformer.getType() == null
+            ? null
+            : childColumnTransformer.getType().getTypeEnum();
     initTypedSet(values);
   }
 
@@ -85,6 +88,9 @@ public class InColumnTransformer extends UnaryColumnTransformer {
   }
 
   private void initTypedSet(Set<String> values) {
+    if (childType == null) {
+      return;
+    }
     switch (childType) {
       case INT32:
         intSet = new HashSet<>();
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/LogicNotColumnTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/LogicNotColumnTransformer.java
index d96685f836..ce7e7d8fc4 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/LogicNotColumnTransformer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/LogicNotColumnTransformer.java
@@ -44,7 +44,7 @@ public class LogicNotColumnTransformer extends UnaryColumnTransformer {
 
   @Override
   protected void checkType() {
-    if (!(childColumnTransformer.getType().getTypeEnum().equals(TypeEnum.BOOLEAN))) {
+    if (!(childColumnTransformer.typeEquals(TypeEnum.BOOLEAN))) {
       throw new UnsupportedOperationException(
           "Unsupported Type: " + childColumnTransformer.getType().getTypeEnum());
     }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/RegularColumnTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/RegularColumnTransformer.java
index 5de3496612..f6fefa637d 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/RegularColumnTransformer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/RegularColumnTransformer.java
@@ -53,7 +53,7 @@ public class RegularColumnTransformer extends UnaryColumnTransformer {
 
   @Override
   protected void checkType() {
-    if (!(childColumnTransformer.getType().getTypeEnum().equals(TypeEnum.BINARY))) {
+    if (!childColumnTransformer.typeEquals(TypeEnum.BINARY)) {
       throw new UnsupportedOperationException(
           "Unsupported Type: " + childColumnTransformer.getType().getTypeEnum());
     }
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/block/column/NullColumn.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/block/column/NullColumn.java
index 587b7a7c32..29a9f8ae6b 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/block/column/NullColumn.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/block/column/NullColumn.java
@@ -20,13 +20,98 @@ package org.apache.iotdb.tsfile.read.common.block.column;
 
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 
+import org.openjdk.jol.info.ClassLayout;
+
 import static java.util.Objects.requireNonNull;
+import static org.apache.iotdb.tsfile.read.common.block.column.ColumnUtil.checkValidRegion;
 
 /**
  * This column is used to represent columns that only contain null values. But its positionCount has
  * to be consistent with corresponding valueColumn.
  */
-public class NullColumn {
+public class NullColumn implements Column {
+
+  private static final int INSTANCE_SIZE =
+      ClassLayout.parseClass(BooleanColumn.class).instanceSize();
+
+  private final int positionCount;
+
+  private final int arrayOffset;
+
+  private final long retainedSizeInBytes;
+
+  public NullColumn(int positionCount) {
+    if (positionCount < 0) {
+      throw new IllegalArgumentException("positionCount is negative");
+    }
+    this.positionCount = positionCount;
+    arrayOffset = 0;
+    retainedSizeInBytes = INSTANCE_SIZE;
+  }
+
+  public NullColumn(int arrayOffset, int positionCount) {
+    if (arrayOffset < 0) {
+      throw new IllegalArgumentException("arrayOffset is negative");
+    }
+    this.arrayOffset = positionCount;
+    if (positionCount < 0) {
+      throw new IllegalArgumentException("positionCount is negative");
+    }
+    this.positionCount = positionCount;
+    retainedSizeInBytes = INSTANCE_SIZE;
+  }
+
+  @Override
+  public TSDataType getDataType() {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  @Override
+  public ColumnEncoding getEncoding() {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  @Override
+  public boolean mayHaveNull() {
+    return true;
+  }
+
+  @Override
+  public boolean isNull(int position) {
+    return true;
+  }
+
+  @Override
+  public boolean[] isNull() {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  @Override
+  public int getPositionCount() {
+    return positionCount;
+  }
+
+  @Override
+  public long getRetainedSizeInBytes() {
+    return retainedSizeInBytes;
+  }
+
+  @Override
+  public Column getRegion(int positionOffset, int length) {
+    checkValidRegion(getPositionCount(), positionOffset, length);
+    return new NullColumn(positionOffset + arrayOffset, length);
+  }
+
+  @Override
+  public Column subColumn(int fromIndex) {
+    if (fromIndex > positionCount) {
+      throw new IllegalArgumentException("fromIndex is not valid");
+    }
+    return new NullColumn(arrayOffset + fromIndex, positionCount - fromIndex);
+  }
+
+  @Override
+  public void reverse() {}
 
   public static Column create(TSDataType dataType, int positionCount) {
     requireNonNull(dataType, "dataType is null");