Search in sources :

Example 1 with NewArrayNodeSet

use of org.exist.dom.persistent.NewArrayNodeSet in project exist by eXist-db.

the class RootNode method eval.

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());
        }
    }
    // first, if we have been explicitly given a context item or context sequence, we can just use that
    if (contextItem != null) {
        return new ValueSequence(contextItem);
    } else if (contextSequence != null && contextSequence != Sequence.EMPTY_SEQUENCE) {
        return contextSequence;
    }
    // second, check if a context item is declared
    final ContextItemDeclaration decl = context.getContextItemDeclartion();
    if (decl != null) {
        final Sequence seq = decl.eval(null, null);
        if (!seq.isEmpty()) {
            final Item item = seq.itemAt(0);
            // context item must be a node
            if (!Type.subTypeOf(item.getType(), Type.NODE)) {
                throw new XPathException(this, ErrorCodes.XPTY0020, "Context item is not a node");
            }
            final NodeValue node = (NodeValue) item;
            // return fn:root(self::node()) treat as document-node()
            if (node.getImplementationType() == NodeValue.PERSISTENT_NODE) {
                return new NodeProxy(((NodeProxy) item).getOwnerDocument());
            } else {
                if (node.getType() == Type.DOCUMENT) {
                    return node;
                }
                return (org.exist.dom.memtree.DocumentImpl) node.getOwnerDocument();
            }
        }
        return Sequence.EMPTY_SEQUENCE;
    }
    // get statically known documents from the context
    DocumentSet ds = context.getStaticallyKnownDocuments();
    if (ds == null || ds.getDocumentCount() == 0) {
        return Sequence.EMPTY_SEQUENCE;
    }
    // fix for util:eval-with-context
    if (contextSequence != null) {
        if (!contextSequence.isEmpty()) {
            final Item item = contextSequence.itemAt(0);
            // context item must be a node
            if (!Type.subTypeOf(item.getType(), Type.NODE)) {
                throw new XPathException(this, ErrorCodes.XPTY0020, "Context item is not a node");
            }
            final NodeValue node = (NodeValue) item;
            // return fn:root(self::node()) treat as document-node()
            if (node.getImplementationType() == NodeValue.PERSISTENT_NODE) {
                return new NodeProxy(((NodeProxy) item).getOwnerDocument());
            } else {
                if (node.getType() == Type.DOCUMENT) {
                    return node;
                }
                return (org.exist.dom.memtree.DocumentImpl) node.getOwnerDocument();
            }
        } else {
            return Sequence.EMPTY_SEQUENCE;
        }
    }
    // // if the expression occurs in a nested context, we might have cached the
    // // document set
    // // TODO: disabled cache for now as it may cause concurrency issues
    // // better use compile-time inspection and maybe a pragma to mark those
    // // sections in the query that can be safely cached
    // if (cachedDocs != null && cachedDocs.equalDocs(ds)) return cached;
    // check if the loaded documents should remain locked
    NewArrayNodeSet result = new NewArrayNodeSet();
    // NOTE(AR) locking the documents here does not actually do anything useful, eXist-db will still exhibit weak isolation with concurrent updates
    // ManagedLocks<ManagedDocumentLock> docLocks = null;
    // try {
    // // wait for pending updates
    // if (!context.inProtectedMode()) {
    // docLocks = ds.lock(context.getBroker(), false);
    // }
    DocumentImpl doc;
    for (final Iterator<DocumentImpl> i = ds.getDocumentIterator(); i.hasNext(); ) {
        doc = i.next();
        if (context.inProtectedMode() && !context.getProtectedDocs().containsKey(doc.getDocId())) {
            continue;
        }
        if (doc.getResourceType() == DocumentImpl.XML_FILE) {
            // skip binary resources
            result.add(new NodeProxy(doc));
        }
    }
    cached = result;
    cachedDocs = ds;
    // result.updateNoSort();
    if (context.getProfiler().isEnabled()) {
        context.getProfiler().end(this, "", result);
    }
    registerUpdateListener();
    return result;
}
Also used : NewArrayNodeSet(org.exist.dom.persistent.NewArrayNodeSet) NodeProxy(org.exist.dom.persistent.NodeProxy) DocumentImpl(org.exist.dom.persistent.DocumentImpl) DocumentSet(org.exist.dom.persistent.DocumentSet)

Example 2 with NewArrayNodeSet

use of org.exist.dom.persistent.NewArrayNodeSet in project exist by eXist-db.

the class Predicate method selectByPosition.

/**
 * @param outerSequence the outer sequence
 * @param contextSequence the context sequence
 * @param mode the mode
 * @param innerSeq the inner sequence
 *
 * @return The result of the positional evaluation of the predicate.
 *
 * @throws XPathException if an error occurs
 */
private Sequence selectByPosition(final Sequence outerSequence, final Sequence contextSequence, final int mode, final Sequence innerSeq) throws XPathException {
    if (outerSequence != null && !outerSequence.isEmpty() && Type.subTypeOf(contextSequence.getItemType(), Type.NODE) && contextSequence.isPersistentSet() && outerSequence.isPersistentSet()) {
        final Sequence result = new NewArrayNodeSet();
        final NodeSet contextSet = contextSequence.toNodeSet();
        switch(mode) {
            case Constants.CHILD_AXIS:
            case Constants.ATTRIBUTE_AXIS:
            case Constants.DESCENDANT_AXIS:
            case Constants.DESCENDANT_SELF_AXIS:
            case Constants.DESCENDANT_ATTRIBUTE_AXIS:
                {
                    final NodeSet outerNodeSet = outerSequence.toNodeSet();
                    // TODO: in some cases, especially with in-memory nodes,
                    // outerSequence.toNodeSet() will generate a document
                    // which will be different from the one(s) in contextSet
                    // ancestors will thus be empty :-(
                    // A special treatment of VirtualNodeSet does not seem to be
                    // required anymore
                    final Sequence ancestors = outerNodeSet.selectAncestors(contextSet, true, getExpressionId());
                    if (contextSet.getDocumentSet().intersection(outerNodeSet.getDocumentSet()).getDocumentCount() == 0) {
                        LOG.info("contextSet and outerNodeSet don't share any document");
                    }
                    final NewArrayNodeSet temp = new NewArrayNodeSet();
                    for (final SequenceIterator i = ancestors.iterate(); i.hasNext(); ) {
                        NodeProxy p = (NodeProxy) i.nextItem();
                        ContextItem contextNode = p.getContext();
                        temp.reset();
                        while (contextNode != null) {
                            if (contextNode.getContextId() == getExpressionId()) {
                                temp.add(contextNode.getNode());
                            }
                            contextNode = contextNode.getNextDirect();
                        }
                        p.clearContext(getExpressionId());
                        // TODO : understand why we sort here...
                        temp.sortInDocumentOrder();
                        for (final SequenceIterator j = innerSeq.iterate(); j.hasNext(); ) {
                            final NumericValue v = (NumericValue) j.nextItem();
                            // Non integers return... nothing, not even an error !
                            if (!v.hasFractionalPart() && !v.isZero()) {
                                // ... whereas we don't want a sorted array here
                                // TODO : rename this method as getInDocumentOrder ? -pb
                                p = temp.get(v.getInt() - 1);
                                if (p != null) {
                                    result.add(p);
                                }
                            // TODO : does null make sense here ? Well... sometimes ;-)
                            }
                        }
                    }
                    break;
                }
            default:
                for (final SequenceIterator i = outerSequence.iterate(); i.hasNext(); ) {
                    NodeProxy p = (NodeProxy) i.nextItem();
                    Sequence temp;
                    boolean reverseAxis = true;
                    switch(mode) {
                        case Constants.ANCESTOR_AXIS:
                            temp = contextSet.selectAncestors(p, false, Expression.IGNORE_CONTEXT);
                            break;
                        case Constants.ANCESTOR_SELF_AXIS:
                            temp = contextSet.selectAncestors(p, true, Expression.IGNORE_CONTEXT);
                            break;
                        case Constants.PARENT_AXIS:
                            // TODO : understand why the contextSet is not involved
                            // here
                            // NodeProxy.getParent returns a *theoretical* parent
                            // which is *not* guaranteed to be in the context set !
                            temp = p.getParents(Expression.NO_CONTEXT_ID);
                            break;
                        case Constants.PRECEDING_AXIS:
                            temp = contextSet.selectPreceding(p, Expression.IGNORE_CONTEXT);
                            break;
                        case Constants.PRECEDING_SIBLING_AXIS:
                            temp = contextSet.selectPrecedingSiblings(p, Expression.IGNORE_CONTEXT);
                            break;
                        case Constants.FOLLOWING_SIBLING_AXIS:
                            temp = contextSet.selectFollowingSiblings(p, Expression.IGNORE_CONTEXT);
                            reverseAxis = false;
                            break;
                        case Constants.FOLLOWING_AXIS:
                            temp = contextSet.selectFollowing(p, Expression.IGNORE_CONTEXT);
                            reverseAxis = false;
                            break;
                        case Constants.SELF_AXIS:
                            temp = p;
                            reverseAxis = false;
                            break;
                        default:
                            throw new IllegalArgumentException("Tried to test unknown axis");
                    }
                    if (!temp.isEmpty()) {
                        for (final SequenceIterator j = innerSeq.iterate(); j.hasNext(); ) {
                            final NumericValue v = (NumericValue) j.nextItem();
                            // Non integers return... nothing, not even an error !
                            if (!v.hasFractionalPart() && !v.isZero()) {
                                final int pos = (reverseAxis ? temp.getItemCount() - v.getInt() : v.getInt() - 1);
                                // Other positions are ignored
                                if (pos >= 0 && pos < temp.getItemCount()) {
                                    final NodeProxy t = (NodeProxy) temp.itemAt(pos);
                                    // for the current context: filter out those
                                    // context items not selected by the positional predicate
                                    ContextItem ctx = t.getContext();
                                    t.clearContext(Expression.IGNORE_CONTEXT);
                                    while (ctx != null) {
                                        if (ctx.getContextId() == outerContextId) {
                                            if (ctx.getNode().getNodeId().equals(p.getNodeId())) {
                                                t.addContextNode(outerContextId, ctx.getNode());
                                            }
                                        } else {
                                            t.addContextNode(ctx.getContextId(), ctx.getNode());
                                        }
                                        ctx = ctx.getNextDirect();
                                    }
                                    result.add(t);
                                }
                            }
                        }
                    }
                }
        }
        return result;
    } else {
        final boolean reverseAxis = Type.subTypeOf(contextSequence.getItemType(), Type.NODE) && (mode == Constants.ANCESTOR_AXIS || mode == Constants.ANCESTOR_SELF_AXIS || mode == Constants.PARENT_AXIS || mode == Constants.PRECEDING_AXIS || mode == Constants.PRECEDING_SIBLING_AXIS);
        final Set<NumericValue> set = new TreeSet<>();
        final ValueSequence result = new ValueSequence();
        for (final SequenceIterator i = innerSeq.iterate(); i.hasNext(); ) {
            final NumericValue v = (NumericValue) i.nextItem();
            // Non integers return... nothing, not even an error !
            if (!v.hasFractionalPart() && !v.isZero()) {
                final int pos = (reverseAxis ? contextSequence.getItemCount() - v.getInt() : v.getInt() - 1);
                // Other positions are ignored
                if (pos >= 0 && pos < contextSequence.getItemCount() && !set.contains(v)) {
                    result.add(contextSequence.itemAt(pos));
                    set.add(v);
                }
            }
        }
        return result;
    }
}
Also used : NodeSet(org.exist.dom.persistent.NodeSet) VirtualNodeSet(org.exist.dom.persistent.VirtualNodeSet) NewArrayNodeSet(org.exist.dom.persistent.NewArrayNodeSet) NewArrayNodeSet(org.exist.dom.persistent.NewArrayNodeSet) ContextItem(org.exist.dom.persistent.ContextItem) ValueSequence(org.exist.xquery.value.ValueSequence) Sequence(org.exist.xquery.value.Sequence) NodeProxy(org.exist.dom.persistent.NodeProxy) SequenceIterator(org.exist.xquery.value.SequenceIterator) TreeSet(java.util.TreeSet) ValueSequence(org.exist.xquery.value.ValueSequence) NumericValue(org.exist.xquery.value.NumericValue)

Example 3 with NewArrayNodeSet

use of org.exist.dom.persistent.NewArrayNodeSet in project exist by eXist-db.

the class GeneralComparison method preSelect.

public NodeSet preSelect(Sequence contextSequence, boolean useContext) throws XPathException {
    // the expression can be called multiple times, so we need to clear the previous preselectResult
    preselectResult = null;
    final long start = System.currentTimeMillis();
    final int indexType = Optimize.getQNameIndexType(context, contextSequence, contextQName);
    if (LOG.isTraceEnabled()) {
        LOG.trace("Using QName index on type {}", Type.getTypeName(indexType));
    }
    final Sequence rightSeq = getRight().eval(contextSequence);
    // into preselectResult
    if (rightSeq.getItemCount() > 1) {
        preselectResult = new NewArrayNodeSet();
    }
    // Iterate through each item in the right-hand sequence
    for (final SequenceIterator itRightSeq = Atomize.atomize(rightSeq).iterate(); itRightSeq.hasNext(); ) {
        // Get the index key
        Item key = itRightSeq.nextItem();
        // if key has truncation, convert it to string
        if (truncation != StringTruncationOperator.NONE) {
            if (!Type.subTypeOf(key.getType(), Type.STRING)) {
                LOG.info("Truncated key. Converted from {} to xs:string", Type.getTypeName(key.getType()));
                // truncation is only possible on strings
                key = key.convertTo(Type.STRING);
            }
        } else // TODO : use Type.isSubType() ??? -pb
        if (key.getType() != indexType) {
            // try to convert the key to the index type
            try {
                key = key.convertTo(indexType);
            } catch (final XPathException xpe) {
                if (LOG.isTraceEnabled()) {
                    LOG.trace("Cannot convert key: {} to required index type: {}", Type.getTypeName(key.getType()), Type.getTypeName(indexType));
                }
                throw (new XPathException(this, "Cannot convert key to required index type"));
            }
        }
        // If key implements org.exist.storage.Indexable, we can use the index
        if (key instanceof Indexable) {
            if (LOG.isTraceEnabled()) {
                LOG.trace("Using QName range index for key: {}", key.getStringValue());
            }
            NodeSet temp;
            final NodeSet contextSet = useContext ? contextSequence.toNodeSet() : null;
            final Collator collator = ((collationArg != null) ? getCollator(contextSequence) : null);
            if (truncation == StringTruncationOperator.NONE) {
                temp = context.getBroker().getValueIndex().find(context.getWatchDog(), relation, contextSequence.getDocumentSet(), contextSet, NodeSet.DESCENDANT, contextQName, (Indexable) key);
                hasUsedIndex = true;
            } else {
                try {
                    final String matchString = key.getStringValue();
                    final int matchType = getMatchType(truncation);
                    temp = context.getBroker().getValueIndex().match(context.getWatchDog(), contextSequence.getDocumentSet(), contextSet, NodeSet.DESCENDANT, matchString, contextQName, matchType, collator, truncation);
                    hasUsedIndex = true;
                } catch (final EXistException e) {
                    throw (new XPathException(this, "Error during index lookup: " + e.getMessage(), e));
                }
            }
            // else replace it.
            if (preselectResult == null) {
                preselectResult = temp;
            } else {
                preselectResult.addAll(temp);
            }
        }
    }
    if (context.getProfiler().traceFunctions()) {
        context.getProfiler().traceIndexUsage(context, PerformanceStats.RANGE_IDX_TYPE, this, PerformanceStats.OPTIMIZED_INDEX, System.currentTimeMillis() - start);
    }
    return ((preselectResult == null) ? NodeSet.EMPTY_SET : preselectResult);
}
Also used : NodeSet(org.exist.dom.persistent.NodeSet) VirtualNodeSet(org.exist.dom.persistent.VirtualNodeSet) NewArrayNodeSet(org.exist.dom.persistent.NewArrayNodeSet) NewArrayNodeSet(org.exist.dom.persistent.NewArrayNodeSet) Item(org.exist.xquery.value.Item) ContextItem(org.exist.dom.persistent.ContextItem) SequenceIterator(org.exist.xquery.value.SequenceIterator) Indexable(org.exist.storage.Indexable) Sequence(org.exist.xquery.value.Sequence) EXistException(org.exist.EXistException) Collator(com.ibm.icu.text.Collator)

Example 4 with NewArrayNodeSet

use of org.exist.dom.persistent.NewArrayNodeSet in project exist by eXist-db.

the class LuceneMatchListener method reset.

protected void reset(final DBBroker broker, final NodeProxy proxy) {
    this.broker = broker;
    this.match = proxy.getMatches();
    setNextInChain(null);
    final IndexSpec indexConf = proxy.getOwnerDocument().getCollection().getIndexConfiguration(broker);
    if (indexConf != null) {
        config = (LuceneConfig) indexConf.getCustomIndexSpec(LuceneIndex.ID);
    } else {
        config = LuceneConfig.DEFAULT_CONFIG;
    }
    getTerms();
    nodesWithMatch = new TreeMap<>();
    /* Check if an index is defined on an ancestor of the current node.
        * If yes, scan the ancestor to get the offset of the first character
        * in the current node. For example, if the indexed node is &lt;a>abc&lt;b>de&lt;/b></a>
        * and we query for //a[text:ngram-contains(., 'de')]/b, proxy will be a &lt;b> node, but
        * the offsets of the matches are relative to the start of &lt;a>.
        */
    NodeSet ancestors = null;
    Match nextMatch = this.match;
    while (nextMatch != null) {
        if (proxy.getNodeId().isDescendantOf(nextMatch.getNodeId())) {
            if (ancestors == null) {
                ancestors = new NewArrayNodeSet();
            }
            ancestors.add(new NodeProxy(proxy.getOwnerDocument(), nextMatch.getNodeId()));
        }
        nextMatch = nextMatch.getNextMatch();
    }
    if (ancestors != null && !ancestors.isEmpty()) {
        for (final NodeProxy p : ancestors) {
            scanMatches(p);
        }
    }
}
Also used : NodeSet(org.exist.dom.persistent.NodeSet) NewArrayNodeSet(org.exist.dom.persistent.NewArrayNodeSet) NewArrayNodeSet(org.exist.dom.persistent.NewArrayNodeSet) IndexSpec(org.exist.storage.IndexSpec) NodeProxy(org.exist.dom.persistent.NodeProxy) Match(org.exist.dom.persistent.Match)

Example 5 with NewArrayNodeSet

use of org.exist.dom.persistent.NewArrayNodeSet in project exist by eXist-db.

the class ArrayListValueSequence method toNodeSet.

@Override
public NodeSet toNodeSet() throws XPathException {
    if (isEmpty) {
        return NodeSet.EMPTY_SET;
    }
    // for this method to work, all items have to be nodes
    if (itemType != Type.ANY_TYPE && Type.subTypeOf(itemType, Type.NODE)) {
        final NodeSet set = new NewArrayNodeSet();
        for (int i = 0; i <= values.size(); i++) {
            NodeValue v = (NodeValue) values.get(i);
            if (v.getImplementationType() != NodeValue.PERSISTENT_NODE) {
                // found an in-memory document
                final DocumentImpl doc;
                if (v.getType() == Type.DOCUMENT) {
                    doc = (DocumentImpl) v;
                } else {
                    doc = ((NodeImpl) v).getOwnerDocument();
                }
                if (doc == null) {
                    continue;
                }
                // make this document persistent: doc.makePersistent()
                // returns a map of all root node ids mapped to the corresponding
                // persistent node. We scan the current sequence and replace all
                // in-memory nodes with their new persistent node objects.
                final DocumentImpl expandedDoc = doc.expandRefs(null);
                final org.exist.dom.persistent.DocumentImpl newDoc = expandedDoc.makePersistent();
                if (newDoc != null) {
                    NodeId rootId = newDoc.getBrokerPool().getNodeFactory().createInstance();
                    for (int j = i; j <= values.size(); j++) {
                        v = (NodeValue) values.get(j);
                        if (v.getImplementationType() != NodeValue.PERSISTENT_NODE) {
                            NodeImpl node = (NodeImpl) v;
                            final Document nodeOwnerDoc;
                            if (node.getNodeType() == Node.DOCUMENT_NODE) {
                                nodeOwnerDoc = (Document) node;
                            } else {
                                nodeOwnerDoc = node.getOwnerDocument();
                            }
                            if (nodeOwnerDoc == doc) {
                                if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
                                    node = expandedDoc.getAttribute(node.getNodeNumber());
                                } else {
                                    node = expandedDoc.getNode(node.getNodeNumber());
                                }
                                NodeId nodeId = node.getNodeId();
                                if (nodeId == null) {
                                    throw new XPathException("Internal error: nodeId == null");
                                }
                                if (node.getNodeType() == Node.DOCUMENT_NODE) {
                                    nodeId = rootId;
                                } else {
                                    nodeId = rootId.append(nodeId);
                                }
                                final NodeProxy p = new NodeProxy(newDoc, nodeId, node.getNodeType());
                                // replace the node by the NodeProxy
                                values.set(j, p);
                                setHasChanged();
                            }
                        }
                    }
                    set.add((NodeProxy) values.get(i));
                }
            } else {
                set.add((NodeProxy) v);
            }
        }
        // }
        return set;
    } else {
        throw new XPathException("Type error: the sequence cannot be converted into" + " a node set. Item type is " + Type.getTypeName(itemType));
    }
}
Also used : NodeSet(org.exist.dom.persistent.NodeSet) NewArrayNodeSet(org.exist.dom.persistent.NewArrayNodeSet) NewArrayNodeSet(org.exist.dom.persistent.NewArrayNodeSet) NodeImpl(org.exist.dom.memtree.NodeImpl) XPathException(org.exist.xquery.XPathException) Document(org.w3c.dom.Document) DocumentImpl(org.exist.dom.memtree.DocumentImpl) NodeProxy(org.exist.dom.persistent.NodeProxy) NodeId(org.exist.numbering.NodeId)

Aggregations

NewArrayNodeSet (org.exist.dom.persistent.NewArrayNodeSet)14 NodeProxy (org.exist.dom.persistent.NodeProxy)10 NodeSet (org.exist.dom.persistent.NodeSet)9 DocumentImpl (org.exist.dom.persistent.DocumentImpl)6 ReentrantLock (java.util.concurrent.locks.ReentrantLock)4 ContextItem (org.exist.dom.persistent.ContextItem)4 VirtualNodeSet (org.exist.dom.persistent.VirtualNodeSet)4 NodeId (org.exist.numbering.NodeId)4 PermissionDeniedException (org.exist.security.PermissionDeniedException)4 Value (org.exist.storage.btree.Value)4 DatabaseConfigurationException (org.exist.util.DatabaseConfigurationException)4 LockException (org.exist.util.LockException)4 IndexQuery (org.exist.storage.btree.IndexQuery)3 Sequence (org.exist.xquery.value.Sequence)3 SequenceIterator (org.exist.xquery.value.SequenceIterator)3 Collator (com.ibm.icu.text.Collator)2 QName (org.exist.dom.QName)2 TreeSet (java.util.TreeSet)1 EXistException (org.exist.EXistException)1 DocumentImpl (org.exist.dom.memtree.DocumentImpl)1