diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/ReuseCriteriaWithMixedParametersTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/ReuseCriteriaWithMixedParametersTest.java new file mode 100644 index 000000000000..a8bcb71a6f72 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/ReuseCriteriaWithMixedParametersTest.java @@ -0,0 +1,214 @@ +package org.hibernate.orm.test.jpa.query; + +import java.time.Instant; +import java.util.Date; +import java.util.List; + +import org.hibernate.orm.test.jpa.Wallet; +import org.hibernate.orm.test.jpa.Wallet_; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.Jpa; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Query; +import jakarta.persistence.TypedQuery; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.ParameterExpression; +import jakarta.persistence.criteria.Root; + +import static org.junit.Assert.assertEquals; + + +@Jpa( + annotatedClasses = { Wallet.class, ReuseCriteriaWithMixedParametersTest.Person.class } +) +@TestForIssue(jiraKey = "HHH-15142") +public class ReuseCriteriaWithMixedParametersTest { + + @AfterEach + public void tearDown(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> + entityManager.createQuery( "delete from Person" ).executeUpdate() + ); + } + + @Test + public void cqReuse(EntityManagerFactoryScope scope) { + scope.inTransaction( entityManager -> { + final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + final CriteriaQuery criteriaQuery = criteriaBuilder.createQuery( Wallet.class ); + final Root root = criteriaQuery.from( Wallet.class ); + + final ParameterExpression stringValueParameter = criteriaBuilder.parameter( String.class ); + + criteriaQuery.where( + criteriaBuilder.like( + root.get( Wallet_.model ), + stringValueParameter + ), + criteriaBuilder.lessThan( + root.get( Wallet_.marketEntrance ), + criteriaBuilder.literal( Date.from( Instant.EPOCH ) ) + ) + ); + + Query query = entityManager.createQuery( criteriaQuery ); + query.setParameter( stringValueParameter, "Z%" ); + + query.getResultList(); + + query = entityManager.createQuery( criteriaQuery ); + query.setParameter( stringValueParameter, "A%" ); + + query.getResultList(); + + } ); + } + + @Test + public void likeCqReuse(EntityManagerFactoryScope scope) { + scope.inTransaction( entityManager -> { + + final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + final CriteriaQuery criteriaQuery = criteriaBuilder.createQuery( Wallet.class ); + final Root root = criteriaQuery.from( Wallet.class ); + + final ParameterExpression stringValueParameter = criteriaBuilder.parameter( String.class ); + + criteriaQuery.where( + criteriaBuilder.like( + root.get( Wallet_.model ), + stringValueParameter, + '/' + ) + ); + + Query query = entityManager.createQuery( criteriaQuery ); + query.setParameter( stringValueParameter, "Z%" ); + + query.getResultList(); + + query = entityManager.createQuery( criteriaQuery ); + query.setParameter( stringValueParameter, "A%" ); + + query.getResultList(); + + } ); + } + + @Test + public void predicateReuse(EntityManagerFactoryScope scope) { + scope.inTransaction( entityManager -> { + final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + final CriteriaQuery criteriaQuery = criteriaBuilder.createQuery( Wallet.class ); + final Root root = criteriaQuery.from( Wallet.class ); + + final ParameterExpression stringValueParameter = criteriaBuilder.parameter( String.class ); + final ParameterExpression dateValueParameter = criteriaBuilder.parameter( Date.class ); + + criteriaQuery.where( + criteriaBuilder.like( + root.get( Wallet_.model ), + stringValueParameter + ) + ); + + Query query = entityManager.createQuery( criteriaQuery ); + query.setParameter( stringValueParameter, "Z%" ); + + query.getResultList(); + + criteriaQuery.where( + criteriaBuilder.like( + root.get( Wallet_.model ), + stringValueParameter + ), + criteriaBuilder.lessThan( + root.get( Wallet_.marketEntrance ), + dateValueParameter + ) + ); + + query = entityManager.createQuery( criteriaQuery ); + query.setParameter( stringValueParameter, "A%" ); + query.setParameter( dateValueParameter, Date.from( Instant.EPOCH ) ); + + query.getResultList(); + } ); + } + + @Test + public void testLikePredicate(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> { + entityManager.persist( new Person( "Person 1" ) ); + entityManager.persist( new Person( "Person 2" ) ); + } + ); + + scope.inTransaction( + entityManager -> { + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + final CriteriaQuery personQuery = cb.createQuery( Person.class ); + final Root root = personQuery.from( Person.class ); + final ParameterExpression pattern = cb.parameter( String.class ); + CriteriaQuery criteriaQuery = personQuery + .where( cb.like( + root.get( "name" ), + pattern, + cb.literal( '\\' ) + ) ); + for ( int i = 0; i < 2; i++ ) { + final TypedQuery query = entityManager.createQuery( criteriaQuery ); + query.setParameter( pattern, "%_1" ); + final List result = query.getResultList(); + + assertEquals( 1, result.size() ); + } + } + ); + + } + + @Entity(name = "Person") + public static class Person { + @Id + @GeneratedValue + private Long id; + + private String name; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + +} +