HHH-14739 - Implement ILike support

Signed-off-by: Jan Schatteman <jschatte@redhat.com>
This commit is contained in:
Jan Schatteman 2021-07-19 19:29:20 +02:00 committed by Jan Schatteman
parent be485796b1
commit 0c1c469352
12 changed files with 670 additions and 25 deletions

View File

@ -212,6 +212,7 @@ LEAST : [lL] [eE] [aA] [sS] [tT];
LEFT : [lL] [eE] [fF] [tT];
LENGTH : [lL] [eE] [nN] [gG] [tT] [hH];
LIKE : [lL] [iI] [kK] [eE];
ILIKE : [iI] [lL] [iI] [kK] [eE];
LIMIT : [lL] [iI] [mM] [iI] [tT];
LIST : [lL] [iI] [sS] [tT];
LN : [lL] [nN];

View File

@ -400,20 +400,20 @@ whereClause
predicate
//highest to lowest precedence
: LEFT_PAREN predicate RIGHT_PAREN # GroupedPredicate
| expression IS (NOT)? NULL # IsNullPredicate
| expression IS (NOT)? EMPTY # IsEmptyPredicate
| expression (NOT)? IN inList # InPredicate
| expression (NOT)? BETWEEN expression AND expression # BetweenPredicate
| expression (NOT)? LIKE expression (likeEscape)? # LikePredicate
| expression comparisonOperator expression # ComparisonPredicate
: LEFT_PAREN predicate RIGHT_PAREN # GroupedPredicate
| expression IS (NOT)? NULL # IsNullPredicate
| expression IS (NOT)? EMPTY # IsEmptyPredicate
| expression (NOT)? IN inList # InPredicate
| expression (NOT)? BETWEEN expression AND expression # BetweenPredicate
| expression (NOT)? (LIKE | ILIKE) expression (likeEscape)? # LikePredicate
| expression comparisonOperator expression # ComparisonPredicate
| EXISTS (ELEMENTS|INDICES) LEFT_PAREN dotIdentifierSequence RIGHT_PAREN # ExistsCollectionPartPredicate
| EXISTS expression # ExistsPredicate
| expression (NOT)? MEMBER OF path # MemberOfPredicate
| NOT predicate # NegatedPredicate
| predicate AND predicate # AndPredicate
| predicate OR predicate # OrPredicate
| expression # BooleanExpressionPredicate
| EXISTSexpression # ExistsPredicate
| expression (NOT)? MEMBER OF path # MemberOfPredicate
| NOT predicate # NegatedPredicate
| predicate AND predicate # AndPredicate
| predicate OR predicate # OrPredicate
| expression # BooleanExpressionPredicate
;
comparisonOperator
@ -973,6 +973,7 @@ identifier
| HOUR
| ID
| IFNULL
| ILIKE
| IN
| INDEX
| INDICES

View File

@ -33,7 +33,6 @@ import javax.persistence.criteria.Subquery;
import org.hibernate.query.NullPrecedence;
import org.hibernate.query.SortOrder;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
/**
@ -621,6 +620,18 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
@Override
JpaPredicate like(Expression<String> x, String pattern, char escapeChar);
JpaPredicate ilike(Expression<String> x, Expression<String> pattern);
JpaPredicate ilike(Expression<String> x, String pattern);
JpaPredicate ilike(Expression<String> x, Expression<String> pattern, Expression<Character> escapeChar);
JpaPredicate ilike(Expression<String> x, Expression<String> pattern, char escapeChar);
JpaPredicate ilike(Expression<String> x, String pattern, Expression<Character> escapeChar);
JpaPredicate ilike(Expression<String> x, String pattern, char escapeChar);
@Override
JpaPredicate notLike(Expression<String> x, Expression<String> pattern);
@ -639,6 +650,18 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
@Override
JpaPredicate notLike(Expression<String> x, String pattern, char escapeChar);
JpaPredicate notIlike(Expression<String> x, Expression<String> pattern);
JpaPredicate notIlike(Expression<String> x, String pattern);
JpaPredicate notIlike(Expression<String> x, Expression<String> pattern, Expression<Character> escapeChar);
JpaPredicate notIlike(Expression<String> x, Expression<String> pattern, char escapeChar);
JpaPredicate notIlike(Expression<String> x, String pattern, Expression<Character> escapeChar);
JpaPredicate notIlike(Expression<String> x, String pattern, char escapeChar);
@Override
<T> JpaInPredicate<T> in(Expression<? extends T> expression);

View File

@ -1972,12 +1972,15 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
public SqmPredicate visitLikePredicate(HqlParser.LikePredicateContext ctx) {
final boolean negated = ( (TerminalNode) ctx.getChild( 1 ) ).getSymbol().getType() == HqlParser.NOT;
final int startIndex = negated ? 3 : 2;
final boolean caseSensitive = ( (TerminalNode) ctx.getChild( negated ? 2 : 1 ) ).getSymbol()
.getType() == HqlParser.LIKE;
if ( ctx.getChildCount() == startIndex + 2 ) {
return new SqmLikePredicate(
(SqmExpression<?>) ctx.getChild( 0 ).accept( this ),
(SqmExpression<?>) ctx.getChild( startIndex ).accept( this ),
(SqmExpression<?>) ctx.getChild( startIndex + 1 ).getChild( 1 ).accept( this ),
negated,
caseSensitive,
creationContext.getNodeBuilder()
);
}
@ -1986,6 +1989,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
(SqmExpression<?>) ctx.getChild( 0 ).accept( this ),
(SqmExpression<?>) ctx.getChild( startIndex ).accept( this ),
negated,
caseSensitive,
creationContext.getNodeBuilder()
);
}

View File

@ -1970,6 +1970,79 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
);
}
@Override
public SqmPredicate ilike(Expression<String> searchString, Expression<String> pattern) {
return new SqmLikePredicate(
(SqmExpression) searchString,
(SqmExpression) pattern,
false,
false,
this
);
}
@Override
public SqmPredicate ilike(Expression<String> searchString, String pattern) {
return new SqmLikePredicate(
(SqmExpression) searchString,
value( pattern, (SqmExpression) searchString ),
false,
false,
this
);
}
@Override
public SqmPredicate ilike(
Expression<String> searchString,
Expression<String> pattern,
Expression<Character> escapeChar) {
return new SqmLikePredicate(
(SqmExpression) searchString,
(SqmExpression) pattern,
(SqmExpression) escapeChar,
false,
false,
this
);
}
@Override
public SqmPredicate ilike(Expression<String> searchString, Expression<String> pattern, char escapeChar) {
return new SqmLikePredicate(
(SqmExpression) searchString,
(SqmExpression) pattern,
literal( escapeChar ),
false,
false,
this
);
}
@Override
public SqmPredicate ilike(Expression<String> searchString, String pattern, Expression<Character> escapeChar) {
return new SqmLikePredicate(
(SqmExpression) searchString,
value( pattern, (SqmExpression) searchString ),
(SqmExpression) escapeChar,
false,
false,
this
);
}
@Override
public SqmPredicate ilike(Expression<String> searchString, String pattern, char escapeChar) {
return new SqmLikePredicate(
(SqmExpression) searchString,
value( pattern, (SqmExpression) searchString ),
literal( escapeChar ),
false,
false,
this
);
}
@Override
public SqmPredicate notLike(Expression<String> x, Expression<String> pattern) {
return not( like( x, pattern ) );
@ -2000,6 +2073,36 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return not( like( x, pattern, escapeChar ) );
}
@Override
public SqmPredicate notIlike(Expression<String> x, Expression<String> pattern) {
return not( ilike( x, pattern ) );
}
@Override
public SqmPredicate notIlike(Expression<String> x, String pattern) {
return not( ilike( x, pattern ) );
}
@Override
public SqmPredicate notIlike(Expression<String> x, Expression<String> pattern, Expression<Character> escapeChar) {
return not( ilike( x, pattern, escapeChar ) );
}
@Override
public SqmPredicate notIlike(Expression<String> x, Expression<String> pattern, char escapeChar) {
return not( ilike( x, pattern, escapeChar ) );
}
@Override
public SqmPredicate notIlike(Expression<String> x, String pattern, Expression<Character> escapeChar) {
return not( ilike( x, pattern, escapeChar ) );
}
@Override
public SqmPredicate notIlike(Expression<String> x, String pattern, char escapeChar) {
return not( ilike( x, pattern, escapeChar ) );
}
@Override
@SuppressWarnings("unchecked")
public <T> SqmInPredicate<T> in(Expression<? extends T> expression) {

View File

@ -838,8 +838,9 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
@Override
public Object visitLikePredicate(SqmLikePredicate predicate) {
final String likeType = predicate.isCaseSensitive() ? "like" : "ilike";
processStanza(
predicate.isNegated() ? "is-not-like" : "is-like",
( predicate.isNegated() ? "is-not-" : "is-" ) + likeType,
() -> {
predicate.getPattern().accept( this );
predicate.getMatchExpression().accept( this );

View File

@ -4468,7 +4468,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
(Expression) predicate.getMatchExpression().accept( this ),
(Expression) predicate.getPattern().accept( this ),
escapeExpression,
predicate.isNegated()
predicate.isNegated(),
predicate.isCaseSensitive()
);
}

View File

@ -17,6 +17,7 @@ public class SqmLikePredicate extends AbstractNegatableSqmPredicate {
private final SqmExpression<?> matchExpression;
private final SqmExpression<?> pattern;
private final SqmExpression<?> escapeCharacter;
private final boolean isCaseSensitive;
public SqmLikePredicate(
SqmExpression<?> matchExpression,
@ -26,17 +27,27 @@ public class SqmLikePredicate extends AbstractNegatableSqmPredicate {
this( matchExpression, pattern, escapeCharacter, false, nodeBuilder );
}
@SuppressWarnings("WeakerAccess")
public SqmLikePredicate(
SqmExpression<?> matchExpression,
SqmExpression<?> pattern,
SqmExpression<?> escapeCharacter,
boolean negated,
NodeBuilder nodeBuilder) {
this( matchExpression, pattern, escapeCharacter, negated, true, nodeBuilder );
}
public SqmLikePredicate(
SqmExpression<?> matchExpression,
SqmExpression<?> pattern,
SqmExpression<?> escapeCharacter,
boolean negated,
boolean isCaseSensitive,
NodeBuilder nodeBuilder) {
super( negated, nodeBuilder );
this.matchExpression = matchExpression;
this.pattern = pattern;
this.escapeCharacter = escapeCharacter;
this.isCaseSensitive = isCaseSensitive;
}
public SqmLikePredicate(
@ -50,8 +61,9 @@ public class SqmLikePredicate extends AbstractNegatableSqmPredicate {
SqmExpression<?> matchExpression,
SqmExpression<?> pattern,
boolean negated,
boolean isCaseSensitive,
NodeBuilder nodeBuilder) {
this( matchExpression, pattern, null, negated, nodeBuilder );
this( matchExpression, pattern, null, negated, isCaseSensitive, nodeBuilder );
}
public SqmExpression<?> getMatchExpression() {
@ -66,6 +78,10 @@ public class SqmLikePredicate extends AbstractNegatableSqmPredicate {
return escapeCharacter;
}
public boolean isCaseSensitive() {
return isCaseSensitive;
}
@Override
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitLikePredicate( this );

View File

@ -4562,15 +4562,60 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
@Override
public void visitLikePredicate(LikePredicate likePredicate) {
likePredicate.getMatchExpression().accept( this );
if ( likePredicate.isNegated() ) {
appendSql( " not" );
if ( likePredicate.isCaseSensitive() ) {
likePredicate.getMatchExpression().accept( this );
if ( likePredicate.isNegated() ) {
appendSql( " not" );
}
appendSql( " like " );
likePredicate.getPattern().accept( this );
if ( likePredicate.getEscapeCharacter() != null ) {
appendSql( " escape " );
likePredicate.getEscapeCharacter().accept( this );
}
}
else {
if (dialect.supportsCaseInsensitiveLike()) {
likePredicate.getMatchExpression().accept( this );
if ( likePredicate.isNegated() ) {
appendSql( " not" );
}
appendSql( " " );
appendSql( dialect.getCaseInsensitiveLike() );
appendSql( " " );
likePredicate.getPattern().accept( this );
if ( likePredicate.getEscapeCharacter() != null ) {
appendSql( " escape " );
likePredicate.getEscapeCharacter().accept( this );
}
}
else {
renderCaseInsensitiveLikeEmulation(likePredicate.getMatchExpression(), likePredicate.getPattern(), likePredicate.getEscapeCharacter(), likePredicate.isNegated());
}
}
}
protected void renderCaseInsensitiveLikeEmulation(Expression lhs, Expression rhs, Expression escapeCharacter, boolean negated) {
//LOWER(lhs) operator LOWER(rhs)
appendSql( " " );
appendSql( dialect.getLowercaseFunction() );
appendSql( "( ");
lhs.accept( this );
appendSql( " )" );
appendSql( negated ? " not" : "" );
appendSql( " like " );
likePredicate.getPattern().accept( this );
if ( likePredicate.getEscapeCharacter() != null ) {
appendSql( dialect.getLowercaseFunction() );
appendSql( "( " );
rhs.accept( this );
appendSql( " ) " );
if ( escapeCharacter != null ) {
appendSql( " escape " );
likePredicate.getEscapeCharacter().accept( this );
escapeCharacter.accept( this );
}
}

View File

@ -17,6 +17,7 @@ public class LikePredicate implements Predicate {
private final Expression pattern;
private final Expression escapeCharacter;
private final boolean negated;
private final boolean isCaseSensitive;
public LikePredicate(
Expression matchExpression,
@ -28,11 +29,22 @@ public class LikePredicate implements Predicate {
public LikePredicate(
Expression matchExpression,
Expression pattern,
Expression escapeCharacter, boolean negated) {
Expression escapeCharacter,
boolean negated) {
this( matchExpression, pattern, escapeCharacter, negated, true );
}
public LikePredicate(
Expression matchExpression,
Expression pattern,
Expression escapeCharacter,
boolean negated,
boolean isCaseSensitive) {
this.matchExpression = matchExpression;
this.pattern = pattern;
this.escapeCharacter = escapeCharacter;
this.negated = negated;
this.isCaseSensitive = isCaseSensitive;
}
public LikePredicate(Expression matchExpression, Expression pattern) {
@ -55,6 +67,10 @@ public class LikePredicate implements Predicate {
return negated;
}
public boolean isCaseSensitive() {
return isCaseSensitive;
}
@Override
public boolean isEmpty() {
return false;

View File

@ -0,0 +1,278 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.query.hql;
import java.util.List;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.hibernate.query.Query;
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
import org.hibernate.testing.orm.domain.StandardDomainModel;
import org.hibernate.testing.orm.domain.gambit.BasicEntity;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @author Jan Schatteman
*/
@ServiceRegistry
@DomainModel(
standardModels = StandardDomainModel.GAMBIT
)
@SessionFactory
public class ILikeCriteriaTest {
@BeforeEach
public void prepareData(SessionFactoryScope scope) {
scope.inTransaction(
em -> {
BasicEntity be1 = new BasicEntity(1, "Product_one");
em.persist( be1 );
BasicEntity be2 = new BasicEntity(2, "proDUct two");
em.persist( be2 );
BasicEntity be3 = new BasicEntity(3, "Product three");
em.persist( be3 );
BasicEntity be4 = new BasicEntity(4, "pROducT four");
em.persist( be4 );
BasicEntity be5 = new BasicEntity(5, "Product five");
em.persist( be5 );
BasicEntity be6 = new BasicEntity(6, "Prodact six");
em.persist( be6 );
BasicEntity be7 = new BasicEntity(7, "prodACt seven");
em.persist( be7 );
BasicEntity be8 = new BasicEntity(8, "Prod_act eight");
em.persist( be8 );
BasicEntity be9 = new BasicEntity(9, "prod_ACt nine");
em.persist( be9 );
}
);
}
@AfterEach
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction(
session -> session.createQuery( "delete from BasicEntity" ).executeUpdate()
);
}
@Test
public void testLike(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery( BasicEntity.class);
Root<BasicEntity> from = cq.from( BasicEntity.class );
cq.where( cb.like( from.get( "data" ), "Prod%" ) );
Query q = session.createQuery( cq );
List l = q.getResultList();
assertEquals( 5, l.size() );
cq.where( cb.like( from.get( "data" ), cb.literal( "Prod%" ) ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 5, l.size() );
}
);
}
@Test
public void testLikeEscape(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery( BasicEntity.class);
Root<BasicEntity> from = cq.from( BasicEntity.class );
cq.where( cb.like( from.get( "data" ), cb.literal( "Prod%" ), cb.literal( '$' ) ) );
Query q = session.createQuery( cq );
List l = q.getResultList();
assertEquals( 5, l.size() );
cq.where( cb.like( from.get( "data" ), cb.literal( "Prod%" ), '$' ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 5, l.size() );
cq.where( cb.like( from.get( "data" ), "Prod%", cb.literal( '$' ) ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 5, l.size() );
cq.where( cb.like( from.get( "data" ), "Prod%", '$' ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 5, l.size() );
}
);
}
@Test
public void testNotLike(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery( BasicEntity.class);
Root<BasicEntity> from = cq.from( BasicEntity.class );
cq.where( cb.notLike( from.get( "data" ), "Prod%" ) );
Query q = session.createQuery( cq );
List l = q.getResultList();
assertEquals( 4, l.size() );
cq.where( cb.notLike( from.get( "data" ), cb.literal( "Prod%" ) ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 4, l.size() );
}
);
}
@Test
public void testNotLikeEscape(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery( BasicEntity.class);
Root<BasicEntity> from = cq.from( BasicEntity.class );
cq.where( cb.notLike( from.get( "data" ), cb.literal( "Pr%$_%" ), cb.literal( '$' ) ) );
Query q = session.createQuery( cq );
List l = q.getResultList();
assertEquals( 7, l.size() );
cq.where( cb.notLike( from.get( "data" ), cb.literal( "Pr%$_%" ), '$' ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 7, l.size() );
cq.where( cb.notLike( from.get( "data" ), "Pr%$_%", cb.literal( '$' ) ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 7, l.size() );
cq.where( cb.notLike( from.get( "data" ), "Pr%$_%", '$' ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 7, l.size() );
}
);
}
@Test
public void testIlike(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery( BasicEntity.class);
Root<BasicEntity> from = cq.from( BasicEntity.class );
cq.where( cb.ilike( from.get( "data" ), "Produ%" ) );
Query q = session.createQuery( cq );
List l = q.getResultList();
assertEquals( 5, l.size() );
cq.where( cb.ilike( from.get( "data" ), cb.literal( "Produ%" ) ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 5, l.size() );
}
);
}
@Test
public void testIlikeEscape(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery( BasicEntity.class);
Root<BasicEntity> from = cq.from( BasicEntity.class );
cq.where( cb.ilike( from.get( "data" ), cb.literal( "Pr%$_%" ), cb.literal( '$' ) ) );
Query q = session.createQuery( cq );
List l = q.getResultList();
assertEquals( 3, l.size() );
cq.where( cb.ilike( from.get( "data" ), cb.literal( "Pr%$_%" ), '$' ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 3, l.size() );
cq.where( cb.ilike( from.get( "data" ), "Pr%$_%", cb.literal( '$' ) ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 3, l.size() );
cq.where( cb.ilike( from.get( "data" ), "Pr%$_%", '$' ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 3, l.size() );
}
);
}
@Test
public void testNotIlike(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery( BasicEntity.class);
Root<BasicEntity> from = cq.from( BasicEntity.class );
cq.where( cb.notIlike( from.get( "data" ), "Produ%" ) );
Query q = session.createQuery( cq );
List l = q.getResultList();
assertEquals( 4, l.size() );
cq.where( cb.notIlike( from.get( "data" ), cb.literal( "Produ%" ) ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 4, l.size() );
}
);
}
@Test
public void testNotIlikeEscape(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery( BasicEntity.class);
Root<BasicEntity> from = cq.from( BasicEntity.class );
cq.where( cb.notIlike( from.get( "data" ), cb.literal( "Pr%$_%" ), cb.literal( '$' ) ) );
Query q = session.createQuery( cq );
List l = q.getResultList();
assertEquals( 6, l.size() );
cq.where( cb.notIlike( from.get( "data" ), cb.literal( "Pr%$_%" ), '$' ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 6, l.size() );
cq.where( cb.notIlike( from.get( "data" ), "Pr%$_%", cb.literal( '$' ) ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 6, l.size() );
cq.where( cb.notIlike( from.get( "data" ), "Pr%$_%", '$' ) );
q = session.createQuery( cq );
l = q.getResultList();
assertEquals( 6, l.size() );
}
);
}
}

View File

@ -0,0 +1,156 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.query.hql;
import java.util.List;
import org.hibernate.query.Query;
import org.hibernate.testing.orm.domain.StandardDomainModel;
import org.hibernate.testing.orm.domain.gambit.BasicEntity;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @author Jan Schatteman
*/
@ServiceRegistry
@DomainModel(
standardModels = StandardDomainModel.GAMBIT
)
@SessionFactory
public class ILikeTest {
@BeforeEach
public void prepareData(SessionFactoryScope scope) {
scope.inTransaction(
em -> {
BasicEntity be1 = new BasicEntity(1, "Product_one");
em.persist( be1 );
BasicEntity be2 = new BasicEntity(2, "proDUct two");
em.persist( be2 );
BasicEntity be3 = new BasicEntity(3, "Product three");
em.persist( be3 );
BasicEntity be4 = new BasicEntity(4, "pROducT four");
em.persist( be4 );
BasicEntity be5 = new BasicEntity(5, "Product five");
em.persist( be5 );
BasicEntity be6 = new BasicEntity(6, "Prodact six");
em.persist( be6 );
BasicEntity be7 = new BasicEntity(7, "prodACt seven");
em.persist( be7 );
BasicEntity be8 = new BasicEntity(8, "Prod_act eight");
em.persist( be8 );
BasicEntity be9 = new BasicEntity(9, "prod_ACt nine");
em.persist( be9 );
}
);
}
@AfterEach
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction(
session -> session.createQuery( "delete from BasicEntity" ).executeUpdate()
);
}
@Test
public void testLike(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Query q = session.createQuery( "from BasicEntity be where be.data like 'Prod%'" );
List l = q.getResultList();
assertEquals( 5, l.size() );
}
);
}
@Test
public void testNotLike(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Query q = session.createQuery( "from BasicEntity be where be.data not like 'Prod%'" );
List l = q.getResultList();
assertEquals( 4, l.size() );
}
);
}
@Test
public void testLikeEscape(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Query q = session.createQuery( "from BasicEntity be where be.data like 'Pr%$_%' escape '$'" );
List l = q.getResultList();
assertEquals( 2, l.size() );
}
);
}
@Test
public void testNotLikeEscape(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Query q = session.createQuery( "from BasicEntity be where be.data not like 'Pr%$_%' escape '$'" );
List l = q.getResultList();
assertEquals( 7, l.size() );
}
);
}
@Test
public void testIlike(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Query q = session.createQuery( "from BasicEntity be where be.data ilike 'Produ%'" );
List l = q.getResultList();
assertEquals( 5, l.size() );
}
);
}
@Test
public void testNotIlike(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Query q = session.createQuery( "from BasicEntity be where be.data not ilike 'Produ%'" );
List l = q.getResultList();
assertEquals( 4, l.size() );
}
);
}
@Test
public void testIlikeEscape(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Query q = session.createQuery( "from BasicEntity be where be.data ilike 'Pr%$_%' escape '$'" );
List l = q.getResultList();
assertEquals( 3, l.size() );
}
);
}
@Test
public void testNotIlikeEscape(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Query q = session.createQuery( "from BasicEntity be where be.data not ilike 'Pr%$_%' escape '$'" );
List l = q.getResultList();
assertEquals( 6, l.size() );
}
);
}
}