Project

Profile

Help

Bug #6051

closed

Bug on exist() with non-existing attribute

Added by Christian Grün 10 months ago. Updated 7 months ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
XPath conformance
Sprint/Milestone:
-
Start date:
2023-05-25
Due date:
% Done:

100%

Estimated time:
Legacy ID:
Applies to branch:
11
Fix Committed on Branch:
11
Fixed in Maintenance Release:
Platforms:
.NET, Java

Description

Actions #1

Updated by Michael Kay 10 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.

Actions #2

Updated by Michael Kay 10 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 ().

Actions #3

Updated by Michael Kay 10 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.

Actions #4

Updated by Michael Kay 10 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.

Actions #5

Updated by Christian Grün 10 months ago

Coincidental bug fixes are not the worst ;)

Actions #6

Updated by Michael Kay 10 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.

Actions #7

Updated by John Lumley 10 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 wrote:


Actions #8

Updated by Christian Grün 10 months ago

…must have been a heisen(de)bugger!

Actions #9

Updated by Michael Kay 10 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

Actions #10

Updated by Michael Kay 10 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.

Actions #11

Updated by Shuxin Li 10 months 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!

Actions #12

Updated by Shuxin Li 10 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"?>
Actions #13

Updated by Shuxin Li 10 months ago

Perhaps there is another part of the source code where this bug still exists?

Actions #14

Updated by Martin Honnen 10 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.

Actions #15

Updated by Michael Kay 10 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.

Actions #16

Updated by Shuxin Li 10 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?

Actions #17

Updated by Shuxin Li 10 months ago

For in this test BaseX did return the node as expected, and I thought it should be the case.

Actions #18

Updated by Martin Honnen 10 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.

Actions #19

Updated by Shuxin Li 10 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.

Actions #20

Updated by Shuxin Li 10 months 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.

Actions #21

Updated by Michael Kay 10 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.

Actions #22

Updated by Shuxin Li 10 months ago

Thank you for the detailed explanation! I get that :)

Actions #23

Updated by Debbie Lockett 7 months 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

Also available in: Atom PDF