HHH-15895 - IllegalArgumentException :Cannot create binding for parameter referencen with criteria builder
This commit is contained in:
parent
e65ded7a21
commit
7abc9f712c
|
@ -13,7 +13,6 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.query.internal.QueryParameterNamedImpl;
|
import org.hibernate.query.internal.QueryParameterNamedImpl;
|
||||||
import org.hibernate.query.internal.QueryParameterPositionalImpl;
|
import org.hibernate.query.internal.QueryParameterPositionalImpl;
|
||||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
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.SqmStatement;
|
||||||
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
|
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
|
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.SqmParameter;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maintains a cross-reference between SqmParameter and QueryParameter references.
|
* Maintains a cross-reference between SqmParameter and QueryParameter references.
|
||||||
|
@ -32,8 +29,7 @@ import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
|
||||||
*/
|
*/
|
||||||
public class DomainParameterXref {
|
public class DomainParameterXref {
|
||||||
/**
|
/**
|
||||||
* Create a DomainParameterXref for the parameters defined in the passed
|
* Create a DomainParameterXref for the parameters defined in the SQM statement
|
||||||
* SQM statement
|
|
||||||
*/
|
*/
|
||||||
public static DomainParameterXref from(SqmStatement<?> sqmStatement) {
|
public static DomainParameterXref from(SqmStatement<?> sqmStatement) {
|
||||||
// `xrefMap` is used to help maintain the proper cardinality between an
|
// `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
|
// `.. 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
|
// references (one for each occurrence of `:param`) both of which map to
|
||||||
// the same QueryParameter.
|
// the same QueryParameter.
|
||||||
final Map<SqmParameter, QueryParameterImplementor<?>> xrefMap = new TreeMap<>(
|
final Map<SqmParameter<?>, QueryParameterImplementor<?>> xrefMap = new TreeMap<>();
|
||||||
(o1, o2) ->
|
|
||||||
o1.compare( o2 )
|
|
||||||
);
|
|
||||||
|
|
||||||
final SqmStatement.ParameterResolutions parameterResolutions = sqmStatement.resolveParameters();
|
final SqmStatement.ParameterResolutions parameterResolutions = sqmStatement.resolveParameters();
|
||||||
if ( parameterResolutions.getSqmParameters().isEmpty() ) {
|
if ( parameterResolutions.getSqmParameters().isEmpty() ) {
|
||||||
|
|
|
@ -166,9 +166,9 @@ public class JpaCriteriaParameter<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(SqmParameter anotherParameter) {
|
public int compareTo(SqmParameter anotherParameter) {
|
||||||
return anotherParameter instanceof JpaCriteriaParameter ?
|
return anotherParameter instanceof JpaCriteriaParameter
|
||||||
Integer.compare( hashCode(), anotherParameter.hashCode() )
|
? Integer.compare( hashCode(), anotherParameter.hashCode() )
|
||||||
: 1;
|
: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,35 +124,9 @@ public class SqmJpaCriteriaParameterWrapper<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(SqmParameter anotherParameter) {
|
public int compareTo(SqmParameter anotherParameter) {
|
||||||
return anotherParameter instanceof SqmJpaCriteriaParameterWrapper ?
|
return anotherParameter instanceof SqmJpaCriteriaParameterWrapper ?
|
||||||
getJpaCriteriaParameter().compare( ( (SqmJpaCriteriaParameterWrapper<?>) anotherParameter ).getJpaCriteriaParameter() )
|
getJpaCriteriaParameter().compareTo( ( (SqmJpaCriteriaParameterWrapper<?>) anotherParameter ).getJpaCriteriaParameter() )
|
||||||
: 1;
|
: 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();
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class SqmNamedParameter<T> extends AbstractSqmParameter<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(SqmParameter anotherParameter) {
|
public int compareTo(SqmParameter anotherParameter) {
|
||||||
return anotherParameter instanceof SqmNamedParameter<?>
|
return anotherParameter instanceof SqmNamedParameter<?>
|
||||||
? getName().compareTo( ( (SqmNamedParameter<?>) anotherParameter ).getName() )
|
? getName().compareTo( ( (SqmNamedParameter<?>) anotherParameter ).getName() )
|
||||||
: -1;
|
: -1;
|
||||||
|
|
|
@ -23,7 +23,7 @@ import org.hibernate.query.sqm.tree.SqmCopyContext;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @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;
|
* If this represents a named parameter, return that parameter name;
|
||||||
* otherwise return {@code null}.
|
* otherwise return {@code null}.
|
||||||
|
@ -76,20 +76,25 @@ public interface SqmParameter<T> extends SqmExpression<T>, JpaParameterExpressio
|
||||||
@Override
|
@Override
|
||||||
SqmParameter<T> copy(SqmCopyContext context);
|
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 ) {
|
if ( this instanceof SqmNamedParameter ) {
|
||||||
final SqmNamedParameter<?> one = (SqmNamedParameter<?>) this;
|
final SqmNamedParameter<?> one = (SqmNamedParameter<?>) this;
|
||||||
return anotherParameter instanceof SqmNamedParameter<?>
|
return anotherParameter instanceof SqmNamedParameter<?>
|
||||||
? one.getName().compareTo( ( (SqmNamedParameter<?>) anotherParameter ).getName() )
|
? one.getName().compareTo( anotherParameter.getName() )
|
||||||
: -1;
|
: -1;
|
||||||
}
|
}
|
||||||
else if ( this instanceof SqmPositionalParameter ) {
|
else if ( this instanceof SqmPositionalParameter ) {
|
||||||
final SqmPositionalParameter<?> one = (SqmPositionalParameter<?>) this;
|
final SqmPositionalParameter<?> one = (SqmPositionalParameter<?>) this;
|
||||||
return anotherParameter instanceof SqmPositionalParameter<?>
|
return anotherParameter instanceof SqmPositionalParameter<?>
|
||||||
? one.getPosition().compareTo( ( (SqmPositionalParameter<?>) anotherParameter ).getPosition() )
|
? one.getPosition().compareTo( anotherParameter.getPosition() )
|
||||||
: 1;
|
: 1;
|
||||||
}
|
}
|
||||||
else if ( anotherParameter instanceof SqmJpaCriteriaParameterWrapper
|
else if ( this instanceof SqmJpaCriteriaParameterWrapper
|
||||||
&& anotherParameter instanceof SqmJpaCriteriaParameterWrapper ) {
|
&& anotherParameter instanceof SqmJpaCriteriaParameterWrapper ) {
|
||||||
return Integer.compare( this.hashCode(), anotherParameter.hashCode() );
|
return Integer.compare( this.hashCode(), anotherParameter.hashCode() );
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class SqmPositionalParameter<T> extends AbstractSqmParameter<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(SqmParameter anotherParameter) {
|
public int compareTo(SqmParameter anotherParameter) {
|
||||||
return anotherParameter instanceof SqmPositionalParameter<?>
|
return anotherParameter instanceof SqmPositionalParameter<?>
|
||||||
? getPosition().compareTo( ( (SqmPositionalParameter<?>) anotherParameter ).getPosition() )
|
? getPosition().compareTo( ( (SqmPositionalParameter<?>) anotherParameter ).getPosition() )
|
||||||
: 1;
|
: 1;
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.query.sqm.tree.expression;
|
package org.hibernate.query.sqm.tree.expression;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import org.hibernate.query.BindableType;
|
import org.hibernate.query.BindableType;
|
||||||
import org.hibernate.query.sqm.NodeBuilder;
|
import org.hibernate.query.sqm.NodeBuilder;
|
||||||
import org.hibernate.query.sqm.tree.SqmCopyContext;
|
import org.hibernate.query.sqm.tree.SqmCopyContext;
|
||||||
|
@ -54,10 +52,7 @@ public class ValueBindJpaCriteriaParameter<T> extends JpaCriteriaParameter<T>{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if ( this == o ) {
|
return this == o;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -66,7 +61,7 @@ public class ValueBindJpaCriteriaParameter<T> extends JpaCriteriaParameter<T>{
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(SqmParameter anotherParameter) {
|
public int compareTo(SqmParameter anotherParameter) {
|
||||||
if ( this == anotherParameter ) {
|
if ( this == anotherParameter ) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,15 +9,23 @@ package org.hibernate.orm.test.jpa.criteria;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.dialect.DB2Dialect;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.dialect.H2Dialect;
|
import org.hibernate.dialect.H2Dialect;
|
||||||
import org.hibernate.dialect.HSQLDialect;
|
import org.hibernate.dialect.HSQLDialect;
|
||||||
import org.hibernate.dialect.MariaDBDialect;
|
import org.hibernate.dialect.MariaDBDialect;
|
||||||
import org.hibernate.dialect.MySQLDialect;
|
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.TestForIssue;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Jpa;
|
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 org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
|
@ -30,42 +38,31 @@ import jakarta.persistence.criteria.Root;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
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")
|
@TestForIssue(jiraKey = "HHH-15895")
|
||||||
|
@DomainModel(annotatedClasses = InPredicateTest.Event.class)
|
||||||
|
@SessionFactory(exportSchema = false)
|
||||||
public class InPredicateTest {
|
public class InPredicateTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInPredicate(EntityManagerFactoryScope scope) {
|
public void testInPredicate(SessionFactoryScope scope) {
|
||||||
scope.inTransaction(
|
scope.inTransaction( (session) -> {
|
||||||
entityManager -> {
|
CriteriaBuilder cb = session.getCriteriaBuilder();
|
||||||
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
|
||||||
CriteriaQuery<Event> cr = cb.createQuery( Event.class );
|
CriteriaQuery<Event> cr = cb.createQuery( Event.class );
|
||||||
Root<Event> root = cr.from( 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 ) );
|
cr.select( root ).where( root.get( "name" ).in( names ) );
|
||||||
|
|
||||||
List<Event> results = entityManager.createQuery( cr ).getResultList();
|
// This should trigger the error from HHH-15895 as QuerySqmImpl
|
||||||
assertNotNull( results );
|
// tries to handle the Criteria parameters
|
||||||
}
|
session.createQuery( cr );
|
||||||
);
|
} );
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> getNames() {
|
||||||
|
int maxNames = 100000;
|
||||||
List<String> names = new ArrayList<>( maxNames );
|
List<String> names = new ArrayList<>( maxNames );
|
||||||
for ( int i = 0; i < maxNames; i++ ) {
|
for ( int i = 0; i < maxNames; i++ ) {
|
||||||
names.add( "abc" + i );
|
names.add( "abc" + i );
|
||||||
|
|
Loading…
Reference in New Issue