From: <hib...@li...> - 2006-06-28 05:21:29
|
Author: ste...@jb... Date: 2006-06-28 01:20:51 -0400 (Wed, 28 Jun 2006) New Revision: 10061 Added: trunk/Hibernate3/src/org/hibernate/criterion/LikeExpression.java Modified: trunk/Hibernate3/src/org/hibernate/criterion/Example.java trunk/Hibernate3/test/org/hibernate/test/criteria/CriteriaQueryTest.java Log: HHH-1847 : added escape option for like operator in QBE (Scott Marlow) Modified: trunk/Hibernate3/src/org/hibernate/criterion/Example.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/criterion/Example.java 2006-06-28 02:53:39 UTC (rev 10060) +++ trunk/Hibernate3/src/org/hibernate/criterion/Example.java 2006-06-28 05:20:51 UTC (rev 10061) @@ -36,6 +36,7 @@ private final Set excludedProperties = new HashSet(); private PropertySelector selector; private boolean isLikeEnabled; + private Character escapeCharacter; private boolean isIgnoreCaseEnabled; private MatchMode matchMode; @@ -85,6 +86,14 @@ } /** + * Set escape character for "like" clause + */ + public Example setEscapeCharacter(Character escapeCharacter) { + this.escapeCharacter = escapeCharacter; + return this; + } + + /** * Set the property selector */ public Example setPropertySelector(PropertySelector selector) { @@ -300,8 +309,18 @@ Criterion crit; if ( propertyValue!=null ) { boolean isString = propertyValue instanceof String; - String op = isLikeEnabled && isString ? " like " : "="; - crit = new SimpleExpression( propertyName, propertyValue, op, isIgnoreCaseEnabled && isString ); + if ( isLikeEnabled && isString ) { + crit = new LikeExpression( + propertyName, + ( String ) propertyValue, + matchMode, + escapeCharacter, + isIgnoreCaseEnabled + ); + } + else { + crit = new SimpleExpression( propertyName, propertyValue, "=", isIgnoreCaseEnabled && isString ); + } } else { crit = new NullExpression(propertyName); Added: trunk/Hibernate3/src/org/hibernate/criterion/LikeExpression.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/criterion/LikeExpression.java 2006-06-28 02:53:39 UTC (rev 10060) +++ trunk/Hibernate3/src/org/hibernate/criterion/LikeExpression.java 2006-06-28 05:20:51 UTC (rev 10061) @@ -0,0 +1,75 @@ +package org.hibernate.criterion; + +import org.hibernate.Criteria; +import org.hibernate.HibernateException; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.TypedValue; + +/** + * A criterion representing a "like" expression + * + * @author Scott Marlow + * @author Steve Ebersole + */ +public class LikeExpression implements Criterion { + private final String propertyName; + private final Object value; + private final Character escapeChar; + private final boolean ignoreCase; + + protected LikeExpression( + String propertyName, + String value, + Character escapeChar, + boolean ignoreCase) { + this.propertyName = propertyName; + this.value = value; + this.escapeChar = escapeChar; + this.ignoreCase = ignoreCase; + } + + protected LikeExpression( + String propertyName, + String value) { + this( propertyName, value, null, false ); + } + + protected LikeExpression( + String propertyName, + String value, + MatchMode matchMode) { + this( propertyName, matchMode.toMatchString( value ) ); + } + + protected LikeExpression( + String propertyName, + String value, + MatchMode matchMode, + Character escapeChar, + boolean ignoreCase) { + this( propertyName, matchMode.toMatchString( value ), escapeChar, ignoreCase ); + } + + public String toSqlString( + Criteria criteria, + CriteriaQuery criteriaQuery) throws HibernateException { + Dialect dialect = criteriaQuery.getFactory().getDialect(); + String[] columns = criteriaQuery.getColumnsUsingProjection( criteria, propertyName ); + if ( columns.length != 1 ) { + throw new HibernateException( "Like may only be used with single-column properties" ); + } + String lhs = ignoreCase + ? dialect.getLowercaseFunction() + '(' + columns[0] + ')' + : columns[0]; + return lhs + " like ?" + ( escapeChar == null ? "" : " escape \'" + escapeChar + "\'" ); + + } + + public TypedValue[] getTypedValues( + Criteria criteria, + CriteriaQuery criteriaQuery) throws HibernateException { + return new TypedValue[] { + criteriaQuery.getTypedValue( criteria, propertyName, value.toString().toLowerCase() ) + }; + } +} Modified: trunk/Hibernate3/test/org/hibernate/test/criteria/CriteriaQueryTest.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/criteria/CriteriaQueryTest.java 2006-06-28 02:53:39 UTC (rev 10060) +++ trunk/Hibernate3/test/org/hibernate/test/criteria/CriteriaQueryTest.java 2006-06-28 05:20:51 UTC (rev 10061) @@ -24,10 +24,10 @@ import org.hibernate.criterion.Property; import org.hibernate.criterion.Restrictions; import org.hibernate.criterion.Subqueries; +import org.hibernate.criterion.Example; import org.hibernate.test.TestCase; import org.hibernate.test.hql.Animal; import org.hibernate.test.hql.Reptile; -import org.hibernate.transform.AliasToBeanResultTransformer; import org.hibernate.transform.Transformers; import org.hibernate.type.Type; import org.hibernate.util.SerializationHelper; @@ -40,7 +40,44 @@ public CriteriaQueryTest(String str) { super(str); } - + + public void testEscapeCharacter() { + Session session = openSession(); + Transaction t = session.beginTransaction(); + Course c1 = new Course(); + c1.setCourseCode( "course-1" ); + c1.setDescription( "%1" ); + Course c2 = new Course(); + c2.setCourseCode( "course-2" ); + c2.setDescription( "%2" ); + Course c3 = new Course(); + c3.setCourseCode( "course-3" ); + c3.setDescription( "control" ); + session.persist( c1 ); + session.persist( c2 ); + session.persist( c3 ); + session.flush(); + session.clear(); + + // finds all courses which have a description equal to '%1' + Course example = new Course(); + example.setDescription( "&%1" ); + List result = session.createCriteria( Course.class ) + .add( Example.create( example ).ignoreCase().enableLike().setEscapeCharacter( new Character( '&' ) ) ) + .list(); + assertEquals( 1, result.size() ); + // finds all courses which contain '%' as the first char in the description + example.setDescription( "&%%" ); + result = session.createCriteria( Course.class ) + .add( Example.create( example ).ignoreCase().enableLike().setEscapeCharacter( new Character( '&' ) ) ) + .list(); + assertEquals( 2, result.size() ); + + session.createQuery( "delete Course" ).executeUpdate(); + t.commit(); + session.close(); + } + public void testScrollCriteria() { Session session = openSession(); Transaction t = session.beginTransaction(); |