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)));
+ }
+}