Search in sources :

Example 1 with NodeProxy

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

the class DOMFile method findValue.

/**
 * Retrieve node at virtual address.
 *
 * @param broker the database broker
 * @param node The virtual address
 * @return The reference of the node
 * @throws IOException if an I/O error occurs
 * @throws BTreeException if an error occurs reading the tree
 */
protected long findValue(final DBBroker broker, final NodeProxy node) throws IOException, BTreeException {
    if (LOG.isDebugEnabled() && !lockManager.isBtreeLocked(getLockName())) {
        LOG.debug("The file doesn't own a lock");
    }
    final DocumentImpl doc = node.getOwnerDocument();
    final NodeRef nodeRef = new NativeBroker.NodeRef(doc.getDocId(), node.getNodeId());
    // first try to find the node in the index
    final long pointer = findValue(nodeRef);
    if (pointer == KEY_NOT_FOUND) {
        // node not found in index: try to find the nearest available
        // ancestor and traverse it
        NodeId nodeID = node.getNodeId();
        long parentPointer = KEY_NOT_FOUND;
        do {
            nodeID = nodeID.getParentId();
            if (nodeID == null) {
                SanityCheck.TRACE("Node " + node.getOwnerDocument().getDocId() + ":<null nodeID> not found.");
                throw new BTreeException("Node not found.");
            }
            if (nodeID == NodeId.DOCUMENT_NODE) {
                SanityCheck.TRACE("Node " + node.getOwnerDocument().getDocId() + ":" + nodeID + " not found.");
                return KEY_NOT_FOUND;
            }
            final NativeBroker.NodeRef parentRef = new NativeBroker.NodeRef(doc.getDocId(), nodeID);
            try {
                parentPointer = findValue(parentRef);
            } catch (final BTreeException bte) {
                LOG.error("report me", bte);
            }
        } while (parentPointer == KEY_NOT_FOUND);
        try {
            final int thisLevel = nodeID.getTreeLevel();
            // lazily initialized below
            Integer childLevel = null;
            final NodeProxy parent = new NodeProxy(doc, nodeID, parentPointer);
            final EmbeddedXMLStreamReader reader = (EmbeddedXMLStreamReader) broker.getXMLStreamReader(parent, true);
            while (reader.hasNext()) {
                final int status = reader.next();
                if (status != XMLStreamReader.END_ELEMENT) {
                    if (childLevel == null) {
                        childLevel = reader.getNode().getNodeType() == Node.ELEMENT_NODE ? thisLevel + 1 : thisLevel;
                    }
                    final NodeId otherId = (NodeId) reader.getProperty(ExtendedXMLStreamReader.PROPERTY_NODE_ID);
                    if (otherId.equals(node.getNodeId())) {
                        return reader.getCurrentPosition();
                    }
                }
                if (status == XMLStreamConstants.END_ELEMENT) {
                    final NodeId otherId = (NodeId) reader.getProperty(ExtendedXMLStreamReader.PROPERTY_NODE_ID);
                    final int otherLevel = otherId.getTreeLevel();
                    if (childLevel != null && childLevel != otherLevel && otherLevel == thisLevel) {
                        // exit-while
                        break;
                    }
                }
            }
            if (LOG.isDebugEnabled()) {
                LOG.debug("Node {} could not be found. Giving up. This is usually not an error.", node.getNodeId());
            }
            return KEY_NOT_FOUND;
        } catch (final XMLStreamException e) {
            SanityCheck.TRACE("Node " + node.getOwnerDocument().getDocId() + ":" + node.getNodeId() + " not found.");
            throw new BTreeException("Node " + node.getNodeId() + " not found.");
        }
    } else {
        return pointer;
    }
}
Also used : NodeRef(org.exist.storage.NativeBroker.NodeRef) BTreeException(org.exist.storage.btree.BTreeException) XMLStreamException(javax.xml.stream.XMLStreamException) NodeId(org.exist.numbering.NodeId) EmbeddedXMLStreamReader(org.exist.stax.EmbeddedXMLStreamReader) NativeBroker(org.exist.storage.NativeBroker) NodeRef(org.exist.storage.NativeBroker.NodeRef) DocumentImpl(org.exist.dom.persistent.DocumentImpl) NodeProxy(org.exist.dom.persistent.NodeProxy)

Example 2 with NodeProxy

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

the class DOMFile method getNodeValue.

/**
 * Retrieve the string value of the specified node. This is an optimized low-level method
 * which will directly traverse the stored DOM nodes and collect the string values of
 * the specified root node and all its descendants. By directly scanning the stored
 * node data, we do not need to create a potentially large amount of node objects
 * and thus save memory and time for garbage collection.
 *
 * @param broker the database broker
 * @param node the node
 * @param addWhitespace true if whitespace should be added to the node value
 * @return string value of the specified node
 */
public String getNodeValue(final DBBroker broker, final IStoredNode node, final boolean addWhitespace) {
    if (LOG.isDebugEnabled() && !lockManager.isBtreeLocked(getLockName())) {
        LOG.debug("The file doesn't own a lock");
    }
    try {
        long address = node.getInternalAddress();
        RecordPos recordPos = null;
        // try to directly locate the root node through its storage address
        if (StorageAddress.hasAddress(address)) {
            recordPos = findRecord(address);
        }
        if (recordPos == null) {
            // fallback to a BTree lookup if the node could not be found
            // by its storage address
            address = findValue(broker, new NodeProxy(node));
            if (address == BTree.KEY_NOT_FOUND) {
                LOG.error("Node value not found: {}", node);
                // TODO : throw exception ? -pb
                return null;
            }
            recordPos = findRecord(address);
            SanityCheck.THROW_ASSERT(recordPos != null, "Node data could not be found!");
        // TODO : throw exception ? -pb
        }
        // we collect the string values in binary format and append them to a ByteArrayOutputStream
        try (final UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream(32)) {
            // now traverse the tree
            getNodeValue(broker.getBrokerPool(), os, recordPos, true, addWhitespace);
            final byte[] data = os.toByteArray();
            final XMLString str = UTF8.decode(data);
            if (str != null) {
                return str.toString();
            } else {
                return "";
            }
        }
    } catch (final BTreeException e) {
        LOG.error("BTree error while reading node value", e);
    // TODO : rethrow exception ? -pb
    } catch (final Exception e) {
        LOG.error("IO error while reading node value", e);
    // TODO : rethrow exception ? -pb
    }
    // TODO : remove if exceptions thrown...
    return null;
}
Also used : BTreeException(org.exist.storage.btree.BTreeException) UnsynchronizedByteArrayOutputStream(org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream) NodeProxy(org.exist.dom.persistent.NodeProxy) JournalException(org.exist.storage.journal.JournalException) TerminatedException(org.exist.xquery.TerminatedException) XMLStreamException(javax.xml.stream.XMLStreamException) DBException(org.exist.storage.btree.DBException) BTreeException(org.exist.storage.btree.BTreeException) IOException(java.io.IOException)

Example 3 with NodeProxy

use of org.exist.dom.persistent.NodeProxy 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 4 with NodeProxy

use of org.exist.dom.persistent.NodeProxy 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 5 with NodeProxy

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

the class ValueComparison method nodeSetCompare.

protected Sequence nodeSetCompare(NodeSet nodes, Sequence contextSequence) throws XPathException {
    if (context.getProfiler().isEnabled()) {
        context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION CHOICE", "nodeSetCompare");
    }
    final NodeSet result = new ExtArrayNodeSet();
    final Collator collator = getCollator(contextSequence);
    if (contextSequence != null && !contextSequence.isEmpty()) {
        for (final NodeProxy current : nodes) {
            ContextItem context = current.getContext();
            if (context == null) {
                throw new XPathException(this, ErrorCodes.XPDY0002, "Context is missing for node set comparison");
            }
            do {
                final AtomicValue lv = current.atomize();
                final Sequence rs = getRight().eval(context.getNode().toSequence());
                if (!rs.hasOne()) {
                    throw new XPathException(this, ErrorCodes.XPTY0004, "Type error: sequence with less or more than one item is not allowed here");
                }
                if (compareAtomic(collator, lv, rs.itemAt(0).atomize(), StringTruncationOperator.NONE, relation)) {
                    result.add(current);
                }
            } while ((context = context.getNextDirect()) != null);
        }
    } else {
        final Sequence rs = getRight().eval(null);
        if (!rs.hasOne()) {
            throw new XPathException(this, ErrorCodes.XPTY0004, "Type error: sequence with less or more than one item is not allowed here");
        }
        final AtomicValue rv = rs.itemAt(0).atomize();
        for (final NodeProxy current : nodes) {
            final AtomicValue lv = current.atomize();
            if (compareAtomic(collator, lv, rv, StringTruncationOperator.NONE, Comparison.EQ)) {
                result.add(current);
            }
        }
    }
    return result;
}
Also used : ExtArrayNodeSet(org.exist.dom.persistent.ExtArrayNodeSet) NodeSet(org.exist.dom.persistent.NodeSet) ContextItem(org.exist.dom.persistent.ContextItem) ExtArrayNodeSet(org.exist.dom.persistent.ExtArrayNodeSet) AtomicValue(org.exist.xquery.value.AtomicValue) Sequence(org.exist.xquery.value.Sequence) NodeProxy(org.exist.dom.persistent.NodeProxy) Collator(com.ibm.icu.text.Collator)

Aggregations

NodeProxy (org.exist.dom.persistent.NodeProxy)79 DocumentImpl (org.exist.dom.persistent.DocumentImpl)18 Sequence (org.exist.xquery.value.Sequence)17 NodeSet (org.exist.dom.persistent.NodeSet)16 NodeId (org.exist.numbering.NodeId)16 XPathException (org.exist.xquery.XPathException)16 IOException (java.io.IOException)12 NewArrayNodeSet (org.exist.dom.persistent.NewArrayNodeSet)10 PermissionDeniedException (org.exist.security.PermissionDeniedException)10 LockException (org.exist.util.LockException)10 NodeValue (org.exist.xquery.value.NodeValue)10 Node (org.w3c.dom.Node)9 Document (org.w3c.dom.Document)8 SAXException (org.xml.sax.SAXException)8 NodeImpl (org.exist.dom.memtree.NodeImpl)7 ExtArrayNodeSet (org.exist.dom.persistent.ExtArrayNodeSet)7 SequenceIterator (org.exist.xquery.value.SequenceIterator)7 ReentrantLock (java.util.concurrent.locks.ReentrantLock)6 MemTreeBuilder (org.exist.dom.memtree.MemTreeBuilder)6 Match (org.exist.dom.persistent.Match)6