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

xiong 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 583e73f1a3 [CALCITE-7373] FILTER_INTO_JOIN should not push Filter into 
a join when the Filter contains non-deterministic function
583e73f1a3 is described below

commit 583e73f1a3723ba47d3f9a0cdbaefbe8c83c9dea
Author: Xiong Duan <[email protected]>
AuthorDate: Thu Jan 15 19:24:32 2026 +0800

    [CALCITE-7373] FILTER_INTO_JOIN should not push Filter into a join when the 
Filter contains non-deterministic function
---
 .../apache/calcite/rel/rules/FilterJoinRule.java   |  9 +++++
 .../org/apache/calcite/test/RelOptRulesTest.java   | 27 +++++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 44 ++++++++++++++++++++++
 3 files changed, 80 insertions(+)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
index 1f80126aa8..9c6b560bfa 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
@@ -72,6 +72,15 @@ protected FilterJoinRule(C config) {
 
   protected void perform(RelOptRuleCall call, @Nullable Filter filter,
       Join join) {
+    // Skip non-deterministic filter condition
+    if (filter != null && !RexUtil.isDeterministic(filter.getCondition())) {
+      return;
+    }
+    // Skip non-deterministic join condition
+    if (!RexUtil.isDeterministic(join.getCondition())) {
+      return;
+    }
+
     List<RexNode> joinFilters =
         RelOptUtil.conjunctions(join.getCondition());
     final List<RexNode> origJoinFilters = ImmutableList.copyOf(joinFilters);
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java 
b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 899635c38c..f46030dd8b 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -2187,6 +2187,33 @@ private void 
checkSemiOrAntiJoinProjectTranspose(JoinRelType type) {
     assertTrue(join.getHints().contains(noHashJoinHint));
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-7373";>[CALCITE-7373]
+   * FILTER_INTO_JOIN should not push Filter into a join
+   * when the Filter contains non-deterministic function</a>. */
+  @Test void testPushFilterThroughJoinWithNonDeterministic() {
+    final String sql = "select * from (\n"
+        + "  select * from dept inner join\n"
+        + "     emp on dept.deptno = emp.deptno) R\n"
+        + "where 0.9 <= rand()";
+    sql(sql)
+        .withRule(CoreRules.FILTER_PROJECT_TRANSPOSE,
+            CoreRules.FILTER_INTO_JOIN,
+            CoreRules.JOIN_CONDITION_PUSH)
+        .check();
+  }
+
+  @Test void testPushJoinConditionWithNonDeterministic() {
+    final String sql = "select * from (\n"
+        + "  select * from dept inner join\n"
+        + "     emp on dept.deptno = emp.deptno and emp.mgr <= rand()) R\n";
+    sql(sql)
+        .withRule(CoreRules.FILTER_PROJECT_TRANSPOSE,
+            CoreRules.FILTER_INTO_JOIN,
+            CoreRules.JOIN_CONDITION_PUSH)
+        .checkUnchanged();
+  }
+
   /** Test case for
    * <a href="https://issues.apache.org/jira/browse/CALCITE-438";>[CALCITE-438]
    * Push predicates through SemiJoin</a>. */
diff --git 
a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml 
b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 193b7c87db..c7c39f82a8 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -14228,6 +14228,34 @@ LogicalProject(DNAME=[$1])
     LogicalTableScan(table=[[scott, DEPT]])
     LogicalFilter(condition=[=($5, 100)])
       LogicalTableScan(table=[[scott, EMP]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testPushFilterThroughJoinWithNonDeterministic">
+    <Resource name="sql">
+      <![CDATA[select * from (
+  select * from dept inner join
+     emp on dept.deptno = emp.deptno) R
+where 0.9 <= rand()]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(DEPTNO=[$0], NAME=[$1], EMPNO=[$2], ENAME=[$3], JOB=[$4], 
MGR=[$5], HIREDATE=[$6], SAL=[$7], COMM=[$8], DEPTNO0=[$9], SLACKER=[$10])
+  LogicalFilter(condition=[<=(CAST(0.9:DECIMAL(2, 1)):DOUBLE NOT NULL, 
RAND())])
+    LogicalProject(DEPTNO=[$0], NAME=[$1], EMPNO=[$2], ENAME=[$3], JOB=[$4], 
MGR=[$5], HIREDATE=[$6], SAL=[$7], COMM=[$8], DEPTNO0=[$9], SLACKER=[$10])
+      LogicalJoin(condition=[=($0, $9)], joinType=[inner])
+        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(DEPTNO=[$0], NAME=[$1], EMPNO=[$2], ENAME=[$3], JOB=[$4], 
MGR=[$5], HIREDATE=[$6], SAL=[$7], COMM=[$8], DEPTNO0=[$9], SLACKER=[$10])
+  LogicalProject(DEPTNO=[$0], NAME=[$1], EMPNO=[$2], ENAME=[$3], JOB=[$4], 
MGR=[$5], HIREDATE=[$6], SAL=[$7], COMM=[$8], DEPTNO0=[$9], SLACKER=[$10])
+    LogicalFilter(condition=[<=(CAST(0.9:DECIMAL(2, 1)):DOUBLE NOT NULL, 
RAND())])
+      LogicalJoin(condition=[=($0, $9)], joinType=[inner])
+        LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
     </Resource>
   </TestCase>
@@ -14337,6 +14365,22 @@ LogicalProject(DEPTNO=[$0], DEPTNO0=[$9])
         LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
       LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], 
HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], $f9=[*($7, 2)])
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testPushJoinConditionWithNonDeterministic">
+    <Resource name="sql">
+      <![CDATA[select * from (
+  select * from dept inner join
+     emp on dept.deptno = emp.deptno and emp.mgr <= rand()) R
+]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(DEPTNO=[$0], NAME=[$1], EMPNO=[$2], ENAME=[$3], JOB=[$4], 
MGR=[$5], HIREDATE=[$6], SAL=[$7], COMM=[$8], DEPTNO0=[$9], SLACKER=[$10])
+  LogicalJoin(condition=[AND(=($0, $9), <=(CAST($5):DOUBLE, RAND()))], 
joinType=[inner])
+    LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
     </Resource>
   </TestCase>

Reply via email to