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 [4/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/jdoqlc/Optimizer.g
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/Optimizer.g?rev=171353&view=auto
==============================================================================
--- incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/Optimizer.g (added)
+++ incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/Optimizer.g Sun May 22 11:08:57 2005
@@ -0,0 +1,1313 @@
+/*
+ * 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.
+ */
+
+/*
+ * Optimizer.g
+ *
+ * Created on August 28, 2001
+ */
+
+header
+{
+    package org.apache.jdo.impl.jdoql.jdoqlc;
+    
+    import java.util.Collection;
+    
+    import java.math.BigDecimal;
+    import java.math.BigInteger;
+
+    import java.lang.reflect.Field;
+    import java.security.AccessController;
+    import java.security.PrivilegedAction;
+
+    import org.apache.jdo.model.java.JavaField;
+    import org.apache.jdo.model.java.JavaType;
+    import org.apache.jdo.impl.model.java.PredefinedType;
+    import org.apache.jdo.impl.model.java.WrapperClassType;
+
+    import org.apache.jdo.pm.PersistenceManagerInternal;
+    import org.apache.jdo.util.I18NHelper;
+    import org.apache.jdo.impl.jdoql.tree.*;
+    import org.apache.jdo.impl.jdoql.scope.ParameterTable;
+}
+
+/**
+ * This class defines the optimizer pass of the JDOQL compiler.
+ * It takes the typed AST as produced by the smenatic analysis and
+ * converts it into a simpler but equivalent typed AST.
+ * 
+ * @author  Michael Bouschen
+ */
+class Optimizer extends TreeParser;
+
+options
+{
+    importVocab = JDOQL;
+    buildAST = true;
+    defaultErrorHandler = false;
+    ASTLabelType = "JDOQLAST"; //NOI18N
+}
+
+{
+    /** The persistence manager of the query instance. */
+    protected PersistenceManagerInternal pm;
+
+    /** The error message support class. */
+    protected ErrorMsg errorMsg;
+    
+    /** The query parameter table */
+    protected ParameterTable paramtab;
+    
+    /** Flag indicating whether query parameers should be included. */
+    protected boolean optimizeParameters;
+
+    /** I18N support */
+    protected final static I18NHelper msg = I18NHelper.getInstance(
+        "org.apache.jdo.impl.jdoql.Bundle", Optimizer.class.getClassLoader()); //NOI18N
+    
+    /**
+     *
+     */
+    public void init(PersistenceManagerInternal pm,
+                     ParameterTable paramtab, ErrorMsg errorMsg)
+    {
+        this.pm = pm;
+        this.errorMsg = errorMsg;
+        this.paramtab = paramtab;
+        this.optimizeParameters = (paramtab != null);
+    }
+
+    /**
+     *
+     */
+    public void reportError(RecognitionException ex) {
+        errorMsg.fatal(msg.msg("ERR_OptimizerError", ex)); //NOI18N
+    }
+
+    /**
+     *
+     */
+    public void reportError(String s) {
+        errorMsg.fatal(msg.msg("ERR_OptimizerError") + s); //NOI18N
+    }
+
+    /**
+     * Converts the string argument into a single char.
+     */
+    protected static char parseChar(String text)
+    {
+        char first = text.charAt(0);
+        if (first == '\\') {
+            //found escape => check the next char
+            char second = text.charAt(1);
+            switch (second)
+            {
+            case 'n': return '\n';
+            case 'r': return '\r';
+            case 't': return '\t';
+            case 'b': return '\b';
+            case 'f': return '\f';
+            case 'u': 
+                // unicode spec
+                return (char)Integer.parseInt(text.substring(2, text.length()), 16);
+            case '0':            
+            case '1':
+            case '2':
+            case '3':            
+            case '4':
+            case '5':            
+            case '6':
+            case '7': 
+                // octal spec 
+                return (char)Integer.parseInt(text.substring(1, text.length()), 8);
+            default : return second;
+            }
+        }
+        return first;
+    }
+
+    /**
+     * Check an AND operation (BAND, AND) for constant operands 
+     * that could be optimized.
+     * @param op the AND operator
+     * @param left the left operand
+     * @param right the right operand
+     * @return optimized JDOQLAST 
+     */
+    protected JDOQLAST checkAnd(JDOQLAST op, JDOQLAST left, JDOQLAST right)
+    {
+        JDOQLAST ast = op;
+
+        if (isBooleanValueAST(left)) {
+            ast = handleValueAndExpr(op, ((ConstantExpr)left).getValue(), right);
+        }
+        else if (isBooleanValueAST(right)) {
+            ast = handleValueAndExpr(op, ((ConstantExpr)right).getValue(), left);
+        }
+        return ast;
+    }
+
+    /**
+     * Check an OR operation (BOR, OR) for constant operands 
+     * that could be optimized.
+     * @param op the OR operator
+     * @param left the left operand
+     * @param right the right operand
+     * @return optimized JDOQLAST 
+     */
+    protected JDOQLAST checkOr(JDOQLAST op, JDOQLAST left, JDOQLAST right)
+    {
+        JDOQLAST ast = op;
+
+        if (isBooleanValueAST(left)) {
+            ast = handleValueOrExpr(op, ((ConstantExpr)left).getValue(), right);
+        }
+        else if (isBooleanValueAST(right)) {
+            ast = handleValueOrExpr(op, ((ConstantExpr)right).getValue(), left);
+        }
+        return ast;
+    }
+
+    /**
+     * Check a equality operation (EQUAL, NOT_EQUAL) for constant operands
+     * that could be optimized.
+     * @param op the equality operator
+     * @param left the left operand
+     * @param right the right operand
+     * @param negate true for not equal operation, false otherwise
+     * @return optimized JDOQLAST 
+     */
+    protected JDOQLAST checkEqualityOp(JDOQLAST op, JDOQLAST left, 
+                                       JDOQLAST right, boolean negate)
+    {
+        JDOQLAST ast = op;
+        
+        // case <CONSTANT> <op> <CONSTANT> 
+        if ((left.getType() == CONSTANT) && (right.getType() == CONSTANT)) {
+            ast = handleValueEqValue(op, left, right, negate);
+        }
+        // case <boolean CONSTANT> <op> <expr>
+        else if (isBooleanValueAST(left)) {
+            ast = handleBooleanValueEqExpr(op, ((ConstantExpr)left).getValue(), 
+                                           right, negate);
+        }
+        // case <expr> <op> <boolean CONSTANT>
+        else if (isBooleanValueAST(right)) {
+            ast = handleBooleanValueEqExpr(op, ((ConstantExpr)right).getValue(),
+                                           left, negate);
+        }
+        return ast;
+    }
+
+    /**
+     * Check a object equality operation (OBJECT_EQUAL, OBJECT_NOT_EQUAL) 
+     * for constant operands that could be optimized.
+     * @param op the object equality operator
+     * @param left the left operand
+     * @param right the right operand
+     * @param negate true for not equal operation, false otherwise
+     * @return optimized JDOQLAST 
+     */
+    protected JDOQLAST checkObjectEqualityOp(JDOQLAST op, JDOQLAST left, 
+                                             JDOQLAST right, boolean negate)
+    {
+        JDOQLAST ast = op;
+
+        if ((left.getType() == CONSTANT) && (right.getType() == CONSTANT)) {
+            ast = handleValueEqValue(op, left, right, negate);
+        }
+        return ast;
+    }
+
+    /**
+     * Check a collection equality operation (COLLECTION_EQUAL, 
+     * COLLECTION_NOT_EQUAL) for constant operands that could be optimized.
+     * @param op the collection equality operator
+     * @param left the left operand
+     * @param right the right operand
+     * @param negate true for not equal operation, false otherwise
+     * @return optimized JDOQLAST 
+     */
+    protected JDOQLAST checkCollectionEqualityOp(JDOQLAST op, JDOQLAST left, 
+                                                 JDOQLAST right, boolean negate)
+    {
+        JDOQLAST ast = op;
+        boolean isLeftConstant = (left.getType() == CONSTANT);
+        boolean isRightConstant = (right.getType() == CONSTANT);
+        
+        if (isLeftConstant && isRightConstant) {
+            ast = handleValueEqValue(op, left, right, negate);
+        }
+        return ast;
+    }
+
+    /**
+     * Check a logical not operation (LNOT) for a constant operand 
+     * that could be optimized.
+     * @param op the logical not operator
+     * @param arg the operand
+     * @return optimized JDOQLAST 
+     */
+    protected JDOQLAST checkLogicalNotOp(JDOQLAST op, JDOQLAST arg)
+    {
+        JDOQLAST ast = op;
+
+        if (arg.getType() == CONSTANT) {
+            // !value may be calculated at compile time.
+            Object valueObj = ((ConstantExpr)arg).getValue();
+            Boolean value = (valueObj instanceof Boolean) ? 
+                            new Boolean(!((Boolean)valueObj).booleanValue()) :
+                            Boolean.TRUE;
+            ast = ConstantExpr.newConstant(value);
+            ast.setType(CONSTANT);
+            ast.setText(value.toString());
+            ast.setTypeInfo(op.getTypeInfo());
+        }
+        return ast;
+    }
+
+    /**
+     * Check a binary plus operation (PLUS) for constant operands
+     * that could be optimized.
+     * @param op the plus operator
+     * @param left the left operand
+     * @param right the right operand
+     * @return optimized JDOQLAST 
+     */
+    protected JDOQLAST checkBinaryPlusOp(JDOQLAST op, JDOQLAST left, 
+                                         JDOQLAST right)
+    {
+        JDOQLAST ast = op;
+
+        if ((left.getType() == CONSTANT) && (right.getType() == CONSTANT)) {
+            Object leftValue = ((ConstantExpr)left).getValue();
+            Object rightValue = ((ConstantExpr)right).getValue();
+            Object value = null;
+            if (leftValue == null)
+                value = rightValue;
+            else if (rightValue == null)
+                value = leftValue;
+            else {
+                JavaType type = op.getTypeInfo();
+                
+                if (type.isWrapperClass())
+                    type = ((WrapperClassType)type).getWrappedPrimitiveType();
+                
+                if (type.equals(PredefinedType.intType))
+                    value = new Integer(((Number)leftValue).intValue() + 
+                        ((Number)rightValue).intValue());
+                else if (type.equals(PredefinedType.longType))
+                    value = new Long(((Number)leftValue).longValue() + 
+                        ((Number)rightValue).longValue());
+                else if (type.equals(PredefinedType.floatType))
+                    value = new Float(((Number)leftValue).floatValue() + 
+                        ((Number)rightValue).floatValue());
+                else if (type.equals(PredefinedType.doubleType))
+                    value = new Double(((Number)leftValue).doubleValue() + 
+                        ((Number)rightValue).doubleValue());
+                else if (type.equals(PredefinedType.bigDecimalType))
+                    value = getBigDecimalValue(leftValue).add(
+                       getBigDecimalValue(rightValue));
+                else if (type.equals(PredefinedType.bigIntegerType))
+                    value = getBigIntegerValue(leftValue).add(
+                        getBigIntegerValue(rightValue));
+                else 
+                    errorMsg.fatal(msg.msg("ERR_OptmizerInvalidType", //NOI18N
+                        "checkBinaryPlusOp", type)); //NOI18N
+            }
+            ast = ConstantExpr.newConstant(value);
+            ast.setType(CONSTANT);
+            ast.setText(value.toString());
+            ast.setTypeInfo(op.getTypeInfo());
+        }
+        return ast;
+    }
+    
+    /**
+     * Check a string concatenation operation (CONCAT) for constant operands
+     * that could be optimized.
+     * @param op the concat operator
+     * @param left the left operand
+     * @param right the right operand
+     * @return optimized JDOQLAST 
+     */
+    protected JDOQLAST checkConcatOp(JDOQLAST op, JDOQLAST left, JDOQLAST right)
+    {
+        JDOQLAST ast = op;
+
+        if ((left.getType() == CONSTANT) && (right.getType() == CONSTANT)) {
+            Object leftValue = ((ConstantExpr)left).getValue();
+            Object rightValue = ((ConstantExpr)right).getValue();
+            Object value = null;
+            if (leftValue == null)
+                value = rightValue;
+            else if (rightValue == null)
+                value = leftValue;
+            else 
+                value = leftValue.toString() + rightValue.toString();
+            ast = ConstantExpr.newConstant(value);
+            ast.setType(CONSTANT);
+            ast.setText(value.toString());
+            ast.setTypeInfo(op.getTypeInfo());
+        }
+        return ast;
+    }
+
+    /**
+     * Check a binary minus operation (MINUS) for constant operands
+     * that could be optimized.
+     * @param op the minus operator
+     * @param left the left operand
+     * @param right the right operand
+     * @return optimized JDOQLAST 
+     */
+    protected JDOQLAST checkBinaryMinusOp(JDOQLAST op, JDOQLAST left, 
+                                          JDOQLAST right)
+    {
+        JDOQLAST ast = op;
+
+        if ((left.getType() == CONSTANT) && (right.getType() == CONSTANT)) {
+            Object leftValue = ((ConstantExpr)left).getValue();
+            Object rightValue = ((ConstantExpr)right).getValue();
+            Object value = null;
+            if (rightValue == null)
+                value = leftValue;
+            else {
+                if (leftValue == null)
+                    leftValue = new Integer(0);
+                
+                JavaType type = op.getTypeInfo();
+                
+                if (type.isWrapperClass())
+                    type = ((WrapperClassType)type).getWrappedPrimitiveType();
+                
+                if (type.equals(PredefinedType.intType))
+                    value = new Integer(((Number)leftValue).intValue() -
+                        ((Number)rightValue).intValue());
+                else if (type.equals(PredefinedType.longType))
+                    value = new Long(((Number)leftValue).longValue() -
+                        ((Number)rightValue).longValue());
+                else if (type.equals(PredefinedType.floatType))
+                    value = new Float(((Number)leftValue).floatValue() - 
+                        ((Number)rightValue).floatValue());
+                else if (type.equals(PredefinedType.doubleType))
+                    value = new Double(((Number)leftValue).doubleValue() - 
+                        ((Number)rightValue).doubleValue());
+                else if (type.equals(PredefinedType.bigDecimalType))
+                    value = getBigDecimalValue(leftValue).subtract(
+                       getBigDecimalValue(rightValue));
+                else if (type.equals(PredefinedType.bigIntegerType))
+                    value = getBigIntegerValue(leftValue).subtract(
+                        getBigIntegerValue(rightValue));
+                else 
+                    errorMsg.fatal(msg.msg("ERR_OptmizerInvalidType", //NOI18N
+                        "checkBinaryMinusOp", type)); //NOI18N
+            }
+            ast = ConstantExpr.newConstant(value);
+            ast.setType(CONSTANT);
+            ast.setText(value.toString());
+            ast.setTypeInfo(op.getTypeInfo());
+        }
+        return ast;
+    }
+    
+    /**
+     * Check a binary multiplication operation (STAR) for constant operands
+     * that could be optimized.
+     * @param op the multiplication operator
+     * @param left the left operand
+     * @param right the right operand
+     * @return optimized JDOQLAST 
+     */
+    protected JDOQLAST checkMultiplicationOp(JDOQLAST op, JDOQLAST left, 
+                                             JDOQLAST right)
+    {
+        JDOQLAST ast = op;
+
+        if ((left.getType() == CONSTANT) && (right.getType() == CONSTANT)) {
+            Object leftValue = ((ConstantExpr)left).getValue();
+            Object rightValue = ((ConstantExpr)right).getValue();
+            Object value = null;
+            if (leftValue == null)
+                leftValue = new Integer(0);
+            if (rightValue == null)
+                rightValue = new Integer(0);
+            JavaType type = op.getTypeInfo();
+                
+            if (type.isWrapperClass())
+                type = ((WrapperClassType)type).getWrappedPrimitiveType();
+                
+            if (type.equals(PredefinedType.intType))
+                value = new Integer(((Number)leftValue).intValue() *
+                    ((Number)rightValue).intValue());
+            else if (type.equals(PredefinedType.longType))
+                value = new Long(((Number)leftValue).longValue() *
+                    ((Number)rightValue).longValue());
+            else if (type.equals(PredefinedType.floatType))
+                value = new Float(((Number)leftValue).floatValue() * 
+                    ((Number)rightValue).floatValue());
+            else if (type.equals(PredefinedType.doubleType))
+                value = new Double(((Number)leftValue).doubleValue() * 
+                    ((Number)rightValue).doubleValue());
+            else if (type.equals(PredefinedType.bigDecimalType))
+                value = getBigDecimalValue(leftValue).multiply(
+                    getBigDecimalValue(rightValue));
+            else if (type.equals(PredefinedType.bigIntegerType))
+                value = getBigIntegerValue(leftValue).multiply(
+                    getBigIntegerValue(rightValue));
+            else 
+                errorMsg.fatal(msg.msg("ERR_OptmizerInvalidType", //NOI18N
+                    "checkMultiplicationOp", type)); //NOI18N
+
+            ast = ConstantExpr.newConstant(value);
+            ast.setType(CONSTANT);
+            ast.setText(value.toString());
+            ast.setTypeInfo(op.getTypeInfo());
+        }
+        return ast;
+    }
+    
+    /**
+     * Check a binary division operation (DIV) for constant operands
+     * that could be optimized.
+     * @param op the division operator
+     * @param left the left operand
+     * @param right the right operand
+     * @return optimized JDOQLAST 
+     */
+    protected JDOQLAST checkDivisionOp(JDOQLAST op, JDOQLAST left, 
+                                       JDOQLAST right)
+    {
+        JDOQLAST ast = op;
+
+        if ((left.getType() == CONSTANT) && (right.getType() == CONSTANT)) {
+            Object leftValue = ((ConstantExpr)left).getValue();
+            Object rightValue = ((ConstantExpr)right).getValue();
+            Object value = null;
+            if (leftValue == null)
+                leftValue = new Integer(0);
+            if (rightValue == null)
+                // division by zero!
+                rightValue = new Integer(0);
+
+            JavaType type = op.getTypeInfo();
+            
+            if (type.isWrapperClass())
+                type = ((WrapperClassType)type).getWrappedPrimitiveType();
+                
+            if (type.equals(PredefinedType.intType))
+                value = new Integer(((Number)leftValue).intValue() /
+                    ((Number)rightValue).intValue());
+            else if (type.equals(PredefinedType.longType))
+                value = new Long(((Number)leftValue).longValue() /
+                    ((Number)rightValue).longValue());
+            else if (type.equals(PredefinedType.floatType))
+                value = new Float(((Number)leftValue).floatValue() / 
+                    ((Number)rightValue).floatValue());
+            else if (type.equals(PredefinedType.doubleType))
+                value = new Double(((Number)leftValue).doubleValue() / 
+                    ((Number)rightValue).doubleValue());
+            else if (type.equals(PredefinedType.bigDecimalType))
+                value = getBigDecimalValue(leftValue).divide(
+                   getBigDecimalValue(rightValue), BigDecimal.ROUND_HALF_EVEN);
+            else if (type.equals(PredefinedType.bigIntegerType))
+                value = getBigIntegerValue(leftValue).divide(
+                    getBigIntegerValue(rightValue));
+            else 
+                errorMsg.fatal(msg.msg("ERR_OptmizerInvalidType", //NOI18N
+                    "checkDivisionOp", type)); //NOI18N
+
+            ast = ConstantExpr.newConstant(value);
+            ast.setType(CONSTANT);
+            ast.setText(value.toString());
+            ast.setTypeInfo(op.getTypeInfo());
+        }
+        return ast;
+    }
+    
+    /**
+     * Check a unary minus operation (UNARY_MINUS) for a constant operand
+     * that could be optimized.
+     * @param op the unary minus operator
+     * @param arg the operand
+     * @return optimized JDOQLAST 
+     */
+    protected JDOQLAST checkUnaryMinusOp(JDOQLAST op, JDOQLAST arg)
+    {
+        JDOQLAST ast = op;
+        
+        if (arg.getType() == CONSTANT) {
+            Object value = ((ConstantExpr)arg).getValue();
+            JavaType type = op.getTypeInfo();
+            Object negate = null;
+            
+            if (type.equals(PredefinedType.intType))
+                negate = new Integer(-((Number)value).intValue());
+            else if (type.equals(PredefinedType.longType))
+                negate = new Long(-((Number)value).longValue());
+            else if (type.equals(PredefinedType.floatType))
+                negate = new Float(-((Number)value).floatValue());
+            else if (type.equals(PredefinedType.doubleType))
+                negate = new Double(-((Number)value).doubleValue());
+            else if (type.equals(PredefinedType.bigDecimalType))
+                negate = getBigDecimalValue(value).negate();
+            else if (type.equals(PredefinedType.bigIntegerType))
+                negate = getBigIntegerValue(value).negate();
+            else 
+                errorMsg.fatal(msg.msg("ERR_OptmizerInvalidType", //NOI18N
+                    "checkUnaryMinusOp", type)); //NOI18N
+            
+            ast = ConstantExpr.newConstant(negate);
+            ast.setType(CONSTANT);
+            ast.setText(negate.toString());
+            ast.setTypeInfo(op.getTypeInfo());
+        }
+        return ast;
+    }
+
+    /**
+     * Converts the specified value into a BigDecimal value. 
+     * @param value value to be converted
+     * @return BigDecimal representation
+     */
+    protected BigDecimal getBigDecimalValue(Object value)
+    {
+        BigDecimal ret = null;
+        if (value instanceof BigDecimal)
+            ret = (BigDecimal)value;
+        else if (value instanceof BigInteger)
+            ret = new BigDecimal((BigInteger)value);
+        else if (value instanceof Double)
+            ret = new BigDecimal(((Double)value).doubleValue());
+        else if (value instanceof Float)
+            ret = new BigDecimal(((Float)value).doubleValue());
+        else if (value instanceof Number)
+            ret = BigDecimal.valueOf(((Number)value).longValue());
+        else
+            errorMsg.fatal(msg.msg("ERR_OptmizerNumberExpected", //NOI18N
+                "getBigDecimalValue", value)); //NOI18N
+        return ret;
+    }
+
+    /**
+     * Converts the specified value into a BigInteger value. 
+     * @param value value to be converted
+     * @return BigInteger representation
+     */
+    protected BigInteger getBigIntegerValue(Object value)
+    {
+        BigInteger ret = null;
+
+        if (value instanceof BigInteger)
+            ret = (BigInteger)value;
+        else if (value instanceof Number)
+            ret = BigInteger.valueOf(((Number)value).longValue());
+        else
+            errorMsg.fatal(msg.msg("ERR_OptmizerNumberExpected", //NOI18N
+                "getBigIntegerValue", value)); //NOI18N
+        return ret;
+    }
+    
+    /**
+     * This method is called in the case of an equality operation having two 
+     * constant operands. It calculates the result of this constant operation 
+     * and returns a JDOQLAST node representing a constant boolean value.
+     * @param op the equality operator
+     * @param left the left operand
+     * @param right the right operand
+     * @param negate true for not equal operation, false otherwise
+     * @return optimized JDOQLAST 
+     */
+    protected JDOQLAST handleValueEqValue(JDOQLAST op, JDOQLAST left,
+                                          JDOQLAST right, 
+                                          boolean negate)
+    {
+        Object leftValue = ((ConstantExpr)left).getValue();
+        Object rightValue = ((ConstantExpr)right).getValue();
+        boolean booleanValue = false;
+        
+        if ((leftValue == null) && (rightValue == null)) {
+            // both values are null -> true
+            booleanValue = true;
+        }
+        else if ((leftValue != null) && (rightValue != null)) {
+            // both values are not null -> use equals
+            booleanValue = leftValue.equals(rightValue);
+        }
+        else
+        {
+            // one value is null, the other is not null -> false
+            booleanValue = false;
+        }
+        if (negate) {
+            booleanValue = !booleanValue;
+        }
+        
+        Boolean value = booleanValue ? Boolean.TRUE : Boolean.FALSE;
+        ConstantExpr constant = ConstantExpr.newConstant(value);
+        constant.setType(CONSTANT);
+        constant.setText(value.toString());
+        constant.setTypeInfo(op.getTypeInfo());
+        return op;
+    }
+
+    /**
+     * This method is called in the case of an equality operation having 
+     * a boolean constant operand and a non constant operand. 
+     * It returns the non constant operand either as it is or inverted, 
+     * depending on the equality operation.
+     * @param op the equality operator
+     * @param value the contant boolean value
+     * @param expr the non constant operand
+     * @param negate true for not equal operation, false otherwise
+     * @return optimized JDOQLAST 
+     */
+    private JDOQLAST handleBooleanValueEqExpr(JDOQLAST op, Object value, 
+                                              JDOQLAST expr, boolean negate)
+    {
+        JDOQLAST ast;
+        boolean skip = (value instanceof Boolean) ? 
+                       ((Boolean)value).booleanValue() : false;
+        if (negate) skip = !skip;
+
+        if (skip) {
+            // expr == true -> expr
+            // expr != false -> expr
+            ast = expr;
+        }
+        else {
+            // if expr is a equality op or a not op the invert operation 
+            // may be "inlined":
+            //   (expr1 == expr2) != true -> expr1 != expr2
+            //   (expr1 != expr2) != true -> expr1 == expr2
+            //   !expr != true -> expr
+            //   !expr == false -> expr
+            // Otherwise wrap the expr with a not op
+            //   expr != true -> !expr
+            //   expr == false -> !expr
+            switch (expr.getType()) {
+            case EQUAL:
+                ast = new NotEqualsExpr();
+                ast.initialize(NOT_EQUAL, "!=", PredefinedType.booleanType); //NOI18N
+                ast.setFirstChild(expr.getFirstChild());
+                ((BinaryExpr)ast).setCommonOperandType(
+                    ((BinaryExpr)expr).getCommonOperandType());
+                break;
+            case NOT_EQUAL:
+                ast = new EqualsExpr();
+                ast.initialize(EQUAL, "==", PredefinedType.booleanType); //NOI18N
+                ast.setFirstChild(expr.getFirstChild());
+                ((BinaryExpr)ast).setCommonOperandType(
+                    ((BinaryExpr)expr).getCommonOperandType());
+                break;
+            case LNOT:
+                ast = (JDOQLAST)expr.getFirstChild();
+                break;
+            default:
+                ast = new NotExpr();
+                ast.initialize(LNOT, "!", PredefinedType.booleanType); //NOI18N
+                ast.setFirstChild(expr);
+            }
+            expr.setNextSibling(null);
+        }
+        return ast;
+    }
+
+    /**
+     * This method is called in the case of an AND operation having at least 
+     * one constant operand. If the constant operand evaluates to true it 
+     * returns the other operand. If it evaluates to false it returns an AST
+     * representing the constant boolean value false.
+     * @param op the AND operator
+     * @param value the value of the contsnat operand
+     * @param expr the other operand
+     * @return optimized JDOQLAST 
+     */
+    private JDOQLAST handleValueAndExpr(JDOQLAST op, Object value, JDOQLAST expr)
+    {
+        JDOQLAST ast;
+
+        if ((value instanceof Boolean) && ((Boolean)value).booleanValue()) {
+            // true AND expr -> expr
+            // expr AND true -> expr
+            expr.setNextSibling(null);
+            ast = expr;
+        }
+        else
+        {
+            // false AND expr -> false
+            // expr AND false -> false
+            ast = ConstantExpr.newConstant(Boolean.FALSE);
+            ast.setType(CONSTANT);
+            ast.setText("false"); //NOI18N
+            ast.setTypeInfo(op.getTypeInfo());
+        }
+        return ast;
+    }
+
+    /**
+     * This method is called in the case of an OR operation having at least 
+     * one constant operand. If the constant operand evaluates to false it 
+     * returns the other operand. If it evaluates to true it returns an AST
+     * representing the constant boolean value true.
+     * @param op the AND operator
+     * @param value the value of the constant operand
+     * @param expr the other operand
+     * @return optimized JDOQLAST 
+     */
+    private JDOQLAST handleValueOrExpr(JDOQLAST op, Object value, JDOQLAST expr)
+    {
+        JDOQLAST ast;
+
+        if ((value instanceof Boolean) && ((Boolean)value).booleanValue()) {
+            // true OR expr -> true
+            // expr OR true -> true
+            ast = ConstantExpr.newConstant(Boolean.TRUE);
+            ast.setType(CONSTANT);
+            ast.setText("true"); //NOI18N
+            ast.setTypeInfo(op.getTypeInfo());
+        }
+        else {
+            // false OR expr -> expr
+            // expr OR false -> expr
+            expr.setNextSibling(null);
+            ast = expr;
+        }
+        return ast;
+    }
+
+    /**
+     * Returns true if the specified AST represents a constant boolean value.
+     */
+    protected boolean isBooleanValueAST(JDOQLAST ast)
+    {
+        return (ast.getType() == CONSTANT) && 
+               (PredefinedType.booleanType.equals(ast.getTypeInfo()));
+    }
+
+    /**
+     * Returns the specified string w/o a long type suffix 'l' or 'L' or
+     * the specified string if there is no such suffix.
+     */
+    private String skipLongTypeSuffix(String txt)
+    {
+        int index = txt.length() - 1;
+        char last = txt.charAt(index);
+        return ((last == 'l') || (last == 'L')) ? txt.substring(0, index) : txt;
+    }
+
+    /**
+     * Returns the value of the specified field of the specified object.
+     * The method uses StateManager methods to access the field value, 
+     * if it is a managed field of a persistent instance. 
+     * Otherwise it uses reflection.
+     * @param javaField the field representation
+     * @param pm the pm used in case of a managed field of a persistent instance
+     * @param object the instance
+     * @return the field value
+     */
+    private Object getFieldValue(JavaField javaField, 
+                                 PersistenceManagerInternal pm, 
+                                 Object object)
+    {
+        int fieldNumber = 
+            TypeSupport.getFieldNumber(javaField.getJDOField(), pm, object);
+        if (fieldNumber == -1) 
+            return TypeSupport.getFieldValue(getAccessibleField(javaField), 
+                                             object);
+        else
+            return TypeSupport.getFieldValue(fieldNumber, pm, object);
+    }
+
+    /**
+     * Returns the value of the specified static field.
+     * @param javaField the field representation
+     * @return the field value
+     */
+    private Object getStaticFieldValue(JavaField javaField)
+    {
+        return TypeSupport.getFieldValue(getAccessibleField(javaField), null);
+    } 
+
+    /**
+     * Method executing TypeSupport.getAccessibleField in a doPrivileged block.
+     */
+    private Field getAccessibleField(final JavaField javaField)
+    {
+        return (Field) AccessController.doPrivileged(
+            new PrivilegedAction() {
+                public Object run () {
+                    return TypeSupport.getAccessibleField(javaField);
+                }});
+    }
+
+}
+
+// rules
+
+query!
+    :   #(  q:QUERY_TREE
+            c:candidateClass
+            p:parameters
+            v:variables
+            o:ordering
+            f:filter
+        )
+        {
+            Tree tree = new Tree((CandidateClassImpl)#c, (ParameterDecl)#p, 
+                                 (VariableDecl)#v, (OrderingExpr)#o, (Expr)#f);
+            tree.setType(QUERY_TREE);
+            tree.setText("QUERY_TREE"); //NOI18N
+            #query = tree;
+        }
+    ;
+
+// ----------------------------------
+// rules: candidate class
+// ----------------------------------
+
+candidateClass
+{   
+    errorMsg.setContext("setCandidates"); //NOI18N
+}
+    :   #(CANDIDATE_CLASS TYPE)
+    ;
+
+// ----------------------------------
+// rules: parameter declaration
+// ----------------------------------
+
+parameters
+{   
+    errorMsg.setContext("declareParameters"); //NOI18N
+}
+    :   ( declareParameter )*
+    ;
+
+declareParameter
+    :   #( PARAMETER_DECL TYPE ( IDENT )? )
+    ;
+
+// ----------------------------------
+// rules: variable declaration
+// ----------------------------------
+
+variables 
+{ 
+    errorMsg.setContext("declareVariables"); //NOI18N
+}
+    :   ( declareVariable )*
+    ;
+
+declareVariable
+    :   #( VARIABLE_DECL TYPE ( IDENT )? )
+    ;
+
+// ----------------------------------
+// rules: ordering specification
+// ----------------------------------
+
+ordering 
+{   
+    errorMsg.setContext("setOrdering"); //NOI18N
+}
+    :   ( orderSpec )*
+    ;
+
+orderSpec
+    :   #( ASCENDING expression )
+    |   #( DESCENDING expression )
+    ;
+
+// ----------------------------------
+// rules: filer expression
+// ----------------------------------
+
+filter
+{   
+    errorMsg.setContext("setFilter"); //NOI18N
+}
+    :   expression
+    ;
+
+expression 
+    :   primary
+    |   bitwiseExpr
+    |   conditionalExpr
+    |   relationalExpr
+    |   binaryArithmeticExpr
+    |   unaryArithmeticExpr
+    |   complementExpr
+    ;
+
+bitwiseExpr
+    :   #( op1:BAND left1:expression right1:expression )
+        {
+            #bitwiseExpr = checkAnd(#op1, #left1, #right1);
+        }
+    |   #( op2:BOR  left2:expression right2:expression )
+        {
+            #bitwiseExpr = checkOr(#op2, #left2, #right2);
+        }
+    ;
+
+conditionalExpr
+    :   #( op1:AND left1:expression right1:expression )
+        {
+            #conditionalExpr = checkAnd(#op1, #left1, #right1);
+        }
+    |   #( op2:OR  left2:expression right2:expression )
+        {
+            #conditionalExpr = checkOr(#op2, #left2, #right2);
+        }
+   ;
+
+relationalExpr
+    :   #( op1:EQUAL left1:expression right1:expression )
+        {
+            #relationalExpr = checkEqualityOp(#op1, #left1, #right1, false);
+        }
+    |   #( op2:NOT_EQUAL left2:expression right2:expression )
+        {
+            #relationalExpr = checkEqualityOp(#op2, #left2, #right2, true);
+        }
+    |   #( op3:OBJECT_EQUAL left3:expression right3:expression ) 
+        {
+            #relationalExpr = checkObjectEqualityOp(#op3, #left3, #right3, false);
+        }
+    |   #( op4:OBJECT_NOT_EQUAL left4:expression right4:expression )
+        {
+            #relationalExpr = checkObjectEqualityOp(#op4, #left4, #right4, true);
+        }
+    |   #( op5:COLLECTION_EQUAL left5:expression right5:expression )
+        {
+            #relationalExpr = checkCollectionEqualityOp(#op5, #left5, #right5, false);
+        }
+    |   #( op6:COLLECTION_NOT_EQUAL left6:expression right6:expression )
+        {
+            #relationalExpr = checkCollectionEqualityOp(#op6, #left6, #right6, true);
+        }
+    |   #( LT expression expression )
+    |   #( GT expression expression )
+    |   #( LE expression expression )
+    |   #( GE expression expression )
+    ;
+
+binaryArithmeticExpr
+    :   #( op1:PLUS   left1:expression right1:expression )
+        {
+            #binaryArithmeticExpr = checkBinaryPlusOp(#op1, #left1, #right1);
+        }
+    |   #( op2:CONCAT left2:expression right2:expression )
+        {
+            #binaryArithmeticExpr = checkConcatOp(#op2, #left2, #right2);
+        }
+    |   #( op3:MINUS  left3:expression right3:expression )
+        {
+            #binaryArithmeticExpr = checkBinaryMinusOp(#op3, #left3, #right3);
+        }
+    |   #( op4:STAR   left4:expression right4:expression )
+        {
+            #binaryArithmeticExpr = checkMultiplicationOp(#op4, #left4, #right4);
+        }
+    |   #( op5:DIV    left5:expression right5:expression )
+        {
+            #binaryArithmeticExpr = checkDivisionOp(#op5, #left5, #right5);
+        }
+    ;
+
+unaryArithmeticExpr 
+    :   #( UNARY_PLUS expression )
+    |   ( #( UNARY_MINUS ( INT_LITERAL | LONG_LITERAL ) ) )=> 
+        #( UNARY_MINUS l:integralLiteral[true] )
+        { 
+            #unaryArithmeticExpr = #l; 
+        }
+    |   #( op2:UNARY_MINUS arg2:expression )
+        {
+            #unaryArithmeticExpr = checkUnaryMinusOp(#op2, #arg2);
+        }
+    ;
+
+complementExpr 
+    :   #( op1:BNOT arg1:expression )
+    |   #( op2:LNOT arg2:expression )
+        {
+            #complementExpr = checkLogicalNotOp(#op2, #arg2);
+        }
+    ;
+
+primary 
+    :   #( CAST TYPE expression )
+    |   literal
+    |   THIS
+    |   parameterAccess
+    |   variableAccess
+    |   staticFieldAccess
+    |   fieldAccess
+    |   navigation
+    |   contains
+    |   startsWith
+    |   endsWith
+    |   isEmpty
+    ;
+
+literal
+    :   b1:TRUE
+        { 
+            ConstantExpr constant = ConstantExpr.newConstant(Boolean.TRUE);
+            constant.setType(CONSTANT);
+            constant.setText("true"); //NOI18N
+            constant.setTypeInfo(b1.getTypeInfo());
+            #literal = constant;
+        }
+    |   b2:FALSE
+        { 
+            ConstantExpr constant = ConstantExpr.newConstant(Boolean.FALSE);
+            constant.setType(CONSTANT);
+            constant.setText("false"); //NOI18N
+            constant.setTypeInfo(b2.getTypeInfo());
+            #literal = constant;
+        }
+    |   b3:BOOLEAN_LITERAL
+        {
+            b3.setType(CONSTANT);
+        }
+    |   integralLiteral[false]
+    |   f:FLOAT_LITERAL
+        {  
+            String txt = f.getText();
+            Float value = null;
+            try {
+                value = new Float(txt);
+            } 
+            catch (NumberFormatException ex) {
+                errorMsg.error(f.getLine(), f.getColumn(), 
+                    msg.msg("EXC_InvalidLiteral", "float", txt)); //NOI18N
+            }
+            ConstantExpr constant = ConstantExpr.newConstant(value);
+            constant.setType(CONSTANT);
+            constant.setText(f.getText());
+            constant.setTypeInfo(f.getTypeInfo());
+            #literal = constant;
+        }
+    |   d:DOUBLE_LITERAL
+        {  
+            String txt = d.getText();
+            Double value = null;
+            try {
+                value = new Double(txt);
+            } 
+            catch (NumberFormatException ex) {
+                errorMsg.error(d.getLine(), d.getColumn(), 
+                    msg.msg("EXC_InvalidLiteral", "double", txt)); //NOI18N
+            }
+            ConstantExpr constant = ConstantExpr.newConstant(value);
+            constant.setType(CONSTANT);
+            constant.setText(d.getText());
+            constant.setTypeInfo(d.getTypeInfo());
+            #literal = constant;
+        }
+    |   c:CHAR_LITERAL
+        { 
+            Character value = new Character(parseChar(c.getText())); 
+            ConstantExpr constant = ConstantExpr.newConstant(value);
+            constant.setType(CONSTANT);
+            constant.setText(c.getText());
+            constant.setTypeInfo(c.getTypeInfo());
+            #literal = constant;
+        }
+    |   s:STRING_LITERAL
+        { 
+            ConstantExpr constant = ConstantExpr.newConstant(s.getText());
+            constant.setType(CONSTANT);
+            constant.setText(s.getText());
+            constant.setTypeInfo(s.getTypeInfo());
+            #literal = constant;
+        }
+    |   n:NULL
+        { 
+            ConstantExpr constant = ConstantExpr.newConstant(null);
+            constant.setType(CONSTANT);
+            constant.setText("null"); //NOI18N
+            constant.setTypeInfo(n.getTypeInfo());
+            #literal = constant;
+        }
+    |   by:BYTE_LITERAL
+        {
+            by.setType(CONSTANT);
+        }
+    |   sh:SHORT_LITERAL
+        {
+            sh.setType(CONSTANT);
+        }
+    |   con:CONSTANT
+    ;
+
+integralLiteral! [boolean negate]
+    :   i:INT_LITERAL
+        { 
+            String txt = negate ? "-" + i.getText() : i.getText();
+            Integer value = null;
+            try {
+                value = Integer.decode(txt);
+            } 
+            catch (NumberFormatException ex) {
+                errorMsg.error(i.getLine(), i.getColumn(), 
+                    msg.msg("EXC_InvalidLiteral", "int", txt)); //NOI18N
+            }
+            ConstantExpr constant = ConstantExpr.newConstant(value);
+            constant.setType(CONSTANT);
+            constant.setText(txt);
+            constant.setTypeInfo(i.getTypeInfo());
+            #integralLiteral = constant;
+        }
+    |   l:LONG_LITERAL
+        {   
+            String txt = negate ? "-" + l.getText() : l.getText();
+            Long value = null;
+            try {
+                value = Long.decode(skipLongTypeSuffix(txt));
+            } 
+            catch (NumberFormatException ex) {
+                errorMsg.error(l.getLine(), l.getColumn(), 
+                    msg.msg("EXC_InvalidLiteral", "long", txt)); //NOI18N
+            }
+            ConstantExpr constant = ConstantExpr.newConstant(value);
+            constant.setType(CONSTANT);
+            constant.setText(txt);
+            constant.setTypeInfo(l.getTypeInfo());
+            #integralLiteral = constant;
+        }
+    ;
+
+parameterAccess
+    :   p:PARAMETER_ACCESS
+        {
+            if (optimizeParameters) {
+                Object value = paramtab.getValue(#p.getText());
+                ConstantExpr constant = ConstantExpr.newConstant(value);
+                constant.setType(CONSTANT);
+                constant.setText((value==null) ? "null" : value.toString()); //NOI18N
+                constant.setTypeInfo(#p.getTypeInfo());
+                #parameterAccess = constant;
+            }
+        }
+    ;
+
+variableAccess
+    :   #( VARIABLE_ACCESS ( expression )? )
+    ;
+
+staticFieldAccess!
+    :   #( s:STATIC_FIELD_ACCESS t:TYPE (i:IDENT)? )
+        {
+            // Calculate the value of the static field at compile time
+            // and treat it as constant value.
+            StaticFieldAccessExpr fieldAccess = (StaticFieldAccessExpr)#s;
+            String fieldName = fieldAccess.getName();
+            JavaField javaField = #t.getTypeInfo().getJavaField(fieldName);
+            Object value = getStaticFieldValue(javaField);
+            ConstantExpr constant = ConstantExpr.newConstant(value);
+            constant.setType(CONSTANT);
+            constant.setText((value==null) ? "null" : value.toString()); //NOI18N
+            constant.setTypeInfo(#s.getTypeInfo());
+            #staticFieldAccess = constant;
+        }
+    ;
+
+fieldAccess
+    :   #( f:FIELD_ACCESS o:expression ( i:IDENT )? )
+        {
+            if (#o.getType() == CONSTANT) {
+                // If the object of the field access is a constant value, 
+                // evaluate the field access at compile time and 
+                // treat the expression as constant value.
+                FieldAccessExpr fieldAccess = (FieldAccessExpr)#f;
+                String fieldName = fieldAccess.getName();
+                JavaField javaField = #o.getTypeInfo().getJavaField(fieldName);
+                Object value = getFieldValue(
+                    javaField, pm, ((ConstantExpr)#o).getValue());
+                ConstantExpr constant = ConstantExpr.newConstant(value);
+                constant.setType(CONSTANT);
+                constant.setText((value==null) ? "null" : value.toString()); //NOI18N
+                constant.setTypeInfo(#f.getTypeInfo());
+                #fieldAccess = constant;
+            }
+        }
+    ;
+
+navigation
+    :   #(  n:NAVIGATION o:expression ( i:IDENT )? )
+        {
+            if (#o.getType() == CONSTANT) {
+                // If the object of the navigation is a constant value, 
+                // evaluate the field access at compile time and 
+                // treat the expression as constant value.
+                FieldAccessExpr fieldAccess = (FieldAccessExpr)#n;
+                String fieldName = fieldAccess.getName();
+                JavaField javaField = #o.getTypeInfo().getJavaField(fieldName);
+                Object value = getFieldValue(
+                    javaField, pm, ((ConstantExpr)#o).getValue());
+                ConstantExpr constant = ConstantExpr.newConstant(value);
+                constant.setType(CONSTANT);
+                constant.setText((value==null) ? "null" : value.toString()); //NOI18N
+                constant.setTypeInfo(#n.getTypeInfo());
+                #navigation = constant;
+            }
+        }
+    ;
+
+contains
+    :   #( CONTAINS expression expression )
+    ;
+
+startsWith
+    :   #( STARTS_WITH expression expression ) 
+    ;
+
+endsWith
+    :   #( ENDS_WITH expression expression ) 
+    ;
+
+isEmpty
+    :   #( op:IS_EMPTY e:expression)
+        {
+            if (#e.getType() == CONSTANT) {
+                // If the expression that specifies the collection is a 
+                // constant value, evaluate the isEmpty call at compile time 
+                // and treat the expression as constant value.
+                Object object = ((ConstantExpr)#e).getValue();
+                Object value = null;
+                if (object == null) {
+                    value = new Boolean(false);
+                }
+                else if (object instanceof Collection) {
+                    value = new Boolean(((Collection)object).isEmpty());
+                }
+                else {
+                    errorMsg.fatal(msg.msg("ERR_OptmizerCollectionExpected", //NOI18N
+                            "isEmpty", object)); //NOI18N
+                }
+                ConstantExpr constant = ConstantExpr.newConstant(value);
+                constant.setType(CONSTANT);
+                constant.setText((value==null) ? "null" : value.toString()); //NOI18N
+                constant.setTypeInfo(#op.getTypeInfo());
+                #isEmpty = constant;
+            }
+        }
+    ;
+