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]; LEFT : [lL] [eE] [fF] [tT];
LENGTH : [lL] [eE] [nN] [gG] [tT] [hH]; LENGTH : [lL] [eE] [nN] [gG] [tT] [hH];
LIKE : [lL] [iI] [kK] [eE]; LIKE : [lL] [iI] [kK] [eE];
ILIKE : [iI] [lL] [iI] [kK] [eE];
LIMIT : [lL] [iI] [mM] [iI] [tT]; LIMIT : [lL] [iI] [mM] [iI] [tT];
LIST : [lL] [iI] [sS] [tT]; LIST : [lL] [iI] [sS] [tT];
LN : [lL] [nN]; LN : [lL] [nN];

View File

@ -405,10 +405,10 @@ predicate
| expression IS (NOT)? EMPTY # IsEmptyPredicate | expression IS (NOT)? EMPTY # IsEmptyPredicate
| expression (NOT)? IN inList # InPredicate | expression (NOT)? IN inList # InPredicate
| expression (NOT)? BETWEEN expression AND expression # BetweenPredicate | expression (NOT)? BETWEEN expression AND expression # BetweenPredicate
| expression (NOT)? LIKE expression (likeEscape)? # LikePredicate | expression (NOT)? (LIKE | ILIKE) expression (likeEscape)? # LikePredicate
| expression comparisonOperator expression # ComparisonPredicate | expression comparisonOperator expression # ComparisonPredicate
| EXISTS (ELEMENTS|INDICES) LEFT_PAREN dotIdentifierSequence RIGHT_PAREN # ExistsCollectionPartPredicate | EXISTS (ELEMENTS|INDICES) LEFT_PAREN dotIdentifierSequence RIGHT_PAREN # ExistsCollectionPartPredicate
| EXISTS expression # ExistsPredicate | EXISTSexpression # ExistsPredicate
| expression (NOT)? MEMBER OF path # MemberOfPredicate | expression (NOT)? MEMBER OF path # MemberOfPredicate
| NOT predicate # NegatedPredicate | NOT predicate # NegatedPredicate
| predicate AND predicate # AndPredicate | predicate AND predicate # AndPredicate
@ -973,6 +973,7 @@ identifier
| HOUR | HOUR
| ID | ID
| IFNULL | IFNULL
| ILIKE
| IN | IN
| INDEX | INDEX
| INDICES | INDICES

View File

@ -33,7 +33,6 @@ import javax.persistence.criteria.Subquery;
import org.hibernate.query.NullPrecedence; import org.hibernate.query.NullPrecedence;
import org.hibernate.query.SortOrder; import org.hibernate.query.SortOrder;
import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.expression.SqmExpression;
/** /**
@ -621,6 +620,18 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
@Override @Override
JpaPredicate like(Expression<String> x, String pattern, char escapeChar); 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 @Override
JpaPredicate notLike(Expression<String> x, Expression<String> pattern); JpaPredicate notLike(Expression<String> x, Expression<String> pattern);
@ -639,6 +650,18 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
@Override @Override
JpaPredicate notLike(Expression<String> x, String pattern, char escapeChar); 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 @Override
<T> JpaInPredicate<T> in(Expression<? extends T> expression); <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) { public SqmPredicate visitLikePredicate(HqlParser.LikePredicateContext ctx) {
final boolean negated = ( (TerminalNode) ctx.getChild( 1 ) ).getSymbol().getType() == HqlParser.NOT; final boolean negated = ( (TerminalNode) ctx.getChild( 1 ) ).getSymbol().getType() == HqlParser.NOT;
final int startIndex = negated ? 3 : 2; final int startIndex = negated ? 3 : 2;
final boolean caseSensitive = ( (TerminalNode) ctx.getChild( negated ? 2 : 1 ) ).getSymbol()
.getType() == HqlParser.LIKE;
if ( ctx.getChildCount() == startIndex + 2 ) { if ( ctx.getChildCount() == startIndex + 2 ) {
return new SqmLikePredicate( return new SqmLikePredicate(
(SqmExpression<?>) ctx.getChild( 0 ).accept( this ), (SqmExpression<?>) ctx.getChild( 0 ).accept( this ),
(SqmExpression<?>) ctx.getChild( startIndex ).accept( this ), (SqmExpression<?>) ctx.getChild( startIndex ).accept( this ),
(SqmExpression<?>) ctx.getChild( startIndex + 1 ).getChild( 1 ).accept( this ), (SqmExpression<?>) ctx.getChild( startIndex + 1 ).getChild( 1 ).accept( this ),
negated, negated,
caseSensitive,
creationContext.getNodeBuilder() creationContext.getNodeBuilder()
); );
} }
@ -1986,6 +1989,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
(SqmExpression<?>) ctx.getChild( 0 ).accept( this ), (SqmExpression<?>) ctx.getChild( 0 ).accept( this ),
(SqmExpression<?>) ctx.getChild( startIndex ).accept( this ), (SqmExpression<?>) ctx.getChild( startIndex ).accept( this ),
negated, negated,
caseSensitive,
creationContext.getNodeBuilder() 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 @Override
public SqmPredicate notLike(Expression<String> x, Expression<String> pattern) { public SqmPredicate notLike(Expression<String> x, Expression<String> pattern) {
return not( like( x, pattern ) ); return not( like( x, pattern ) );
@ -2000,6 +2073,36 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return not( like( x, pattern, escapeChar ) ); 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 @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> SqmInPredicate<T> in(Expression<? extends T> expression) { public <T> SqmInPredicate<T> in(Expression<? extends T> expression) {

View File

@ -838,8 +838,9 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
@Override @Override
public Object visitLikePredicate(SqmLikePredicate predicate) { public Object visitLikePredicate(SqmLikePredicate predicate) {
final String likeType = predicate.isCaseSensitive() ? "like" : "ilike";
processStanza( processStanza(
predicate.isNegated() ? "is-not-like" : "is-like", ( predicate.isNegated() ? "is-not-" : "is-" ) + likeType,
() -> { () -> {
predicate.getPattern().accept( this ); predicate.getPattern().accept( this );
predicate.getMatchExpression().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.getMatchExpression().accept( this ),
(Expression) predicate.getPattern().accept( this ), (Expression) predicate.getPattern().accept( this ),
escapeExpression, 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<?> matchExpression;
private final SqmExpression<?> pattern; private final SqmExpression<?> pattern;
private final SqmExpression<?> escapeCharacter; private final SqmExpression<?> escapeCharacter;
private final boolean isCaseSensitive;
public SqmLikePredicate( public SqmLikePredicate(
SqmExpression<?> matchExpression, SqmExpression<?> matchExpression,
@ -26,17 +27,27 @@ public class SqmLikePredicate extends AbstractNegatableSqmPredicate {
this( matchExpression, pattern, escapeCharacter, false, nodeBuilder ); this( matchExpression, pattern, escapeCharacter, false, nodeBuilder );
} }
@SuppressWarnings("WeakerAccess")
public SqmLikePredicate( public SqmLikePredicate(
SqmExpression<?> matchExpression, SqmExpression<?> matchExpression,
SqmExpression<?> pattern, SqmExpression<?> pattern,
SqmExpression<?> escapeCharacter, SqmExpression<?> escapeCharacter,
boolean negated, boolean negated,
NodeBuilder nodeBuilder) { 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 ); super( negated, nodeBuilder );
this.matchExpression = matchExpression; this.matchExpression = matchExpression;
this.pattern = pattern; this.pattern = pattern;
this.escapeCharacter = escapeCharacter; this.escapeCharacter = escapeCharacter;
this.isCaseSensitive = isCaseSensitive;
} }
public SqmLikePredicate( public SqmLikePredicate(
@ -50,8 +61,9 @@ public class SqmLikePredicate extends AbstractNegatableSqmPredicate {
SqmExpression<?> matchExpression, SqmExpression<?> matchExpression,
SqmExpression<?> pattern, SqmExpression<?> pattern,
boolean negated, boolean negated,
boolean isCaseSensitive,
NodeBuilder nodeBuilder) { NodeBuilder nodeBuilder) {
this( matchExpression, pattern, null, negated, nodeBuilder ); this( matchExpression, pattern, null, negated, isCaseSensitive, nodeBuilder );
} }
public SqmExpression<?> getMatchExpression() { public SqmExpression<?> getMatchExpression() {
@ -66,6 +78,10 @@ public class SqmLikePredicate extends AbstractNegatableSqmPredicate {
return escapeCharacter; return escapeCharacter;
} }
public boolean isCaseSensitive() {
return isCaseSensitive;
}
@Override @Override
public <T> T accept(SemanticQueryWalker<T> walker) { public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitLikePredicate( this ); return walker.visitLikePredicate( this );

View File

@ -4562,6 +4562,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
@Override @Override
public void visitLikePredicate(LikePredicate likePredicate) { public void visitLikePredicate(LikePredicate likePredicate) {
if ( likePredicate.isCaseSensitive() ) {
likePredicate.getMatchExpression().accept( this ); likePredicate.getMatchExpression().accept( this );
if ( likePredicate.isNegated() ) { if ( likePredicate.isNegated() ) {
appendSql( " not" ); appendSql( " not" );
@ -4572,6 +4574,49 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
appendSql( " escape " ); appendSql( " escape " );
likePredicate.getEscapeCharacter().accept( this ); 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 " );
appendSql( dialect.getLowercaseFunction() );
appendSql( "( " );
rhs.accept( this );
appendSql( " ) " );
if ( escapeCharacter != null ) {
appendSql( " escape " );
escapeCharacter.accept( this );
}
} }
@Override @Override

View File

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