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);
}
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);
}
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;
}
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;
}
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;
}
Aggregations