Search in sources :

Example 1 with ComputableValue

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

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

the class FunMin 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());
        }
    }
    boolean computableProcessing = false;
    Sequence result;
    final Sequence arg = getArgument(0).eval(contextSequence, contextItem);
    if (arg.isEmpty()) {
        result = Sequence.EMPTY_SEQUENCE;
    } else {
        // TODO : test if a range index is defined *iff* it is compatible with the collator
        final Collator collator = getCollator(contextSequence, contextItem, 2);
        final SequenceIterator iter = arg.unorderedIterator();
        AtomicValue min = null;
        while (iter.hasNext()) {
            final Item item = iter.nextItem();
            if (item instanceof QNameValue) {
                throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(item.getType()), arg);
            }
            AtomicValue value = item.atomize();
            // Duration values must either all be xs:yearMonthDuration values or must all be xs:dayTimeDuration values.
            if (Type.subTypeOf(value.getType(), Type.DURATION)) {
                value = ((DurationValue) value).wrap();
                if (value.getType() == Type.YEAR_MONTH_DURATION) {
                    if (min != null && min.getType() != Type.YEAR_MONTH_DURATION) {
                        throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), value);
                    }
                } else if (value.getType() == Type.DAY_TIME_DURATION) {
                    if (min != null && min.getType() != Type.DAY_TIME_DURATION) {
                        throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), value);
                    }
                } else {
                    throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(value.getType()), value);
                }
            // Any value of type xdt:untypedAtomic is cast to xs:double
            } else if (value.getType() == Type.UNTYPED_ATOMIC) {
                value = value.convertTo(Type.DOUBLE);
            }
            if (min == null) {
                min = value;
            } else {
                if (Type.getCommonSuperType(min.getType(), value.getType()) == Type.ATOMIC) {
                    throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), value);
                }
                // Any value of type xdt:untypedAtomic is cast to xs:double
                if (value.getType() == Type.ATOMIC) {
                    value = value.convertTo(Type.DOUBLE);
                }
                // Numeric tests
                if (Type.subTypeOfUnion(value.getType(), Type.NUMBER)) {
                    // Don't mix comparisons
                    if (!Type.subTypeOfUnion(min.getType(), Type.NUMBER)) {
                        throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), min);
                    }
                    if (((NumericValue) value).isNaN()) {
                        // Type NaN correctly
                        value = value.promote(min);
                        if (value.getType() == Type.FLOAT) {
                            min = FloatValue.NaN;
                        } else {
                            min = DoubleValue.NaN;
                        }
                        // although result will be NaN, we need to continue on order to type correctly
                        continue;
                    }
                    min = min.promote(value);
                }
                // Ugly test
                if (value instanceof ComputableValue) {
                    if (!(min instanceof ComputableValue)) {
                        throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), min);
                    }
                    // Type value correctly
                    value = value.promote(min);
                    min = min.min(collator, value);
                    computableProcessing = true;
                } else {
                    if (computableProcessing) {
                        throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), value);
                    }
                    if (Collations.compare(collator, value.getStringValue(), min.getStringValue()) < 0) {
                        min = value;
                    }
                }
            }
        }
        result = min;
    }
    if (context.getProfiler().isEnabled()) {
        context.getProfiler().end(this, "", result);
    }
    return result;
}
Also used : Item(org.exist.xquery.value.Item) ComputableValue(org.exist.xquery.value.ComputableValue) SequenceIterator(org.exist.xquery.value.SequenceIterator) XPathException(org.exist.xquery.XPathException) QNameValue(org.exist.xquery.value.QNameValue) AtomicValue(org.exist.xquery.value.AtomicValue) Sequence(org.exist.xquery.value.Sequence) NumericValue(org.exist.xquery.value.NumericValue) Collator(com.ibm.icu.text.Collator)

Example 3 with ComputableValue

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

the class FunAvg 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());
        }
    }
    Sequence result;
    final Sequence inner = getArgument(0).eval(contextSequence, contextItem);
    if (inner.isEmpty()) {
        result = Sequence.EMPTY_SEQUENCE;
    } else {
        final SequenceIterator iter = inner.iterate();
        Item item = iter.nextItem();
        AtomicValue value = item.atomize();
        // Any values of type xdt:untypedAtomic are cast to xs:double
        if (value.getType() == Type.UNTYPED_ATOMIC) {
            value = value.convertTo(Type.DOUBLE);
        }
        if (!(value instanceof ComputableValue)) {
            throw new XPathException(this, ErrorCodes.FORG0006, Type.getTypeName(value.getType()) + "(" + value + ") " + "can not be an operand in a sum", value);
        }
        // Set the first value
        ComputableValue sum = (ComputableValue) value;
        while (iter.hasNext()) {
            item = iter.nextItem();
            value = item.atomize();
            // Any value of type xdt:untypedAtomic are cast to xs:double
            if (value.getType() == Type.UNTYPED_ATOMIC) {
                value = value.convertTo(Type.DOUBLE);
            }
            if (!(value instanceof ComputableValue)) {
                throw new XPathException(this, ErrorCodes.FORG0006, "" + Type.getTypeName(value.getType()) + "(" + value + ") can not be an operand in a sum", value);
            }
            if (Type.subTypeOfUnion(value.getType(), Type.NUMBER)) {
                if (((NumericValue) value).isInfinite()) {
                    gotInfinity = true;
                }
                if (((NumericValue) value).isNaN()) {
                    sum = DoubleValue.NaN;
                    break;
                }
            }
            try {
                sum = (ComputableValue) sum.promote(value);
                // Aggregate next values
                sum = sum.plus((ComputableValue) value);
            } catch (final XPathException e) {
                throw new XPathException(this, ErrorCodes.FORG0006, e.getMessage());
            }
        }
        result = sum.div(new IntegerValue(inner.getItemCount()));
    }
    if (!gotInfinity) {
        if (Type.subTypeOfUnion(result.getItemType(), Type.NUMBER) && ((NumericValue) result).isInfinite()) {
        // Throw an overflow exception here since we get an infinity
        // whereas is hasn't been provided by the sequence
        // TODO ? -pb
        }
    }
    if (context.getProfiler().isEnabled()) {
        context.getProfiler().end(this, "", result);
    }
    return result;
}
Also used : Item(org.exist.xquery.value.Item) ComputableValue(org.exist.xquery.value.ComputableValue) SequenceIterator(org.exist.xquery.value.SequenceIterator) XPathException(org.exist.xquery.XPathException) IntegerValue(org.exist.xquery.value.IntegerValue) AtomicValue(org.exist.xquery.value.AtomicValue) Sequence(org.exist.xquery.value.Sequence) NumericValue(org.exist.xquery.value.NumericValue)

Example 4 with ComputableValue

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

the class FunSum 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());
        }
    }
    Sequence result;
    final Sequence inner = getArgument(0).eval(contextSequence, contextItem);
    if (inner.isEmpty()) {
        // If $zero is not specified, then the value returned for an empty sequence is the xs:integer value 0
        Sequence zero = IntegerValue.ZERO;
        if (getSignature().getArgumentCount() == 2) {
            zero = getArgument(1).eval(contextSequence, contextItem);
        }
        result = zero;
    } else {
        final SequenceIterator iter = inner.iterate();
        Item item = iter.nextItem();
        AtomicValue value = item.atomize();
        value = check(value, null);
        // Set the first value
        ComputableValue sum = (ComputableValue) value;
        while (iter.hasNext()) {
            item = iter.nextItem();
            value = item.atomize();
            value = check(value, sum);
            if (Type.subTypeOfUnion(value.getType(), Type.NUMBER)) {
                if (((NumericValue) value).isInfinite()) {
                    gotInfinity = true;
                }
                if (((NumericValue) value).isNaN()) {
                    sum = DoubleValue.NaN;
                    break;
                }
            }
            sum = (ComputableValue) sum.promote(value);
            // Aggregate next values
            sum = sum.plus((ComputableValue) value);
        }
        result = sum;
    }
    if (!gotInfinity) {
        if (Type.subTypeOfUnion(result.getItemType(), Type.NUMBER) && ((NumericValue) result).isInfinite()) {
        // Throw an overflow eception here since we get an infinity
        // whereas is hasn't been provided by the sequence
        }
    }
    if (context.getProfiler().isEnabled()) {
        context.getProfiler().end(this, "", result);
    }
    return result;
}
Also used : Item(org.exist.xquery.value.Item) ComputableValue(org.exist.xquery.value.ComputableValue) SequenceIterator(org.exist.xquery.value.SequenceIterator) AtomicValue(org.exist.xquery.value.AtomicValue) Sequence(org.exist.xquery.value.Sequence) NumericValue(org.exist.xquery.value.NumericValue)

Example 5 with ComputableValue

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

the class FunMax 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());
        }
    }
    Sequence result;
    final Sequence arg = getArgument(0).eval(contextSequence, contextItem);
    if (arg.isEmpty()) {
        result = Sequence.EMPTY_SEQUENCE;
    } else {
        boolean computableProcessing = false;
        // TODO : test if a range index is defined *iff* it is compatible with the collator
        final Collator collator = getCollator(contextSequence, contextItem, 2);
        final SequenceIterator iter = arg.unorderedIterator();
        AtomicValue max = null;
        while (iter.hasNext()) {
            final Item item = iter.nextItem();
            if (item instanceof QNameValue) {
                throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(item.getType()), arg);
            }
            AtomicValue value = item.atomize();
            // Duration values must either all be xs:yearMonthDuration values or must all be xs:dayTimeDuration values.
            if (Type.subTypeOf(value.getType(), Type.DURATION)) {
                value = ((DurationValue) value).wrap();
                if (value.getType() == Type.YEAR_MONTH_DURATION) {
                    if (max != null && max.getType() != Type.YEAR_MONTH_DURATION) {
                        throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(max.getType()) + " and " + Type.getTypeName(value.getType()), value);
                    }
                } else if (value.getType() == Type.DAY_TIME_DURATION) {
                    if (max != null && max.getType() != Type.DAY_TIME_DURATION) {
                        throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(max.getType()) + " and " + Type.getTypeName(value.getType()), value);
                    }
                } else {
                    throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(value.getType()), value);
                }
            // Any value of type xdt:untypedAtomic is cast to xs:double
            } else if (value.getType() == Type.UNTYPED_ATOMIC) {
                value = value.convertTo(Type.DOUBLE);
            }
            if (max == null) {
                max = value;
            } else {
                if (Type.getCommonSuperType(max.getType(), value.getType()) == Type.ATOMIC) {
                    throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(max.getType()) + " and " + Type.getTypeName(value.getType()), max);
                }
                // Any value of type xdt:untypedAtomic is cast to xs:double
                if (value.getType() == Type.UNTYPED_ATOMIC) {
                    value = value.convertTo(Type.DOUBLE);
                }
                // Numeric tests
                if (Type.subTypeOfUnion(value.getType(), Type.NUMBER)) {
                    // Don't mix comparisons
                    if (!Type.subTypeOfUnion(max.getType(), Type.NUMBER)) {
                        throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(max.getType()) + " and " + Type.getTypeName(value.getType()), max);
                    }
                    if (((NumericValue) value).isNaN()) {
                        // Type NaN correctly
                        value = value.promote(max);
                        if (value.getType() == Type.FLOAT) {
                            max = FloatValue.NaN;
                        } else {
                            max = DoubleValue.NaN;
                        }
                        // although result will be NaN, we need to continue on order to type correctly
                        continue;
                    } else {
                        max = max.promote(value);
                    }
                }
                // Ugly test
                if (max instanceof ComputableValue && value instanceof ComputableValue) {
                    // Type value correctly
                    value = value.promote(max);
                    max = (ComputableValue) max.max(collator, value);
                    computableProcessing = true;
                } else {
                    if (computableProcessing) {
                        throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(max.getType()) + " and " + Type.getTypeName(value.getType()), max);
                    }
                    if (Collations.compare(collator, value.getStringValue(), max.getStringValue()) > 0) {
                        max = value;
                    }
                }
            }
        }
        result = max;
    }
    if (context.getProfiler().isEnabled()) {
        context.getProfiler().end(this, "", result);
    }
    return result;
}
Also used : Item(org.exist.xquery.value.Item) ComputableValue(org.exist.xquery.value.ComputableValue) SequenceIterator(org.exist.xquery.value.SequenceIterator) XPathException(org.exist.xquery.XPathException) QNameValue(org.exist.xquery.value.QNameValue) AtomicValue(org.exist.xquery.value.AtomicValue) Sequence(org.exist.xquery.value.Sequence) NumericValue(org.exist.xquery.value.NumericValue) Collator(com.ibm.icu.text.Collator)

Aggregations

ComputableValue (org.exist.xquery.value.ComputableValue)5 Item (org.exist.xquery.value.Item)5 NumericValue (org.exist.xquery.value.NumericValue)5 Sequence (org.exist.xquery.value.Sequence)5 AtomicValue (org.exist.xquery.value.AtomicValue)4 SequenceIterator (org.exist.xquery.value.SequenceIterator)4 XPathException (org.exist.xquery.XPathException)3 Collator (com.ibm.icu.text.Collator)2 QNameValue (org.exist.xquery.value.QNameValue)2 IntegerValue (org.exist.xquery.value.IntegerValue)1