You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@calcite.apache.org by Mihai Budiu <mb...@vmware.com.INVALID> on 2022/09/17 00:53:56 UTC

Bug in the Bushy join optimization for outer joins with nullable columns

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

Re: Bug in the Bushy join optimization for outer joins with nullable columns

Posted by Julian Hyde <jh...@gmail.com>.
There are is ’netiquette’ around filing a bug that is often unsaid, so I’ll say it now:

1. When a committer asks you in an email to file a Jira case, you must file the case, and you must reply to the email with the URL of the case. (Rationale: People have expanded time and effort researching your case, and filing the case is necessary so that that knowledge is not lost. The committer asked you to file it so that you receive updates.)

2. Logging a case does not guarantee that it will be fixed. (A good summary and description will help, especially if you include steps to reproduce or a test case.)

3. Test cases are useful, but minimal test cases are even better. If you say that your test case is minimal, and includes a query with a COUNT(DISTINCT) and HAVING clause, the developer will know that removing the DISTINCT or the HAVING makes the problem go away. Those are valuable clues to the cause of the problem.

4. If you are working on a case, assign it to yourself, and set the status to ‘in progress’.

5. Do not set fixVersion of a case unless you are actively working on the case (or are the release manager).

6. Be aware that the project does not pay much attention to the case type (‘bug’ vs ‘feature’) or priority (‘major’, ‘minor’, ‘critical’).

7. The subject of the jira case is really important. It should be clear from the subject whether the case is a bug (something that is supposed to work, but doesn’t) or a feature request (something that the project doesn’t claim to do, but you would like it to do). The subject will become the commit message, and the commit message will become a line in the release notes, and the release notes are often the only documentation that we have. So, write the subject in terms that most end users will understand. Most end users speak SQL, so if your problem can be described in SQL terms, do that. Also, don’t describe your problem in terms of what you did to fix the code; that’s the solution, not the problem.

8. If you are using SQL keywords in the subject or description (which you should, see #7), write them in upper case.

9. When writing a description, you should generally start by repeating the subject. The subject may change over time, so we need a description that will continue to be valid. Also, it’s good to get straight to the point - tell us what you think is wrong - and then move on to the 

10. Check your spelling. If you write ’throws IlegalArgumentError’ rather than ’throws IllegalArgumentException’, someone with a similar problem to yours may not be able to find it.

Calcite’s Jira database is a knowledge base of past issues (keyed by symptoms, underlying cause, code fix, and possible workarounds), features being developed, design discussions, and possible future directions. It is immensely valuable to the community. By writing a good case, you are contributing to that community.

Julian





> On Sep 17, 2022, at 12:22 AM, Alessandro Solimando <al...@gmail.com> wrote:
> 
> Hi Mihai,
> from a quick look you indeed seem to have hit a bug, filing a Jira ticket
> would be great.
> 
> In principle all the information you need around filing a ticket are
> available here: https://calcite.apache.org/develop/#contributing
> 
> If there is something missing there, please let us know here and we might
> also consider improving the doc.
> 
> If you don't plan to tackle the issue, the repro instructions you gave seem
> enough to me, if you file a PR please add a new test covering exactly the
> error you are fixing (do not modify the existing one, unless you can make
> it cover both the original and the new case elegantly) so that we avoid
> regressions over time.
> 
> If you want to assign the ticket to yourself, you can request the
> "contributor" role for Jira in this list (I don't have permissions for
> granting that, it's generally Francis who takes care of that and he is very
> responsive).
> 
> Best regards,
> Alessandro
> 
> On Sat, 17 Sept 2022 at 02:54, Mihai Budiu <mb...@vmware.com.invalid>
> wrote:
> 
>> 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
>> 


Re: Bug in the Bushy join optimization for outer joins with nullable columns

Posted by Alessandro Solimando <al...@gmail.com>.
Hi Mihai,
from a quick look you indeed seem to have hit a bug, filing a Jira ticket
would be great.

In principle all the information you need around filing a ticket are
available here: https://calcite.apache.org/develop/#contributing

If there is something missing there, please let us know here and we might
also consider improving the doc.

If you don't plan to tackle the issue, the repro instructions you gave seem
enough to me, if you file a PR please add a new test covering exactly the
error you are fixing (do not modify the existing one, unless you can make
it cover both the original and the new case elegantly) so that we avoid
regressions over time.

If you want to assign the ticket to yourself, you can request the
"contributor" role for Jira in this list (I don't have permissions for
granting that, it's generally Francis who takes care of that and he is very
responsive).

Best regards,
Alessandro

On Sat, 17 Sept 2022 at 02:54, Mihai Budiu <mb...@vmware.com.invalid>
wrote:

> 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
>