HHH-8454 - Criteria queries sometimes lead to SQL like "... where ? in (?,?)"
This commit is contained in:
parent
0ecb76f9d5
commit
1a59e9194b
|
@ -29,14 +29,19 @@ import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.persistence.criteria.Expression;
|
import javax.persistence.criteria.Expression;
|
||||||
|
import javax.persistence.criteria.ParameterExpression;
|
||||||
import javax.persistence.criteria.Subquery;
|
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.CriteriaBuilderImpl;
|
||||||
import org.hibernate.jpa.criteria.ParameterRegistry;
|
import org.hibernate.jpa.criteria.ParameterRegistry;
|
||||||
import org.hibernate.jpa.criteria.Renderable;
|
import org.hibernate.jpa.criteria.Renderable;
|
||||||
import org.hibernate.jpa.criteria.ValueHandlerFactory;
|
import org.hibernate.jpa.criteria.ValueHandlerFactory;
|
||||||
import org.hibernate.jpa.criteria.compile.RenderingContext;
|
import org.hibernate.jpa.criteria.compile.RenderingContext;
|
||||||
import org.hibernate.jpa.criteria.expression.LiteralExpression;
|
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
|
* Models an <tt>[NOT] IN</tt> restriction
|
||||||
|
@ -166,7 +171,22 @@ public class InPredicate<T>
|
||||||
@Override
|
@Override
|
||||||
public String render(boolean isNegated, RenderingContext renderingContext) {
|
public String render(boolean isNegated, RenderingContext renderingContext) {
|
||||||
final StringBuilder buffer = new StringBuilder();
|
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 ) {
|
if ( isNegated ) {
|
||||||
buffer.append( " not" );
|
buffer.append( " not" );
|
||||||
|
|
|
@ -94,6 +94,40 @@ public class ParameterTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
TypedQuery<MultiTypedBasicAttributesEntity> query = em.createQuery( criteria );
|
TypedQuery<MultiTypedBasicAttributesEntity> query = em.createQuery( criteria );
|
||||||
Parameter parameter = query.getParameter( "id" );
|
Parameter parameter = query.getParameter( "id" );
|
||||||
assertEquals( "id", parameter.getName() );
|
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
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue