This is an automated email from the ASF dual-hosted git repository.

mbudiu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/main by this push:
     new 6b577851fb [CALCITE-6422] Query with '<>' throws NullPointerException 
during materialized view matching
6b577851fb is described below

commit 6b577851fbdc4cb87aca2c939cf74bfd9d5f3eb8
Author: Mou Wu <[email protected]>
AuthorDate: Mon May 27 16:52:05 2024 +0800

    [CALCITE-6422] Query with '<>' throws NullPointerException during 
materialized view matching
---
 .../apache/calcite/plan/SubstitutionVisitor.java   |  6 ++-
 .../apache/calcite/test/MaterializationTest.java   |  4 ++
 .../test/MaterializedViewRelOptRulesTest.java      | 13 ++++++
 .../calcite/test/schemata/hr/NullableTest.java     | 50 ++++++++++++++++++++++
 4 files changed, 71 insertions(+), 2 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java 
b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
index 2068305321..4688a4bb7a 100644
--- a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
+++ b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
@@ -443,7 +443,8 @@ public class SubstitutionVisitor {
     for (RexNode disjunction : disjunctions) {
       switch (disjunction.getKind()) {
       case LITERAL:
-        if (!RexLiteral.booleanValue(disjunction)) {
+        if (!RexLiteral.isNullLiteral(disjunction)
+            && !RexLiteral.booleanValue(disjunction)) {
           return false;
         }
         break;
@@ -454,7 +455,8 @@ public class SubstitutionVisitor {
     for (RexNode disjunction : notDisjunctions) {
       switch (disjunction.getKind()) {
       case LITERAL:
-        if (RexLiteral.booleanValue(disjunction)) {
+        if (!RexLiteral.isNullLiteral(disjunction)
+            && RexLiteral.booleanValue(disjunction)) {
           return false;
         }
         break;
diff --git 
a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java 
b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
index 9e4aad39fe..c9333a78d3 100644
--- a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
+++ b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
@@ -35,6 +35,7 @@ import org.apache.calcite.test.schemata.hr.Employee;
 import org.apache.calcite.test.schemata.hr.Event;
 import org.apache.calcite.test.schemata.hr.HrSchema;
 import org.apache.calcite.test.schemata.hr.Location;
+import org.apache.calcite.test.schemata.hr.NullableTest;
 import org.apache.calcite.util.JsonBuilder;
 import org.apache.calcite.util.Smalls;
 import org.apache.calcite.util.TryThreadLocal;
@@ -416,6 +417,9 @@ public class MaterializationTest {
         new Dependent(10, "Michael"),
         new Dependent(10, "Jane"),
     };
+    public final NullableTest[] nullables = {
+        new NullableTest(null, null, 1),
+    };
     public final Dependent[] locations = {
         new Dependent(10, "San Francisco"),
         new Dependent(20, "San Diego"),
diff --git 
a/core/src/test/java/org/apache/calcite/test/MaterializedViewRelOptRulesTest.java
 
b/core/src/test/java/org/apache/calcite/test/MaterializedViewRelOptRulesTest.java
index ccbb851412..d15fdbeafa 100644
--- 
a/core/src/test/java/org/apache/calcite/test/MaterializedViewRelOptRulesTest.java
+++ 
b/core/src/test/java/org/apache/calcite/test/MaterializedViewRelOptRulesTest.java
@@ -1227,4 +1227,17 @@ class MaterializedViewRelOptRulesTest {
             + "    EnumerableTableScan(table=[[hr, MV0]]")
         .ok();
   }
+
+  @Test public void testNpeInSplitFilterOfSubstitutionVisitor() {
+    sql("select \"col1\", \"col2\""
+            + " from \"nullables\""
+            + " where \"col1\" <> \"col2\" and \"col3\" = 1",
+        "select \"col1\", \"col2\""
+            + " from \"nullables\""
+            + " where \"col1\" = \"col2\" and \"col3\" = 1")
+        .checkingThatResultContains(""
+            + "EnumerableCalc(expr#0..2=[{inputs}], expr#3=[=($t0, $t1)], 
expr#4=[CAST($t2):INTEGER NOT NULL], expr#5=[1], expr#6=[=($t4, $t5)], 
expr#7=[AND($t3, $t6)], proj#0..1=[{exprs}], $condition=[$t7])\n"
+            + "  EnumerableTableScan(table=[[hr, nullables]])")
+        .ok();
+  }
 }
diff --git 
a/testkit/src/main/java/org/apache/calcite/test/schemata/hr/NullableTest.java 
b/testkit/src/main/java/org/apache/calcite/test/schemata/hr/NullableTest.java
new file mode 100644
index 0000000000..db7da76f93
--- /dev/null
+++ 
b/testkit/src/main/java/org/apache/calcite/test/schemata/hr/NullableTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.calcite.test.schemata.hr;
+
+import java.util.Objects;
+
+/**
+ * A table model that contains nullable columns.
+ */
+public class NullableTest {
+  public final Integer col1;
+  public final Integer col2;
+  public final int col3;
+
+  public NullableTest(Integer col1, Integer col2, int col3) {
+    this.col1 = col1;
+    this.col2 = col2;
+    this.col3 = col3;
+  }
+
+  @Override public String toString() {
+    return "DependentNullable [col1: " + col1 + ", col2: " + col2 + ", col3: " 
+ col3 + "]";
+  }
+
+  @Override public boolean equals(Object obj) {
+    return obj == this
+        || obj instanceof NullableTest
+        && Objects.equals(col1, ((NullableTest) obj).col1)
+        && Objects.equals(col2, ((NullableTest) obj).col2)
+        && col3 == ((NullableTest) obj).col3;
+  }
+
+  @Override public int hashCode() {
+    return Objects.hash(col1, col2, col3);
+  }
+}

Reply via email to