Hello,

I think I have hit a bug in the MultiJoinOptimizeBushyRule planner rule, but I 
could not figure out how to file an issue on the JIRA.
If you give me some guidance I can file the issue there directly.

The reproduction is easy: just modify the following test case from 
PlannerTest.java:

--- a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
@@ -1005,7 +1005,7 @@ private void checkJoinNWay(int n) throws Exception {
   private void checkHeuristic(String sql, String expected) throws Exception {
     Planner planner = getPlanner(null,
-        Programs.heuristicJoinOrder(Programs.RULE_SET, false, 0));
+        Programs.heuristicJoinOrder(Programs.RULE_SET, true, 0));
     SqlNode parse = planner.parse(sql);
     SqlNode validate = planner.validate(parse);
     RelNode convert = planner.rel(validate).rel;

Then the test fails with the exception shown below. This happens with the 
latest version of calcite, the main branch.
It looks like the rule does not account for the fact that outer joins can 
produce results with a different nullability than the input relations.

Thank you,
Mihai

java.lang.RuntimeException: Error while applying rule 
MultiJoinOptimizeBushyRule, args 
[rel#44:MultiJoin.NONE.[](input#0=RelSubset#42,input#1=RelSubset#43,joinFilter=true,isFullOuterJoin=false,joinTypes=[RIGHT,
 INNER],outerJoinConditions=[=($0, $10), NULL],projFields=[ALL, ALL])]

               at 
org.apache.calcite.plan.volcano.VolcanoRuleCall.onMatch(VolcanoRuleCall.java:250)
               at 
org.apache.calcite.plan.volcano.IterativeRuleDriver.drive(IterativeRuleDriver.java:59)
               at 
org.apache.calcite.plan.volcano.VolcanoPlanner.findBestExp(VolcanoPlanner.java:523)
               at 
org.apache.calcite.tools.Programs$RuleSetProgram.run(Programs.java:318)
               at 
org.apache.calcite.tools.Programs$SequenceProgram.run(Programs.java:337)
               at 
org.apache.calcite.tools.Programs.lambda$heuristicJoinOrder$1(Programs.java:223)
               at 
org.apache.calcite.prepare.PlannerImpl.transform(PlannerImpl.java:373)
               at 
org.apache.calcite.tools.PlannerTest.checkHeuristic(PlannerTest.java:1014)
               at 
org.apache.calcite.tools.PlannerTest.testHeuristicRightJoin(PlannerTest.java:1003)
               at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
               at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
               at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
               at java.lang.reflect.Method.invoke(Method.java:498)
               at 
org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
               at 
org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
               at 
org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
               at 
org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
               at 
org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
               at 
org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
               at 
org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
               at 
org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
               at 
org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
               at 
org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
               at 
org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
               at 
org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
               at 
org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
               at 
org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
               at 
org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
               at 
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
               at 
org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
               at 
org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
               at 
org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
               at 
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
               at 
org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
               at 
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
               at java.util.ArrayList.forEach(ArrayList.java:1257)
               at 
org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
               at 
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
               at 
org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
               at 
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
               at java.util.ArrayList.forEach(ArrayList.java:1257)
               at 
org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
               at 
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
               at 
org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
               at 
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
               at 
org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
               at 
org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
               at 
org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
               at 
org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
               at 
org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
               at 
org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
               at 
org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
               at 
org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
               at 
org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
               at 
org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
               at 
org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
               at 
org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
               at 
org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
               at 
com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
               at 
com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
               at 
com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
               at 
com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
               at 
com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
               at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.RuntimeException: Error occurred while applying rule 
MultiJoinOptimizeBushyRule
               at 
org.apache.calcite.plan.volcano.VolcanoRuleCall.transformTo(VolcanoRuleCall.java:157)
               at 
org.apache.calcite.plan.RelOptRuleCall.transformTo(RelOptRuleCall.java:269)
               at 
org.apache.calcite.plan.RelOptRuleCall.transformTo(RelOptRuleCall.java:284)
               at 
org.apache.calcite.rel.rules.MultiJoinOptimizeBushyRule.onMatch(MultiJoinOptimizeBushyRule.java:292)
               at 
org.apache.calcite.plan.volcano.VolcanoRuleCall.onMatch(VolcanoRuleCall.java:223)
               ... 77 more
Caused by: java.lang.IllegalArgumentException: Type mismatch:
rel rowtype: RecordType(JavaType(int) NOT NULL empid, JavaType(int) NOT NULL 
deptno, JavaType(class java.lang.String) name, JavaType(float) NOT NULL salary, 
JavaType(class java.lang.Integer) commission, JavaType(int) NOT NULL deptno0, 
JavaType(class java.lang.String) name0, RecordType(JavaType(int) NOT NULL 
empid, JavaType(int) NOT NULL deptno, JavaType(class java.lang.String) name, 
JavaType(float) NOT NULL salary, JavaType(class java.lang.Integer) commission) 
NOT NULL ARRAY NOT NULL employees, JavaType(int) NOT NULL x, JavaType(int) NOT 
NULL y, JavaType(int) NOT NULL empid0, JavaType(class java.lang.String) name1) 
NOT NULL
equiv rowtype: RecordType(JavaType(class java.lang.Integer) empid, 
JavaType(class java.lang.Integer) deptno, JavaType(class java.lang.String) 
name, JavaType(class java.lang.Float) salary, JavaType(class java.lang.Integer) 
commission, JavaType(class java.lang.Integer) deptno0, JavaType(class 
java.lang.String) name0, RecordType(JavaType(int) NOT NULL empid, JavaType(int) 
NOT NULL deptno, JavaType(class java.lang.String) name, JavaType(float) NOT 
NULL salary, JavaType(class java.lang.Integer) commission) NOT NULL ARRAY 
employees, JavaType(class java.lang.Integer) x, JavaType(class 
java.lang.Integer) y, JavaType(int) NOT NULL empid0, JavaType(class 
java.lang.String) name1) NOT NULL
Difference:
empid: JavaType(int) NOT NULL -> JavaType(class java.lang.Integer)
deptno: JavaType(int) NOT NULL -> JavaType(class java.lang.Integer)
salary: JavaType(float) NOT NULL -> JavaType(class java.lang.Float)
deptno0: JavaType(int) NOT NULL -> JavaType(class java.lang.Integer)
employees: RecordType(JavaType(int) NOT NULL empid, JavaType(int) NOT NULL 
deptno, JavaType(class java.lang.String) name, JavaType(float) NOT NULL salary, 
JavaType(class java.lang.Integer) commission) NOT NULL ARRAY NOT NULL -> 
RecordType(JavaType(int) NOT NULL empid, JavaType(int) NOT NULL deptno, 
JavaType(class java.lang.String) name, JavaType(float) NOT NULL salary, 
JavaType(class java.lang.Integer) commission) NOT NULL ARRAY
x: JavaType(int) NOT NULL -> JavaType(class java.lang.Integer)
y: JavaType(int) NOT NULL -> JavaType(class java.lang.Integer)

               at 
org.apache.calcite.plan.volcano.VolcanoPlanner.register(VolcanoPlanner.java:592)
               at 
org.apache.calcite.plan.volcano.VolcanoPlanner.ensureRegistered(VolcanoPlanner.java:613)
               at 
org.apache.calcite.plan.volcano.VolcanoRuleCall.transformTo(VolcanoRuleCall.java:144)
               ... 81 more

Reply via email to