HHH-16815 fix generic signature of ascending() / descending()
+ code cleanups in the Query hierarchy
This commit is contained in:
parent
3211cb8e9b
commit
7ecec615d3
|
@ -1065,12 +1065,12 @@ public class ProcedureCallImpl<R>
|
|||
}
|
||||
|
||||
@Override
|
||||
public Query<R> ascending(SingularAttribute<R, ?> attribute) {
|
||||
public Query<R> ascending(SingularAttribute<? super R, ?> attribute) {
|
||||
throw new UnsupportedOperationException( "Not supported for procedure calls" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<R> descending(SingularAttribute<R, ?> attribute) {
|
||||
public Query<R> descending(SingularAttribute<? super R, ?> attribute) {
|
||||
throw new UnsupportedOperationException( "Not supported for procedure calls" );
|
||||
}
|
||||
|
||||
|
|
|
@ -900,10 +900,10 @@ public interface Query<R> extends SelectionQuery<R>, MutationQuery, TypedQuery<R
|
|||
Query<R> setLockMode(LockModeType lockMode);
|
||||
|
||||
@Override
|
||||
Query<R> ascending(SingularAttribute<R, ?> attribute);
|
||||
Query<R> ascending(SingularAttribute<? super R, ?> attribute);
|
||||
|
||||
@Override
|
||||
Query<R> descending(SingularAttribute<R, ?> attribute);
|
||||
Query<R> descending(SingularAttribute<? super R, ?> attribute);
|
||||
|
||||
@Override
|
||||
Query<R> unordered();
|
||||
|
|
|
@ -472,10 +472,10 @@ public interface SelectionQuery<R> extends CommonQueryContract {
|
|||
SelectionQuery<R> setLockMode(String alias, LockMode lockMode);
|
||||
|
||||
@Incubating
|
||||
SelectionQuery<R> ascending(SingularAttribute<R, ?> attribute);
|
||||
SelectionQuery<R> ascending(SingularAttribute<? super R, ?> attribute);
|
||||
|
||||
@Incubating
|
||||
SelectionQuery<R> descending(SingularAttribute<R, ?> attribute);
|
||||
SelectionQuery<R> descending(SingularAttribute<? super R, ?> attribute);
|
||||
|
||||
@Incubating
|
||||
SelectionQuery<R> unordered();
|
||||
|
|
|
@ -125,18 +125,18 @@ public interface SqmQueryImplementor<R> extends QueryImplementor<R>, SqmQuery, N
|
|||
SqmQueryImplementor<R> setLockMode(LockModeType lockMode);
|
||||
|
||||
@Override
|
||||
default SqmQueryImplementor<R> ascending(SingularAttribute<R, ?> attribute) {
|
||||
default SqmQueryImplementor<R> ascending(SingularAttribute<? super R, ?> attribute) {
|
||||
addOrdering( attribute, SortOrder.ASCENDING );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
default SqmQueryImplementor<R> descending(SingularAttribute<R, ?> attribute) {
|
||||
default SqmQueryImplementor<R> descending(SingularAttribute<? super R, ?> attribute) {
|
||||
addOrdering( attribute, SortOrder.DESCENDING );
|
||||
return this;
|
||||
}
|
||||
|
||||
SqmQueryImplementor<R> addOrdering(SingularAttribute<R, ?> attribute, SortOrder order);
|
||||
SqmQueryImplementor<R> addOrdering(SingularAttribute<? super R, ?> attribute, SortOrder order);
|
||||
|
||||
@Override
|
||||
SqmQueryImplementor<R> unordered();
|
||||
|
|
|
@ -71,6 +71,7 @@ import org.hibernate.sql.exec.internal.CallbackImpl;
|
|||
import org.hibernate.sql.exec.spi.Callback;
|
||||
import org.hibernate.sql.results.internal.TupleMetadata;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.BasicTypeRegistry;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.java.spi.PrimitiveJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
@ -138,51 +139,51 @@ public abstract class AbstractSelectionQuery<R>
|
|||
}
|
||||
|
||||
private static TupleElement<?>[] buildTupleElementArray(List<SqmSelection<?>> selections) {
|
||||
final TupleElement<?>[] elements;
|
||||
if ( selections.size() == 1 ) {
|
||||
final SqmSelectableNode<?> selectableNode = selections.get(0).getSelectableNode();
|
||||
if ( selectableNode instanceof CompoundSelection<?> ) {
|
||||
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++ ) {
|
||||
elements[i] = selectionItems.get( i );
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
else {
|
||||
elements = new TupleElement<?>[] { selectableNode };
|
||||
return new TupleElement<?>[] { selectableNode };
|
||||
}
|
||||
}
|
||||
else {
|
||||
elements = new TupleElement<?>[ selections.size() ];
|
||||
final TupleElement<?>[] elements = new TupleElement<?>[ selections.size() ];
|
||||
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) {
|
||||
final String[] elements;
|
||||
if ( selections.size() == 1 ) {
|
||||
final SqmSelectableNode<?> selectableNode = selections.get(0).getSelectableNode();
|
||||
if ( selectableNode instanceof CompoundSelection<?> ) {
|
||||
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++ ) {
|
||||
elements[i] = selectionItems.get( i ).getAlias();
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
else {
|
||||
elements = new String[] { selectableNode.getAlias() };
|
||||
return new String[] { selectableNode.getAlias() };
|
||||
}
|
||||
}
|
||||
else {
|
||||
elements = new String[ selections.size() ];
|
||||
final String[] elements = new String[ selections.size() ];
|
||||
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) {
|
||||
|
@ -197,14 +198,13 @@ public abstract class AbstractSelectionQuery<R>
|
|||
}
|
||||
|
||||
if ( memento.getParameterTypes() != null ) {
|
||||
final BasicTypeRegistry basicTypeRegistry =
|
||||
getSessionFactory().getTypeConfiguration().getBasicTypeRegistry();
|
||||
for ( Map.Entry<String, String> entry : memento.getParameterTypes().entrySet() ) {
|
||||
final QueryParameterImplementor<?> parameter =
|
||||
getParameterMetadata().getQueryParameter( entry.getKey() );
|
||||
final BasicType<?> type =
|
||||
getSessionFactory().getTypeConfiguration()
|
||||
.getBasicTypeRegistry()
|
||||
.getRegisteredType( entry.getValue() );
|
||||
parameter.applyAnticipatedType( type );
|
||||
basicTypeRegistry.getRegisteredType( entry.getValue() );
|
||||
getParameterMetadata()
|
||||
.getQueryParameter( entry.getKey() ).applyAnticipatedType( type );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -270,11 +270,10 @@ public abstract class AbstractSelectionQuery<R>
|
|||
}
|
||||
// if there is a single root, use that as the selection
|
||||
if ( sqmRoots.size() == 1 ) {
|
||||
final SqmRoot<?> sqmRoot = sqmRoots.get( 0 );
|
||||
sqmQuerySpec.getSelectClause().add( sqmRoot, null );
|
||||
sqmQuerySpec.getSelectClause().add( sqmRoots.get( 0 ), null );
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException( );
|
||||
throw new IllegalArgumentException( "Criteria has multiple query roots" );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,11 +312,7 @@ public abstract class AbstractSelectionQuery<R>
|
|||
}
|
||||
}
|
||||
|
||||
final boolean jpaQueryComplianceEnabled =
|
||||
sessionFactory.getSessionFactoryOptions()
|
||||
.getJpaCompliance()
|
||||
.isJpaQueryComplianceEnabled();
|
||||
if ( !jpaQueryComplianceEnabled ) {
|
||||
if ( !sessionFactory.getSessionFactoryOptions().getJpaCompliance().isJpaQueryComplianceEnabled() ) {
|
||||
verifyResultType( expectedResultClass, sqmSelection.getNodeType() );
|
||||
}
|
||||
}
|
||||
|
@ -347,16 +342,15 @@ public abstract class AbstractSelectionQuery<R>
|
|||
final Class<?> javaTypeClass = expressibleJavaType.getJavaTypeClass();
|
||||
if ( !resultClass.isAssignableFrom( javaTypeClass ) ) {
|
||||
if ( expressibleJavaType instanceof PrimitiveJavaType ) {
|
||||
if ( ( (PrimitiveJavaType<?>) expressibleJavaType ).getPrimitiveClass() != resultClass ) {
|
||||
final PrimitiveJavaType<?> javaType = (PrimitiveJavaType<?>) expressibleJavaType;
|
||||
if ( javaType.getPrimitiveClass() != resultClass ) {
|
||||
throwQueryTypeMismatchException( resultClass, sqmExpressible );
|
||||
}
|
||||
}
|
||||
else if ( isMatchingDateType( javaTypeClass, resultClass, sqmExpressible ) ) {
|
||||
// special case, we are good
|
||||
}
|
||||
else {
|
||||
else if ( !isMatchingDateType( javaTypeClass, resultClass, sqmExpressible ) ) {
|
||||
throwQueryTypeMismatchException( resultClass, sqmExpressible );
|
||||
}
|
||||
// else special case, we are good
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -375,7 +369,8 @@ public abstract class AbstractSelectionQuery<R>
|
|||
return ( (BasicDomainType<?>) sqmExpressible).getJdbcType();
|
||||
}
|
||||
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<?> ) {
|
||||
return ( (BasicDomainType<?>) domainType ).getJdbcType();
|
||||
}
|
||||
|
|
|
@ -1501,12 +1501,12 @@ public class NativeQueryImpl<R>
|
|||
}
|
||||
|
||||
@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");
|
||||
}
|
||||
|
||||
@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");
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.hibernate.LockMode;
|
|||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.TypeMismatchException;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.query.spi.EntityGraphQueryHint;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
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.query.spi.SqlOmittingQueryOptions.omitSqlQueryOptions;
|
||||
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.verifyIsNonSelectStatement;
|
||||
|
||||
/**
|
||||
* {@link Query} implementation based on an SQM
|
||||
|
@ -158,8 +162,7 @@ public class QuerySqmImpl<R>
|
|||
this.hql = memento.getHqlString();
|
||||
this.resultType = expectedResultType;
|
||||
|
||||
final SessionFactoryImplementor factory = session.getFactory();
|
||||
final QueryEngine queryEngine = factory.getQueryEngine();
|
||||
final QueryEngine queryEngine = session.getFactory().getQueryEngine();
|
||||
final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache();
|
||||
final HqlInterpretation hqlInterpretation = interpretationCache.resolveHqlInterpretation(
|
||||
hql,
|
||||
|
@ -225,39 +228,32 @@ public class QuerySqmImpl<R>
|
|||
Class<R> expectedResultType,
|
||||
SharedSessionContractImplementor producer) {
|
||||
super( producer );
|
||||
this.hql = CRITERIA_HQL_STRING;
|
||||
hql = CRITERIA_HQL_STRING;
|
||||
if ( producer.isCriteriaCopyTreeEnabled() ) {
|
||||
this.sqm = criteria.copy( SqmCopyContext.simpleContext() );
|
||||
sqm = criteria.copy( SqmCopyContext.simpleContext() );
|
||||
}
|
||||
else {
|
||||
this.sqm = criteria;
|
||||
sqm = criteria;
|
||||
// Cache immutable query plans by default
|
||||
setQueryPlanCacheable( true );
|
||||
}
|
||||
|
||||
setComment( hql );
|
||||
|
||||
this.domainParameterXref = DomainParameterXref.from( this.sqm );
|
||||
domainParameterXref = DomainParameterXref.from( sqm );
|
||||
if ( ! domainParameterXref.hasParameters() ) {
|
||||
this.parameterMetadata = ParameterMetadataImpl.EMPTY;
|
||||
parameterMetadata = ParameterMetadataImpl.EMPTY;
|
||||
}
|
||||
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
|
||||
for ( SqmParameter<?> sqmParameter : this.domainParameterXref.getParameterResolutions().getSqmParameters() ) {
|
||||
for ( SqmParameter<?> sqmParameter : domainParameterXref.getParameterResolutions().getSqmParameters() ) {
|
||||
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> ) {
|
||||
final JpaCriteriaParameter<Object> jpaCriteriaParameter = ( (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() );
|
||||
}
|
||||
bindCriteriaParameter((SqmJpaCriteriaParameterWrapper<?>) sqmParameter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,18 +270,13 @@ public class QuerySqmImpl<R>
|
|||
}
|
||||
else {
|
||||
if ( expectedResultType != null ) {
|
||||
throw new IllegalQueryOperationException(
|
||||
"Result type given for a non-SELECT Query",
|
||||
hql,
|
||||
null
|
||||
);
|
||||
throw new IllegalQueryOperationException( "Result type given for a non-SELECT Query", hql, null );
|
||||
}
|
||||
if ( sqm instanceof SqmUpdateStatement<?> ) {
|
||||
final SqmUpdateStatement<R> updateStatement = (SqmUpdateStatement<R>) sqm;
|
||||
verifyImmutableEntityUpdate( CRITERIA_HQL_STRING, updateStatement, producer.getFactory() );
|
||||
if ( updateStatement.getSetClause() == null || updateStatement.getSetClause()
|
||||
.getAssignments()
|
||||
.isEmpty() ) {
|
||||
if ( updateStatement.getSetClause() == null
|
||||
|| updateStatement.getSetClause().getAssignments().isEmpty() ) {
|
||||
throw new IllegalArgumentException( "No assignments specified as part of UPDATE criteria" );
|
||||
}
|
||||
}
|
||||
|
@ -294,8 +285,20 @@ public class QuerySqmImpl<R>
|
|||
}
|
||||
}
|
||||
|
||||
this.resultType = expectedResultType;
|
||||
this.tupleMetadata = buildTupleMetadata( criteria, expectedResultType );
|
||||
resultType = 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) {
|
||||
|
@ -304,11 +307,7 @@ public class QuerySqmImpl<R>
|
|||
}
|
||||
else {
|
||||
if ( resultType != null ) {
|
||||
throw new IllegalQueryOperationException(
|
||||
"Result type given for a non-SELECT Query",
|
||||
hql,
|
||||
null
|
||||
);
|
||||
throw new IllegalQueryOperationException( "Result type given for a non-SELECT Query", hql, null );
|
||||
}
|
||||
if ( sqmStatement instanceof SqmUpdateStatement<?> ) {
|
||||
final SqmUpdateStatement<R> updateStatement = (SqmUpdateStatement<R>) sqmStatement;
|
||||
|
@ -325,30 +324,22 @@ public class QuerySqmImpl<R>
|
|||
String hqlString,
|
||||
SqmUpdateStatement<R> sqmStatement,
|
||||
SessionFactoryImplementor factory) {
|
||||
final EntityPersister entityDescriptor = factory.getRuntimeMetamodels()
|
||||
.getMappingMetamodel()
|
||||
.getEntityDescriptor( sqmStatement.getTarget().getEntityName() );
|
||||
if ( entityDescriptor.isMutable() ) {
|
||||
return;
|
||||
}
|
||||
final ImmutableEntityUpdateQueryHandlingMode immutableEntityUpdateQueryHandlingMode = factory
|
||||
.getSessionFactoryOptions()
|
||||
.getImmutableEntityUpdateQueryHandlingMode();
|
||||
|
||||
final String querySpaces = Arrays.toString( entityDescriptor.getQuerySpaces() );
|
||||
|
||||
switch ( immutableEntityUpdateQueryHandlingMode ) {
|
||||
case WARNING:
|
||||
LOG.immutableEntityUpdateQuery( hqlString, querySpaces );
|
||||
break;
|
||||
case EXCEPTION:
|
||||
throw new HibernateException(
|
||||
"The query: [" + hqlString + "] attempts to update an immutable entity: " + querySpaces
|
||||
);
|
||||
default:
|
||||
throw new UnsupportedOperationException(
|
||||
"The " + immutableEntityUpdateQueryHandlingMode + " is not supported"
|
||||
);
|
||||
final EntityPersister persister =
|
||||
factory.getMappingMetamodel().getEntityDescriptor( sqmStatement.getTarget().getEntityName() );
|
||||
if ( !persister.isMutable() ) {
|
||||
final ImmutableEntityUpdateQueryHandlingMode mode =
|
||||
factory.getSessionFactoryOptions().getImmutableEntityUpdateQueryHandlingMode();
|
||||
final String querySpaces = Arrays.toString( persister.getQuerySpaces() );
|
||||
switch ( mode ) {
|
||||
case WARNING:
|
||||
LOG.immutableEntityUpdateQuery( hqlString, querySpaces );
|
||||
break;
|
||||
case EXCEPTION:
|
||||
throw new HibernateException( "The query [" + hqlString + "] attempts to update an immutable entity: "
|
||||
+ querySpaces );
|
||||
default:
|
||||
throw new UnsupportedOperationException( "The " + mode + " is not supported" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -387,10 +378,11 @@ public class QuerySqmImpl<R>
|
|||
}
|
||||
else {
|
||||
final SqmInsertSelectStatement<R> statement = (SqmInsertSelectStatement<R>) sqmStatement;
|
||||
final List<SqmSelectableNode<?>> selections = statement.getSelectQueryPart()
|
||||
.getFirstQuerySpec()
|
||||
.getSelectClause()
|
||||
.getSelectionItems();
|
||||
final List<SqmSelectableNode<?>> selections =
|
||||
statement.getSelectQueryPart()
|
||||
.getFirstQuerySpec()
|
||||
.getSelectClause()
|
||||
.getSelectionItems();
|
||||
verifyInsertTypesMatch( hqlString, insertionTargetPaths, selections );
|
||||
statement.getSelectQueryPart().validateQueryStructureAndFetchOwners();
|
||||
}
|
||||
|
@ -488,7 +480,7 @@ public class QuerySqmImpl<R>
|
|||
|
||||
protected boolean hasMultiValuedParameterBindings() {
|
||||
return getQueryParameterBindings().hasAnyMultiValuedBindings()
|
||||
|| getParameterMetadata().hasAnyMatching( QueryParameter::allowsMultiValuedBinding );
|
||||
|| getParameterMetadata().hasAnyMatching( QueryParameter::allowsMultiValuedBinding );
|
||||
}
|
||||
|
||||
|
||||
|
@ -515,14 +507,15 @@ public class QuerySqmImpl<R>
|
|||
verifySelect();
|
||||
|
||||
final SqmSelectStatement<?> sqmStatement = (SqmSelectStatement<?>) getSqmStatement();
|
||||
final boolean containsCollectionFetches = sqmStatement.containsCollectionFetches() || AppliedGraphs.containsCollectionFetches(
|
||||
getQueryOptions() );
|
||||
final boolean containsCollectionFetches =
|
||||
sqmStatement.containsCollectionFetches()
|
||||
|| AppliedGraphs.containsCollectionFetches( getQueryOptions() );
|
||||
final boolean hasLimit = hasLimit( sqmStatement, getQueryOptions() );
|
||||
final boolean needsDistinct = containsCollectionFetches
|
||||
&& ( sqmStatement.usesDistinct() || hasAppliedGraph( getQueryOptions() ) || hasLimit );
|
||||
&& ( hasLimit || sqmStatement.usesDistinct() || hasAppliedGraph( getQueryOptions() ) );
|
||||
|
||||
final List<R> list = resolveSelectQueryPlan()
|
||||
.performList( executionContextFordoList( containsCollectionFetches, hasLimit, needsDistinct ) );
|
||||
.performList( executionContextForDoList( containsCollectionFetches, hasLimit, needsDistinct ) );
|
||||
|
||||
if ( needsDistinct ) {
|
||||
final int first = !hasLimit || getQueryOptions().getLimit().getFirstRow() == null
|
||||
|
@ -532,99 +525,72 @@ public class QuerySqmImpl<R>
|
|||
? getMaxRows( sqmStatement, list.size() )
|
||||
: getQueryOptions().getLimit().getMaxRows();
|
||||
if ( first > 0 || max != -1 ) {
|
||||
final int toIndex;
|
||||
final int resultSize = list.size();
|
||||
if ( max != -1 ) {
|
||||
toIndex = first + max;
|
||||
}
|
||||
else {
|
||||
toIndex = resultSize;
|
||||
}
|
||||
final int toIndex = max != -1 ? first + max : resultSize;
|
||||
if ( first > resultSize ) {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
return list.subList( first, toIndex > resultSize ? resultSize : toIndex );
|
||||
return list.subList( first, Math.min( toIndex, resultSize ) );
|
||||
}
|
||||
}
|
||||
return list;
|
||||
|
||||
}
|
||||
|
||||
protected DomainQueryExecutionContext executionContextFordoList(boolean containsCollectionFetches, boolean hasLimit, boolean needsDistinct) {
|
||||
final DomainQueryExecutionContext executionContextToUse;
|
||||
protected DomainQueryExecutionContext executionContextForDoList(boolean containsCollectionFetches, boolean hasLimit, boolean needsDistinct) {
|
||||
final MutableQueryOptions originalQueryOptions;
|
||||
final QueryOptions normalizedQueryOptions;
|
||||
if ( hasLimit && containsCollectionFetches ) {
|
||||
boolean fail = getSessionFactory().getSessionFactoryOptions().isFailOnPaginationOverCollectionFetchEnabled();
|
||||
if (fail) {
|
||||
if ( getSessionFactory().getSessionFactoryOptions().isFailOnPaginationOverCollectionFetchEnabled() ) {
|
||||
throw new HibernateException(
|
||||
"firstResult/maxResults specified with collection fetch. " +
|
||||
"In memory pagination was about to be applied. " +
|
||||
"Failing because 'Fail on pagination over collection fetch' is enabled."
|
||||
"setFirstResult() or setMaxResults() specified with collection fetch join "
|
||||
+ "(in-memory pagination was about to be applied, but '"
|
||||
+ AvailableSettings.FAIL_ON_PAGINATION_OVER_COLLECTION_FETCH
|
||||
+ "' is enabled)"
|
||||
);
|
||||
}
|
||||
else {
|
||||
QueryLogging.QUERY_MESSAGE_LOGGER.firstOrMaxResultsSpecifiedWithCollectionFetch();
|
||||
}
|
||||
|
||||
final MutableQueryOptions originalQueryOptions = getQueryOptions();
|
||||
final QueryOptions normalizedQueryOptions;
|
||||
if ( needsDistinct ) {
|
||||
normalizedQueryOptions = omitSqlQueryOptionsWithUniqueSemanticFilter( originalQueryOptions, true, false );
|
||||
}
|
||||
else {
|
||||
normalizedQueryOptions = omitSqlQueryOptions( originalQueryOptions, true, false );
|
||||
}
|
||||
if ( originalQueryOptions == normalizedQueryOptions ) {
|
||||
executionContextToUse = this;
|
||||
}
|
||||
else {
|
||||
executionContextToUse = new DelegatingDomainQueryExecutionContext( this ) {
|
||||
@Override
|
||||
public QueryOptions getQueryOptions() {
|
||||
return normalizedQueryOptions;
|
||||
}
|
||||
};
|
||||
}
|
||||
originalQueryOptions = getQueryOptions();
|
||||
normalizedQueryOptions = needsDistinct
|
||||
? omitSqlQueryOptionsWithUniqueSemanticFilter( originalQueryOptions, true, false )
|
||||
: omitSqlQueryOptions( originalQueryOptions, true, false );
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
originalQueryOptions = getQueryOptions();
|
||||
normalizedQueryOptions = uniqueSemanticQueryOptions( originalQueryOptions );
|
||||
}
|
||||
else {
|
||||
executionContextToUse = this;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
return executionContextToUse;
|
||||
|
||||
if ( originalQueryOptions == normalizedQueryOptions ) {
|
||||
return this;
|
||||
}
|
||||
else {
|
||||
return new DelegatingDomainQueryExecutionContext( this ) {
|
||||
@Override
|
||||
public QueryOptions getQueryOptions() {
|
||||
return normalizedQueryOptions;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static QueryOptions uniqueSemanticQueryOptions(QueryOptions originalOptions) {
|
||||
final ListResultsConsumer.UniqueSemantic semantic = originalOptions.getUniqueSemantic();
|
||||
|
||||
|
||||
if ( semantic == ListResultsConsumer.UniqueSemantic.FILTER ) {
|
||||
return originalOptions;
|
||||
}
|
||||
|
||||
return new UniqueSemanticFilterQueryOption( originalOptions );
|
||||
return originalOptions.getUniqueSemantic() == ListResultsConsumer.UniqueSemantic.FILTER
|
||||
? originalOptions
|
||||
: new UniqueSemanticFilterQueryOption( originalOptions );
|
||||
}
|
||||
|
||||
public static class UniqueSemanticFilterQueryOption extends DelegatingQueryOptions{
|
||||
|
||||
public UniqueSemanticFilterQueryOption(QueryOptions queryOptions) {
|
||||
private static class UniqueSemanticFilterQueryOption extends DelegatingQueryOptions{
|
||||
private UniqueSemanticFilterQueryOption(QueryOptions queryOptions) {
|
||||
super( queryOptions );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListResultsConsumer.UniqueSemantic getUniqueSemantic() {
|
||||
return ListResultsConsumer.UniqueSemantic.FILTER;
|
||||
|
@ -632,7 +598,7 @@ public class QuerySqmImpl<R>
|
|||
}
|
||||
|
||||
@Override
|
||||
protected ScrollableResultsImplementor doScroll(ScrollMode scrollMode) {
|
||||
protected ScrollableResultsImplementor<R> doScroll(ScrollMode scrollMode) {
|
||||
return resolveSelectQueryPlan().performScroll( scrollMode, this );
|
||||
}
|
||||
|
||||
|
@ -649,12 +615,10 @@ public class QuerySqmImpl<R>
|
|||
}
|
||||
|
||||
private SelectQueryPlan<R> resolveSelectQueryPlan() {
|
||||
final QueryInterpretationCache.Key cacheKey = SqmInterpretationsKey.createInterpretationsKey( this );
|
||||
final QueryInterpretationCache.Key cacheKey = createInterpretationsKey( this );
|
||||
if ( cacheKey != null ) {
|
||||
return getSession().getFactory().getQueryEngine().getInterpretationCache().resolveSelectQueryPlan(
|
||||
cacheKey,
|
||||
this::buildSelectQueryPlan
|
||||
);
|
||||
return getSession().getFactory().getQueryEngine().getInterpretationCache()
|
||||
.resolveSelectQueryPlan( cacheKey, this::buildSelectQueryPlan );
|
||||
}
|
||||
else {
|
||||
return buildSelectQueryPlan();
|
||||
|
@ -737,7 +701,7 @@ public class QuerySqmImpl<R>
|
|||
|
||||
protected void verifyUpdate() {
|
||||
try {
|
||||
SqmUtil.verifyIsNonSelectStatement( getSqmStatement(), hql );
|
||||
verifyIsNonSelectStatement( getSqmStatement(), hql );
|
||||
}
|
||||
catch (IllegalQueryOperationException e) {
|
||||
// per JPA
|
||||
|
@ -755,15 +719,17 @@ public class QuerySqmImpl<R>
|
|||
|
||||
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 ) {
|
||||
queryPlan = getSession().getFactory().getQueryEngine().getInterpretationCache().getNonSelectQueryPlan( cacheKey );
|
||||
queryPlan = interpretationCache.getNonSelectQueryPlan( cacheKey );
|
||||
}
|
||||
|
||||
if ( queryPlan == null ) {
|
||||
queryPlan = buildNonSelectQueryPlan();
|
||||
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" );
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private NonSelectQueryPlan buildDeleteQueryPlan() {
|
||||
final SqmDeleteStatement[] concreteSqmStatements = QuerySplitter.split(
|
||||
(SqmDeleteStatement) getSqmStatement(),
|
||||
final SqmDeleteStatement<R>[] concreteSqmStatements = QuerySplitter.split(
|
||||
(SqmDeleteStatement<R>) getSqmStatement(),
|
||||
getSessionFactory()
|
||||
);
|
||||
|
||||
if ( concreteSqmStatements.length > 1 ) {
|
||||
return buildAggregatedDeleteQueryPlan( concreteSqmStatements );
|
||||
}
|
||||
else {
|
||||
return buildConcreteDeleteQueryPlan( concreteSqmStatements[0] );
|
||||
}
|
||||
return concreteSqmStatements.length > 1
|
||||
? buildAggregatedDeleteQueryPlan( concreteSqmStatements )
|
||||
: buildConcreteDeleteQueryPlan( concreteSqmStatements[0] );
|
||||
}
|
||||
|
||||
private NonSelectQueryPlan buildConcreteDeleteQueryPlan(@SuppressWarnings("rawtypes") SqmDeleteStatement sqmDelete) {
|
||||
final EntityDomainType<?> entityDomainType = sqmDelete.getTarget().getModel();
|
||||
final String entityNameToDelete = entityDomainType.getHibernateEntityName();
|
||||
final EntityPersister entityDescriptor = getSessionFactory().getRuntimeMetamodels()
|
||||
.getMappingMetamodel()
|
||||
.getEntityDescriptor( entityNameToDelete );
|
||||
final SqmMultiTableMutationStrategy multiTableStrategy = entityDescriptor.getSqmMultiTableMutationStrategy();
|
||||
if ( multiTableStrategy == null ) {
|
||||
return new SimpleDeleteQueryPlan( entityDescriptor, sqmDelete, domainParameterXref );
|
||||
}
|
||||
else {
|
||||
return new MultiTableDeleteQueryPlan( sqmDelete, domainParameterXref, multiTableStrategy );
|
||||
}
|
||||
final EntityPersister persister =
|
||||
getSessionFactory().getMappingMetamodel().getEntityDescriptor( entityNameToDelete );
|
||||
final SqmMultiTableMutationStrategy multiTableStrategy = persister.getSqmMultiTableMutationStrategy();
|
||||
return multiTableStrategy == null
|
||||
? new SimpleDeleteQueryPlan( persister, sqmDelete, domainParameterXref )
|
||||
: new MultiTableDeleteQueryPlan( sqmDelete, domainParameterXref, multiTableStrategy );
|
||||
}
|
||||
|
||||
private NonSelectQueryPlan buildAggregatedDeleteQueryPlan(@SuppressWarnings("rawtypes") SqmDeleteStatement[] concreteSqmStatements) {
|
||||
|
@ -829,64 +787,46 @@ public class QuerySqmImpl<R>
|
|||
}
|
||||
|
||||
private NonSelectQueryPlan buildUpdateQueryPlan() {
|
||||
//noinspection rawtypes
|
||||
final SqmUpdateStatement sqmUpdate = (SqmUpdateStatement) getSqmStatement();
|
||||
final SqmUpdateStatement<R> sqmUpdate = (SqmUpdateStatement<R>) getSqmStatement();
|
||||
|
||||
final String entityNameToUpdate = sqmUpdate.getTarget().getModel().getHibernateEntityName();
|
||||
final EntityPersister entityDescriptor = getSessionFactory().getRuntimeMetamodels()
|
||||
.getMappingMetamodel()
|
||||
.getEntityDescriptor( entityNameToUpdate );
|
||||
final EntityPersister persister =
|
||||
getSessionFactory().getMappingMetamodel().getEntityDescriptor( entityNameToUpdate );
|
||||
|
||||
final SqmMultiTableMutationStrategy multiTableStrategy = entityDescriptor.getSqmMultiTableMutationStrategy();
|
||||
if ( multiTableStrategy == null ) {
|
||||
return new SimpleUpdateQueryPlan( sqmUpdate, domainParameterXref );
|
||||
}
|
||||
else {
|
||||
return new MultiTableUpdateQueryPlan( sqmUpdate, domainParameterXref, multiTableStrategy );
|
||||
}
|
||||
final SqmMultiTableMutationStrategy multiTableStrategy = persister.getSqmMultiTableMutationStrategy();
|
||||
return multiTableStrategy == null
|
||||
? new SimpleUpdateQueryPlan( sqmUpdate, domainParameterXref )
|
||||
: new MultiTableUpdateQueryPlan( sqmUpdate, domainParameterXref, multiTableStrategy );
|
||||
}
|
||||
|
||||
private NonSelectQueryPlan buildInsertQueryPlan() {
|
||||
//noinspection rawtypes
|
||||
final SqmInsertStatement sqmInsert = (SqmInsertStatement) getSqmStatement();
|
||||
final SqmInsertStatement<R> sqmInsert = (SqmInsertStatement<R>) getSqmStatement();
|
||||
|
||||
final String entityNameToInsert = sqmInsert.getTarget().getModel().getHibernateEntityName();
|
||||
final AbstractEntityPersister entityDescriptor = (AbstractEntityPersister) getSessionFactory().getRuntimeMetamodels()
|
||||
.getMappingMetamodel()
|
||||
.getEntityDescriptor( entityNameToInsert );
|
||||
final AbstractEntityPersister persister = (AbstractEntityPersister)
|
||||
getSessionFactory().getMappingMetamodel().getEntityDescriptor( entityNameToInsert );
|
||||
|
||||
boolean useMultiTableInsert = entityDescriptor.isMultiTable();
|
||||
if ( !useMultiTableInsert && !isSimpleValuesInsert( sqmInsert, entityDescriptor ) ) {
|
||||
final Generator identifierGenerator = entityDescriptor.getGenerator();
|
||||
boolean useMultiTableInsert = persister.isMultiTable();
|
||||
if ( !useMultiTableInsert && !isSimpleValuesInsert( sqmInsert, persister ) ) {
|
||||
final Generator identifierGenerator = persister.getGenerator();
|
||||
if ( identifierGenerator instanceof BulkInsertionCapableIdentifierGenerator
|
||||
&& identifierGenerator instanceof OptimizableGenerator ) {
|
||||
final Optimizer optimizer = ( (OptimizableGenerator) identifierGenerator ).getOptimizer();
|
||||
if ( optimizer != null && optimizer.getIncrementSize() > 1 ) {
|
||||
useMultiTableInsert = !hasIdentifierAssigned( sqmInsert, entityDescriptor );
|
||||
useMultiTableInsert = !hasIdentifierAssigned( sqmInsert, persister );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !useMultiTableInsert ) {
|
||||
return new SimpleInsertQueryPlan( sqmInsert, domainParameterXref );
|
||||
}
|
||||
else {
|
||||
return new MultiTableInsertQueryPlan(
|
||||
sqmInsert,
|
||||
domainParameterXref,
|
||||
entityDescriptor.getSqmMultiTableInsertStrategy()
|
||||
);
|
||||
}
|
||||
return !useMultiTableInsert
|
||||
? new SimpleInsertQueryPlan( sqmInsert, domainParameterXref )
|
||||
: new MultiTableInsertQueryPlan( sqmInsert, domainParameterXref, persister.getSqmMultiTableInsertStrategy() );
|
||||
}
|
||||
|
||||
protected boolean hasIdentifierAssigned(SqmInsertStatement<?> sqmInsert, EntityPersister entityDescriptor) {
|
||||
final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping();
|
||||
final String partName;
|
||||
if ( identifierMapping instanceof SingleAttributeIdentifierMapping ) {
|
||||
partName = ( (SingleAttributeIdentifierMapping) identifierMapping ).getAttributeName();
|
||||
}
|
||||
else {
|
||||
partName = EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
||||
}
|
||||
final String partName = identifierMapping instanceof SingleAttributeIdentifierMapping
|
||||
? identifierMapping.getAttributeName()
|
||||
: EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
||||
for ( SqmPath<?> insertionTargetPath : sqmInsert.getInsertionTargetPaths() ) {
|
||||
final SqmPath<?> lhs = insertionTargetPath.getLhs();
|
||||
if ( !( lhs instanceof SqmRoot<?> ) ) {
|
||||
|
@ -904,10 +844,10 @@ public class QuerySqmImpl<R>
|
|||
protected boolean isSimpleValuesInsert(SqmInsertStatement<?> sqmInsert, EntityPersister entityDescriptor) {
|
||||
// Simple means that we can translate the statement to a single plain insert
|
||||
return sqmInsert instanceof SqmInsertValuesStatement
|
||||
// An insert is only simple if no SqmMultiTableMutation strategy is available,
|
||||
// as the presence of it means the entity has multiple tables involved,
|
||||
// in which case we currently need to use the MultiTableInsertQueryPlan
|
||||
&& entityDescriptor.getSqmMultiTableMutationStrategy() == null;
|
||||
// An insert is only simple if no SqmMultiTableMutation strategy is available,
|
||||
// as the presence of it means the entity has multiple tables involved,
|
||||
// in which case we currently need to use the MultiTableInsertQueryPlan
|
||||
&& entityDescriptor.getSqmMultiTableMutationStrategy() == null;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1000,7 +940,7 @@ public class QuerySqmImpl<R>
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmQueryImplementor<R> addOrdering(SingularAttribute<R, ?> attribute, SortOrder order) {
|
||||
public SqmQueryImplementor<R> addOrdering(SingularAttribute<? super R, ?> attribute, SortOrder order) {
|
||||
if ( sqm instanceof SqmSelectStatement ) {
|
||||
SqmSelectStatement<R> select = (SqmSelectStatement<R>) sqm;
|
||||
List<Order> orders = new ArrayList<>( select.getOrderList() );
|
||||
|
@ -1123,7 +1063,7 @@ public class QuerySqmImpl<R>
|
|||
@Override
|
||||
public NamedQueryMemento toMemento(String name) {
|
||||
if ( CRITERIA_HQL_STRING.equals( getQueryString() ) ) {
|
||||
final SqmStatement sqmStatement ;
|
||||
final SqmStatement<R> sqmStatement;
|
||||
if ( !getSession().isCriteriaCopyTreeEnabled() ) {
|
||||
sqmStatement = getSqmStatement().copy( SqmCopyContext.simpleContext() );
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ import org.hibernate.FlushMode;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.graph.spi.AppliedGraph;
|
||||
import org.hibernate.internal.util.collections.IdentitySet;
|
||||
|
@ -85,7 +85,8 @@ import static org.hibernate.query.sqm.internal.SqmInterpretationsKey.createInter
|
|||
/**
|
||||
* @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 SqmSelectStatement<R> sqm;
|
||||
|
||||
|
@ -162,8 +163,7 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
|
|||
this.expectedResultType = resultType;
|
||||
this.resultType = resultType;
|
||||
|
||||
final SessionFactoryImplementor factory = session.getFactory();
|
||||
final QueryEngine queryEngine = factory.getQueryEngine();
|
||||
final QueryEngine queryEngine = session.getFactory().getQueryEngine();
|
||||
final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache();
|
||||
final HqlInterpretation hqlInterpretation = interpretationCache.resolveHqlInterpretation(
|
||||
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
|
||||
for ( SqmParameter<?> sqmParameter : domainParameterXref.getParameterResolutions().getSqmParameters() ) {
|
||||
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> ) {
|
||||
final JpaCriteriaParameter<Object> jpaCriteriaParameter =
|
||||
( (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() );
|
||||
}
|
||||
bindCriteriaParameter( (SqmJpaCriteriaParameterWrapper<?>) sqmParameter );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,6 +233,19 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
|
|||
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() {
|
||||
return tupleMetadata;
|
||||
}
|
||||
|
@ -281,7 +285,7 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
|
|||
}
|
||||
|
||||
protected List<R> doList() {
|
||||
final SqmSelectStatement<?> sqmStatement = (SqmSelectStatement<?>) getSqmStatement();
|
||||
final SqmSelectStatement<?> sqmStatement = getSqmStatement();
|
||||
final boolean containsCollectionFetches = sqmStatement.containsCollectionFetches();
|
||||
final boolean hasLimit = hasLimit( sqmStatement, getQueryOptions() );
|
||||
final boolean needsDistinct = containsCollectionFetches
|
||||
|
@ -289,12 +293,12 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
|
|||
|
||||
final DomainQueryExecutionContext executionContextToUse;
|
||||
if ( hasLimit && containsCollectionFetches ) {
|
||||
boolean fail = getSessionFactory().getSessionFactoryOptions().isFailOnPaginationOverCollectionFetchEnabled();
|
||||
if ( fail ) {
|
||||
if ( getSessionFactory().getSessionFactoryOptions().isFailOnPaginationOverCollectionFetchEnabled() ) {
|
||||
throw new HibernateException(
|
||||
"firstResult/maxResults specified with collection fetch. " +
|
||||
"In memory pagination was about to be applied. " +
|
||||
"Failing because 'Fail on pagination over collection fetch' is enabled."
|
||||
"setFirstResult() or setMaxResults() specified with collection fetch join "
|
||||
+ "(in-memory pagination was about to be applied, but '"
|
||||
+ AvailableSettings.FAIL_ON_PAGINATION_OVER_COLLECTION_FETCH
|
||||
+ "' is enabled)"
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
@ -342,7 +346,7 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
|
|||
}
|
||||
tmp.add( result );
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
@ -427,7 +431,7 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
|
|||
|
||||
protected boolean hasMultiValuedParameterBindings() {
|
||||
return getQueryParameterBindings().hasAnyMultiValuedBindings()
|
||||
|| getParameterMetadata().hasAnyMatching( QueryParameter::allowsMultiValuedBinding );
|
||||
|| getParameterMetadata().hasAnyMatching( QueryParameter::allowsMultiValuedBinding );
|
||||
}
|
||||
|
||||
|
||||
|
@ -552,18 +556,18 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmSelectionQuery<R> ascending(SingularAttribute<R, ?> attribute) {
|
||||
public SqmSelectionQuery<R> ascending(SingularAttribute<? super R, ?> attribute) {
|
||||
addOrdering( attribute, SortOrder.ASCENDING );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmSelectionQuery<R> descending(SingularAttribute<R, ?> attribute) {
|
||||
public SqmSelectionQuery<R> descending(SingularAttribute<? super R, ?> attribute) {
|
||||
addOrdering( attribute, SortOrder.DESCENDING );
|
||||
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() );
|
||||
sqm.getQuerySpec().getRoots().forEach( root -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -574,7 +578,6 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
|
|||
|
||||
} );
|
||||
sqm.orderBy( orders );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -68,7 +68,7 @@ public class ImmutableEntityUpdateQueryHandlingModeExceptionTest extends BaseNon
|
|||
catch (PersistenceException e) {
|
||||
assertTrue( e instanceof HibernateException );
|
||||
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()
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue