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

Fix detection of XQuery errors thrown by XQueryServlet #284

Merged
merged 2 commits into from Dec 21, 2020

Conversation

joewiz
Copy link
Member

@joewiz joewiz commented Dec 20, 2020

A subtle change between eXist 5.2.0 and 5.3.0 meant that the fix in #261 caused eXide to raise an error for all queries for users of eXist 5.2.0 but not for those of 5.3.0.

This commit makes eXide’s error reporting introduced in #261 impervious to this difference between eXist 5.2.0 and 5.3.0 and adds some comments to aid in maintenance.

Background: #261 introduced additional detection of errors thrown by the XQueryServlet. Previously, errors that lacked descriptions slipped through unreported. The additional error detection worked in eXist 5.3.0-SNAPSHOT, but caused a serious regression in eXist 5.2.0. I found a difference in the results returned by the call to request:get-data() here; in eXist 5.2.0, this function returns an empty string when there is no XQueryServlet error, but in eXist 5.3.0-SNAPSHOT, the same call to request:get-data() returns an empty sequence.

To clarify my assertion that a subtle change between 5.2.0 and 5.3.0 played a role in this issue, I couldn't reproduce any difference in request:get-data() outside of eXide, so it doesn't appear that request:get-data() itself changed between 5.2.0 and 5.3.0. Rather, something about the particular context this function operates in did change—the context being the particular way that eXide sends queries to XQueryServlet for execution and processes the results. For example, exists(request:get-data()) returns true() in 5.2.0 and false() in 5.3.0—when run from eXide—but this query always returns false() when executed via a saved query (i.e., http://localhost:8080/exist/rest/db/test.xq). Why would we get true() in eXide under 5.2.0 but not 5.3.0? Do we know of any changes that could be responsible? I'm not complaining about 5.3.0; I think its behavior is correct here.

Thanks to @line-o for reporting the incompatibility between #261 and eXist 5.2.0.

Aside: To avoid the quirks of XQueryServlet's error handling, we should switch query execution to util:eval wrapped in a try-catch block. For an example of such an approach, see:

A subtle change between eXist 5.2.0 and 5.3.0 meant that the fix in eXist-db#261 caused every eXide query to raise an error for users of eXist 5.2.0 but not for those of 5.3.0. eXist-db#261 introduced a check of request:get-data() to detect errors thrown by the XQueryServlet that lacked descriptions and had silently failed in earlier versions of eXide. In eXist 5.2.0, the call to request:get-data() here returns an empty string when there is no XQueryServlet error. Under eXist 5.3.0-SNAPSHOT, the call to request:get-data here returns an empty sequence. This commit makes eXide’s error reporting introduced in eXist-db#261 impervious to this difference between eXist 5.2.0 and 5.3.0 and adds some comments to aid in maintenance.
@joewiz joewiz added the bug label Dec 20, 2020
@joewiz joewiz requested a review from a team December 20, 2020 05:38
if (string-length($xqueryservlet-error) gt 0) then
$xqueryservlet-error
(
if ($xqueryservlet-error instance of document-node()) then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would combine the to conditions into one

if (
    $xqueryservlet-error instance of document-node() and
    $xqueryservlet-error/error => normalize-space() => string-length()
)

I also left out the "gt 0" because any integer greater zero evals to true

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$is-error and ...

Copy link
Member Author

@joewiz joewiz Dec 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, but request:get-data() can return a string, in which case request:get-data()/error would throw an error.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the first condition of the two is false the second is not evaluated

Copy link
Member Author

@joewiz joewiz Dec 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That’s implementation-dependent behavior, which I avoid without a compelling reason. From https://www.w3.org/TR/xquery-31/#id-logical-expressions:

The order in which the operands of a logical expression are evaluated is implementation-dependent. The tables above are defined in such a way that an or-expression can return true if the first expression evaluated is true, and it can raise an error if evaluation of the first expression raises an error. Similarly, an and-expression can return false if the first expression evaluated is false, and it can raise an error if evaluation of the first expression raises an error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(If that is an eXist optimization, it’s not documented, is it? If not, it should perhaps be noted in https://exist-db.org/exist/apps/doc/xquery and/or https://exist-db.org/exist/apps/doc/tuning.)

if ($xqueryservlet-error instance of document-node()) then
if (string-length(normalize-space($xqueryservlet-error/error)) gt 0) then
$xqueryservlet-error
else
Copy link
Member

@line-o line-o Dec 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else if ($xqueryservlet-error instance of document-node()) then

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else if ($is-error)

description is null), so the <error> element is empty. To aid the user
in such situations, the script reports that an unidentified error was
raised. It also points the user to exist.log, where a hopefully a stack
trace shows the full error.
:)
session:create(),
let $xqueryservlet-error := request:get-data()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a new variable here

let $is-error := $xqueryservlet-error instance of document-node()

@@ -19,14 +19,14 @@
xquery version "3.0";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update to 3.1?

Copy link
Member

@line-o line-o left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see and understand your reasons for nested if-statements.
Especially given that it fixes an issue for users of the stable release, I would rather merge it now than to discuss this longer.
One question still is nagging me: Why is the the variable called $xqueryservlet-error ?
Can request:get-data() only contain an error? If not, I would like to avoid future confusion by giving it a neutral name like $data or $data-or-error or so.
What do you think, @joewiz ?

@joewiz
Copy link
Member Author

joewiz commented Dec 21, 2020

@line-o Ok, sounds good. Yes, for session.xql, which is only called by controller.xql to store and retrieve query results, a call to request:get-data() will only ever contain an error from the XQueryServlet, if present.

@line-o line-o merged commit d5ee66d into eXist-db:develop Dec 21, 2020
@joewiz joewiz deleted the fix/xqueryservlet-error-handling branch December 21, 2020 21:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants