exist icon indicating copy to clipboard operation
exist copied to clipboard

[BUG] Named function references - arguments ignored

Open joewiz opened this issue 4 years ago • 3 comments

Describe the bug

eXist ignores arguments passed to named function references and returns the function's identity instead of the results of the function applied to the arguments. For example:

fn:string-length#1("foo")

... returns fn:string-length#1 instead of 3.

BaseX and Saxon return the expected result, 3.

Expected behavior

eXist should apply arguments to named function references instead of ignoring them and returning the named function's identity.

I think the relevant code is in https://github.com/eXist-db/exist/blob/develop/exist-core/src/main/java/org/exist/xquery/NamedFunctionReference.java.

To reproduce

Besides the xqsuite below, XQTS tests named function references extensively: https://github.com/w3c/qt3tests/blob/master/prod/NamedFunctionRef.xml (as spotted by @dizzzz). I suspect that if the tests below would pass, we'd pass this segment of XQTS too.

xquery version "3.1";

module namespace t="http://exist-db.org/xquery/test";

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

declare
    %test:assertEquals(3)
function t:named-function-reference-direct() {
    string-length#1("foo")
};

declare
    %test:assertEquals(3)
function t:named-function-reference-variable() {
    let $fn-string-length := string-length#1
    return
        $fn-string-length("foo")
};

declare
    %test:assertEquals(3)
function t:named-function-reference-wrapped() {
    (string-length#1)("foo")
};

declare
    %test:assertEquals(3)
function t:named-function-reference-apply() {
    apply(string-length#1, ["foo"])
};

This test returns:

<testsuite package="http://exist-db.org/xquery/test" timestamp="2021-01-06T10:28:01.974-05:00"
    tests="4" failures="0" errors="1" pending="0" time="PT0.002S">
    <testcase name="named-function-reference-direct" class="t:named-function-reference-direct">
        <error type="err:FOTY0013"
            message="The argument to fn:data() contains a function item. A function item other than an array cannot be atomized"
        />
    </testcase>
    <testcase name="named-function-reference-variable" class="t:named-function-reference-variable"/>
    <testcase name="named-function-reference-wrapped" class="t:named-function-reference-wrapped"/>
    <testcase name="named-function-reference-apply" class="t:named-function-reference-apply"/>
</testsuite>

Not included in the xqsuite is this expression:

deep-equal(string-length#1("foo"), "3")

... which raises an unexpected and very puzzling error:

Cannot compile xquery: err:XPST0017 Unexpectedly received 1 parameter(s) in call to function 'deep-equal()'... [at line 1, column 1]

This error suggests that somehow eXist evaluates string-length#1("foo") to be an empty sequence?!

When this test is added to the test suite as follows, the test suite won't even run:

declare
    %test:assertTrue
function t:named-function-reference-deep-equal() {
    deep-equal(string-length#1("foo"), "3")
};

The error:

err:XPST0017 Error while loading module /db/test.xq: Unexpectedly received 1 parameter(s) in call to function 'deep-equal()'. Defined function signatures are: deep-equal($items-1 as item(), $items-2 as item()) xs:boolean deep-equal($items-1 as item(), $items-2 as item(), $collation-uri as xs:string) xs:boolean [at line 36, column 5] In function: test:suite(function(*)+) [5:1:jar:file:/Users/joe/workspace/exist/exist-distribution/target/exist-distribution-5.3.0-SNAPSHOT.app/Contents/Java/exist-core-5.3.0-SNAPSHOT.jar!/org/exist/xquery/lib/xqsuite/xqsuite.xql]

Also not included in the xqsuite is this expression:

"foo" => string-length#1()

... which raises what looks to be a parser error:

Cannot compile xquery: exerr:ERROR org.exist.xquery.XPathException: err:XPST0003 expecting opening parenthesis '(', found '#' [at line 1, column 23]

When this test is added to the test suite as follows, the test suite won't even run:

declare
    %test:assertTrue
function t:named-function-reference-arrow() {
    "foo" => string-length#1()
};

The error:

err:XPST0003 Error while loading module /db/test.xq: Syntax error within user defined function t:named-function-reference-arrow: expecting opening parenthesis '(', found '#' [at line 36, column 27] In function: test:suite(function(*)+) [5:1:jar:file:/Users/joe/workspace/exist/exist-distribution/target/exist-distribution-5.3.0-SNAPSHOT.app/Contents/Java/exist-core-5.3.0-SNAPSHOT.jar!/org/exist/xquery/lib/xqsuite/xqsuite.xql]

Context (please always complete the following information):

  • OS: macOS 11.1
  • eXist-db version: eXist 5.3.0-SNAPSHOT 35a76f25f0431220de95ff43752232bbf6a59efc 20210104165718
  • Java Version: 1.8.0_275

Additional context

  • How is eXist-db installed? built from source
  • Any custom changes in e.g. conf.xml? none

joewiz avatar Jan 06 '21 15:01 joewiz

I saw similar issues in the XQTS suite. If I remember it was like pi#0()

dizzzz avatar Jan 06 '21 19:01 dizzzz

@dizzzz Indeed, your note in https://github.com/eXist-db/exist/pull/3691#event-4174729995 was what made me start looking into this. I chose string-length rather than pi for this report since it's a bit more straightforward.

By the way, I've added a couple of tests to the report - t:named-function-reference-variable and t:named-function-reference-arrow.

joewiz avatar Jan 07 '21 14:01 joewiz

Yeah, more -special- ways to call functions :) This is definitely a parser issue from what I have learned making changes to it. Our grammar simply does not include the case function reference called immediately.

line-o avatar Feb 26 '21 12:02 line-o