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");