Bug #6051
closed

Bug on exist() with non-existing attribute
100%
Updated by Michael Kay 4 months 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 4 months 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 4 months 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 4 months 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 4 months ago
Coincidental bug fixes are not the worst ;)
Updated by Michael Kay 4 months 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 4 months 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 4 months 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 4 months 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 4 months 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 Martin Honnen 4 months 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 4 months 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 4 months 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 Martin Honnen 4 months 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 4 months 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 Michael Kay 4 months 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 Debbie Lockett about 1 month 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