Bug #6051
closedBug on exist() with non-existing attribute
Added by Christian Grün over 1 year ago. Updated about 1 year ago.
100%
Updated by Michael Kay over 1 year ago
- Status changed from New to Rejected
- Assignee set to Michael Kay
Thanks.
But Saxon appears to give the correct result.
Test case fn-exists-101 added to qt4tests.
Updated by Michael Kay over 1 year ago
- Status changed from Rejected to In Progress
Reopening. The test is working from the command line but not in the test driver.
The test is working in 12.x but not in 11.x. In 11.x, the predicate is being rewritten to [exists(data(@n1) ge -1)]
which is incorrect; the ge
operator returns ()
when one of the operands is ()
.
Updated by Michael Kay over 1 year ago
In 11.x, GeneralComparison.typeCheck() line 305 rewrites the comparison to a value comparison like this:
Expression vun = makeCompareUntypedToNumeric(getLhsExpression(), getRhsExpression(), singletonOperator);
return vun.typeCheck(visitor, contextInfo);
In 12.x this has been changed to:
setAtomicComparer(new UntypedNumericComparer());
return this;
Git Blame dates this as 19/08/22 and attributes it to bytecode changes, I suspect a bug fix mixed into the same commit as something else.
Updated by Michael Kay over 1 year ago
I've done a fair bit of digging in the history and I can't find any record of what motivated this code change on 2022-08-19. So I'm going to have to deal with it from first principles.
Updated by Christian Grün over 1 year ago
Coincidental bug fixes are not the worst ;)
Updated by Michael Kay over 1 year ago
- Category set to XPath conformance
- Status changed from In Progress to Resolved
- Priority changed from Low to Normal
- Applies to branch 11 added
- Fix Committed on Branch 11 added
- Platforms .NET, Java added
I've retrofitted the code change from 12.x to 11.x and it seems to regression test OK.
Updated by John Lumley over 1 year ago
The worst I’ve had was where a bug went away when run under the debugger, due to a bug in the debugger!
Sent from my iPad
On 25 May 2023, at 18:04, Saxonica Developer Community notifications@plan.io wrote:
Updated by Michael Kay over 1 year ago
- Status changed from Resolved to In Progress
Reopened because there are reports that this fails on 12.2 see https://github.com/BaseXdb/basex/issues/2212
Updated by Michael Kay over 1 year ago
- Status changed from In Progress to Resolved
- Applies to branch 9.7 added
- Applies to branch deleted (
11)
Closing this again. I have checked carefully, and I'm convinced Saxon 12.2 returns the correct result.
Updated by Shuxin Li over 1 year ago
Thanks for the update! I checked again and I think it might be the influence of other Jar files which I included in the project which is pretty strange. When I remove the jar file of eXist-core the problem indeed disappeared. Thanks again!
Updated by Shuxin Li over 1 year ago
Hi, today I found another case which seems to be very similar to this issue about non-existing attributes (I verified through the command line that this is reproducible for Saxon-HE 12.2) XML:
<Q1/>
XPath:
//Q1[(@p1 ! (. > 1)) = false()]
Saxon returned empty result set. Should return Q1.
This is the what I executed from the cmd:
java -cp saxon-he-12.2.jar net.sf.saxon.Query -t -s:test.xml -q:xq.xq -o:out.txt
In out:
<?xml version="1.0" encoding="UTF-8"?>
Updated by Shuxin Li over 1 year ago
Perhaps there is another part of the source code where this bug still exists?
Updated by Martin Honnen over 1 year ago
Shuxin Li wrote in #note-12:
Hi, today I found another case which seems to be very similar to this issue about non-existing attributes (I verified through the command line that this is reproducible for Saxon-HE 12.2) XML:
<Q1/>
XPath:
//Q1[(@p1 ! (. > 1)) = false()]
Saxon returned empty result set. Should return Q1.
Can you explain why?
The predicate in my view evaluates to false (as () = false()
is false()
) so //Q1[false()]
correctly doesn't select anything.
Updated by Michael Kay over 1 year ago
I agree with Martin's analysis.
Note however that if XPath 1.0 compatibility mode is enabled, comparing an empty sequence to false()
returns true, whereas without 1.0 compatibility mode, it returns false. Of course an XPath 1.0 processor doesn't understand the "!" operator, but a 2.0 processor running in 1.0 mode will give a different result.
Updated by Shuxin Li over 1 year ago
Hi Martin, I'm not very sure about the semantics because I didn't actually find where it is documented.
I derived this from the discussion here: https://github.com/BaseXdb/basex/issues/2212
It was mentioned that () >= -1 returns false(), therefore I thought that in this case (. > 1) is (() > 1) should return false(), and false() = false() should return true(). So the node should be selected. I don't know if this is correct?
Updated by Shuxin Li over 1 year ago
For in this test BaseX did return the node as expected, and I thought it should be the case.
Updated by Martin Honnen over 1 year ago
Shuxin Li wrote in #note-16:
Hi Martin, I'm not very sure about the semantics because I didn't actually find where it is documented.
I derived this from the discussion here: https://github.com/BaseXdb/basex/issues/2212
It was mentioned that () >= -1 returns false(), therefore I thought that in this case (. > 1) is (() > 1) should return false(), and false() = false() should return true(). So the node should be selected. I don't know if this is correct?
As @p1
gives the empty sequence the result of @p1 ! (. > 1)
is the empty sequence.
Updated by Shuxin Li over 1 year ago
Hi Martin, I could understand that if take map as a streaming process, empty sequence will result in an empty sequence. So is it correct that it's the map that changed the situation? Still it seems a bit confusing though, for in previous case () >= 1 returns false() and here () > 1 returns the empty sequence.
Updated by Shuxin Li over 1 year ago
I get the idea that with map Saxon takes the input as a sequence, and if no item is in the sequence it will result in an empty sequence instead of giving the empty sequence as an input to the following functions. That makes a lot of sense! Thank you very much.
Updated by Michael Kay over 1 year ago
An expression using the "=" operator is called a General Comparison, and the rules are found at
https://www.w3.org/TR/xpath-31/#id-general-comparisons
To summarise, if you compare S = T
when S and T are sequences, the comparison is true if there is an item $s
in S
and an item $t
in T such that $s equals $t. That means if either S or T is an empty sequence, the result is necessarily false: () = X
is false regardless what X
is.
So given the expression
`(@p1 ! (. > 1)) = false()`
@p1 is an empty sequence
Therefore @p1 ! X
is an empty sequence (regardless what X is)
So you are comparing an empty sequence with false()
, which is always false.
Updated by Shuxin Li over 1 year ago
Thank you for the detailed explanation! I get that :)
Updated by Debbie Lockett about 1 year ago
- Status changed from Resolved to Closed
- % Done changed from 0 to 100
- Applies to branch 11 added
- Applies to branch deleted (
9.7) - Fixed in Maintenance Release 11.6 added
Bug fix applied in the Saxon 11.6 maintenance release.
Please register to edit this issue