use of org.exist.dom.persistent.DocumentSet in project exist by eXist-db.
the class NativeStructuralIndexWorkerTest method getDocIdRanges_contiguousIds_followed_by_single.
@Test
public void getDocIdRanges_contiguousIds_followed_by_single() {
final NativeStructuralIndexWorker indexWorker = new NativeStructuralIndexWorker(null);
final DocumentSet docs = documentIdSet(Arrays.asList(11, 12, 13, 14, 15, 6574));
final List<NativeStructuralIndexWorker.Range> ranges = indexWorker.getDocIdRanges(docs);
assertEquals(2, ranges.size());
assertEquals(11, ranges.get(0).start);
assertEquals(15, ranges.get(0).end);
assertEquals(6574, ranges.get(1).start);
assertEquals(6574, ranges.get(1).end);
}
use of org.exist.dom.persistent.DocumentSet in project exist by eXist-db.
the class Lookup method eval.
@Override
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (!canOptimize && fallback != null) {
return fallback.eval(contextSequence, contextItem);
}
if (contextItem != null)
contextSequence = contextItem.toSequence();
if (contextSequence != null && !contextSequence.isPersistentSet()) {
// in-memory docs won't have an index
if (fallback == null) {
return Sequence.EMPTY_SEQUENCE;
} else {
return fallback.eval(contextSequence, contextItem);
}
}
NodeSet result;
if (preselectResult == null) {
long start = System.currentTimeMillis();
Sequence input = getArgument(0).eval(contextSequence);
if (!(input instanceof VirtualNodeSet) && input.isEmpty())
result = NodeSet.EMPTY_SET;
else {
RangeIndexWorker index = (RangeIndexWorker) context.getBroker().getIndexController().getWorkerByIndexId(RangeIndex.ID);
AtomicValue[] keys = getKeys(contextSequence);
if (keys.length == 0) {
return NodeSet.EMPTY_SET;
}
List<QName> qnames = null;
if (contextQName != null) {
qnames = new ArrayList<>(1);
qnames.add(contextQName);
}
final RangeIndex.Operator operator = getOperator();
// throw an exception if substring match operation is applied to collated index
if (usesCollation && !operator.supportsCollation()) {
throw new XPathException(this, RangeIndexModule.EXXQDYFT0001, "Index defines a collation which cannot be " + "used with the '" + operator + "' operation.");
}
try {
NodeSet inNodes = input.toNodeSet();
DocumentSet docs = inNodes.getDocumentSet();
result = index.query(getExpressionId(), docs, inNodes, qnames, keys, operator, NodeSet.ANCESTOR);
} catch (IOException e) {
throw new XPathException(this, e.getMessage());
}
}
if (context.getProfiler().traceFunctions()) {
context.getProfiler().traceIndexUsage(context, "new-range", this, PerformanceStats.BASIC_INDEX, System.currentTimeMillis() - start);
}
// LOG.info("eval plain took " + (System.currentTimeMillis() - start));
} else {
// long start = System.currentTimeMillis();
contextStep.setPreloadedData(preselectResult.getDocumentSet(), preselectResult);
result = getArgument(0).eval(contextSequence).toNodeSet();
// LOG.info("eval took " + (System.currentTimeMillis() - start));
}
return result;
}
use of org.exist.dom.persistent.DocumentSet in project exist by eXist-db.
the class Lookup method preSelect.
@Override
public NodeSet preSelect(Sequence contextSequence, boolean useContext) throws XPathException {
if (!canOptimize) {
return ((Optimizable) fallback).preSelect(contextSequence, useContext);
}
if (contextSequence != null && !contextSequence.isPersistentSet())
// in-memory docs won't have an index
return NodeSet.EMPTY_SET;
// throw an exception if substring match operation is applied to collated index
final RangeIndex.Operator operator = getOperator();
if (usesCollation && !operator.supportsCollation()) {
throw new XPathException(this, RangeIndexModule.EXXQDYFT0001, "Index defines a collation which cannot be " + "used with the '" + operator + "' operation.");
}
long start = System.currentTimeMillis();
// the expression can be called multiple times, so we need to clear the previous preselectResult
preselectResult = null;
RangeIndexWorker index = (RangeIndexWorker) context.getBroker().getIndexController().getWorkerByIndexId(RangeIndex.ID);
DocumentSet docs = contextSequence.getDocumentSet();
AtomicValue[] keys = getKeys(contextSequence);
if (keys.length == 0) {
return NodeSet.EMPTY_SET;
}
List<QName> qnames = null;
if (contextQName != null) {
qnames = new ArrayList<>(1);
qnames.add(contextQName);
}
try {
preselectResult = index.query(getExpressionId(), docs, contextSequence.toNodeSet(), qnames, keys, operator, NodeSet.DESCENDANT);
} catch (XPathException | IOException e) {
throw new XPathException(this, "Error while querying full text index: " + e.getMessage(), e);
}
// " and took " + (System.currentTimeMillis() - start));
if (context.getProfiler().traceFunctions()) {
context.getProfiler().traceIndexUsage(context, "new-range", this, PerformanceStats.OPTIMIZED_INDEX, System.currentTimeMillis() - start);
}
if (preselectResult == null) {
preselectResult = NodeSet.EMPTY_SET;
}
return preselectResult;
}
use of org.exist.dom.persistent.DocumentSet in project exist by eXist-db.
the class FunIdRef method eval.
/**
* @see org.exist.xquery.Expression#eval(Sequence, Item)
*/
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
if (getArgumentCount() < 1) {
throw new XPathException(this, ErrorCodes.XPST0017, "function id requires one argument");
}
if (contextItem != null) {
contextSequence = contextItem.toSequence();
}
Sequence result;
boolean processInMem = false;
final Expression arg = getArgument(0);
final Sequence idrefval = arg.eval(contextSequence);
if (idrefval.isEmpty()) {
result = Sequence.EMPTY_SEQUENCE;
} else {
String nextId;
DocumentSet docs = null;
if (getArgumentCount() == 2) {
// second argument should be a node, whose owner document will be
// searched for the id
final Sequence nodes = getArgument(1).eval(contextSequence);
if (nodes.isEmpty()) {
throw new XPathException(this, ErrorCodes.XPDY0002, "no node or context item for fn:idref");
}
if (!Type.subTypeOf(nodes.itemAt(0).getType(), Type.NODE)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "fn:idref() argument is not a node");
}
NodeValue node = (NodeValue) nodes.itemAt(0);
if (node.getImplementationType() == NodeValue.IN_MEMORY_NODE) // TODO : how to enforce this ?
// If $node, or the context item if the second argument is omitted,
// is a node in a tree whose root is not a document node [err:FODC0001] is raised processInMem = true;
{
processInMem = true;
} else {
MutableDocumentSet ndocs = new DefaultDocumentSet();
ndocs.add(((NodeProxy) node).getOwnerDocument());
docs = ndocs;
}
contextSequence = node;
} else if (contextSequence == null) {
throw new XPathException(this, ErrorCodes.XPDY0002, "no context item specified");
} else if (!Type.subTypeOf(contextSequence.getItemType(), Type.NODE)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "context item is not a node");
} else {
if (contextSequence.isPersistentSet()) {
docs = contextSequence.toNodeSet().getDocumentSet();
} else {
processInMem = true;
}
}
if (processInMem) {
result = new ValueSequence();
} else {
result = new ExtArrayNodeSet();
}
for (final SequenceIterator i = idrefval.iterate(); i.hasNext(); ) {
nextId = i.nextItem().getStringValue();
if (nextId.isEmpty()) {
continue;
}
if (XMLNames.isNCName(nextId)) {
if (processInMem) {
getIdRef(result, contextSequence, nextId);
} else {
getIdRef((NodeSet) result, docs, nextId);
}
}
}
}
result.removeDuplicates();
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", result);
}
return result;
}
use of org.exist.dom.persistent.DocumentSet in project exist by eXist-db.
the class FunMatches method evalWithIndex.
/**
* @param contextSequence the context sequence
* @param contextItem the context item
* @param input the value of the $input arg
* @return The resulting sequence
* @throws XPathException if an error occurs
*/
private Sequence evalWithIndex(final Sequence contextSequence, final Item contextItem, final Sequence input) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
final int flags;
if (getSignature().getArgumentCount() == 3) {
final String flagsArg = getArgument(2).eval(contextSequence, contextItem).getStringValue();
flags = parseFlags(this, flagsArg);
} else {
flags = 0;
}
final boolean caseSensitive = !hasCaseInsensitive(flags);
Sequence result = null;
final String pattern;
if (isCalledAs("matches-regex")) {
pattern = getArgument(1).eval(contextSequence, contextItem).getStringValue();
} else {
final boolean literal = hasLiteral(flags);
if (literal) {
// no need to change anything
pattern = getArgument(1).eval(contextSequence, contextItem).getStringValue();
} else {
final boolean ignoreWhitespace = hasIgnoreWhitespace(flags);
final boolean caseBlind = !caseSensitive;
pattern = translateRegexp(this, getArgument(1).eval(contextSequence, contextItem).getStringValue(), ignoreWhitespace, caseBlind);
}
}
final NodeSet nodes = input.toNodeSet();
// get the type of a possible index
final int indexType = nodes.getIndexType();
if (LOG.isTraceEnabled()) {
LOG.trace("found an index of type: {}", Type.getTypeName(indexType));
}
if (Type.subTypeOf(indexType, Type.STRING)) {
boolean indexScan = false;
if (contextSequence != null) {
final GeneralComparison.IndexFlags iflags = GeneralComparison.checkForQNameIndex(idxflags, context, contextSequence, contextQName);
boolean indexFound = false;
if (!iflags.indexOnQName()) {
// if contextQName != null and no index is defined on
// contextQName, we don't need to scan other QName indexes
// and can just use the generic range index
indexFound = contextQName != null;
// set contextQName to null so the index lookup below is not
// restricted to that QName
contextQName = null;
}
if (!indexFound && contextQName == null) {
// we need to check them all
if (iflags.hasIndexOnQNames()) {
indexScan = true;
}
// else use range index defined on path by default
}
} else {
result = evalFallback(nodes, pattern, flags, indexType);
}
if (result == null) {
final DocumentSet docs = nodes.getDocumentSet();
try {
final NativeValueIndex index = context.getBroker().getValueIndex();
hasUsedIndex = true;
// TODO : check index' case compatibility with flags' one ? -pb
if (context.isProfilingEnabled()) {
context.getProfiler().message(this, Profiler.OPTIMIZATIONS, "Using value index '" + index.toString() + "'", "Regex: " + pattern);
}
if (LOG.isTraceEnabled()) {
LOG.trace("Using range index for fn:matches expression: {}", pattern);
}
if (indexScan) {
result = index.matchAll(context.getWatchDog(), docs, nodes, NodeSet.ANCESTOR, pattern, DBBroker.MATCH_REGEXP, flags, caseSensitive);
} else {
result = index.match(context.getWatchDog(), docs, nodes, NodeSet.ANCESTOR, pattern, contextQName, DBBroker.MATCH_REGEXP, flags, caseSensitive);
}
} catch (final EXistException e) {
throw new XPathException(this, e);
}
}
} else {
result = evalFallback(nodes, pattern, flags, indexType);
}
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", result);
}
return result;
}
Aggregations