You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-commits@db.apache.org by mb...@apache.org on 2005/05/22 20:09:00 UTC

svn commit: r171353 [2/13] - in /incubator/jdo/trunk/query20: ./ src/ src/conf/ src/java/ src/java/org/ src/java/org/apache/ src/java/org/apache/jdo/ src/java/org/apache/jdo/impl/ src/java/org/apache/jdo/impl/jdoql/ src/java/org/apache/jdo/impl/jdoql/jdoqlc/ src/java/org/apache/jdo/impl/jdoql/scope/ src/java/org/apache/jdo/impl/jdoql/tree/ src/java/org/apache/jdo/jdoql/ src/java/org/apache/jdo/jdoql/tree/

Added: incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/MemoryQuery.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/MemoryQuery.java?rev=171353&view=auto
==============================================================================
--- incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/MemoryQuery.java (added)
+++ incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/MemoryQuery.java Sun May 22 11:08:57 2005
@@ -0,0 +1,1484 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.jdoql;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Collections;
+
+import javax.jdo.JDOHelper;
+import javax.jdo.PersistenceManager;
+
+import org.apache.jdo.impl.jdoql.scope.ParameterTable;
+import org.apache.jdo.impl.jdoql.scope.UNDEFINED;
+import org.apache.jdo.impl.jdoql.scope.VariableTable;
+import org.apache.jdo.jdoql.JDOQueryException;
+import org.apache.jdo.jdoql.tree.AbstractNodeVisitor;
+import org.apache.jdo.jdoql.tree.AndExpression;
+import org.apache.jdo.jdoql.tree.CastExpression;
+import org.apache.jdo.jdoql.tree.ComplementExpression;
+import org.apache.jdo.jdoql.tree.ConditionalAndExpression;
+import org.apache.jdo.jdoql.tree.ConditionalOrExpression;
+import org.apache.jdo.jdoql.tree.ConstantExpression;
+import org.apache.jdo.jdoql.tree.ContainsCallExpression;
+import org.apache.jdo.jdoql.tree.DivideExpression;
+import org.apache.jdo.jdoql.tree.EndsWithCallExpression;
+import org.apache.jdo.jdoql.tree.EqualsExpression;
+import org.apache.jdo.jdoql.tree.Expression;
+import org.apache.jdo.jdoql.tree.FieldAccessExpression;
+import org.apache.jdo.jdoql.tree.GreaterThanEqualsExpression;
+import org.apache.jdo.jdoql.tree.GreaterThanExpression;
+import org.apache.jdo.jdoql.tree.IsEmptyCallExpression;
+import org.apache.jdo.jdoql.tree.LessThanEqualsExpression;
+import org.apache.jdo.jdoql.tree.LessThanExpression;
+import org.apache.jdo.jdoql.tree.MinusExpression;
+import org.apache.jdo.jdoql.tree.NotEqualsExpression;
+import org.apache.jdo.jdoql.tree.NotExpression;
+import org.apache.jdo.jdoql.tree.OrExpression;
+import org.apache.jdo.jdoql.tree.OrderingExpression;
+import org.apache.jdo.jdoql.tree.ParameterAccessExpression;
+import org.apache.jdo.jdoql.tree.PlusExpression;
+import org.apache.jdo.jdoql.tree.StartsWithCallExpression;
+import org.apache.jdo.jdoql.tree.StaticFieldAccessExpression;
+import org.apache.jdo.jdoql.tree.ThisExpression;
+import org.apache.jdo.jdoql.tree.TimesExpression;
+import org.apache.jdo.jdoql.tree.TreeWalker;
+import org.apache.jdo.jdoql.tree.UnaryMinusExpression;
+import org.apache.jdo.jdoql.tree.UnaryPlusExpression;
+import org.apache.jdo.jdoql.tree.VariableAccessExpression;
+import org.apache.jdo.pm.PersistenceManagerInternal;
+import org.apache.jdo.util.I18NHelper;
+
+/**
+ * An instance of this class is used to evaluate a
+ * query tree in memory. For this purpose this class keeps references
+ * to a parameter/variable table and to the current object corresponding
+ * with a <code>ThisExpression</code>.
+ * It extends <code>AbstractNodeVisitor</code>.
+ * To evaluate a query tree, you need to pass the query tree instance and
+ * an instance of this class to method <code>walk</code> of a tree walker
+ * instance.
+ *
+ * @author Michael Watzek
+ */
+public class MemoryQuery extends AbstractNodeVisitor
+{
+    /** I18N support */
+    final static I18NHelper msg = I18NHelper.getInstance(MemoryQuery.class);
+    final static UNDEFINED  undefined = UNDEFINED.getInstance();
+
+    final TreeWalker            walker = new TreeWalker();
+    final List                  boundVariables = new ArrayList();
+    VariableAccessExpression    unboundVariableAccess = null;
+    BoundVariable               removedBoundVariable = null;
+
+    final PersistenceManagerInternal pm;
+    final ParameterTable        parameters;
+    final VariableTable         variables;
+    Object                      current;
+
+    /**
+     * Constructs an instance of this class for the specified paramter table
+     * and variable table. This query evaluator uses reflection for
+     * field accesses.
+     * @param parameters the parameter table
+     * @param variables the variable table
+     */
+    public MemoryQuery(ParameterTable parameters, VariableTable variables)
+    {   this( null, parameters, variables );
+    }
+
+    /**
+     * Constructs an instance of this class for the specified paramter table
+     * and variable table.
+     * @param pm the persistence manager
+     * @param parameters the parameter table
+     * @param variables the variable table
+     */
+    public MemoryQuery(PersistenceManagerInternal pm, ParameterTable parameters, VariableTable variables)
+    {   this.pm = pm;
+        this.parameters = parameters;
+        this.variables = variables;
+    }
+
+    /**
+     * Sets the instance returned by leaving an instance if
+     * <code>ThisExpression</code>.
+     * @param current the instance to set
+     */
+    public void setCurrent(Object current)
+    {   this.current = current;
+    }
+
+    //public methods of NodeVisitor
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the results evaluated by the node's
+     * children are non boolean types
+     */
+    public Object leave(AndExpression node, Object[] results)
+    {   Class clazz = node.getJavaClass();
+        if( clazz==Boolean.class || clazz==boolean.class )
+            return logicalAnd( results[0], results[1] );
+        throw new JDOQueryException( msg.msg("EXC_IllegalResultTypeForExpression", "&", clazz.getName()) ); //NOI18N
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the result evaluated
+     * by the child of the argument <code>node</code>. The result
+     * returned by this method is the same as the result evaluated by the child
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the result evaluated by the node's child
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the result evaluated by the node's
+     * child is not an instance of the type to cast to
+     */
+    public Object leave(CastExpression node, Object[] results)
+    {   Object value = results[1];
+        if( value==undefined )
+            return undefined;
+        Class clazz = node.getJavaClass();
+        if( value!=null &&
+            !clazz.isInstance(value) )
+        {   
+            if( clazz==Byte.class || clazz==byte.class ) {
+                if( value instanceof Character )
+                    return new Byte( (byte)((Character)value).charValue() );
+                else
+                    return new Byte( ((Number)value).byteValue() );
+            }
+            else if( clazz==Double.class || clazz==double.class ) {
+                if( value instanceof Character )
+                    return new Double( ((Character)value).charValue() );
+                else
+                    return new Double( ((Number)value).doubleValue() );
+            }
+            else if( clazz==Float.class || clazz==float.class ) {
+                if( value instanceof Character )
+                    return new Float( ((Character)value).charValue() );
+                else
+                    return new Float( ((Number)value).floatValue() );
+            }
+            else if( clazz==Integer.class || clazz==int.class ) {
+                if( value instanceof Character )
+                    return new Integer( ((Character)value).charValue() );
+                else
+                    return new Integer( ((Number)value).intValue() );
+            }
+            else if( clazz==Long.class || clazz==long.class ) {
+                if( value instanceof Character )
+                   return new Long( ((Character)value).charValue() );
+                else
+                    return new Long( ((Number)value).longValue() );
+            }
+            else if( clazz==Short.class || clazz==short.class ) {
+                if( value instanceof Character )
+                    return new Short( (short) ((Character)value).charValue() );
+                else
+                    return new Short( ((Number)value).shortValue() );
+            }
+            else if( clazz==BigInteger.class ) {
+                if( value instanceof Character )
+                   return BigInteger.valueOf( (long) ((Character)value).charValue() );
+                else
+                    return BigInteger.valueOf( ((Number)value).longValue() );
+            }
+            else if( clazz==BigDecimal.class ) {
+                if( value instanceof Character )
+                    return new BigDecimal( (double) ((Character)value).charValue() );
+                else
+                    return new BigDecimal( ((Number)value).doubleValue() );
+            }
+            else if( clazz==Character.class || clazz==char.class ) {
+                if (value instanceof Number )
+                    return new Character((char)((Number)value).intValue());
+                else
+                    return value;
+            }
+            // value is not null and is not an instance of the type
+            // specified in the cast expression => return undefined
+            return undefined;
+        }
+        return value;
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the result evaluated
+     * by the child of the argument <code>node</code>. The result
+     * returned by this method is based on the result evaluated by the child
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the result evaluated by the node's child
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the result evaluated by the node's
+     * child is not a boolean or integral type.
+     */
+    public Object leave(ComplementExpression node, Object[] results)
+    {   if( results[0]==null ||
+            results[0]==undefined )
+            return undefined;
+        Class clazz = node.getJavaClass();
+        if( clazz==Integer.class || clazz==int.class )
+            return new Integer( ~((Number)results[0]).intValue() );
+        else if( clazz==Long.class || clazz==long.class )
+            return new Long( ~((Number)results[0]).longValue() );
+        else if( clazz==BigInteger.class )
+            return ((BigInteger)results[0]).not();
+        else if( clazz==Byte.class || clazz==byte.class )
+            return new Byte( (byte) ~((Number)results[0]).byteValue() );
+        else if( clazz==Character.class || clazz==char.class )
+            return new Character( (char) ~((Character)results[0]).charValue() );
+        else if( clazz==Short.class || clazz==short.class )
+            return new Short( (short) ~((Number)results[0]).shortValue() );
+        throw new JDOQueryException( msg.msg("EXC_IllegalResultTypeForExpression", "~", clazz.getName()) ); //NOI18N
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the results evaluated by the node's
+     * children are non boolean types
+     */
+    public Object leave(ConditionalAndExpression node, Object[] results)
+    {   Class clazz = node.getJavaClass();
+        if( clazz==Boolean.class || clazz==boolean.class )
+            return logicalAnd( results[0], results[1] );
+        throw new JDOQueryException( msg.msg("EXC_IllegalResultTypeForExpression", "&&", clazz.getName()) ); //NOI18N
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the results evaluated by the node's
+     * children are non boolean types
+     */
+    public Object leave(ConditionalOrExpression node, Object[] results)
+    {   Class clazz = node.getJavaClass();
+        if( clazz==Boolean.class || clazz==boolean.class )
+            return logicalOr( results[0], results[1] );
+        throw new JDOQueryException( msg.msg("EXC_IllegalResultTypeForExpression", "||", clazz.getName()) ); //NOI18N
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> is <code>null</code> as the argument
+     * <code>node</code> does not have any children. The result
+     * returned by this method is the object wrapped by the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results <code>null</code>
+     * @return the object wrapped by node
+     */
+    public Object leave(ConstantExpression node, Object[] results)
+    {   return node.getValue();
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     */
+    public Object leave(ContainsCallExpression node, Object[] results)
+    {   if( results[0]==null ||
+            results[0]==undefined )
+        {   // bind an empty set to the variable, if collection evaluates
+            // to null or undefined, otherwise the variable access results
+            // in an exception that unbound variables are not supported.
+            if( this.unboundVariableAccess!=null )
+            {   this.boundVariables.add(  new BoundVariable(this.unboundVariableAccess.getName(), this.unboundVariableAccess.getJavaClass(), Collections.EMPTY_SET) );
+            }
+            this.unboundVariableAccess = null;
+            return undefined;
+        }
+        Collection collection = (Collection) results[0];
+        boolean result;
+        if( this.unboundVariableAccess!=null )
+        {   this.boundVariables.add(  new BoundVariable(this.unboundVariableAccess.getName(), this.unboundVariableAccess.getJavaClass(), collection) );
+            result = !collection.isEmpty();
+        }
+        else
+            result = ((Collection)results[0]).contains( results[1] );
+        this.unboundVariableAccess = null;
+        return result ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the results evaluated by the node's
+     * children are non integral types
+     */
+    public Object leave(DivideExpression node, Object[] results)
+    {   if( results[0]==null || results[1]==null ||
+            results[0]==undefined || results[1]==undefined )
+            return undefined;
+        Class clazz = node.getJavaClass();
+        if( clazz==Integer.class || clazz==int.class )
+            return new Integer( ((Number)results[0]).intValue() / ((Number)results[1]).intValue() );
+        else if( clazz==Long.class || clazz==long.class )
+            return new Long( ((Number)results[0]).longValue() / ((Number)results[1]).longValue() );
+        else if( clazz==Double.class || clazz==double.class )
+            return new Double( ((Number)results[0]).doubleValue() / ((Number)results[1]).doubleValue() );
+        else if( clazz==Float.class || clazz==float.class )
+            return new Float( ((Number)results[0]).floatValue() / ((Number)results[1]).floatValue() );
+        else if( clazz==BigDecimal.class  )
+        {   BigDecimal left, right;
+            if( results[0] instanceof BigDecimal )
+                left = (BigDecimal) results[0];
+            else
+                left = new BigDecimal( results[0].toString() );
+            if( results[1] instanceof BigDecimal )
+                right = (BigDecimal) results[1];
+            else
+                right = new BigDecimal( results[1].toString() );
+            return left.divide( right, BigDecimal.ROUND_HALF_UP );
+        }
+        else if( clazz==BigInteger.class  )
+        {   BigInteger left, right;
+            if( results[0] instanceof BigInteger )
+                left = (BigInteger) results[0];
+            else
+                left = new BigInteger( results[0].toString() );
+            if( results[1] instanceof BigInteger )
+                right = (BigInteger) results[1];
+            else
+                right = new BigInteger( results[1].toString() );
+            return left.divide( right );
+        }
+        else if( clazz==Byte.class || clazz==byte.class )
+            return new Byte( (byte) (((Number)results[0]).byteValue() / ((Number)results[1]).byteValue()) );
+        else if( clazz==Character.class || clazz==char.class )
+            return new Character( (char) (((Character)results[0]).charValue() / ((Character)results[1]).charValue()) );
+        else if( clazz==Short.class || clazz==short.class )
+            return new Short( (short) (((Number)results[0]).shortValue() / ((Number)results[1]).shortValue()) );
+        throw new JDOQueryException( msg.msg("EXC_IllegalResultTypeForExpression", "/", clazz.getName()) ); //NOI18N
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     */
+    public Object leave(EndsWithCallExpression node, Object[] results)
+    {   if( results[0]==null ||
+            results[0]==undefined )
+            return undefined;
+        boolean result = ((String)results[0]).endsWith( (String)results[1] );
+        return result ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     */
+    public Object leave(EqualsExpression node, Object[] results)
+    {   if( results[0]==undefined || results[1]==undefined )
+            return undefined;
+        boolean result;
+        if( results[0]==null && results[1]==null )
+            result = true;
+        else if( results[0]==null || results[1]==null )
+            result = false;
+        else
+        {   Class clazz = node.getCommonOperandType();
+            if( clazz==Integer.class || clazz==int.class )
+                result = ((Number)results[0]).intValue() == ((Number)results[1]).intValue();
+            else if( clazz==Long.class || clazz==long.class )
+                result = ((Number)results[0]).longValue() == ((Number)results[1]).longValue();
+            else if( clazz==Double.class || clazz==double.class )
+                result = ((Number)results[0]).doubleValue() == ((Number)results[1]).doubleValue();
+            else if( clazz==Float.class || clazz==float.class )
+                result = ((Number)results[0]).floatValue() == ((Number)results[1]).floatValue();
+            else if( clazz==BigDecimal.class  )
+            {   BigDecimal left, right;
+                if( results[0] instanceof BigDecimal )
+                    left = (BigDecimal) results[0];
+                else
+                    left = new BigDecimal( results[0].toString() );
+                if( results[1] instanceof BigDecimal )
+                    right = (BigDecimal) results[1];
+                else
+                    right = new BigDecimal( results[1].toString() );
+                result = left.compareTo( right ) == 0;
+            }
+            else if( clazz==BigInteger.class  )
+            {   BigInteger left, right;
+                if( results[0] instanceof BigInteger )
+                    left = (BigInteger) results[0];
+                else
+                    left = new BigInteger( results[0].toString() );
+                if( results[1] instanceof BigInteger )
+                    right = (BigInteger) results[1];
+                else
+                    right = new BigInteger( results[1].toString() );
+                result = left.compareTo( right ) == 0;
+            }
+            else if( Date.class.isAssignableFrom(clazz) )
+                result = ((Date)results[0]).getTime() == ((Date)results[1]).getTime();
+            else if( clazz==Byte.class || clazz==byte.class )
+                result = ((Number)results[0]).byteValue() == ((Number)results[1]).byteValue();
+            else if( clazz==Character.class || clazz==char.class )
+                result = ((Character)results[0]).charValue() == ((Character)results[1]).charValue();
+            else if( clazz==Short.class || clazz==short.class )
+                result = ((Number)results[0]).shortValue() == ((Number)results[1]).shortValue();
+            else 
+            {   PersistenceManager leftPM = JDOHelper.getPersistenceManager(results[0]);
+                PersistenceManager rightPM = JDOHelper.getPersistenceManager(results[1]);
+                if( leftPM!=null && rightPM!=null )
+                    // use == for persistence instances
+                    result = results[0] == results[1];
+                else if( leftPM==null && rightPM==null )
+                    // use equals for non persistent instances
+                    result = results[0].equals( results[1] );
+                else 
+                    // comparing persistent with non persistent instance
+                    result = false;
+            }
+        }
+        return result ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the results evaluated by the node's
+     * children is undefined
+     */
+    public Object leave(FieldAccessExpression node, Object[] results)
+    {   if( results[0]==null ||
+            results[0]==undefined )
+            return undefined;
+        return node.getFieldValue( pm, results[0] );
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the results evaluated by the node's
+     * children are non integral types
+     */
+    public Object leave(GreaterThanEqualsExpression node, Object[] results)
+    {   if( results[0]==null || results[1]==null ||
+            results[0]==undefined || results[1]==undefined )
+            return undefined;
+        boolean result;
+        Class clazz = node.getCommonOperandType();
+        if( clazz==Integer.class || clazz==int.class )
+            result = ((Number)results[0]).intValue() >= ((Number)results[1]).intValue();
+        else if( clazz==Long.class || clazz==long.class )
+            result = ((Number)results[0]).longValue() >= ((Number)results[1]).longValue();
+        else if( clazz==Double.class || clazz==double.class )
+            result = ((Number)results[0]).doubleValue() >= ((Number)results[1]).doubleValue();
+        else if( clazz==Float.class || clazz==float.class )
+            result = ((Number)results[0]).floatValue() >= ((Number)results[1]).floatValue();
+        else if( clazz==BigDecimal.class  )
+        {   BigDecimal left, right;
+            if( results[0] instanceof BigDecimal )
+                left = (BigDecimal) results[0];
+            else
+                left = new BigDecimal( results[0].toString() );
+            if( results[1] instanceof BigDecimal )
+                right = (BigDecimal) results[1];
+            else
+                right = new BigDecimal( results[1].toString() );
+            result = left.compareTo(right) >= 0;
+        }
+        else if( clazz==BigInteger.class  )
+        {   BigInteger left, right;
+            if( results[0] instanceof BigInteger )
+                left = (BigInteger) results[0];
+            else
+                left = new BigInteger( results[0].toString() );
+            if( results[1] instanceof BigInteger )
+                right = (BigInteger) results[1];
+            else
+                right = new BigInteger( results[1].toString() );
+            result = left.compareTo(right) >= 0;
+        }
+        // Comparable covers Date and String
+        else if( Comparable.class.isAssignableFrom(clazz) )
+            result = ((Comparable)results[0]).compareTo((Comparable)results[1]) >= 0;
+        else if( clazz==Byte.class || clazz==byte.class )
+            result = ((Number)results[0]).byteValue() >= ((Number)results[1]).byteValue();
+        else if( clazz==Character.class || clazz==char.class )
+            result = ((Character)results[0]).charValue() >= ((Character)results[1]).charValue();
+        else if( clazz==Short.class || clazz==short.class )
+            result = ((Number)results[0]).shortValue() >= ((Number)results[1]).shortValue();
+        else
+            throw new JDOQueryException( msg.msg("EXC_IllegalResultTypeForExpression", ">=", clazz.getName()) ); //NOI18N
+        return result ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the results evaluated by the node's
+     * children are non integral types
+     */
+    public Object leave(GreaterThanExpression node, Object[] results)
+    {   if( results[0]==null || results[1]==null ||
+            results[0]==undefined || results[1]==undefined )
+            return undefined;
+        boolean result;
+        Class clazz = node.getCommonOperandType();
+        if( clazz==Integer.class || clazz==int.class )
+            result = ((Number)results[0]).intValue() > ((Number)results[1]).intValue();
+        else if( clazz==Long.class || clazz==long.class )
+            result = ((Number)results[0]).longValue() > ((Number)results[1]).longValue();
+        else if( clazz==Double.class || clazz==double.class )
+            result = ((Number)results[0]).doubleValue() > ((Number)results[1]).doubleValue();
+        else if( clazz==Float.class || clazz==float.class )
+            result = ((Number)results[0]).floatValue() > ((Number)results[1]).floatValue();
+        else if( clazz==BigDecimal.class  )
+        {   BigDecimal left, right;
+            if( results[0] instanceof BigDecimal )
+                left = (BigDecimal) results[0];
+            else
+                left = new BigDecimal( results[0].toString() );
+            if( results[1] instanceof BigDecimal )
+                right = (BigDecimal) results[1];
+            else
+                right = new BigDecimal( results[1].toString() );
+            result = left.compareTo(right) > 0;
+        }
+        else if( clazz==BigInteger.class  )
+        {   BigInteger left, right;
+            if( results[0] instanceof BigInteger )
+                left = (BigInteger) results[0];
+            else
+                left = new BigInteger( results[0].toString() );
+            if( results[1] instanceof BigInteger )
+                right = (BigInteger) results[1];
+            else
+                right = new BigInteger( results[1].toString() );
+            result = left.compareTo(right) > 0;
+        }
+        // Comparable covers Date and String
+        else if( Comparable.class.isAssignableFrom(clazz) )
+            result = ((Comparable)results[0]).compareTo((Comparable)results[1]) > 0;
+        else if( clazz==Byte.class || clazz==byte.class )
+            result = ((Number)results[0]).byteValue() > ((Number)results[1]).byteValue();
+        else if( clazz==Character.class || clazz==char.class )
+            result = ((Character)results[0]).charValue() > ((Character)results[1]).charValue();
+        else if( clazz==Short.class || clazz==short.class )
+            result = ((Number)results[0]).shortValue() > ((Number)results[1]).shortValue();
+        else
+            throw new JDOQueryException( msg.msg("EXC_IllegalResultTypeForExpression", ">", clazz.getName()) ); //NOI18N
+        return result ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     */
+    public Object leave(IsEmptyCallExpression node, Object[] results)
+    {   if( results[0]==null )
+            return Boolean.TRUE;
+        else if( results[0]==undefined )
+            return undefined;
+        boolean result = ((Collection)results[0]).isEmpty();
+        return result ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the results evaluated by the node's
+     * children are non integral types
+     */
+    public Object leave(LessThanEqualsExpression node, Object[] results)
+    {   if( results[0]==null || results[1]==null ||
+            results[0]==undefined || results[1]==undefined )
+            return undefined;
+        boolean result;
+        Class clazz = node.getCommonOperandType();
+        if( clazz==Integer.class || clazz==int.class )
+            result = ((Number)results[0]).intValue() <= ((Number)results[1]).intValue();
+        else if( clazz==Long.class || clazz==long.class )
+            result = ((Number)results[0]).longValue() <= ((Number)results[1]).longValue();
+        else if( clazz==Double.class || clazz==double.class )
+            result = ((Number)results[0]).doubleValue() <= ((Number)results[1]).doubleValue();
+        else if( clazz==Float.class || clazz==float.class )
+            result = ((Number)results[0]).floatValue() <= ((Number)results[1]).floatValue();
+        else if( clazz==BigDecimal.class  )
+        {   BigDecimal left, right;
+            if( results[0] instanceof BigDecimal )
+                left = (BigDecimal) results[0];
+            else
+                left = new BigDecimal( results[0].toString() );
+            if( results[1] instanceof BigDecimal )
+                right = (BigDecimal) results[1];
+            else
+                right = new BigDecimal( results[1].toString() );
+            result = left.compareTo(right) <= 0;
+        }
+        else if( clazz==BigInteger.class  )
+        {   BigInteger left, right;
+            if( results[0] instanceof BigInteger )
+                left = (BigInteger) results[0];
+            else
+                left = new BigInteger( results[0].toString() );
+            if( results[1] instanceof BigInteger )
+                right = (BigInteger) results[1];
+            else
+                right = new BigInteger( results[1].toString() );
+            result = left.compareTo(right) <= 0;
+        }
+        // Comparable covers Date and String
+        else if( Comparable.class.isAssignableFrom(clazz) )
+            result = ((Comparable)results[0]).compareTo((Comparable)results[1]) <= 0;
+        else if( clazz==Byte.class || clazz==byte.class )
+            result = ((Number)results[0]).byteValue() <= ((Number)results[1]).byteValue();
+        else if( clazz==Character.class || clazz==char.class )
+            result = ((Character)results[0]).charValue() <= ((Character)results[1]).charValue();
+        else if( clazz==Short.class || clazz==short.class )
+            result = ((Number)results[0]).shortValue() <= ((Number)results[1]).shortValue();
+        else
+            throw new JDOQueryException( msg.msg("EXC_IllegalResultTypeForExpression", "<=", clazz.getName()) ); //NOI18N
+        return result ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the results evaluated by the node's
+     * children are non integral types
+     */
+    public Object leave(LessThanExpression node, Object[] results)
+    {   if( results[0]==null || results[1]==null ||
+            results[0]==undefined || results[1]==undefined )
+            return undefined;
+        boolean result;
+        Class clazz = node.getCommonOperandType();
+        if( clazz==Integer.class || clazz==int.class )
+            result = ((Number)results[0]).intValue() < ((Number)results[1]).intValue();
+        else if( clazz==Long.class || clazz==long.class )
+            result = ((Number)results[0]).longValue() < ((Number)results[1]).longValue();
+        else if( clazz==Double.class || clazz==double.class )
+            result = ((Number)results[0]).doubleValue() < ((Number)results[1]).doubleValue();
+        else if( clazz==Float.class || clazz==float.class )
+            result = ((Number)results[0]).floatValue() < ((Number)results[1]).floatValue();
+        else if( clazz==BigDecimal.class  )
+        {   BigDecimal left, right;
+            if( results[0] instanceof BigDecimal )
+                left = (BigDecimal) results[0];
+            else
+                left = new BigDecimal( results[0].toString() );
+            if( results[1] instanceof BigDecimal )
+                right = (BigDecimal) results[1];
+            else
+                right = new BigDecimal( results[1].toString() );
+            result = left.compareTo(right) < 0;
+        }
+        else if( clazz==BigInteger.class  )
+        {   BigInteger left, right;
+            if( results[0] instanceof BigInteger )
+                left = (BigInteger) results[0];
+            else
+                left = new BigInteger( results[0].toString() );
+            if( results[1] instanceof BigInteger )
+                right = (BigInteger) results[1];
+            else
+                right = new BigInteger( results[1].toString() );
+            result = left.compareTo(right) < 0;
+        }
+        // Comparable covers Date and String
+        else if( Comparable.class.isAssignableFrom(clazz) )
+            result = ((Comparable)results[0]).compareTo((Comparable)results[1]) < 0;
+        else if( clazz==Byte.class || clazz==byte.class )
+            result = ((Number)results[0]).byteValue() < ((Number)results[1]).byteValue();
+        else if( clazz==Character.class || clazz==char.class )
+            result = ((Character)results[0]).charValue() < ((Character)results[1]).charValue();
+        else if( clazz==Short.class || clazz==short.class )
+            result = ((Number)results[0]).shortValue() < ((Number)results[1]).shortValue();
+        else
+            throw new JDOQueryException( msg.msg("EXC_IllegalResultTypeForExpression", "<", clazz.getName()) ); //NOI18N
+        return result ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the results evaluated by the node's
+     * children are non integral types
+     */
+    public Object leave(MinusExpression node, Object[] results)
+    {   if( results[0]==null || results[1]==null ||
+            results[0]==undefined || results[1]==undefined )
+            return undefined;
+        Class clazz = node.getJavaClass();
+        if( clazz==Integer.class || clazz==int.class )
+            return new Integer( ((Number)results[0]).intValue() - ((Number)results[1]).intValue() );
+        else if( clazz==Long.class || clazz==long.class )
+            return new Long( ((Number)results[0]).longValue() - ((Number)results[1]).longValue() );
+        else if( clazz==Double.class || clazz==double.class )
+            return new Double( ((Number)results[0]).doubleValue() - ((Number)results[1]).doubleValue() );
+        else if( clazz==Float.class || clazz==float.class )
+            return new Float( ((Number)results[0]).floatValue() - ((Number)results[1]).floatValue() );
+        else if( clazz==BigDecimal.class  )
+        {   BigDecimal left, right;
+            if( results[0] instanceof BigDecimal )
+                left = (BigDecimal) results[0];
+            else
+                left = new BigDecimal( results[0].toString() );
+            if( results[1] instanceof BigDecimal )
+                right = (BigDecimal) results[1];
+            else
+                right = new BigDecimal( results[1].toString() );
+            return left.subtract( right );
+        }
+        else if( clazz==BigInteger.class  )
+        {   BigInteger left, right;
+            if( results[0] instanceof BigInteger )
+                left = (BigInteger) results[0];
+            else
+                left = new BigInteger( results[0].toString() );
+            if( results[1] instanceof BigInteger )
+                right = (BigInteger) results[1];
+            else
+                right = new BigInteger( results[1].toString() );
+            return left.subtract( right );
+        }
+        else if( clazz==Byte.class || clazz==byte.class )
+            return new Byte( (byte) (((Number)results[0]).byteValue() - ((Number)results[1]).byteValue()) );
+        else if( clazz==Character.class || clazz==char.class )
+            return new Character( (char) (((Character)results[0]).charValue() - ((Character)results[1]).charValue()) );
+        else if( clazz==Short.class || clazz==short.class )
+            return new Short( (short) (((Number)results[0]).shortValue() - ((Number)results[1]).shortValue()) );
+        throw new JDOQueryException( msg.msg("EXC_IllegalResultTypeForExpression", "-", clazz.getName()) ); //NOI18N
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the results evaluated by the node's
+     * children are non integral types
+     */
+    public Object leave(NotEqualsExpression node, Object[] results)
+    {   if( results[0]==undefined || results[1]==undefined )
+            return undefined;
+        boolean result;
+        if( results[0]==null && results[1]==null )
+            result = false;
+        else if( results[0]==null || results[1]==null )
+            result = true;
+        else
+        {   Class clazz = node.getCommonOperandType();
+            if( clazz==Integer.class || clazz==int.class )
+                result = ((Number)results[0]).intValue() != ((Number)results[1]).intValue();
+            else if( clazz==Long.class || clazz==long.class )
+                result = ((Number)results[0]).longValue() != ((Number)results[1]).longValue();
+            else if( clazz==Double.class || clazz==double.class )
+                result = ((Number)results[0]).doubleValue() != ((Number)results[1]).doubleValue();
+            else if( clazz==Float.class || clazz==float.class )
+                result = ((Number)results[0]).floatValue() != ((Number)results[1]).floatValue();
+            else if( clazz==BigDecimal.class  )
+            {   BigDecimal left, right;
+                if( results[0] instanceof BigDecimal )
+                    left = (BigDecimal) results[0];
+                else
+                    left = new BigDecimal( results[0].toString() );
+                if( results[1] instanceof BigDecimal )
+                    right = (BigDecimal) results[1];
+                else
+                    right = new BigDecimal( results[1].toString() );
+                result = left.compareTo( right ) != 0;
+            }
+            else if( clazz==BigInteger.class  )
+            {   BigInteger left, right;
+                if( results[0] instanceof BigInteger )
+                    left = (BigInteger) results[0];
+                else
+                    left = new BigInteger( results[0].toString() );
+                if( results[1] instanceof BigInteger )
+                    right = (BigInteger) results[1];
+                else
+                    right = new BigInteger( results[1].toString() );
+                result = left.compareTo( right ) != 0;
+            }
+            else if( Date.class.isAssignableFrom(clazz) )
+                result = ((Date)results[0]).getTime() != ((Date)results[1]).getTime();
+            else if( clazz==Byte.class || clazz==byte.class )
+                result = ((Number)results[0]).byteValue() != ((Number)results[1]).byteValue();
+            else if( clazz==Character.class || clazz==char.class )
+                result = ((Character)results[0]).charValue() != ((Character)results[1]).charValue();
+            else if( clazz==Short.class || clazz==short.class )
+                result = ((Number)results[0]).shortValue() != ((Number)results[1]).shortValue();
+            else 
+            {   PersistenceManager leftPM = JDOHelper.getPersistenceManager( results[0] );
+                PersistenceManager rightPM = JDOHelper.getPersistenceManager( results[1] );
+                if( leftPM!=null && rightPM!=null )
+                    // use == for persistence instances
+                    result = results[0] != results[1];
+                else if( leftPM==null && rightPM==null )
+                    // use equals for non persistent instances
+                    result = !results[0].equals( results[1] );
+                else
+                    // comparing persistent with non persistent instance
+                    result = true;
+            }
+        }
+        return result ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the result evaluated
+     * by the child of the argument <code>node</code>. The result
+     * returned by this method is based on the result evaluated by the child
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the result evaluated by child of node
+     * @return the result evaluated for node
+     */
+    public Object leave(NotExpression node, Object[] results)
+    {   if( results[0]==null ||
+            results[0]==undefined )
+            return undefined;
+        boolean result = !((Boolean)results[0]).booleanValue();
+        return result ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the result evaluated
+     * by the child of the argument <code>node</code>. The result
+     * returned by this method is based on the result evaluated by the child
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the result evaluated by child of node
+     * @return the result evaluated for node
+     */
+    public Object leave(OrderingExpression node, Object[] results)
+    {   if( results[0]==null ||
+            results[0]==undefined )
+            return undefined;
+        return results[0];
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the results evaluated by the node's
+     * children are non boolean types
+     */
+    public Object leave(OrExpression node, Object[] results)
+    {   Class clazz = node.getJavaClass();
+        if( clazz==Boolean.class || clazz==boolean.class )
+            return logicalOr( results[0], results[1] );
+        throw new JDOQueryException( msg.msg("EXC_IllegalResultTypeForExpression", "|", clazz.getName()) ); //NOI18N
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> is <code>null</code> as the argument
+     * <code>node</code> does not have any children. The result
+     * returned by this method is the instance obtained by the parameter table
+     * for for the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results <code>null</code>
+     * @return the instance obtained by the parameter table for node
+     */
+    public Object leave(ParameterAccessExpression node, Object[] results)
+    {   return this.parameters.getValue( node.getName() );
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the results evaluated by the node's
+     * children are non integral types
+     */
+    public Object leave(PlusExpression node, Object[] results)
+    {   if( results[0]==null || results[1]==null ||
+            results[0]==undefined || results[1]==undefined )
+            return undefined;
+        Class clazz = node.getJavaClass();
+        if( clazz==Integer.class || clazz==int.class )
+            return new Integer( ((Number)results[0]).intValue() + ((Number)results[1]).intValue() );
+        else if( clazz==Long.class || clazz==long.class )
+            return new Long( ((Number)results[0]).longValue() + ((Number)results[1]).longValue() );
+        else if( clazz==Double.class || clazz==double.class )
+            return new Double( ((Number)results[0]).doubleValue() + ((Number)results[1]).doubleValue() );
+        else if( clazz==Float.class || clazz==float.class )
+            return new Float( ((Number)results[0]).floatValue() + ((Number)results[1]).floatValue() );
+        else if( clazz==BigDecimal.class  )
+        {   BigDecimal left, right;
+            if( results[0] instanceof BigDecimal )
+                left = (BigDecimal) results[0];
+            else
+                left = new BigDecimal( results[0].toString() );
+            if( results[1] instanceof BigDecimal )
+                right = (BigDecimal) results[1];
+            else
+                right = new BigDecimal( results[1].toString() );
+            return left.add( right );
+        }
+        else if( clazz==BigInteger.class  )
+        {   BigInteger left, right;
+            if( results[0] instanceof BigInteger )
+                left = (BigInteger) results[0];
+            else
+                left = new BigInteger( results[0].toString() );
+            if( results[1] instanceof BigInteger )
+                right = (BigInteger) results[1];
+            else
+                right = new BigInteger( results[1].toString() );
+            return left.add( right );
+        }
+        else if( clazz==String.class )
+            return (String)results[0] + (String)results[1];
+        else if( clazz==Byte.class || clazz==byte.class )
+            return new Byte( (byte) (((Number)results[0]).byteValue() + ((Number)results[1]).byteValue()) );
+        else if( clazz==Character.class || clazz==char.class )
+            return new Character( (char) (((Character)results[0]).charValue() + ((Character)results[1]).charValue()) );
+        else if( clazz==Short.class || clazz==short.class )
+            return new Short( (short) (((Number)results[0]).shortValue() + ((Number)results[1]).shortValue()) );
+        throw new JDOQueryException( msg.msg("EXC_IllegalResultTypeForExpression", "+", clazz.getName()) ); //NOI18N
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     */
+    public Object leave(StartsWithCallExpression node, Object[] results)
+    {   if( results[0]==null ||
+            results[0]==undefined )
+            return undefined;
+        boolean result = ((String)results[0]).startsWith( (String)results[1] );
+        return result ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     */
+    public Object leave(StaticFieldAccessExpression node, Object[] results)
+    {   return node.getFieldValue( pm );
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> is <code>null</code> as the argument
+     * <code>node</code> does not have any children. The result
+     * returned by this method is the current instance stored in this node visitor
+     * by method <code>setCurrent</code>.
+     * @param node the node to be evaluated
+     * @param results <code>null</code>
+     * @return the current instance stored in this node visitor
+     * by method <code>setCurrent</code>
+     */
+    public Object leave(ThisExpression node, Object[] results)
+    {   return this.current;
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the results evaluated
+     * by the children of the argument <code>node</code>. The result
+     * returned by this method is based on the results evaluated by the children
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the results evaluated by children of node
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the results evaluated by the node's
+     * children are non integral types
+     */
+    public Object leave(TimesExpression node, Object[] results)
+    {   if( results[0]==null || results[1]==null ||
+            results[0]==undefined || results[1]==undefined )
+            return undefined;
+        Class clazz = node.getJavaClass();
+        if( clazz==Integer.class || clazz==int.class )
+            return new Integer( ((Number)results[0]).intValue() * ((Number)results[1]).intValue() );
+        else if( clazz==Long.class || clazz==long.class )
+            return new Long( ((Number)results[0]).longValue() * ((Number)results[1]).longValue() );
+        else if( clazz==Double.class || clazz==double.class )
+            return new Double( ((Number)results[0]).doubleValue() * ((Number)results[1]).doubleValue() );
+        else if( clazz==Float.class || clazz==float.class )
+            return new Float( ((Number)results[0]).floatValue() * ((Number)results[1]).floatValue() );
+        else if( clazz==BigDecimal.class  )
+        {   BigDecimal left, right;
+            if( results[0] instanceof BigDecimal )
+                left = (BigDecimal) results[0];
+            else
+                left = new BigDecimal( results[0].toString() );
+            if( results[1] instanceof BigDecimal )
+                right = (BigDecimal) results[1];
+            else
+                right = new BigDecimal( results[1].toString() );
+            return left.multiply( right );
+        }
+        else if( clazz==BigInteger.class  )
+        {   BigInteger left, right;
+            if( results[0] instanceof BigInteger )
+                left = (BigInteger) results[0];
+            else
+                left = new BigInteger( results[0].toString() );
+            if( results[1] instanceof BigInteger )
+                right = (BigInteger) results[1];
+            else
+                right = new BigInteger( results[1].toString() );
+            return left.multiply( right );
+        }
+        else if( clazz==Byte.class || clazz==byte.class )
+            return new Byte( (byte) (((Number)results[0]).byteValue() * ((Number)results[1]).byteValue()) );
+        else if( clazz==Character.class || clazz==char.class )
+            return new Character( (char) (((Character)results[0]).charValue() * ((Character)results[1]).charValue()) );
+        else if( clazz==Short.class || clazz==short.class )
+            return new Short( (short) (((Number)results[0]).shortValue() * ((Number)results[1]).shortValue()) );
+        throw new JDOQueryException( msg.msg("EXC_IllegalResultTypeForExpression", "*", clazz.getName()) ); //NOI18N
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the result evaluated
+     * by the child of the argument <code>node</code>. The result
+     * returned by this method is based on the result evaluated by the child
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the result evaluated by the node's child
+     * @return the result evaluated for node
+     * @exception JDOQueryException if the result evaluated by the node's
+     * child is not an integral type.
+     */
+    public Object leave(UnaryMinusExpression node, Object[] results)
+    {   if( results[0]==null ||
+            results[0]==undefined )
+            return undefined;
+        Class clazz = node.getJavaClass();
+        if( clazz==Integer.class || clazz==int.class )
+            return new Integer( -((Number)results[0]).intValue() );
+        else if( clazz==Long.class || clazz==long.class )
+            return new Long( -((Number)results[0]).longValue() );
+        else if( clazz==Double.class || clazz==double.class )
+            return new Double( -((Number)results[0]).doubleValue() );
+        else if( clazz==Float.class || clazz==float.class )
+            return new Float( -((Number)results[0]).floatValue() );
+        else if( clazz==BigInteger.class )
+            return ((BigInteger)results[0]).negate();
+        else if( clazz==BigDecimal.class )
+            return ((BigDecimal)results[0]).negate();
+        else if( clazz==Byte.class || clazz==byte.class )
+            return new Byte( (byte) -((Number)results[0]).byteValue() );
+        else if( clazz==Character.class || clazz==char.class )
+            return new Character( (char) -((Character)results[0]).charValue() );
+        else if( clazz==Short.class || clazz==short.class )
+            return new Short( (short) -((Number)results[0]).shortValue() );
+        throw new JDOQueryException( msg.msg("EXC_IllegalResultTypeForExpression", "-", clazz.getName()) ); //NOI18N
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> contains the result evaluated
+     * by the child of the argument <code>node</code>. The result
+     * returned by this method is the same as the result evaluated by the child
+     * of the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results the result evaluated by the node's child
+     * @return the result evaluated for node
+     */
+    public Object leave(UnaryPlusExpression node, Object[] results)
+    {   return results[0];
+    }
+
+    /**
+     * Returns the result evaluated for the argument <code>node</code>.
+     * The argument <code>results</code> is <code>null</code> as the argument
+     * <code>node</code> does not have any children. The result
+     * returned by this method is the instance obtained by the variable table
+     * for for the argument <code>node</code>.
+     * @param node the node to be evaluated
+     * @param results <code>null</code>
+     * @return the instance obtained by the variable table for node
+     */
+    public Object leave(VariableAccessExpression node, Object[] results)
+    {   Object result = this.variables.getValue( node.getName() );
+        if( result==undefined )
+            this.unboundVariableAccess = node;
+        return result;
+    }
+
+    /**
+     * Returns <code>false</code> if the argument <code>resultOfPreviousChild</code>
+     * is undefined and the argument <code>indexOfNextChild</code> is greater
+     * than 0.
+     * @param node the parent node of the children currently evaluated
+     * @param resultOfPreviousChild an array of <code>null</code> instances
+     * @param indexOfNextChild the index of the next child to be dumped
+     * @return <code>false</code> if the argument <code>resultOfPreviousChild</code>
+     * is undefined and the argument <code>indexOfNextChild</code> is greater
+     * than 0
+     */
+    public boolean walkNextChild(AndExpression node, Object resultOfPreviousChild, int indexOfNextChild)
+    {   if( indexOfNextChild>0 )
+        {   BoundVariable boundVariable = removeBoundVariable();
+            if( isIteration(boundVariable, node.getRightExpression()) )
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns <code>false</code> if the argument <code>resultOfPreviousChild</code>
+     * is <code>null</code>, undefined or <code>false</code> and the argument <code>indexOfNextChild</code> is greater
+     * than 0.
+     * @param node the parent node of the children currently evaluated
+     * @param resultOfPreviousChild an array of <code>null</code> instances
+     * @param indexOfNextChild the index of the next child to be dumped
+     * @return <code>false</code> if the argument <code>resultOfPreviousChild</code>
+     * is <code>null</code>, undefined or <code>false</code> and the argument <code>indexOfNextChild</code> is greater
+     * than 0
+     */
+    public boolean walkNextChild(ConditionalAndExpression node, Object resultOfPreviousChild, int indexOfNextChild)
+    {   if( indexOfNextChild>0 )
+        {   BoundVariable boundVariable = removeBoundVariable();
+            if ( isIteration(boundVariable, node.getRightExpression()) )
+                return false;
+            else if ( resultOfPreviousChild==undefined ) 
+                // evaluate second operand, if first is undefined
+                return true;
+
+            Class clazz = node.getJavaClass();
+            if( ((clazz==Boolean.class || clazz==boolean.class) &&
+                 resultOfPreviousChild!=null &&
+                 !((Boolean)resultOfPreviousChild).booleanValue()) )
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns <code>false</code> if the argument <code>resultOfPreviousChild</code>
+     * is <code>null</code>, undefined or <code>true</code> and the argument <code>indexOfNextChild</code> is greater
+     * than 0.
+     * @param node the parent node of the children currently evaluated
+     * @param resultOfPreviousChild an array of <code>null</code> instances
+     * @param indexOfNextChild the index of the next child to be dumped
+     * @return <code>false</code> if the argument <code>resultOfPreviousChild</code>
+     * is <code>null</code>, undefined or <code>true</code> and the argument <code>indexOfNextChild</code> is greater
+     * than 0
+     */
+    public boolean walkNextChild(ConditionalOrExpression node, Object resultOfPreviousChild, int indexOfNextChild)
+    {   if( indexOfNextChild>0 )
+        {   BoundVariable boundVariable = removeBoundVariable();
+            if( resultOfPreviousChild==undefined ) 
+                // evaluate second operand, if first is undefined
+                return true;
+
+            Class clazz = node.getJavaClass();
+            if ( ((clazz==Boolean.class || clazz==boolean.class) &&
+                  resultOfPreviousChild!=null &&
+                  ((Boolean)resultOfPreviousChild).booleanValue()) )
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns <code>false</code> if the argument <code>resultOfPreviousChild</code>
+     * is undefined and the argument <code>indexOfNextChild</code> is greater
+     * than 0.
+     * @param node the parent node of the children currently evaluated
+     * @param resultOfPreviousChild an array of <code>null</code> instances
+     * @param indexOfNextChild the index of the next child to be dumped
+     * @return <code>false</code> if the argument <code>resultOfPreviousChild</code>
+     * is undefined and the argument <code>indexOfNextChild</code> is greater than 0
+     */
+    public boolean walkNextChild(ContainsCallExpression node, Object resultOfPreviousChild, int indexOfNextChild)
+    {   return true;
+    }
+
+    /**
+     * Returns <code>false</code> if the argument <code>resultOfPreviousChild</code>
+     * is undefined and the argument <code>indexOfNextChild</code> is greater
+     * than 0.
+     * @param node the parent node of the children currently evaluated
+     * @param resultOfPreviousChild an array of <code>null</code> instances
+     * @param indexOfNextChild the index of the next child to be dumped
+     * @return <code>false</code> if the argument <code>resultOfPreviousChild</code>
+     * is undefined and the argument <code>indexOfNextChild</code> is greater
+     * than 0
+     */
+    public boolean walkNextChild(OrExpression node, Object resultOfPreviousChild, int indexOfNextChild)
+    {   if( indexOfNextChild>0 )
+        {   BoundVariable boundVariable = removeBoundVariable();
+        }
+        return true;
+    }
+
+    //private members
+    private class BoundVariable
+    {   String name;
+        Class clazz;
+        Collection collection;
+        boolean result = false;
+
+        BoundVariable(String name, Class clazz, Collection collection)
+        {   this.name = name;
+            this.clazz = clazz;
+            this.collection = collection;
+        }
+        public boolean equals(Object obj)
+        {   return name.equals( obj );
+        }
+        public int hashCode()
+        {   return name.hashCode();
+        }
+        public String toString()
+        {   return name.toString();
+        }
+    }
+    private BoundVariable removeBoundVariable()
+    {   if( this.unboundVariableAccess!=null )
+            throw new JDOQueryException( msg.msg("EXC_CannotAccessUnboundVariables", this.unboundVariableAccess.getName()) ); //NOI18N
+        int nrOfBoundVariables = this.boundVariables.size();
+        if( nrOfBoundVariables>1 )
+            throw new JDOQueryException( msg.msg("EXC_CannotProcessMultipleContainsClauses") ); //NOI18N
+        BoundVariable boundVariable;
+        if( nrOfBoundVariables>0 )
+            boundVariable = (BoundVariable) this.boundVariables.remove( nrOfBoundVariables-1 );
+        else
+            boundVariable = null;
+        return boundVariable;
+    }
+    private boolean isIteration(BoundVariable boundVariable, Expression expr)
+    {   boolean result = false;
+        if( boundVariable!=null )
+        {   result = true;
+            boundVariable.result = false;
+            int nrOfBoundVariables = this.boundVariables.size();
+            for( Iterator i=boundVariable.collection.iterator(); i.hasNext(); )
+            {   Object value = i.next();
+                if( boundVariable.clazz.isInstance(value) )
+                {   this.variables.setValue( boundVariable.name, value );
+                    Object object = walker.walk( expr, this );
+                    while( nrOfBoundVariables<this.boundVariables.size() )
+                        removeBoundVariable();
+                    if( object!=null &&
+                        object instanceof Boolean &&
+                        ((Boolean)object).booleanValue() )
+                    {   boundVariable.result = true;
+                        break;
+            }   }   }
+            this.variables.setValue( boundVariable.name, undefined );
+            this.removedBoundVariable = boundVariable;
+        }
+        return result;
+    }
+    private Object logicalAnd(Object left, Object right)
+    {   Object result;
+        //if the expression has been an iteration then return the iteration result
+        if( right==null )
+        {   if( this.removedBoundVariable!=null )
+            {   result = this.removedBoundVariable.result ? Boolean.TRUE : Boolean.FALSE;
+                this.removedBoundVariable = null;
+            }
+            else
+                result = left;
+        }
+        else if( right==undefined ) 
+        {   // right hand side is undefined =>
+            // T AND U -> U
+            // F AND U -> F
+            // U AND U -> U
+            if( (left==undefined) || ((Boolean)left).booleanValue() )
+                result = undefined;
+            else 
+                result = Boolean.FALSE;
+        }
+        else if( left==undefined )
+        {   // left hand side is undefined
+            // U AND T -> U
+            // U AND F -> F
+            // U AND U -> U (handled above)
+            if( ((Boolean)right).booleanValue() )
+                result = undefined;
+            else
+                result = Boolean.FALSE;
+        }
+        else 
+        {   result = ((Boolean)left).booleanValue() && ((Boolean)right).booleanValue() ?
+                Boolean.TRUE : Boolean.FALSE;
+        }
+        return result;
+    }
+    private Object logicalOr(Object left, Object right)
+    {   Object result;
+        //if the expression has been an iteration then return the iteration result
+        if( right==null )
+        {   if( this.removedBoundVariable!=null )
+            {   result = this.removedBoundVariable.result ? Boolean.TRUE : Boolean.FALSE;
+                this.removedBoundVariable = null;
+            }
+            else
+                result = left;
+        }
+        else if( right==undefined )
+        {   // right hand side is undefined =>
+            // T OR U -> T
+            // F OR U -> U
+            // U OR U -> U
+            if( (left==undefined) || !((Boolean)left).booleanValue() )
+                result = undefined;
+            else
+                result =  Boolean.TRUE;
+        }
+        else if( left==undefined )
+        {   // left hand side is undefined
+            // U OR T -> T
+            // U OR F -> U
+            // U OR U -> U (handled above)
+            if ( ((Boolean)right).booleanValue() )
+                result = Boolean.TRUE;
+            else
+                result = undefined; 
+        }
+        else 
+        {   result = ((Boolean)left).booleanValue() || ((Boolean)right).booleanValue() ?
+                Boolean.TRUE : Boolean.FALSE;
+        }
+        return result;
+    }
+    private void log(String s)
+    {   System.out.print( s );
+    }
+    private void logln(String s)
+    {   System.out.println( s );
+    }
+}

Added: incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/OrderingComparator.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/OrderingComparator.java?rev=171353&view=auto
==============================================================================
--- incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/OrderingComparator.java (added)
+++ incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/OrderingComparator.java Sun May 22 11:08:57 2005
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.jdoql;
+
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.jdo.impl.jdoql.scope.UNDEFINED;
+import org.apache.jdo.jdoql.tree.DescendingOrderingExpression;
+import org.apache.jdo.jdoql.tree.OrderingExpression;
+import org.apache.jdo.jdoql.tree.QueryTree;
+import org.apache.jdo.jdoql.tree.TreeWalker;
+
+/**
+ * An instance of this class is used to compare two instances of
+ * <code>Comparable</code> based on the ordering expressions
+ * defined by a query tree. This instance holds references to a query tree,
+ * a tree walker and a memory query instance for this purpose.
+ *
+ * @author Michael Watzek
+ */
+public class OrderingComparator implements Comparator
+{
+    private static final UNDEFINED  undefined = UNDEFINED.getInstance();
+
+          List          orderings;
+    final TreeWalker    walker;
+    final MemoryQuery   nodeVisitor;
+
+    /**
+     * Constructs an ordering comparator for a tree walker and a node visitor.
+     * This comparator is not bound to a query tree.
+     * It can be bound to a query tree by calling method
+     * <code>setQueryTree</code>.
+     * @param walker the tree walker
+     * @param nodeVisitor the node visitor evaluating the ordering expressions
+     */
+    public OrderingComparator(TreeWalker walker, MemoryQuery nodeVisitor)
+    {   this( walker, nodeVisitor, null );
+    }
+
+    /**
+     * Constructs an ordering comparator for a tree walker, a node visitor
+     * and a query tree. This comparator is bound to that query tree.
+     * @param walker the tree walker
+     * @param nodeVisitor the node visitor evaluating the ordering expressions
+     * @param queryTree the query tree containing the ordering expressions
+     */
+    public OrderingComparator(TreeWalker walker, MemoryQuery nodeVisitor, QueryTree queryTree)
+    {   this.walker = walker;
+        this.nodeVisitor = nodeVisitor;
+        setQueryTree( queryTree );
+    }
+
+    /**
+     * Sets the query tree for this ordering comparator. Each ordering comparator
+     * can be bound to a query tree. The ordering expression list inside
+     * that query tree determines the ordering semantics of this comparator.
+     * @param queryTree the query tree containing the ordering expression list
+     */
+    public void setQueryTree(QueryTree queryTree)
+    {   if( queryTree!=null )
+            this.orderings = queryTree.getOrderingExpressions();
+        else
+            this.orderings = null;
+    }
+
+    /**
+     * Required method for implementing the interface <code>Comparator</code>.
+     * This method returns a negative integer, zero, or a positive integer
+     * as the first argument is less than, equal to, or greater than the second
+     * argument.
+     * If this instance is not bound to a query tree or,
+     * if the query tree bound to this instance
+     * does not have any ordering expression, then argument <code>o1</code>
+     * is less than argument <code>o2</code> by definition.
+     * @param o1 the first object to be compared
+     * @param o2 the second object to be compared
+     * @return a negative integer, zero, or a positive integer
+     * as the first argument is less than, equal to, or greater than the second
+     * @exception ClassCastException if the arguments are not instances of
+     * <code>Comparable</code>
+     */
+    public int compare(Object o1, Object o2)
+    {   int cmp = -1;
+        if( this.orderings!=null )
+            for( Iterator i=this.orderings.iterator(); i.hasNext(); )
+            {   OrderingExpression orderExpr = (OrderingExpression) i.next();
+                nodeVisitor.setCurrent( o1 );
+                Object result1 = walker.walk( orderExpr, nodeVisitor );
+                nodeVisitor.setCurrent( o2 );
+                Object result2 = walker.walk( orderExpr, nodeVisitor );
+                if( result1!=null ||
+                    result2!=null )
+                {   if( !(result1 instanceof Comparable) )
+                        break;
+                    else if( !(result2 instanceof Comparable) )
+                    {   cmp = 1;
+                        break;
+                    }
+                    cmp = ((Comparable)result1).compareTo( result2 );
+                    if( cmp!=0 )
+                    {   if( orderExpr instanceof DescendingOrderingExpression )
+                            cmp = -cmp;
+                        break;
+            }   }   }
+        return cmp;
+    }
+}
\ No newline at end of file