HHH-15895 - IllegalArgumentException :Cannot create binding for parameter referencen with criteria builder

This commit is contained in:
Steve Ebersole 2023-03-01 09:41:37 -06:00 committed by Christian Beikov
parent e65ded7a21
commit 7abc9f712c
8 changed files with 47 additions and 83 deletions

View File

@ -13,7 +13,6 @@ import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.hibernate.HibernateException;
import org.hibernate.query.internal.QueryParameterNamedImpl;
import org.hibernate.query.internal.QueryParameterPositionalImpl;
import org.hibernate.query.spi.QueryParameterImplementor;
@ -21,9 +20,7 @@ import org.hibernate.query.sqm.SqmTreeTransformationLogger;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
/**
* Maintains a cross-reference between SqmParameter and QueryParameter references.
@ -32,8 +29,7 @@ import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
*/
public class DomainParameterXref {
/**
* Create a DomainParameterXref for the parameters defined in the passed
* SQM statement
* Create a DomainParameterXref for the parameters defined in the SQM statement
*/
public static DomainParameterXref from(SqmStatement<?> sqmStatement) {
// `xrefMap` is used to help maintain the proper cardinality between an
@ -42,10 +38,7 @@ public class DomainParameterXref {
// `.. where a.b = :param or a.c = :param`. Here we have 2 SqmParameter
// references (one for each occurrence of `:param`) both of which map to
// the same QueryParameter.
final Map<SqmParameter, QueryParameterImplementor<?>> xrefMap = new TreeMap<>(
(o1, o2) ->
o1.compare( o2 )
);
final Map<SqmParameter<?>, QueryParameterImplementor<?>> xrefMap = new TreeMap<>();
final SqmStatement.ParameterResolutions parameterResolutions = sqmStatement.resolveParameters();
if ( parameterResolutions.getSqmParameters().isEmpty() ) {

View File

@ -166,9 +166,9 @@ public class JpaCriteriaParameter<T>
}
@Override
public int compare(SqmParameter anotherParameter) {
return anotherParameter instanceof JpaCriteriaParameter ?
Integer.compare( hashCode(), anotherParameter.hashCode() )
public int compareTo(SqmParameter anotherParameter) {
return anotherParameter instanceof JpaCriteriaParameter
? Integer.compare( hashCode(), anotherParameter.hashCode() )
: 1;
}
}

View File

@ -124,35 +124,9 @@ public class SqmJpaCriteriaParameterWrapper<T>
}
@Override
public int compare(SqmParameter anotherParameter) {
public int compareTo(SqmParameter anotherParameter) {
return anotherParameter instanceof SqmJpaCriteriaParameterWrapper ?
getJpaCriteriaParameter().compare( ( (SqmJpaCriteriaParameterWrapper<?>) anotherParameter ).getJpaCriteriaParameter() )
getJpaCriteriaParameter().compareTo( ( (SqmJpaCriteriaParameterWrapper<?>) anotherParameter ).getJpaCriteriaParameter() )
: 1;
}
// @Override
// public Expression toSqlExpression(
// Clause clause,
// SqmToSqlAstConverter walker,
// SqlAstCreationState sqlAstCreationState) {
//
// final MappingModelExpressible mappingModelExpressible = DomainModelHelper.resolveMappingModelExpressible(
// jpaCriteriaParameter,
// sqlAstCreationState
// );
//
// final List<JdbcMapping> jdbcMappings = mappingModelExpressible.getJdbcMappings(
// sqlAstCreationState.getCreationContext().getDomainModel().getTypeConfiguration()
// );
//
// if ( jdbcMappings.size() == 1 ) {
// return new JdbcParameterImpl( jdbcMappings.get( 0 ) );
// }
//
// final SqlTuple.Builder tupleBuilder = new SqlTuple.Builder( mappingModelExpressible );
// for ( JdbcMapping jdbcMapping : jdbcMappings ) {
// tupleBuilder.addSubExpression( new JdbcParameterImpl( jdbcMapping ) );
// }
// return tupleBuilder.buildTuple();
// }
}

View File

@ -83,7 +83,7 @@ public class SqmNamedParameter<T> extends AbstractSqmParameter<T> {
}
@Override
public int compare(SqmParameter anotherParameter) {
public int compareTo(SqmParameter anotherParameter) {
return anotherParameter instanceof SqmNamedParameter<?>
? getName().compareTo( ( (SqmNamedParameter<?>) anotherParameter ).getName() )
: -1;

View File

@ -23,7 +23,7 @@ import org.hibernate.query.sqm.tree.SqmCopyContext;
*
* @author Steve Ebersole
*/
public interface SqmParameter<T> extends SqmExpression<T>, JpaParameterExpression<T> {
public interface SqmParameter<T> extends SqmExpression<T>, JpaParameterExpression<T>, Comparable<SqmParameter<T>> {
/**
* If this represents a named parameter, return that parameter name;
* otherwise return {@code null}.
@ -76,20 +76,25 @@ public interface SqmParameter<T> extends SqmExpression<T>, JpaParameterExpressio
@Override
SqmParameter<T> copy(SqmCopyContext context);
default int compare(SqmParameter anotherParameter) {
/**
* @implSpec Defined as default since this is an SPI to
* support any previous extensions
*/
@Override
default int compareTo(SqmParameter<T> anotherParameter) {
if ( this instanceof SqmNamedParameter ) {
final SqmNamedParameter<?> one = (SqmNamedParameter<?>) this;
return anotherParameter instanceof SqmNamedParameter<?>
? one.getName().compareTo( ( (SqmNamedParameter<?>) anotherParameter ).getName() )
? one.getName().compareTo( anotherParameter.getName() )
: -1;
}
else if ( this instanceof SqmPositionalParameter ) {
final SqmPositionalParameter<?> one = (SqmPositionalParameter<?>) this;
return anotherParameter instanceof SqmPositionalParameter<?>
? one.getPosition().compareTo( ( (SqmPositionalParameter<?>) anotherParameter ).getPosition() )
? one.getPosition().compareTo( anotherParameter.getPosition() )
: 1;
}
else if ( anotherParameter instanceof SqmJpaCriteriaParameterWrapper
else if ( this instanceof SqmJpaCriteriaParameterWrapper
&& anotherParameter instanceof SqmJpaCriteriaParameterWrapper ) {
return Integer.compare( this.hashCode(), anotherParameter.hashCode() );
}

View File

@ -86,7 +86,7 @@ public class SqmPositionalParameter<T> extends AbstractSqmParameter<T> {
}
@Override
public int compare(SqmParameter anotherParameter) {
public int compareTo(SqmParameter anotherParameter) {
return anotherParameter instanceof SqmPositionalParameter<?>
? getPosition().compareTo( ( (SqmPositionalParameter<?>) anotherParameter ).getPosition() )
: 1;

View File

@ -6,8 +6,6 @@
*/
package org.hibernate.query.sqm.tree.expression;
import java.util.Objects;
import org.hibernate.query.BindableType;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.tree.SqmCopyContext;
@ -54,10 +52,7 @@ public class ValueBindJpaCriteriaParameter<T> extends JpaCriteriaParameter<T>{
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
return false;
return this == o;
}
@Override
@ -66,7 +61,7 @@ public class ValueBindJpaCriteriaParameter<T> extends JpaCriteriaParameter<T>{
}
@Override
public int compare(SqmParameter anotherParameter) {
public int compareTo(SqmParameter anotherParameter) {
if ( this == anotherParameter ) {
return 0;
}

View File

@ -9,15 +9,23 @@ package org.hibernate.orm.test.jpa.criteria;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.SkipForDialect;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Entity;
@ -30,42 +38,31 @@ import jakarta.persistence.criteria.Root;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@Jpa(annotatedClasses = {
InPredicateTest.Event.class
})
/**
* @implNote Skipped for Dialects which do not support at lease
*/
@TestForIssue(jiraKey = "HHH-15895")
@DomainModel(annotatedClasses = InPredicateTest.Event.class)
@SessionFactory(exportSchema = false)
public class InPredicateTest {
@Test
public void testInPredicate(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
public void testInPredicate(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Event> cr = cb.createQuery( Event.class );
Root<Event> root = cr.from( Event.class );
List<String> names = getNames( scope );
List<String> names = getNames();
cr.select( root ).where( root.get( "name" ).in( names ) );
List<Event> results = entityManager.createQuery( cr ).getResultList();
assertNotNull( results );
}
);
}
private List<String> getNames(EntityManagerFactoryScope scope) {
int maxNames;
Dialect dialect = scope.getDialect();
if ( dialect instanceof H2Dialect
|| dialect instanceof MariaDBDialect
|| dialect instanceof HSQLDialect
|| dialect instanceof MySQLDialect ) {
maxNames = 100000;
}
else {
// the other dialects does not support 100000 parameters
maxNames = 65500;
// This should trigger the error from HHH-15895 as QuerySqmImpl
// tries to handle the Criteria parameters
session.createQuery( cr );
} );
}
private List<String> getNames() {
int maxNames = 100000;
List<String> names = new ArrayList<>( maxNames );
for ( int i = 0; i < maxNames; i++ ) {
names.add( "abc" + i );