Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] exist:output-size-limit is not observed when using load-xquery-module #5569

Open
nverwer opened this issue Nov 27, 2024 · 3 comments
Open
Labels
investigate issues being looked at

Comments

@nverwer
Copy link

nverwer commented Nov 27, 2024

When a function is loaded using load-xquery-module, any declared exist:output-size-limit is not used.
The only way to set exist:output-size-limit is in the function itself.
This differs from function in modules that are loaded using import.

Expected behavior
A function should always use exist:output-size-limit, regardless of how it is loaded.

To Reproduce
Make the following two files in the same eXist collection.

test-output-size-limit.xql

import module namespace osl="http://output-size.limit/" at "test-output-size-limit.xqm";

declare option exist:output-size-limit "10";

declare variable $osl-uri := "http://output-size.limit/";

let $dynload1 := load-xquery-module($osl-uri, map{"location-hints": "test-output-size-limit.xqm"})
let $dynload1-too-many-nodes as item() := $dynload1?functions?(QName($osl-uri, "osl:too-many-nodes"))?0
let $dynload1-not-many-nodes as item() := $dynload1?functions?(QName($osl-uri, "osl:not-many-nodes"))?1
let $dynload2 := load-xquery-module($osl-uri, map{"location-hints": "test-output-size-limit.xqm", "vendor-options": map{"exist:output-size-limit":"9"}})
let $dynload2-too-many-nodes as item() := $dynload2?functions?(QName($osl-uri, "osl:too-many-nodes"))?0
return
  ( try {
      osl:too-many-nodes()
    } catch * { $err:description }
  , try {
      osl:not-many-nodes(100)
    } catch * { $err:description }
  , try {
      $dynload1-too-many-nodes()
    } catch * { $err:description }
  , try {
      $dynload1-not-many-nodes(8)
    } catch * { $err:description }
  , try {
      $dynload2-too-many-nodes()
    } catch * { $err:description }
  )

test-output-size-limit.xqm

module namespace osl="http://output-size.limit/";

declare option exist:output-size-limit "5";

declare function osl:too-many-nodes() as node()
{
  <a id="too-many" output-size-limit="{util:get-option('exist:output-size-limit')}">
    <b><c/><d/><e><f/></e><g/></b>
    <b><c/><d/><e><f/></e><g/></b>
    <b><c/><d/><e><f/></e><g/></b>
  </a>
};


declare function osl:not-many-nodes($limit) as node()
{
  let $increased-output-size-limit := util:declare-option('exist:output-size-limit', $limit)
  return
  <a id="not-many" output-size-limit="{util:get-option('exist:output-size-limit')}">
    <b><c/><d/><e><f/></e><g/></b>
    <b><c/><d/><e><f/></e><g/></b>
    <b><c/><d/><e><f/></e><g/></b>
  </a>
};

Then execute test-output-size-limit.xql. The output is something like:

exerr:ERROR The constructed document fragment exceeded the predefined output-size-limit (current: 11; allowed: 10). The query has been killed. [at line 9, column 17]
In function:
	osl:too-many-nodes() [14:7:/db/apps/_test/test-output-size-limit.xqm]. The constructed document fragment exceeded the predefined output-size-limit (current: 11; allowed: 10). The query has been killed.
<a id="not-many" output-size-limit="5"><b><c/><d/><e><f/></e><g/></b><b><c/><d/><e><f/></e><g/></b><b><c/><d/><e><f/></e><g/></b></a>
<a id="too-many" output-size-limit="5"><b><c/><d/><e><f/></e><g/></b><b><c/><d/><e><f/></e><g/></b><b><c/><d/><e><f/></e><g/></b></a>
exerr:ERROR The constructed document fragment exceeded the predefined output-size-limit (current: 9; allowed: 8). The query has been killed. [at line 21, column 9]
In function:
	osl:not-many-nodes(item()*) [7:18:/db/apps/_test/test-output-size-limit.xqm]. The constructed document fragment exceeded the predefined output-size-limit (current: 9; allowed: 8). The query has been killed.
<a id="too-many" output-size-limit="5"><b><c/><d/><e><f/></e><g/></b><b><c/><d/><e><f/></e><g/></b><b><c/><d/><e><f/></e><g/></b></a>

The first result is expected, as there are too many nodes. The second result is expected, because exist:output-size-limit has been set to 100.
The third result is wrong, because all possibly relevant exist:output-size-limit declarations would make the output too large.
The fourth result is expected, because the exist:output-size-limit has been changed inside the function.
The fifth result is maybe wrong. I attempted to use the vendor-options to set exist:output-size-limit, just to see if that would work.

The output-size-limit attributes give the value of util:get-option('exist:output-size-limit'), but they are clearly not the output size limit that is used.

Context
eXist Version: 6.4.0-SNAPSHOT
eXist Build: 2024-10-29T10:04:56Z
Operating System: Windows 10 10.0 amd64
Java Version: 11.0.14.1

eXist is started via launcher.bat.

@line-o line-o added the investigate issues being looked at label Nov 27, 2024
@line-o
Copy link
Member

line-o commented Nov 27, 2024

@nverwer thanks for your exhaustive bug report. Have you, by any chance, checked if basex does observe this option regardless of module loading mechanism?

@joewiz
Copy link
Member

joewiz commented Nov 27, 2024

@line-o BaseX hasn't implemented fn:load-xquery-module yet. https://docs.basex.org/main/XQuery_3.1#functions: Also, BaseX uses pragmas rather than option declarations for setting certain options. Most options, though, are not accessible by the query but are set at the BaseX instance level: https://docs.basex.org/main/Options.

@nverwer
Copy link
Author

nverwer commented Nov 27, 2024

Thank you @joewiz for clarifying why this cannot be tested in BaseX. I never needed load-xquery-module in my BaseX projects, and I was unaware that it is not implemented in BaseX.

Of course, util:declare-option is also unavailable in BaseX, It is possible to do declare option output:limit "100";, which limits the number of serialized bytes, but not in library modules.

I have not been able to find a specification of how options should behave w.r.t. dynamically loaded modules, but I would think that it should not be different from imported modules.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
investigate issues being looked at
Projects
None yet
Development

No branches or pull requests

3 participants