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

cancai 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 93c792fb19 [CALCITE-7450] ValuesReduceRule incorrectly drops tuples 
when filter condition is irreducible
93c792fb19 is described below

commit 93c792fb19c469c801134e1da83f65c414aaeffc
Author: Darpan <[email protected]>
AuthorDate: Wed Mar 25 11:52:51 2026 +0530

    [CALCITE-7450] ValuesReduceRule incorrectly drops tuples when filter 
condition is irreducible
    
    When the filter condition contains a UDF that cannot be reduced to a
    RexLiteral (e.g., no Janino CallImplementor), isAlwaysTrue() returns
    false for the unreduced RexCall, causing the rule to incorrectly drop
    the tuple. The fix checks whether the reduced value is a RexLiteral
    before evaluating isAlwaysTrue(); if it is not, the rule bails out
    and leaves the plan unchanged.
---
 .../apache/calcite/rel/rules/ValuesReduceRule.java | 14 ++++-
 .../calcite/rel/rules/ValuesReduceRuleTest.java    | 69 ++++++++++++++++++++++
 2 files changed, 80 insertions(+), 3 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
index 3b8d03e57c..acd80a81d9 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
@@ -186,9 +186,17 @@ protected void apply(RelOptRuleCall call, @Nullable 
LogicalProject project,
         final RexNode reducedValue =
             reducibleExps.get((row * fieldsPerRow) + i);
         ++i;
-        if (!reducedValue.isAlwaysTrue()) {
-          ++changeCount;
-          continue;
+        // Condition reduced to a literal (or CAST(NULL AS type));
+        // evaluate it to decide whether to keep or drop the tuple.
+        if (reducedValue instanceof RexLiteral
+            || RexUtil.isNullLiteral(reducedValue, true)) {
+          if (!reducedValue.isAlwaysTrue()) {
+            ++changeCount;
+            continue;
+          }
+        } else {
+          // Condition could not be reduced to a literal
+          return;
         }
       }
 
diff --git 
a/core/src/test/java/org/apache/calcite/rel/rules/ValuesReduceRuleTest.java 
b/core/src/test/java/org/apache/calcite/rel/rules/ValuesReduceRuleTest.java
new file mode 100644
index 0000000000..81472fce76
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/rel/rules/ValuesReduceRuleTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.rel.rules;
+
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.hep.HepPlanner;
+import org.apache.calcite.plan.hep.HepProgram;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.tools.FrameworkConfig;
+import org.apache.calcite.tools.Frameworks;
+import org.apache.calcite.tools.Planner;
+
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+/**
+ * Tests for {@link ValuesReduceRule}.
+ */
+class ValuesReduceRuleTest {
+
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-7450";>[CALCITE-7450]
+   * ValuesReduceRule incorrectly drops tuples when filter condition is
+   * irreducible</a>.
+   *
+   * <p> {@code RAND()} function, is non-deterministic
+   * therefore not reduced by {@code ReduceExpressionsRule}. */
+  @Test void testFilterWithNonDeterministicConditionDoesNotDropTuples()
+      throws Exception {
+    final FrameworkConfig config = Frameworks.newConfigBuilder()
+        .defaultSchema(Frameworks.createRootSchema(true))
+        .parserConfig(SqlParser.config().withCaseSensitive(false))
+        .build();
+
+    final Planner planner = Frameworks.getPlanner(config);
+    final String sql = "SELECT * FROM (VALUES (0, 1, 2), (3, 4, 5)) "
+        + "AS t(a, b, c) WHERE RAND(t.a) > 0.5";
+    final RelNode planBefore =
+        planner.rel(planner.validate(planner.parse(sql))).rel;
+
+    final HepProgram program = HepProgram.builder()
+        .addRuleInstance(CoreRules.PROJECT_FILTER_VALUES_MERGE)
+        .build();
+    final HepPlanner hepPlanner = new HepPlanner(program);
+    hepPlanner.setRoot(planBefore);
+    final RelNode planAfter = hepPlanner.findBestExp();
+
+    // RAND() is non-deterministic, so the condition cannot be reduced.
+    // The plan must remain unchanged.
+    assertThat(RelOptUtil.toString(planAfter), 
is(RelOptUtil.toString(planBefore)));
+  }
+}

Reply via email to