Vladimir Sitnikov created CALCITE-7853:
------------------------------------------

             Summary: Lambda with no parameters throws NullPointerException 
when called through FunctionExpression.getFunction()
                 Key: CALCITE-7853
                 URL: https://issues.apache.org/jira/browse/CALCITE-7853
             Project: Calcite
          Issue Type: Bug
          Components: linq4j
    Affects Versions: 1.42.0
            Reporter: Vladimir Sitnikov


I build a linq4j lambda that takes no parameters, ask for its function with 
{{getFunction()}}, and call {{apply()}}. The call throws 
{{NullPointerException}} instead of returning the lambda's value. A lambda with 
parameters works through the same path (see {{ExpressionTest.testCompile}}).

h3. Reproduction

{code:java}
import org.apache.calcite.linq4j.function.Function0;
import org.apache.calcite.linq4j.tree.Expressions;

String x =
    Expressions.<Function0<String>>lambda(Expressions.constant("abc"))
        .getFunction()
        .apply();
{code}

h3. Expected

{{apply()}} returns {{"abc"}}, the value of the lambda body.

h3. Actual

{noformat}
java.lang.NullPointerException: Cannot read the array length because "args" is 
null
        at 
org.apache.calcite.linq4j.tree.FunctionExpression.lambda$compile$0(FunctionExpression.java:88)
        at 
org.apache.calcite.linq4j.tree.FunctionExpression.lambda$getFunction$0(FunctionExpression.java:107)
        at jdk.proxy3/jdk.proxy3.$Proxy13.apply(Unknown Source)
        at 
org.apache.calcite.linq4j.test.ExpressionTest.testLambdaWithoutParametersViaGetFunction(ExpressionTest.java:1191)
{noformat}

Reproduced on main at commit 8f27e24a02 with Amazon Corretto 21.0.9. The same 
{{getFunction()}} code is in calcite-1.42.0; I did not run the reproduction on 
that release.

h3. Analysis

The symptom and reproduction above stand without this section. 
{{getFunction()}} wraps the compiled lambda in a {{java.lang.reflect.Proxy}} 
whose handler calls {{Invokable.dynamicInvoke(args)}}. The 
[InvocationHandler.invoke|https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/reflect/InvocationHandler.html#invoke(java.lang.Object,java.lang.reflect.Method,java.lang.Object%5B%5D)]
 contract says {{args}} is {{null}} if the interface method takes no arguments, 
and the invokable built by {{compile()}} reads {{args.length}}. Passing an 
empty array when {{args}} is {{null}} fixes it.

Found while reviewing CALCITE-7736 ([PR 
#5213|https://github.com/apache/calcite/pull/5213]), which carries the same fix 
inside the nullness migration; this issue extracts it so it can land on its own.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to