You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2010/01/31 19:48:04 UTC
svn commit: r905095 - in /cayenne/main/trunk: 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/
framework/ca...
Author: aadamchik
Date: Sun Jan 31 18:48:03 2010
New Revision: 905095
URL: http://svn.apache.org/viewvc?rev=905095&view=rev
Log:
CAY-1380 Support for Escaped LIKE Clauses in Expressions
patch by Andrew Lindesay
Additions by Andrus:
+ unit tests
+ MySQL support
Added:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.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/trans/QualifierTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssemblerHelper.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLike.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLikeIgnoreCase.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLike.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLikeIgnoreCase.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/PatternMatchNode.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/SelectQueryTest.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=905095&r1=905094&r2=905095&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 31 18:48:03 2010
@@ -28,6 +28,7 @@
CAY-1340 Implement ConfigurationNode / ConfigurationNodeVisitor for the Cayenne project tree, including DataMap objects.
CAY-1342 Remove wocompat package from Cayenne core
CAY-1350 Implement memorized sorting of modeler columns
+CAY-1380 Support for Escaped LIKE Clauses in Expressions
Bug Fixes Since 3.0:
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java?rev=905095&r1=905094&r2=905095&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java Sun Jan 31 18:48:03 2010
@@ -30,6 +30,7 @@
import org.apache.cayenne.exp.TraversalHandler;
import org.apache.cayenne.exp.parser.ASTDbPath;
import org.apache.cayenne.exp.parser.ASTObjPath;
+import org.apache.cayenne.exp.parser.PatternMatchNode;
import org.apache.cayenne.exp.parser.SimpleNode;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.DbRelationship;
@@ -346,14 +347,23 @@
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/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssemblerHelper.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssemblerHelper.java?rev=905095&r1=905094&r2=905095&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssemblerHelper.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssemblerHelper.java Sun Jan 31 18:48:03 2010
@@ -30,6 +30,7 @@
import org.apache.cayenne.Persistent;
import org.apache.cayenne.dba.QuotingStrategy;
import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.PatternMatchNode;
import org.apache.cayenne.exp.parser.SimpleNode;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.DbEntity;
@@ -108,6 +109,33 @@
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.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/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java?rev=905095&r1=905094&r2=905095&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java Sun Jan 31 18:48:03 2010
@@ -31,6 +31,8 @@
import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.access.jdbc.EJBQLTranslatorFactory;
+import org.apache.cayenne.access.trans.QualifierTranslator;
+import org.apache.cayenne.access.trans.QueryAssembler;
import org.apache.cayenne.access.types.ByteArrayType;
import org.apache.cayenne.access.types.CharType;
import org.apache.cayenne.access.types.ExtendedTypeMap;
@@ -94,6 +96,11 @@
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/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java?rev=905095&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java Sun Jan 31 18:48:03 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/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java?rev=905095&r1=905094&r2=905095&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java Sun Jan 31 18:48:03 2010
@@ -25,6 +25,7 @@
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 @@
appendObjectMatch();
}
+ if(PatternMatchNode.class.isAssignableFrom(node.getClass()))
+ appendLikeEscapeCharacter((PatternMatchNode) node);
+
if (parenthesisNeeded(node, parentNode))
out.append(')');
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java?rev=905095&r1=905094&r2=905095&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java Sun Jan 31 18:48:03 2010
@@ -25,6 +25,7 @@
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 @@
if (matchingObject) {
appendObjectMatch();
}
+
+ if(PatternMatchNode.class.isAssignableFrom(node.getClass()))
+ appendLikeEscapeCharacter((PatternMatchNode) node);
if (parenthesisNeeded(node, parentNode))
out.append(')');
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java?rev=905095&r1=905094&r2=905095&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/ExpressionFactory.java Sun Jan 31 18:48:03 2010
@@ -576,6 +576,20 @@
}
/**
+ * <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.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 @@
}
/**
+ * <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.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.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 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.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.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 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.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 @@
}
/**
+ * <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.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 @@
}
/**
+ * <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.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/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLike.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLike.java?rev=905095&r1=905094&r2=905095&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLike.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLike.java Sun Jan 31 18:48:03 2010
@@ -30,6 +30,10 @@
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 @@
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 @@
*/
@Override
public Expression shallowCopy() {
- return new ASTLike(id);
+ return new ASTLike(id, escapeChar);
}
@Override
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLikeIgnoreCase.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLikeIgnoreCase.java?rev=905095&r1=905094&r2=905095&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLikeIgnoreCase.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTLikeIgnoreCase.java Sun Jan 31 18:48:03 2010
@@ -30,6 +30,10 @@
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 @@
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 @@
*/
@Override
public Expression shallowCopy() {
- return new ASTLikeIgnoreCase(id);
+ return new ASTLikeIgnoreCase(id, escapeChar);
}
@Override
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLike.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLike.java?rev=905095&r1=905094&r2=905095&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLike.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLike.java Sun Jan 31 18:48:03 2010
@@ -44,6 +44,13 @@
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 {
int len = jjtGetNumChildren();
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLikeIgnoreCase.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLikeIgnoreCase.java?rev=905095&r1=905094&r2=905095&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLikeIgnoreCase.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTNotLikeIgnoreCase.java Sun Jan 31 18:48:03 2010
@@ -42,6 +42,13 @@
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/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java?rev=905095&r1=905094&r2=905095&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java Sun Jan 31 18:48:03 2010
@@ -29,6 +29,10 @@
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) {
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/PatternMatchNode.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/PatternMatchNode.java?rev=905095&r1=905094&r2=905095&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/PatternMatchNode.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/PatternMatchNode.java Sun Jan 31 18:48:03 2010
@@ -21,6 +21,7 @@
import java.util.regex.Pattern;
+import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.util.Util;
/**
@@ -34,11 +35,45 @@
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/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java?rev=905095&r1=905094&r2=905095&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java Sun Jan 31 18:48:03 2010
@@ -28,6 +28,8 @@
import org.apache.cayenne.Cayenne;
import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.Persistent;
+import org.apache.cayenne.exp.parser.ASTLike;
+import org.apache.cayenne.exp.parser.ASTLikeIgnoreCase;
import org.apache.cayenne.query.SelectQuery;
import org.apache.cayenne.query.SortOrder;
import org.apache.cayenne.unit.CayenneCase;
@@ -189,11 +191,33 @@
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/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/SelectQueryTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/SelectQueryTest.java?rev=905095&r1=905094&r2=905095&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/SelectQueryTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/SelectQueryTest.java Sun Jan 31 18:48:03 2010
@@ -210,6 +210,18 @@
assertNotNull(objects);
assertEquals(1, objects.size());
}
+
+ public void testSelectLikeSingleWildcardMatchAndEscape() throws Exception {
+ query.setRoot(Artist.class);
+ Expression qual = ExpressionFactory.likeExp("artistName", "=artist11%", '=');
+ query.setQualifier(qual);
+ performQuery();
+
+ // check query results
+ List objects = opObserver.rowsForQuery(query);
+ assertNotNull(objects);
+ assertEquals(1, objects.size());
+ }
public void testSelectLikeMultipleWildcardMatch() throws Exception {
query.setRoot(Artist.class);