HHH-8454 - Criteria queries sometimes lead to SQL like "... where ? in (?,?)"

This commit is contained in:
Steve Ebersole 2013-08-25 20:01:00 -05:00
parent 0ecb76f9d5
commit 1a59e9194b
2 changed files with 55 additions and 1 deletions

View File

@ -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 <tt>[NOT] IN</tt> restriction
@ -166,7 +171,22 @@ public class InPredicate<T>
@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" );

View File

@ -94,6 +94,40 @@ public class ParameterTest extends BaseEntityManagerFunctionalTestCase {
TypedQuery<MultiTypedBasicAttributesEntity> 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<MultiTypedBasicAttributesEntity> 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<MultiTypedBasicAttributesEntity> query = em.createQuery( criteria );
query.setParameter( "p1", 1L );
query.setParameter( "p2", 2L );
query.setParameter( "p3", 3L );
query.getResultList();
em.getTransaction().commit();
em.close();
}
@Override