pull up some duplicated code to AbstractSqmSelectionQuery
This commit is contained in:
parent
f87ea083e6
commit
0502869545
|
@ -16,7 +16,6 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Spliterator;
|
import java.util.Spliterator;
|
||||||
import java.util.Spliterators;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
@ -77,7 +76,9 @@ 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;
|
||||||
|
|
||||||
|
import static java.util.Spliterators.spliteratorUnknownSize;
|
||||||
import static org.hibernate.CacheMode.fromJpaModes;
|
import static org.hibernate.CacheMode.fromJpaModes;
|
||||||
|
import static org.hibernate.FlushMode.fromJpaFlushMode;
|
||||||
import static org.hibernate.cfg.AvailableSettings.JAKARTA_SHARED_CACHE_RETRIEVE_MODE;
|
import static org.hibernate.cfg.AvailableSettings.JAKARTA_SHARED_CACHE_RETRIEVE_MODE;
|
||||||
import static org.hibernate.cfg.AvailableSettings.JAKARTA_SHARED_CACHE_STORE_MODE;
|
import static org.hibernate.cfg.AvailableSettings.JAKARTA_SHARED_CACHE_STORE_MODE;
|
||||||
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE;
|
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE;
|
||||||
|
@ -385,32 +386,26 @@ public abstract class AbstractSelectionQuery<R>
|
||||||
if ( jdbcType != null ) {
|
if ( jdbcType != null ) {
|
||||||
switch ( jdbcType.getDefaultSqlTypeCode() ) {
|
switch ( jdbcType.getDefaultSqlTypeCode() ) {
|
||||||
case Types.DATE:
|
case Types.DATE:
|
||||||
if ( resultClass.isAssignableFrom( java.sql.Date.class ) ) {
|
return resultClass.isAssignableFrom( java.sql.Date.class );
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Types.TIME:
|
case Types.TIME:
|
||||||
if ( resultClass.isAssignableFrom( java.sql.Time.class ) ) {
|
return resultClass.isAssignableFrom( java.sql.Time.class );
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Types.TIMESTAMP:
|
case Types.TIMESTAMP:
|
||||||
if ( resultClass.isAssignableFrom( java.sql.Timestamp.class ) ) {
|
return resultClass.isAssignableFrom( java.sql.Timestamp.class );
|
||||||
return true;
|
default:
|
||||||
}
|
return false;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> void throwQueryTypeMismatchException(Class<T> resultClass, SqmExpressible<?> sqmExpressible) {
|
private static <T> void throwQueryTypeMismatchException(Class<T> resultClass, SqmExpressible<?> sqmExpressible) {
|
||||||
final String errorMessage = String.format(
|
throw new QueryTypeMismatchException( String.format(
|
||||||
"Specified result type [%s] did not match Query selection type [%s] - multiple selections: use Tuple or array",
|
"Specified result type [%s] did not match Query selection type [%s] - multiple selections: use Tuple or array",
|
||||||
resultClass.getName(),
|
resultClass.getName(),
|
||||||
sqmExpressible.getTypeName()
|
sqmExpressible.getTypeName()
|
||||||
);
|
) );
|
||||||
throw new QueryTypeMismatchException( errorMessage );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -442,9 +437,7 @@ public abstract class AbstractSelectionQuery<R>
|
||||||
|
|
||||||
protected HashSet<String> beforeQueryHandlingFetchProfiles() {
|
protected HashSet<String> beforeQueryHandlingFetchProfiles() {
|
||||||
beforeQuery();
|
beforeQuery();
|
||||||
|
|
||||||
final MutableQueryOptions options = getQueryOptions();
|
final MutableQueryOptions options = getQueryOptions();
|
||||||
|
|
||||||
return getSession().getLoadQueryInfluencers()
|
return getSession().getLoadQueryInfluencers()
|
||||||
.adjustFetchProfiles( options.getDisabledFetchProfiles(), options.getEnabledFetchProfiles() );
|
.adjustFetchProfiles( options.getDisabledFetchProfiles(), options.getEnabledFetchProfiles() );
|
||||||
}
|
}
|
||||||
|
@ -519,7 +512,7 @@ public abstract class AbstractSelectionQuery<R>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ScrollableResultsImplementor<R> scroll() {
|
public ScrollableResultsImplementor<R> scroll() {
|
||||||
return scroll( getSession().getFactory().getJdbcServices().getJdbcEnvironment().getDialect().defaultScrollMode() );
|
return scroll( getSessionFactory().getJdbcServices().getDialect().defaultScrollMode() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -545,7 +538,7 @@ public abstract class AbstractSelectionQuery<R>
|
||||||
public Stream stream() {
|
public Stream stream() {
|
||||||
final ScrollableResultsImplementor scrollableResults = scroll( ScrollMode.FORWARD_ONLY );
|
final ScrollableResultsImplementor scrollableResults = scroll( ScrollMode.FORWARD_ONLY );
|
||||||
final ScrollableResultsIterator iterator = new ScrollableResultsIterator<>( scrollableResults );
|
final ScrollableResultsIterator iterator = new ScrollableResultsIterator<>( scrollableResults );
|
||||||
final Spliterator spliterator = Spliterators.spliteratorUnknownSize( iterator, Spliterator.NONNULL );
|
final Spliterator spliterator = spliteratorUnknownSize( iterator, Spliterator.NONNULL );
|
||||||
|
|
||||||
final Stream stream = StreamSupport.stream( spliterator, false );
|
final Stream stream = StreamSupport.stream( spliterator, false );
|
||||||
return (Stream) stream.onClose( scrollableResults::close );
|
return (Stream) stream.onClose( scrollableResults::close );
|
||||||
|
@ -577,14 +570,16 @@ public abstract class AbstractSelectionQuery<R>
|
||||||
if ( size == 0 ) {
|
if ( size == 0 ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final T first = list.get( 0 );
|
else {
|
||||||
// todo (6.0) : add a setting here to control whether to perform this validation or not
|
final T first = list.get( 0 );
|
||||||
for ( int i = 1; i < size; i++ ) {
|
// todo (6.0) : add a setting here to control whether to perform this validation or not
|
||||||
if ( list.get( i ) != first ) {
|
for ( int i = 1; i < size; i++ ) {
|
||||||
throw new NonUniqueResultException( list.size() );
|
if ( list.get( i ) != first ) {
|
||||||
|
throw new NonUniqueResultException( list.size() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return first;
|
||||||
}
|
}
|
||||||
return first;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -602,17 +597,6 @@ public abstract class AbstractSelectionQuery<R>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static boolean hasLimit(SqmSelectStatement<?> sqm, MutableQueryOptions queryOptions) {
|
|
||||||
return queryOptions.hasLimit() || sqm.getFetch() != null || sqm.getOffset() != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static boolean hasAppliedGraph(MutableQueryOptions queryOptions) {
|
|
||||||
return queryOptions.getAppliedGraph() != null
|
|
||||||
&& queryOptions.getAppliedGraph().getSemantic() != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// DomainQueryExecutionContext
|
// DomainQueryExecutionContext
|
||||||
|
|
||||||
|
@ -641,7 +625,7 @@ public abstract class AbstractSelectionQuery<R>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SelectionQuery<R> setFlushMode(FlushModeType flushMode) {
|
public SelectionQuery<R> setFlushMode(FlushModeType flushMode) {
|
||||||
getQueryOptions().setFlushMode( FlushMode.fromJpaFlushMode( flushMode ) );
|
getQueryOptions().setFlushMode( fromJpaFlushMode( flushMode ) );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.query.sqm.internal;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.graph.spi.AppliedGraph;
|
||||||
|
import org.hibernate.query.QueryLogging;
|
||||||
|
import org.hibernate.query.hql.internal.QuerySplitter;
|
||||||
|
import org.hibernate.query.spi.AbstractSelectionQuery;
|
||||||
|
import org.hibernate.query.spi.MutableQueryOptions;
|
||||||
|
import org.hibernate.query.spi.QueryOptions;
|
||||||
|
import org.hibernate.query.spi.SelectQueryPlan;
|
||||||
|
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||||
|
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||||
|
import org.hibernate.sql.results.internal.TupleMetadata;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.hibernate.cfg.QuerySettings.FAIL_ON_PAGINATION_OVER_COLLECTION_FETCH;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gavin King
|
||||||
|
*/
|
||||||
|
abstract class AbstractSqmSelectionQuery<R> extends AbstractSelectionQuery<R> {
|
||||||
|
|
||||||
|
AbstractSqmSelectionQuery(SharedSessionContractImplementor session) {
|
||||||
|
super(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int max(boolean hasLimit, SqmSelectStatement<?> sqmStatement, List<R> list) {
|
||||||
|
return !hasLimit || getQueryOptions().getLimit().getMaxRows() == null
|
||||||
|
? getMaxRows( sqmStatement, list.size() )
|
||||||
|
: getQueryOptions().getLimit().getMaxRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int first(boolean hasLimit, SqmSelectStatement<?> sqmStatement) {
|
||||||
|
return !hasLimit || getQueryOptions().getLimit().getFirstRow() == null
|
||||||
|
? getIntegerLiteral( sqmStatement.getOffset(), 0 )
|
||||||
|
: getQueryOptions().getLimit().getFirstRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean hasLimit(SqmSelectStatement<?> sqm, MutableQueryOptions queryOptions) {
|
||||||
|
return queryOptions.hasLimit() || sqm.getFetch() != null || sqm.getOffset() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean needsDistinct(boolean containsCollectionFetches, boolean hasLimit, SqmSelectStatement<?> sqmStatement) {
|
||||||
|
return containsCollectionFetches
|
||||||
|
&& ( hasLimit || sqmStatement.usesDistinct() || hasAppliedGraph( getQueryOptions() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean hasAppliedGraph(MutableQueryOptions queryOptions) {
|
||||||
|
final AppliedGraph appliedGraph = queryOptions.getAppliedGraph();
|
||||||
|
return appliedGraph != null && appliedGraph.getSemantic() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void errorOrLogForPaginationWithCollectionFetch() {
|
||||||
|
if ( getSessionFactory().getSessionFactoryOptions().isFailOnPaginationOverCollectionFetchEnabled() ) {
|
||||||
|
throw new HibernateException(
|
||||||
|
"setFirstResult() or setMaxResults() specified with collection fetch join "
|
||||||
|
+ "(in-memory pagination was about to be applied, but '"
|
||||||
|
+ FAIL_ON_PAGINATION_OVER_COLLECTION_FETCH
|
||||||
|
+ "' is enabled)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
QueryLogging.QUERY_MESSAGE_LOGGER.firstOrMaxResultsSpecifiedWithCollectionFetch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract SqmStatement<R> getSqmStatement();
|
||||||
|
public abstract DomainParameterXref getDomainParameterXref();
|
||||||
|
public abstract TupleMetadata getTupleMetadata();
|
||||||
|
public abstract Class<R> getExpectedResultType();
|
||||||
|
|
||||||
|
protected SelectQueryPlan<R> buildSelectQueryPlan() {
|
||||||
|
final SqmSelectStatement<R> statement = (SqmSelectStatement<R>) getSqmStatement();
|
||||||
|
final SqmSelectStatement<R>[] concreteSqmStatements = QuerySplitter.split( statement );
|
||||||
|
return concreteSqmStatements.length > 1
|
||||||
|
? buildAggregatedQueryPlan( concreteSqmStatements )
|
||||||
|
: buildConcreteQueryPlan( concreteSqmStatements[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
private SelectQueryPlan<R> buildAggregatedQueryPlan(SqmSelectStatement<R>[] concreteSqmStatements) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final SelectQueryPlan<R>[] aggregatedQueryPlans = new SelectQueryPlan[ concreteSqmStatements.length ];
|
||||||
|
// todo (6.0) : we want to make sure that certain thing (ResultListTransformer, etc) only get applied at the aggregator-level
|
||||||
|
for ( int i = 0, length = concreteSqmStatements.length; i < length; i++ ) {
|
||||||
|
aggregatedQueryPlans[i] = buildConcreteQueryPlan( concreteSqmStatements[i] );
|
||||||
|
}
|
||||||
|
return new AggregatedSelectQueryPlanImpl<>( aggregatedQueryPlans );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SelectQueryPlan<R> buildConcreteQueryPlan(SqmSelectStatement<R> concreteSqmStatement) {
|
||||||
|
return buildConcreteQueryPlan(
|
||||||
|
concreteSqmStatement,
|
||||||
|
getExpectedResultType(),
|
||||||
|
getTupleMetadata(),
|
||||||
|
getQueryOptions()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <T> ConcreteSqmSelectQueryPlan<T> buildConcreteQueryPlan(
|
||||||
|
SqmSelectStatement<T> concreteSqmStatement,
|
||||||
|
Class<T> expectedResultType,
|
||||||
|
TupleMetadata tupleMetadata,
|
||||||
|
QueryOptions queryOptions) {
|
||||||
|
return new ConcreteSqmSelectQueryPlan<>(
|
||||||
|
concreteSqmStatement,
|
||||||
|
getQueryString(),
|
||||||
|
getDomainParameterXref(),
|
||||||
|
expectedResultType,
|
||||||
|
tupleMetadata,
|
||||||
|
queryOptions
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,6 @@ import org.hibernate.graph.spi.AppliedGraph;
|
||||||
import org.hibernate.graph.spi.AttributeNodeImplementor;
|
import org.hibernate.graph.spi.AttributeNodeImplementor;
|
||||||
import org.hibernate.graph.spi.GraphImplementor;
|
import org.hibernate.graph.spi.GraphImplementor;
|
||||||
import org.hibernate.graph.spi.SubGraphImplementor;
|
import org.hibernate.graph.spi.SubGraphImplementor;
|
||||||
import org.hibernate.metamodel.model.domain.PersistentAttribute;
|
|
||||||
import org.hibernate.query.spi.QueryOptions;
|
import org.hibernate.query.spi.QueryOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,17 +22,18 @@ public class AppliedGraphs {
|
||||||
|
|
||||||
public static boolean containsCollectionFetches(QueryOptions queryOptions) {
|
public static boolean containsCollectionFetches(QueryOptions queryOptions) {
|
||||||
final AppliedGraph appliedGraph = queryOptions.getAppliedGraph();
|
final AppliedGraph appliedGraph = queryOptions.getAppliedGraph();
|
||||||
return appliedGraph != null && appliedGraph.getGraph() != null && containsCollectionFetches(appliedGraph.getGraph());
|
return appliedGraph != null
|
||||||
|
&& appliedGraph.getGraph() != null
|
||||||
|
&& containsCollectionFetches( appliedGraph.getGraph() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean containsCollectionFetches(GraphImplementor<?> graph) {
|
private static boolean containsCollectionFetches(GraphImplementor<?> graph) {
|
||||||
for (AttributeNodeImplementor<?> attributeNodeImplementor : graph.getAttributeNodeImplementors()) {
|
for ( AttributeNodeImplementor<?> attributeNodeImplementor : graph.getAttributeNodeImplementors() ) {
|
||||||
PersistentAttribute<?, ?> attributeDescriptor = attributeNodeImplementor.getAttributeDescriptor();
|
if ( attributeNodeImplementor.getAttributeDescriptor().isCollection() ) {
|
||||||
if (attributeDescriptor.isCollection()) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (SubGraphImplementor<?> subGraph : attributeNodeImplementor.getSubGraphMap().values()) {
|
for ( SubGraphImplementor<?> subGraph : attributeNodeImplementor.getSubGraphMap().values() ) {
|
||||||
if (containsCollectionFetches(subGraph)) {
|
if ( containsCollectionFetches(subGraph) ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import org.hibernate.HibernateException;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.ScrollMode;
|
import org.hibernate.ScrollMode;
|
||||||
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;
|
||||||
|
@ -52,7 +51,6 @@ import org.hibernate.query.IllegalSelectQueryException;
|
||||||
import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
|
import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
|
||||||
import org.hibernate.query.Order;
|
import org.hibernate.query.Order;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
import org.hibernate.query.QueryLogging;
|
|
||||||
import org.hibernate.query.QueryParameter;
|
import org.hibernate.query.QueryParameter;
|
||||||
import org.hibernate.query.ResultListTransformer;
|
import org.hibernate.query.ResultListTransformer;
|
||||||
import org.hibernate.query.SemanticException;
|
import org.hibernate.query.SemanticException;
|
||||||
|
@ -65,7 +63,6 @@ import org.hibernate.query.internal.DelegatingDomainQueryExecutionContext;
|
||||||
import org.hibernate.query.internal.ParameterMetadataImpl;
|
import org.hibernate.query.internal.ParameterMetadataImpl;
|
||||||
import org.hibernate.query.internal.QueryParameterBindingsImpl;
|
import org.hibernate.query.internal.QueryParameterBindingsImpl;
|
||||||
import org.hibernate.query.named.NamedQueryMemento;
|
import org.hibernate.query.named.NamedQueryMemento;
|
||||||
import org.hibernate.query.spi.AbstractSelectionQuery;
|
|
||||||
import org.hibernate.query.spi.DelegatingQueryOptions;
|
import org.hibernate.query.spi.DelegatingQueryOptions;
|
||||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||||
import org.hibernate.query.spi.HqlInterpretation;
|
import org.hibernate.query.spi.HqlInterpretation;
|
||||||
|
@ -125,6 +122,7 @@ 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.AppliedGraphs.containsCollectionFetches;
|
||||||
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.SqmInterpretationsKey.generateNonSelectKey;
|
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;
|
||||||
|
@ -139,7 +137,7 @@ import static org.hibernate.query.sqm.tree.SqmCopyContext.noParamCopyContext;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class QuerySqmImpl<R>
|
public class QuerySqmImpl<R>
|
||||||
extends AbstractSelectionQuery<R>
|
extends AbstractSqmSelectionQuery<R>
|
||||||
implements SqmQueryImplementor<R>, InterpretationsKeySource, DomainQueryExecutionContext {
|
implements SqmQueryImplementor<R>, InterpretationsKeySource, DomainQueryExecutionContext {
|
||||||
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( QuerySqmImpl.class );
|
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( QuerySqmImpl.class );
|
||||||
|
|
||||||
|
@ -413,6 +411,7 @@ public class QuerySqmImpl<R>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TupleMetadata getTupleMetadata() {
|
public TupleMetadata getTupleMetadata() {
|
||||||
return tupleMetadata;
|
return tupleMetadata;
|
||||||
}
|
}
|
||||||
|
@ -427,6 +426,7 @@ public class QuerySqmImpl<R>
|
||||||
return sqm;
|
return sqm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DomainParameterXref getDomainParameterXref() {
|
public DomainParameterXref getDomainParameterXref() {
|
||||||
return domainParameterXref;
|
return domainParameterXref;
|
||||||
}
|
}
|
||||||
|
@ -446,10 +446,16 @@ public class QuerySqmImpl<R>
|
||||||
return getQueryParameterBindings();
|
return getQueryParameterBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Class<R> getResultType() {
|
public Class<R> getResultType() {
|
||||||
return resultType;
|
return resultType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<R> getExpectedResultType() {
|
||||||
|
return resultType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoadQueryInfluencers getLoadQueryInfluencers() {
|
public LoadQueryInfluencers getLoadQueryInfluencers() {
|
||||||
return getSession().getLoadQueryInfluencers();
|
return getSession().getLoadQueryInfluencers();
|
||||||
|
@ -501,59 +507,48 @@ public class QuerySqmImpl<R>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
final SqmSelectStatement<?> sqmStatement = (SqmSelectStatement<?>) getSqmStatement();
|
final SqmSelectStatement<?> sqmStatement = (SqmSelectStatement<?>) getSqmStatement();
|
||||||
return buildConcreteSelectQueryPlan( sqmStatement.createCountQuery(), Long.class, null, getQueryOptions() )
|
return buildConcreteQueryPlan( sqmStatement.createCountQuery(), Long.class, null, getQueryOptions() )
|
||||||
.executeQuery( context, new SingleResultConsumer<>() );
|
.executeQuery( context, new SingleResultConsumer<>() );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<R> doList() {
|
protected List<R> doList() {
|
||||||
verifySelect();
|
verifySelect();
|
||||||
|
final SqmSelectStatement<?> statement = (SqmSelectStatement<?>) getSqmStatement();
|
||||||
final SqmSelectStatement<?> sqmStatement = (SqmSelectStatement<?>) getSqmStatement();
|
|
||||||
final boolean containsCollectionFetches =
|
final boolean containsCollectionFetches =
|
||||||
sqmStatement.containsCollectionFetches()
|
statement.containsCollectionFetches()
|
||||||
|| AppliedGraphs.containsCollectionFetches( getQueryOptions() );
|
|| containsCollectionFetches( getQueryOptions() );
|
||||||
final boolean hasLimit = hasLimit( sqmStatement, getQueryOptions() );
|
final boolean hasLimit = hasLimit( statement, getQueryOptions() );
|
||||||
final boolean needsDistinct = containsCollectionFetches
|
final boolean needsDistinct = needsDistinct( containsCollectionFetches, hasLimit, statement );
|
||||||
&& ( 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 ) );
|
||||||
|
return needsDistinct ? handleDistinct( hasLimit, statement, list ) : list;
|
||||||
|
}
|
||||||
|
|
||||||
if ( needsDistinct ) {
|
private List<R> handleDistinct(boolean hasLimit, SqmSelectStatement<?> statement, List<R> list) {
|
||||||
final int first = !hasLimit || getQueryOptions().getLimit().getFirstRow() == null
|
final int first = first( hasLimit, statement );
|
||||||
? getIntegerLiteral( sqmStatement.getOffset(), 0 )
|
final int max = max( hasLimit, statement, list );
|
||||||
: getQueryOptions().getLimit().getFirstRow();
|
if ( first > 0 || max != -1 ) {
|
||||||
final int max = !hasLimit || getQueryOptions().getLimit().getMaxRows() == null
|
final int resultSize = list.size();
|
||||||
? getMaxRows( sqmStatement, list.size() )
|
if ( first > resultSize ) {
|
||||||
: getQueryOptions().getLimit().getMaxRows();
|
return new ArrayList<>(0);
|
||||||
if ( first > 0 || max != -1 ) {
|
}
|
||||||
final int resultSize = list.size();
|
else {
|
||||||
final int toIndex = max != -1 ? first + max : resultSize;
|
final int toIndex = max != -1 ? first + max : resultSize;
|
||||||
if ( first > resultSize ) {
|
|
||||||
return new ArrayList<>(0);
|
|
||||||
}
|
|
||||||
return list.subList( first, Math.min( toIndex, resultSize ) );
|
return list.subList( first, Math.min( toIndex, resultSize ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list;
|
else {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DomainQueryExecutionContext executionContextForDoList(boolean containsCollectionFetches, boolean hasLimit, boolean needsDistinct) {
|
// TODO: very similar to SqmSelectionQueryImpl.executionContext()
|
||||||
|
protected DomainQueryExecutionContext executionContextForDoList(
|
||||||
|
boolean containsCollectionFetches, boolean hasLimit, boolean needsDistinct) {
|
||||||
final MutableQueryOptions originalQueryOptions;
|
final MutableQueryOptions originalQueryOptions;
|
||||||
final QueryOptions normalizedQueryOptions;
|
final QueryOptions normalizedQueryOptions;
|
||||||
if ( hasLimit && containsCollectionFetches ) {
|
if ( hasLimit && containsCollectionFetches ) {
|
||||||
if ( getSessionFactory().getSessionFactoryOptions().isFailOnPaginationOverCollectionFetchEnabled() ) {
|
errorOrLogForPaginationWithCollectionFetch();
|
||||||
throw new HibernateException(
|
|
||||||
"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();
|
|
||||||
}
|
|
||||||
|
|
||||||
originalQueryOptions = getQueryOptions();
|
originalQueryOptions = getQueryOptions();
|
||||||
normalizedQueryOptions = needsDistinct
|
normalizedQueryOptions = needsDistinct
|
||||||
|
@ -627,52 +622,6 @@ public class QuerySqmImpl<R>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SelectQueryPlan<R> buildSelectQueryPlan() {
|
|
||||||
final SqmSelectStatement<R>[] concreteSqmStatements =
|
|
||||||
QuerySplitter.split( (SqmSelectStatement<R>) getSqmStatement() );
|
|
||||||
|
|
||||||
if ( concreteSqmStatements.length > 1 ) {
|
|
||||||
return buildAggregatedSelectQueryPlan( concreteSqmStatements );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return buildConcreteSelectQueryPlan( concreteSqmStatements[0] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private SelectQueryPlan<R> buildAggregatedSelectQueryPlan(SqmSelectStatement<R>[] concreteSqmStatements) {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
final SelectQueryPlan<R>[] aggregatedQueryPlans = new SelectQueryPlan[ concreteSqmStatements.length ];
|
|
||||||
// todo (6.0) : we want to make sure that certain thing (ResultListTransformer, etc) only get applied at the aggregator-level
|
|
||||||
for ( int i = 0, x = concreteSqmStatements.length; i < x; i++ ) {
|
|
||||||
aggregatedQueryPlans[i] = buildConcreteSelectQueryPlan( concreteSqmStatements[i] );
|
|
||||||
}
|
|
||||||
return new AggregatedSelectQueryPlanImpl<>( aggregatedQueryPlans );
|
|
||||||
}
|
|
||||||
|
|
||||||
private SelectQueryPlan<R> buildConcreteSelectQueryPlan(SqmSelectStatement<R> concreteSqmStatement) {
|
|
||||||
return buildConcreteSelectQueryPlan(
|
|
||||||
concreteSqmStatement,
|
|
||||||
getResultType(),
|
|
||||||
tupleMetadata,
|
|
||||||
getQueryOptions()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> SelectQueryPlan<T> buildConcreteSelectQueryPlan(
|
|
||||||
SqmSelectStatement<T> concreteSqmStatement,
|
|
||||||
Class<T> resultType,
|
|
||||||
TupleMetadata tupleMetadata,
|
|
||||||
QueryOptions queryOptions) {
|
|
||||||
return new ConcreteSqmSelectQueryPlan<>(
|
|
||||||
concreteSqmStatement,
|
|
||||||
getQueryString(),
|
|
||||||
getDomainParameterXref(),
|
|
||||||
resultType,
|
|
||||||
tupleMetadata,
|
|
||||||
queryOptions
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Update / delete / insert query execution
|
// Update / delete / insert query execution
|
||||||
|
@ -721,7 +670,7 @@ public class QuerySqmImpl<R>
|
||||||
|
|
||||||
final QueryInterpretationCache.Key cacheKey = generateNonSelectKey( this );
|
final QueryInterpretationCache.Key cacheKey = generateNonSelectKey( this );
|
||||||
final QueryInterpretationCache interpretationCache =
|
final QueryInterpretationCache interpretationCache =
|
||||||
getSession().getFactory().getQueryEngine().getInterpretationCache();
|
getSessionFactory().getQueryEngine().getInterpretationCache();
|
||||||
if ( cacheKey != null ) {
|
if ( cacheKey != null ) {
|
||||||
queryPlan = interpretationCache.getNonSelectQueryPlan( cacheKey );
|
queryPlan = interpretationCache.getNonSelectQueryPlan( cacheKey );
|
||||||
}
|
}
|
||||||
|
@ -762,7 +711,7 @@ public class QuerySqmImpl<R>
|
||||||
: buildConcreteDeleteQueryPlan( concreteSqmStatements[0] );
|
: buildConcreteDeleteQueryPlan( concreteSqmStatements[0] );
|
||||||
}
|
}
|
||||||
|
|
||||||
private NonSelectQueryPlan buildConcreteDeleteQueryPlan(@SuppressWarnings("rawtypes") SqmDeleteStatement sqmDelete) {
|
private NonSelectQueryPlan buildConcreteDeleteQueryPlan(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 persister = getSessionFactory().getMappingMetamodel().getEntityDescriptor( entityNameToDelete );
|
final EntityPersister persister = getSessionFactory().getMappingMetamodel().getEntityDescriptor( entityNameToDelete );
|
||||||
|
@ -776,13 +725,11 @@ public class QuerySqmImpl<R>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private NonSelectQueryPlan buildAggregatedDeleteQueryPlan(@SuppressWarnings("rawtypes") SqmDeleteStatement[] concreteSqmStatements) {
|
private NonSelectQueryPlan buildAggregatedDeleteQueryPlan(SqmDeleteStatement<?>[] concreteSqmStatements) {
|
||||||
final NonSelectQueryPlan[] aggregatedQueryPlans = new NonSelectQueryPlan[ concreteSqmStatements.length ];
|
final NonSelectQueryPlan[] aggregatedQueryPlans = new NonSelectQueryPlan[ concreteSqmStatements.length ];
|
||||||
|
|
||||||
for ( int i = 0, x = concreteSqmStatements.length; i < x; i++ ) {
|
for ( int i = 0, x = concreteSqmStatements.length; i < x; i++ ) {
|
||||||
aggregatedQueryPlans[i] = buildConcreteDeleteQueryPlan( concreteSqmStatements[i] );
|
aggregatedQueryPlans[i] = buildConcreteDeleteQueryPlan( concreteSqmStatements[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AggregatedNonSelectQueryPlanImpl( aggregatedQueryPlans );
|
return new AggregatedNonSelectQueryPlanImpl( aggregatedQueryPlans );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,8 @@ import jakarta.persistence.TemporalType;
|
||||||
|
|
||||||
import org.hibernate.CacheMode;
|
import org.hibernate.CacheMode;
|
||||||
import org.hibernate.FlushMode;
|
import org.hibernate.FlushMode;
|
||||||
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.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.graph.spi.AppliedGraph;
|
import org.hibernate.graph.spi.AppliedGraph;
|
||||||
|
@ -35,16 +33,13 @@ import org.hibernate.internal.util.collections.IdentitySet;
|
||||||
import org.hibernate.query.BindableType;
|
import org.hibernate.query.BindableType;
|
||||||
import org.hibernate.query.Order;
|
import org.hibernate.query.Order;
|
||||||
import org.hibernate.query.Page;
|
import org.hibernate.query.Page;
|
||||||
import org.hibernate.query.QueryLogging;
|
|
||||||
import org.hibernate.query.QueryParameter;
|
import org.hibernate.query.QueryParameter;
|
||||||
import org.hibernate.query.SelectionQuery;
|
import org.hibernate.query.SelectionQuery;
|
||||||
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;
|
||||||
import org.hibernate.query.hql.internal.QuerySplitter;
|
|
||||||
import org.hibernate.query.internal.DelegatingDomainQueryExecutionContext;
|
import org.hibernate.query.internal.DelegatingDomainQueryExecutionContext;
|
||||||
import org.hibernate.query.internal.ParameterMetadataImpl;
|
import org.hibernate.query.internal.ParameterMetadataImpl;
|
||||||
import org.hibernate.query.internal.QueryParameterBindingsImpl;
|
import org.hibernate.query.internal.QueryParameterBindingsImpl;
|
||||||
import org.hibernate.query.spi.AbstractSelectionQuery;
|
|
||||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||||
import org.hibernate.query.spi.HqlInterpretation;
|
import org.hibernate.query.spi.HqlInterpretation;
|
||||||
import org.hibernate.query.spi.MutableQueryOptions;
|
import org.hibernate.query.spi.MutableQueryOptions;
|
||||||
|
@ -87,7 +82,7 @@ import static org.hibernate.query.sqm.internal.SqmUtil.sortSpecification;
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R>
|
public class SqmSelectionQueryImpl<R> extends AbstractSqmSelectionQuery<R>
|
||||||
implements SqmSelectionQueryImplementor<R>, InterpretationsKeySource {
|
implements SqmSelectionQueryImplementor<R>, InterpretationsKeySource {
|
||||||
private final String hql;
|
private final String hql;
|
||||||
private SqmSelectStatement<R> sqm;
|
private SqmSelectStatement<R> sqm;
|
||||||
|
@ -240,6 +235,7 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TupleMetadata getTupleMetadata() {
|
public TupleMetadata getTupleMetadata() {
|
||||||
return tupleMetadata;
|
return tupleMetadata;
|
||||||
}
|
}
|
||||||
|
@ -249,6 +245,7 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R>
|
||||||
return sqm;
|
return sqm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DomainParameterXref getDomainParameterXref() {
|
public DomainParameterXref getDomainParameterXref() {
|
||||||
return domainParameterXref;
|
return domainParameterXref;
|
||||||
}
|
}
|
||||||
|
@ -328,33 +325,51 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R>
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<R> doList() {
|
protected List<R> doList() {
|
||||||
final SqmSelectStatement<?> sqmStatement = getSqmStatement();
|
final SqmSelectStatement<?> statement = getSqmStatement();
|
||||||
final boolean containsCollectionFetches = sqmStatement.containsCollectionFetches();
|
final boolean containsCollectionFetches =
|
||||||
final boolean hasLimit = hasLimit( sqmStatement, getQueryOptions() );
|
//TODO: why is this different from QuerySqmImpl.doList()?
|
||||||
final boolean needsDistinct = containsCollectionFetches
|
statement.containsCollectionFetches();
|
||||||
&& ( sqmStatement.usesDistinct() || hasAppliedGraph( getQueryOptions() ) || hasLimit );
|
final boolean hasLimit = hasLimit( statement, getQueryOptions() );
|
||||||
|
final boolean needsDistinct = needsDistinct( containsCollectionFetches, hasLimit, statement );
|
||||||
|
final List<R> list = resolveQueryPlan()
|
||||||
|
.performList( executionContext( hasLimit, containsCollectionFetches ) );
|
||||||
|
return needsDistinct ? handleDistinct( hasLimit, statement, list ) : list;
|
||||||
|
}
|
||||||
|
|
||||||
final DomainQueryExecutionContext executionContextToUse;
|
private List<R> handleDistinct(boolean hasLimit, SqmSelectStatement<?> statement, List<R> list) {
|
||||||
|
int includedCount = -1;
|
||||||
|
// NOTE: 'firstRow' is zero-based
|
||||||
|
final int first = first( hasLimit, statement );
|
||||||
|
final int max = max( hasLimit, statement, list );
|
||||||
|
final List<R> distinctList = new ArrayList<>( list.size() );
|
||||||
|
final IdentitySet<Object> distinction = new IdentitySet<>( list.size() );
|
||||||
|
for ( final R result : list) {
|
||||||
|
if ( distinction.add( result ) ) {
|
||||||
|
includedCount++;
|
||||||
|
if ( includedCount >= first ) {
|
||||||
|
distinctList.add( result );
|
||||||
|
// NOTE: 'max-1' because 'first' is zero-based while 'max' is not
|
||||||
|
if ( max >= 0 && includedCount - first >= max - 1 ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return distinctList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: very similar to QuerySqmImpl.executionContextForDoList()
|
||||||
|
private DomainQueryExecutionContext executionContext(boolean hasLimit, boolean containsCollectionFetches) {
|
||||||
if ( hasLimit && containsCollectionFetches ) {
|
if ( hasLimit && containsCollectionFetches ) {
|
||||||
if ( getSessionFactory().getSessionFactoryOptions().isFailOnPaginationOverCollectionFetchEnabled() ) {
|
errorOrLogForPaginationWithCollectionFetch();
|
||||||
throw new HibernateException(
|
|
||||||
"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 MutableQueryOptions originalQueryOptions = getQueryOptions();
|
||||||
final QueryOptions normalizedQueryOptions = omitSqlQueryOptions( originalQueryOptions, true, false );
|
final QueryOptions normalizedQueryOptions = omitSqlQueryOptions( originalQueryOptions, true, false );
|
||||||
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;
|
||||||
|
@ -363,39 +378,8 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
executionContextToUse = this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<R> list = resolveQueryPlan().performList( executionContextToUse );
|
|
||||||
|
|
||||||
if ( needsDistinct ) {
|
|
||||||
int includedCount = -1;
|
|
||||||
// NOTE : firstRow is zero-based
|
|
||||||
final int first = !hasLimit || getQueryOptions().getLimit().getFirstRow() == null
|
|
||||||
? getIntegerLiteral( sqmStatement.getOffset(), 0 )
|
|
||||||
: getQueryOptions().getLimit().getFirstRow();
|
|
||||||
final int max = !hasLimit || getQueryOptions().getLimit().getMaxRows() == null
|
|
||||||
? getMaxRows( sqmStatement, list.size() )
|
|
||||||
: getQueryOptions().getLimit().getMaxRows();
|
|
||||||
final List<R> tmp = new ArrayList<>( list.size() );
|
|
||||||
final IdentitySet<Object> distinction = new IdentitySet<>( list.size() );
|
|
||||||
for ( final R result : list ) {
|
|
||||||
if ( !distinction.add( result ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
includedCount++;
|
|
||||||
if ( includedCount < first ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
tmp.add( result );
|
|
||||||
// NOTE : ( max - 1 ) because first is zero-based while max is not...
|
|
||||||
if ( max >= 0 && includedCount - first >= max - 1 ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -408,58 +392,25 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R>
|
||||||
return resolveQueryPlan().executeQuery( this, resultsConsumer );
|
return resolveQueryPlan().executeQuery( this, resultsConsumer );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<R> getExpectedResultType() {
|
||||||
|
return expectedResultType;
|
||||||
|
}
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Query plan
|
// Query plan
|
||||||
|
|
||||||
private SelectQueryPlan<R> resolveQueryPlan() {
|
private SelectQueryPlan<R> resolveQueryPlan() {
|
||||||
final QueryInterpretationCache.Key cacheKey = createInterpretationsKey( this );
|
final QueryInterpretationCache.Key cacheKey = createInterpretationsKey( this );
|
||||||
if ( cacheKey != null ) {
|
if ( cacheKey != null ) {
|
||||||
return getSession().getFactory().getQueryEngine().getInterpretationCache()
|
return getSessionFactory().getQueryEngine().getInterpretationCache()
|
||||||
.resolveSelectQueryPlan( cacheKey, this::buildQueryPlan );
|
.resolveSelectQueryPlan( cacheKey, this::buildSelectQueryPlan );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return buildQueryPlan();
|
return buildSelectQueryPlan();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SelectQueryPlan<R> buildQueryPlan() {
|
|
||||||
final SqmSelectStatement<R>[] concreteSqmStatements = QuerySplitter.split( getSqmStatement() );
|
|
||||||
return concreteSqmStatements.length > 1
|
|
||||||
? buildAggregatedQueryPlan( concreteSqmStatements )
|
|
||||||
: buildConcreteQueryPlan( concreteSqmStatements[0], getQueryOptions() );
|
|
||||||
}
|
|
||||||
|
|
||||||
private SelectQueryPlan<R> buildAggregatedQueryPlan(SqmSelectStatement<R>[] concreteSqmStatements) {
|
|
||||||
//noinspection unchecked
|
|
||||||
final SelectQueryPlan<R>[] aggregatedQueryPlans = new SelectQueryPlan[ concreteSqmStatements.length ];
|
|
||||||
// todo (6.0) : we want to make sure that certain thing (ResultListTransformer, etc) only get applied at the aggregator-level
|
|
||||||
for ( int i = 0, x = concreteSqmStatements.length; i < x; i++ ) {
|
|
||||||
aggregatedQueryPlans[i] = buildConcreteQueryPlan( concreteSqmStatements[i], getQueryOptions() );
|
|
||||||
}
|
|
||||||
return new AggregatedSelectQueryPlanImpl<>( aggregatedQueryPlans );
|
|
||||||
}
|
|
||||||
|
|
||||||
private SelectQueryPlan<R> buildConcreteQueryPlan(
|
|
||||||
SqmSelectStatement<R> concreteSqmStatement,
|
|
||||||
QueryOptions queryOptions) {
|
|
||||||
return buildConcreteQueryPlan( concreteSqmStatement, expectedResultType, tupleMetadata, queryOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> ConcreteSqmSelectQueryPlan<T> buildConcreteQueryPlan(
|
|
||||||
SqmSelectStatement<T> concreteSqmStatement,
|
|
||||||
Class<T> expectedResultType,
|
|
||||||
TupleMetadata tupleMetadata,
|
|
||||||
QueryOptions queryOptions) {
|
|
||||||
return new ConcreteSqmSelectQueryPlan<>(
|
|
||||||
concreteSqmStatement,
|
|
||||||
getQueryString(),
|
|
||||||
getDomainParameterXref(),
|
|
||||||
expectedResultType,
|
|
||||||
tupleMetadata,
|
|
||||||
queryOptions
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// InterpretationsKeySource
|
// InterpretationsKeySource
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
package org.hibernate.sql.results.internal;
|
package org.hibernate.sql.results.internal;
|
||||||
|
|
||||||
import org.hibernate.TypeMismatchException;
|
import org.hibernate.query.QueryTypeMismatchException;
|
||||||
import org.hibernate.sql.results.spi.RowTransformer;
|
import org.hibernate.sql.results.spi.RowTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,7 +29,7 @@ public class RowTransformerCheckingImpl<R> implements RowTransformer<R> {
|
||||||
return (R) result;
|
return (R) result;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new TypeMismatchException( "Result type is '" + type.getSimpleName()
|
throw new QueryTypeMismatchException( "Result type is '" + type.getSimpleName()
|
||||||
+ "' but the query returned a '" + result.getClass().getSimpleName() + "'" );
|
+ "' but the query returned a '" + result.getClass().getSimpleName() + "'" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue