Project

Profile

Help

Bug #4399

closed

functx:non-distinct-values says cannot compare xs:integer to xs:integer, in 9.8 EE only

Added by Priscilla Walmsley over 4 years ago. Updated over 4 years ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
XSLT conformance
Sprint/Milestone:
-
Start date:
2019-11-27
Due date:
% Done:

0%

Estimated time:
Legacy ID:
Applies to branch:
9.8, 9.9, trunk
Fix Committed on Branch:
9.9, trunk
Fixed in Maintenance Release:
Platforms:

Description

When the attached XSLT runs in EE, it results in the error:

Engine name: Saxon-EE 9.8.0.12 Description: Cannot compare xs:integer to xs:integer

but it works in HE and PE 9.8.0.12


Files

saxonissues3.xsl (628 Bytes) saxonissues3.xsl Priscilla Walmsley, 2019-11-27 18:32
dummyin.xml (66 Bytes) dummyin.xml Priscilla Walmsley, 2019-11-27 18:32
Actions #1

Updated by Michael Kay over 4 years ago

  • Category set to XSLT conformance
  • Status changed from New to In Progress
  • Assignee set to Michael Kay
  • Priority changed from Low to Normal

Problem reproduced.

I'm afraid the comical error message is a bit of an old chestnut. When we're comparing A and B, and get a ClassCastException, we report "cannot compare A to B, because that's how we detect the error in the normal course of events. Of course if the ClassCastException is caused by some internal bug then the message is nonsense.

Actions #2

Updated by Michael Kay over 4 years ago

Stack trace of the exception is:

java.lang.ClassCastException: net.sf.saxon.value.Int64Value cannot be cast to net.sf.saxon.value.UntypedAtomicValue
	at net.sf.saxon.expr.sort.UntypedNumericComparer.compareAtomicValues(UntypedNumericComparer.java:183)
	at net.sf.saxon.expr.sort.UntypedNumericComparer.comparesEqual(UntypedNumericComparer.java:223)
	at net.sf.saxon.expr.ValueComparison.compare(ValueComparison.java:742)
	at net.sf.saxon.expr.ValueComparison.effectiveBooleanValue(ValueComparison.java:703)

The UntypedNumericComparer is supposed to handle comparisons of xs:untypedAtomic to numerics (it tries to do this "smartly", returning false for cases like "123" = 5 without actually doing a string-to-integer conversion).

The question here is, why has an UntypedNumericConverter been allocated? Something must have gone wrong with the type inferencing.

Actions #3

Updated by Michael Kay over 4 years ago

As often happens with artificial test cases involving literals as input, the optimizer has gone to town on this one:

OPT : At line 12 of file:/Users/mike/bugs/2019/4399-walmsley/test.xsl
OPT : Replaced general comparison by value comparison
OPT : Expression after rewrite: (count($Q{}seq[. = $val])) gt 1
OPT : At line 4 of file:/Users/mike/bugs/2019/4399-walmsley/test.xsl
OPT : Moved function functx:non-distinct-values inline: 
OPT : Expression after rewrite: let $seq := (1, 2, 3, 3) return (for $val in distinct-values($seq) return ($val[(count($seq[. = $val])) gt 1]))
OPT : At line 12 of file:/Users/mike/bugs/2019/4399-walmsley/test.xsl
OPT : Pre-evaluated function call fn:distinct-values(...)
OPT : Expression after rewrite: (1, 2, 3)
OPT : At line 12 of file:/Users/mike/bugs/2019/4399-walmsley/test.xsl
OPT : Replaced general comparison by value comparison
OPT : Expression after rewrite: . eq $val
OPT : At line 4 of file:/Users/mike/bugs/2019/4399-walmsley/test.xsl
OPT : Inlined constant variable seq
OPT : Expression after rewrite: (1, 2, 3, 3)
OPT : At line 12 of file:/Users/mike/bugs/2019/4399-walmsley/test.xsl
OPT : Rewrite count()>=N as:
OPT : Expression after rewrite: exists(tail((1, 2, 3, 3)[. eq $val]))
OPT : At line 12 of file:/Users/mike/bugs/2019/4399-walmsley/test.xsl
OPT : Lifted (tail((1,...)[. eq $val])) above ($val[fn:exists(...)]) on line 12
OPT : Expression after rewrite: let $Q{http://saxon.sf.net/generated-variable}v0 := tail((1, 2, 3, 3)[. eq $val]) return ($val[exists($Q{http://saxon.sf.net/generated-variable}v0)])
OPT : At line 12 of file:/Users/mike/bugs/2019/4399-walmsley/test.xsl
OPT : Lifted (bytecode(fn:exists(...))) above ($val[$vv:v0]) on line 12
OPT : Expression after rewrite: let $Q{http://saxon.sf.net/generated-variable}v0 := bytecode(exists($Q{http://saxon.sf.net/generated-variable}v0)) return ($val[$Q{http://saxon.sf.net/generated-variable}v0])
OPT : At line 12 of file:/Users/mike/bugs/2019/4399-walmsley/test.xsl
OPT : Created indexed filter expression: 
OPT : Expression after rewrite: IndexedFilterExpression($seq, ., $val)
OPT : At line 12 of file:/Users/mike/bugs/2019/4399-walmsley/test.xsl
OPT : Rewrite count()>=N as:
OPT : Expression after rewrite: exists(tail(IndexedFilterExpression($seq, ., $val)))
OPT : At line 12 of file:/Users/mike/bugs/2019/4399-walmsley/test.xsl
OPT : Lifted (tail($seq[(:indexed:).=$val])) above ($val[fn:exists(...)]) on line 12
OPT : Expression after rewrite: let $Q{http://saxon.sf.net/generated-variable}v0 := tail(IndexedFilterExpression($seq, ., $val)) return ($val[exists($Q{http://saxon.sf.net/generated-variable}v0)])

I'm mildly surprised that it hasn't done the whole computation at compile time, since there is no dependency on anything in the source document. The reason an "innocent" query like this can exercise unusual paths in the Saxon code is because real life queries can rarely be optimized quite so heavily.

Actions #4

Updated by Michael Kay over 4 years ago

A peculiarity, which I don't think I've ever seen before, is that it doesn't crash when run with the -explain option.

Without -explain, we seem to following a slightly different path in the optimizer. I suspect that it's simply an effect of the fact that the order in which functions/templates are processed by the optimizer is fairly unpredictable.

Looking more closely at the non-explain path in the debugger, it is actually oprimizing more ambitiously than the -explain case. In the IndexedFilterExpression($seq, ., $val), the variable $seq has has been replaced by its value (1,2,3,3), and the optimizer now tries to undo the indexing because it can see that it has become pointless. But the undoing is its undoing, to coin a phrase, because it doesn't allow for the different focus for ".". In particular, it wrongly decides that the context item type for "." is document-node(), and that it therefore needs to be atomized, and from this point everything falls apart.

Actions #5

Updated by Michael Kay over 4 years ago

  • Status changed from In Progress to Resolved
  • Applies to branch 9.9, trunk added
  • Applies to branch deleted (9.8)
  • Fix Committed on Branch 9.9, trunk added

Resolved with a patch to IndexedFilterExpression: on the path in optimize() where it decides to revert to an ordinary filter expression, it now correctly sets the context item type for the predicate of the new filter expression.

Actions #6

Updated by Michael Kay over 4 years ago

  • Applies to branch 9.8 added
Actions #7

Updated by O'Neil Delpratt over 4 years ago

  • Status changed from Resolved to Closed
  • Fixed in Maintenance Release 9.9.1.6 added

Patch committed to the Saxon 9.9.1.6 maintenance release.

Please register to edit this issue

Also available in: Atom PDF