HHH-16815 fix generic signature of ascending() / descending()

+ code cleanups in the Query hierarchy
This commit is contained in:
Gavin King 2023-06-17 21:52:02 +02:00
parent 3211cb8e9b
commit 7ecec615d3
9 changed files with 208 additions and 270 deletions

View File

@ -1065,12 +1065,12 @@ public class ProcedureCallImpl<R>
} }
@Override @Override
public Query<R> ascending(SingularAttribute<R, ?> attribute) { public Query<R> ascending(SingularAttribute<? super R, ?> attribute) {
throw new UnsupportedOperationException( "Not supported for procedure calls" ); throw new UnsupportedOperationException( "Not supported for procedure calls" );
} }
@Override @Override
public Query<R> descending(SingularAttribute<R, ?> attribute) { public Query<R> descending(SingularAttribute<? super R, ?> attribute) {
throw new UnsupportedOperationException( "Not supported for procedure calls" ); throw new UnsupportedOperationException( "Not supported for procedure calls" );
} }

View File

@ -900,10 +900,10 @@ public interface Query<R> extends SelectionQuery<R>, MutationQuery, TypedQuery<R
Query<R> setLockMode(LockModeType lockMode); Query<R> setLockMode(LockModeType lockMode);
@Override @Override
Query<R> ascending(SingularAttribute<R, ?> attribute); Query<R> ascending(SingularAttribute<? super R, ?> attribute);
@Override @Override
Query<R> descending(SingularAttribute<R, ?> attribute); Query<R> descending(SingularAttribute<? super R, ?> attribute);
@Override @Override
Query<R> unordered(); Query<R> unordered();

View File

@ -472,10 +472,10 @@ public interface SelectionQuery<R> extends CommonQueryContract {
SelectionQuery<R> setLockMode(String alias, LockMode lockMode); SelectionQuery<R> setLockMode(String alias, LockMode lockMode);
@Incubating @Incubating
SelectionQuery<R> ascending(SingularAttribute<R, ?> attribute); SelectionQuery<R> ascending(SingularAttribute<? super R, ?> attribute);
@Incubating @Incubating
SelectionQuery<R> descending(SingularAttribute<R, ?> attribute); SelectionQuery<R> descending(SingularAttribute<? super R, ?> attribute);
@Incubating @Incubating
SelectionQuery<R> unordered(); SelectionQuery<R> unordered();

View File

@ -125,18 +125,18 @@ public interface SqmQueryImplementor<R> extends QueryImplementor<R>, SqmQuery, N
SqmQueryImplementor<R> setLockMode(LockModeType lockMode); SqmQueryImplementor<R> setLockMode(LockModeType lockMode);
@Override @Override
default SqmQueryImplementor<R> ascending(SingularAttribute<R, ?> attribute) { default SqmQueryImplementor<R> ascending(SingularAttribute<? super R, ?> attribute) {
addOrdering( attribute, SortOrder.ASCENDING ); addOrdering( attribute, SortOrder.ASCENDING );
return this; return this;
} }
@Override @Override
default SqmQueryImplementor<R> descending(SingularAttribute<R, ?> attribute) { default SqmQueryImplementor<R> descending(SingularAttribute<? super R, ?> attribute) {
addOrdering( attribute, SortOrder.DESCENDING ); addOrdering( attribute, SortOrder.DESCENDING );
return this; return this;
} }
SqmQueryImplementor<R> addOrdering(SingularAttribute<R, ?> attribute, SortOrder order); SqmQueryImplementor<R> addOrdering(SingularAttribute<? super R, ?> attribute, SortOrder order);
@Override @Override
SqmQueryImplementor<R> unordered(); SqmQueryImplementor<R> unordered();

View File

@ -71,6 +71,7 @@ import org.hibernate.sql.exec.internal.CallbackImpl;
import org.hibernate.sql.exec.spi.Callback; import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.results.internal.TupleMetadata; import org.hibernate.sql.results.internal.TupleMetadata;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.spi.PrimitiveJavaType; import org.hibernate.type.descriptor.java.spi.PrimitiveJavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType;
@ -138,52 +139,52 @@ public abstract class AbstractSelectionQuery<R>
} }
private static TupleElement<?>[] buildTupleElementArray(List<SqmSelection<?>> selections) { private static TupleElement<?>[] buildTupleElementArray(List<SqmSelection<?>> selections) {
final TupleElement<?>[] elements;
if ( selections.size() == 1 ) { if ( selections.size() == 1 ) {
final SqmSelectableNode<?> selectableNode = selections.get(0).getSelectableNode(); final SqmSelectableNode<?> selectableNode = selections.get(0).getSelectableNode();
if ( selectableNode instanceof CompoundSelection<?> ) { if ( selectableNode instanceof CompoundSelection<?> ) {
final List<? extends JpaSelection<?>> selectionItems = selectableNode.getSelectionItems(); final List<? extends JpaSelection<?>> selectionItems = selectableNode.getSelectionItems();
elements = new TupleElement<?>[ selectionItems.size() ]; final TupleElement<?>[] elements = new TupleElement<?>[ selectionItems.size() ];
for ( int i = 0; i < selectionItems.size(); i++ ) { for ( int i = 0; i < selectionItems.size(); i++ ) {
elements[i] = selectionItems.get( i ); elements[i] = selectionItems.get( i );
} }
return elements;
} }
else { else {
elements = new TupleElement<?>[] { selectableNode }; return new TupleElement<?>[] { selectableNode };
} }
} }
else { else {
elements = new TupleElement<?>[ selections.size() ]; final TupleElement<?>[] elements = new TupleElement<?>[ selections.size() ];
for ( int i = 0; i < selections.size(); i++ ) { for ( int i = 0; i < selections.size(); i++ ) {
elements[i] = selections.get( i ).getSelectableNode(); elements[i] = selections.get( i ).getSelectableNode();
} }
}
return elements; return elements;
} }
}
private static String[] buildTupleAliasArray(List<SqmSelection<?>> selections) { private static String[] buildTupleAliasArray(List<SqmSelection<?>> selections) {
final String[] elements;
if ( selections.size() == 1 ) { if ( selections.size() == 1 ) {
final SqmSelectableNode<?> selectableNode = selections.get(0).getSelectableNode(); final SqmSelectableNode<?> selectableNode = selections.get(0).getSelectableNode();
if ( selectableNode instanceof CompoundSelection<?> ) { if ( selectableNode instanceof CompoundSelection<?> ) {
final List<? extends JpaSelection<?>> selectionItems = selectableNode.getSelectionItems(); final List<? extends JpaSelection<?>> selectionItems = selectableNode.getSelectionItems();
elements = new String[ selectionItems.size() ]; final String[] elements = new String[ selectionItems.size() ];
for ( int i = 0; i < selectionItems.size(); i++ ) { for ( int i = 0; i < selectionItems.size(); i++ ) {
elements[i] = selectionItems.get( i ).getAlias(); elements[i] = selectionItems.get( i ).getAlias();
} }
return elements;
} }
else { else {
elements = new String[] { selectableNode.getAlias() }; return new String[] { selectableNode.getAlias() };
} }
} }
else { else {
elements = new String[ selections.size() ]; final String[] elements = new String[ selections.size() ];
for ( int i = 0; i < selections.size(); i++ ) { for ( int i = 0; i < selections.size(); i++ ) {
elements[i] = selections.get( i ).getAlias(); elements[i] = selections.get( i ).getAlias();
} }
}
return elements; return elements;
} }
}
protected void applyOptions(NamedSqmQueryMemento memento) { protected void applyOptions(NamedSqmQueryMemento memento) {
applyOptions( (NamedQueryMemento) memento ); applyOptions( (NamedQueryMemento) memento );
@ -197,14 +198,13 @@ public abstract class AbstractSelectionQuery<R>
} }
if ( memento.getParameterTypes() != null ) { if ( memento.getParameterTypes() != null ) {
final BasicTypeRegistry basicTypeRegistry =
getSessionFactory().getTypeConfiguration().getBasicTypeRegistry();
for ( Map.Entry<String, String> entry : memento.getParameterTypes().entrySet() ) { for ( Map.Entry<String, String> entry : memento.getParameterTypes().entrySet() ) {
final QueryParameterImplementor<?> parameter =
getParameterMetadata().getQueryParameter( entry.getKey() );
final BasicType<?> type = final BasicType<?> type =
getSessionFactory().getTypeConfiguration() basicTypeRegistry.getRegisteredType( entry.getValue() );
.getBasicTypeRegistry() getParameterMetadata()
.getRegisteredType( entry.getValue() ); .getQueryParameter( entry.getKey() ).applyAnticipatedType( type );
parameter.applyAnticipatedType( type );
} }
} }
} }
@ -270,11 +270,10 @@ public abstract class AbstractSelectionQuery<R>
} }
// if there is a single root, use that as the selection // if there is a single root, use that as the selection
if ( sqmRoots.size() == 1 ) { if ( sqmRoots.size() == 1 ) {
final SqmRoot<?> sqmRoot = sqmRoots.get( 0 ); sqmQuerySpec.getSelectClause().add( sqmRoots.get( 0 ), null );
sqmQuerySpec.getSelectClause().add( sqmRoot, null );
} }
else { else {
throw new IllegalArgumentException( ); throw new IllegalArgumentException( "Criteria has multiple query roots" );
} }
} }
@ -313,11 +312,7 @@ public abstract class AbstractSelectionQuery<R>
} }
} }
final boolean jpaQueryComplianceEnabled = if ( !sessionFactory.getSessionFactoryOptions().getJpaCompliance().isJpaQueryComplianceEnabled() ) {
sessionFactory.getSessionFactoryOptions()
.getJpaCompliance()
.isJpaQueryComplianceEnabled();
if ( !jpaQueryComplianceEnabled ) {
verifyResultType( expectedResultClass, sqmSelection.getNodeType() ); verifyResultType( expectedResultClass, sqmSelection.getNodeType() );
} }
} }
@ -347,16 +342,15 @@ public abstract class AbstractSelectionQuery<R>
final Class<?> javaTypeClass = expressibleJavaType.getJavaTypeClass(); final Class<?> javaTypeClass = expressibleJavaType.getJavaTypeClass();
if ( !resultClass.isAssignableFrom( javaTypeClass ) ) { if ( !resultClass.isAssignableFrom( javaTypeClass ) ) {
if ( expressibleJavaType instanceof PrimitiveJavaType ) { if ( expressibleJavaType instanceof PrimitiveJavaType ) {
if ( ( (PrimitiveJavaType<?>) expressibleJavaType ).getPrimitiveClass() != resultClass ) { final PrimitiveJavaType<?> javaType = (PrimitiveJavaType<?>) expressibleJavaType;
if ( javaType.getPrimitiveClass() != resultClass ) {
throwQueryTypeMismatchException( resultClass, sqmExpressible ); throwQueryTypeMismatchException( resultClass, sqmExpressible );
} }
} }
else if ( isMatchingDateType( javaTypeClass, resultClass, sqmExpressible ) ) { else if ( !isMatchingDateType( javaTypeClass, resultClass, sqmExpressible ) ) {
// special case, we are good
}
else {
throwQueryTypeMismatchException( resultClass, sqmExpressible ); throwQueryTypeMismatchException( resultClass, sqmExpressible );
} }
// else special case, we are good
} }
} }
@ -375,7 +369,8 @@ public abstract class AbstractSelectionQuery<R>
return ( (BasicDomainType<?>) sqmExpressible).getJdbcType(); return ( (BasicDomainType<?>) sqmExpressible).getJdbcType();
} }
else if ( sqmExpressible instanceof SqmPathSource<?> ) { else if ( sqmExpressible instanceof SqmPathSource<?> ) {
final DomainType<?> domainType = ( (SqmPathSource<?>) sqmExpressible).getSqmPathType(); final SqmPathSource<?> pathSource = (SqmPathSource<?>) sqmExpressible;
final DomainType<?> domainType = pathSource.getSqmPathType();
if ( domainType instanceof BasicDomainType<?> ) { if ( domainType instanceof BasicDomainType<?> ) {
return ( (BasicDomainType<?>) domainType ).getJdbcType(); return ( (BasicDomainType<?>) domainType ).getJdbcType();
} }

View File

@ -1501,12 +1501,12 @@ public class NativeQueryImpl<R>
} }
@Override @Override
public Query<R> ascending(SingularAttribute<R, ?> attribute) { public Query<R> ascending(SingularAttribute<? super R, ?> attribute) {
throw new UnsupportedOperationException("Not yet supported for native queries"); throw new UnsupportedOperationException("Not yet supported for native queries");
} }
@Override @Override
public Query<R> descending(SingularAttribute<R, ?> attribute) { public Query<R> descending(SingularAttribute<? super R, ?> attribute) {
throw new UnsupportedOperationException("Not yet supported for native queries"); throw new UnsupportedOperationException("Not yet supported for native queries");
} }

View File

@ -27,6 +27,7 @@ import org.hibernate.LockMode;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.TypeMismatchException; import org.hibernate.TypeMismatchException;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.query.spi.EntityGraphQueryHint; import org.hibernate.engine.query.spi.EntityGraphQueryHint;
import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
@ -123,7 +124,10 @@ import static org.hibernate.jpa.SpecHints.HINT_SPEC_CACHE_RETRIEVE_MODE;
import static org.hibernate.jpa.SpecHints.HINT_SPEC_CACHE_STORE_MODE; import static org.hibernate.jpa.SpecHints.HINT_SPEC_CACHE_STORE_MODE;
import static org.hibernate.query.spi.SqlOmittingQueryOptions.omitSqlQueryOptions; import static org.hibernate.query.spi.SqlOmittingQueryOptions.omitSqlQueryOptions;
import static org.hibernate.query.spi.SqlOmittingQueryOptions.omitSqlQueryOptionsWithUniqueSemanticFilter; import static org.hibernate.query.spi.SqlOmittingQueryOptions.omitSqlQueryOptionsWithUniqueSemanticFilter;
import static org.hibernate.query.sqm.internal.SqmInterpretationsKey.createInterpretationsKey;
import static org.hibernate.query.sqm.internal.SqmInterpretationsKey.generateNonSelectKey;
import static org.hibernate.query.sqm.internal.SqmUtil.isSelect; import static org.hibernate.query.sqm.internal.SqmUtil.isSelect;
import static org.hibernate.query.sqm.internal.SqmUtil.verifyIsNonSelectStatement;
/** /**
* {@link Query} implementation based on an SQM * {@link Query} implementation based on an SQM
@ -158,8 +162,7 @@ public class QuerySqmImpl<R>
this.hql = memento.getHqlString(); this.hql = memento.getHqlString();
this.resultType = expectedResultType; this.resultType = expectedResultType;
final SessionFactoryImplementor factory = session.getFactory(); final QueryEngine queryEngine = session.getFactory().getQueryEngine();
final QueryEngine queryEngine = factory.getQueryEngine();
final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache(); final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache();
final HqlInterpretation hqlInterpretation = interpretationCache.resolveHqlInterpretation( final HqlInterpretation hqlInterpretation = interpretationCache.resolveHqlInterpretation(
hql, hql,
@ -225,39 +228,32 @@ public class QuerySqmImpl<R>
Class<R> expectedResultType, Class<R> expectedResultType,
SharedSessionContractImplementor producer) { SharedSessionContractImplementor producer) {
super( producer ); super( producer );
this.hql = CRITERIA_HQL_STRING; hql = CRITERIA_HQL_STRING;
if ( producer.isCriteriaCopyTreeEnabled() ) { if ( producer.isCriteriaCopyTreeEnabled() ) {
this.sqm = criteria.copy( SqmCopyContext.simpleContext() ); sqm = criteria.copy( SqmCopyContext.simpleContext() );
} }
else { else {
this.sqm = criteria; sqm = criteria;
// Cache immutable query plans by default // Cache immutable query plans by default
setQueryPlanCacheable( true ); setQueryPlanCacheable( true );
} }
setComment( hql ); setComment( hql );
this.domainParameterXref = DomainParameterXref.from( this.sqm ); domainParameterXref = DomainParameterXref.from( sqm );
if ( ! domainParameterXref.hasParameters() ) { if ( ! domainParameterXref.hasParameters() ) {
this.parameterMetadata = ParameterMetadataImpl.EMPTY; parameterMetadata = ParameterMetadataImpl.EMPTY;
} }
else { else {
this.parameterMetadata = new ParameterMetadataImpl( domainParameterXref.getQueryParameters() ); parameterMetadata = new ParameterMetadataImpl( domainParameterXref.getQueryParameters() );
} }
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, producer.getFactory() ); parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, producer.getFactory() );
// Parameters might be created through HibernateCriteriaBuilder.value which we need to bind here // Parameters might be created through HibernateCriteriaBuilder.value which we need to bind here
for ( SqmParameter<?> sqmParameter : this.domainParameterXref.getParameterResolutions().getSqmParameters() ) { for ( SqmParameter<?> sqmParameter : domainParameterXref.getParameterResolutions().getSqmParameters() ) {
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> ) { if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> ) {
final JpaCriteriaParameter<Object> jpaCriteriaParameter = ( (SqmJpaCriteriaParameterWrapper<Object>) sqmParameter ).getJpaCriteriaParameter(); bindCriteriaParameter((SqmJpaCriteriaParameterWrapper<?>) sqmParameter);
final Object value = jpaCriteriaParameter.getValue();
// We don't set a null value, unless the type is also null which is the case when using HibernateCriteriaBuilder.value
if ( value != null || jpaCriteriaParameter.getNodeType() == null ) {
// Use the anticipated type for binding the value if possible
getQueryParameterBindings().getBinding( jpaCriteriaParameter )
.setBindValue( value, jpaCriteriaParameter.getAnticipatedType() );
}
} }
} }
@ -274,18 +270,13 @@ public class QuerySqmImpl<R>
} }
else { else {
if ( expectedResultType != null ) { if ( expectedResultType != null ) {
throw new IllegalQueryOperationException( throw new IllegalQueryOperationException( "Result type given for a non-SELECT Query", hql, null );
"Result type given for a non-SELECT Query",
hql,
null
);
} }
if ( sqm instanceof SqmUpdateStatement<?> ) { if ( sqm instanceof SqmUpdateStatement<?> ) {
final SqmUpdateStatement<R> updateStatement = (SqmUpdateStatement<R>) sqm; final SqmUpdateStatement<R> updateStatement = (SqmUpdateStatement<R>) sqm;
verifyImmutableEntityUpdate( CRITERIA_HQL_STRING, updateStatement, producer.getFactory() ); verifyImmutableEntityUpdate( CRITERIA_HQL_STRING, updateStatement, producer.getFactory() );
if ( updateStatement.getSetClause() == null || updateStatement.getSetClause() if ( updateStatement.getSetClause() == null
.getAssignments() || updateStatement.getSetClause().getAssignments().isEmpty() ) {
.isEmpty() ) {
throw new IllegalArgumentException( "No assignments specified as part of UPDATE criteria" ); throw new IllegalArgumentException( "No assignments specified as part of UPDATE criteria" );
} }
} }
@ -294,8 +285,20 @@ public class QuerySqmImpl<R>
} }
} }
this.resultType = expectedResultType; resultType = expectedResultType;
this.tupleMetadata = buildTupleMetadata( criteria, expectedResultType ); tupleMetadata = buildTupleMetadata( criteria, expectedResultType );
}
private <T> void bindCriteriaParameter(SqmJpaCriteriaParameterWrapper<T> sqmParameter) {
final JpaCriteriaParameter<T> jpaCriteriaParameter = sqmParameter.getJpaCriteriaParameter();
final T value = jpaCriteriaParameter.getValue();
// We don't set a null value, unless the type is also null which
// is the case when using HibernateCriteriaBuilder.value
if ( value != null || jpaCriteriaParameter.getNodeType() == null ) {
// Use the anticipated type for binding the value if possible
getQueryParameterBindings().getBinding( jpaCriteriaParameter )
.setBindValue( value, jpaCriteriaParameter.getAnticipatedType() );
}
} }
private void validateStatement(SqmStatement<R> sqmStatement, Class<R> resultType) { private void validateStatement(SqmStatement<R> sqmStatement, Class<R> resultType) {
@ -304,11 +307,7 @@ public class QuerySqmImpl<R>
} }
else { else {
if ( resultType != null ) { if ( resultType != null ) {
throw new IllegalQueryOperationException( throw new IllegalQueryOperationException( "Result type given for a non-SELECT Query", hql, null );
"Result type given for a non-SELECT Query",
hql,
null
);
} }
if ( sqmStatement instanceof SqmUpdateStatement<?> ) { if ( sqmStatement instanceof SqmUpdateStatement<?> ) {
final SqmUpdateStatement<R> updateStatement = (SqmUpdateStatement<R>) sqmStatement; final SqmUpdateStatement<R> updateStatement = (SqmUpdateStatement<R>) sqmStatement;
@ -325,30 +324,22 @@ public class QuerySqmImpl<R>
String hqlString, String hqlString,
SqmUpdateStatement<R> sqmStatement, SqmUpdateStatement<R> sqmStatement,
SessionFactoryImplementor factory) { SessionFactoryImplementor factory) {
final EntityPersister entityDescriptor = factory.getRuntimeMetamodels() final EntityPersister persister =
.getMappingMetamodel() factory.getMappingMetamodel().getEntityDescriptor( sqmStatement.getTarget().getEntityName() );
.getEntityDescriptor( sqmStatement.getTarget().getEntityName() ); if ( !persister.isMutable() ) {
if ( entityDescriptor.isMutable() ) { final ImmutableEntityUpdateQueryHandlingMode mode =
return; factory.getSessionFactoryOptions().getImmutableEntityUpdateQueryHandlingMode();
} final String querySpaces = Arrays.toString( persister.getQuerySpaces() );
final ImmutableEntityUpdateQueryHandlingMode immutableEntityUpdateQueryHandlingMode = factory switch ( mode ) {
.getSessionFactoryOptions()
.getImmutableEntityUpdateQueryHandlingMode();
final String querySpaces = Arrays.toString( entityDescriptor.getQuerySpaces() );
switch ( immutableEntityUpdateQueryHandlingMode ) {
case WARNING: case WARNING:
LOG.immutableEntityUpdateQuery( hqlString, querySpaces ); LOG.immutableEntityUpdateQuery( hqlString, querySpaces );
break; break;
case EXCEPTION: case EXCEPTION:
throw new HibernateException( throw new HibernateException( "The query [" + hqlString + "] attempts to update an immutable entity: "
"The query: [" + hqlString + "] attempts to update an immutable entity: " + querySpaces + querySpaces );
);
default: default:
throw new UnsupportedOperationException( throw new UnsupportedOperationException( "The " + mode + " is not supported" );
"The " + immutableEntityUpdateQueryHandlingMode + " is not supported" }
);
} }
} }
@ -387,7 +378,8 @@ public class QuerySqmImpl<R>
} }
else { else {
final SqmInsertSelectStatement<R> statement = (SqmInsertSelectStatement<R>) sqmStatement; final SqmInsertSelectStatement<R> statement = (SqmInsertSelectStatement<R>) sqmStatement;
final List<SqmSelectableNode<?>> selections = statement.getSelectQueryPart() final List<SqmSelectableNode<?>> selections =
statement.getSelectQueryPart()
.getFirstQuerySpec() .getFirstQuerySpec()
.getSelectClause() .getSelectClause()
.getSelectionItems(); .getSelectionItems();
@ -515,14 +507,15 @@ public class QuerySqmImpl<R>
verifySelect(); verifySelect();
final SqmSelectStatement<?> sqmStatement = (SqmSelectStatement<?>) getSqmStatement(); final SqmSelectStatement<?> sqmStatement = (SqmSelectStatement<?>) getSqmStatement();
final boolean containsCollectionFetches = sqmStatement.containsCollectionFetches() || AppliedGraphs.containsCollectionFetches( final boolean containsCollectionFetches =
getQueryOptions() ); sqmStatement.containsCollectionFetches()
|| AppliedGraphs.containsCollectionFetches( getQueryOptions() );
final boolean hasLimit = hasLimit( sqmStatement, getQueryOptions() ); final boolean hasLimit = hasLimit( sqmStatement, getQueryOptions() );
final boolean needsDistinct = containsCollectionFetches final boolean needsDistinct = containsCollectionFetches
&& ( sqmStatement.usesDistinct() || hasAppliedGraph( getQueryOptions() ) || hasLimit ); && ( hasLimit || sqmStatement.usesDistinct() || hasAppliedGraph( getQueryOptions() ) );
final List<R> list = resolveSelectQueryPlan() final List<R> list = resolveSelectQueryPlan()
.performList( executionContextFordoList( containsCollectionFetches, hasLimit, needsDistinct ) ); .performList( executionContextForDoList( containsCollectionFetches, hasLimit, needsDistinct ) );
if ( needsDistinct ) { if ( needsDistinct ) {
final int first = !hasLimit || getQueryOptions().getLimit().getFirstRow() == null final int first = !hasLimit || getQueryOptions().getLimit().getFirstRow() == null
@ -532,52 +525,54 @@ public class QuerySqmImpl<R>
? getMaxRows( sqmStatement, list.size() ) ? getMaxRows( sqmStatement, list.size() )
: getQueryOptions().getLimit().getMaxRows(); : getQueryOptions().getLimit().getMaxRows();
if ( first > 0 || max != -1 ) { if ( first > 0 || max != -1 ) {
final int toIndex;
final int resultSize = list.size(); final int resultSize = list.size();
if ( max != -1 ) { final int toIndex = max != -1 ? first + max : resultSize;
toIndex = first + max;
}
else {
toIndex = resultSize;
}
if ( first > resultSize ) { if ( first > resultSize ) {
return new ArrayList<>(0); return new ArrayList<>(0);
} }
return list.subList( first, toIndex > resultSize ? resultSize : toIndex ); return list.subList( first, Math.min( toIndex, resultSize ) );
} }
} }
return list; return list;
} }
protected DomainQueryExecutionContext executionContextFordoList(boolean containsCollectionFetches, boolean hasLimit, boolean needsDistinct) { protected DomainQueryExecutionContext executionContextForDoList(boolean containsCollectionFetches, boolean hasLimit, boolean needsDistinct) {
final DomainQueryExecutionContext executionContextToUse; final MutableQueryOptions originalQueryOptions;
final QueryOptions normalizedQueryOptions;
if ( hasLimit && containsCollectionFetches ) { if ( hasLimit && containsCollectionFetches ) {
boolean fail = getSessionFactory().getSessionFactoryOptions().isFailOnPaginationOverCollectionFetchEnabled(); if ( getSessionFactory().getSessionFactoryOptions().isFailOnPaginationOverCollectionFetchEnabled() ) {
if (fail) {
throw new HibernateException( throw new HibernateException(
"firstResult/maxResults specified with collection fetch. " + "setFirstResult() or setMaxResults() specified with collection fetch join "
"In memory pagination was about to be applied. " + + "(in-memory pagination was about to be applied, but '"
"Failing because 'Fail on pagination over collection fetch' is enabled." + AvailableSettings.FAIL_ON_PAGINATION_OVER_COLLECTION_FETCH
+ "' is enabled)"
); );
} }
else { else {
QueryLogging.QUERY_MESSAGE_LOGGER.firstOrMaxResultsSpecifiedWithCollectionFetch(); QueryLogging.QUERY_MESSAGE_LOGGER.firstOrMaxResultsSpecifiedWithCollectionFetch();
} }
final MutableQueryOptions originalQueryOptions = getQueryOptions(); originalQueryOptions = getQueryOptions();
final QueryOptions normalizedQueryOptions; normalizedQueryOptions = needsDistinct
? omitSqlQueryOptionsWithUniqueSemanticFilter( originalQueryOptions, true, false )
: omitSqlQueryOptions( originalQueryOptions, true, false );
}
else {
if ( needsDistinct ) { if ( needsDistinct ) {
normalizedQueryOptions = omitSqlQueryOptionsWithUniqueSemanticFilter( originalQueryOptions, true, false ); originalQueryOptions = getQueryOptions();
normalizedQueryOptions = uniqueSemanticQueryOptions( originalQueryOptions );
} }
else { else {
normalizedQueryOptions = omitSqlQueryOptions( originalQueryOptions, true, false ); return this;
} }
}
if ( originalQueryOptions == normalizedQueryOptions ) { if ( originalQueryOptions == normalizedQueryOptions ) {
executionContextToUse = this; return this;
} }
else { else {
executionContextToUse = new DelegatingDomainQueryExecutionContext( this ) { return new DelegatingDomainQueryExecutionContext( this ) {
@Override @Override
public QueryOptions getQueryOptions() { public QueryOptions getQueryOptions() {
return normalizedQueryOptions; return normalizedQueryOptions;
@ -585,46 +580,17 @@ public class QuerySqmImpl<R>
}; };
} }
} }
else {
if ( needsDistinct ) {
final MutableQueryOptions originalQueryOptions = getQueryOptions();
final QueryOptions normalizedQueryOptions = uniqueSemanticQueryOptions( originalQueryOptions );
if ( originalQueryOptions == normalizedQueryOptions ) {
executionContextToUse = this;
}
else {
executionContextToUse = new DelegatingDomainQueryExecutionContext( this ) {
@Override
public QueryOptions getQueryOptions() {
return normalizedQueryOptions;
}
};
}
}
else {
executionContextToUse = this;
}
}
return executionContextToUse;
}
public static QueryOptions uniqueSemanticQueryOptions(QueryOptions originalOptions) { public static QueryOptions uniqueSemanticQueryOptions(QueryOptions originalOptions) {
final ListResultsConsumer.UniqueSemantic semantic = originalOptions.getUniqueSemantic(); return originalOptions.getUniqueSemantic() == ListResultsConsumer.UniqueSemantic.FILTER
? originalOptions
: new UniqueSemanticFilterQueryOption( originalOptions );
if ( semantic == ListResultsConsumer.UniqueSemantic.FILTER ) {
return originalOptions;
} }
return new UniqueSemanticFilterQueryOption( originalOptions ); private static class UniqueSemanticFilterQueryOption extends DelegatingQueryOptions{
} private UniqueSemanticFilterQueryOption(QueryOptions queryOptions) {
public static class UniqueSemanticFilterQueryOption extends DelegatingQueryOptions{
public UniqueSemanticFilterQueryOption(QueryOptions queryOptions) {
super( queryOptions ); super( queryOptions );
} }
@Override @Override
public ListResultsConsumer.UniqueSemantic getUniqueSemantic() { public ListResultsConsumer.UniqueSemantic getUniqueSemantic() {
return ListResultsConsumer.UniqueSemantic.FILTER; return ListResultsConsumer.UniqueSemantic.FILTER;
@ -632,7 +598,7 @@ public class QuerySqmImpl<R>
} }
@Override @Override
protected ScrollableResultsImplementor doScroll(ScrollMode scrollMode) { protected ScrollableResultsImplementor<R> doScroll(ScrollMode scrollMode) {
return resolveSelectQueryPlan().performScroll( scrollMode, this ); return resolveSelectQueryPlan().performScroll( scrollMode, this );
} }
@ -649,12 +615,10 @@ public class QuerySqmImpl<R>
} }
private SelectQueryPlan<R> resolveSelectQueryPlan() { private SelectQueryPlan<R> resolveSelectQueryPlan() {
final QueryInterpretationCache.Key cacheKey = SqmInterpretationsKey.createInterpretationsKey( this ); final QueryInterpretationCache.Key cacheKey = createInterpretationsKey( this );
if ( cacheKey != null ) { if ( cacheKey != null ) {
return getSession().getFactory().getQueryEngine().getInterpretationCache().resolveSelectQueryPlan( return getSession().getFactory().getQueryEngine().getInterpretationCache()
cacheKey, .resolveSelectQueryPlan( cacheKey, this::buildSelectQueryPlan );
this::buildSelectQueryPlan
);
} }
else { else {
return buildSelectQueryPlan(); return buildSelectQueryPlan();
@ -737,7 +701,7 @@ public class QuerySqmImpl<R>
protected void verifyUpdate() { protected void verifyUpdate() {
try { try {
SqmUtil.verifyIsNonSelectStatement( getSqmStatement(), hql ); verifyIsNonSelectStatement( getSqmStatement(), hql );
} }
catch (IllegalQueryOperationException e) { catch (IllegalQueryOperationException e) {
// per JPA // per JPA
@ -755,15 +719,17 @@ public class QuerySqmImpl<R>
NonSelectQueryPlan queryPlan = null; NonSelectQueryPlan queryPlan = null;
final QueryInterpretationCache.Key cacheKey = SqmInterpretationsKey.generateNonSelectKey( this ); final QueryInterpretationCache.Key cacheKey = generateNonSelectKey( this );
final QueryInterpretationCache interpretationCache =
getSession().getFactory().getQueryEngine().getInterpretationCache();
if ( cacheKey != null ) { if ( cacheKey != null ) {
queryPlan = getSession().getFactory().getQueryEngine().getInterpretationCache().getNonSelectQueryPlan( cacheKey ); queryPlan = interpretationCache.getNonSelectQueryPlan( cacheKey );
} }
if ( queryPlan == null ) { if ( queryPlan == null ) {
queryPlan = buildNonSelectQueryPlan(); queryPlan = buildNonSelectQueryPlan();
if ( cacheKey != null ) { if ( cacheKey != null ) {
getSession().getFactory().getQueryEngine().getInterpretationCache().cacheNonSelectQueryPlan( cacheKey, queryPlan ); interpretationCache.cacheNonSelectQueryPlan( cacheKey, queryPlan );
} }
} }
@ -788,34 +754,26 @@ public class QuerySqmImpl<R>
throw new UnsupportedOperationException( "Query#executeUpdate for Statements of type [" + getSqmStatement() + "] not supported" ); throw new UnsupportedOperationException( "Query#executeUpdate for Statements of type [" + getSqmStatement() + "] not supported" );
} }
@SuppressWarnings({ "unchecked", "rawtypes" })
private NonSelectQueryPlan buildDeleteQueryPlan() { private NonSelectQueryPlan buildDeleteQueryPlan() {
final SqmDeleteStatement[] concreteSqmStatements = QuerySplitter.split( final SqmDeleteStatement<R>[] concreteSqmStatements = QuerySplitter.split(
(SqmDeleteStatement) getSqmStatement(), (SqmDeleteStatement<R>) getSqmStatement(),
getSessionFactory() getSessionFactory()
); );
if ( concreteSqmStatements.length > 1 ) { return concreteSqmStatements.length > 1
return buildAggregatedDeleteQueryPlan( concreteSqmStatements ); ? buildAggregatedDeleteQueryPlan( concreteSqmStatements )
} : buildConcreteDeleteQueryPlan( concreteSqmStatements[0] );
else {
return buildConcreteDeleteQueryPlan( concreteSqmStatements[0] );
}
} }
private NonSelectQueryPlan buildConcreteDeleteQueryPlan(@SuppressWarnings("rawtypes") SqmDeleteStatement sqmDelete) { private NonSelectQueryPlan buildConcreteDeleteQueryPlan(@SuppressWarnings("rawtypes") SqmDeleteStatement sqmDelete) {
final EntityDomainType<?> entityDomainType = sqmDelete.getTarget().getModel(); final EntityDomainType<?> entityDomainType = sqmDelete.getTarget().getModel();
final String entityNameToDelete = entityDomainType.getHibernateEntityName(); final String entityNameToDelete = entityDomainType.getHibernateEntityName();
final EntityPersister entityDescriptor = getSessionFactory().getRuntimeMetamodels() final EntityPersister persister =
.getMappingMetamodel() getSessionFactory().getMappingMetamodel().getEntityDescriptor( entityNameToDelete );
.getEntityDescriptor( entityNameToDelete ); final SqmMultiTableMutationStrategy multiTableStrategy = persister.getSqmMultiTableMutationStrategy();
final SqmMultiTableMutationStrategy multiTableStrategy = entityDescriptor.getSqmMultiTableMutationStrategy(); return multiTableStrategy == null
if ( multiTableStrategy == null ) { ? new SimpleDeleteQueryPlan( persister, sqmDelete, domainParameterXref )
return new SimpleDeleteQueryPlan( entityDescriptor, sqmDelete, domainParameterXref ); : new MultiTableDeleteQueryPlan( sqmDelete, domainParameterXref, multiTableStrategy );
}
else {
return new MultiTableDeleteQueryPlan( sqmDelete, domainParameterXref, multiTableStrategy );
}
} }
private NonSelectQueryPlan buildAggregatedDeleteQueryPlan(@SuppressWarnings("rawtypes") SqmDeleteStatement[] concreteSqmStatements) { private NonSelectQueryPlan buildAggregatedDeleteQueryPlan(@SuppressWarnings("rawtypes") SqmDeleteStatement[] concreteSqmStatements) {
@ -829,64 +787,46 @@ public class QuerySqmImpl<R>
} }
private NonSelectQueryPlan buildUpdateQueryPlan() { private NonSelectQueryPlan buildUpdateQueryPlan() {
//noinspection rawtypes final SqmUpdateStatement<R> sqmUpdate = (SqmUpdateStatement<R>) getSqmStatement();
final SqmUpdateStatement sqmUpdate = (SqmUpdateStatement) getSqmStatement();
final String entityNameToUpdate = sqmUpdate.getTarget().getModel().getHibernateEntityName(); final String entityNameToUpdate = sqmUpdate.getTarget().getModel().getHibernateEntityName();
final EntityPersister entityDescriptor = getSessionFactory().getRuntimeMetamodels() final EntityPersister persister =
.getMappingMetamodel() getSessionFactory().getMappingMetamodel().getEntityDescriptor( entityNameToUpdate );
.getEntityDescriptor( entityNameToUpdate );
final SqmMultiTableMutationStrategy multiTableStrategy = entityDescriptor.getSqmMultiTableMutationStrategy(); final SqmMultiTableMutationStrategy multiTableStrategy = persister.getSqmMultiTableMutationStrategy();
if ( multiTableStrategy == null ) { return multiTableStrategy == null
return new SimpleUpdateQueryPlan( sqmUpdate, domainParameterXref ); ? new SimpleUpdateQueryPlan( sqmUpdate, domainParameterXref )
} : new MultiTableUpdateQueryPlan( sqmUpdate, domainParameterXref, multiTableStrategy );
else {
return new MultiTableUpdateQueryPlan( sqmUpdate, domainParameterXref, multiTableStrategy );
}
} }
private NonSelectQueryPlan buildInsertQueryPlan() { private NonSelectQueryPlan buildInsertQueryPlan() {
//noinspection rawtypes final SqmInsertStatement<R> sqmInsert = (SqmInsertStatement<R>) getSqmStatement();
final SqmInsertStatement sqmInsert = (SqmInsertStatement) getSqmStatement();
final String entityNameToInsert = sqmInsert.getTarget().getModel().getHibernateEntityName(); final String entityNameToInsert = sqmInsert.getTarget().getModel().getHibernateEntityName();
final AbstractEntityPersister entityDescriptor = (AbstractEntityPersister) getSessionFactory().getRuntimeMetamodels() final AbstractEntityPersister persister = (AbstractEntityPersister)
.getMappingMetamodel() getSessionFactory().getMappingMetamodel().getEntityDescriptor( entityNameToInsert );
.getEntityDescriptor( entityNameToInsert );
boolean useMultiTableInsert = entityDescriptor.isMultiTable(); boolean useMultiTableInsert = persister.isMultiTable();
if ( !useMultiTableInsert && !isSimpleValuesInsert( sqmInsert, entityDescriptor ) ) { if ( !useMultiTableInsert && !isSimpleValuesInsert( sqmInsert, persister ) ) {
final Generator identifierGenerator = entityDescriptor.getGenerator(); final Generator identifierGenerator = persister.getGenerator();
if ( identifierGenerator instanceof BulkInsertionCapableIdentifierGenerator if ( identifierGenerator instanceof BulkInsertionCapableIdentifierGenerator
&& identifierGenerator instanceof OptimizableGenerator ) { && identifierGenerator instanceof OptimizableGenerator ) {
final Optimizer optimizer = ( (OptimizableGenerator) identifierGenerator ).getOptimizer(); final Optimizer optimizer = ( (OptimizableGenerator) identifierGenerator ).getOptimizer();
if ( optimizer != null && optimizer.getIncrementSize() > 1 ) { if ( optimizer != null && optimizer.getIncrementSize() > 1 ) {
useMultiTableInsert = !hasIdentifierAssigned( sqmInsert, entityDescriptor ); useMultiTableInsert = !hasIdentifierAssigned( sqmInsert, persister );
} }
} }
} }
if ( !useMultiTableInsert ) { return !useMultiTableInsert
return new SimpleInsertQueryPlan( sqmInsert, domainParameterXref ); ? new SimpleInsertQueryPlan( sqmInsert, domainParameterXref )
} : new MultiTableInsertQueryPlan( sqmInsert, domainParameterXref, persister.getSqmMultiTableInsertStrategy() );
else {
return new MultiTableInsertQueryPlan(
sqmInsert,
domainParameterXref,
entityDescriptor.getSqmMultiTableInsertStrategy()
);
}
} }
protected boolean hasIdentifierAssigned(SqmInsertStatement<?> sqmInsert, EntityPersister entityDescriptor) { protected boolean hasIdentifierAssigned(SqmInsertStatement<?> sqmInsert, EntityPersister entityDescriptor) {
final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping(); final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping();
final String partName; final String partName = identifierMapping instanceof SingleAttributeIdentifierMapping
if ( identifierMapping instanceof SingleAttributeIdentifierMapping ) { ? identifierMapping.getAttributeName()
partName = ( (SingleAttributeIdentifierMapping) identifierMapping ).getAttributeName(); : EntityIdentifierMapping.ROLE_LOCAL_NAME;
}
else {
partName = EntityIdentifierMapping.ROLE_LOCAL_NAME;
}
for ( SqmPath<?> insertionTargetPath : sqmInsert.getInsertionTargetPaths() ) { for ( SqmPath<?> insertionTargetPath : sqmInsert.getInsertionTargetPaths() ) {
final SqmPath<?> lhs = insertionTargetPath.getLhs(); final SqmPath<?> lhs = insertionTargetPath.getLhs();
if ( !( lhs instanceof SqmRoot<?> ) ) { if ( !( lhs instanceof SqmRoot<?> ) ) {
@ -1000,7 +940,7 @@ public class QuerySqmImpl<R>
} }
@Override @Override
public SqmQueryImplementor<R> addOrdering(SingularAttribute<R, ?> attribute, SortOrder order) { public SqmQueryImplementor<R> addOrdering(SingularAttribute<? super R, ?> attribute, SortOrder order) {
if ( sqm instanceof SqmSelectStatement ) { if ( sqm instanceof SqmSelectStatement ) {
SqmSelectStatement<R> select = (SqmSelectStatement<R>) sqm; SqmSelectStatement<R> select = (SqmSelectStatement<R>) sqm;
List<Order> orders = new ArrayList<>( select.getOrderList() ); List<Order> orders = new ArrayList<>( select.getOrderList() );
@ -1123,7 +1063,7 @@ public class QuerySqmImpl<R>
@Override @Override
public NamedQueryMemento toMemento(String name) { public NamedQueryMemento toMemento(String name) {
if ( CRITERIA_HQL_STRING.equals( getQueryString() ) ) { if ( CRITERIA_HQL_STRING.equals( getQueryString() ) ) {
final SqmStatement sqmStatement ; final SqmStatement<R> sqmStatement;
if ( !getSession().isCriteriaCopyTreeEnabled() ) { if ( !getSession().isCriteriaCopyTreeEnabled() ) {
sqmStatement = getSqmStatement().copy( SqmCopyContext.simpleContext() ); sqmStatement = getSqmStatement().copy( SqmCopyContext.simpleContext() );
} }

View File

@ -29,8 +29,8 @@ import org.hibernate.FlushMode;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.graph.spi.AppliedGraph; import org.hibernate.graph.spi.AppliedGraph;
import org.hibernate.internal.util.collections.IdentitySet; import org.hibernate.internal.util.collections.IdentitySet;
@ -85,7 +85,8 @@ import static org.hibernate.query.sqm.internal.SqmInterpretationsKey.createInter
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implements SqmSelectionQuery<R>, InterpretationsKeySource { public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R>
implements SqmSelectionQuery<R>, InterpretationsKeySource {
private final String hql; private final String hql;
private final SqmSelectStatement<R> sqm; private final SqmSelectStatement<R> sqm;
@ -162,8 +163,7 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
this.expectedResultType = resultType; this.expectedResultType = resultType;
this.resultType = resultType; this.resultType = resultType;
final SessionFactoryImplementor factory = session.getFactory(); final QueryEngine queryEngine = session.getFactory().getQueryEngine();
final QueryEngine queryEngine = factory.getQueryEngine();
final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache(); final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache();
final HqlInterpretation hqlInterpretation = interpretationCache.resolveHqlInterpretation( final HqlInterpretation hqlInterpretation = interpretationCache.resolveHqlInterpretation(
hql, hql,
@ -220,16 +220,7 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
// Parameters might be created through HibernateCriteriaBuilder.value which we need to bind here // Parameters might be created through HibernateCriteriaBuilder.value which we need to bind here
for ( SqmParameter<?> sqmParameter : domainParameterXref.getParameterResolutions().getSqmParameters() ) { for ( SqmParameter<?> sqmParameter : domainParameterXref.getParameterResolutions().getSqmParameters() ) {
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> ) { if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> ) {
final JpaCriteriaParameter<Object> jpaCriteriaParameter = bindCriteriaParameter( (SqmJpaCriteriaParameterWrapper<?>) sqmParameter );
( (SqmJpaCriteriaParameterWrapper<Object>) sqmParameter ).getJpaCriteriaParameter();
final Object value = jpaCriteriaParameter.getValue();
// We don't set a null value, unless the type is also null which is the case when using HibernateCriteriaBuilder.value
if ( value != null || jpaCriteriaParameter.getNodeType() == null ) {
// Use the anticipated type for binding the value if possible
getQueryParameterBindings()
.getBinding( jpaCriteriaParameter )
.setBindValue( value, jpaCriteriaParameter.getAnticipatedType() );
}
} }
} }
@ -242,6 +233,19 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
this.tupleMetadata = buildTupleMetadata( sqm, expectedResultType ); this.tupleMetadata = buildTupleMetadata( sqm, expectedResultType );
} }
private <T> void bindCriteriaParameter(SqmJpaCriteriaParameterWrapper<T> sqmParameter) {
final JpaCriteriaParameter<T> jpaCriteriaParameter = sqmParameter.getJpaCriteriaParameter();
final T value = jpaCriteriaParameter.getValue();
// We don't set a null value, unless the type is also null which
// is the case when using HibernateCriteriaBuilder.value
if ( value != null || jpaCriteriaParameter.getNodeType() == null ) {
// Use the anticipated type for binding the value if possible
getQueryParameterBindings()
.getBinding( jpaCriteriaParameter )
.setBindValue( value, jpaCriteriaParameter.getAnticipatedType() );
}
}
public TupleMetadata getTupleMetadata() { public TupleMetadata getTupleMetadata() {
return tupleMetadata; return tupleMetadata;
} }
@ -281,7 +285,7 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
} }
protected List<R> doList() { protected List<R> doList() {
final SqmSelectStatement<?> sqmStatement = (SqmSelectStatement<?>) getSqmStatement(); final SqmSelectStatement<?> sqmStatement = getSqmStatement();
final boolean containsCollectionFetches = sqmStatement.containsCollectionFetches(); final boolean containsCollectionFetches = sqmStatement.containsCollectionFetches();
final boolean hasLimit = hasLimit( sqmStatement, getQueryOptions() ); final boolean hasLimit = hasLimit( sqmStatement, getQueryOptions() );
final boolean needsDistinct = containsCollectionFetches final boolean needsDistinct = containsCollectionFetches
@ -289,12 +293,12 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
final DomainQueryExecutionContext executionContextToUse; final DomainQueryExecutionContext executionContextToUse;
if ( hasLimit && containsCollectionFetches ) { if ( hasLimit && containsCollectionFetches ) {
boolean fail = getSessionFactory().getSessionFactoryOptions().isFailOnPaginationOverCollectionFetchEnabled(); if ( getSessionFactory().getSessionFactoryOptions().isFailOnPaginationOverCollectionFetchEnabled() ) {
if ( fail ) {
throw new HibernateException( throw new HibernateException(
"firstResult/maxResults specified with collection fetch. " + "setFirstResult() or setMaxResults() specified with collection fetch join "
"In memory pagination was about to be applied. " + + "(in-memory pagination was about to be applied, but '"
"Failing because 'Fail on pagination over collection fetch' is enabled." + AvailableSettings.FAIL_ON_PAGINATION_OVER_COLLECTION_FETCH
+ "' is enabled)"
); );
} }
else { else {
@ -342,7 +346,7 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
} }
tmp.add( result ); tmp.add( result );
// NOTE : ( max - 1 ) because first is zero-based while max is not... // NOTE : ( max - 1 ) because first is zero-based while max is not...
if ( max >= 0 && ( includedCount - first ) >= ( max - 1 ) ) { if ( max >= 0 && includedCount - first >= max - 1 ) {
break; break;
} }
} }
@ -552,18 +556,18 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
} }
@Override @Override
public SqmSelectionQuery<R> ascending(SingularAttribute<R, ?> attribute) { public SqmSelectionQuery<R> ascending(SingularAttribute<? super R, ?> attribute) {
addOrdering( attribute, SortOrder.ASCENDING ); addOrdering( attribute, SortOrder.ASCENDING );
return this; return this;
} }
@Override @Override
public SqmSelectionQuery<R> descending(SingularAttribute<R, ?> attribute) { public SqmSelectionQuery<R> descending(SingularAttribute<? super R, ?> attribute) {
addOrdering( attribute, SortOrder.DESCENDING ); addOrdering( attribute, SortOrder.DESCENDING );
return this; return this;
} }
public SqmSelectionQuery<R> addOrdering(SingularAttribute<R, ?> attribute, SortOrder order) { private void addOrdering(SingularAttribute<? super R, ?> attribute, SortOrder order) {
List<Order> orders = new ArrayList<>( sqm.getOrderList() ); List<Order> orders = new ArrayList<>( sqm.getOrderList() );
sqm.getQuerySpec().getRoots().forEach( root -> { sqm.getQuerySpec().getRoots().forEach( root -> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -574,7 +578,6 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
} ); } );
sqm.orderBy( orders ); sqm.orderBy( orders );
return this;
} }
@Override @Override

View File

@ -68,7 +68,7 @@ public class ImmutableEntityUpdateQueryHandlingModeExceptionTest extends BaseNon
catch (PersistenceException e) { catch (PersistenceException e) {
assertTrue( e instanceof HibernateException ); assertTrue( e instanceof HibernateException );
assertEquals( assertEquals(
"The query: [update Country set name = :name] attempts to update an immutable entity: [Country]", "The query [update Country set name = :name] attempts to update an immutable entity: [Country]",
e.getMessage() e.getMessage()
); );
} }