Bug #3764


Optimizing GeneralComparison to ValueComparison

Added by Michael Kay over 4 years ago. Updated almost 4 years ago.

Start date:
Due date:
% Done:


Estimated time:
Legacy ID:
Applies to branch:
Fix Committed on Branch:
Fixed in Maintenance Release:


Saxon attempts to rewrite a GeneralComparison (x = y) as a ValueComparison (x eq y) when it is safe to do so. The reason for this is that a ValueComparison is simpler (and therefore fractionally faster) but more particularly because a ValueComparison is more amenable to further optimizations. For example an xsl:choose of the form

  <xsl:when test="x = 1">...</xsl:when>
  <xsl:when test="x = 2">...</xsl:when>
  <xsl:when test="x = 3">...</xsl:when>
  <xsl:when test="x = 4">...</xsl:when>

is optimized internally to a SwitchExpression provided that the conditions are all ValueComparisons.

This rewrite is not happening for the very common expression of the form (@x = 'value'). In fact, it is only done where both operands have static cardinality exactly one and in this case the LHS cardinality is zero-or-one. It's not clear why this is done, because the result of a ValueComparison when one operand is an empty sequence is effectively false, which works out fine.

Probably it's because (@x = 'value') returns false when @x doesn't exist, while (@x eq 'value') returns an empty sequence; so the rewrite is only safe in a context where we are only interested in the effective boolean value. But ValueComparison has a flag that can be set to force it to return false on empty, so we could set this flag.

Actions #1

Updated by Michael Kay over 4 years ago

I have tried making this change to GeneralComparison.typeCheck() and it causes regression in a few tests, for example Count005. This test uses the query

count(//*[@name='John Doe 4']) lt 1.5

I've fixed this regression by changing the generated CastExpressions to permit an empty sequence.

Actions #2

Updated by Michael Kay about 4 years ago

The change also breaks the test predicate-051, in particular the predicate [not(@a="")]. Reverting for the time being.

Actions #3

Updated by Michael Kay almost 4 years ago

  • Description updated (diff)

I suspect the reason that test predicate-051 broke was because the rewrite exposed bug 3983. Shame we didn't investigate it further at the time.

Actions #4

Updated by Michael Kay almost 4 years ago

  • Category set to Performance
  • Status changed from New to Resolved
  • Priority changed from Low to Normal
  • Applies to branch 9.9 added
  • Fix Committed on Branch 9.9 added

The change now causes no test regression, so I am committing it.

Specifically, the change is to GeneralComparison.typeCheck(). It now rewrites as a ValueComparison if both operands have cardinality 0-or-1, whereas previously it required exactly-one.

Actions #5

Updated by O'Neil Delpratt almost 4 years ago

  • Status changed from Resolved to Closed
  • % Done changed from 0 to 100
  • Fixed in Maintenance Release added

Bug fix applied to the Saxon maintenance release.

Please register to edit this issue

Also available in: Atom PDF