eXist-db / exist

eXist Native XML Database and Application Platform
https://exist-db.org
GNU Lesser General Public License v2.1
429 stars 180 forks source link

NPE with higher order functions #2779

Open peterstadler opened 5 years ago

peterstadler commented 5 years ago

What is the problem

In trying to migrate an eXist app currently running on eXist 3.3 to current 4.7 I hit a strange NPE. The actual code is scattered across several modules and functions but I was able to squeeze it into a single reproducible test (yet, the code does not make much sense anymore ;)

The issue might be related to #2577 and/or #2385?

Describe how to reproduce or add a test

xquery version "3.1";

module namespace ct2="http://exist-db.org/xquery/closures/test2";
declare namespace test="http://exist-db.org/xquery/xqsuite";

(: first object :)
declare function ct2:obj1($item as item()*) as map(*) {
    map {
        'name' : 'obj1',
        'check' : function() as xs:boolean {
            matches($item, 'foo')
        },
        'test' : function() { ct2:do-something($item) }
    }
};

(: second object, referencing a function from object1 :)
declare function ct2:obj2($item as item()*) as map(*) {
    map {
        'name' : 'obj2',
        'check' : function() as xs:boolean {
            not(ct2:obj1($item)('check')())
        },
        'test' : function() { ct2:do-something($item) }
    }
};

(: some function calling ct2:name-by-id() :)
(: this is only introduced to catch the NPE and make it more readable :)
declare function ct2:do-something($id as xs:string) as xs:string+ {
    try { ct2:name-by-id($id) } catch * { $err:code cast as xs:string }
};

(: iterate over objects and return their name, if the test passes :)
declare function ct2:name-by-id($id as xs:string) as xs:string+ {
    for $func in $ct2:functions
    return 
        if($func($id)('check')()) then $func($id)('name')
        else ()
};

(: expose objects :)
declare variable $ct2:functions := 
    for $func in inspect:module-functions()
    return 
        if(function-name($func) => starts-with('ct2:obj')) then $func
        else ()
;

(: now following the tests … :)
declare 
    %test:assertEquals('obj1') 
    function ct2:test1() as xs:string {
        ct2:obj1('foo')('test')()
    };

declare 
    %test:assertEquals('obj1') 
    function ct2:test2() as xs:string {
        ct2:obj2('foo')('test')()
    };

declare 
    %test:assertEquals('obj1', 'obj1') 
    function ct2:test3() as xs:string+ {
        ct2:obj1('foo')('test')(),
        ct2:obj2('foo')('test')()
    };

Test output

<testsuites>
    <testsuite package="http://exist-db.org/xquery/closures/test2"
        timestamp="2019-06-02T14:29:02.281Z" tests="3" failures="1" errors="0" pending="0"
        time="PT0.011S">
        <testcase name="test1" class="ct2:test1">
            <failure message="assertEquals failed." type="failure-error-code-1">obj1</failure>
            <output>java:java.lang.NullPointerException</output>
        </testcase>
        <testcase name="test2" class="ct2:test2"/>
        <testcase name="test3" class="ct2:test3"/>
    </testsuite>
</testsuites>

NB: the single invocation of ct2:obj1('foo')('test')() fails (= testcase 1) but the combination with a successful call to ct2:obj2('foo')('test')() works (= testcase 3).

Context information

adamretter commented 5 years ago

@peterstadler Do you have the stracktrace for the NPE? It could be in exist.log?

peterstadler commented 5 years ago

Sorry, in exist.log there's only

2019-06-03 16:03:56,484 [qtp1276894402-47] ERROR (XQueryServlet.java [process]:552) - null 
java.lang.NullPointerException: null
adamretter commented 5 years ago

@peterstadler okay thanks (I removed your thread-dump as that doesn't help here).

peterstadler commented 5 years ago

This still has the "awaiting response" label. Is there anything more I could/should provide?

wolfgangmm commented 5 years ago

@peterstadler somehow I thought I addressed this issue, but maybe it was a different one. I'll retest.

peterstadler commented 5 years ago

Just checked myself with a recent eXist 4.7.1 and the error still occurs.

line-o commented 4 years ago

Can be reproduced. exist version 5 is affected.

peterstadler commented 4 years ago

ping, ping – any updates here? Needless to say that I'd really love to see this issue fixed for migrating my app to eXist5 …