use of org.exist.dom.persistent.NodeSet in project exist by eXist-db.
the class XQueryTrigger method finish.
private void finish(int event, DBBroker broker, Txn transaction, XmldbURI src, XmldbURI dst, boolean isCollection) {
// get the query
final Source query = getQuerySource(broker);
if (query == null) {
return;
}
// avoid infinite recursion by allowing just one trigger per thread
if (!TriggerStatePerThread.verifyUniqueTriggerPerThreadBeforeFinish(this, src)) {
return;
}
final XQueryContext context = new XQueryContext(broker.getBrokerPool());
CompiledXQuery compiledQuery = null;
try {
// compile the XQuery
compiledQuery = service.compile(context, query);
// declare external variables
context.declareVariable(bindingPrefix + "type", EVENT_TYPE_FINISH);
context.declareVariable(bindingPrefix + "event", new StringValue(eventToString(event)));
if (isCollection) {
context.declareVariable(bindingPrefix + "collection", new AnyURIValue(src));
} else {
context.declareVariable(bindingPrefix + "collection", new AnyURIValue(src.removeLastSegment()));
}
context.declareVariable(bindingPrefix + "uri", new AnyURIValue(src));
if (dst == null) {
context.declareVariable(bindingPrefix + "new-uri", Sequence.EMPTY_SEQUENCE);
} else {
context.declareVariable(bindingPrefix + "new-uri", new AnyURIValue(dst));
}
// For backward compatibility
context.declareVariable(bindingPrefix + "eventType", EVENT_TYPE_FINISH);
context.declareVariable(bindingPrefix + "triggerEvent", new StringValue(eventToString(event)));
if (isCollection) {
context.declareVariable(bindingPrefix + "collectionName", new AnyURIValue(src));
} else {
context.declareVariable(bindingPrefix + "collectionName", new AnyURIValue(src.removeLastSegment()));
context.declareVariable(bindingPrefix + "documentName", new AnyURIValue(src));
}
// declare user defined parameters as external variables
for (Object o : userDefinedVariables.keySet()) {
final String varName = (String) o;
final String varValue = userDefinedVariables.getProperty(varName);
context.declareVariable(bindingPrefix + varName, new StringValue(varValue));
}
} catch (final XPathException | IOException | PermissionDeniedException e) {
// Should never be reached
LOG.error(e);
}
// execute the XQuery
try {
// TODO : should we provide another contextSet ?
final NodeSet contextSet = NodeSet.EMPTY_SET;
service.execute(broker, compiledQuery, contextSet);
// TODO : should we have a special processing ?
} catch (final XPathException e) {
// Should never be reached
LOG.error("Error during trigger finish", e);
} catch (final PermissionDeniedException e) {
// Should never be reached
LOG.error(e);
}
TriggerStatePerThread.setTriggerRunningState(TriggerStatePerThread.NO_TRIGGER_RUNNING, this, null);
TriggerStatePerThread.setTransaction(null);
LOG.debug("Trigger fired for finish");
}
use of org.exist.dom.persistent.NodeSet in project exist by eXist-db.
the class XQueryTrigger method prepare.
private void prepare(int event, DBBroker broker, Txn transaction, XmldbURI src, XmldbURI dst, boolean isCollection) throws TriggerException {
// get the query
final Source query = getQuerySource(broker);
if (query == null) {
return;
}
// avoid infinite recursion by allowing just one trigger per thread
if (!TriggerStatePerThread.verifyUniqueTriggerPerThreadBeforePrepare(this, src)) {
return;
}
TriggerStatePerThread.setTransaction(transaction);
final XQueryContext context = new XQueryContext(broker.getBrokerPool());
// TODO : further initialisations ?
CompiledXQuery compiledQuery;
try {
// compile the XQuery
compiledQuery = service.compile(context, query);
// declare external variables
context.declareVariable(bindingPrefix + "type", EVENT_TYPE_PREPARE);
context.declareVariable(bindingPrefix + "event", new StringValue(eventToString(event)));
if (isCollection) {
context.declareVariable(bindingPrefix + "collection", new AnyURIValue(src));
} else {
context.declareVariable(bindingPrefix + "collection", new AnyURIValue(src.removeLastSegment()));
}
context.declareVariable(bindingPrefix + "uri", new AnyURIValue(src));
if (dst == null) {
context.declareVariable(bindingPrefix + "new-uri", Sequence.EMPTY_SEQUENCE);
} else {
context.declareVariable(bindingPrefix + "new-uri", new AnyURIValue(dst));
}
// For backward compatibility
context.declareVariable(bindingPrefix + "eventType", EVENT_TYPE_PREPARE);
context.declareVariable(bindingPrefix + "triggerEvent", new StringValue(eventToString(event)));
if (isCollection) {
context.declareVariable(bindingPrefix + "collectionName", new AnyURIValue(src));
} else {
context.declareVariable(bindingPrefix + "collectionName", new AnyURIValue(src.removeLastSegment()));
context.declareVariable(bindingPrefix + "documentName", new AnyURIValue(src));
}
// declare user defined parameters as external variables
for (Object o : userDefinedVariables.keySet()) {
final String varName = (String) o;
final String varValue = userDefinedVariables.getProperty(varName);
context.declareVariable(bindingPrefix + varName, new StringValue(varValue));
}
} catch (final XPathException | IOException | PermissionDeniedException e) {
TriggerStatePerThread.setTriggerRunningState(TriggerStatePerThread.NO_TRIGGER_RUNNING, this, null);
TriggerStatePerThread.setTransaction(null);
throw new TriggerException(PREPARE_EXCEPTION_MESSAGE, e);
}
// execute the XQuery
try {
// TODO : should we provide another contextSet ?
final NodeSet contextSet = NodeSet.EMPTY_SET;
service.execute(broker, compiledQuery, contextSet);
// TODO : should we have a special processing ?
LOG.debug("Trigger fired for prepare");
} catch (final XPathException | PermissionDeniedException e) {
TriggerStatePerThread.setTriggerRunningState(TriggerStatePerThread.NO_TRIGGER_RUNNING, this, null);
TriggerStatePerThread.setTransaction(null);
throw new TriggerException(PREPARE_EXCEPTION_MESSAGE, e);
}
}
use of org.exist.dom.persistent.NodeSet 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;
}
}
use of org.exist.dom.persistent.NodeSet 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.dom.persistent.NodeSet 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);
}
Aggregations