Search in sources :

Example 6 with Sequence

use of org.exist.xquery.value.Sequence 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 7 with Sequence

use of org.exist.xquery.value.Sequence in project exist by eXist-db.

the class GeneralComparison method eval.

/* (non-Javadoc)
     * @see org.exist.xquery.Expression#eval(org.exist.xquery.StaticContext, org.exist.dom.persistent.DocumentSet, org.exist.xquery.value.Sequence, org.exist.xquery.value.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());
        }
    }
    Sequence result;
    // if the context sequence hasn't changed we can return a cached result
    if ((cached != null) && cached.isValid(contextSequence, contextItem)) {
        LOG.debug("Using cached results");
        if (context.getProfiler().isEnabled()) {
            context.getProfiler().message(this, Profiler.OPTIMIZATIONS, "OPTIMIZATION", "Returned cached result");
        }
        result = cached.getResult();
    } else {
        // we won't have any matches and can return
        if ((preselectResult != null) && preselectResult.isEmpty()) {
            result = Sequence.EMPTY_SEQUENCE;
        } else {
            if ((contextStep == null) || (preselectResult == null)) {
                /*
                     * If we are inside a predicate and one of the arguments is a node set,
                     * we try to speed up the query by returning nodes from the context set.
                     * This works only inside a predicate. The node set will always be the left
                     * operand.
                     */
                if (inPredicate && !invalidNodeEvaluation && !Dependency.dependsOn(this, Dependency.CONTEXT_ITEM) && Type.subTypeOf(getLeft().returnsType(), Type.NODE) && ((contextSequence == null) || contextSequence.isPersistentSet())) {
                    if (contextItem != null) {
                        contextSequence = contextItem.toSequence();
                    }
                    if ((!Dependency.dependsOn(rightOpDeps, Dependency.CONTEXT_ITEM))) {
                        result = quickNodeSetCompare(contextSequence);
                    } else {
                        final NodeSet nodes = (NodeSet) getLeft().eval(contextSequence);
                        result = nodeSetCompare(nodes, contextSequence);
                    }
                } else {
                    result = genericCompare(contextSequence, contextItem);
                }
            } else {
                contextStep.setPreloadedData(preselectResult.getDocumentSet(), preselectResult);
                result = getLeft().eval(contextSequence).toNodeSet();
                // the expression can be called multiple times, so we need to clear the previous preselectResult
                preselectResult = null;
            }
        }
        // can this result be cached? Don't cache if the result depends on local variables.
        final boolean canCache = (contextSequence != null) && contextSequence.isCacheable() && !Dependency.dependsOn(getLeft(), Dependency.CONTEXT_ITEM) && !Dependency.dependsOn(getRight(), Dependency.CONTEXT_ITEM) && !Dependency.dependsOnVar(getLeft()) && !Dependency.dependsOnVar(getRight());
        if (canCache) {
            cached = new CachedResult(contextSequence, contextItem, result);
        }
    }
    if (context.getProfiler().isEnabled()) {
        context.getProfiler().end(this, "", result);
    }
    actualReturnType = result.getItemType();
    return (result);
}
Also used : NodeSet(org.exist.dom.persistent.NodeSet) VirtualNodeSet(org.exist.dom.persistent.VirtualNodeSet) NewArrayNodeSet(org.exist.dom.persistent.NewArrayNodeSet) Sequence(org.exist.xquery.value.Sequence)

Example 8 with Sequence

use of org.exist.xquery.value.Sequence in project exist by eXist-db.

the class JavaCall method eval.

/* (non-Javadoc)
	 * @see org.exist.xquery.Expression#eval(org.exist.xquery.value.Sequence, org.exist.xquery.value.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());
        }
    }
    // get the actual arguments
    final Sequence[] args = getArguments(contextSequence, contextItem);
    AccessibleObject bestMethod = candidateMethods.get(0);
    int[] conversionPrefs = getConversionPreferences(bestMethod, args);
    for (AccessibleObject nextMethod : candidateMethods) {
        int[] prefs = getConversionPreferences(nextMethod, args);
        for (int j = 0; j < prefs.length; j++) {
            if (prefs[j] < conversionPrefs[j]) {
                bestMethod = nextMethod;
                conversionPrefs = prefs;
                break;
            }
        }
    }
    // LOG.debug("calling method " + bestMethod.toString());
    Class<?>[] paramTypes = null;
    boolean isStatic = true;
    if (bestMethod instanceof Constructor<?>) {
        paramTypes = ((Constructor<?>) bestMethod).getParameterTypes();
    } else {
        paramTypes = ((Method) bestMethod).getParameterTypes();
        isStatic = Modifier.isStatic(((Method) bestMethod).getModifiers());
    }
    final Object[] params = new Object[isStatic ? args.length : args.length - 1];
    if (isStatic) {
        for (int i = 0; i < args.length; i++) {
            params[i] = args[i].toJavaObject(paramTypes[i]);
        }
    } else {
        for (int i = 1; i < args.length; i++) {
            params[i - 1] = args[i].toJavaObject(paramTypes[i - 1]);
        }
    }
    Sequence result;
    if (bestMethod instanceof Constructor<?>) {
        try {
            final Object object = ((Constructor<?>) bestMethod).newInstance(params);
            result = new JavaObjectValue(object);
        } catch (final IllegalArgumentException e) {
            throw new XPathException(this, "illegal argument to constructor " + bestMethod.toString() + ": " + e.getMessage(), e);
        } catch (final Exception e) {
            if (e instanceof XPathException) {
                throw (XPathException) e;
            } else {
                throw new XPathException(this, "exception while calling constructor " + bestMethod.toString() + ": " + e.getMessage(), e);
            }
        }
    } else {
        try {
            Object invocationResult;
            if (isStatic) {
                invocationResult = ((Method) bestMethod).invoke(null, params);
            } else {
                invocationResult = ((Method) bestMethod).invoke(args[0].toJavaObject(myClass), params);
            }
            result = XPathUtil.javaObjectToXPath(invocationResult, getContext());
        } catch (final IllegalArgumentException e) {
            throw new XPathException(this, "illegal argument to method " + bestMethod.toString() + ": " + e.getMessage(), e);
        } catch (final Exception e) {
            if (e instanceof XPathException) {
                throw (XPathException) e;
            } else {
                throw new XPathException(this, "exception while calling method " + bestMethod.toString() + ": " + e.getMessage(), e);
            }
        }
    }
    if (context.getProfiler().isEnabled()) {
        context.getProfiler().end(this, "", result);
    }
    if (result == null) {
        result = Sequence.EMPTY_SEQUENCE;
    }
    return result;
}
Also used : Constructor(java.lang.reflect.Constructor) Sequence(org.exist.xquery.value.Sequence) Method(java.lang.reflect.Method) AccessibleObject(java.lang.reflect.AccessibleObject) AccessibleObject(java.lang.reflect.AccessibleObject) JavaObjectValue(org.exist.xquery.value.JavaObjectValue)

Example 9 with Sequence

use of org.exist.xquery.value.Sequence in project exist by eXist-db.

the class OpNumeric 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());
        }
    }
    final Sequence lseq = Atomize.atomize(getLeft().eval(contextSequence, contextItem));
    final Sequence rseq = Atomize.atomize(getRight().eval(contextSequence, contextItem));
    if (lseq.hasMany()) {
        throw new XPathException(this, ErrorCodes.XPTY0004, "Too many operands at the left of " + operator.symbol);
    }
    if (rseq.hasMany()) {
        throw new XPathException(this, ErrorCodes.XPTY0004, "Too many operands at the right of " + operator.symbol);
    }
    Sequence result;
    if (rseq.isEmpty()) {
        result = Sequence.EMPTY_SEQUENCE;
    } else if (lseq.isEmpty()) {
        result = Sequence.EMPTY_SEQUENCE;
    } else {
        Item lvalue = lseq.itemAt(0);
        Item rvalue = rseq.itemAt(0);
        try {
            if (lvalue.getType() == Type.UNTYPED_ATOMIC || lvalue.getType() == Type.ATOMIC) {
                lvalue = lvalue.convertTo(Type.NUMBER);
            }
            if (rvalue.getType() == Type.UNTYPED_ATOMIC || rvalue.getType() == Type.ATOMIC) {
                rvalue = rvalue.convertTo(Type.NUMBER);
            }
            if (!(lvalue instanceof ComputableValue)) {
                throw new XPathException(this, ErrorCodes.XPTY0004, "'" + Type.getTypeName(lvalue.getType()) + "(" + lvalue + ")' can not be an operand for " + operator.symbol);
            }
            if (!(rvalue instanceof ComputableValue)) {
                throw new XPathException(this, ErrorCodes.XPTY0004, "'" + Type.getTypeName(rvalue.getType()) + "(" + rvalue + ")' can not be an operand for " + operator.symbol);
            }
            // TODO : move to implementations
            if (operator == ArithmeticOperator.DIVISION_INTEGER) {
                if (!Type.subTypeOfUnion(lvalue.getType(), Type.NUMBER)) {
                    throw new XPathException(this, ErrorCodes.XPTY0004, "'" + Type.getTypeName(lvalue.getType()) + "(" + lvalue + ")' can not be an operand for " + operator.symbol);
                }
                if (!Type.subTypeOfUnion(rvalue.getType(), Type.NUMBER)) {
                    throw new XPathException(this, ErrorCodes.XPTY0004, "'" + Type.getTypeName(rvalue.getType()) + "(" + rvalue + ")' can not be an operand for " + operator.symbol);
                }
                // If the divisor is (positive or negative) zero, then an error is raised [err:FOAR0001]
                if (((NumericValue) rvalue).isZero()) {
                    throw new XPathException(this, ErrorCodes.FOAR0001, "Division by zero");
                }
                // If either operand is NaN then an error is raised [err:FOAR0002].
                if (((NumericValue) lvalue).isNaN()) {
                    throw new XPathException(this, ErrorCodes.FOAR0002, "Division of " + Type.getTypeName(lvalue.getType()) + "(" + lvalue + ")'");
                }
                // If either operand is NaN then an error is raised [err:FOAR0002].
                if (((NumericValue) rvalue).isNaN()) {
                    throw new XPathException(this, ErrorCodes.FOAR0002, "Division of " + Type.getTypeName(rvalue.getType()) + "(" + rvalue + ")'");
                }
                // If $arg1 is INF or -INF then an error is raised [err:FOAR0002].
                if (((NumericValue) lvalue).isInfinite()) {
                    throw new XPathException(this, ErrorCodes.FOAR0002, "Division of " + Type.getTypeName(lvalue.getType()) + "(" + lvalue + ")'");
                }
                result = ((NumericValue) lvalue).idiv((NumericValue) rvalue);
            } else {
                result = applyOperator((ComputableValue) lvalue, (ComputableValue) rvalue);
            }
        // TODO : type-checks on MOD operator : maybe the same ones than above -pb
        } catch (final XPathException e) {
            e.setLocation(line, column);
            throw e;
        }
    }
    if (context.getProfiler().isEnabled()) {
        context.getProfiler().end(this, "", result);
    }
    // Sets the return type if not already set
    if (returnType == Type.ATOMIC) // TODO : refine previously set type ? -pb
    {
        returnType = result.getItemType();
    }
    return result;
}
Also used : Item(org.exist.xquery.value.Item) ComputableValue(org.exist.xquery.value.ComputableValue) Sequence(org.exist.xquery.value.Sequence) NumericValue(org.exist.xquery.value.NumericValue)

Example 10 with Sequence

use of org.exist.xquery.value.Sequence in project exist by eXist-db.

the class SimpleStep method eval.

/* (non-Javadoc)
	 * @see org.exist.xquery.Expression#eval(org.exist.dom.persistent.DocumentSet, org.exist.xquery.value.Sequence, org.exist.xquery.value.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 (contextItem != null) {
        contextSequence = contextItem.toSequence();
    }
    Sequence result = Sequence.EMPTY_SEQUENCE;
    final Sequence set = expression.eval(contextSequence);
    if (!set.isEmpty()) {
        if (set.isPersistentSet()) {
            final NodeSet nodeSet = set.toNodeSet();
            switch(axis) {
                case Constants.DESCENDANT_SELF_AXIS:
                    result = nodeSet.selectAncestorDescendant(contextSequence.toNodeSet(), NodeSet.DESCENDANT, true, contextId, true);
                    break;
                case Constants.CHILD_AXIS:
                    result = nodeSet.selectParentChild(contextSequence.toNodeSet(), NodeSet.DESCENDANT, contextId);
                    break;
                default:
                    throw new XPathException(this, "Wrong axis specified");
            }
        } else {
            final MemoryNodeSet ctxNodes = contextSequence.toMemNodeSet();
            final MemoryNodeSet nodes = set.toMemNodeSet();
            switch(axis) {
                case Constants.DESCENDANT_SELF_AXIS:
                    result = ctxNodes.selectDescendants(nodes);
                    break;
                case Constants.CHILD_AXIS:
                    result = ctxNodes.selectChildren(nodes);
                    break;
            }
        }
    }
    if (context.getProfiler().isEnabled()) {
        context.getProfiler().end(this, "", result);
    }
    return result;
}
Also used : MemoryNodeSet(org.exist.xquery.value.MemoryNodeSet) NodeSet(org.exist.dom.persistent.NodeSet) MemoryNodeSet(org.exist.xquery.value.MemoryNodeSet) Sequence(org.exist.xquery.value.Sequence)

Aggregations

Sequence (org.exist.xquery.value.Sequence)427 DBBroker (org.exist.storage.DBBroker)179 BrokerPool (org.exist.storage.BrokerPool)158 Test (org.junit.Test)114 XQuery (org.exist.xquery.XQuery)108 XPathException (org.exist.xquery.XPathException)86 Txn (org.exist.storage.txn.Txn)81 Item (org.exist.xquery.value.Item)68 ValueSequence (org.exist.xquery.value.ValueSequence)55 StringValue (org.exist.xquery.value.StringValue)49 Source (org.exist.source.Source)45 QName (org.exist.dom.QName)42 StringSource (org.exist.source.StringSource)42 SequenceIterator (org.exist.xquery.value.SequenceIterator)40 StringInputSource (org.exist.util.StringInputSource)37 CompiledXQuery (org.exist.xquery.CompiledXQuery)36 XQueryContext (org.exist.xquery.XQueryContext)35 IntegerValue (org.exist.xquery.value.IntegerValue)33 InputSource (org.xml.sax.InputSource)23 Diff (org.xmlunit.diff.Diff)21