diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/criteria/predicate/InPredicate.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/criteria/predicate/InPredicate.java index 8e698a0d8f..dc132b9db2 100755 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/criteria/predicate/InPredicate.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/criteria/predicate/InPredicate.java @@ -29,14 +29,19 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; import javax.persistence.criteria.Expression; +import javax.persistence.criteria.ParameterExpression; import javax.persistence.criteria.Subquery; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.jpa.criteria.CriteriaBuilderImpl; import org.hibernate.jpa.criteria.ParameterRegistry; import org.hibernate.jpa.criteria.Renderable; import org.hibernate.jpa.criteria.ValueHandlerFactory; import org.hibernate.jpa.criteria.compile.RenderingContext; import org.hibernate.jpa.criteria.expression.LiteralExpression; +import org.hibernate.jpa.criteria.expression.ParameterExpressionImpl; +import org.hibernate.type.Type; /** * Models an [NOT] IN restriction @@ -166,7 +171,22 @@ public class InPredicate @Override public String render(boolean isNegated, RenderingContext renderingContext) { final StringBuilder buffer = new StringBuilder(); - buffer.append( ( (Renderable) getExpression() ).render( renderingContext ) ); + final Expression exp = getExpression(); + if ( ParameterExpressionImpl.class.isInstance( exp ) ) { + // technically we only need to CAST (afaik) if expression and all values are parameters. + // but checking for that condition could take long time on a lon value list + final ParameterExpressionImpl parameterExpression = (ParameterExpressionImpl) exp; + final SessionFactoryImplementor sfi = criteriaBuilder().getEntityManagerFactory().unwrap( SessionFactoryImplementor.class ); + final Type mappingType = sfi.getTypeResolver().heuristicType( parameterExpression.getParameterType().getName() ); + buffer.append( "cast(" ) + .append( parameterExpression.render( renderingContext ) ) + .append( " as " ) + .append( mappingType.getName() ) + .append( ")" ); + } + else { + buffer.append( ( (Renderable) getExpression() ).render( renderingContext ) ); + } if ( isNegated ) { buffer.append( " not" ); diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/ParameterTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/ParameterTest.java index 164dc6f8ac..b9e887a85c 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/ParameterTest.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/ParameterTest.java @@ -94,6 +94,40 @@ public class ParameterTest extends BaseEntityManagerFunctionalTestCase { TypedQuery query = em.createQuery( criteria ); Parameter parameter = query.getParameter( "id" ); assertEquals( "id", parameter.getName() ); + + em.getTransaction().commit(); + em.close(); + } + + @Test + public void testParameterInParameterList() { + // Yes, this test makes no semantic sense. But the JPA TCK does it... + // it causes a problem on Derby, which does not like the form "... where ? in (?,?)" + // Derby wants one side or the other to be CAST (I assume so it can check typing). + + // IMPL NOTE : currently this does not assert the format of the ultimate SQL. We'll let the matrix runs + // verify that the generated SQL is valid for each DB + + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + CriteriaQuery criteria = em.getCriteriaBuilder() + .createQuery( MultiTypedBasicAttributesEntity.class ); + criteria.from( MultiTypedBasicAttributesEntity.class ); + + criteria.where( + em.getCriteriaBuilder().in( em.getCriteriaBuilder().parameter( Long.class, "p1" ) ) + .value( em.getCriteriaBuilder().parameter( Long.class, "p2" ) ) + .value( em.getCriteriaBuilder().parameter( Long.class, "p3" ) ) + ); + + TypedQuery query = em.createQuery( criteria ); + query.setParameter( "p1", 1L ); + query.setParameter( "p2", 2L ); + query.setParameter( "p3", 3L ); + query.getResultList(); + + em.getTransaction().commit(); + em.close(); } @Override