HHH-18596 Get rid of ValueHandlingMode hack in query pagination
This commit is contained in:
parent
0e5846b805
commit
ddadad2dac
|
@ -94,10 +94,16 @@ import static org.hibernate.jpa.internal.util.LockModeTypeHelper.interpretLockMo
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractCommonQueryContract implements CommonQueryContract {
|
public abstract class AbstractCommonQueryContract implements CommonQueryContract {
|
||||||
private final SharedSessionContractImplementor session;
|
private final SharedSessionContractImplementor session;
|
||||||
private final QueryOptionsImpl queryOptions = new QueryOptionsImpl();
|
private final QueryOptionsImpl queryOptions;
|
||||||
|
|
||||||
public AbstractCommonQueryContract(SharedSessionContractImplementor session) {
|
public AbstractCommonQueryContract(SharedSessionContractImplementor session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
this.queryOptions = new QueryOptionsImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractCommonQueryContract(AbstractCommonQueryContract original) {
|
||||||
|
this.session = original.session;
|
||||||
|
this.queryOptions = original.queryOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SharedSessionContractImplementor getSession() {
|
public SharedSessionContractImplementor getSession() {
|
||||||
|
|
|
@ -80,6 +80,12 @@ public abstract class AbstractSelectionQuery<R>
|
||||||
super( session );
|
super( session );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected AbstractSelectionQuery(AbstractSelectionQuery<?> original) {
|
||||||
|
super( original );
|
||||||
|
this.sessionFlushMode = original.sessionFlushMode;
|
||||||
|
this.sessionCacheMode = original.sessionCacheMode;
|
||||||
|
}
|
||||||
|
|
||||||
protected void applyOptions(NamedQueryMemento<?> memento) {
|
protected void applyOptions(NamedQueryMemento<?> memento) {
|
||||||
if ( memento.getHints() != null ) {
|
if ( memento.getHints() != null ) {
|
||||||
memento.getHints().forEach( this::applyHint );
|
memento.getHints().forEach( this::applyHint );
|
||||||
|
|
|
@ -15,7 +15,6 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.hibernate.Internal;
|
|
||||||
import org.hibernate.jpa.spi.JpaCompliance;
|
import org.hibernate.jpa.spi.JpaCompliance;
|
||||||
import org.hibernate.metamodel.model.domain.JpaMetamodel;
|
import org.hibernate.metamodel.model.domain.JpaMetamodel;
|
||||||
import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
|
import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
|
||||||
|
@ -33,7 +32,6 @@ import org.hibernate.query.criteria.JpaSearchedCase;
|
||||||
import org.hibernate.query.criteria.JpaSelection;
|
import org.hibernate.query.criteria.JpaSelection;
|
||||||
import org.hibernate.query.criteria.JpaSimpleCase;
|
import org.hibernate.query.criteria.JpaSimpleCase;
|
||||||
import org.hibernate.query.criteria.JpaWindow;
|
import org.hibernate.query.criteria.JpaWindow;
|
||||||
import org.hibernate.query.criteria.ValueHandlingMode;
|
|
||||||
import org.hibernate.query.spi.QueryEngine;
|
import org.hibernate.query.spi.QueryEngine;
|
||||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmBagJoin;
|
import org.hibernate.query.sqm.tree.domain.SqmBagJoin;
|
||||||
|
@ -91,9 +89,6 @@ public interface NodeBuilder extends HibernateCriteriaBuilder, BindingContext {
|
||||||
|
|
||||||
QueryEngine getQueryEngine();
|
QueryEngine getQueryEngine();
|
||||||
|
|
||||||
@Internal
|
|
||||||
ValueHandlingMode setCriteriaValueHandlingMode(ValueHandlingMode criteriaValueHandlingMode);
|
|
||||||
|
|
||||||
<R> SqmTuple<R> tuple(
|
<R> SqmTuple<R> tuple(
|
||||||
Class<R> tupleType,
|
Class<R> tupleType,
|
||||||
SqmExpression<?>... expressions);
|
SqmExpression<?>... expressions);
|
||||||
|
|
|
@ -15,7 +15,6 @@ import org.hibernate.query.Page;
|
||||||
import org.hibernate.query.QueryLogging;
|
import org.hibernate.query.QueryLogging;
|
||||||
import org.hibernate.query.SelectionQuery;
|
import org.hibernate.query.SelectionQuery;
|
||||||
import org.hibernate.query.criteria.JpaSelection;
|
import org.hibernate.query.criteria.JpaSelection;
|
||||||
import org.hibernate.query.criteria.ValueHandlingMode;
|
|
||||||
import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl;
|
import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl;
|
||||||
import org.hibernate.query.hql.internal.QuerySplitter;
|
import org.hibernate.query.hql.internal.QuerySplitter;
|
||||||
import org.hibernate.query.named.NamedQueryMemento;
|
import org.hibernate.query.named.NamedQueryMemento;
|
||||||
|
@ -25,7 +24,6 @@ import org.hibernate.query.spi.MutableQueryOptions;
|
||||||
import org.hibernate.query.spi.QueryEngine;
|
import org.hibernate.query.spi.QueryEngine;
|
||||||
import org.hibernate.query.spi.QueryOptions;
|
import org.hibernate.query.spi.QueryOptions;
|
||||||
import org.hibernate.query.spi.SelectQueryPlan;
|
import org.hibernate.query.spi.SelectQueryPlan;
|
||||||
import org.hibernate.query.sqm.NodeBuilder;
|
|
||||||
import org.hibernate.query.sqm.spi.NamedSqmQueryMemento;
|
import org.hibernate.query.sqm.spi.NamedSqmQueryMemento;
|
||||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||||
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
||||||
|
@ -48,7 +46,6 @@ import jakarta.persistence.criteria.CompoundSelection;
|
||||||
import static java.util.stream.Collectors.toList;
|
import static java.util.stream.Collectors.toList;
|
||||||
import static org.hibernate.cfg.QuerySettings.FAIL_ON_PAGINATION_OVER_COLLECTION_FETCH;
|
import static org.hibernate.cfg.QuerySettings.FAIL_ON_PAGINATION_OVER_COLLECTION_FETCH;
|
||||||
import static org.hibernate.query.KeyedPage.KeyInterpretation.KEY_OF_FIRST_ON_NEXT_PAGE;
|
import static org.hibernate.query.KeyedPage.KeyInterpretation.KEY_OF_FIRST_ON_NEXT_PAGE;
|
||||||
import static org.hibernate.query.sqm.internal.KeyBasedPagination.paginate;
|
|
||||||
import static org.hibernate.query.sqm.internal.KeyedResult.collectKeys;
|
import static org.hibernate.query.sqm.internal.KeyedResult.collectKeys;
|
||||||
import static org.hibernate.query.sqm.internal.KeyedResult.collectResults;
|
import static org.hibernate.query.sqm.internal.KeyedResult.collectResults;
|
||||||
import static org.hibernate.query.sqm.internal.SqmUtil.isHqlTuple;
|
import static org.hibernate.query.sqm.internal.SqmUtil.isHqlTuple;
|
||||||
|
@ -65,6 +62,10 @@ abstract class AbstractSqmSelectionQuery<R> extends AbstractSelectionQuery<R> {
|
||||||
super(session);
|
super(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AbstractSqmSelectionQuery(AbstractSqmSelectionQuery<?> original) {
|
||||||
|
super( original );
|
||||||
|
}
|
||||||
|
|
||||||
protected int max(boolean hasLimit, SqmSelectStatement<?> sqmStatement, List<R> list) {
|
protected int max(boolean hasLimit, SqmSelectStatement<?> sqmStatement, List<R> list) {
|
||||||
return !hasLimit || getQueryOptions().getLimit().getMaxRows() == null
|
return !hasLimit || getQueryOptions().getLimit().getMaxRows() == null
|
||||||
? getMaxRows( sqmStatement, list.size() )
|
? getMaxRows( sqmStatement, list.size() )
|
||||||
|
@ -154,46 +155,14 @@ abstract class AbstractSqmSelectionQuery<R> extends AbstractSelectionQuery<R> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SqmSelectStatement<KeyedResult<R>> paginateQuery(
|
|
||||||
List<Order<? super R>> keyDefinition, List<Comparable<?>> keyValues) {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
final SqmSelectStatement<KeyedResult<R>> sqm =
|
|
||||||
(SqmSelectStatement<KeyedResult<R>>)
|
|
||||||
getSqmSelectStatement().copy( noParamCopyContext() );
|
|
||||||
final NodeBuilder builder = sqm.nodeBuilder();
|
|
||||||
//TODO: find a better way handle parameters
|
|
||||||
final ValueHandlingMode valueHandlingMode = builder.setCriteriaValueHandlingMode(ValueHandlingMode.INLINE);
|
|
||||||
try {
|
|
||||||
return paginate( keyDefinition, keyValues, sqm, builder );
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
builder.setCriteriaValueHandlingMode( valueHandlingMode );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyedResultList<R> getKeyedResultList(KeyedPage<R> keyedPage) {
|
public KeyedResultList<R> getKeyedResultList(KeyedPage<R> keyedPage) {
|
||||||
if ( keyedPage == null ) {
|
if ( keyedPage == null ) {
|
||||||
throw new IllegalArgumentException( "KeyedPage was null" );
|
throw new IllegalArgumentException( "KeyedPage was null" );
|
||||||
}
|
}
|
||||||
|
final List<KeyedResult<R>> results = new SqmSelectionQueryImpl<KeyedResult<R>>( this, keyedPage )
|
||||||
|
.getResultList();
|
||||||
final Page page = keyedPage.getPage();
|
final Page page = keyedPage.getPage();
|
||||||
final List<Comparable<?>> key = keyedPage.getKey();
|
|
||||||
final List<Order<? super R>> keyDefinition = keyedPage.getKeyDefinition();
|
|
||||||
final List<Order<? super R>> appliedKeyDefinition =
|
|
||||||
keyedPage.getKeyInterpretation() == KEY_OF_FIRST_ON_NEXT_PAGE
|
|
||||||
? Order.reverse( keyDefinition ) : keyDefinition;
|
|
||||||
|
|
||||||
setMaxResults( page.getMaxResults() + 1 );
|
|
||||||
if ( key == null ) {
|
|
||||||
setFirstResult( page.getFirstResult() );
|
|
||||||
}
|
|
||||||
|
|
||||||
// getQueryOptions().setQueryPlanCachingEnabled( false );
|
|
||||||
final List<KeyedResult<R>> results =
|
|
||||||
buildConcreteQueryPlan( paginateQuery( appliedKeyDefinition, key ), getQueryOptions() )
|
|
||||||
.performList(this);
|
|
||||||
|
|
||||||
return new KeyedResultList<>(
|
return new KeyedResultList<>(
|
||||||
collectResults( results, page.getSize(), keyedPage.getKeyInterpretation() ),
|
collectResults( results, page.getSize(), keyedPage.getKeyInterpretation() ),
|
||||||
collectKeys( results, page.getSize() ),
|
collectKeys( results, page.getSize() ),
|
||||||
|
@ -277,10 +246,6 @@ abstract class AbstractSqmSelectionQuery<R> extends AbstractSelectionQuery<R> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> SelectQueryPlan<T> buildConcreteQueryPlan(SqmSelectStatement<T> sqmStatement, QueryOptions options) {
|
|
||||||
return buildConcreteQueryPlan( sqmStatement, null, null, options );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void applyOptions(NamedSqmQueryMemento<?> memento) {
|
protected void applyOptions(NamedSqmQueryMemento<?> memento) {
|
||||||
applyOptions( (NamedQueryMemento<?>) memento );
|
applyOptions( (NamedQueryMemento<?>) memento );
|
||||||
|
|
||||||
|
|
|
@ -116,11 +116,6 @@ public class KeyBasedPagination {
|
||||||
Expression<? extends C> key, C keyValue, SortDirection direction,
|
Expression<? extends C> key, C keyValue, SortDirection direction,
|
||||||
List<SqmPath<?>> previousKeys, List<Comparable<?>> keyValues,
|
List<SqmPath<?>> previousKeys, List<Comparable<?>> keyValues,
|
||||||
NodeBuilder builder) {
|
NodeBuilder builder) {
|
||||||
// TODO: use a parameter here and create a binding for it
|
|
||||||
// @SuppressWarnings("unchecked")
|
|
||||||
// final Class<C> valueClass = (Class<C>) keyValue.getClass();
|
|
||||||
// final JpaParameterExpression<C> parameter = builder.parameter(valueClass);
|
|
||||||
// setParameter( parameter, keyValue );
|
|
||||||
SqmPredicate predicate;
|
SqmPredicate predicate;
|
||||||
switch ( direction ) {
|
switch ( direction ) {
|
||||||
case ASCENDING:
|
case ASCENDING:
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.query.sqm.internal;
|
package org.hibernate.query.sqm.internal;
|
||||||
|
|
||||||
|
import org.hibernate.query.sqm.SqmQuerySource;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
@ -12,6 +13,13 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
* @author Marco Belladelli
|
* @author Marco Belladelli
|
||||||
*/
|
*/
|
||||||
public class NoParamSqmCopyContext extends SimpleSqmCopyContext {
|
public class NoParamSqmCopyContext extends SimpleSqmCopyContext {
|
||||||
|
public NoParamSqmCopyContext() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public NoParamSqmCopyContext(@Nullable SqmQuerySource querySource) {
|
||||||
|
super( querySource );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> @Nullable T getCopy(T original) {
|
public <T> @Nullable T getCopy(T original) {
|
||||||
if ( original instanceof SqmParameter<?> ) {
|
if ( original instanceof SqmParameter<?> ) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ package org.hibernate.query.sqm.internal;
|
||||||
|
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
|
|
||||||
|
import org.hibernate.query.sqm.SqmQuerySource;
|
||||||
import org.hibernate.query.sqm.tree.SqmCopyContext;
|
import org.hibernate.query.sqm.tree.SqmCopyContext;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
@ -15,6 +16,15 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
*/
|
*/
|
||||||
public class SimpleSqmCopyContext implements SqmCopyContext {
|
public class SimpleSqmCopyContext implements SqmCopyContext {
|
||||||
private final IdentityHashMap<Object, Object> map = new IdentityHashMap<>();
|
private final IdentityHashMap<Object, Object> map = new IdentityHashMap<>();
|
||||||
|
private final @Nullable SqmQuerySource querySource;
|
||||||
|
|
||||||
|
public SimpleSqmCopyContext() {
|
||||||
|
this( null );
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleSqmCopyContext(@Nullable SqmQuerySource querySource) {
|
||||||
|
this.querySource = querySource;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
|
@ -30,4 +40,9 @@ public class SimpleSqmCopyContext implements SqmCopyContext {
|
||||||
}
|
}
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable SqmQuerySource getQuerySource() {
|
||||||
|
return querySource;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,13 +242,6 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ValueHandlingMode setCriteriaValueHandlingMode(ValueHandlingMode criteriaValueHandlingMode) {
|
|
||||||
ValueHandlingMode current = this.criteriaValueHandlingMode;
|
|
||||||
this.criteriaValueHandlingMode = criteriaValueHandlingMode;
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JpaMetamodel getDomainModel() {
|
public JpaMetamodel getDomainModel() {
|
||||||
return bindingContext.getJpaMetamodel();
|
return bindingContext.getJpaMetamodel();
|
||||||
|
|
|
@ -29,7 +29,11 @@ import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||||
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;
|
||||||
|
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||||
import org.hibernate.query.BindableType;
|
import org.hibernate.query.BindableType;
|
||||||
|
import org.hibernate.query.KeyedPage;
|
||||||
|
import org.hibernate.query.Order;
|
||||||
|
import org.hibernate.query.Page;
|
||||||
import org.hibernate.query.QueryParameter;
|
import org.hibernate.query.QueryParameter;
|
||||||
import org.hibernate.query.criteria.internal.NamedCriteriaQueryMementoImpl;
|
import org.hibernate.query.criteria.internal.NamedCriteriaQueryMementoImpl;
|
||||||
import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl;
|
import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl;
|
||||||
|
@ -41,9 +45,11 @@ import org.hibernate.query.spi.MutableQueryOptions;
|
||||||
import org.hibernate.query.spi.ParameterMetadataImplementor;
|
import org.hibernate.query.spi.ParameterMetadataImplementor;
|
||||||
import org.hibernate.query.spi.QueryInterpretationCache;
|
import org.hibernate.query.spi.QueryInterpretationCache;
|
||||||
import org.hibernate.query.spi.QueryOptions;
|
import org.hibernate.query.spi.QueryOptions;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBinding;
|
||||||
import org.hibernate.query.spi.QueryParameterBindings;
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||||
import org.hibernate.query.spi.SelectQueryPlan;
|
import org.hibernate.query.spi.SelectQueryPlan;
|
||||||
|
import org.hibernate.query.sqm.SqmQuerySource;
|
||||||
import org.hibernate.query.sqm.SqmSelectionQuery;
|
import org.hibernate.query.sqm.SqmSelectionQuery;
|
||||||
import org.hibernate.query.sqm.internal.SqmInterpretationsKey.InterpretationsKeySource;
|
import org.hibernate.query.sqm.internal.SqmInterpretationsKey.InterpretationsKeySource;
|
||||||
import org.hibernate.query.sqm.spi.SqmSelectionQueryImplementor;
|
import org.hibernate.query.sqm.spi.SqmSelectionQueryImplementor;
|
||||||
|
@ -68,9 +74,12 @@ import static org.hibernate.jpa.LegacySpecHints.HINT_JAVAEE_CACHE_RETRIEVE_MODE;
|
||||||
import static org.hibernate.jpa.LegacySpecHints.HINT_JAVAEE_CACHE_STORE_MODE;
|
import static org.hibernate.jpa.LegacySpecHints.HINT_JAVAEE_CACHE_STORE_MODE;
|
||||||
import static org.hibernate.jpa.SpecHints.HINT_SPEC_CACHE_RETRIEVE_MODE;
|
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.KeyedPage.KeyInterpretation.KEY_OF_FIRST_ON_NEXT_PAGE;
|
||||||
import static org.hibernate.query.spi.SqlOmittingQueryOptions.omitSqlQueryOptions;
|
import static org.hibernate.query.spi.SqlOmittingQueryOptions.omitSqlQueryOptions;
|
||||||
|
import static org.hibernate.query.sqm.internal.KeyBasedPagination.paginate;
|
||||||
import static org.hibernate.query.sqm.internal.SqmInterpretationsKey.createInterpretationsKey;
|
import static org.hibernate.query.sqm.internal.SqmInterpretationsKey.createInterpretationsKey;
|
||||||
import static org.hibernate.query.sqm.internal.SqmUtil.isSelectionAssignableToResultType;
|
import static org.hibernate.query.sqm.internal.SqmUtil.isSelectionAssignableToResultType;
|
||||||
|
import static org.hibernate.query.sqm.tree.SqmCopyContext.noParamCopyContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -178,6 +187,87 @@ public class SqmSelectionQueryImpl<R> extends AbstractSqmSelectionQuery<R>
|
||||||
this.tupleMetadata = buildTupleMetadata( sqm, expectedResultType );
|
this.tupleMetadata = buildTupleMetadata( sqm, expectedResultType );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<E> SqmSelectionQueryImpl(AbstractSqmSelectionQuery<?> original, KeyedPage<E> keyedPage) {
|
||||||
|
super( original );
|
||||||
|
|
||||||
|
final Page page = keyedPage.getPage();
|
||||||
|
final List<Comparable<?>> key = keyedPage.getKey();
|
||||||
|
final List<Order<? super E>> keyDefinition = keyedPage.getKeyDefinition();
|
||||||
|
final List<Order<? super E>> appliedKeyDefinition =
|
||||||
|
keyedPage.getKeyInterpretation() == KEY_OF_FIRST_ON_NEXT_PAGE
|
||||||
|
? Order.reverse( keyDefinition ) : keyDefinition;
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
this.sqm = (SqmSelectStatement<R>) paginate(
|
||||||
|
appliedKeyDefinition,
|
||||||
|
key,
|
||||||
|
// Change the query source to CRITERIA, because we will change the query and introduce parameters
|
||||||
|
(SqmSelectStatement<KeyedResult<E>>) original.getSqmStatement()
|
||||||
|
.copy( noParamCopyContext( SqmQuerySource.CRITERIA ) ),
|
||||||
|
original.getSqmStatement().nodeBuilder()
|
||||||
|
);
|
||||||
|
this.hql = CRITERIA_HQL_STRING;
|
||||||
|
|
||||||
|
this.domainParameterXref = DomainParameterXref.from( sqm );
|
||||||
|
this.parameterMetadata = domainParameterXref.hasParameters()
|
||||||
|
? new ParameterMetadataImpl( domainParameterXref.getQueryParameters() )
|
||||||
|
: ParameterMetadataImpl.EMPTY;
|
||||||
|
|
||||||
|
// Just use the original parameter bindings since this object is never going to be mutated
|
||||||
|
this.parameterBindings = parameterMetadata.createBindings( original.getSession().getSessionFactory() );
|
||||||
|
// Don't remove this cast. This is here to work around this bug: https://bugs.openjdk.org/browse/JDK-8340443
|
||||||
|
(( DomainQueryExecutionContext) original ).getQueryParameterBindings().visitBindings(
|
||||||
|
(parameter, binding) -> {
|
||||||
|
//noinspection unchecked
|
||||||
|
final QueryParameterBinding<Object> parameterBinding =
|
||||||
|
(QueryParameterBinding<Object>) this.parameterBindings.getBinding( parameter );
|
||||||
|
//noinspection unchecked
|
||||||
|
final BindableType<Object> bindType = (BindableType<Object>) binding.getBindType();
|
||||||
|
final TemporalType explicitTemporalPrecision = binding.getExplicitTemporalPrecision();
|
||||||
|
if ( explicitTemporalPrecision != null ) {
|
||||||
|
if ( binding.isMultiValued() ) {
|
||||||
|
parameterBinding.setBindValues(
|
||||||
|
binding.getBindValues(),
|
||||||
|
explicitTemporalPrecision,
|
||||||
|
getSessionFactory().getTypeConfiguration()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parameterBinding.setBindValue( binding.getBindValue(), explicitTemporalPrecision );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( binding.isMultiValued() ) {
|
||||||
|
parameterBinding.setBindValues( binding.getBindValues(), bindType );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parameterBinding.setBindValue( binding.getBindValue(), bindType );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//noinspection unchecked
|
||||||
|
parameterBinding.setType( (MappingModelExpressible<Object>) binding.getType() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Parameters might be created through HibernateCriteriaBuilder.value which we need to bind here
|
||||||
|
for ( SqmParameter<?> sqmParameter : domainParameterXref.getParameterResolutions().getSqmParameters() ) {
|
||||||
|
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> ) {
|
||||||
|
bindCriteriaParameter( (SqmJpaCriteriaParameterWrapper<?>) sqmParameter );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
this.expectedResultType = (Class<R>) KeyedResult.class;
|
||||||
|
this.resultType = determineResultType( sqm, expectedResultType );
|
||||||
|
this.tupleMetadata = null;
|
||||||
|
|
||||||
|
setMaxResults( page.getMaxResults() + 1 );
|
||||||
|
if ( key == null ) {
|
||||||
|
setFirstResult( page.getFirstResult() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static Class<?> determineResultType(SqmSelectStatement<?> sqm, Class<?> expectedResultType) {
|
private static Class<?> determineResultType(SqmSelectStatement<?> sqm, Class<?> expectedResultType) {
|
||||||
final List<SqmSelection<?>> selections = sqm.getQuerySpec().getSelectClause().getSelections();
|
final List<SqmSelection<?>> selections = sqm.getQuerySpec().getSelectClause().getSelections();
|
||||||
if ( selections.size() == 1 ) {
|
if ( selections.size() == 1 ) {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package org.hibernate.query.sqm.tree;
|
package org.hibernate.query.sqm.tree;
|
||||||
|
|
||||||
import org.hibernate.Incubating;
|
import org.hibernate.Incubating;
|
||||||
|
import org.hibernate.query.sqm.SqmQuerySource;
|
||||||
import org.hibernate.query.sqm.internal.NoParamSqmCopyContext;
|
import org.hibernate.query.sqm.internal.NoParamSqmCopyContext;
|
||||||
import org.hibernate.query.sqm.internal.SimpleSqmCopyContext;
|
import org.hibernate.query.sqm.internal.SimpleSqmCopyContext;
|
||||||
|
|
||||||
|
@ -29,11 +30,30 @@ public interface SqmCopyContext {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the query source to use for copied queries.
|
||||||
|
* {@code null} means, that the original query source should be retained.
|
||||||
|
*
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
@Incubating
|
||||||
|
default @Nullable SqmQuerySource getQuerySource() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
static SqmCopyContext simpleContext() {
|
static SqmCopyContext simpleContext() {
|
||||||
return new SimpleSqmCopyContext();
|
return new SimpleSqmCopyContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SqmCopyContext simpleContext(SqmQuerySource querySource) {
|
||||||
|
return new SimpleSqmCopyContext( querySource );
|
||||||
|
}
|
||||||
|
|
||||||
static SqmCopyContext noParamCopyContext() {
|
static SqmCopyContext noParamCopyContext() {
|
||||||
return new NoParamSqmCopyContext();
|
return new NoParamSqmCopyContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SqmCopyContext noParamCopyContext(SqmQuerySource querySource) {
|
||||||
|
return new NoParamSqmCopyContext( querySource );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ public class SqmDeleteStatement<T>
|
||||||
this,
|
this,
|
||||||
new SqmDeleteStatement<>(
|
new SqmDeleteStatement<>(
|
||||||
nodeBuilder(),
|
nodeBuilder(),
|
||||||
getQuerySource(),
|
context.getQuerySource() == null ? getQuerySource() : context.getQuerySource(),
|
||||||
copyParameters( context ),
|
copyParameters( context ),
|
||||||
copyCteStatements( context ),
|
copyCteStatements( context ),
|
||||||
getTarget().copy( context )
|
getTarget().copy( context )
|
||||||
|
|
|
@ -85,7 +85,7 @@ public class SqmInsertSelectStatement<T> extends AbstractSqmInsertStatement<T> i
|
||||||
this,
|
this,
|
||||||
new SqmInsertSelectStatement<>(
|
new SqmInsertSelectStatement<>(
|
||||||
nodeBuilder(),
|
nodeBuilder(),
|
||||||
getQuerySource(),
|
context.getQuerySource() == null ? getQuerySource() : context.getQuerySource(),
|
||||||
copyParameters( context ),
|
copyParameters( context ),
|
||||||
copyCteStatements( context ),
|
copyCteStatements( context ),
|
||||||
getTarget().copy( context ),
|
getTarget().copy( context ),
|
||||||
|
|
|
@ -90,7 +90,7 @@ public class SqmInsertValuesStatement<T> extends AbstractSqmInsertStatement<T> i
|
||||||
this,
|
this,
|
||||||
new SqmInsertValuesStatement<>(
|
new SqmInsertValuesStatement<>(
|
||||||
nodeBuilder(),
|
nodeBuilder(),
|
||||||
getQuerySource(),
|
context.getQuerySource() == null ? getQuerySource() : context.getQuerySource(),
|
||||||
copyParameters( context ),
|
copyParameters( context ),
|
||||||
copyCteStatements( context ),
|
copyCteStatements( context ),
|
||||||
getTarget().copy( context ),
|
getTarget().copy( context ),
|
||||||
|
@ -106,7 +106,7 @@ public class SqmInsertValuesStatement<T> extends AbstractSqmInsertStatement<T> i
|
||||||
this,
|
this,
|
||||||
new SqmInsertValuesStatement<>(
|
new SqmInsertValuesStatement<>(
|
||||||
nodeBuilder(),
|
nodeBuilder(),
|
||||||
getQuerySource(),
|
context.getQuerySource() == null ? getQuerySource() : context.getQuerySource(),
|
||||||
copyParameters( context ),
|
copyParameters( context ),
|
||||||
copyCteStatements( context ),
|
copyCteStatements( context ),
|
||||||
getTarget().copy( context ),
|
getTarget().copy( context ),
|
||||||
|
|
|
@ -146,7 +146,7 @@ public class SqmSelectStatement<T> extends AbstractSqmSelectQuery<T> implements
|
||||||
nodeBuilder(),
|
nodeBuilder(),
|
||||||
copyCteStatements( context ),
|
copyCteStatements( context ),
|
||||||
resultType,
|
resultType,
|
||||||
getQuerySource(),
|
context.getQuerySource() == null ? getQuerySource() : context.getQuerySource(),
|
||||||
parameters
|
parameters
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -106,7 +106,7 @@ public class SqmUpdateStatement<T>
|
||||||
this,
|
this,
|
||||||
new SqmUpdateStatement<>(
|
new SqmUpdateStatement<>(
|
||||||
nodeBuilder(),
|
nodeBuilder(),
|
||||||
getQuerySource(),
|
context.getQuerySource() == null ? getQuerySource() : context.getQuerySource(),
|
||||||
copyParameters( context ),
|
copyParameters( context ),
|
||||||
copyCteStatements( context ),
|
copyCteStatements( context ),
|
||||||
getTarget().copy( context )
|
getTarget().copy( context )
|
||||||
|
|
|
@ -69,7 +69,6 @@ import static org.hamcrest.Matchers.isOneOf;
|
||||||
import static org.hibernate.testing.orm.domain.gambit.EntityOfBasics.Gender.FEMALE;
|
import static org.hibernate.testing.orm.domain.gambit.EntityOfBasics.Gender.FEMALE;
|
||||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue