<commit_before>/*
 *  eXist Open Source Native XML Database
 *  Copyright (C) 2001-03 <NAME>
 *  <EMAIL>
 *  http://exist.sourceforge.net
 *  
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *  
 *  $Id$
 */
package org.exist.xquery;

import org.exist.dom.DocumentSet;
import org.exist.dom.NodeProxy;
import org.exist.dom.NodeSet;
import org.exist.dom.QName;
import org.exist.xquery.util.ExpressionDumper;
import org.exist.xquery.value.IntegerValue;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.OrderedValueSequence;
import org.exist.xquery.value.PreorderedValueSequence;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceIterator;
import org.exist.xquery.value.Type;
import org.exist.xquery.value.ValueSequence;

/**
 * Represents an XQuery "for" expression.
 * 
 * @author <NAME> <<EMAIL>>
 */
public class ForExpr extends BindingExpression {

	private String positionalVariable = null;
	
	public ForExpr(XQueryContext context) {
		super(context);
	}

	/**
	 * A "for" expression may have an optional positional variable whose
	 * QName can be set via this method.
	 * 
	 * @param var
	 */
	public void setPositionalVariable(String var) {
		positionalVariable = var;
	}
	
	/* (non-Javadoc)
     * @see org.exist.xquery.Expression#analyze(org.exist.xquery.Expression)
     */
    public void analyze(Expression parent, int flags, OrderSpec orderBy[]) throws XPathException {
        // Save the local variable stack
		LocalVariable mark = context.markLocalVariables(false);
		
		inputSequence.analyze(this, flags);
		
		// Declare the iteration variable
        LocalVariable inVar = new LocalVariable(QName.parse(context, varName, null));
        inVar.setSequenceType(sequenceType);
		context.declareVariable(inVar);
		
		// Declare positional variable
		if(positionalVariable != null) {
			LocalVariable posVar = new LocalVariable(QName.parse(context, positionalVariable, null));
            posVar.setSequenceType(POSITIONAL_VAR_TYPE);
            context.declareVariable(posVar);
        }
        
		if(whereExpr != null) {
		    whereExpr.analyze(this, flags | IN_PREDICATE | IN_WHERE_CLAUSE);
		}
		// the order by specs should be analyzed by the last binding expression
		// in the chain to have access to all variables. So if the return expression
		// is another binding expression, we just forward the order specs.
		if(returnExpr instanceof BindingExpression) {
		    ((BindingExpression)returnExpr).analyze(this, flags | SINGLE_STEP_EXECUTION, orderBy);
		} else {
		    // analyze the order specs
			if(orderBy != null) {
			    for(int i = 0; i < orderBy.length; i++)
			        orderBy[i].analyze(this, flags | SINGLE_STEP_EXECUTION);
			}
			returnExpr.analyze(this, flags);
		}
		
		// restore the local variable stack
		context.popLocalVariables(mark);
    }
    
	/**
	 * This implementation tries to process the "where" clause in advance, i.e. in one single
	 * step. This is possible if the input sequence is a node set and the where expression
	 * has no dependencies on other variables than those declared in this "for" statement.
	 * 
	 * @see org.exist.xquery.Expression#eval(org.exist.xquery.StaticContext, org.exist.dom.DocumentSet, org.exist.xquery.value.Sequence, org.exist.xquery.value.Item)
	 */
	public Sequence eval(
		Sequence contextSequence,
		Item contextItem,
		Sequence resultSequence)
		throws XPathException {
		// Save the local variable stack
		LocalVariable mark = context.markLocalVariables(false);
		
		// Evaluate the "in" expression
		Sequence in = inputSequence.eval(null, null);
		clearContext(in);
        
		// Declare the iteration variable
		LocalVariable var = new LocalVariable(QName.parse(context, varName, null));
        var.setSequenceType(sequenceType);
		context.declareVariable(var);
		
		// Declare positional variable
		LocalVariable at = null;
		if(positionalVariable != null) {
			at = new LocalVariable(QName.parse(context, positionalVariable, null));
            at.setSequenceType(POSITIONAL_VAR_TYPE);
			context.declareVariable(at);
		}
		
		// Assign the whole input sequence to the bound variable.
		// This is required if we process the "where" or "order by" clause
		// in one step.
		var.setValue(in);
		
		// Save the current context document set to the variable as a hint
		// for path expressions occurring in the "return" clause.
		if(in instanceof NodeSet) {
		    DocumentSet contextDocs = ((NodeSet)in).getDocumentSet();
		    var.setContextDocs(contextDocs);
		}

		// Check if we can speed up the processing of the "order by" clause.
		boolean fastOrderBy = false; // checkOrderSpecs(in);
		
		// See if we can process the "where" clause in a single step (instead of
		// calling the where expression for each item in the input sequence)
		// This is possible if the input sequence is a node set and has no
		// dependencies on the current context item.
		boolean fastExec = whereExpr != null &&
			( whereExpr.getDependencies() & Dependency.CONTEXT_ITEM ) == 0 &&
			at == null &&
			in.getItemType() == Type.NODE;
		
		// If possible, apply the where expression ahead of the iteration
		if(fastExec) {
			if(!in.isCached())
				setContext(in);
			in = applyWhereExpression(in);
			if(!in.isCached())
				clearContext(in);
		}
		
		// PreorderedValueSequence applies the order specs to all items
		// in one single processing step
		if(fastOrderBy) {
			in = new PreorderedValueSequence(orderSpecs, in);
		}
		
		// Otherwise, if there's an order by clause, wrap the result into
		// an OrderedValueSequence. OrderedValueSequence will compute
		// order expressions for every item when it is added to the result sequence.
		if(resultSequence == null) {<commit_msg>Where clauses should now be optimizable again<commit_after>/*
 *  eXist Open Source Native XML Database
 *  Copyright (C) 2001-03 <NAME>
 *  <EMAIL>
 *  http://exist.sourceforge.net
 *  
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *  
 *  $Id$
 */
package org.exist.xquery;

import org.exist.dom.DocumentSet;
import org.exist.dom.NodeProxy;
import org.exist.dom.NodeSet;
import org.exist.dom.QName;
import org.exist.xquery.util.ExpressionDumper;
import org.exist.xquery.value.IntegerValue;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.OrderedValueSequence;
import org.exist.xquery.value.PreorderedValueSequence;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceIterator;
import org.exist.xquery.value.Type;
import org.exist.xquery.value.ValueSequence;

/**
 * Represents an XQuery "for" expression.
 * 
 * @author <NAME> <<EMAIL>>
 */
public class ForExpr extends BindingExpression {

	private String positionalVariable = null;
	
	public ForExpr(XQueryContext context) {
		super(context);
	}

	/**
	 * A "for" expression may have an optional positional variable whose
	 * QName can be set via this method.
	 * 
	 * @param var
	 */
	public void setPositionalVariable(String var) {
		positionalVariable = var;
	}
	
	/* (non-Javadoc)
     * @see org.exist.xquery.Expression#analyze(org.exist.xquery.Expression)
     */
    public void analyze(Expression parent, int flags, OrderSpec orderBy[]) throws XPathException {
        // Save the local variable stack
		LocalVariable mark = context.markLocalVariables(false);
		
		inputSequence.analyze(this, flags);
		
		// Declare the iteration variable
        LocalVariable inVar = new LocalVariable(QName.parse(context, varName, null));
        inVar.setSequenceType(sequenceType);
		context.declareVariable(inVar);
		
		// Declare positional variable
		if(positionalVariable != null) {
			LocalVariable posVar = new LocalVariable(QName.parse(context, positionalVariable, null));
            posVar.setSequenceType(POSITIONAL_VAR_TYPE);
            context.declareVariable(posVar);
        }
        
		if(whereExpr != null) {
		    whereExpr.analyze(this, flags | IN_PREDICATE | IN_WHERE_CLAUSE);
		}
		// the order by specs should be analyzed by the last binding expression
		// in the chain to have access to all variables. So if the return expression
		// is another binding expression, we just forward the order specs.
		if(returnExpr instanceof BindingExpression) {
		    ((BindingExpression)returnExpr).analyze(this, flags | SINGLE_STEP_EXECUTION, orderBy);
		} else {
		    // analyze the order specs
			if(orderBy != null) {
			    for(int i = 0; i < orderBy.length; i++)
			        orderBy[i].analyze(this, flags | SINGLE_STEP_EXECUTION);
			}
			returnExpr.analyze(this, flags);
		}
		
		// restore the local variable stack
		context.popLocalVariables(mark);
    }
    
	/**
	 * This implementation tries to process the "where" clause in advance, i.e. in one single
	 * step. This is possible if the input sequence is a node set and the where expression
	 * has no dependencies on other variables than those declared in this "for" statement.
	 * 
	 * @see org.exist.xquery.Expression#eval(org.exist.xquery.StaticContext, org.exist.dom.DocumentSet, org.exist.xquery.value.Sequence, org.exist.xquery.value.Item)
	 */
	public Sequence eval(
		Sequence contextSequence,
		Item contextItem,
		Sequence resultSequence)
		throws XPathException {
		// Save the local variable stack
		LocalVariable mark = context.markLocalVariables(false);
		
		// Evaluate the "in" expression
		Sequence in = inputSequence.eval(null, null);
		clearContext(in);
        
		// Declare the iteration variable
		LocalVariable var = new LocalVariable(QName.parse(context, varName, null));
        var.setSequenceType(sequenceType);
		context.declareVariable(var);
		
		// Declare positional variable
		LocalVariable at = null;
		if(positionalVariable != null) {
			at = new LocalVariable(QName.parse(context, positionalVariable, null));
            at.setSequenceType(POSITIONAL_VAR_TYPE);
			context.declareVariable(at);
		}
		
		// Assign the whole input sequence to the bound variable.
		// This is required if we process the "where" or "order by" clause
		// in one step.
		var.setValue(in);
		
		// Save the current context document set to the variable as a hint
		// for path expressions occurring in the "return" clause.
		if(in instanceof NodeSet) {
		    DocumentSet contextDocs = ((NodeSet)in).getDocumentSet();
		    var.setContextDocs(contextDocs);
		}

		// Check if we can speed up the processing of the "order by" clause.
		boolean fastOrderBy = false; // checkOrderSpecs(in);
		
		// See if we can process the "where" clause in a single step (instead of
		// calling the where expression for each item in the input sequence)
		// This is possible if the input sequence is a node set and has no
		// dependencies on the current context item.
		boolean fastExec = whereExpr != null &&
			( whereExpr.getDependencies() & Dependency.CONTEXT_ITEM ) == 0 &&
			at == null &&
			Type.subTypeOf( in.getItemType() , Type.NODE);
		
		// If possible, apply the where expression ahead of the iteration
		if(fastExec) {
			if(!in.isCached())
				setContext(in);
			in = applyWhereExpression(in);
			if(!in.isCached())
				clearContext(in);
		}
		
		// PreorderedValueSequence applies the order specs to all items
		// in one single processing step
		if(fastOrderBy) {
			in = new PreorderedValueSequence(orderSpecs, in);
		}
		
		// Otherwise, if there's an order by clause, wrap the result into
		// an OrderedValueSequence. OrderedValueSequence will compute
		// order expressions for every item when it is added to the result sequence.
		if(resultSequence == null) {
{'fraction_non_alphanumeric': 0.09262435677530018, 'fraction_numerical': 0.002650865429596133, 'mean_word_length': 3.534110993283846, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5811240', 'n_tokens_mistral': 3995, 'n_tokens_neox': 3591, 'n_words': 1241}