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