Search in sources :

Example 1 with ContextItem

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

use of org.exist.dom.persistent.ContextItem 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)

Example 3 with ContextItem

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

the class PreorderedValueSequence method processAll.

private void processAll() throws XPathException {
    for (int i = 0; i < orderSpecs.length; i++) {
        final Expression expr = orderSpecs[i].getSortExpression();
        final NodeSet result = expr.eval(null).toNodeSet();
        for (final NodeProxy p : result) {
            ContextItem context = p.getContext();
            // TODO : review to consider transverse context
            while (context != null) {
                if (context.getNode() instanceof OrderedNodeProxy) {
                    final OrderedNodeProxy cp = (OrderedNodeProxy) context.getNode();
                    cp.values[i] = p.atomize();
                }
                context = context.getNextDirect();
            }
        }
    }
}
Also used : NodeSet(org.exist.dom.persistent.NodeSet) ContextItem(org.exist.dom.persistent.ContextItem) Expression(org.exist.xquery.Expression) NodeProxy(org.exist.dom.persistent.NodeProxy)

Example 4 with ContextItem

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

the class Predicate method selectByNodeSet.

/**
 * @param contextSequence the context sequence
 *
 * @return The result of the node set evaluation of the predicate.
 *
 * @throws XPathException if an error occurs
 */
private Sequence selectByNodeSet(final Sequence contextSequence) throws XPathException {
    final NewArrayNodeSet result = new NewArrayNodeSet();
    final NodeSet contextSet = contextSequence.toNodeSet();
    final boolean contextIsVirtual = contextSet instanceof VirtualNodeSet;
    contextSet.setTrackMatches(false);
    final NodeSet nodes = super.eval(contextSet, null).toNodeSet();
    /*
         * if the predicate expression returns results from the cache we can
         * also return the cached result.
         */
    if (cached != null && cached.isValid(contextSequence, null) && nodes.isCached()) {
        if (context.getProfiler().isEnabled()) {
            context.getProfiler().message(this, Profiler.OPTIMIZATIONS, "Using cached results", result);
        }
        return cached.getResult();
    }
    DocumentImpl lastDoc = null;
    for (final NodeProxy currentNode : nodes) {
        int sizeHint = Constants.NO_SIZE_HINT;
        if (lastDoc == null || currentNode.getOwnerDocument() != lastDoc) {
            lastDoc = currentNode.getOwnerDocument();
            sizeHint = nodes.getSizeHint(lastDoc);
        }
        ContextItem contextItem = currentNode.getContext();
        if (contextItem == null) {
            throw new XPathException(this, "Internal evaluation error: context is missing for node " + currentNode.getNodeId() + " !");
        }
        // TODO : review to consider transverse context
        while (contextItem != null) {
            if (contextItem.getContextId() == getExpressionId()) {
                final NodeProxy next = contextItem.getNode();
                if (contextIsVirtual || contextSet.contains(next)) {
                    next.addMatches(currentNode);
                    result.add(next, sizeHint);
                }
            }
            contextItem = contextItem.getNextDirect();
        }
    }
    if (contextSequence.isCacheable()) {
        cached = new CachedResult(contextSequence, null, result);
    }
    contextSet.setTrackMatches(true);
    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) DocumentImpl(org.exist.dom.persistent.DocumentImpl) NodeProxy(org.exist.dom.persistent.NodeProxy) VirtualNodeSet(org.exist.dom.persistent.VirtualNodeSet)

Example 5 with ContextItem

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

the class GeneralComparison method nodeSetCompare.

/**
 * Optimized implementation, which can be applied if the left operand returns a node set. In this case, the left expression is executed first. All
 * matching context nodes are then passed to the right expression.
 *
 * @param   nodes            DOCUMENT ME!
 * @param   contextSequence  DOCUMENT ME!
 *
 * @return  DOCUMENT ME!
 *
 * @throws  XPathException  DOCUMENT ME!
 */
protected Sequence nodeSetCompare(NodeSet nodes, Sequence contextSequence) throws XPathException {
    if (context.getProfiler().isEnabled()) {
        context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION CHOICE", "nodeSetCompare");
    }
    if (LOG.isTraceEnabled()) {
        LOG.trace("No index: fall back to nodeSetCompare");
    }
    final long start = System.currentTimeMillis();
    final NodeSet result = new NewArrayNodeSet();
    final Collator collator = getCollator(contextSequence);
    if ((contextSequence != null) && !contextSequence.isEmpty() && !contextSequence.getDocumentSet().contains(nodes.getDocumentSet())) {
        for (final NodeProxy item : nodes) {
            ContextItem context = item.getContext();
            if (context == null) {
                throw (new XPathException(this, "Internal error: context node missing"));
            }
            final AtomicValue lv = item.atomize();
            do {
                final Sequence rs = getRight().eval(context.getNode().toSequence());
                for (final SequenceIterator i2 = Atomize.atomize(rs).iterate(); i2.hasNext(); ) {
                    final AtomicValue rv = i2.nextItem().atomize();
                    if (compareAtomic(collator, lv, rv)) {
                        result.add(item);
                    }
                }
            } while ((context = context.getNextDirect()) != null);
        }
    } else {
        for (final NodeProxy item : nodes) {
            final AtomicValue lv = item.atomize();
            final Sequence rs = getRight().eval(contextSequence);
            for (final SequenceIterator i2 = Atomize.atomize(rs).iterate(); i2.hasNext(); ) {
                final AtomicValue rv = i2.nextItem().atomize();
                if (compareAtomic(collator, lv, rv)) {
                    result.add(item);
                }
            }
        }
    }
    if (context.getProfiler().traceFunctions()) {
        context.getProfiler().traceIndexUsage(context, PerformanceStats.RANGE_IDX_TYPE, this, PerformanceStats.NO_INDEX, System.currentTimeMillis() - start);
    }
    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) SequenceIterator(org.exist.xquery.value.SequenceIterator) 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

ContextItem (org.exist.dom.persistent.ContextItem)5 NodeProxy (org.exist.dom.persistent.NodeProxy)5 NodeSet (org.exist.dom.persistent.NodeSet)5 NewArrayNodeSet (org.exist.dom.persistent.NewArrayNodeSet)3 VirtualNodeSet (org.exist.dom.persistent.VirtualNodeSet)3 Sequence (org.exist.xquery.value.Sequence)3 Collator (com.ibm.icu.text.Collator)2 AtomicValue (org.exist.xquery.value.AtomicValue)2 SequenceIterator (org.exist.xquery.value.SequenceIterator)2 TreeSet (java.util.TreeSet)1 DocumentImpl (org.exist.dom.persistent.DocumentImpl)1 ExtArrayNodeSet (org.exist.dom.persistent.ExtArrayNodeSet)1 Expression (org.exist.xquery.Expression)1 NumericValue (org.exist.xquery.value.NumericValue)1 ValueSequence (org.exist.xquery.value.ValueSequence)1