All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.exist.xquery.WhereClause Maven / Gradle / Ivy

There is a newer version: 6.3.0
Show newest version
package org.exist.xquery;

import org.exist.dom.persistent.*;
import org.exist.xquery.util.ExpressionDumper;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.Type;

/**
 * Implements a where clause inside a FLWOR expressions.
 *
 * @author wolf
 */
public class WhereClause extends AbstractFLWORClause {

    protected Expression whereExpr;
    protected boolean fastTrack = false;

    public WhereClause(XQueryContext context, Expression whereExpr) {
        super(context);
        this.whereExpr = whereExpr;
    }

    @Override
    public ClauseType getType() {
        return ClauseType.WHERE;
    }

    public Expression getWhereExpr() {
        return whereExpr;
    }

    @Override
    public void analyze(AnalyzeContextInfo contextInfo) throws XPathException {
        contextInfo.setParent(this);
        AnalyzeContextInfo newContextInfo = new AnalyzeContextInfo(contextInfo);
        newContextInfo.setFlags(contextInfo.getFlags() | IN_PREDICATE | IN_WHERE_CLAUSE);
        newContextInfo.setContextId(getExpressionId());
        whereExpr.analyze(newContextInfo);

        newContextInfo = new AnalyzeContextInfo(contextInfo);
        newContextInfo.addFlag(SINGLE_STEP_EXECUTION);
        returnExpr.analyze(newContextInfo);
    }

    @Override
    public Sequence preEval(Sequence in) throws XPathException {
        if (in != null && Type.subTypeOf(in.getItemType(), Type.NODE) &&
                in.isPersistentSet() &&
                !Dependency.dependsOn(whereExpr, Dependency.CONTEXT_ITEM) &&
                //We might not be sure of the return type at this level
                Type.subTypeOf(whereExpr.returnsType(), Type.ITEM)) {
            if (!in.isCached()) {
                BindingExpression.setContext(getExpressionId(), in);
            }
            try {
                final Sequence seq = in.isEmpty() ? in : whereExpr.eval(in);
                //But *now*, we are ;-)
                if (Type.subTypeOf(whereExpr.returnsType(), Type.NODE)) {
                    final NodeSet nodes = seq.toNodeSet();
                    // if the where expression returns a node set, check the context
                    // node of each node in the set
                    final NodeSet contextSet = in.toNodeSet();
                    final boolean contextIsVirtual = contextSet instanceof VirtualNodeSet;
                    final NodeSet result = new ExtArrayNodeSet();
                    DocumentImpl lastDoc = null;

                    for (final NodeProxy current : nodes) {
                        int sizeHint = Constants.NO_SIZE_HINT;
                        if (lastDoc == null || current.getOwnerDocument() != lastDoc) {
                            lastDoc = current.getOwnerDocument();
                            sizeHint = nodes.getSizeHint(lastDoc);
                        }
                        ContextItem context = current.getContext();
                        if (context == null) {
                            throw new XPathException(this, "Internal evaluation error: context node is missing for node " +
                                    current.getNodeId() + "!");
                        }
                        //				LOG.debug(current.debugContext());
                        while (context != null) {
                            //TODO : Is this the context we want ? Not sure... would have prefered the LetExpr.
                            if (context.getContextId() == whereExpr.getContextId()) {
                                final NodeProxy contextNode = context.getNode();
                                if (contextIsVirtual || contextSet.contains(contextNode)) {
                                    contextNode.addMatches(current);
                                    result.add(contextNode, sizeHint);
                                }
                            }
                            context = context.getNextDirect();
                        }
                    }
                    fastTrack = true;
                    return result;
                }
            } finally {
                if (!in.isCached()) {
                    BindingExpression.clearContext(getExpressionId(), in);
                }
            }
        }
        return super.preEval(in);
    }

    @Override
    public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
        if (applyWhereExpression()) {
            return returnExpr.eval(null);
        }
        return Sequence.EMPTY_SEQUENCE;
    }

    @Override
    public Sequence postEval(Sequence seq) throws XPathException {
        fastTrack = false;
        if (returnExpr instanceof FLWORClause) {
            seq = ((FLWORClause) returnExpr).postEval(seq);
        }
        return super.postEval(seq);
    }

    private boolean applyWhereExpression() throws XPathException {
        if (fastTrack) {
            return true;
        }
        final Sequence innerSeq = whereExpr.eval(null);
        return innerSeq.effectiveBooleanValue();
    }

    @Override
    public void dump(ExpressionDumper dumper) {
        dumper.display("where", whereExpr.getLine());
        dumper.startIndent();
        whereExpr.dump(dumper);
        dumper.endIndent().nl();
    }

    @Override
    public void resetState(boolean postOptimization) {
        super.resetState(postOptimization);
        whereExpr.resetState(postOptimization);
        returnExpr.resetState(postOptimization);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy