You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by an...@apache.org on 2010/01/24 13:26:55 UTC

svn commit: r902551 - in /cayenne/main/trunk: docs/doc/src/main/resources/ framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/ framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/ framework/...

Author: andrey
Date: Sun Jan 24 12:26:55 2010
New Revision: 902551

URL: http://svn.apache.org/viewvc?rev=902551&view=rev
Log:
CAY-1371 EJBQL query doesn't preserve grouping by brackets

Added:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/AggregateConditionNode.java
Modified:
    cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLAnd.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLNot.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLOr.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/EJBQLQueryTest.java

Modified: cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt?rev=902551&r1=902550&r2=902551&view=diff
==============================================================================
--- cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt (original)
+++ cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt Sun Jan 24 12:26:55 2010
@@ -59,6 +59,7 @@
 CAY-1365 "= NULL" being used instead of "IS NULL" on an EJBQL expression..
 CAY-1368 Left Join and Prefetches do not work together
 CAY-1369 EJBQL: Fix likeIgnoreCase issues
+CAY-1371 EJBQL query doesn't preserve grouping by brackets
 
 ----------------------------------
 Release: 3.0 RC 1

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java?rev=902551&r1=902550&r2=902551&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java Sun Jan 24 12:26:55 2010
@@ -31,6 +31,7 @@
 import org.apache.cayenne.ejbql.EJBQLBaseVisitor;
 import org.apache.cayenne.ejbql.EJBQLException;
 import org.apache.cayenne.ejbql.EJBQLExpression;
+import org.apache.cayenne.ejbql.parser.AggregateConditionNode;
 import org.apache.cayenne.ejbql.parser.EJBQLDecimalLiteral;
 import org.apache.cayenne.ejbql.parser.EJBQLEquals;
 import org.apache.cayenne.ejbql.parser.EJBQLIdentificationVariable;
@@ -80,7 +81,7 @@
 
     @Override
     public boolean visitAnd(EJBQLExpression expression, int finishedChildIndex) {
-        afterChild(expression, " AND", finishedChildIndex);
+        visitConditional((AggregateConditionNode) expression, " AND", finishedChildIndex);
         return true;
     }
 
@@ -380,7 +381,7 @@
 
     @Override
     public boolean visitOr(EJBQLExpression expression, int finishedChildIndex) {
-        afterChild(expression, " OR", finishedChildIndex);
+        visitConditional((AggregateConditionNode) expression, " OR", finishedChildIndex);
         return true;
     }
 
@@ -572,6 +573,29 @@
 
         return true;
     }
+    
+    /**
+     * Visits conditional node, suppling brackets if needed
+     */
+    void visitConditional(AggregateConditionNode e, String afterText, int childIndex) {
+        if (childIndex == -1 && needBracket(e)) {
+            context.append(" (");
+        }
+
+        afterChild(e, afterText, childIndex);
+        
+        if (childIndex == e.getChildrenCount() - 1 && needBracket(e)) {
+            context.append(")");
+        }
+    }
+    
+    /**
+     * Checks whether expression needs to be rounded by brackets
+     */
+    boolean needBracket(AggregateConditionNode e) {
+        return (e.jjtGetParent() instanceof AggregateConditionNode) &&
+            e.getPriority() > ((AggregateConditionNode) e.jjtGetParent()).getPriority();
+    }
 
     protected void afterChild(EJBQLExpression e, String text, int childIndex) {
         if (childIndex >= 0) {

Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/AggregateConditionNode.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/AggregateConditionNode.java?rev=902551&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/AggregateConditionNode.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/AggregateConditionNode.java Sun Jan 24 12:26:55 2010
@@ -0,0 +1,42 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.cayenne.ejbql.parser;
+
+/**
+ * Superclass of aggregated conditional nodes such as NOT, AND, OR. 
+ * Defines priority of operations, so that SQL can be supplied with brackets as needed
+ * 
+ * @since 3.0
+ */
+public abstract class AggregateConditionNode extends SimpleNode {
+    //defining all priorities here so that it would be easy to compare them visually
+    static final int NOT_PRIORITY = 10;
+    static final int AND_PRIORITY = 20;
+    static final int OR_PRIORITY = 30;
+    
+    public AggregateConditionNode(int id) {
+        super(id);
+    }
+    
+    /**
+     * Returns priority of conditional operator. 
+     * This is used to decide whether brackets are needed in resulting SQL 
+     */
+    public abstract int getPriority();
+}

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLAnd.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLAnd.java?rev=902551&r1=902550&r2=902551&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLAnd.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLAnd.java Sun Jan 24 12:26:55 2010
@@ -23,7 +23,7 @@
 /**
  * @since 3.0
  */
-public class EJBQLAnd extends SimpleNode {
+public class EJBQLAnd extends AggregateConditionNode {
 
     public EJBQLAnd(int id) {
         super(id);
@@ -39,4 +39,9 @@
         return super.visitChild(visitor, childIndex)
                 && visitor.visitAnd(this, childIndex);
     }
+
+    @Override
+    public int getPriority() {
+        return AND_PRIORITY;
+    }
 }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLNot.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLNot.java?rev=902551&r1=902550&r2=902551&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLNot.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLNot.java Sun Jan 24 12:26:55 2010
@@ -23,7 +23,7 @@
 /**
  * @since 3.0
  */
-public class EJBQLNot extends SimpleNode {
+public class EJBQLNot extends AggregateConditionNode {
 
     public EJBQLNot(int id) {
         super(id);
@@ -33,4 +33,9 @@
     protected boolean visitNode(EJBQLExpressionVisitor visitor) {
         return visitor.visitNot(this);
     }
+
+    @Override
+    public int getPriority() {
+        return NOT_PRIORITY;
+    }
 }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLOr.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLOr.java?rev=902551&r1=902550&r2=902551&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLOr.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLOr.java Sun Jan 24 12:26:55 2010
@@ -23,7 +23,7 @@
 /**
  * @since 3.0
  */
-public class EJBQLOr extends SimpleNode {
+public class EJBQLOr extends AggregateConditionNode {
 
     public EJBQLOr(int id) {
         super(id);
@@ -38,4 +38,9 @@
     protected boolean visitChild(EJBQLExpressionVisitor visitor, int childIndex) {
         return super.visitChild(visitor, childIndex) && visitor.visitOr(this, childIndex);
     }
+
+    @Override
+    public int getPriority() {
+        return OR_PRIORITY;
+    }
 }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/EJBQLQueryTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/EJBQLQueryTest.java?rev=902551&r1=902550&r2=902551&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/EJBQLQueryTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/EJBQLQueryTest.java Sun Jan 24 12:26:55 2010
@@ -339,4 +339,39 @@
     
         context.performQuery(query);
     }
+    
+    public void testOrBrackets() throws Exception {
+        deleteTestData();
+        ObjectContext context = createDataContext();
+        
+        Artist a = context.newObject(Artist.class);
+        a.setArtistName("testOrBrackets");
+        context.commitChanges();
+        
+        //this query is equivalent to (false and (false or true)) and
+        //should always return 0 rows
+        EJBQLQuery query = new EJBQLQuery("select a from Artist a " +
+    		"where a.artistName <> a.artistName and " +
+    		"(a.artistName <> a.artistName or a.artistName = a.artistName)");
+        assertEquals(context.performQuery(query).size(), 0);
+        
+        //on the other hand, the following is equivalent to (false and false) or true) and
+        //should return >0 rows
+        query = new EJBQLQuery("select a from Artist a " +
+            "where a.artistName <> a.artistName and " +
+            "a.artistName <> a.artistName or a.artistName = a.artistName");
+        assertTrue(context.performQuery(query).size() > 0);
+        
+        //checking brackets around not
+        query = new EJBQLQuery("select a from Artist a " +
+            "where not(a.artistName <> a.artistName and " +
+            "a.artistName <> a.artistName or a.artistName = a.artistName)");
+        assertEquals(context.performQuery(query).size(), 0);
+        
+        //not is first to process
+        query = new EJBQLQuery("select a from Artist a " +
+                "where not a.artistName <> a.artistName or " +
+                "a.artistName = a.artistName");
+        assertTrue(context.performQuery(query).size() > 0);
+    }
 }