HHH-16651 introduce new setting to globally enable the use of subselect fetching

and lay foundation for making this settable on the Session
This commit is contained in:
Gavin 2023-05-21 00:40:18 +02:00 committed by Gavin King
parent 2b0bc61873
commit eb959722f9
26 changed files with 199 additions and 107 deletions

View File

@ -46,7 +46,7 @@ public class CockroachLegacySqlAstTranslator<T extends JdbcOperation> extends Ab
else {
final boolean isNegated = booleanExpressionPredicate.isNegated();
if ( isNegated ) {
appendSql( "not(" );
appendSql( "not (" );
}
booleanExpressionPredicate.getExpression().accept( this );
if ( isNegated ) {
@ -188,7 +188,7 @@ public class CockroachLegacySqlAstTranslator<T extends JdbcOperation> extends Ab
@Override
public void visitInArrayPredicate(InArrayPredicate inArrayPredicate) {
inArrayPredicate.getTestExpression().accept( this );
appendSql( " = ANY(" );
appendSql( " = any(" );
inArrayPredicate.getArrayParameter().accept( this );
appendSql( ')' );
}

View File

@ -124,6 +124,7 @@ import static org.hibernate.cfg.AvailableSettings.USE_SCROLLABLE_RESULTSET;
import static org.hibernate.cfg.AvailableSettings.USE_SECOND_LEVEL_CACHE;
import static org.hibernate.cfg.AvailableSettings.USE_SQL_COMMENTS;
import static org.hibernate.cfg.AvailableSettings.USE_STRUCTURED_CACHE;
import static org.hibernate.cfg.AvailableSettings.USE_SUBSELECT_FETCH;
import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN;
import static org.hibernate.internal.CoreLogging.messageLogger;
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
@ -194,6 +195,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
private boolean delayBatchFetchLoaderCreations;
private int defaultBatchFetchSize;
private Integer maximumFetchDepth;
private boolean subselectFetchEnabled;
private NullPrecedence defaultNullPrecedence;
private boolean orderUpdatesEnabled;
private boolean orderInsertsEnabled;
@ -361,6 +363,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
this.batchFetchStyle = BatchFetchStyle.interpret( configurationSettings.get( BATCH_FETCH_STYLE ) );
this.delayBatchFetchLoaderCreations = configurationService.getSetting( DELAY_ENTITY_LOADER_CREATIONS, BOOLEAN, true );
this.defaultBatchFetchSize = getInt( DEFAULT_BATCH_FETCH_SIZE, configurationSettings, -1 );
this.subselectFetchEnabled = getBoolean( USE_SUBSELECT_FETCH, configurationSettings );
this.maximumFetchDepth = getInteger( MAX_FETCH_DEPTH, configurationSettings );
final String defaultNullPrecedence = getString(
AvailableSettings.DEFAULT_NULL_ORDERING, configurationSettings, "none", "first", "last"
@ -972,6 +975,11 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
return maximumFetchDepth;
}
@Override
public boolean isSubselectFetchEnabled() {
return subselectFetchEnabled;
}
@Override
public NullPrecedence getDefaultNullPrecedence() {
return defaultNullPrecedence;
@ -1342,6 +1350,10 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
this.maximumFetchDepth = depth;
}
public void applySubselectFetchEnabled(boolean subselectFetchEnabled) {
this.subselectFetchEnabled = subselectFetchEnabled;
}
public void applyDefaultNullPrecedence(NullPrecedence nullPrecedence) {
this.defaultNullPrecedence = nullPrecedence;
}

View File

@ -187,6 +187,11 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
return delegate.getMaximumFetchDepth();
}
@Override
public boolean isSubselectFetchEnabled() {
return delegate.isSubselectFetchEnabled();
}
@Override
public NullPrecedence getDefaultNullPrecedence() {
return delegate.getDefaultNullPrecedence();

View File

@ -144,6 +144,8 @@ public interface SessionFactoryOptions extends QueryEngineOptions {
Integer getMaximumFetchDepth();
boolean isSubselectFetchEnabled();
NullPrecedence getDefaultNullPrecedence();
boolean isOrderUpdatesEnabled();

View File

@ -1032,6 +1032,17 @@ public interface AvailableSettings {
*/
String DEFAULT_BATCH_FETCH_SIZE = "hibernate.default_batch_fetch_size";
/**
* When enabled, Hibernate will use subselect fetching, when possible, to
* fetch any collection.
* <p>
* By default, Hibernate only uses subselect fetching for collections
* explicitly annotated {@code @Fetch(SUBSELECT)}.
*
* @see org.hibernate.annotations.FetchMode#SUBSELECT
*/
String USE_SUBSELECT_FETCH = "hibernate.use_subselect_fetch";
/**
* When enabled, specifies that JDBC scrollable {@code ResultSet}s may be used.
* This property is only necessary when there is no {@code ConnectionProvider},

View File

@ -46,7 +46,7 @@ public class CockroachSqlAstTranslator<T extends JdbcOperation> extends Abstract
else {
final boolean isNegated = booleanExpressionPredicate.isNegated();
if ( isNegated ) {
appendSql( "not(" );
appendSql( "not (" );
}
booleanExpressionPredicate.getExpression().accept( this );
if ( isNegated ) {
@ -160,7 +160,7 @@ public class CockroachSqlAstTranslator<T extends JdbcOperation> extends Abstract
@Override
public void visitInArrayPredicate(InArrayPredicate inArrayPredicate) {
inArrayPredicate.getTestExpression().accept( this );
appendSql( " = ANY(" );
appendSql( " = any(" );
inArrayPredicate.getArrayParameter().accept( this );
appendSql( ')' );
}

View File

@ -208,7 +208,7 @@ public class DerbySqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
if ( inListPredicate.isNegated() ) {
appendSql( " not" );
}
appendSql( " in(" );
appendSql( " in (" );
renderCommaSeparated( listExpressions );
appendSql( CLOSE_PARENTHESIS );
}

View File

@ -868,7 +868,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
public void addUninitializedCollection(CollectionPersister persister, PersistentCollection<?> collection, Object id) {
final CollectionEntry ce = new CollectionEntry( collection, persister, id, flushing );
addCollection( collection, ce, id );
if ( persister.getBatchSize() > 1 ) {
if ( session.getLoadQueryInfluencers().effectiveBatchSize( persister ) > 1 ) {
getBatchFetchQueue().addBatchLoadableCollection( collection, ce );
}
}
@ -877,7 +877,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
public void addUninitializedDetachedCollection(CollectionPersister persister, PersistentCollection<?> collection) {
final CollectionEntry ce = new CollectionEntry( persister, collection.getKey() );
addCollection( collection, ce, collection.getKey() );
if ( persister.getBatchSize() > 1 ) {
if ( session.getLoadQueryInfluencers().effectiveBatchSize( persister ) > 1 ) {
getBatchFetchQueue().addBatchLoadableCollection( collection, ce );
}
}

View File

@ -6,12 +6,6 @@
*/
package org.hibernate.engine.spi;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Collection;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.collection.spi.AbstractPersistentCollection;
@ -21,6 +15,12 @@ import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.pretty.MessageHelper;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Collection;
/**
* We need an entry to tell us all about the current state
* of a collection with respect to its persistent state
@ -202,10 +202,10 @@ public final class CollectionEntry implements Serializable {
snapshot = loadedPersister.isMutable()
? collection.getSnapshot( loadedPersister )
: null;
collection.setSnapshot(loadedKey, role, snapshot);
if ( loadedPersister.getBatchSize() > 1 ) {
( (AbstractPersistentCollection<?>) collection ).getSession()
.getPersistenceContextInternal()
collection.setSnapshot( loadedKey, role, snapshot );
final SharedSessionContractImplementor session = ((AbstractPersistentCollection<?>) collection).getSession();
if ( session.getLoadQueryInfluencers().effectiveBatchSize( loadedPersister ) > 1 ) {
session.getPersistenceContextInternal()
.getBatchFetchQueue()
.removeBatchLoadableCollection( this );
}

View File

@ -19,6 +19,7 @@ import org.hibernate.Filter;
import org.hibernate.UnknownProfileException;
import org.hibernate.internal.FilterImpl;
import org.hibernate.loader.ast.spi.CascadingFetchProfile;
import org.hibernate.persister.collection.CollectionPersister;
/**
* Centralize all options which can influence the SQL query needed to load an
@ -48,6 +49,10 @@ public class LoadQueryInfluencers implements Serializable {
//Lazily initialized!
private HashMap<String,Filter> enabledFilters;
private Boolean subselectFetchEnabled;
private Integer batchSize;
private final EffectiveEntityGraph effectiveEntityGraph = new EffectiveEntityGraph();
private Boolean readOnly;
@ -57,7 +62,7 @@ public class LoadQueryInfluencers implements Serializable {
}
public LoadQueryInfluencers(SessionFactoryImplementor sessionFactory) {
this(sessionFactory, null);
this( sessionFactory, null );
}
public LoadQueryInfluencers(SessionFactoryImplementor sessionFactory, Boolean readOnly) {
@ -73,13 +78,13 @@ public class LoadQueryInfluencers implements Serializable {
// internal fetch profile support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public <T> T fromInternalFetchProfile(CascadingFetchProfile profile, Supplier<T> supplier) {
final CascadingFetchProfile previous = this.enabledCascadingFetchProfile;
this.enabledCascadingFetchProfile = profile;
final CascadingFetchProfile previous = enabledCascadingFetchProfile;
enabledCascadingFetchProfile = profile;
try {
return supplier.get();
}
finally {
this.enabledCascadingFetchProfile = previous;
enabledCascadingFetchProfile = previous;
}
}
@ -250,6 +255,30 @@ public class LoadQueryInfluencers implements Serializable {
this.readOnly = readOnly;
}
public Integer getBatchSize() {
return batchSize;
}
public void setBatchSize(Integer batchSize) {
this.batchSize = batchSize;
}
public int effectiveBatchSize(CollectionPersister persister) {
return batchSize != null ? batchSize : persister.getBatchSize();
}
public Boolean getSubselectFetchEnabled() {
return subselectFetchEnabled;
}
public void setSubselectFetchEnabled(Boolean subselectFetchEnabled) {
this.subselectFetchEnabled = subselectFetchEnabled;
}
public boolean effectiveSubselectFetchEnabled(CollectionPersister persister) {
return subselectFetchEnabled != null ? subselectFetchEnabled : persister.isSubselectLoadable();
}
private void checkMutability() {
if ( sessionFactory == null ) {
// that's the signal that this is the immutable, context-less

View File

@ -12,6 +12,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.from.TableGroup;
@ -149,11 +150,13 @@ public class SubselectFetch {
}
public void addKey(EntityKey key, LoadingEntityEntry entry) {
if ( !entry.getDescriptor().hasSubselectLoadableCollections() ) {
return;
}
if ( shouldAddSubselectFetch( entry ) ) {
final EntityPersister persister = entry.getDescriptor();
boolean subselectsPossible =
persister.hasCollections()
&& persister.getFactory().getSessionFactoryOptions().isSubselectFetchEnabled()
|| persister.hasSubselectLoadableCollections();
if ( subselectsPossible && shouldAddSubselectFetch( entry ) ) {
final SubselectFetch subselectFetch = subselectFetches.computeIfAbsent(
entry.getEntityInitializer().getNavigablePath(),
navigablePath -> new SubselectFetch(

View File

@ -15,9 +15,11 @@ import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.event.spi.EventSource;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.type.CollectionType;
import static org.hibernate.pretty.MessageHelper.collectionInfoString;
/**
* Evict any collections referenced by the object from the session cache.
* This will NOT pick up any collections that were dereferenced, so they
@ -37,8 +39,8 @@ public class EvictVisitor extends AbstractVisitor {
@Override
Object processCollection(Object collection, CollectionType type) throws HibernateException {
if (collection != null) {
evictCollection(collection, type);
if ( collection != null ) {
evictCollection( collection, type );
}
return null;
@ -55,34 +57,37 @@ public class EvictVisitor extends AbstractVisitor {
}
else if ( value == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
final Object keyOfOwner = type.getKeyOfOwner( owner, session );
collection = (PersistentCollection<?>) type.getCollection( keyOfOwner, session, owner, Boolean.FALSE );
collection = (PersistentCollection<?>) type.getCollection( keyOfOwner, session, owner, false );
}
else {
return; //EARLY EXIT!
}
if ( collection != null && collection.unsetSession(session) ) {
evictCollection(collection);
if ( collection != null && collection.unsetSession( session ) ) {
evictCollection( collection );
}
}
private void evictCollection(PersistentCollection<?> collection) {
final PersistenceContext persistenceContext = getSession().getPersistenceContextInternal();
CollectionEntry ce = persistenceContext.removeCollectionEntry( collection );
final EventSource session = getSession();
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final CollectionEntry ce = persistenceContext.removeCollectionEntry( collection );
final CollectionPersister persister = ce.getLoadedPersister();
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Evicting collection: %s",
MessageHelper.collectionInfoString( ce.getLoadedPersister(),
collection,
ce.getLoadedKey(),
getSession() ) );
collectionInfoString( persister, collection, ce.getLoadedKey(), session )
);
}
if (ce.getLoadedPersister() != null && ce.getLoadedPersister().getBatchSize() > 1) {
persistenceContext.getBatchFetchQueue().removeBatchLoadableCollection(ce);
if ( persister != null
&& session.getLoadQueryInfluencers().effectiveBatchSize(persister) > 1 ) {
persistenceContext.getBatchFetchQueue().removeBatchLoadableCollection( ce );
}
if ( ce.getLoadedPersister() != null && ce.getLoadedKey() != null ) {
if ( persister != null && ce.getLoadedKey() != null ) {
//TODO: is this 100% correct?
persistenceContext.removeCollectionByKey( new CollectionKey( ce.getLoadedPersister(), ce.getLoadedKey() ) );
persistenceContext.removeCollectionByKey( new CollectionKey( persister, ce.getLoadedKey() ) );
}
}

View File

@ -265,9 +265,9 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public Integer getConfiguredJdbcBatchSize() {
final Integer sessionJdbcBatchSize = jdbcBatchSize;
return sessionJdbcBatchSize == null ?
fastSessionServices.defaultJdbcBatchSize :
sessionJdbcBatchSize;
return sessionJdbcBatchSize == null
? fastSessionServices.defaultJdbcBatchSize
: sessionJdbcBatchSize;
}
protected void addSharedSessionTransactionObserver(TransactionCoordinator transactionCoordinator) {

View File

@ -1932,6 +1932,22 @@ public class SessionImpl
loadQueryInfluencers.disableFetchProfile( name );
}
public void setSubselectFetchingEnabled(boolean enabled) {
loadQueryInfluencers.setSubselectFetchEnabled( enabled );
}
public boolean isSubselectFetchingEnabled() {
return loadQueryInfluencers.getSubselectFetchEnabled();
}
public void setFetchBatchSize(int batchSize) {
loadQueryInfluencers.setBatchSize( batchSize );
}
public int getFetchBatchSize() {
return loadQueryInfluencers.getBatchSize();
}
@Override
public LobHelper getLobHelper() {
if ( lobHelper == null ) {

View File

@ -34,7 +34,7 @@ import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
import org.hibernate.sql.results.spi.ListResultsConsumer;
/**
* A one-time use CollectionLoader for applying a sub-select fetch
* A one-time use {@link CollectionLoader} for applying a subselect fetch.
*
* @author Steve Ebersole
*/

View File

@ -252,7 +252,10 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
.translate( jdbcParameterBindings, QueryOptions.NONE );
final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler;
if ( getLoadable().getEntityPersister().hasSubselectLoadableCollections() ) {
final EntityPersister persister = getLoadable().getEntityPersister();
if ( persister.hasCollections()
&& session.getSessionFactory().getSessionFactoryOptions().isSubselectFetchEnabled()
|| persister.hasSubselectLoadableCollections() ) {
subSelectFetchableKeysHandler = SubselectFetch.createRegistrationHandler(
session.getPersistenceContext().getBatchFetchQueue(),
sqlAst,

View File

@ -20,6 +20,7 @@ import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.loader.ast.spi.MultiNaturalIdLoadOptions;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
@ -138,7 +139,10 @@ public class MultiNaturalIdLoadingBatcher {
private <E> List<E> performLoad(JdbcParameterBindings jdbcParamBindings, SharedSessionContractImplementor session) {
final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler;
if ( entityDescriptor.getEntityPersister().hasSubselectLoadableCollections() ) {
final EntityPersister persister = entityDescriptor.getEntityPersister();
if ( persister.hasCollections()
&& session.getSessionFactory().getSessionFactoryOptions().isSubselectFetchEnabled()
|| persister.hasSubselectLoadableCollections() ) {
subSelectFetchableKeysHandler = SubselectFetch.createRegistrationHandler(
session.getPersistenceContext().getBatchFetchQueue(),
sqlSelect,

View File

@ -61,9 +61,9 @@ public final class FetchOptionsHelper {
}
}
else {
CollectionPersister persister = (CollectionPersister) type.getAssociatedJoinable( sessionFactory );
final CollectionPersister persister = (CollectionPersister) type.getAssociatedJoinable( sessionFactory );
if ( persister instanceof AbstractCollectionPersister
&& ( (AbstractCollectionPersister) persister ).isSubselectLoadable() ) {
&& persister.isSubselectLoadable() ) {
return FetchStyle.SUBSELECT;
}
else if ( persister.getBatchSize() > 0 ) {

View File

@ -42,7 +42,6 @@ import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.profile.Fetch;
import org.hibernate.engine.profile.internal.FetchProfileAffectee;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
@ -281,7 +280,8 @@ public abstract class AbstractCollectionPersister
// isSet = collectionBinding.isSet();
// isSorted = collectionBinding.isSorted();
isPrimitiveArray = collectionBootDescriptor.isPrimitiveArray();
subselectLoadable = collectionBootDescriptor.isSubselectLoadable();
subselectLoadable = collectionBootDescriptor.isSubselectLoadable()
|| factory.getSessionFactoryOptions().isSubselectFetchEnabled();
qualifiedTableName = determineTableName( table );
@ -705,48 +705,47 @@ public abstract class AbstractCollectionPersister
// if there is a user-specified loader, return that
return getStandardCollectionLoader();
}
final LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers();
final CollectionLoader subSelectLoader = resolveSubSelectLoader( key, session );
if ( subSelectLoader != null ) {
return subSelectLoader;
if ( loadQueryInfluencers.effectiveSubselectFetchEnabled( this ) ) {
final CollectionLoader subSelectLoader = resolveSubSelectLoader( key, session );
if ( subSelectLoader != null ) {
return subSelectLoader;
}
}
if ( ! session.getLoadQueryInfluencers().hasEnabledFilters() && ! isAffectedByEnabledFetchProfiles( session.getLoadQueryInfluencers() ) ) {
if ( !loadQueryInfluencers.hasEnabledFilters()
&& !isAffectedByEnabledFetchProfiles( loadQueryInfluencers ) ) {
return getStandardCollectionLoader();
}
return createCollectionLoader( session.getLoadQueryInfluencers() );
else {
return createCollectionLoader( loadQueryInfluencers );
}
}
private CollectionLoader resolveSubSelectLoader(Object key, SharedSessionContractImplementor session) {
if ( !isSubselectLoadable() ) {
return null;
}
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final EntityKey ownerEntityKey = session.generateEntityKey( key, getOwnerEntityPersister() );
final SubselectFetch subselect = persistenceContext.getBatchFetchQueue().getSubselect( ownerEntityKey );
final SubselectFetch subselect =
persistenceContext.getBatchFetchQueue()
.getSubselect( session.generateEntityKey( key, getOwnerEntityPersister() ) );
if ( subselect == null ) {
return null;
}
else {
// Take care of any entities that might have
// been evicted!
subselect.getResultingEntityKeys()
.removeIf( entityKey -> !persistenceContext.containsEntity( entityKey ) );
// Take care of any entities that might have
// been evicted!
subselect.getResultingEntityKeys().removeIf( o -> !persistenceContext.containsEntity( o ) );
// Run a subquery loader
return createSubSelectLoader( subselect, session );
// Run a subquery loader
return createSubSelectLoader( subselect, session );
}
}
protected CollectionLoader createSubSelectLoader(SubselectFetch subselect, SharedSessionContractImplementor session) {
//noinspection RedundantCast
return new CollectionLoaderSubSelectFetch(
attributeMapping,
(DomainResult<?>) null,
subselect,
session
);
return new CollectionLoaderSubSelectFetch( attributeMapping, (DomainResult<?>) null, subselect, session );
}
private CollectionLoader reusableCollectionLoader;
@ -758,9 +757,10 @@ public abstract class AbstractCollectionPersister
}
return reusableCollectionLoader;
}
// create a one-off
return generateCollectionLoader( loadQueryInfluencers );
else {
// create a one-off
return generateCollectionLoader( loadQueryInfluencers );
}
}
private boolean canUseReusableCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
@ -769,13 +769,15 @@ public abstract class AbstractCollectionPersister
}
private CollectionLoader generateCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
final int batchSize = getBatchSize();
final int batchSize = loadQueryInfluencers.effectiveBatchSize( this );
if ( batchSize > 1 ) {
return getFactory().getServiceRegistry()
.getService( BatchLoaderFactory.class )
.createCollectionBatchLoader( batchSize, loadQueryInfluencers, attributeMapping, getFactory() );
}
return new CollectionLoaderSingleKey( attributeMapping, loadQueryInfluencers, getFactory() );
else {
return new CollectionLoaderSingleKey( attributeMapping, loadQueryInfluencers, getFactory() );
}
}
@Override
@ -1371,6 +1373,7 @@ public abstract class AbstractCollectionPersister
return isAffectedByEnabledFilters( session.getLoadQueryInfluencers() );
}
@Override
public boolean isSubselectLoadable() {
return subselectLoadable;
}

View File

@ -302,12 +302,19 @@ public interface CollectionPersister extends Restrictable {
throw new UnsupportedOperationException( "CollectionPersister used for [" + getRole() + "] does not support SQL AST" );
}
boolean isExtraLazy();
default boolean isExtraLazy() {
return false;
}
int getSize(Object key, SharedSessionContractImplementor session);
boolean indexExists(Object key, Object index, SharedSessionContractImplementor session);
boolean elementExists(Object key, Object element, SharedSessionContractImplementor session);
Object getElementByIndex(Object key, Object index, SharedSessionContractImplementor session, Object owner);
int getBatchSize();
default int getBatchSize() {
return 0;
}
default boolean isSubselectLoadable() {
return false;
}
/**
* @return the name of the property this collection is mapped by

View File

@ -512,7 +512,8 @@ public abstract class AbstractEntityPersister
batch = creationContext.getSessionFactoryOptions().getDefaultBatchFetchSize();
}
batchSize = batch;
hasSubselectLoadableCollections = persistentClass.hasSubselectLoadableCollections();
hasSubselectLoadableCollections = persistentClass.hasSubselectLoadableCollections()
|| entityMetamodel.hasCollections() && factory.getSessionFactoryOptions().isSubselectFetchEnabled();
hasPartitionedSelectionMapping = persistentClass.hasPartitionedSelectionMapping();
hasCollectionNotReferencingPK = persistentClass.hasCollectionNotReferencingPK();

View File

@ -6939,7 +6939,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
if ( inSubQueryPredicate.isNegated() ) {
appendSql( " not" );
}
appendSql( " in" );
appendSql( " in " );
inSubQueryPredicate.getSubQuery().accept( this );
}
else if ( !supportsRowValueConstructorSyntaxInInSubQuery() ) {
@ -6957,7 +6957,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
if ( inSubQueryPredicate.isNegated() ) {
appendSql( " not" );
}
appendSql( " in" );
appendSql( " in " );
inSubQueryPredicate.getSubQuery().accept( this );
}
}
@ -6966,7 +6966,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
if ( inSubQueryPredicate.isNegated() ) {
appendSql( " not" );
}
appendSql( " in" );
appendSql( " in " );
inSubQueryPredicate.getSubQuery().accept( this );
}
}

View File

@ -966,10 +966,6 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public boolean isExtraLazy() {
return false; //To change body of implemented methods use File | Settings | File Templates.
}
public int getSize(Object key, SharedSessionContractImplementor session) {
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
@ -986,11 +982,6 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public int getBatchSize() {
return 0;
}
@Override
public String getMappedByProperty() {
return null;

View File

@ -104,7 +104,7 @@ public class DepthOneBatchTest {
);
assertThat( executedQueries.get( 4 ).toLowerCase() ).isEqualTo(
"select u1_0.group_id,u1_1.user_id,a1_0.agency_id,a1_0.agency_txt,u1_1.user_name from group_user u1_0 join user_table u1_1 on u1_1.user_id=u1_0.user_id left join agency_table a1_0 on a1_0.agency_id=u1_1.agency_id where u1_0.group_id in(select g1_0.group_id from group_table g1_0 where g1_0.agency_id=?)"
"select u1_0.group_id,u1_1.user_id,a1_0.agency_id,a1_0.agency_txt,u1_1.user_name from group_user u1_0 join user_table u1_1 on u1_1.user_id=u1_0.user_id left join agency_table a1_0 on a1_0.agency_id=u1_1.agency_id where u1_0.group_id in (select g1_0.group_id from group_table g1_0 where g1_0.agency_id=?)"
);
}

View File

@ -100,7 +100,7 @@ public class DepthOneTest {
);
assertThat( executedQueries.get( 3 ).toLowerCase() ).isEqualTo(
"select u1_0.group_id,u1_1.user_id,a1_0.agency_id,a1_0.agency_txt,u1_1.user_name from group_user u1_0 join user_table u1_1 on u1_1.user_id=u1_0.user_id left join agency_table a1_0 on a1_0.agency_id=u1_1.agency_id where u1_0.group_id in(select g1_0.group_id from group_table g1_0 where g1_0.agency_id=?)"
"select u1_0.group_id,u1_1.user_id,a1_0.agency_id,a1_0.agency_txt,u1_1.user_name from group_user u1_0 join user_table u1_1 on u1_1.user_id=u1_0.user_id left join agency_table a1_0 on a1_0.agency_id=u1_1.agency_id where u1_0.group_id in (select g1_0.group_id from group_table g1_0 where g1_0.agency_id=?)"
);
assertThat( executedQueries.get( 4 ).toLowerCase() ).isEqualTo(

View File

@ -41,7 +41,7 @@ public class CompareEntityValuedPathsTest {
"select " +
"1 " +
"from PERSON_TABLE p1_0 " +
"where p1_0.uk in(" +
"where p1_0.uk in (" +
"select c1_0.child_uk " +
"from children_uks c1_0 " +
"where p1_0.uk=c1_0.owner_uk" +
@ -65,7 +65,7 @@ public class CompareEntityValuedPathsTest {
"select " +
"1 " +
"from PERSON_TABLE p1_0 " +
"where p1_0.id in(" +
"where p1_0.id in (" +
"select c1_0.children_id " +
"from PERSON_TABLE_PERSON_TABLE c1_0 " +
"where p1_0.id=c1_0.Person_id" +
@ -109,7 +109,7 @@ public class CompareEntityValuedPathsTest {
"select " +
"1 " +
"from PERSON_TABLE p1_0 " +
"where p1_0.parent_id in(" +
"where p1_0.parent_id in (" +
"select c1_1.id " +
"from children_uks c1_0 " +
"join PERSON_TABLE c1_1 on c1_1.uk=c1_0.child_uk " +
@ -135,7 +135,7 @@ public class CompareEntityValuedPathsTest {
"1 " +
"from PERSON_TABLE p1_0 " +
"join PERSON_TABLE p2_0 on p2_0.uk=p1_0.parent_uk " +
"where p2_0.id in(" +
"where p2_0.id in (" +
"select c1_0.children_id " +
"from PERSON_TABLE_PERSON_TABLE c1_0 " +
"where p1_0.id=c1_0.Person_id" +
@ -159,7 +159,7 @@ public class CompareEntityValuedPathsTest {
"select " +
"1 " +
"from PERSON_TABLE p1_0 " +
"where p1_0.id in(" +
"where p1_0.id in (" +
"select e1_0.id " +
"from PERSON_TABLE e1_0 " +
"where p1_0.id=e1_0.supervisor_id" +
@ -183,7 +183,7 @@ public class CompareEntityValuedPathsTest {
"select " +
"1 " +
"from PERSON_TABLE p1_0 " +
"where p1_0.id in(" +
"where p1_0.id in (" +
"select e1_0.id " +
"from PERSON_TABLE e1_0 " +
"where p1_0.uk=e1_0.supervisor_uk" +
@ -294,7 +294,7 @@ public class CompareEntityValuedPathsTest {
"1 " +
"from PERSON_TABLE p1_0 " +
"join (children_uks c1_0 join PERSON_TABLE c1_1 on c1_1.uk=c1_0.child_uk) on p1_0.uk=c1_0.owner_uk " +
"where c1_1.id in(select c2_0.children_id from PERSON_TABLE_PERSON_TABLE c2_0 where p1_0.id=c2_0.Person_id)",
"where c1_1.id in (select c2_0.children_id from PERSON_TABLE_PERSON_TABLE c2_0 where p1_0.id=c2_0.Person_id)",
statementInspector.getSqlQueries().get( 0 )
);
}
@ -315,7 +315,7 @@ public class CompareEntityValuedPathsTest {
"1 " +
"from PERSON_TABLE p1_0 " +
"join PERSON_TABLE_PERSON_TABLE c1_0 on p1_0.id=c1_0.Person_id " +
"where c1_0.children_id in(select c2_1.id from children_uks c2_0 join PERSON_TABLE c2_1 on c2_1.uk=c2_0.child_uk where p1_0.uk=c2_0.owner_uk)",
"where c1_0.children_id in (select c2_1.id from children_uks c2_0 join PERSON_TABLE c2_1 on c2_1.uk=c2_0.child_uk where p1_0.uk=c2_0.owner_uk)",
statementInspector.getSqlQueries().get( 0 )
);
}
@ -335,7 +335,7 @@ public class CompareEntityValuedPathsTest {
"select " +
"1 " +
"from PERSON_TABLE p1_0 " +
"where p1_0.uk in(" +
"where p1_0.uk in (" +
"select p2_0.parent_uk " +
"from PERSON_TABLE p2_0" +
")",
@ -358,7 +358,7 @@ public class CompareEntityValuedPathsTest {
"select " +
"1 " +
"from PERSON_TABLE p1_0 " +
"where p1_0.id in(" +
"where p1_0.id in (" +
"select p2_0.parent_id " +
"from PERSON_TABLE p2_0" +
")",