Package org.exist.xquery

Source Code of org.exist.xquery.BindingExpression$ExprUpdateListener

/*
*  eXist Open Source Native XML Database
*  Copyright (C) 2001-06 Wolfgang M. Meier
*  wolfgang@exist-db.org
*  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.apache.log4j.Logger;
import org.exist.dom.ContextItem;
import org.exist.dom.DocumentImpl;
import org.exist.dom.DocumentSet;
import org.exist.dom.ExtArrayNodeSet;
import org.exist.dom.NodeProxy;
import org.exist.dom.NodeSet;
import org.exist.dom.StoredNode;
import org.exist.dom.VirtualNodeSet;
import org.exist.numbering.NodeId;
import org.exist.storage.UpdateListener;
import org.exist.xquery.value.BooleanValue;
import org.exist.xquery.value.GroupedValueSequenceTable;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceIterator;
import org.exist.xquery.value.SequenceType;
import org.exist.xquery.value.Type;
import org.exist.xquery.value.ValueSequence;

/**
* Abstract superclass for the variable binding expressions "for" and "let".
*
* @author Wolfgang Meier <wolfgang@exist-db.org>
*/
public abstract class BindingExpression extends AbstractExpression implements RewritableExpression {

  protected final static Logger LOG =
    Logger.getLogger(BindingExpression.class);

    protected final static SequenceType POSITIONAL_VAR_TYPE =
        new SequenceType(Type.INTEGER, Cardinality.EXACTLY_ONE);
   
  protected String varName;
  protected SequenceType sequenceType = null;
  protected Expression inputSequence;
  protected Expression returnExpr;
  protected Expression whereExpr;
  protected OrderSpec orderSpecs[] = null;
  protected int actualReturnType = Type.ITEM;

  /* bv : variables for group by
      group toGroupVarName as groupVarName as groupSpecs... return groupReturnExpr */
  protected GroupSpec groupSpecs[] = null;
  protected Expression groupReturnExpr;
  protected String groupVarName;
  protected String toGroupVarName;  
  private ExprUpdateListener listener;


    public BindingExpression(XQueryContext context) {
    super(context);
  }

  public void setVariable(String qname) {
    varName = qname;
  }

    public String getVariable() {
        return this.varName;
    }
   
    /**
   * Set the sequence type of the variable (as specified in the "as" clause).
   *
   * @param type
   */
  public void setSequenceType(SequenceType type) {
    this.sequenceType = type;
  }

  public void setInputSequence(Expression sequence) {
    this.inputSequence = sequence.simplify();
  }

    public Expression getInputSequence() {
        return this.inputSequence;
    }
   
    public void setReturnExpression(Expression expr) {
    this.returnExpr = expr.simplify();
  }

    public Expression getReturnExpression() {
        return this.returnExpr;
    }

    public void setWhereExpression(Expression expr) {
    this.whereExpr = expr.simplify();
  }

    public Expression getWhereExpression() {
        return this.whereExpr;
    }
   
    public void setOrderSpecs(OrderSpec specs[]) {
    this.orderSpecs = specs;
  }

    public OrderSpec[] getOrderSpecs() {
        return orderSpecs == null ? new OrderSpec[0] : orderSpecs;
    }

  public void setGroupSpecs(GroupSpec specs[]) {
    this.groupSpecs = specs;
  }

    public GroupSpec[] getGroupSpecs() {
        return groupSpecs == null ? new GroupSpec[0] : groupSpecs;
    }

  public void setGroupReturnExpr(Expression expr) {
    this.groupReturnExpr = expr;
 
 
  public void setGroupVariable(String qname) {
    groupVarName = qname;
  }

  public void setToGroupVariable(String qname) {
    toGroupVarName = qname;
  }

  /* (non-Javadoc)
     * @see org.exist.xquery.Expression#analyze(org.exist.xquery.Expression, int)
     */
    public void analyze(AnalyzeContextInfo contextInfo) throws XPathException {
        unordered = (contextInfo.getFlags() & UNORDERED) > 0;

      analyze(contextInfo, orderSpecs, groupSpecs);
    }
   

    public abstract void analyze(AnalyzeContextInfo contextInfo, OrderSpec orderBy[], GroupSpec groupBy[]) throws XPathException;
   
  /* (non-Javadoc)
   * @see org.exist.xquery.AbstractExpression#eval(org.exist.xquery.value.Sequence, org.exist.xquery.value.Item)
   */
  public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
    return eval(contextSequence, contextItem, null, null);

  }
 
  /* (non-Javadoc)
   * @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 abstract Sequence eval(Sequence contextSequence,    Item contextItem, Sequence resultSequence, GroupedValueSequenceTable groupedSequence)
    throws XPathException;

  protected Sequence applyWhereExpression(Sequence contextSequence) throws XPathException {
    if (contextSequence != null &&
        Type.subTypeOf(contextSequence.getItemType(), Type.NODE) &&
                contextSequence.isPersistentSet() &&
                //We might not be sure of the return type at this level
        Type.subTypeOf(whereExpr.returnsType(), Type.ITEM)) {
      final Sequence seq = whereExpr.eval(contextSequence);
      //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 = contextSequence.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.getDocument() != lastDoc) {
            lastDoc = current.getDocument();
            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();
          }
        }
        return result;
      }
    }
   
    if (contextSequence == null) {
      final Sequence innerSeq = whereExpr.eval(null);
      return innerSeq.effectiveBooleanValue() ? BooleanValue.TRUE : BooleanValue.FALSE;
    } else {
      // general where clause: just check the effective boolean value
      final ValueSequence result = new ValueSequence();
      int p = 0;     
      for (final SequenceIterator i = contextSequence.iterate(); i.hasNext(); p++) {
        final Item item = i.nextItem();
        context.setContextSequencePosition(p, contextSequence);
                final Sequence innerSeq = whereExpr.eval(contextSequence, item);               
        if (innerSeq.effectiveBooleanValue())
          {result.add(item);}                   
      }
      return result;
    }
  }

  /**
   * Check all order specs to see if we can process them in
   * one single step. In general, this is possible if all order
   * expressions return nodes.
   *
   * @return Whether or not the order specs can be processed in one signle step.
   */
  protected boolean checkOrderSpecs(Sequence in) {
    if (orderSpecs == null)
      {return false;}
    if (!Type.subTypeOf(in.getItemType(), Type.NODE))
      {return false;}
    for (int i = 0; i < orderSpecs.length; i++) {
      final Expression expr = orderSpecs[i].getSortExpression();
      if(!Type.subTypeOf(expr.returnsType(), Type.NODE) ||
          Dependency.dependsOn(expr, Dependency.CONTEXT_ITEM ))
        {return false;}
    }
    return true;
  }
 
  /* (non-Javadoc)
   * @see org.exist.xquery.Expression#preselect(org.exist.dom.DocumentSet, org.exist.xquery.StaticContext)
   */
  public DocumentSet preselect(DocumentSet in_docs) throws XPathException {
    return in_docs;
  }

  /* (non-Javadoc)
   * @see org.exist.xquery.AbstractExpression#resetState()
   */
  public void resetState(boolean postOptimization) {
    super.resetState(postOptimization);
    inputSequence.resetState(postOptimization);
    if(whereExpr != null) {whereExpr.resetState(postOptimization);}
    returnExpr.resetState(postOptimization);
    if(orderSpecs != null) {
        for(int i = 0; i < orderSpecs.length; i++) {
            orderSpecs[i].resetState(postOptimization);
        }
    }
  }
 
  protected final static void setContext(int contextId, Sequence seq) throws XPathException {
    if (seq instanceof VirtualNodeSet) {
      ((VirtualNodeSet)seq).setInPredicate(true);
            ((VirtualNodeSet)seq).setSelfIsContext();
    } else {
      Item next;
      for (final SequenceIterator i = seq.unorderedIterator(); i.hasNext();) {
        next = i.nextItem();
        if (next instanceof NodeProxy)
           {((NodeProxy) next).addContextNode(contextId, (NodeProxy) next);}
      }
    }
  }
 
  protected final static void clearContext(int contextId, Sequence seq) throws XPathException {
    if (seq != null && !(seq instanceof VirtualNodeSet)) {
            seq.clearContext(contextId);
    }
  }

    protected void registerUpdateListener(final Sequence sequence) {
        if (listener == null) {
            listener = new ExprUpdateListener(sequence);
            context.registerUpdateListener(listener);
        } else
            {listener.setSequence(sequence);}
    }

    private class ExprUpdateListener implements UpdateListener {
        private Sequence sequence;

        public ExprUpdateListener(Sequence sequence) {
            this.sequence = sequence;
        }

        public void setSequence(Sequence sequence) {
            this.sequence = sequence;
        }
       
        public void documentUpdated(DocumentImpl document, int event) {
        }

        public void nodeMoved(NodeId oldNodeId, StoredNode newNode) {
            sequence.nodeMoved(oldNodeId, newNode);
        }

        public void unsubscribe() {
            BindingExpression.this.listener = null;
        }

        public void debug() {
        }
    }
   
  public int getDependencies() {
    return returnExpr.getDependencies();
  }
 
  /* RewritableExpression API */
 
  @Override
  public void replace(Expression oldExpr, Expression newExpr) {
    if (inputSequence == oldExpr)
      {inputSequence = newExpr;}
    else if (whereExpr == oldExpr)
      {whereExpr = newExpr;}
    else if (returnExpr == oldExpr)
      {returnExpr = newExpr;}
        else {
            for (OrderSpec orderSpec: getOrderSpecs()) {
                orderSpec.replace(oldExpr, newExpr);
            }
            for (GroupSpec groupSpec: getGroupSpecs()) {
                groupSpec.replace(oldExpr, newExpr);
            }
        }
  }
 
  @Override
  public Expression getPrevious(Expression current) {
    return null;
  }
 
  @Override
  public Expression getFirst() {
    return null;
  }
 
  @Override
  public void remove(Expression oldExpr) throws XPathException {
  }
 
  /* END RewritableExpression API */
TOP

Related Classes of org.exist.xquery.BindingExpression$ExprUpdateListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.