cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aadamc...@apache.org
Subject svn commit: r932511 - in /cayenne/main/branches/STABLE-3.0: docs/doc/src/main/resources/ framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/ framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql...
Date Fri, 09 Apr 2010 17:06:27 GMT
Author: aadamchik
Date: Fri Apr  9 17:06:27 2010
New Revision: 932511

URL: http://svn.apache.org/viewvc?rev=932511&view=rev
Log:
CAY-1380 Support for Escaped LIKE Clauses in Expressions

patch by Andrew Lindesay

Added:
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java
Modified:
    cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssemblerHelper.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLike.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLikeIgnoreCase.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLike.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLikeIgnoreCase.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/PatternMatchNode.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
    cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/SelectQueryTest.java

Modified: cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt (original)
+++ cayenne/main/branches/STABLE-3.0/docs/doc/src/main/resources/RELEASE-NOTES.txt Fri Apr
 9 17:06:27 2010
@@ -15,6 +15,7 @@ Date: 
 Bug Fixes Since 3.0-final:
 
 CAY-1354 Wrong Types mapping for selected values in Row Queries
+CAY-1380 Support for Escaped LIKE Clauses in Expressions
 CAY-1402 Ability to use Terminating "@size" in Nested Properties Against Collections
 CAY-1416 ExpressionFactory.noMatchExp.toEJBQL() produces incorrect output
 CAY-1417 EJBQL doesn't support null numeric parameters

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java
(original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java
Fri Apr  9 17:06:27 2010
@@ -40,6 +40,7 @@ import org.apache.cayenne.query.Qualifie
 import org.apache.cayenne.query.Query;
 import org.apache.commons.collections.IteratorUtils;
 import org.apache.commons.collections.Transformer;
+import org.apache.cayenne.exp.parser.PatternMatchNode;
 
 /**
  * Translates query qualifier to SQL. Used as a helper class by query translators.
@@ -345,14 +346,23 @@ public class QualifierTranslator extends
                 appendObjectMatch();
             }
 
-            if (parenthesisNeeded(node, parentNode)) {
+            boolean parenthesisNeeded = parenthesisNeeded(node, parentNode);
+            boolean likeIgnoreCase = (node.getType() == Expression.LIKE_IGNORE_CASE || node
+                    .getType() == Expression.NOT_LIKE_IGNORE_CASE);
+            boolean isPatternMatchNode = PatternMatchNode.class.isAssignableFrom(node
+                    .getClass());
+
+            if (isPatternMatchNode && !likeIgnoreCase)
+                appendLikeEscapeCharacter((PatternMatchNode) node);
+
+            if (parenthesisNeeded)
                 out.append(')');
-            }
 
-            if (node.getType() == Expression.LIKE_IGNORE_CASE
-                    || node.getType() == Expression.NOT_LIKE_IGNORE_CASE) {
+            if (isPatternMatchNode && likeIgnoreCase)
+                appendLikeEscapeCharacter((PatternMatchNode) node);
+
+            if (likeIgnoreCase)
                 out.append(')');
-            }
         }
         catch (IOException ioex) {
             throw new CayenneRuntimeException("Error appending content", ioex);

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssemblerHelper.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssemblerHelper.java?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssemblerHelper.java
(original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssemblerHelper.java
Fri Apr  9 17:06:27 2010
@@ -25,6 +25,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.cayenne.exp.parser.PatternMatchNode;
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.Persistent;
@@ -103,6 +104,33 @@ public abstract class QueryAssemblerHelp
     protected abstract void doAppendPart() throws IOException;
 
     /**
+     * Outputs the standard JDBC (database agnostic) expression for supplying the escape
+     * character to the database server when supplying a LIKE clause. This has been
+     * factored-out because some database adaptors handle LIKE differently and they need
+     * access to this common method in order not to repeat this code. </p>
+     * <p>
+     * If there is no escape character defined then this method will not output anything.
+     * An escape character of 0 will mean no escape character.
+     * 
+     * @since 3.0.1
+     */
+    protected void appendLikeEscapeCharacter(PatternMatchNode patternMatchNode)
+            throws IOException {
+        char escapeChar = patternMatchNode.getEscapeChar();
+
+        if ('?' == escapeChar) {
+            throw new CayenneRuntimeException(
+                    "the escape character of '?' is illegal for LIKE clauses.");
+        }
+
+        if (0 != escapeChar) {
+            out.append(" {escape '");
+            out.append(escapeChar);
+            out.append("'}");
+        }
+    }
+    
+    /**
      * Processes parts of the OBJ_PATH expression.
      */
     protected void appendObjPath(Expression pathExp) throws IOException {

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java
(original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java
Fri Apr  9 17:06:27 2010
@@ -33,6 +33,8 @@ import org.apache.cayenne.access.jdbc.EJ
 import org.apache.cayenne.access.types.ByteArrayType;
 import org.apache.cayenne.access.types.CharType;
 import org.apache.cayenne.access.types.ExtendedTypeMap;
+import org.apache.cayenne.access.trans.QualifierTranslator;
+import org.apache.cayenne.access.trans.QueryAssembler;
 import org.apache.cayenne.dba.JdbcAdapter;
 import org.apache.cayenne.dba.PkGenerator;
 import org.apache.cayenne.dba.QuotingStrategy;
@@ -87,6 +89,11 @@ public class MySQLAdapter extends JdbcAd
         this.identifiersStartQuote = MYSQL_QUOTE_SQL_IDENTIFIERS_CHAR_START;
         this.identifiersEndQuote = MYSQL_QUOTE_SQL_IDENTIFIERS_CHAR_END;
     }
+    
+    @Override
+    public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) {
+        return new MySQLQualifierTranslator(queryAssembler);
+    }
 
     /**
      * Uses special action builder to create the right action.

Added: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java?rev=932511&view=auto
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java
(added)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java
Fri Apr  9 17:06:27 2010
@@ -0,0 +1,54 @@
+/*****************************************************************
+ *   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.dba.mysql;
+
+import java.io.IOException;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.access.trans.QualifierTranslator;
+import org.apache.cayenne.access.trans.QueryAssembler;
+import org.apache.cayenne.exp.parser.PatternMatchNode;
+
+class MySQLQualifierTranslator extends QualifierTranslator {
+
+    public MySQLQualifierTranslator(QueryAssembler queryAssembler) {
+        super(queryAssembler);
+    }
+
+    @Override
+    protected void appendLikeEscapeCharacter(PatternMatchNode patternMatchNode)
+            throws IOException {
+
+        char escapeChar = patternMatchNode.getEscapeChar();
+
+        if ('?' == escapeChar) {
+            throw new CayenneRuntimeException(
+                    "the escape character of '?' is illegal for LIKE clauses.");
+        }
+
+        if (0 != escapeChar) {
+            // this is a difference with super implementation - MySQL driver does not
+            // support JDBC escape syntax, so creating an explicit SQL escape:
+            out.append(" ESCAPE '");
+            out.append(escapeChar);
+            out.append("'");
+        }
+    }
+
+}

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java
(original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java
Fri Apr  9 17:06:27 2010
@@ -25,6 +25,7 @@ import org.apache.cayenne.CayenneRuntime
 import org.apache.cayenne.access.trans.QualifierTranslator;
 import org.apache.cayenne.access.trans.QueryAssembler;
 import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.PatternMatchNode;
 import org.apache.cayenne.map.DbAttribute;
 
 /**
@@ -75,6 +76,9 @@ public class OpenBaseQualifierTranslator
                     appendObjectMatch();
                 }
 
+                if(PatternMatchNode.class.isAssignableFrom(node.getClass()))
+                    appendLikeEscapeCharacter((PatternMatchNode) node);
+                
                 if (parenthesisNeeded(node, parentNode))
                     out.append(')');
 

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java
(original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java
Fri Apr  9 17:06:27 2010
@@ -25,6 +25,7 @@ import org.apache.cayenne.CayenneRuntime
 import org.apache.cayenne.access.trans.QueryAssembler;
 import org.apache.cayenne.access.trans.TrimmingQualifierTranslator;
 import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.PatternMatchNode;
 
 /**
  * Uses Postgres extensions to optimize various translations.
@@ -73,6 +74,9 @@ public class PostgresQualifierTranslator
                 if (matchingObject) {
                     appendObjectMatch();
                 }
+                
+                if(PatternMatchNode.class.isAssignableFrom(node.getClass()))
+                    appendLikeEscapeCharacter((PatternMatchNode) node);
 
                 if (parenthesisNeeded(node, parentNode))
                     out.append(')');

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java
(original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java
Fri Apr  9 17:06:27 2010
@@ -576,6 +576,20 @@ public class ExpressionFactory {
     }
 
     /**
+     * <p>A convenience shortcut for building LIKE expression.</p>
+     * 
+     * <p>The escape character allows for escaping meta-characters
+     * in the LIKE clause.  Note that the escape character cannot
+     * be '?'.  To specify no escape character, supply 0 as the
+     * escape character.</p>
+     * 
+     * @since 3.0.1
+     */
+    public static Expression likeExp(String pathSpec, Object value, char escapeChar) {
+        return new ASTLike(new ASTObjPath(pathSpec), value, escapeChar);
+    }
+    
+    /**
      * A convenience shortcut for building LIKE DB_PATH expression.
      * 
      * @since 3.0
@@ -585,11 +599,39 @@ public class ExpressionFactory {
     }
 
     /**
+     * <p>A convenience shortcut for building LIKE DB_PATH expression.</p>
+     * 
+     * <p>The escape character allows for escaping meta-characters
+     * in the LIKE clause.  Note that the escape character cannot
+     * be '?'.  To specify no escape character, supply 0 as the
+     * escape character.</p>
+     * 
+     * @since 3.0.1
+     */
+    public static Expression likeDbExp(String pathSpec, Object value, char escapeChar) {
+        return new ASTLike(new ASTDbPath(pathSpec), value,escapeChar);
+    }
+    
+    /**
      * A convenience shortcut for building NOT_LIKE expression.
      */
     public static Expression notLikeExp(String pathSpec, Object value) {
         return new ASTNotLike(new ASTObjPath(pathSpec), value);
     }
+    
+    /**
+     * <p>A convenience shortcut for building NOT_LIKE expression.</p>
+     * 
+     * <p>The escape character allows for escaping meta-characters
+     * in the LIKE clause.  Note that the escape character cannot
+     * be '?'.  To specify no escape character, supply 0 as the
+     * escape character.</p>
+     * 
+     * @since 3.0.1
+     */
+    public static Expression notLikeExp(String pathSpec, Object value, char escapeChar) {
+        return new ASTNotLike(new ASTObjPath(pathSpec), value, escapeChar);
+    }
 
     /**
      * A convenience shortcut for building NOT_LIKE expression.
@@ -599,15 +641,44 @@ public class ExpressionFactory {
     public static Expression notLikeDbExp(String pathSpec, Object value) {
         return new ASTNotLike(new ASTDbPath(pathSpec), value);
     }
+    
+    /**
+     * <p>A convenience shortcut for building NOT_LIKE expression.</p>
+     *
+     * <p>The escape character allows for escaping meta-characters
+     * in the LIKE clause.  Note that the escape character cannot
+     * be '?'.  To specify no escape character, supply 0 as the
+     * escape character.</p>
+     * 
+     * @since 3.0.1
+     */
+    public static Expression notLikeDbExp(String pathSpec, Object value, char escapeChar)
{
+        return new ASTNotLike(new ASTDbPath(pathSpec), value, escapeChar);
+    }
 
     /**
      * A convenience shortcut for building LIKE_IGNORE_CASE expression.
      */
+    
     public static Expression likeIgnoreCaseExp(String pathSpec, Object value) {
         return new ASTLikeIgnoreCase(new ASTObjPath(pathSpec), value);
     }
 
     /**
+     * <p>A convenience shortcut for building LIKE_IGNORE_CASE expression.</p>
+     *
+     * <p>The escape character allows for escaping meta-characters
+     * in the LIKE clause.  Note that the escape character cannot
+     * be '?'.  To specify no escape character, supply 0 as the
+     * escape character.</p>
+     * 
+     * @since 3.0.1
+     */
+    public static Expression likeIgnoreCaseExp(String pathSpec, Object value, char escapeChar)
{
+        return new ASTLikeIgnoreCase(new ASTObjPath(pathSpec), value, escapeChar);
+    }
+    
+    /**
      * A convenience shortcut for building LIKE_IGNORE_CASE expression.
      * 
      * @since 3.0
@@ -615,6 +686,20 @@ public class ExpressionFactory {
     public static Expression likeIgnoreCaseDbExp(String pathSpec, Object value) {
         return new ASTLikeIgnoreCase(new ASTDbPath(pathSpec), value);
     }
+    
+    /**
+     * <p>A convenience shortcut for building LIKE_IGNORE_CASE expression.</p>
+     * 
+     * <p>The escape character allows for escaping meta-characters
+     * in the LIKE clause.  Note that the escape character cannot
+     * be '?'.  To specify no escape character, supply 0 as the
+     * escape character.</p>
+     * 
+     * @since 3.0.1
+     */
+    public static Expression likeIgnoreCaseDbExp(String pathSpec, Object value, char escapeChar)
{
+        return new ASTLikeIgnoreCase(new ASTDbPath(pathSpec), value, escapeChar);
+    }
 
     /**
      * A convenience shortcut for building NOT_LIKE_IGNORE_CASE expression.
@@ -624,6 +709,20 @@ public class ExpressionFactory {
     }
 
     /**
+     * <p>A convenience shortcut for building NOT_LIKE_IGNORE_CASE expression.</p>
+     * 
+     * <p>The escape character allows for escaping meta-characters
+     * in the LIKE clause.  Note that the escape character cannot
+     * be '?'.  To specify no escape character, supply 0 as the
+     * escape character.</p>
+     * 
+     * @since 3.0.1
+     */ 
+    public static Expression notLikeIgnoreCaseExp(String pathSpec, Object value, char escapeChar)
{
+        return new ASTNotLikeIgnoreCase(new ASTObjPath(pathSpec), value, escapeChar);
+    }
+    
+    /**
      * A convenience shortcut for building NOT_LIKE_IGNORE_CASE expression.
      * 
      * @since 3.0
@@ -633,6 +732,20 @@ public class ExpressionFactory {
     }
 
     /**
+     * <p>A convenience shortcut for building NOT_LIKE_IGNORE_CASE expression.</p>
+     * 
+     * <p>The escape character allows for escaping meta-characters
+     * in the LIKE clause.  Note that the escape character cannot
+     * be '?'.  To specify no escape character, supply 0 as the
+     * escape character.</p>
+     * 
+     * @since 3.0.1
+     */
+    public static Expression notLikeIgnoreCaseDbExp(String pathSpec, Object value, char escapeChar)
{
+        return new ASTNotLikeIgnoreCase(new ASTDbPath(pathSpec), value, escapeChar);
+    }
+    
+    /**
      * A convenience shortcut for boolean true expression.
      * 
      * @since 3.0

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLike.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLike.java?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLike.java
(original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLike.java
Fri Apr  9 17:06:27 2010
@@ -30,6 +30,10 @@ public class ASTLike extends PatternMatc
     ASTLike(int id) {
         super(id, false);
     }
+    
+    ASTLike(int id, char escapeChar) {
+        super(id, false, escapeChar);
+    }
 
     public ASTLike() {
         super(ExpressionParserTreeConstants.JJTLIKE, false);
@@ -42,6 +46,13 @@ public class ASTLike extends PatternMatc
         connectChildren();
     }
 
+    public ASTLike(ASTPath path, Object pattern, char escapeChar) {
+        super(ExpressionParserTreeConstants.JJTLIKE, false, escapeChar);
+        jjtAddChild(path, 0);
+        jjtAddChild(new ASTScalar(pattern), 1);
+        connectChildren();
+    }
+    
     @Override
     protected Object evaluateNode(Object o) throws Exception {
         int len = jjtGetNumChildren();
@@ -62,7 +73,7 @@ public class ASTLike extends PatternMatc
      */
     @Override
     public Expression shallowCopy() {
-        return new ASTLike(id);
+        return new ASTLike(id, escapeChar);
     }
 
     @Override

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLikeIgnoreCase.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLikeIgnoreCase.java?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLikeIgnoreCase.java
(original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLikeIgnoreCase.java
Fri Apr  9 17:06:27 2010
@@ -30,6 +30,10 @@ public class ASTLikeIgnoreCase extends I
     ASTLikeIgnoreCase(int id) {
         super(id, true);
     }
+    
+    ASTLikeIgnoreCase(int id, char escapeChar) {
+        super(id, true, escapeChar);
+    }
 
     public ASTLikeIgnoreCase() {
         super(ExpressionParserTreeConstants.JJTLIKEIGNORECASE, true);
@@ -41,6 +45,13 @@ public class ASTLikeIgnoreCase extends I
         jjtAddChild(new ASTScalar(pattern), 1);
         connectChildren();
     }
+    
+    public ASTLikeIgnoreCase(ASTPath path, Object pattern, char escapeChar) {
+        super(ExpressionParserTreeConstants.JJTLIKEIGNORECASE, true, escapeChar);
+        jjtAddChild(path, 0);
+        jjtAddChild(new ASTScalar(pattern), 1);
+        connectChildren();
+    }
 
     @Override
     protected Object evaluateNode(Object o) throws Exception {
@@ -62,7 +73,7 @@ public class ASTLikeIgnoreCase extends I
      */
     @Override
     public Expression shallowCopy() {
-        return new ASTLikeIgnoreCase(id);
+        return new ASTLikeIgnoreCase(id, escapeChar);
     }
 
     @Override

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLike.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLike.java?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLike.java
(original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLike.java
Fri Apr  9 17:06:27 2010
@@ -43,6 +43,13 @@ public class ASTNotLike extends PatternM
         jjtAddChild(new ASTScalar(value), 1);
         connectChildren();
     }
+    
+    public ASTNotLike(ASTPath path, Object value, char escapeChar) {
+        super(ExpressionParserTreeConstants.JJTNOTLIKE, false, escapeChar);
+        jjtAddChild(path, 0);
+        jjtAddChild(new ASTScalar(value), 1);
+        connectChildren();
+    }
 
     @Override
     protected Object evaluateNode(Object o) throws Exception {

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLikeIgnoreCase.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLikeIgnoreCase.java?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLikeIgnoreCase.java
(original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLikeIgnoreCase.java
Fri Apr  9 17:06:27 2010
@@ -42,6 +42,13 @@ public class ASTNotLikeIgnoreCase extend
         jjtAddChild(new ASTScalar(value), 1);
         connectChildren();
     }
+    
+    public ASTNotLikeIgnoreCase(ASTPath path, Object value, char escapeChar) {
+        super(ExpressionParserTreeConstants.JJTNOTLIKEIGNORECASE, true, escapeChar);
+        jjtAddChild(path, 0);
+        jjtAddChild(new ASTScalar(value), 1);
+        connectChildren();
+    }
 
     @Override
     protected Object evaluateNode(Object o) throws Exception {

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java
(original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java
Fri Apr  9 17:06:27 2010
@@ -26,19 +26,25 @@ import org.apache.cayenne.exp.Expression
  * Common node for likeIgnoreCase and notLikeIgnoreCase
  */
 abstract class IgnoreCaseNode extends PatternMatchNode {
+
     IgnoreCaseNode(int i, boolean ignoringCase) {
         super(i, ignoringCase);
     }
-    
+
+    IgnoreCaseNode(int i, boolean ignoringCase, char escapeChar) {
+        super(i, ignoringCase, escapeChar);
+    }
+
     @Override
     protected void encodeChildrenAsEJBQL(PrintWriter pw, String rootId) {
-        //with like, first expression is always path, second is a literal, which must be
uppercased
+        // with like, first expression is always path, second is a literal, which must be
+        // uppercased
         pw.print("upper(");
         ((SimpleNode) children[0]).encodeAsEJBQL(pw, rootId);
         pw.print(") ");
         pw.print(getEJBQLExpressionOperator(0));
         pw.print(" ");
-        
+
         Object literal = ((ASTScalar) children[1]).getValue();
         if (!(literal instanceof String)) {
             throw new ExpressionException("Literal value should be a string");

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/PatternMatchNode.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/PatternMatchNode.java?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/PatternMatchNode.java
(original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/PatternMatchNode.java
Fri Apr  9 17:06:27 2010
@@ -21,6 +21,7 @@ package org.apache.cayenne.exp.parser;
 
 import java.util.regex.Pattern;
 
+import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.util.Util;
 
 /**
@@ -34,11 +35,45 @@ public abstract class PatternMatchNode e
     protected Pattern pattern;
     protected boolean patternCompiled;
     protected boolean ignoringCase;
+    protected char escapeChar;
 
     PatternMatchNode(int i, boolean ignoringCase) {
         super(i);
         this.ignoringCase = ignoringCase;
     }
+    
+    PatternMatchNode(int i, boolean ignoringCase, char escapeChar) {
+        super(i);
+        this.ignoringCase = ignoringCase;
+        setEscapeChar(escapeChar);
+    }
+    
+    /**
+     * <p>This method will return an escape character for the like
+     * clause.  The escape character will eventually end up in the
+     * query as <code>...(t0.foo LIKE ? {escape '|'}) where the
+     * pipe symbol is the escape character.</p>
+     *
+     * <p>Note that having no escape character is represented as 
+     * the character 0.</p>
+     */
+    
+    public char getEscapeChar() { return escapeChar; }
+    
+    /**
+     * <p>This method allows the setting of the escape character.
+     * The escape character can be used in a LIKE clause.  The
+     * character 0 signifies no escape character.  The escape
+     * characyer '?' is disallowed.</p>
+     */
+    
+    public void setEscapeChar(char value) {
+        
+        if('?'==value)
+            throw new CayenneRuntimeException("the use of the '?' as an escape character
in LIKE clauses is disallowed.");
+        
+        escapeChar = value;
+    }
 
     protected boolean matchPattern(String string) {
         return (string != null) ? getPattern().matcher(string).find() : false;

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
(original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
Fri Apr  9 17:06:27 2010
@@ -30,6 +30,8 @@ import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.Persistent;
 import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.unit.CayenneCase;
+import org.apache.cayenne.exp.parser.ASTLike;
+import org.apache.cayenne.exp.parser.ASTLikeIgnoreCase;
 
 public class ExpressionFactoryTest extends CayenneCase {
 
@@ -188,11 +190,33 @@ public class ExpressionFactoryTest exten
         Expression path = (Expression) exp.getOperand(0);
         assertEquals(Expression.DB_PATH, path.getType());
     }
+    
+    public void testLikeExpEscape() throws Exception {
+        String v = "abc";
+        Expression exp = ExpressionFactory.likeExp("=abc", v, '=');
+        assertEquals(Expression.LIKE, exp.getType());
+        
+        assertEquals('=', ((ASTLike) exp).getEscapeChar());
+
+        Expression path = (Expression) exp.getOperand(0);
+        assertEquals(Expression.OBJ_PATH, path.getType());
+    }
 
     public void testLikeIgnoreCaseExp() throws Exception {
         String v = "abc";
         Expression exp = ExpressionFactory.likeIgnoreCaseExp("abc", v);
         assertEquals(Expression.LIKE_IGNORE_CASE, exp.getType());
+        assertEquals(0, ((ASTLikeIgnoreCase) exp).getEscapeChar());
+
+	    Expression path = (Expression) exp.getOperand(0);
+		assertEquals(Expression.OBJ_PATH, path.getType());
+	}
+
+	public void testLikeIgnoreCaseExpEscape() throws Exception {
+	    String v = "abc";
+		Expression exp = ExpressionFactory.likeIgnoreCaseExp("=abc", v, '=');
+		assertEquals(Expression.LIKE_IGNORE_CASE, exp.getType());
+		assertEquals('=', ((ASTLikeIgnoreCase) exp).getEscapeChar());
 
         Expression path = (Expression) exp.getOperand(0);
         assertEquals(Expression.OBJ_PATH, path.getType());

Modified: cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/SelectQueryTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/SelectQueryTest.java?rev=932511&r1=932510&r2=932511&view=diff
==============================================================================
--- cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/SelectQueryTest.java
(original)
+++ cayenne/main/branches/STABLE-3.0/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/SelectQueryTest.java
Fri Apr  9 17:06:27 2010
@@ -37,6 +37,8 @@ import org.apache.cayenne.exp.Expression
 import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.ObjRelationship;
+// TODO CAY-1380
+// import org.apache.cayenne.test.TableHelper;
 
 public class SelectQueryTest extends SelectQueryBase {
 
@@ -210,6 +212,24 @@ public class SelectQueryTest extends Sel
         assertNotNull(objects);
         assertEquals(1, objects.size());
     }
+    
+    // TODO CAY-1380
+    /*
+    public void testSelectLikeSingleWildcardMatchAndEscape() throws Exception {
+
+        TableHelper artistHelper = new TableHelper(getDbHelper(), "ARTIST");
+        artistHelper.deleteAll();
+        artistHelper.setColumns("ARTIST_ID", "ARTIST_NAME");
+        artistHelper.insert(1, "_X");
+        artistHelper.insert(2, "Y_");
+
+        SelectQuery query = new SelectQuery(Artist.class);
+        query.andQualifier(ExpressionFactory.likeExp("artistName", "=_%", '='));
+ 
+        List objects = createDataContext().performQuery(query);
+        assertEquals(1, objects.size());
+    }
+    */
 
     public void testSelectLikeMultipleWildcardMatch() throws Exception {
         query.setRoot(Artist.class);



Mime
View raw message