[ 
https://issues.apache.org/jira/browse/CALCITE-4054?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17128998#comment-17128998
 ] 

Ruben Q L commented on CALCITE-4054:
------------------------------------

The exception is thrown by the code generated by 
{{EnumerableTableSpool#implement}}:
{code:java}
  @Override public Result implement(EnumerableRelImplementor implementor, 
Prefer pref) {
    ...

    //  ModifiableTable t = (ModifiableTable) 
root.getRootSchema().getTable(tableName);
    //  return lazyCollectionSpool(t.getModifiableCollection(), <inputExp>);
    BlockBuilder builder = new BlockBuilder();
    ...
{code}
The call {{root.getRootSchema().getTable(tableName)}} does not find the table 
and returns {{null}}, hence the subsequent call to 
{{getModifiableCollection()}} throws the NPE.
Normally, the transient table gets added to the root schema when its enumerable 
is create, via {{ListTransientTable#scan}}:
{code:java}
  @Override public Enumerable<Object[]> scan(DataContext root) {
    // add the table into the schema, so that it is accessible by any potential 
operator
    root.getRootSchema().add(name, this);
    ...
{code}

Therefore, we should expect the table to be correctly added to the root schema 
when we build the query result's enumerable. This is the usually the case, 
since its operator in Enumerable convention builds and returns its enumerable. 
But, there is an exception with EnumerableCorrelate. The right-hand-side of 
EnumerableCorrelate does not build an Enumerable, instead it builds a 
*function* that, given a certain correlated value, returns the corresponding 
enumerable for the RHS evaluation with that value (see the implementation of 
EnumerableDefaults#correlateJoin). Therefore, in that situation where the 
ListTransientScan is on the RHS of the EnumerableCorrelate, its scan method has 
not been yet executed, hence the table has not been added to the schema, and we 
reach the NPE when EnumerableTableSpool build its dynamic code.

> RepeatUnion containing a Correlate with a transientScan on its RHS causes NPE
> -----------------------------------------------------------------------------
>
>                 Key: CALCITE-4054
>                 URL: https://issues.apache.org/jira/browse/CALCITE-4054
>             Project: Calcite
>          Issue Type: Bug
>          Components: core
>    Affects Versions: 1.23.0
>            Reporter: Ruben Q L
>            Priority: Major
>
> In order to reach this issue, several factors must occur:
> - We need a "recursive plan", i.e. a RepeatUnion with a TransientScan (see 
> examples in EnumerableRepeatUnionTest.java).
> - Inside the repeat union, there must be a Correlate, or a Join that gets 
> implemented as a Correlate due to JoinToCorrelateRule.
> - We have the TransientScan (i.e. the scan on the transient table) on the 
> right-hand-side of the correlate/join. Normally, transientScan always appear 
> on the LHS of a correlate/join (because they need the top of the RelBuilder's 
> stack to get its rowType); however, it can get on the RHS due to 
> JoinCommuteRule.
> We can force these conditions and reproduce the issue with the following unit 
> test (in EnumerableRepeatUnionTest.java):
> {code:java}
>   @Test void testRepeatUnionWithCorrelateWithTransientScanOnItsRight() {
>     CalciteAssert.that()
>         .with(CalciteConnectionProperty.LEX, Lex.JAVA)
>         .with(CalciteConnectionProperty.FORCE_DECORRELATE, false)
>         .withSchema("s", new ReflectiveSchema(new HierarchySchema()))
>         .query("?")
>         .withHook(Hook.PLANNER, (Consumer<RelOptPlanner>) planner -> {
>           planner.addRule(JoinToCorrelateRule.INSTANCE);
>           planner.removeRule(JoinCommuteRule.INSTANCE);
>           planner.removeRule(EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE);
>           planner.removeRule(EnumerableRules.ENUMERABLE_JOIN_RULE);
>         })
>         .withRel(builder -> {
>           builder
>               //   WITH RECURSIVE delta(empid, name) as (
>               //     SELECT empid, name FROM emps WHERE empid = 2
>               //     UNION ALL
>               //     SELECT e.empid, e.name FROM delta d
>               //                            JOIN hierarchies h ON d.empid = 
> h.managerid
>               //                            JOIN emps e        ON 
> h.subordinateid = e.empid
>               //   )
>               //   SELECT empid, name FROM delta
>               .scan("s", "emps")
>               .filter(
>                   builder.equals(
>                       builder.field("empid"),
>                       builder.literal(2)))
>               .project(
>                   builder.field("emps", "empid"),
>                   builder.field("emps", "name"))
>               .transientScan("#DELTA#");
>           RelNode transientScan = builder.build(); // pop the transientScan 
> to use it later
>           builder
>               .scan("s", "hierarchies")
>               .push(transientScan) // use the transientScan as right input of 
> the join
>               .join(
>                   JoinRelType.INNER,
>                   builder.equals(
>                       builder.field(2, "#DELTA#", "empid"),
>                       builder.field(2, "hierarchies", "managerid")))
>               .scan("s", "emps")
>               .join(
>                   JoinRelType.INNER,
>                   builder.equals(
>                       builder.field(2, "hierarchies", "subordinateid"),
>                       builder.field(2, "emps", "empid")))
>               .project(
>                   builder.field("emps", "empid"),
>                   builder.field("emps", "name"))
>               .repeatUnion("#DELTA#", true);
>           return builder.build();
>         })
>         .explainHookMatches(""
>             + "EnumerableRepeatUnion(all=[true])\n"
>             + "  EnumerableTableSpool(readType=[LAZY], writeType=[LAZY], 
> table=[[#DELTA#]])\n"
>             + "    EnumerableCalc(expr#0..4=[{inputs}], expr#5=[2], 
> expr#6=[=($t0, $t5)], empid=[$t0], name=[$t2], $condition=[$t6])\n"
>             + "      EnumerableTableScan(table=[[s, emps]])\n"
>             + "  EnumerableTableSpool(readType=[LAZY], writeType=[LAZY], 
> table=[[#DELTA#]])\n"
>             + "    EnumerableCalc(expr#0..8=[{inputs}], empid=[$t4], 
> name=[$t6])\n"
>             + "      EnumerableCorrelate(correlation=[$cor1], 
> joinType=[inner], requiredColumns=[{1}])\n"
>             // It is important to have EnumerableCorrelate + #DELTA# table 
> scan on its right
>             + "        EnumerableCorrelate(correlation=[$cor0], 
> joinType=[inner], requiredColumns=[{0}])\n"
>             + "          EnumerableTableScan(table=[[s, hierarchies]])\n"
>             + "          EnumerableCalc(expr#0..1=[{inputs}], expr#2=[$cor0], 
> expr#3=[$t2.managerid], expr#4=[=($t0, $t3)], proj#0..1=[{exprs}], 
> $condition=[$t4])\n"
>             + "            EnumerableInterpreter\n"
>             + "              BindableTableScan(table=[[#DELTA#]])\n"
>             + "        EnumerableCalc(expr#0..4=[{inputs}], expr#5=[$cor1], 
> expr#6=[$t5.subordinateid], expr#7=[=($t6, $t0)], proj#0..4=[{exprs}], 
> $condition=[$t7])\n"
>             + "          EnumerableTableScan(table=[[s, emps]])\n")
>         .returnsUnordered(""
>             + "empid=2; name=Emp2\n"
>             + "empid=3; name=Emp3\n"
>             + "empid=5; name=Emp5");
>   }
> {code}
> Which fails with NPE on the dynamic generated code:
> {code}
> Error while executing SQL "?": null
> java.sql.SQLException: Error while executing SQL "?": null
>       at org.apache.calcite.avatica.Helper.createException(Helper.java:56)
>       at org.apache.calcite.avatica.Helper.createException(Helper.java:41)
>       at 
> org.apache.calcite.avatica.AvaticaStatement.executeInternal(AvaticaStatement.java:163)
>       at 
> org.apache.calcite.avatica.AvaticaStatement.executeQuery(AvaticaStatement.java:227)
>       at 
> org.apache.calcite.test.CalciteAssert.assertQuery(CalciteAssert.java:532)
>       at 
> org.apache.calcite.test.CalciteAssert$AssertQuery.lambda$returns$1(CalciteAssert.java:1511)
>       at 
> org.apache.calcite.test.CalciteAssert$AssertQuery.withConnection(CalciteAssert.java:1450)
>       at 
> org.apache.calcite.test.CalciteAssert$AssertQuery.returns(CalciteAssert.java:1509)
>       at 
> org.apache.calcite.test.CalciteAssert$AssertQuery.returns(CalciteAssert.java:1499)
>       at 
> org.apache.calcite.test.CalciteAssert$AssertQuery.returnsUnordered(CalciteAssert.java:1521)
>       at 
> org.apache.calcite.test.enumerable.EnumerableRepeatUnionTest.testRepeatUnionWithCorrelateWithTransientScanOnItsRight(EnumerableRepeatUnionTest.java:296)
>       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:675)
>       at 
> org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
>       at 
> org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:125)
>       at 
> org.junit.jupiter.engine.extension.TimeoutInvocation.proceed(TimeoutInvocation.java:46)
>       at 
> org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:139)
>       at 
> org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:131)
>       at 
> org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:81)
>       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:104)
>       at 
> org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:62)
>       at 
> org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:43)
>       at 
> org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:35)
>       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$6(TestMethodTestDescriptor.java:202)
>       at 
> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
>       at 
> org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:198)
>       at 
> org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
>       at 
> org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
>       at 
> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
>       at 
> org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
>       at 
> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
>       at 
> org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:171)
>       at 
> org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.invokeAll(ForkJoinPoolHierarchicalTestExecutorService.java:115)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
>       at 
> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
>       at 
> org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
>       at 
> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
>       at 
> org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:171)
>       at 
> org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.invokeAll(ForkJoinPoolHierarchicalTestExecutorService.java:115)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
>       at 
> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
>       at 
> org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
>       at 
> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
>       at 
> org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
>       at 
> org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:171)
>       at java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:189)
>       at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
>       at 
> java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
>       at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
>       at 
> java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
> Caused by: java.lang.NullPointerException
>       at Baz.bind(Unknown Source)
>       at 
> org.apache.calcite.jdbc.CalcitePrepare$CalciteSignature.enumerable(CalcitePrepare.java:355)
>       at 
> org.apache.calcite.jdbc.CalciteConnectionImpl.enumerable(CalciteConnectionImpl.java:315)
>       at 
> org.apache.calcite.jdbc.CalciteMetaImpl._createIterable(CalciteMetaImpl.java:507)
>       at 
> org.apache.calcite.jdbc.CalciteMetaImpl.createIterable(CalciteMetaImpl.java:498)
>       at 
> org.apache.calcite.avatica.AvaticaResultSet.execute(AvaticaResultSet.java:182)
>       at 
> org.apache.calcite.jdbc.CalciteResultSet.execute(CalciteResultSet.java:64)
>       at 
> org.apache.calcite.jdbc.CalciteResultSet.execute(CalciteResultSet.java:43)
>       at 
> org.apache.calcite.avatica.AvaticaConnection$1.execute(AvaticaConnection.java:667)
>       at 
> org.apache.calcite.jdbc.CalciteMetaImpl.prepareAndExecute(CalciteMetaImpl.java:567)
>       at 
> org.apache.calcite.avatica.AvaticaConnection.prepareAndExecuteInternal(AvaticaConnection.java:675)
>       at 
> org.apache.calcite.avatica.AvaticaStatement.executeInternal(AvaticaStatement.java:156)
>       ... 66 more
> {code}



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to