//Iterate through the right hand sequence
for( final SequenceIterator itRightSeq = rightSeq.iterate(); itRightSeq.hasNext(); ) {
//Get the index key
Item key = itRightSeq.nextItem().atomize();
//if key has truncation, convert it to string
if( truncation != Constants.TRUNC_NONE ) {
if( !Type.subTypeOf( key.getType(), Type.STRING ) ) {
LOG.info( "Truncated key. Converted from " + Type.getTypeName( key.getType() ) + " to xs:string" );
//truncation is only possible on strings
key = key.convertTo( Type.STRING );
}
}
//else if key is not the same type as the index
//TODO : use Type.isSubType() ??? -pb
else if( key.getType() != indexType ) {
//try to convert the key to the index type
try {
key = key.convertTo( indexType );
}
catch( final XPathException xpe ) {
//TODO : rethrow the exception ? -pb
//Could not convert the key to a suitable type for the index, fallback to nodeSetCompare()
if( context.getProfiler().isEnabled() ) {
context.getProfiler().message( this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION FALLBACK", "Falling back to nodeSetCompare (" + xpe.getMessage() + ")" );
}
if( LOG.isTraceEnabled() ) {
LOG.trace( "Cannot convert key: " + Type.getTypeName( key.getType() ) + " to required index type: " + Type.getTypeName( indexType ) );
}
return( nodeSetCompare( nodes, contextSequence ) );
}
}
// If key implements org.exist.storage.Indexable, we can use the index
if( key instanceof Indexable ) {
if( LOG.isTraceEnabled() ) {
LOG.trace( "Checking if range index can be used for key: " + key.getStringValue() );
}
final Collator collator = ( ( collationArg != null ) ? getCollator( contextSequence ) : null );
if( Type.subTypeOf( key.getType(), indexType ) ) {
if( truncation == Constants.TRUNC_NONE ) {
if( LOG.isTraceEnabled() ) {
LOG.trace( "Using range index for key: " + key.getStringValue() );
}
//key without truncation, find key
context.getProfiler().message( this, Profiler.OPTIMIZATIONS, "OPTIMIZATION", "Using value index '" + context.getBroker().getValueIndex().toString() + "' to find key '" + Type.getTypeName( key.getType() ) + "(" + key.getStringValue() + ")'" );
NodeSet ns;
if( indexScan ) {
ns = context.getBroker().getValueIndex().findAll( context.getWatchDog(), relation, docs, nodes, NodeSet.ANCESTOR, ( Indexable )key, collator );
} else {
ns = context.getBroker().getValueIndex().find( context.getWatchDog(), relation, docs, nodes, NodeSet.ANCESTOR, myContextQName,
( Indexable )key, collator, indexMixed );
}
hasUsedIndex = true;
if( result == null ) {
result = ns;
} else {
result = result.union( ns );
}
} else {
//key with truncation, match key
if( LOG.isTraceEnabled() ) {
context.getProfiler().message( this, Profiler.OPTIMIZATIONS, "OPTIMIZATION", "Using value index '" + context.getBroker().getValueIndex().toString() + "' to match key '" + Type.getTypeName( key.getType() ) + "(" + key.getStringValue() + ")'" );
}
if( LOG.isTraceEnabled() ) {
LOG.trace( "Using range index for key: " + key.getStringValue() );
}
try {
NodeSet ns;
final String matchString = key.getStringValue();
final int matchType = getMatchType( truncation );
if( indexScan ) {
ns = context.getBroker().getValueIndex().matchAll( context.getWatchDog(), docs, nodes, NodeSet.ANCESTOR, matchString, matchType, 0, true, collator, truncation );
} else {
ns = context.getBroker().getValueIndex().match( context.getWatchDog(), docs, nodes, NodeSet.ANCESTOR, matchString, myContextQName, matchType, collator, truncation );
}
hasUsedIndex = true;
if( result == null ) {
result = ns;
} else {
result = result.union( ns );
}
}
catch( final EXistException e ) {
throw( new XPathException( this, e ) );
}
}
} else {
//our key does is not of the correct type
if( context.getProfiler().isEnabled() ) {
context.getProfiler().message( this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION FALLBACK", "Falling back to nodeSetCompare (key is of type: " + Type.getTypeName( key.getType() ) + ") whereas index is of type '" + Type.getTypeName( indexType ) + "'" );
}
if( LOG.isTraceEnabled() ) {
LOG.trace( "Cannot use range index: key is of type: " + Type.getTypeName( key.getType() ) + ") whereas index is of type '" + Type.getTypeName( indexType ) );
}
return( nodeSetCompare( nodes, contextSequence ) );
}
} else {
//our key does not implement org.exist.storage.Indexable
if( context.getProfiler().isEnabled() ) {
context.getProfiler().message( this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION FALLBACK", "Falling back to nodeSetCompare (key is not an indexable type: " + key.getClass().getName() );
}
if( LOG.isTraceEnabled() ) {
LOG.trace( "Cannot use key which is of type '" + key.getClass().getName() );
}
return( nodeSetCompare( nodes, contextSequence ) );
}