HHH-13763 : Update all load-by-key handling to use SQL AST

* dropped `org.hibernate.loader.plan`
* dropped `org.hibernate.loader.custom` (*)
* dropped `org.hibernate.loader.collection`
* dropped `org.hibernate.loader.entity`
* dropped `org.hibernate.loader.hql`
* cleaned-up `org.hibernate.loader`
This commit is contained in:
Steve Ebersole 2019-12-03 11:31:45 -06:00
parent 10cdb47a97
commit 0a41ac8466
273 changed files with 384 additions and 26241 deletions

View File

@ -18,7 +18,7 @@ import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.dialect.PostgreSQL82Dialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.loader.custom.NonUniqueDiscoveredSqlAliasException;
import org.hibernate.loader.NonUniqueDiscoveredSqlAliasException;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.transform.RootEntityResultTransformer;
import org.hibernate.transform.Transformers;

View File

@ -288,7 +288,10 @@ public interface SessionFactoryBuilder {
* @return {@code this}, for method chaining
*
* @see org.hibernate.cfg.AvailableSettings#BATCH_FETCH_STYLE
*
* @deprecated (since 6.0) : an appropriate style is selected
*/
@Deprecated
SessionFactoryBuilder applyBatchFetchStyle(BatchFetchStyle style);
/**

View File

@ -1291,6 +1291,10 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
this.tempTableDdlTransactionHandling = handling;
}
/**
* @deprecated (since 6.0) : No longer used internally
*/
@Deprecated
public void applyBatchFetchStyle(BatchFetchStyle style) {
this.batchFetchStyle = style;
}

View File

@ -168,6 +168,10 @@ public interface SessionFactoryOptions {
TempTableDdlTransactionHandling getTempTableDdlTransactionHandling();
/**
* @deprecated (since 6.0) : No longer used internally
*/
@Deprecated
BatchFetchStyle getBatchFetchStyle();
boolean isDelayBatchFetchLoaderCreationsEnabled();

View File

@ -1689,7 +1689,10 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings {
* {@link org.hibernate.loader.BatchFetchStyle} instance.
*
* {@code LEGACY} is the default value.
*
* @deprecated (since 6.0) : An appropriate batch-fetch style is selected automatically
*/
@Deprecated
String BATCH_FETCH_STYLE = "hibernate.batch_fetch_style";
/**

View File

@ -169,6 +169,10 @@ public final class Settings {
return sessionFactoryOptions.isInitializeLazyStateOutsideTransactionsEnabled();
}
/**
* @deprecated (since 6.0) : No longer used internally
*/
@Deprecated
public BatchFetchStyle getBatchFetchStyle() {
return sessionFactoryOptions.getBatchFetchStyle();
}

View File

@ -8,8 +8,6 @@ package org.hibernate.collection.internal;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -19,7 +17,6 @@ import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -179,19 +176,6 @@ public class PersistentArrayHolder extends AbstractPersistentCollection {
return false;
}
@Override
@SuppressWarnings("unchecked")
public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
throws HibernateException, SQLException {
final Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
final int index = (Integer) persister.readIndex( rs, descriptor.getSuffixedIndexAliases(), getSession() );
for ( int i = tempList.size(); i<=index; i++) {
tempList.add( i, null );
}
tempList.set( index, element );
return element;
}
@Override
public Object readFrom(
RowProcessingState rowProcessingState,

View File

@ -7,8 +7,6 @@
package org.hibernate.collection.internal;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -21,7 +19,6 @@ import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -124,19 +121,6 @@ public class PersistentBag extends AbstractPersistentCollection implements List
return bag.iterator();
}
@Override
@SuppressWarnings("unchecked")
public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
throws HibernateException, SQLException {
// note that if we load this collection from a cartesian product
// the multiplicity would be broken ... so use an idbag instead
final Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
if ( element != null ) {
bag.add( element );
}
return element;
}
@Override
public Object readFrom(
RowProcessingState rowProcessingState,

View File

@ -7,8 +7,6 @@
package org.hibernate.collection.internal;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@ -20,7 +18,6 @@ import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -354,25 +351,6 @@ public class PersistentIdentifierBag extends AbstractPersistentCollection implem
return old != null && elemType.isDirty( old, entry, getSession() );
}
@Override
public Object readFrom(
ResultSet rs,
CollectionPersister persister,
CollectionAliases descriptor,
Object owner) throws HibernateException, SQLException {
final Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
final Object old = identifiers.put(
values.size(),
persister.readIdentifier( rs, descriptor.getSuffixedIdentifierAlias(), getSession() )
);
if ( old == null ) {
//maintain correct duplication if loaded in a cartesian product
values.add( element );
}
return element;
}
@Override
public Object readFrom(
RowProcessingState rowProcessingState,

View File

@ -7,8 +7,6 @@
package org.hibernate.collection.internal;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
@ -18,7 +16,6 @@ import java.util.ListIterator;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -396,22 +393,6 @@ public class PersistentList extends AbstractPersistentCollection implements List
return list.toString();
}
@Override
@SuppressWarnings("unchecked")
public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
throws HibernateException, SQLException {
final Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() ) ;
final int index = (Integer) persister.readIndex( rs, descriptor.getSuffixedIndexAliases(), getSession() );
//pad with nulls from the current last element up to the new index
for ( int i = list.size(); i<=index; i++) {
list.add( i, null );
}
list.set( index, element );
return element;
}
@Override
public Object readFrom(
RowProcessingState rowProcessingState,

View File

@ -7,8 +7,6 @@
package org.hibernate.collection.internal;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@ -20,7 +18,6 @@ import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -279,23 +276,6 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
private transient List<Object[]> loadingEntries;
@Override
public Object readFrom(
ResultSet rs,
CollectionPersister persister,
CollectionAliases descriptor,
Object owner) throws HibernateException, SQLException {
final Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
if ( element != null ) {
final Object index = persister.readIndex( rs, descriptor.getSuffixedIndexAliases(), getSession() );
if ( loadingEntries == null ) {
loadingEntries = new ArrayList<>();
}
loadingEntries.add( new Object[] { index, element } );
}
return element;
}
@Override
public Object readFrom(
RowProcessingState rowProcessingState,

View File

@ -7,8 +7,6 @@
package org.hibernate.collection.internal;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@ -19,7 +17,6 @@ import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -336,20 +333,6 @@ public class PersistentSet extends AbstractPersistentCollection implements java.
return set.toString();
}
@Override
@SuppressWarnings("unchecked")
public Object readFrom(
ResultSet rs,
CollectionPersister persister,
CollectionAliases descriptor,
Object owner) throws HibernateException, SQLException {
final Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
if ( element != null ) {
tempList.add( element );
}
return element;
}
@Override
public Object readFrom(
RowProcessingState rowProcessingState,

View File

@ -7,14 +7,11 @@
package org.hibernate.collection.spi;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -158,21 +155,10 @@ public interface PersistentCollection {
Iterator entries(CollectionPersister persister);
/**
* Read a row from the JDBC result set
*
* @param rs The JDBC ResultSet
* @param role The collection role
* @param descriptor The aliases used for the columns making up the collection
* @param owner The collection owner
*
* @return The read object
* Read a row from the JDBC values
*
* @throws HibernateException Generally indicates a problem resolving data read from the ResultSet
* @throws SQLException Indicates a problem accessing the ResultSet
*/
Object readFrom(ResultSet rs, CollectionPersister role, CollectionAliases descriptor, Object owner)
throws HibernateException, SQLException;
Object readFrom(
RowProcessingState rowProcessingState,
DomainResultAssembler elementAssembler,

View File

@ -1,126 +0,0 @@
/*
* 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.engine.query.spi;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.action.internal.BulkOperationCleanupAction;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.spi.EventSource;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.loader.custom.CustomQuery;
import org.hibernate.param.ParameterBinder;
/**
* Defines a query execution plan for a native-SQL query.
*
* @author Steve Ebersole
*/
public class NativeSQLQueryPlan implements Serializable {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( NativeSQLQueryPlan.class );
private final String sourceQuery;
private final CustomQuery customQuery;
/**
* Constructs a NativeSQLQueryPlan.
*
* @param sourceQuery The original native query to create a plan for
* @param customQuery The query executed via this plan
*/
public NativeSQLQueryPlan(String sourceQuery, CustomQuery customQuery) {
this.sourceQuery = sourceQuery;
this.customQuery = customQuery;
}
public String getSourceQuery() {
return sourceQuery;
}
public CustomQuery getCustomQuery() {
return customQuery;
}
protected void coordinateSharedCacheCleanup(SharedSessionContractImplementor session) {
final BulkOperationCleanupAction action = new BulkOperationCleanupAction( session, getCustomQuery().getQuerySpaces() );
if ( session.isEventSource() ) {
( (EventSource) session ).getActionQueue().addAction( action );
}
else {
action.getAfterTransactionCompletionProcess().doAfterTransactionCompletion( true, session );
}
}
/**
* Performs the execute query
*
* @param queryParameters The query parameters
* @param session The session
*
* @return The number of affected rows as returned by the JDBC driver
*
* @throws HibernateException Indicates a problem performing the query execution
*/
public int performExecuteUpdate(
QueryParameters queryParameters,
SharedSessionContractImplementor session) throws HibernateException {
coordinateSharedCacheCleanup( session );
if ( queryParameters.isCallable() ) {
throw new IllegalArgumentException("callable not yet supported for native queries");
}
int result = 0;
PreparedStatement ps;
RowSelection selection = queryParameters.getRowSelection();
try {
queryParameters.processFilters( this.customQuery.getSQL(), session );
final String sql = session.getJdbcServices().getDialect()
.addSqlHintOrComment(
queryParameters.getFilteredSQL(),
queryParameters,
session.getFactory().getSessionFactoryOptions().isCommentsEnabled()
);
ps = session.getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
try {
int col = 1;
for ( ParameterBinder binder : this.customQuery.getParameterValueBinders() ) {
col += binder.bind( ps, queryParameters, session, col );
}
if ( selection != null && selection.getTimeout() != null ) {
ps.setQueryTimeout( selection.getTimeout() );
}
result = session.getJdbcCoordinator().getResultSetReturn().executeUpdate( ps );
}
finally {
if ( ps != null ) {
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( ps );
session.getJdbcCoordinator().afterStatementExecution();
}
}
}
catch (SQLException sqle) {
throw session.getFactory().getSQLExceptionHelper().convert(
sqle,
"could not execute native bulk manipulation query",
this.sourceQuery
);
}
return result;
}
}

View File

@ -52,7 +52,6 @@ import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
import org.hibernate.loader.custom.CustomQuery;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.query.spi.QueryImplementor;
@ -192,16 +191,6 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
return delegate.instantiate( entityName, id );
}
@Override
public List listCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) throws HibernateException {
return delegate.listCustomQuery( customQuery, queryParameters );
}
@Override
public ScrollableResultsImplementor scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) throws HibernateException {
return delegate.scrollCustomQuery( customQuery, queryParameters );
}
@Override
public List list(NativeSQLQuerySpecification spec, QueryParameters queryParameters) throws HibernateException {
return delegate.list( spec, queryParameters );

View File

@ -27,7 +27,6 @@ import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.loader.custom.CustomQuery;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.spi.QueryProducerImplementor;
import org.hibernate.query.spi.ScrollableResultsImplementor;
@ -303,18 +302,6 @@ public interface SharedSessionContractImplementor
*/
Object instantiate(String entityName, Serializable id) throws HibernateException;
/**
* Execute an SQL Query
*/
List listCustomQuery(CustomQuery customQuery, QueryParameters queryParameters)
throws HibernateException;
/**
* Execute an SQL Query
*/
ScrollableResultsImplementor scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters)
throws HibernateException;
/**
* Execute a native SQL query, and return the results as a fully built list.
*

View File

@ -48,7 +48,6 @@ import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.MultiIdentifierLoadAccess;
import org.hibernate.NaturalIdLoadAccess;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.ObjectDeletedException;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.ReplicationMode;
@ -73,7 +72,6 @@ import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@ -127,7 +125,6 @@ import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
import org.hibernate.jpa.internal.util.LockOptionsHelper;
import org.hibernate.loader.custom.CustomQuery;
import org.hibernate.metamodel.spi.MetamodelImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.MultiLoadOptions;
@ -138,7 +135,6 @@ import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.query.Query;
import org.hibernate.query.UnknownSqlResultSetMappingException;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.resource.transaction.TransactionRequiredForJoinException;
import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl;
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
@ -1584,61 +1580,6 @@ public final class SessionImpl
return super.createStoredProcedureCall( procedureName, resultClasses );
}
@Override
public ScrollableResultsImplementor scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) {
throw new NotYetImplementedFor6Exception( getClass() );
// checkOpenOrWaitingForAutoClose();
//// checkTransactionSynchStatus();
//
// if ( log.isTraceEnabled() ) {
// log.tracev( "Scroll SQL query: {0}", customQuery.getSQL() );
// }
//
// CustomLoader loader = getFactory().getQueryPlanCache().getNativeQueryInterpreter().createCustomLoader( customQuery, getFactory() );
//
// autoFlushIfRequired( loader.getQuerySpaces() );
//
// dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called
// try {
// return loader.scroll( queryParameters, this );
// }
// finally {
// delayedAfterCompletion();
// dontFlushFromFind--;
// }
}
// basically just an adapted copy of find(CriteriaImpl)
@Override
public List listCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) {
throw new NotYetImplementedFor6Exception( getClass() );
// checkOpenOrWaitingForAutoClose();
//// checkTransactionSynchStatus();
//
// if ( log.isTraceEnabled() ) {
// log.tracev( "SQL query: {0}", customQuery.getSQL() );
// }
//
// CustomLoader loader = getFactory().getQueryPlanCache().getNativeQueryInterpreter().createCustomLoader( customQuery, getFactory() );
//
// autoFlushIfRequired( loader.getQuerySpaces() );
//
// dontFlushFromFind++;
// boolean success = false;
// try {
// List results = loader.list( this, queryParameters );
// success = true;
// return results;
// }
// finally {
// dontFlushFromFind--;
// delayedAfterCompletion();
// afterOperation( success );
// }
}
@Override
public SessionFactoryImplementor getSessionFactory() {
// checkTransactionSynchStatus();

View File

@ -8,7 +8,6 @@ package org.hibernate.internal;
import java.io.Serializable;
import java.sql.Connection;
import java.util.List;
import javax.transaction.SystemException;
import org.hibernate.CacheMode;
@ -27,16 +26,12 @@ import org.hibernate.engine.internal.Versioning;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.id.IdentifierGeneratorHelper;
import org.hibernate.loader.custom.CustomLoader;
import org.hibernate.loader.custom.CustomQuery;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.tuple.entity.EntityMetamodel;
/**
@ -550,40 +545,6 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
}
}
@Override
public List listCustomQuery(CustomQuery customQuery, QueryParameters queryParameters)
throws HibernateException {
checkOpen();
CustomLoader loader = new CustomLoader( customQuery, getFactory() );
boolean success = false;
List results;
try {
results = loader.list( this, queryParameters );
success = true;
}
finally {
afterOperation( success );
}
temporaryPersistenceContext.clear();
return results;
}
@Override
public ScrollableResultsImplementor scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters)
throws HibernateException {
checkOpen();
CustomLoader loader = new CustomLoader( customQuery, getFactory() );
return loader.scroll( queryParameters, this );
}
// @Override
// public ScrollableResultsImplementor scroll(String query, QueryParameters queryParameters) throws HibernateException {
// checkOpen();
// HQLQueryPlan plan = getQueryPlan( query, false );
// return plan.performScroll( queryParameters, this );
// }
@Override
public void afterScrollOperation() {
temporaryPersistenceContext.clear();

View File

@ -1,200 +0,0 @@
/*
* 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.loader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.hibernate.FetchMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.engine.profile.Fetch;
import org.hibernate.engine.profile.FetchProfile;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.sql.JoinFragment;
import org.hibernate.sql.Select;
import org.hibernate.type.AssociationType;
/**
* Abstract walker for walkers which begin at an entity (criteria
* queries and entity loaders).
*
* @author Gavin King
*/
public abstract class AbstractEntityJoinWalker extends JoinWalker {
private final OuterJoinLoadable persister;
private final String alias;
public AbstractEntityJoinWalker(
OuterJoinLoadable persister,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
this( persister, factory, loadQueryInfluencers, null );
}
public AbstractEntityJoinWalker(
OuterJoinLoadable persister,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers,
String alias) {
super( factory, loadQueryInfluencers );
this.persister = persister;
this.alias = ( alias == null ) ? generateRootAlias( persister.getEntityName() ) : alias;
}
protected final void initAll(
final String whereString,
final String orderByString,
final LockOptions lockOptions) throws MappingException {
initAll( whereString, orderByString, lockOptions, AssociationInitCallback.NO_CALLBACK );
}
protected final void initAll(
final String whereString,
final String orderByString,
final LockOptions lockOptions,
final AssociationInitCallback callback) throws MappingException {
walkEntityTree( persister, getAlias() );
List allAssociations = new ArrayList( associations );
allAssociations.add( OuterJoinableAssociation.createRoot( persister.getEntityType(), alias, getFactory() ) );
initPersisters( allAssociations, lockOptions, callback );
initStatementString( whereString, orderByString, lockOptions );
}
protected final void initProjection(
final String projectionString,
final String whereString,
final String orderByString,
final String groupByString,
final LockOptions lockOptions) throws MappingException {
walkEntityTree( persister, getAlias() );
persisters = new Loadable[0];
initStatementString(projectionString, whereString, orderByString, groupByString, lockOptions);
}
private void initStatementString(
final String condition,
final String orderBy,
final LockOptions lockOptions) throws MappingException {
initStatementString(null, condition, orderBy, "", lockOptions);
}
private void initStatementString(
final String projection,
final String condition,
final String orderBy,
final String groupBy,
final LockOptions lockOptions) throws MappingException {
final int joins = countEntityPersisters( associations );
suffixes = BasicLoader.generateSuffixes( joins + 1 );
JoinFragment ojf = mergeOuterJoins( associations );
Select select = new Select( getDialect() )
.setLockOptions( lockOptions )
.setSelectClause(
projection == null ?
persister.selectFragment( alias, suffixes[joins] ) + selectString( associations ) :
projection
)
.setFromClause(
getDialect().appendLockHint( lockOptions, persister.fromTableFragment( alias ) ) +
persister.fromJoinFragment( alias, true, true )
)
.setWhereClause( condition )
.setOuterJoins(
ojf.toFromFragmentString(),
ojf.toWhereFragmentString() + getWhereFragment()
)
.setOrderByClause( orderBy( associations, orderBy ) )
.setGroupByClause( groupBy );
if ( getFactory().getSessionFactoryOptions().isCommentsEnabled() ) {
select.setComment( getComment() );
}
sql = select.toStatementString();
}
protected String getWhereFragment() throws MappingException {
// here we do not bother with the discriminator.
return persister.whereJoinFragment(alias, true, true);
}
/**
* The superclass deliberately excludes collections
*/
protected boolean isJoinedFetchEnabled(AssociationType type, FetchMode config, CascadeStyle cascadeStyle) {
return isJoinedFetchEnabledInMapping( config, type );
}
protected final boolean isJoinFetchEnabledByProfile(OuterJoinLoadable persister, PropertyPath path, int propertyNumber) {
if ( !getLoadQueryInfluencers().hasEnabledFetchProfiles() ) {
// perf optimization
return false;
}
// ugh, this stuff has to be made easier...
final String fullPath = path.getFullPath();
String rootPropertyName = persister.getSubclassPropertyName( propertyNumber );
int pos = fullPath.lastIndexOf( rootPropertyName );
String relativePropertyPath = pos >= 0
? fullPath.substring( pos )
: rootPropertyName;
String fetchRole = persister.getEntityName() + '.' + relativePropertyPath;
for ( String profileName : getLoadQueryInfluencers().getEnabledFetchProfileNames() ) {
final FetchProfile profile = getFactory().getFetchProfile( profileName );
final Fetch fetch = profile.getFetchByRole( fetchRole );
if ( fetch != null && Fetch.Style.JOIN == fetch.getStyle() ) {
return true;
}
}
return false;
}
public abstract String getComment();
@Override
protected boolean isDuplicateAssociation(final String foreignKeyTable, final String[] foreignKeyColumns) {
//disable a join back to this same association
final boolean isSameJoin =
persister.getTableName().equals( foreignKeyTable ) &&
Arrays.equals( foreignKeyColumns, persister.getKeyColumnNames() );
return isSameJoin ||
super.isDuplicateAssociation(foreignKeyTable, foreignKeyColumns);
}
public final Loadable getPersister() {
return persister;
}
public final String getAlias() {
return alias;
}
/**
* For entities, orderings added by, for example, Criteria#addOrder need to come before the associations' @OrderBy
* values. However, other sub-classes of JoinWalker (BasicCollectionJoinWalker, OneToManyJoinWalker, etc.)
* still need the other way around. So, override here instead. See HHH-7116.
*/
@Override
protected String orderBy(final List associations, final String orderBy) {
return mergeOrderings( orderBy, orderBy( associations ) );
}
public String toString() {
return getClass().getName() + '(' + getPersister().getEntityName() + ')';
}
}

View File

@ -1,109 +0,0 @@
/*
* 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.loader;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.internal.AliasConstantsHelper;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.type.BagType;
/**
* Uses the default mapping from property to result set column
* alias defined by the entities' persisters. Used when Hibernate
* is generating result set column aliases.
*
* @author Gavin King
*/
public abstract class BasicLoader extends Loader {
protected static final String[] NO_SUFFIX = {""};
private EntityAliases[] descriptors;
private CollectionAliases[] collectionDescriptors;
public BasicLoader(SessionFactoryImplementor factory) {
super(factory);
}
protected final EntityAliases[] getEntityAliases() {
return descriptors;
}
protected final CollectionAliases[] getCollectionAliases() {
return collectionDescriptors;
}
protected abstract String[] getSuffixes();
protected abstract String[] getCollectionSuffixes();
protected void postInstantiate() {
Loadable[] persisters = getEntityPersisters();
String[] suffixes = getSuffixes();
descriptors = new EntityAliases[persisters.length];
for ( int i=0; i<descriptors.length; i++ ) {
descriptors[i] = new DefaultEntityAliases( persisters[i], suffixes[i] );
}
CollectionPersister[] collectionPersisters = getCollectionPersisters();
List bagRoles = null;
if ( collectionPersisters != null ) {
String[] collectionSuffixes = getCollectionSuffixes();
collectionDescriptors = new CollectionAliases[collectionPersisters.length];
for ( int i = 0; i < collectionPersisters.length; i++ ) {
if ( isBag( collectionPersisters[i] ) ) {
if ( bagRoles == null ) {
bagRoles = new ArrayList();
}
bagRoles.add( collectionPersisters[i].getRole() );
}
collectionDescriptors[i] = new GeneratedCollectionAliases(
collectionPersisters[i],
collectionSuffixes[i]
);
}
}
else {
collectionDescriptors = null;
}
if ( bagRoles != null && bagRoles.size() > 1 ) {
throw new MultipleBagFetchException( bagRoles );
}
}
private boolean isBag(CollectionPersister collectionPersister) {
return collectionPersister.getCollectionType().getClass().isAssignableFrom( BagType.class );
}
/**
* Utility method that generates 0_, 1_ suffixes. Subclasses don't
* necessarily need to use this algorithm, but it is intended that
* they will in most cases.
*
* @param length The number of suffixes to generate
*
* @return The array of generated suffixes (with length=length).
*/
public static String[] generateSuffixes(int length) {
return generateSuffixes( 0, length );
}
public static String[] generateSuffixes(int seed, int length) {
if ( length == 0 ) {
return NO_SUFFIX;
}
String[] suffixes = new String[length];
for ( int i = 0; i < length; i++ ) {
suffixes[i] = AliasConstantsHelper.get( i + seed );
}
return suffixes;
}
}

View File

@ -1,8 +1,8 @@
/*
* 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>.
* 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.loader;
@ -15,7 +15,10 @@ import org.jboss.logging.Logger;
* ({@link org.hibernate.cfg.AvailableSettings#BATCH_FETCH_STYLE}) setting
*
* @author Steve Ebersole
*
* @deprecated (since 6.0) : see {@link BatchLoadSizingStrategy} instead
*/
@Deprecated
public enum BatchFetchStyle {
/**
* The legacy algorithm where we keep a set of pre-built batch sizes based on

View File

@ -1,55 +0,0 @@
/*
* 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.loader;
/**
* Type definition of CollectionAliases.
*
* @author Steve Ebersole
*/
public interface CollectionAliases {
/**
* Returns the suffixed result-set column-aliases for columns making
* up the key for this collection (i.e., its FK to its owner).
*
* @return The key result-set column aliases.
*/
public String[] getSuffixedKeyAliases();
/**
* Returns the suffixed result-set column-aliases for the collumns
* making up the collection's index (map or list).
*
* @return The index result-set column aliases.
*/
public String[] getSuffixedIndexAliases();
/**
* Returns the suffixed result-set column-aliases for the columns
* making up the collection's elements.
*
* @return The element result-set column aliases.
*/
public String[] getSuffixedElementAliases();
/**
* Returns the suffixed result-set column-aliases for the column
* defining the collection's identifier (if any).
*
* @return The identifier result-set column aliases.
*/
public String getSuffixedIdentifierAlias();
/**
* Returns the suffix used to unique the column aliases for this
* particular alias set.
*
* @return The uniqued column alias suffix.
*/
public String getSuffix();
}

View File

@ -1,40 +0,0 @@
/*
* 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.loader;
import java.util.Map;
import org.hibernate.persister.entity.Loadable;
/**
* EntityAliases that chooses the column names over the alias names. This strategy is used
* when the result-set mapping did not give specific aliases to use in extracting from the
* result set. We use the column names from the underlying persister.
*
* @author max
* @author Steve Ebersole
*/
public class ColumnEntityAliases extends DefaultEntityAliases {
public ColumnEntityAliases(
Map returnProperties,
Loadable persister,
String suffix) {
super( returnProperties, persister, suffix );
}
protected String[] getIdentifierAliases(Loadable persister, String suffix) {
return persister.getIdentifierColumnNames();
}
protected String getDiscriminatorAlias(Loadable persister, String suffix) {
return persister.getDiscriminatorColumnName();
}
protected String[] getPropertyAliases(Loadable persister, int j) {
return persister.getPropertyColumnNames(j);
}
}

View File

@ -1,187 +0,0 @@
/*
* 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.loader;
import java.util.Collections;
import java.util.Map;
import org.hibernate.dialect.Dialect;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.persister.entity.Loadable;
/**
* EntityAliases which handles the logic of selecting user provided aliases (via return-property),
* before using the default aliases.
*
* @author max
*
*/
public class DefaultEntityAliases implements EntityAliases {
private static final String[][] EMPTY_ARRAY_OF_ARRAY_OF_STRINGS = new String[0][];
private final String[] suffixedKeyColumns;
private final String[] suffixedVersionColumn;
private final String[][] suffixedPropertyColumns;
private final String suffixedDiscriminatorColumn;
private final String suffix;
private final String rowIdAlias;
private final Map userProvidedAliases;
/**
* Calculate and cache select-clause aliases
*
* @param userProvidedAliases The explicit aliases provided in a result-set mapping.
* @param persister The persister for which we are generating select aliases
* @param suffix The calculated suffix.
*/
public DefaultEntityAliases(
Map userProvidedAliases,
Loadable persister,
String suffix) {
this( userProvidedAliases, persister, suffix, false );
}
public DefaultEntityAliases(Loadable persister, String suffix) {
this( Collections.EMPTY_MAP, persister, suffix, true );
}
private DefaultEntityAliases(
Map userProvidedAliases,
Loadable persister,
String suffix,
boolean interns) {
if ( interns ) {
this.suffix = suffix.intern();
this.rowIdAlias = (Loadable.ROWID_ALIAS + suffix).intern(); // TODO: not visible to the user!
}
else {
this.suffix = suffix;
this.rowIdAlias = (Loadable.ROWID_ALIAS + suffix);
}
this.userProvidedAliases = userProvidedAliases;
suffixedKeyColumns = determineKeyAlias( persister, suffix );
suffixedPropertyColumns = determinePropertyAliases( persister );
suffixedDiscriminatorColumn = determineDiscriminatorAlias( persister, suffix );
suffixedVersionColumn = determineVersionAlias( persister );
}
private String[] determineKeyAlias(Loadable persister, String suffix) {
final String[] aliases;
final String[] keyColumnsCandidates = getUserProvidedAliases( persister.getIdentifierPropertyName(), null );
if ( keyColumnsCandidates == null ) {
aliases = getUserProvidedAliases(
"id",
getIdentifierAliases(persister, suffix)
);
}
else {
aliases = keyColumnsCandidates;
}
return StringHelper.unquote( aliases, persister.getFactory().getDialect() );
}
private String[][] determinePropertyAliases(Loadable persister) {
return getSuffixedPropertyAliases( persister );
}
private String determineDiscriminatorAlias(Loadable persister, String suffix) {
String alias = getUserProvidedAlias( "class", getDiscriminatorAlias( persister, suffix ) );
return StringHelper.unquote( alias, persister.getFactory().getDialect() );
}
private String[] determineVersionAlias(Loadable persister) {
return persister.isVersioned()
? suffixedPropertyColumns[ persister.getVersionProperty() ]
: null;
}
protected String getDiscriminatorAlias(Loadable persister, String suffix) {
return persister.getDiscriminatorAlias(suffix);
}
protected String[] getIdentifierAliases(Loadable persister, String suffix) {
return persister.getIdentifierAliases(suffix);
}
protected String[] getPropertyAliases(Loadable persister, int j) {
return persister.getPropertyAliases(suffix, j);
}
private String[] getUserProvidedAliases(String propertyPath, String[] defaultAliases) {
String[] result = (String[]) userProvidedAliases.get(propertyPath);
if (result==null) {
return defaultAliases;
}
else {
return result;
}
}
private String getUserProvidedAlias(String propertyPath, String defaultAlias) {
String[] columns = (String[]) userProvidedAliases.get( propertyPath );
if ( columns == null ) {
return defaultAlias;
}
else {
return columns[0];
}
}
@Override
public String[][] getSuffixedPropertyAliases(Loadable persister) {
final String[] propertyNames = persister.getPropertyNames();
final int size = propertyNames.length;
final String[][] suffixedPropertyAliases;
if ( size > 0 ) {
suffixedPropertyAliases = new String[size][];
final Dialect dialect = persister.getFactory().getDialect();
for ( int j = 0; j < size; j++ ) {
suffixedPropertyAliases[j] = getUserProvidedAliases(
propertyNames[j],
getPropertyAliases( persister, j )
);
suffixedPropertyAliases[j] = StringHelper.unquote( suffixedPropertyAliases[j], dialect );
}
}
else {
suffixedPropertyAliases = EMPTY_ARRAY_OF_ARRAY_OF_STRINGS;
}
return suffixedPropertyAliases;
}
@Override
public String[] getSuffixedVersionAliases() {
return suffixedVersionColumn;
}
@Override
public String[][] getSuffixedPropertyAliases() {
return suffixedPropertyColumns;
}
@Override
public String getSuffixedDiscriminatorAlias() {
return suffixedDiscriminatorColumn;
}
@Override
public String[] getSuffixedKeyAliases() {
return suffixedKeyColumns;
}
@Override
public String getRowIdAlias() {
return rowIdAlias;
}
@Override
public String getSuffix() {
return suffix;
}
}

View File

@ -1,47 +0,0 @@
/*
* 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.loader;
import org.hibernate.persister.entity.Loadable;
/**
* Metadata describing the SQL result set column aliases
* for a particular entity.
*
* @author Gavin King
*/
public interface EntityAliases {
/**
* The result set column aliases for the primary key columns
*/
public String[] getSuffixedKeyAliases();
/**
* The result set column aliases for the discriminator columns
*/
public String getSuffixedDiscriminatorAlias();
/**
* The result set column aliases for the version columns
*/
public String[] getSuffixedVersionAliases();
/**
* The result set column aliases for the property columns
*/
public String[][] getSuffixedPropertyAliases();
/**
* The result set column aliases for the property columns of a subclass
*/
public String[][] getSuffixedPropertyAliases(Loadable persister);
/**
* The result set column alias for the Oracle row id
*/
public String getRowIdAlias();
/**
* Returns the suffix used to generate the aliases.
* @return the suffix used to generate the aliases.
*/
public String getSuffix();
}

View File

@ -1,141 +0,0 @@
/*
* 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.loader;
import java.util.Collections;
import java.util.Map;
import org.hibernate.persister.collection.CollectionPersister;
/**
* CollectionAliases which handles the logic of selecting user provided aliases (via return-property),
* before using the default aliases.
*
* @author Steve Ebersole
* @author Max Rydahl Andersen
*/
public class GeneratedCollectionAliases implements CollectionAliases {
private final String suffix;
private final String[] keyAliases;
private final String[] indexAliases;
private final String[] elementAliases;
private final String identifierAlias;
private Map userProvidedAliases;
public GeneratedCollectionAliases(Map userProvidedAliases, CollectionPersister persister, String suffix) {
this.suffix = suffix;
this.userProvidedAliases = userProvidedAliases;
this.keyAliases = getUserProvidedAliases(
"key",
persister.getKeyColumnAliases( suffix )
);
this.indexAliases = getUserProvidedAliases(
"index",
persister.getIndexColumnAliases( suffix )
);
this.elementAliases = getUserProvidedAliases(
"element",
persister.getElementColumnAliases( suffix )
);
this.identifierAlias = getUserProvidedAlias(
"id",
persister.getIdentifierColumnAlias( suffix )
);
}
public GeneratedCollectionAliases(CollectionPersister persister, String string) {
this( Collections.EMPTY_MAP, persister, string );
}
/**
* Returns the suffixed result-set column-aliases for columns making up the key for this collection (i.e., its FK to
* its owner).
*
* @return The key result-set column aliases.
*/
public String[] getSuffixedKeyAliases() {
return keyAliases;
}
/**
* Returns the suffixed result-set column-aliases for the collumns making up the collection's index (map or list).
*
* @return The index result-set column aliases.
*/
public String[] getSuffixedIndexAliases() {
return indexAliases;
}
/**
* Returns the suffixed result-set column-aliases for the columns making up the collection's elements.
*
* @return The element result-set column aliases.
*/
public String[] getSuffixedElementAliases() {
return elementAliases;
}
/**
* Returns the suffixed result-set column-aliases for the column defining the collection's identifier (if any).
*
* @return The identifier result-set column aliases.
*/
public String getSuffixedIdentifierAlias() {
return identifierAlias;
}
/**
* Returns the suffix used to unique the column aliases for this particular alias set.
*
* @return The uniqued column alias suffix.
*/
public String getSuffix() {
return suffix;
}
@Override
public String toString() {
return super.toString() + " [suffix=" + suffix +
", suffixedKeyAliases=[" + join( keyAliases ) +
"], suffixedIndexAliases=[" + join( indexAliases ) +
"], suffixedElementAliases=[" + join( elementAliases ) +
"], suffixedIdentifierAlias=[" + identifierAlias + "]]";
}
private String join(String[] aliases) {
if ( aliases == null ) {
return null;
}
return String.join( ", ", aliases );
}
private String[] getUserProvidedAliases(String propertyPath, String[] defaultAliases) {
String[] result = (String[]) userProvidedAliases.get( propertyPath );
if ( result == null ) {
return defaultAliases;
}
else {
return result;
}
}
private String getUserProvidedAlias(String propertyPath, String defaultAlias) {
String[] columns = (String[]) userProvidedAliases.get( propertyPath );
if ( columns == null ) {
return defaultAlias;
}
else {
return columns[0];
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,10 @@
/*
* 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>.
* 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.loader.custom;
package org.hibernate.loader;
import org.hibernate.HibernateException;

View File

@ -1,115 +0,0 @@
/*
* 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.loader;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.type.EntityType;
/**
* Implements logic for walking a tree of associated classes.
*
* Generates an SQL select string containing all properties of those classes.
* Tables are joined using an ANSI-style left outer join.
*
* @author Gavin King
*/
public abstract class OuterJoinLoader extends BasicLoader {
protected Loadable[] persisters;
protected CollectionPersister[] collectionPersisters;
protected int[] collectionOwners;
protected String[] aliases;
private LockOptions lockOptions;
protected LockMode[] lockModeArray;
protected int[] owners;
protected EntityType[] ownerAssociationTypes;
protected String sql;
protected String[] suffixes;
protected String[] collectionSuffixes;
private LoadQueryInfluencers loadQueryInfluencers;
protected final Dialect getDialect() {
return getFactory().getDialect();
}
public OuterJoinLoader(
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
super( factory );
this.loadQueryInfluencers = loadQueryInfluencers;
}
protected String[] getSuffixes() {
return suffixes;
}
protected String[] getCollectionSuffixes() {
return collectionSuffixes;
}
@Override
public final String getSQLString() {
return sql;
}
protected final Loadable[] getEntityPersisters() {
return persisters;
}
protected int[] getOwners() {
return owners;
}
protected EntityType[] getOwnerAssociationTypes() {
return ownerAssociationTypes;
}
protected LockMode[] getLockModes(LockOptions lockOptions) {
return lockModeArray;
}
protected LockOptions getLockOptions() {
return lockOptions;
}
public LoadQueryInfluencers getLoadQueryInfluencers() {
return loadQueryInfluencers;
}
protected final String[] getAliases() {
return aliases;
}
protected final CollectionPersister[] getCollectionPersisters() {
return collectionPersisters;
}
protected final int[] getCollectionOwners() {
return collectionOwners;
}
protected void initFromWalker(JoinWalker walker) {
persisters = walker.getPersisters();
collectionPersisters = walker.getCollectionPersisters();
ownerAssociationTypes = walker.getOwnerAssociationTypes();
lockOptions = walker.getLockModeOptions();
lockModeArray = walker.getLockModeArray();
suffixes = walker.getSuffixes();
collectionSuffixes = walker.getCollectionSuffixes();
owners = walker.getOwners();
collectionOwners = walker.getCollectionOwners();
sql = walker.getSQLString();
aliases = walker.getAliases();
}
}

View File

@ -1,214 +0,0 @@
/*
* 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.loader;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.hibernate.MappingException;
import org.hibernate.engine.internal.JoinHelper;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.sql.JoinFragment;
import org.hibernate.sql.JoinType;
import org.hibernate.type.AssociationType;
import org.hibernate.type.EntityType;
/**
* Part of the Hibernate SQL rendering internals. This class represents
* a joinable association.
*
* @author Gavin King
*/
public final class OuterJoinableAssociation {
private final PropertyPath propertyPath;
private final AssociationType joinableType;
private final Joinable joinable;
private final String lhsAlias; // belong to other persister
private final String[] lhsColumns; // belong to other persister
private final String rhsAlias;
private final String[] rhsColumns;
private final JoinType joinType;
private final String on;
private final Map enabledFilters;
private final boolean hasRestriction;
public static OuterJoinableAssociation createRoot(
AssociationType joinableType,
String alias,
SessionFactoryImplementor factory) {
return new OuterJoinableAssociation(
new PropertyPath(),
joinableType,
null,
null,
alias,
JoinType.LEFT_OUTER_JOIN,
null,
false,
factory,
Collections.EMPTY_MAP
);
}
public OuterJoinableAssociation(
PropertyPath propertyPath,
AssociationType joinableType,
String lhsAlias,
String[] lhsColumns,
String rhsAlias,
JoinType joinType,
String withClause,
boolean hasRestriction,
SessionFactoryImplementor factory,
Map enabledFilters) throws MappingException {
this.propertyPath = propertyPath;
this.joinableType = joinableType;
this.lhsAlias = lhsAlias;
this.lhsColumns = lhsColumns;
this.rhsAlias = rhsAlias;
this.joinType = joinType;
this.joinable = joinableType.getAssociatedJoinable( factory );
this.rhsColumns = JoinHelper.getRHSColumnNames( joinableType, factory );
this.on = joinableType.getOnCondition( rhsAlias, factory, enabledFilters )
+ ( withClause == null || withClause.trim().length() == 0 ? "" : " and ( " + withClause + " )" );
this.hasRestriction = hasRestriction;
this.enabledFilters = enabledFilters; // needed later for many-to-many/filter application
}
public PropertyPath getPropertyPath() {
return propertyPath;
}
public JoinType getJoinType() {
return joinType;
}
public String getLhsAlias() {
return lhsAlias;
}
public String getRHSAlias() {
return rhsAlias;
}
public String getRhsAlias() {
return rhsAlias;
}
private boolean isOneToOne() {
if ( joinableType.isEntityType() ) {
EntityType etype = (EntityType) joinableType;
return etype.isOneToOne() /*&& etype.isReferenceToPrimaryKey()*/;
}
else {
return false;
}
}
public AssociationType getJoinableType() {
return joinableType;
}
public String getRHSUniqueKeyName() {
return joinableType.getRHSUniqueKeyPropertyName();
}
public boolean isCollection() {
return joinableType.isCollectionType();
}
public Joinable getJoinable() {
return joinable;
}
public boolean hasRestriction() {
return hasRestriction;
}
public int getOwner(final List associations) {
if ( isOneToOne() || isCollection() ) {
return getPosition( lhsAlias, associations );
}
else {
return -1;
}
}
/**
* Get the position of the join with the given alias in the
* list of joins
*/
private static int getPosition(String lhsAlias, List associations) {
int result = 0;
for ( Object association : associations ) {
final OuterJoinableAssociation oj = (OuterJoinableAssociation) association;
if ( oj.getJoinable().consumesEntityAlias() /*|| oj.getJoinable().consumesCollectionAlias() */ ) {
if ( oj.rhsAlias.equals( lhsAlias ) ) {
return result;
}
result++;
}
}
return -1;
}
public void addJoins(JoinFragment outerjoin) throws MappingException {
outerjoin.addJoin(
joinable.getTableName(),
rhsAlias,
lhsColumns,
rhsColumns,
joinType,
on
);
outerjoin.addJoins(
joinable.fromJoinFragment( rhsAlias, false, true ),
joinable.whereJoinFragment( rhsAlias, false, true )
);
}
public void validateJoin(String path) throws MappingException {
if ( rhsColumns == null || lhsColumns == null
|| lhsColumns.length != rhsColumns.length || lhsColumns.length == 0 ) {
throw new MappingException( "invalid join columns for association: " + path );
}
}
public boolean isManyToManyWith(OuterJoinableAssociation other) {
if ( joinable.isCollection() ) {
QueryableCollection persister = (QueryableCollection) joinable;
if ( persister.isManyToMany() ) {
return persister.getElementType() == other.getJoinableType();
}
}
return false;
}
public void addManyToManyJoin(JoinFragment outerjoin, QueryableCollection collection) throws MappingException {
String manyToManyFilter = collection.getManyToManyFilterFragment( rhsAlias, enabledFilters );
String condition = "".equals( manyToManyFilter )
? on
: "".equals( on )
? manyToManyFilter
: on + " and " + manyToManyFilter;
outerjoin.addJoin(
joinable.getTableName(),
rhsAlias,
lhsColumns,
rhsColumns,
joinType,
condition
);
outerjoin.addJoins(
joinable.fromJoinFragment( rhsAlias, false, true ),
joinable.whereJoinFragment( rhsAlias, false, true )
);
}
}

View File

@ -43,8 +43,8 @@ import org.jboss.logging.Logger;
*
* @author Steve Ebersole
*/
public class BatchKeyCollectionLoader implements CollectionLoader {
private static final Logger log = Logger.getLogger( BatchKeyCollectionLoader.class );
public class CollectionLoaderBatchKey implements CollectionLoader {
private static final Logger log = Logger.getLogger( CollectionLoaderBatchKey.class );
private final PluralAttributeMapping attributeMapping;
private final int batchSize;
@ -54,7 +54,7 @@ public class BatchKeyCollectionLoader implements CollectionLoader {
private SelectStatement batchSizeSqlAst;
private List<JdbcParameter> batchSizeJdbcParameters;
public BatchKeyCollectionLoader(
public CollectionLoaderBatchKey(
PluralAttributeMapping attributeMapping,
int batchSize,
LoadQueryInfluencers influencers,

View File

@ -0,0 +1,42 @@
/*
* 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.loader.ast.internal;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.ast.spi.CollectionLoader;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
/**
* @author Steve Ebersole
*/
public class CollectionLoaderNamedQuery implements CollectionLoader {
private final String loaderQueryName;
private final CollectionPersister persister;
private final PluralAttributeMapping attributeMapping;
public CollectionLoaderNamedQuery(
String loaderQueryName,
CollectionPersister persister,
PluralAttributeMapping attributeMapping) {
this.loaderQueryName = loaderQueryName;
this.persister = persister;
this.attributeMapping = attributeMapping;
}
@Override
public PluralAttributeMapping getLoadable() {
return attributeMapping;
}
@Override
public PersistentCollection load(Object key, SharedSessionContractImplementor session) {
return null;
}
}

View File

@ -40,7 +40,7 @@ import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
*
* @author Steve Ebersole
*/
public class SingleKeyCollectionLoader implements CollectionLoader {
public class CollectionLoaderSingleKey implements CollectionLoader {
private final PluralAttributeMapping attributeMapping;
private final int keyJdbcCount;
@ -48,7 +48,7 @@ public class SingleKeyCollectionLoader implements CollectionLoader {
private final SelectStatement sqlAst;
private final List<JdbcParameter> jdbcParameters;
public SingleKeyCollectionLoader(
public CollectionLoaderSingleKey(
PluralAttributeMapping attributeMapping,
LoadQueryInfluencers influencers,
SessionFactoryImplementor sessionFactory) {

View File

@ -31,13 +31,13 @@ import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
*
* @author Steve Ebersole
*/
public class SubSelectFetchCollectionLoader implements CollectionLoader {
public class CollectionLoaderSubSelectFetch implements CollectionLoader {
private final PluralAttributeMapping attributeMapping;
private final SubselectFetch subselect;
private final SelectStatement sqlAst;
public SubSelectFetchCollectionLoader(
public CollectionLoaderSubSelectFetch(
PluralAttributeMapping attributeMapping,
DomainResult cachedDomainResult,
SubselectFetch subselect,

View File

@ -107,7 +107,7 @@ public class LoaderSelectBuilder {
/**
* Create a SQL AST select-statement used for subselect-based CollectionLoader
*
* @see SubSelectFetchCollectionLoader
* @see CollectionLoaderSubSelectFetch
*
* @param attributeMapping The plural-attribute being loaded
* @param subselect The subselect details to apply

View File

@ -0,0 +1,42 @@
/*
* 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.loader.ast.internal;
import org.hibernate.LockOptions;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.ast.spi.SingleUniqueKeyEntityLoader;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
/**
* @author Steve Ebersole
*/
public class SingleUniqueKeyEntityLoaderStandard implements SingleUniqueKeyEntityLoader {
private final EntityMappingType entityDescriptor;
private final SingularAttributeMapping uniqueKeyAttribute;
public SingleUniqueKeyEntityLoaderStandard(
EntityMappingType entityDescriptor,
SingularAttributeMapping uniqueKeyAttribute) {
this.entityDescriptor = entityDescriptor;
this.uniqueKeyAttribute = uniqueKeyAttribute;
}
@Override
public EntityMappingType getLoadable() {
return entityDescriptor;
}
@Override
public Object load(
Object ukValue,
LockOptions lockOptions,
SharedSessionContractImplementor session) {
throw new NotYetImplementedFor6Exception( getClass() );
}
}

View File

@ -1,163 +0,0 @@
/*
* 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.loader.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.hibernate.FetchMode;
import org.hibernate.Filter;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.loader.BasicLoader;
import org.hibernate.loader.OuterJoinableAssociation;
import org.hibernate.loader.PropertyPath;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.sql.JoinFragment;
import org.hibernate.sql.JoinType;
import org.hibernate.sql.Select;
import org.hibernate.type.AssociationType;
/**
* Walker for collections of values and many-to-many associations
*
* @see BasicCollectionLoader
* @author Gavin King
*/
public class BasicCollectionJoinWalker extends CollectionJoinWalker {
private final QueryableCollection collectionPersister;
public BasicCollectionJoinWalker(
QueryableCollection collectionPersister,
int batchSize,
String subquery,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
super( factory, loadQueryInfluencers );
this.collectionPersister = collectionPersister;
String alias = generateRootAlias( collectionPersister.getRole() );
walkCollectionTree(collectionPersister, alias);
List allAssociations = new ArrayList( associations );
allAssociations.add( OuterJoinableAssociation.createRoot( collectionPersister.getCollectionType(), alias, getFactory() ) );
initPersisters( allAssociations, LockMode.NONE );
initStatementString( alias, batchSize, subquery );
}
private void initStatementString(
final String alias,
final int batchSize,
final String subquery) throws MappingException {
final int joins = countEntityPersisters( associations );
final int collectionJoins = countCollectionPersisters( associations ) + 1;
suffixes = BasicLoader.generateSuffixes( joins );
collectionSuffixes = BasicLoader.generateSuffixes( joins, collectionJoins );
StringBuilder whereString = whereString(
alias,
collectionPersister.getKeyColumnNames(),
subquery,
batchSize
);
StringBuilder sb = null;
final Map<String, Filter> enabledFilters = getLoadQueryInfluencers().getEnabledFilters();
String filter = collectionPersister.filterFragment( alias, enabledFilters );
if ( collectionPersister.isManyToMany() ) {
// from the collection of associations, locate OJA for the
// ManyToOne corresponding to this persister to fully
// define the many-to-many; we need that OJA so that we can
// use its alias here
// TODO : is there a better way here?
Iterator itr = associations.iterator();
sb = new StringBuilder( 20 );
AssociationType associationType = ( AssociationType ) collectionPersister.getElementType();
while ( itr.hasNext() ) {
OuterJoinableAssociation oja = ( OuterJoinableAssociation ) itr.next();
if ( oja.getJoinableType() == associationType ) {
// we found it
filter += collectionPersister.getManyToManyFilterFragment(
oja.getRHSAlias(),
enabledFilters
);
sb.append( collectionPersister.getManyToManyOrderByString( oja.getRHSAlias() ) );
}
}
}
whereString.insert( 0, StringHelper.moveAndToBeginning( filter ) );
JoinFragment ojf = mergeOuterJoins(associations);
Select select = new Select( getDialect() )
.setSelectClause(
collectionPersister.selectFragment(alias, collectionSuffixes[0] ) +
selectString( associations )
)
.setFromClause( collectionPersister.getTableName(), alias )
.setWhereClause( whereString.toString() )
.setOuterJoins(
ojf.toFromFragmentString(),
ojf.toWhereFragmentString()
);
select.setOrderByClause( orderBy( associations, mergeOrderings( collectionPersister.getSQLOrderByString( alias ), sb == null ? "" : sb.toString() ) ) );
if ( getFactory().getSettings().isCommentsEnabled() ) {
select.setComment( "load collection " + collectionPersister.getRole() );
}
sql = select.toStatementString();
}
protected JoinType getJoinType(
OuterJoinLoadable persister,
PropertyPath path,
int propertyNumber,
AssociationType associationType,
FetchMode metadataFetchMode,
CascadeStyle metadataCascadeStyle,
String lhsTable,
String[] lhsColumns,
boolean nullable,
int currentDepth) throws MappingException {
JoinType joinType = super.getJoinType(
persister,
path,
propertyNumber,
associationType,
metadataFetchMode,
metadataCascadeStyle,
lhsTable,
lhsColumns,
nullable,
currentDepth
);
//we can use an inner join for the many-to-many
if ( joinType==JoinType.LEFT_OUTER_JOIN && path.isRoot() ) {
joinType=JoinType.INNER_JOIN;
}
return joinType;
}
public String toString() {
return getClass().getName() + '(' + collectionPersister.getRole() + ')';
}
}

View File

@ -1,69 +0,0 @@
/*
* 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.loader.collection;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.loader.JoinWalker;
import org.hibernate.persister.collection.QueryableCollection;
import org.jboss.logging.Logger;
/**
* Loads a collection of values or a many-to-many association.
* <br>
* The collection persister must implement <tt>QueryableCOllection<tt>. For
* other collections, create a customized subclass of <tt>Loader</tt>.
*
* @see OneToManyLoader
* @author Gavin King
*/
public class BasicCollectionLoader extends CollectionLoader {
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, BasicCollectionLoader.class.getName() );
public BasicCollectionLoader(
QueryableCollection collectionPersister,
SessionFactoryImplementor session,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
this( collectionPersister, 1, session, loadQueryInfluencers );
}
public BasicCollectionLoader(
QueryableCollection collectionPersister,
int batchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
this( collectionPersister, batchSize, null, factory, loadQueryInfluencers );
}
protected BasicCollectionLoader(
QueryableCollection collectionPersister,
int batchSize,
String subquery,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
super( collectionPersister, factory, loadQueryInfluencers );
JoinWalker walker = new BasicCollectionJoinWalker(
collectionPersister,
batchSize,
subquery,
factory,
loadQueryInfluencers
);
initFromWalker( walker );
postInstantiate();
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Static select for collection %s: %s", collectionPersister.getRole(), getSQLString() );
}
}
}

View File

@ -1,37 +0,0 @@
/*
* 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.loader.collection;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
/**
* The base contract for loaders capable of performing batch-fetch loading of collections using multiple foreign key
* values in the SQL <tt>WHERE</tt> clause.
*
* @author Gavin King
* @author Steve Ebersole
*
* @see BatchingCollectionInitializerBuilder
* @see BasicCollectionLoader
* @see OneToManyLoader
*/
public abstract class BatchingCollectionInitializer implements CollectionInitializer {
private final QueryableCollection collectionPersister;
public BatchingCollectionInitializer(QueryableCollection collectionPersister) {
this.collectionPersister = collectionPersister;
}
public CollectionPersister getCollectionPersister() {
return collectionPersister;
}
public QueryableCollection collectionPersister() {
return collectionPersister;
}
}

View File

@ -1,105 +0,0 @@
/*
* 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.loader.collection;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.collection.QueryableCollection;
/**
* Contract for building {@link CollectionInitializer} instances capable of performing batch-fetch loading.
*
* @author Steve Ebersole
*
* @see org.hibernate.loader.BatchFetchStyle
*/
public abstract class BatchingCollectionInitializerBuilder {
public static BatchingCollectionInitializerBuilder getBuilder(SessionFactoryImplementor factory) {
switch ( factory.getSettings().getBatchFetchStyle() ) {
case PADDED: {
return PaddedBatchingCollectionInitializerBuilder.INSTANCE;
}
case DYNAMIC: {
return DynamicBatchingCollectionInitializerBuilder.INSTANCE;
}
default: {
return org.hibernate.loader.collection.plan.LegacyBatchingCollectionInitializerBuilder.INSTANCE;
//return LegacyBatchingCollectionInitializerBuilder.INSTANCE;
}
}
}
/**
* Builds a batch-fetch capable CollectionInitializer for basic and many-to-many collections (collections with
* a dedicated collection table).
*
* @param persister THe collection persister
* @param maxBatchSize The maximum number of keys to batch-fetch together
* @param factory The SessionFactory
* @param influencers Any influencers that should affect the built query
*
* @return The batch-fetch capable collection initializer
*/
public CollectionInitializer createBatchingCollectionInitializer(
QueryableCollection persister,
int maxBatchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
if ( maxBatchSize <= 1 ) {
// no batching
return buildNonBatchingLoader( persister, factory, influencers );
}
return createRealBatchingCollectionInitializer( persister, maxBatchSize, factory, influencers );
}
protected abstract CollectionInitializer createRealBatchingCollectionInitializer(
QueryableCollection persister,
int maxBatchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers);
/**
* Builds a batch-fetch capable CollectionInitializer for one-to-many collections (collections without
* a dedicated collection table).
*
* @param persister THe collection persister
* @param maxBatchSize The maximum number of keys to batch-fetch together
* @param factory The SessionFactory
* @param influencers Any influencers that should affect the built query
*
* @return The batch-fetch capable collection initializer
*/
public CollectionInitializer createBatchingOneToManyInitializer(
QueryableCollection persister,
int maxBatchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
if ( maxBatchSize <= 1 ) {
// no batching
return buildNonBatchingLoader( persister, factory, influencers );
}
return createRealBatchingOneToManyInitializer( persister, maxBatchSize, factory, influencers );
}
protected abstract CollectionInitializer createRealBatchingOneToManyInitializer(
QueryableCollection persister,
int maxBatchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers);
protected CollectionInitializer buildNonBatchingLoader(
QueryableCollection persister,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return persister.isOneToMany() ?
new OneToManyLoader( persister, factory, influencers ) :
new BasicCollectionLoader( persister, factory, influencers );
}
}

View File

@ -1,23 +0,0 @@
/*
* 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.loader.collection;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* An interface for collection loaders
* @see BasicCollectionLoader
* @see OneToManyLoader
* @author Gavin King
*/
public interface CollectionInitializer {
/**
* Initialize the given collection
*/
void initialize(Object id, SharedSessionContractImplementor session) throws HibernateException;
}

View File

@ -1,46 +0,0 @@
/*
* 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.loader.collection;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.loader.JoinWalker;
/**
* Superclass of walkers for collection initializers
*
* @see CollectionLoader
* @see OneToManyJoinWalker
* @see BasicCollectionJoinWalker
* @author Gavin King
*/
public abstract class CollectionJoinWalker extends JoinWalker {
public CollectionJoinWalker(SessionFactoryImplementor factory, LoadQueryInfluencers loadQueryInfluencers) {
super( factory, loadQueryInfluencers );
}
protected StringBuilder whereString(String alias, String[] columnNames, String subselect, int batchSize) {
if (subselect==null) {
return whereString(alias, columnNames, batchSize);
}
else {
StringBuilder buf = new StringBuilder();
if (columnNames.length>1) {
buf.append('(');
}
buf.append( String.join(", ", StringHelper.qualify(alias, columnNames) ) );
if (columnNames.length>1) {
buf.append(')');
}
buf.append(" in ")
.append('(')
.append(subselect)
.append(')');
return buf;
}
}
}

View File

@ -1,58 +0,0 @@
/*
* 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.loader.collection;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.OuterJoinLoader;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.type.Type;
/**
* Superclass for loaders that initialize collections
*
* @see OneToManyLoader
* @see BasicCollectionLoader
* @author Gavin King
*/
public class CollectionLoader extends OuterJoinLoader implements CollectionInitializer {
private final QueryableCollection collectionPersister;
public CollectionLoader(
QueryableCollection collectionPersister,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
super( factory, loadQueryInfluencers );
this.collectionPersister = collectionPersister;
}
protected QueryableCollection collectionPersister() {
return collectionPersister;
}
@Override
protected boolean isSubselectLoadingEnabled() {
return hasSubselectLoadableCollections();
}
@Override
public void initialize(Object id, SharedSessionContractImplementor session) throws HibernateException {
loadCollection( session, id, getKeyType() );
}
protected Type getKeyType() {
return collectionPersister.getKeyType();
}
@Override
public String toString() {
return getClass().getName() + '(' + collectionPersister.getRole() + ')';
}
}

View File

@ -1,257 +0,0 @@
/*
* 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.loader.collection;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.JoinWalker;
import org.hibernate.loader.Loader;
import org.hibernate.loader.ast.spi.AfterLoadAction;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type;
/**
* A BatchingCollectionInitializerBuilder that builds CollectionInitializer instances capable of dynamically building
* its batch-fetch SQL based on the actual number of collections keys waiting to be fetched.
*
* @author Steve Ebersole
*/
public class DynamicBatchingCollectionInitializerBuilder extends BatchingCollectionInitializerBuilder {
public static final DynamicBatchingCollectionInitializerBuilder INSTANCE = new DynamicBatchingCollectionInitializerBuilder();
@Override
protected CollectionInitializer createRealBatchingCollectionInitializer(
QueryableCollection persister,
int maxBatchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return new DynamicBatchingCollectionInitializer( persister, maxBatchSize, factory, influencers );
}
@Override
protected CollectionInitializer createRealBatchingOneToManyInitializer(
QueryableCollection persister,
int maxBatchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return new DynamicBatchingCollectionInitializer( persister, maxBatchSize, factory, influencers );
}
public static class DynamicBatchingCollectionInitializer extends BatchingCollectionInitializer {
private final int maxBatchSize;
private final Loader singleKeyLoader;
private final DynamicBatchingCollectionLoader batchLoader;
public DynamicBatchingCollectionInitializer(
QueryableCollection collectionPersister,
int maxBatchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
super( collectionPersister );
this.maxBatchSize = maxBatchSize;
if ( collectionPersister.isOneToMany() ) {
this.singleKeyLoader = new OneToManyLoader( collectionPersister, 1, factory, influencers );
}
else {
this.singleKeyLoader = new BasicCollectionLoader( collectionPersister, 1, factory, influencers );
}
this.batchLoader = new DynamicBatchingCollectionLoader( collectionPersister, factory, influencers );
}
@Override
public void initialize(Object id, SharedSessionContractImplementor session) throws HibernateException {
// first, figure out how many batchable ids we have...
final Object[] batch = session.getPersistenceContextInternal()
.getBatchFetchQueue()
.getCollectionBatch( collectionPersister(), id, maxBatchSize );
final int numberOfIds = ArrayHelper.countNonNull( batch );
if ( numberOfIds <= 1 ) {
singleKeyLoader.loadCollection( session, id, collectionPersister().getKeyType() );
return;
}
final Serializable[] idsToLoad = new Serializable[numberOfIds];
System.arraycopy( batch, 0, idsToLoad, 0, numberOfIds );
batchLoader.doBatchedCollectionLoad( session, idsToLoad, collectionPersister().getKeyType() );
}
}
private static class DynamicBatchingCollectionLoader extends CollectionLoader {
// todo : this represents another case where the current Loader contract is unhelpful
// the other recent case was stored procedure support. Really any place where the SQL
// generation is dynamic but the "loading plan" remains constant. The long term plan
// is to split Loader into (a) PreparedStatement generation/execution and (b) ResultSet
// processing.
//
// Same holds true for org.hibernate.loader.entity.DynamicBatchingEntityLoaderBuilder.DynamicBatchingEntityLoader
//
// for now I will essentially semi-re-implement the collection loader contract here to be able to alter
// the SQL (specifically to be able to dynamically build the WHERE-clause IN-condition) later, when
// we actually know the ids to batch fetch
private final String sqlTemplate;
private final String alias;
public DynamicBatchingCollectionLoader(
QueryableCollection collectionPersister,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
super( collectionPersister, factory, influencers );
JoinWalker walker = buildJoinWalker( collectionPersister, factory, influencers );
initFromWalker( walker );
this.sqlTemplate = walker.getSQLString();
this.alias = StringHelper.generateAlias( collectionPersister.getRole(), 0 );
postInstantiate();
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"SQL-template for dynamic collection [%s] batch-fetching : %s",
collectionPersister.getRole(),
sqlTemplate
);
}
}
private JoinWalker buildJoinWalker(
QueryableCollection collectionPersister,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
if ( collectionPersister.isOneToMany() ) {
return new OneToManyJoinWalker( collectionPersister, -1, null, factory, influencers ) {
@Override
protected StringBuilder whereString(String alias, String[] columnNames, String subselect, int batchSize) {
if ( subselect != null ) {
return super.whereString( alias, columnNames, subselect, batchSize );
}
return StringHelper.buildBatchFetchRestrictionFragment( alias, columnNames, getFactory().getDialect() );
}
};
}
else {
return new BasicCollectionJoinWalker( collectionPersister, -1, null, factory, influencers ) {
@Override
protected StringBuilder whereString(String alias, String[] columnNames, String subselect, int batchSize) {
if ( subselect != null ) {
return super.whereString( alias, columnNames, subselect, batchSize );
}
return StringHelper.buildBatchFetchRestrictionFragment( alias, columnNames, getFactory().getDialect() );
}
};
}
}
public final void doBatchedCollectionLoad(
final SharedSessionContractImplementor session,
final Serializable[] ids,
final Type type) throws HibernateException {
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Batch loading collection: %s",
MessageHelper.collectionInfoString( getCollectionPersisters()[0], ids, getFactory() )
);
}
final Type[] idTypes = new Type[ids.length];
Arrays.fill( idTypes, type );
final QueryParameters queryParameters = new QueryParameters( idTypes, ids, ids );
final String sql = StringHelper.expandBatchIdPlaceholder(
sqlTemplate,
ids,
alias,
collectionPersister().getKeyColumnNames(),
session.getJdbcServices().getJdbcEnvironment().getDialect()
);
try {
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
boolean defaultReadOnlyOrig = persistenceContext.isDefaultReadOnly();
if ( queryParameters.isReadOnlyInitialized() ) {
// The read-only/modifiable mode for the query was explicitly set.
// Temporarily set the default read-only/modifiable setting to the query's setting.
persistenceContext.setDefaultReadOnly( queryParameters.isReadOnly() );
}
else {
// The read-only/modifiable setting for the query was not initialized.
// Use the default read-only/modifiable from the persistence context instead.
queryParameters.setReadOnly( persistenceContext.isDefaultReadOnly() );
}
persistenceContext.beforeLoad();
try {
try {
doTheLoad( sql, queryParameters, session );
}
finally {
persistenceContext.afterLoad();
}
persistenceContext.initializeNonLazyCollections();
}
finally {
// Restore the original default
persistenceContext.setDefaultReadOnly( defaultReadOnlyOrig );
}
}
catch ( SQLException e ) {
throw session.getJdbcServices().getSqlExceptionHelper().convert(
e,
"could not initialize a collection batch: " +
MessageHelper.collectionInfoString( collectionPersister(), ids, getFactory() ),
sql
);
}
LOG.debug( "Done batch load" );
}
private void doTheLoad(String sql, QueryParameters queryParameters, SharedSessionContractImplementor session) throws SQLException {
final RowSelection selection = queryParameters.getRowSelection();
final int maxRows = LimitHelper.hasMaxRows( selection ) ?
selection.getMaxRows() :
Integer.MAX_VALUE;
final List<AfterLoadAction> afterLoadActions = Collections.emptyList();
final SqlStatementWrapper wrapper = executeQueryStatement( sql, queryParameters, false, afterLoadActions, session );
final ResultSet rs = wrapper.getResultSet();
final Statement st = wrapper.getStatement();
try {
processResultSet( rs, queryParameters, session, true, null, maxRows, afterLoadActions );
}
finally {
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( st );
session.getJdbcCoordinator().afterStatementExecution();
}
}
}
}

View File

@ -1,86 +0,0 @@
/*
* 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.loader.collection;
import java.io.Serializable;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.Loader;
import org.hibernate.persister.collection.QueryableCollection;
/**
* @author Steve Ebersole
*/
public class LegacyBatchingCollectionInitializerBuilder extends BatchingCollectionInitializerBuilder {
public static final LegacyBatchingCollectionInitializerBuilder INSTANCE = new LegacyBatchingCollectionInitializerBuilder();
@Override
protected CollectionInitializer createRealBatchingCollectionInitializer(
QueryableCollection persister,
int maxBatchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
int[] batchSizes = ArrayHelper.getBatchSizes( maxBatchSize );
Loader[] loaders = new Loader[ batchSizes.length ];
for ( int i = 0; i < batchSizes.length; i++ ) {
loaders[i] = new BasicCollectionLoader( persister, batchSizes[i], factory, loadQueryInfluencers );
}
return new LegacyBatchingCollectionInitializer( persister, batchSizes, loaders );
}
@Override
protected CollectionInitializer createRealBatchingOneToManyInitializer(
QueryableCollection persister,
int maxBatchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
final int[] batchSizes = ArrayHelper.getBatchSizes( maxBatchSize );
final Loader[] loaders = new Loader[ batchSizes.length ];
for ( int i = 0; i < batchSizes.length; i++ ) {
loaders[i] = new OneToManyLoader( persister, batchSizes[i], factory, loadQueryInfluencers );
}
return new LegacyBatchingCollectionInitializer( persister, batchSizes, loaders );
}
public static class LegacyBatchingCollectionInitializer extends BatchingCollectionInitializer {
private final int[] batchSizes;
private final Loader[] loaders;
public LegacyBatchingCollectionInitializer(
QueryableCollection persister,
int[] batchSizes,
Loader[] loaders) {
super( persister );
this.batchSizes = batchSizes;
this.loaders = loaders;
}
@Override
public void initialize(Object id, SharedSessionContractImplementor session) throws HibernateException {
final Object[] batch = session.getPersistenceContextInternal().getBatchFetchQueue()
.getCollectionBatch( collectionPersister(), id, batchSizes[0] );
for ( int i=0; i<batchSizes.length-1; i++) {
final int smallBatchSize = batchSizes[i];
if ( batch[smallBatchSize-1]!=null ) {
Serializable[] smallBatch = new Serializable[smallBatchSize];
System.arraycopy(batch, 0, smallBatch, 0, smallBatchSize);
loaders[i].loadCollectionBatch( session, smallBatch, collectionPersister().getKeyType() );
return; //EARLY EXIT!
}
}
loaders[batchSizes.length-1].loadCollection( session, id, collectionPersister().getKeyType() );
}
}
}

View File

@ -1,133 +0,0 @@
/*
* 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.loader.collection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.loader.BasicLoader;
import org.hibernate.loader.OuterJoinableAssociation;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.sql.JoinFragment;
import org.hibernate.sql.Select;
/**
* Walker for one-to-many associations
*
* @author Gavin King
* @see OneToManyLoader
*/
public class OneToManyJoinWalker extends CollectionJoinWalker {
private final QueryableCollection oneToManyPersister;
@Override
protected boolean isDuplicateAssociation(
final String foreignKeyTable,
final String[] foreignKeyColumns) {
//disable a join back to this same association
final boolean isSameJoin = oneToManyPersister.getTableName().equals( foreignKeyTable ) &&
Arrays.equals( foreignKeyColumns, oneToManyPersister.getKeyColumnNames() );
return isSameJoin ||
super.isDuplicateAssociation( foreignKeyTable, foreignKeyColumns );
}
public OneToManyJoinWalker(
QueryableCollection oneToManyPersister,
int batchSize,
String subquery,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
super( factory, loadQueryInfluencers );
this.oneToManyPersister = oneToManyPersister;
final OuterJoinLoadable elementPersister = (OuterJoinLoadable) oneToManyPersister.getElementPersister();
final String alias = generateRootAlias( oneToManyPersister.getRole() );
walkEntityTree( elementPersister, alias );
List allAssociations = new ArrayList( associations );
allAssociations.add(
OuterJoinableAssociation.createRoot(
oneToManyPersister.getCollectionType(),
alias,
getFactory()
)
);
initPersisters( allAssociations, LockMode.NONE );
initStatementString( elementPersister, alias, batchSize, subquery );
}
private void initStatementString(
final OuterJoinLoadable elementPersister,
final String alias,
final int batchSize,
final String subquery)
throws MappingException {
final int joins = countEntityPersisters( associations );
suffixes = BasicLoader.generateSuffixes( joins + 1 );
final int collectionJoins = countCollectionPersisters( associations ) + 1;
collectionSuffixes = BasicLoader.generateSuffixes( joins + 1, collectionJoins );
StringBuilder whereString = whereString(
alias,
oneToManyPersister.getKeyColumnNames(),
subquery,
batchSize
);
String filter = oneToManyPersister.filterFragment( alias, getLoadQueryInfluencers().getEnabledFilters() );
whereString.insert( 0, StringHelper.moveAndToBeginning( filter ) );
JoinFragment ojf = mergeOuterJoins( associations );
Select select = new Select( getDialect() )
.setSelectClause(
oneToManyPersister.selectFragment(
null,
null,
alias,
suffixes[joins],
collectionSuffixes[0],
true
) +
selectString( associations )
)
.setFromClause(
elementPersister.fromTableFragment( alias ) +
elementPersister.fromJoinFragment( alias, true, true )
)
.setWhereClause( whereString.toString() )
.setOuterJoins(
ojf.toFromFragmentString(),
ojf.toWhereFragmentString() +
elementPersister.whereJoinFragment( alias, true, true )
);
select.setOrderByClause( orderBy( associations, oneToManyPersister.getSQLOrderByString( alias ) ) );
if ( getFactory().getSessionFactoryOptions().isCommentsEnabled() ) {
select.setComment( "load one-to-many " + oneToManyPersister.getRole() );
}
sql = select.toStatementString();
}
@Override
public String toString() {
return getClass().getName() + '(' + oneToManyPersister.getRole() + ')';
}
}

View File

@ -1,68 +0,0 @@
/*
* 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.loader.collection;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.loader.JoinWalker;
import org.hibernate.persister.collection.QueryableCollection;
import org.jboss.logging.Logger;
/**
* Loads one-to-many associations<br>
* <br>
* The collection persister must implement <tt>QueryableCOllection<tt>. For
* other collections, create a customized subclass of <tt>Loader</tt>.
*
* @see BasicCollectionLoader
* @author Gavin King
*/
public class OneToManyLoader extends CollectionLoader {
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, OneToManyLoader.class.getName() );
public OneToManyLoader(
QueryableCollection oneToManyPersister,
SessionFactoryImplementor session,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
this( oneToManyPersister, 1, session, loadQueryInfluencers );
}
public OneToManyLoader(
QueryableCollection oneToManyPersister,
int batchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
this( oneToManyPersister, batchSize, null, factory, loadQueryInfluencers );
}
public OneToManyLoader(
QueryableCollection oneToManyPersister,
int batchSize,
String subquery,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
super( oneToManyPersister, factory, loadQueryInfluencers );
JoinWalker walker = new OneToManyJoinWalker(
oneToManyPersister,
batchSize,
subquery,
factory,
loadQueryInfluencers
);
initFromWalker( walker );
postInstantiate();
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Static select for one-to-many %s: %s", oneToManyPersister.getRole(), getSQLString() );
}
}
}

View File

@ -1,102 +0,0 @@
/*
* 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.loader.collection;
import java.io.Serializable;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.Loader;
import org.hibernate.persister.collection.QueryableCollection;
/**
* A batch-fetch capable CollectionInitializer that performs batch-fetching using the padded style. See
* {@link org.hibernate.loader.BatchFetchStyle} for a discussion of the different styles.
*
* @author Steve Ebersole
*
* @see org.hibernate.loader.BatchFetchStyle#PADDED
*/
public class PaddedBatchingCollectionInitializerBuilder extends BatchingCollectionInitializerBuilder {
public static final PaddedBatchingCollectionInitializerBuilder INSTANCE = new PaddedBatchingCollectionInitializerBuilder();
@Override
public CollectionInitializer createRealBatchingCollectionInitializer(
QueryableCollection persister,
int maxBatchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
int[] batchSizes = ArrayHelper.getBatchSizes( maxBatchSize );
Loader[] loaders = new Loader[ batchSizes.length ];
for ( int i = 0; i < batchSizes.length; i++ ) {
loaders[i] = new BasicCollectionLoader( persister, batchSizes[i], factory, loadQueryInfluencers );
}
return new PaddedBatchingCollectionInitializer( persister, batchSizes, loaders );
}
@Override
public CollectionInitializer createRealBatchingOneToManyInitializer(
QueryableCollection persister,
int maxBatchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
final int[] batchSizes = ArrayHelper.getBatchSizes( maxBatchSize );
final Loader[] loaders = new Loader[ batchSizes.length ];
for ( int i = 0; i < batchSizes.length; i++ ) {
loaders[i] = new OneToManyLoader( persister, batchSizes[i], factory, loadQueryInfluencers );
}
return new PaddedBatchingCollectionInitializer( persister, batchSizes, loaders );
}
private static class PaddedBatchingCollectionInitializer extends BatchingCollectionInitializer {
private final int[] batchSizes;
private final Loader[] loaders;
public PaddedBatchingCollectionInitializer(QueryableCollection persister, int[] batchSizes, Loader[] loaders) {
super( persister );
this.batchSizes = batchSizes;
this.loaders = loaders;
}
@Override
public void initialize(Object id, SharedSessionContractImplementor session) throws HibernateException {
final Object[] batch = session.getPersistenceContextInternal()
.getBatchFetchQueue()
.getCollectionBatch( collectionPersister(), id, batchSizes[0] );
final int numberOfIds = ArrayHelper.countNonNull( batch );
if ( numberOfIds <= 1 ) {
loaders[batchSizes.length-1].loadCollection( session, id, collectionPersister().getKeyType() );
return;
}
// Uses the first batch-size bigger than the number of actual ids in the batch
int indexToUse = batchSizes.length-1;
for ( int i = 0; i < batchSizes.length-1; i++ ) {
if ( batchSizes[i] >= numberOfIds ) {
indexToUse = i;
}
else {
break;
}
}
final Serializable[] idsToLoad = new Serializable[ batchSizes[indexToUse] ];
System.arraycopy( batch, 0, idsToLoad, 0, numberOfIds );
for ( int i = numberOfIds; i < batchSizes[indexToUse]; i++ ) {
idsToLoad[i] = (Serializable) id;
}
loaders[indexToUse].loadCollectionBatch( session, idsToLoad, collectionPersister().getKeyType() );
}
}
}

View File

@ -1,79 +0,0 @@
/*
* 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.loader.collection;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.type.Type;
/**
* Implements subselect fetching for a collection
* @author Gavin King
*/
public class SubselectCollectionLoader extends BasicCollectionLoader {
private final Serializable[] keys;
private final Type[] types;
private final Object[] values;
private final Map<String, TypedValue> namedParameters;
private final Map<String, int[]> namedParameterLocMap;
public SubselectCollectionLoader(
QueryableCollection persister,
String subquery,
Collection entityKeys,
QueryParameters queryParameters,
Map<String, int[]> namedParameterLocMap,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
super( persister, 1, subquery, factory, loadQueryInfluencers );
keys = new Serializable[ entityKeys.size() ];
Iterator iter = entityKeys.iterator();
int i=0;
while ( iter.hasNext() ) {
keys[i++] = ( (EntityKey) iter.next() ).getIdentifier();
}
this.namedParameters = queryParameters.getNamedParameters();
this.types = queryParameters.getFilteredPositionalParameterTypes();
this.values = queryParameters.getFilteredPositionalParameterValues();
this.namedParameterLocMap = namedParameterLocMap;
}
@Override
public void initialize(Object id, SharedSessionContractImplementor session)
throws HibernateException {
loadCollectionSubselect(
session,
keys,
values,
types,
namedParameters,
getKeyType()
);
}
@Override
public int[] getNamedParameterLocs(String name) {
return namedParameterLocMap.get( name );
}
}

View File

@ -1,76 +0,0 @@
/*
* 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.loader.collection;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.type.Type;
/**
* Implements subselect fetching for a one to many association
* @author Gavin King
*/
public class SubselectOneToManyLoader extends OneToManyLoader {
private final Serializable[] keys;
private final Type[] types;
private final Object[] values;
private final Map<String, TypedValue> namedParameters;
private final Map<String, int[]> namedParameterLocMap;
public SubselectOneToManyLoader(
QueryableCollection persister,
String subquery,
Collection entityKeys,
QueryParameters queryParameters,
Map<String, int[]> namedParameterLocMap,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
super( persister, 1, subquery, factory, loadQueryInfluencers );
keys = new Serializable[ entityKeys.size() ];
Iterator iter = entityKeys.iterator();
int i=0;
while ( iter.hasNext() ) {
keys[i++] = ( (EntityKey) iter.next() ).getIdentifier();
}
this.namedParameters = queryParameters.getNamedParameters();
this.types = queryParameters.getFilteredPositionalParameterTypes();
this.values = queryParameters.getFilteredPositionalParameterValues();
this.namedParameterLocMap = namedParameterLocMap;
}
@Override
public void initialize(Object id, SharedSessionContractImplementor session) throws HibernateException {
loadCollectionSubselect(
session,
keys,
values,
types,
namedParameters,
getKeyType()
);
}
@Override
public int[] getNamedParameterLocs(String name) {
return namedParameterLocMap.get( name );
}
}

View File

@ -1,15 +0,0 @@
<!--
~ 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>.
-->
<html>
<head></head>
<body>
<p>
This package defines collection initializers
</p>
</body>
</html>

View File

@ -1,30 +0,0 @@
/*
* 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.loader.collection.plan;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.collection.BatchingCollectionInitializerBuilder;
import org.hibernate.loader.collection.CollectionInitializer;
import org.hibernate.persister.collection.QueryableCollection;
/**
* Base class for LoadPlan-based BatchingCollectionInitializerBuilder implementations. Mainly we handle the common
* "no batching" case here to use the LoadPlan-based CollectionLoader
*
* @author Gail Badner
*/
public abstract class AbstractBatchingCollectionInitializerBuilder extends BatchingCollectionInitializerBuilder {
@Override
protected CollectionInitializer buildNonBatchingLoader(
QueryableCollection persister,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return CollectionLoader.forCollection( persister ).withInfluencers( influencers ).byKey();
}
}

View File

@ -1,126 +0,0 @@
/*
* 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.loader.collection.plan;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.loader.collection.CollectionInitializer;
import org.hibernate.loader.plan.build.internal.FetchStyleLoadPlanBuildingAssociationVisitationStrategy;
import org.hibernate.loader.plan.build.spi.MetamodelDrivenLoadPlanBuilder;
import org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader;
import org.hibernate.loader.plan.exec.internal.BatchingLoadQueryDetailsFactory;
import org.hibernate.loader.plan.exec.query.spi.QueryBuildingParameters;
import org.hibernate.loader.plan.exec.spi.LoadQueryDetails;
import org.hibernate.loader.plan.spi.LoadPlan;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type;
/**
* An abstract {@link CollectionInitializer} implementation based on using LoadPlans
*
* @author Gail Badner
*/
public abstract class AbstractLoadPlanBasedCollectionInitializer
extends AbstractLoadPlanBasedLoader implements CollectionInitializer {
private static final CoreMessageLogger log = CoreLogging.messageLogger( AbstractLoadPlanBasedCollectionInitializer.class );
private final QueryableCollection collectionPersister;
private final LoadQueryDetails staticLoadQuery;
private final LockOptions lockOptions;
public AbstractLoadPlanBasedCollectionInitializer(
QueryableCollection collectionPersister,
QueryBuildingParameters buildingParameters) {
super( collectionPersister.getFactory() );
this.collectionPersister = collectionPersister;
this.lockOptions = buildingParameters.getLockMode() != null
? new LockOptions( buildingParameters.getLockMode() )
: buildingParameters.getLockOptions();
final FetchStyleLoadPlanBuildingAssociationVisitationStrategy strategy =
new FetchStyleLoadPlanBuildingAssociationVisitationStrategy(
collectionPersister.getFactory(),
buildingParameters.getQueryInfluencers(),
this.lockOptions.getLockMode()
);
final LoadPlan plan = MetamodelDrivenLoadPlanBuilder.buildRootCollectionLoadPlan( strategy, collectionPersister );
this.staticLoadQuery = BatchingLoadQueryDetailsFactory.INSTANCE.makeCollectionLoadQueryDetails(
collectionPersister,
plan,
buildingParameters
);
}
@Override
public void initialize(Object id, SharedSessionContractImplementor session)
throws HibernateException {
if ( log.isDebugEnabled() ) {
log.debugf( "Loading collection: %s",
MessageHelper.collectionInfoString( collectionPersister, id, getFactory() ) );
}
final Serializable[] ids = new Serializable[] {(Serializable) id};
try {
final QueryParameters qp = new QueryParameters();
qp.setPositionalParameterTypes( new Type[]{ collectionPersister.getKeyType() } );
qp.setPositionalParameterValues( ids );
qp.setCollectionKeys( ids );
qp.setLockOptions( lockOptions );
executeLoad(
session,
qp,
staticLoadQuery,
true,
null
);
}
catch ( SQLException sqle ) {
throw session.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not initialize a collection: " +
MessageHelper.collectionInfoString( collectionPersister, id, getFactory() ),
staticLoadQuery.getSqlStatement()
);
}
log.debug( "Done loading collection" );
}
protected QueryableCollection collectionPersister() {
return collectionPersister;
}
@Override
protected LoadQueryDetails getStaticLoadQuery() {
return staticLoadQuery;
}
@Override
protected int[] getNamedParameterLocs(String name) {
throw new AssertionFailure("no named parameters");
}
@Override
protected void autoDiscoverTypes(ResultSet rs) {
throw new AssertionFailure("Auto discover types not supported in this loader");
}
}

View File

@ -1,34 +0,0 @@
/*
* 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.loader.collection.plan;
import org.hibernate.loader.collection.CollectionInitializer;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
/**
* The base contract for loaders capable of performing batch-fetch loading of collections using multiple foreign key
* values in the SQL <tt>WHERE</tt> clause.
*
* @author Gavin King
* @author Steve Ebersole
*
* @see org.hibernate.loader.collection.BatchingCollectionInitializerBuilder
* @see org.hibernate.loader.collection.BasicCollectionLoader
* @see org.hibernate.loader.collection.OneToManyLoader
*/
public abstract class BatchingCollectionInitializer implements CollectionInitializer {
private final QueryableCollection collectionPersister;
public BatchingCollectionInitializer(QueryableCollection collectionPersister) {
this.collectionPersister = collectionPersister;
}
public CollectionPersister getCollectionPersister() {
return collectionPersister;
}
}

View File

@ -1,98 +0,0 @@
/*
* 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.loader.collection.plan;
import java.sql.ResultSet;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.internal.CoreLogging;
import org.hibernate.loader.plan.exec.query.internal.QueryBuildingParametersImpl;
import org.hibernate.loader.plan.exec.query.spi.QueryBuildingParameters;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
/**
* Superclass for loaders that initialize collections
*
* @see org.hibernate.loader.collection.OneToManyLoader
* @see org.hibernate.loader.collection.BasicCollectionLoader
* @author Gavin King
* @author Gail Badner
*/
public class CollectionLoader extends AbstractLoadPlanBasedCollectionInitializer {
private static final Logger log = CoreLogging.logger( CollectionLoader.class );
public static Builder forCollection(QueryableCollection collectionPersister) {
return new Builder( collectionPersister );
}
@Override
protected int[] getNamedParameterLocs(String name) {
return new int[0]; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
protected void autoDiscoverTypes(ResultSet rs) {
//To change body of implemented methods use File | Settings | File Templates.
}
protected static class Builder {
private final QueryableCollection collectionPersister;
private int batchSize = 1;
private LoadQueryInfluencers influencers = LoadQueryInfluencers.NONE;
private Builder(QueryableCollection collectionPersister) {
this.collectionPersister = collectionPersister;
}
public Builder withBatchSize(int batchSize) {
this.batchSize = batchSize;
return this;
}
public Builder withInfluencers(LoadQueryInfluencers influencers) {
this.influencers = influencers;
return this;
}
public CollectionLoader byKey() {
// capture current values in a new instance of QueryBuildingParametersImpl
final QueryBuildingParameters currentBuildingParameters = new QueryBuildingParametersImpl(
influencers,
batchSize,
LockMode.NONE,
null
);
return new CollectionLoader( collectionPersister, currentBuildingParameters ) ;
}
}
public CollectionLoader(
QueryableCollection collectionPersister,
QueryBuildingParameters buildingParameters) {
super( collectionPersister, buildingParameters );
if ( log.isDebugEnabled() ) {
log.debugf(
"Static select for collection %s: %s",
collectionPersister.getRole(),
getStaticLoadQuery().getSqlStatement()
);
}
}
protected Type getKeyType() {
return collectionPersister().getKeyType();
}
public String toString() {
return getClass().getName() + '(' + collectionPersister().getRole() + ')';
}
}

View File

@ -1,95 +0,0 @@
/*
* 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.loader.collection.plan;
import java.io.Serializable;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.Loader;
import org.hibernate.loader.collection.BasicCollectionLoader;
import org.hibernate.loader.collection.CollectionInitializer;
import org.hibernate.loader.collection.OneToManyLoader;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.type.Type;
/**
* LoadPlan-based implementation of the the legacy batch collection initializer.
*
* @author Steve Ebersole
*/
public class LegacyBatchingCollectionInitializerBuilder extends AbstractBatchingCollectionInitializerBuilder {
public static final LegacyBatchingCollectionInitializerBuilder INSTANCE = new LegacyBatchingCollectionInitializerBuilder();
@Override
public CollectionInitializer createRealBatchingCollectionInitializer(
QueryableCollection persister,
int maxBatchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
int[] batchSizes = ArrayHelper.getBatchSizes( maxBatchSize );
Loader[] loaders = new Loader[ batchSizes.length ];
for ( int i = 0; i < batchSizes.length; i++ ) {
loaders[i] = new BasicCollectionLoader( persister, batchSizes[i], factory, loadQueryInfluencers );
}
return new LegacyBatchingCollectionInitializer( persister, batchSizes, loaders );
}
@Override
public CollectionInitializer createRealBatchingOneToManyInitializer(
QueryableCollection persister,
int maxBatchSize,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
final int[] batchSizes = ArrayHelper.getBatchSizes( maxBatchSize );
final Loader[] loaders = new Loader[ batchSizes.length ];
for ( int i = 0; i < batchSizes.length; i++ ) {
loaders[i] = new OneToManyLoader( persister, batchSizes[i], factory, loadQueryInfluencers );
}
return new LegacyBatchingCollectionInitializer( persister, batchSizes, loaders );
}
public static class LegacyBatchingCollectionInitializer extends BatchingCollectionInitializer {
private final int[] batchSizes;
private final Loader[] loaders;
public LegacyBatchingCollectionInitializer(
QueryableCollection persister,
int[] batchSizes,
Loader[] loaders) {
super( persister );
this.batchSizes = batchSizes;
this.loaders = loaders;
}
@Override
public void initialize(Object id, SharedSessionContractImplementor session) throws HibernateException {
final CollectionPersister collectionPersister = getCollectionPersister();
Object[] batch = session.getPersistenceContext().getBatchFetchQueue()
.getCollectionBatch( collectionPersister, id, batchSizes[0] );
final Type keyType = collectionPersister.getKeyType();
for ( int i = 0; i < batchSizes.length - 1; i++ ) {
final int smallBatchSize = batchSizes[i];
if ( batch[smallBatchSize-1] != null ) {
Serializable[] smallBatch = new Serializable[smallBatchSize];
System.arraycopy(batch, 0, smallBatch, 0, smallBatchSize);
loaders[i].loadCollectionBatch( session, smallBatch, keyType );
return; //EARLY EXIT!
}
}
loaders[batchSizes.length-1].loadCollection( session, id, keyType );
}
}
}

View File

@ -1,41 +0,0 @@
/*
* 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.loader.custom;
import org.hibernate.LockMode;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.loader.EntityAliases;
/**
* Specifically a fetch return that refers to a collection association.
*
* @author Steve Ebersole
*/
public class CollectionFetchReturn extends FetchReturn {
private final CollectionAliases collectionAliases;
private final EntityAliases elementEntityAliases;
public CollectionFetchReturn(
String alias,
NonScalarReturn owner,
String ownerProperty,
CollectionAliases collectionAliases,
EntityAliases elementEntityAliases,
LockMode lockMode) {
super( owner, ownerProperty, alias, lockMode );
this.collectionAliases = collectionAliases;
this.elementEntityAliases = elementEntityAliases;
}
public CollectionAliases getCollectionAliases() {
return collectionAliases;
}
public EntityAliases getElementEntityAliases() {
return elementEntityAliases;
}
}

View File

@ -1,66 +0,0 @@
/*
* 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.loader.custom;
import org.hibernate.LockMode;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.loader.EntityAliases;
/**
* Represents a return which names a collection role; it
* is used in defining a custom query for loading an entity's
* collection in non-fetching scenarios (i.e., loading the collection
* itself as the "root" of the result).
*
* @author Steve Ebersole
*/
public class CollectionReturn extends NonScalarReturn {
private final String ownerEntityName;
private final String ownerProperty;
private final CollectionAliases collectionAliases;
private final EntityAliases elementEntityAliases;
public CollectionReturn(
String alias,
String ownerEntityName,
String ownerProperty,
CollectionAliases collectionAliases,
EntityAliases elementEntityAliases,
LockMode lockMode) {
super( alias, lockMode );
this.ownerEntityName = ownerEntityName;
this.ownerProperty = ownerProperty;
this.collectionAliases = collectionAliases;
this.elementEntityAliases = elementEntityAliases;
}
/**
* Returns the class owning the collection.
*
* @return The class owning the collection.
*/
public String getOwnerEntityName() {
return ownerEntityName;
}
/**
* Returns the name of the property representing the collection from the {@link #getOwnerEntityName}.
*
* @return The name of the property representing the collection on the owner class.
*/
public String getOwnerProperty() {
return ownerProperty;
}
public CollectionAliases getCollectionAliases() {
return collectionAliases;
}
public EntityAliases getElementEntityAliases() {
return elementEntityAliases;
}
}

View File

@ -1,136 +0,0 @@
/*
* 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.loader.custom;
import java.util.Map;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.SQLLoadableCollection;
/**
* CollectionAliases that uses columnnames instead of generated aliases.
* Aliases can still be overwritten via <return-property>
*
* @author Max Rydahl Andersen
*/
public class ColumnCollectionAliases implements CollectionAliases {
private final String[] keyAliases;
private final String[] indexAliases;
private final String[] elementAliases;
private final String identifierAlias;
private Map userProvidedAliases;
public ColumnCollectionAliases(Map userProvidedAliases, SQLLoadableCollection persister) {
this.userProvidedAliases = userProvidedAliases;
this.keyAliases = getUserProvidedAliases(
"key",
persister.getKeyColumnNames()
);
this.indexAliases = getUserProvidedAliases(
"index",
persister.getIndexColumnNames()
);
this.elementAliases = getUserProvidedAliases(
"element",
persister.getElementColumnNames()
);
this.identifierAlias = getUserProvidedAlias(
"id",
persister.getIdentifierColumnName()
);
}
/**
* Returns the suffixed result-set column-aliases for columns making up the key for this collection (i.e., its FK to
* its owner).
*
* @return The key result-set column aliases.
*/
public String[] getSuffixedKeyAliases() {
return keyAliases;
}
/**
* Returns the suffixed result-set column-aliases for the collumns making up the collection's index (map or list).
*
* @return The index result-set column aliases.
*/
public String[] getSuffixedIndexAliases() {
return indexAliases;
}
/**
* Returns the suffixed result-set column-aliases for the columns making up the collection's elements.
*
* @return The element result-set column aliases.
*/
public String[] getSuffixedElementAliases() {
return elementAliases;
}
/**
* Returns the suffixed result-set column-aliases for the column defining the collection's identifier (if any).
*
* @return The identifier result-set column aliases.
*/
public String getSuffixedIdentifierAlias() {
return identifierAlias;
}
/**
* Returns the suffix used to unique the column aliases for this particular alias set.
*
* @return The uniqued column alias suffix.
*/
public String getSuffix() {
return "";
}
@Override
public String toString() {
return super.toString() + " [ suffixedKeyAliases=[" + join( keyAliases ) +
"], suffixedIndexAliases=[" + join( indexAliases ) +
"], suffixedElementAliases=[" + join( elementAliases ) +
"], suffixedIdentifierAlias=[" + identifierAlias + "]]";
}
private String join(String[] aliases) {
if ( aliases == null ) {
return null;
}
return String.join( ", ", aliases );
}
private String[] getUserProvidedAliases(String propertyPath, String[] defaultAliases) {
String[] result = (String[]) userProvidedAliases.get( propertyPath );
if ( result == null ) {
return defaultAliases;
}
else {
return result;
}
}
private String getUserProvidedAlias(String propertyPath, String defaultAlias) {
String[] columns = (String[]) userProvidedAliases.get( propertyPath );
if ( columns == null ) {
return defaultAlias;
}
else {
return columns[0];
}
}
}

View File

@ -1,100 +0,0 @@
/*
* 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.loader.custom;
import java.lang.reflect.Constructor;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.type.PrimitiveWrapperHelper;
import org.hibernate.type.Type;
/**
* Represents a {@link javax.persistence.ConstructorResult} within the custom query.
*
* @author Steve Ebersole
*/
public class ConstructorResultColumnProcessor implements ResultColumnProcessor {
private final Class targetClass;
private final ScalarResultColumnProcessor[] scalarProcessors;
private Constructor constructor;
public ConstructorResultColumnProcessor(Class targetClass, ScalarResultColumnProcessor[] scalarProcessors) {
this.targetClass = targetClass;
this.scalarProcessors = scalarProcessors;
}
@Override
public void performDiscovery(JdbcResultMetadata metadata, List<Type> types, List<String> aliases) throws SQLException {
final List<Type> localTypes = new ArrayList<>();
for ( ScalarResultColumnProcessor scalar : scalarProcessors ) {
scalar.performDiscovery( metadata, localTypes, aliases );
}
types.addAll( localTypes );
constructor = resolveConstructor( targetClass, localTypes );
}
@Override
public Object extract(Object[] data, ResultSet resultSet, SharedSessionContractImplementor session)
throws SQLException, HibernateException {
if ( constructor == null ) {
throw new IllegalStateException( "Constructor to call was null" );
}
final Object[] args = new Object[ scalarProcessors.length ];
for ( int i = 0; i < scalarProcessors.length; i++ ) {
args[i] = scalarProcessors[i].extract( data, resultSet, session );
}
try {
return constructor.newInstance( args );
}
catch (Exception e) {
throw new HibernateException(
String.format( "Unable to call %s constructor", constructor.getDeclaringClass() ),
e
);
}
}
private static Constructor resolveConstructor(Class targetClass, List<Type> types) {
for ( Constructor constructor : targetClass.getConstructors() ) {
final Class[] argumentTypes = constructor.getParameterTypes();
if ( argumentTypes.length != types.size() ) {
continue;
}
boolean allMatched = true;
for ( int i = 0; i < argumentTypes.length; i++ ) {
if ( ! areAssignmentCompatible( argumentTypes[i], types.get( i ).getReturnedClass() ) ) {
allMatched = false;
break;
}
}
if ( !allMatched ) {
continue;
}
return constructor;
}
throw new IllegalArgumentException( "Could not locate appropriate constructor on class : " + targetClass.getName() );
}
@SuppressWarnings("unchecked")
private static boolean areAssignmentCompatible(Class argumentType, Class typeReturnedClass) {
return argumentType.isAssignableFrom( typeReturnedClass )
|| PrimitiveWrapperHelper.arePrimitiveWrapperEquivalents( argumentType, typeReturnedClass );
}
}

View File

@ -1,30 +0,0 @@
/*
* 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.loader.custom;
/**
* A return representing a {@link javax.persistence.ConstructorResult}
*
* @author Steve Ebersole
*/
public class ConstructorReturn implements Return {
private final Class targetClass;
private final ScalarReturn[] scalars;
public ConstructorReturn(Class targetClass, ScalarReturn[] scalars) {
this.targetClass = targetClass;
this.scalars = scalars;
}
public Class getTargetClass() {
return targetClass;
}
public ScalarReturn[] getScalars() {
return scalars;
}
}

View File

@ -1,548 +0,0 @@
/*
* 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.loader.custom;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.QueryException;
import org.hibernate.Session;
import org.hibernate.cache.spi.QueryKey;
import org.hibernate.cache.spi.QueryResultsCache;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.Loader;
import org.hibernate.loader.ast.spi.AfterLoadAction;
import org.hibernate.param.ParameterBinder;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.Type;
/**
* Extension point for loaders which use a SQL result set with "unexpected" column aliases.
*
* @author Gavin King
* @author Steve Ebersole
*/
public class CustomLoader extends Loader {
// Currently *not* cachable if autodiscover types is in effect (e.g. "select * ...")
private final String sql;
private final Set<Serializable> querySpaces = new HashSet<>();
private final List<ParameterBinder> paramValueBinders;
private final Queryable[] entityPersisters;
private final int[] entiytOwners;
private final EntityAliases[] entityAliases;
private final QueryableCollection[] collectionPersisters;
private final int[] collectionOwners;
private final CollectionAliases[] collectionAliases;
private final LockMode[] lockModes;
private boolean[] includeInResultRow;
// private final String[] sqlAliases;
// private final String[] sqlAliasSuffixes;
private final ResultRowProcessor rowProcessor;
// this is only needed (afaict) for processing results from the query cache;
// however, this cannot possibly work in the case of discovered types...
private Type[] resultTypes;
// this is only needed (afaict) for ResultTransformer processing...
private String[] transformerAliases;
public CustomLoader(CustomQuery customQuery, SessionFactoryImplementor factory) {
super( factory );
throw new NotYetImplementedFor6Exception( getClass() );
// this.sql = customQuery.getSQL();
// this.querySpaces.addAll( customQuery.getQuerySpaces() );
//
// this.paramValueBinders = customQuery.getParameterValueBinders();
//
// List<Queryable> entityPersisters = new ArrayList<>();
// List<Integer> entityOwners = new ArrayList<>();
// List<EntityAliases> entityAliases = new ArrayList<>();
//
// List<QueryableCollection> collectionPersisters = new ArrayList<>();
// List<Integer> collectionOwners = new ArrayList<>();
// List<CollectionAliases> collectionAliases = new ArrayList<>();
//
// List<LockMode> lockModes = new ArrayList<>();
// List<ResultColumnProcessor> resultColumnProcessors = new ArrayList<>();
// List<Return> nonScalarReturnList = new ArrayList<>();
// List<Type> resultTypes = new ArrayList<>();
// List<String> specifiedAliases = new ArrayList<>();
//
// int returnableCounter = 0;
// boolean hasScalars = false;
//
// List<Boolean> includeInResultRowList = new ArrayList<>();
//
// for ( Return rtn : customQuery.getCustomQueryReturns() ) {
// if ( rtn instanceof ScalarReturn ) {
// ScalarReturn scalarRtn = (ScalarReturn) rtn;
// resultTypes.add( scalarRtn.getType() );
// specifiedAliases.add( scalarRtn.getColumnAlias() );
// resultColumnProcessors.add(
// new ScalarResultColumnProcessor(
// StringHelper.unquote( scalarRtn.getColumnAlias(), factory.getJdbcServices().getDialect() ),
// scalarRtn.getType()
// )
// );
// includeInResultRowList.add( true );
// hasScalars = true;
// }
// else if ( ConstructorReturn.class.isInstance( rtn ) ) {
// final ConstructorReturn constructorReturn = (ConstructorReturn) rtn;
// resultTypes.add( null ); // this bit makes me nervous
// includeInResultRowList.add( true );
// hasScalars = true;
//
// ScalarResultColumnProcessor[] scalarProcessors = new ScalarResultColumnProcessor[constructorReturn.getScalars().length];
// int i = 0;
// for ( ScalarReturn scalarReturn : constructorReturn.getScalars() ) {
// scalarProcessors[i++] = new ScalarResultColumnProcessor(
// StringHelper.unquote( scalarReturn.getColumnAlias(), factory.getJdbcServices().getDialect() ),
// scalarReturn.getType()
// );
// }
//
// resultColumnProcessors.add(
// new ConstructorResultColumnProcessor( constructorReturn.getTargetClass(), scalarProcessors )
// );
// }
// else if ( rtn instanceof RootReturn ) {
// RootReturn rootRtn = (RootReturn) rtn;
// Queryable persister = (Queryable) factory.getMetamodel().entityPersister( rootRtn.getEntityName() );
// entityPersisters.add( persister );
// lockModes.add( ( rootRtn.getLockMode() ) );
// resultColumnProcessors.add( new NonScalarResultColumnProcessor( returnableCounter++ ) );
// nonScalarReturnList.add( rtn );
// entityOwners.add( -1 );
// resultTypes.add( persister.getType() );
// specifiedAliases.add( rootRtn.getAlias() );
// entityAliases.add( rootRtn.getEntityAliases() );
// ArrayHelper.addAll( querySpaces, persister.getQuerySpaces() );
// includeInResultRowList.add( true );
// }
// else if ( rtn instanceof CollectionReturn ) {
// CollectionReturn collRtn = (CollectionReturn) rtn;
// String role = collRtn.getOwnerEntityName() + "." + collRtn.getOwnerProperty();
// QueryableCollection persister = (QueryableCollection) factory.getMetamodel().collectionPersister( role );
// collectionPersisters.add( persister );
// lockModes.add( collRtn.getLockMode() );
// resultColumnProcessors.add( new NonScalarResultColumnProcessor( returnableCounter++ ) );
// nonScalarReturnList.add( rtn );
// collectionOwners.add( -1 );
// resultTypes.add( persister.getType() );
// specifiedAliases.add( collRtn.getAlias() );
// collectionAliases.add( collRtn.getCollectionAliases() );
// // determine if the collection elements are entities...
// Type elementType = persister.getElementType();
// if ( elementType.isEntityType() ) {
// Queryable elementPersister = (Queryable) ( (EntityType) elementType ).getAssociatedJoinable( factory );
// entityPersisters.add( elementPersister );
// entityOwners.add( -1 );
// entityAliases.add( collRtn.getElementEntityAliases() );
// ArrayHelper.addAll( querySpaces, elementPersister.getQuerySpaces() );
// }
// includeInResultRowList.add( true );
// }
// else if ( rtn instanceof EntityFetchReturn ) {
// EntityFetchReturn fetchRtn = (EntityFetchReturn) rtn;
// NonScalarReturn ownerDescriptor = fetchRtn.getOwner();
// int ownerIndex = nonScalarReturnList.indexOf( ownerDescriptor );
// entityOwners.add( ownerIndex );
// lockModes.add( fetchRtn.getLockMode() );
// Queryable ownerPersister = determineAppropriateOwnerPersister( ownerDescriptor );
// EntityType fetchedType = (EntityType) ownerPersister.getPropertyType( fetchRtn.getOwnerProperty() );
// String entityName = fetchedType.getAssociatedEntityName( getFactory() );
// Queryable persister = (Queryable) factory.getMetamodel().entityPersister( entityName );
// entityPersisters.add( persister );
// nonScalarReturnList.add( rtn );
// specifiedAliases.add( fetchRtn.getAlias() );
// entityAliases.add( fetchRtn.getEntityAliases() );
// ArrayHelper.addAll( querySpaces, persister.getQuerySpaces() );
// includeInResultRowList.add( false );
// }
// else if ( rtn instanceof CollectionFetchReturn ) {
// CollectionFetchReturn fetchRtn = (CollectionFetchReturn) rtn;
// NonScalarReturn ownerDescriptor = fetchRtn.getOwner();
// int ownerIndex = nonScalarReturnList.indexOf( ownerDescriptor );
// collectionOwners.add( ownerIndex );
// lockModes.add( fetchRtn.getLockMode() );
// Queryable ownerPersister = determineAppropriateOwnerPersister( ownerDescriptor );
// String role = ownerPersister.getEntityName() + '.' + fetchRtn.getOwnerProperty();
// QueryableCollection persister = (QueryableCollection) factory.getMetamodel().collectionPersister( role );
// collectionPersisters.add( persister );
// nonScalarReturnList.add( rtn );
// specifiedAliases.add( fetchRtn.getAlias() );
// collectionAliases.add( fetchRtn.getCollectionAliases() );
// // determine if the collection elements are entities...
// Type elementType = persister.getElementType();
// if ( elementType.isEntityType() ) {
// Queryable elementPersister = (Queryable) ( (EntityType) elementType ).getAssociatedJoinable( factory );
// entityPersisters.add( elementPersister );
// entityOwners.add( ownerIndex );
// entityAliases.add( fetchRtn.getElementEntityAliases() );
// ArrayHelper.addAll( querySpaces, elementPersister.getQuerySpaces() );
// }
// includeInResultRowList.add( false );
// }
// else {
// throw new HibernateException( "unexpected custom query return type : " + rtn.getClass().getName() );
// }
// }
//
// this.entityPersisters = new Queryable[entityPersisters.size()];
// for ( int i = 0; i < entityPersisters.size(); i++ ) {
// this.entityPersisters[i] = entityPersisters.get( i );
// }
// this.entiytOwners = ArrayHelper.toIntArray( entityOwners );
// this.entityAliases = new EntityAliases[entityAliases.size()];
// for ( int i = 0; i < entityAliases.size(); i++ ) {
// this.entityAliases[i] = entityAliases.get( i );
// }
//
// this.collectionPersisters = new QueryableCollection[collectionPersisters.size()];
// for ( int i = 0; i < collectionPersisters.size(); i++ ) {
// this.collectionPersisters[i] = collectionPersisters.get( i );
// }
// this.collectionOwners = ArrayHelper.toIntArray( collectionOwners );
// this.collectionAliases = new CollectionAliases[collectionAliases.size()];
// for ( int i = 0; i < collectionAliases.size(); i++ ) {
// this.collectionAliases[i] = collectionAliases.get( i );
// }
//
// this.lockModes = new LockMode[lockModes.size()];
// for ( int i = 0; i < lockModes.size(); i++ ) {
// this.lockModes[i] = lockModes.get( i );
// }
//
// this.resultTypes = ArrayHelper.toTypeArray( resultTypes );
// this.transformerAliases = ArrayHelper.toStringArray( specifiedAliases );
//
// this.rowProcessor = new ResultRowProcessor(
// hasScalars,
// resultColumnProcessors.toArray( new ResultColumnProcessor[resultColumnProcessors.size()] )
// );
//
// this.includeInResultRow = ArrayHelper.toBooleanArray( includeInResultRowList );
}
// private Queryable determineAppropriateOwnerPersister(NonScalarReturn ownerDescriptor) {
// String entityName = null;
// if ( ownerDescriptor instanceof RootReturn ) {
// entityName = ( (RootReturn) ownerDescriptor ).getEntityName();
// }
// else if ( ownerDescriptor instanceof CollectionReturn ) {
// CollectionReturn collRtn = (CollectionReturn) ownerDescriptor;
// String role = collRtn.getOwnerEntityName() + "." + collRtn.getOwnerProperty();
// CollectionPersister persister = getFactory().getMetamodel().collectionPersister( role );
// EntityType ownerType = (EntityType) persister.getElementType();
// entityName = ownerType.getAssociatedEntityName( getFactory() );
// }
// else if ( ownerDescriptor instanceof FetchReturn ) {
// FetchReturn fetchRtn = (FetchReturn) ownerDescriptor;
// Queryable persister = determineAppropriateOwnerPersister( fetchRtn.getOwner() );
// Type ownerType = persister.getPropertyType( fetchRtn.getOwnerProperty() );
// if ( ownerType.isEntityType() ) {
// entityName = ( (EntityType) ownerType ).getAssociatedEntityName( getFactory() );
// }
// else if ( ownerType.isCollectionType() ) {
// Type ownerCollectionElementType = ( (CollectionType) ownerType ).getElementType( getFactory() );
// if ( ownerCollectionElementType.isEntityType() ) {
// entityName = ( (EntityType) ownerCollectionElementType ).getAssociatedEntityName( getFactory() );
// }
// }
// }
//
// if ( entityName == null ) {
// throw new HibernateException( "Could not determine fetch owner : " + ownerDescriptor );
// }
//
// return (Queryable) getFactory().getMetamodel().entityPersister( entityName );
// }
@Override
protected String getQueryIdentifier() {
return sql;
}
@Override
public String getSQLString() {
return sql;
}
public Set getQuerySpaces() {
return querySpaces;
}
@Override
protected LockMode[] getLockModes(LockOptions lockOptions) {
return lockModes;
}
@Override
protected Loadable[] getEntityPersisters() {
return entityPersisters;
}
@Override
protected CollectionPersister[] getCollectionPersisters() {
return collectionPersisters;
}
@Override
protected int[] getCollectionOwners() {
return collectionOwners;
}
@Override
protected int[] getOwners() {
return entiytOwners;
}
public List list(SharedSessionContractImplementor session, QueryParameters queryParameters) throws HibernateException {
return list( session, queryParameters, querySpaces, resultTypes );
}
@Override
protected String applyLocks(
String sql,
QueryParameters parameters,
Dialect dialect,
List<AfterLoadAction> afterLoadActions) throws QueryException {
final LockOptions lockOptions = parameters.getLockOptions();
if ( lockOptions == null ||
( lockOptions.getLockMode() == LockMode.NONE && lockOptions.getAliasLockCount() == 0 ) ) {
return sql;
}
// user is request locking, lets see if we can apply locking directly to the SQL...
// some dialects wont allow locking with paging...
afterLoadActions.add(
new AfterLoadAction() {
private final LockOptions originalLockOptions = lockOptions.makeCopy();
@Override
public void afterLoad(SharedSessionContractImplementor session, Object entity, Loadable persister) {
( (Session) session ).buildLockRequest( originalLockOptions ).lock(
persister.getEntityName(),
entity
);
}
}
);
parameters.getLockOptions().setLockMode( LockMode.READ );
return sql;
}
public ScrollableResultsImplementor scroll(final QueryParameters queryParameters, final SharedSessionContractImplementor session)
throws HibernateException {
ResultTransformer resultTransformer = queryParameters.getResultTransformer();
throw new NotYetImplementedFor6Exception( getClass() );
// final RowReader rowReader = ...;
//
// return scroll( queryParameters, resultTypes, rowReader, session );
}
@Override
protected String[] getResultRowAliases() {
return transformerAliases;
}
@Override
protected ResultTransformer resolveResultTransformer(ResultTransformer resultTransformer) {
throw new NotYetImplementedFor6Exception( getClass() );
// return HolderInstantiator.resolveResultTransformer( null, resultTransformer );
}
@Override
protected boolean[] includeInResultRow() {
return includeInResultRow;
}
@Override
protected Object getResultColumnOrRow(
Object[] row,
ResultTransformer transformer,
ResultSet rs,
SharedSessionContractImplementor session) throws SQLException, HibernateException {
return rowProcessor.buildResultRow( row, rs, transformer != null, session );
}
@Override
protected Object[] getResultRow(Object[] row, ResultSet rs, SharedSessionContractImplementor session)
throws SQLException, HibernateException {
return rowProcessor.buildResultRow( row, rs, session );
}
@Override
@SuppressWarnings("unchecked")
protected List getResultList(List results, ResultTransformer resultTransformer) throws QueryException {
throw new NotYetImplementedFor6Exception( getClass() );
// // meant to handle dynamic instantiation queries...(Copy from QueryLoader)
// HolderInstantiator holderInstantiator = HolderInstantiator.getHolderInstantiator(
// null,
// resultTransformer,
// getReturnAliasesForTransformer()
// );
// if ( holderInstantiator.isRequired() ) {
// for ( int i = 0; i < results.size(); i++ ) {
// Object[] row = (Object[]) results.get( i );
// Object result = holderInstantiator.instantiate( row );
// results.set( i, result );
// }
//
// return resultTransformer.transformList( results );
// }
// else {
// return results;
// }
}
private String[] getReturnAliasesForTransformer() {
return transformerAliases;
}
@Override
protected EntityAliases[] getEntityAliases() {
return entityAliases;
}
@Override
protected CollectionAliases[] getCollectionAliases() {
return collectionAliases;
}
@Override
protected int bindParameterValues(
PreparedStatement statement,
QueryParameters queryParameters,
int startIndex,
SharedSessionContractImplementor session) throws SQLException {
final Serializable optionalId = queryParameters.getOptionalId();
if ( optionalId != null ) {
paramValueBinders.get( 0 ).bind( statement, queryParameters, session, startIndex );
return session.getFactory().getMetamodel()
.entityPersister( queryParameters.getOptionalEntityName() )
.getIdentifierType()
.getColumnSpan( session.getFactory() );
}
int span = 0;
for ( ParameterBinder paramValueBinder : paramValueBinders ) {
span += paramValueBinder.bind(
statement,
queryParameters,
session,
startIndex + span
);
}
return span;
}
@Override
protected void autoDiscoverTypes(ResultSet rs) {
try {
JdbcResultMetadata metadata = new JdbcResultMetadata( getFactory(), rs );
rowProcessor.prepareForAutoDiscovery( metadata );
List<String> aliases = new ArrayList<>();
List<Type> types = new ArrayList<>();
for ( ResultColumnProcessor resultProcessor : rowProcessor.getColumnProcessors() ) {
resultProcessor.performDiscovery( metadata, types, aliases );
}
validateAliases( aliases );
resultTypes = ArrayHelper.toTypeArray( types );
transformerAliases = ArrayHelper.toStringArray( aliases );
}
catch (SQLException e) {
throw new HibernateException( "Exception while trying to autodiscover types.", e );
}
}
private void validateAliases(List<String> aliases) {
// lets make sure we did not end up with duplicate aliases. this can occur when the user supplied query
// did not rename same-named columns. e.g.:
// select u.username, u2.username from t_user u, t_user u2 ...
//
// the above will lead to an unworkable situation in most cases (the difference is how the driver/db
// handle this situation. But if the 'aliases' variable contains duplicate names, then we have that
// troublesome condition, so lets throw an error. See HHH-5992
final HashSet<String> aliasesSet = new HashSet<String>();
for ( String alias : aliases ) {
validateAlias( alias );
boolean alreadyExisted = !aliasesSet.add( alias );
if ( alreadyExisted ) {
throw new NonUniqueDiscoveredSqlAliasException(
"Encountered a duplicated sql alias [" + alias + "] during auto-discovery of a native-sql query"
);
}
}
}
@SuppressWarnings("UnusedParameters")
protected void validateAlias(String alias) {
}
/**
* {@link #resultTypes} can be overridden by {@link #autoDiscoverTypes(ResultSet)},
* *after* {@link #list(SharedSessionContractImplementor, QueryParameters)} has already been called. It's a bit of a
* chicken-and-the-egg issue since {@link #autoDiscoverTypes(ResultSet)} needs the {@link ResultSet}.
* <p/>
* As a hacky workaround, overriden here to provide the {@link #resultTypes}.
*
* see HHH-3051
*/
@Override
protected void putResultInQueryCache(
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final Type[] resultTypes,
final QueryResultsCache queryCache,
final QueryKey key,
final List result) {
super.putResultInQueryCache( session, queryParameters, this.resultTypes, queryCache, key, result );
}
}

View File

@ -1,49 +0,0 @@
/*
* 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.loader.custom;
import java.util.List;
import java.util.Set;
import org.hibernate.param.ParameterBinder;
/**
* Extension point allowing any SQL query with named and positional parameters
* to be executed by Hibernate, returning managed entities, collections and
* simple scalar values.
*
* @author Gavin King
* @author Steve Ebersole
*/
public interface CustomQuery {
/**
* The SQL query string to be performed.
*
* @return The SQL statement string.
*/
String getSQL();
/**
* Any query spaces to apply to the query execution. Query spaces are
* used in Hibernate's auto-flushing mechanism to determine which
* entities need to be checked for pending changes.
*
* @return The query spaces
*/
Set<String> getQuerySpaces();
List<ParameterBinder> getParameterValueBinders();
/**
* A collection of {@link Return descriptors} describing the
* JDBC result set to be expected and how to map this result set.
*
* @return List of return descriptors.
*/
List<Return> getCustomQueryReturns();
}

View File

@ -1,32 +0,0 @@
/*
* 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.loader.custom;
import org.hibernate.LockMode;
import org.hibernate.loader.EntityAliases;
/**
* Spefically a fetch return that refers to an entity association.
*
* @author Steve Ebersole
*/
public class EntityFetchReturn extends FetchReturn {
private final EntityAliases entityAliases;
public EntityFetchReturn(
String alias,
EntityAliases entityAliases,
NonScalarReturn owner,
String ownerProperty,
LockMode lockMode) {
super( owner, ownerProperty, alias, lockMode );
this.entityAliases = entityAliases;
}
public EntityAliases getEntityAliases() {
return entityAliases;
}
}

View File

@ -1,54 +0,0 @@
/*
* 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.loader.custom;
import org.hibernate.LockMode;
/**
* Represents a return which names a fetched association.
*
* @author Steve Ebersole
*/
public abstract class FetchReturn extends NonScalarReturn {
private final NonScalarReturn owner;
private final String ownerProperty;
/**
* Creates a return descriptor for an association fetch.
*
* @param owner The return descriptor for the owner of the fetch
* @param ownerProperty The name of the property represernting the association being fetched
* @param alias The alias for the fetch
* @param lockMode The lock mode to apply to the fetched association.
*/
public FetchReturn(
NonScalarReturn owner,
String ownerProperty,
String alias,
LockMode lockMode) {
super( alias, lockMode );
this.owner = owner;
this.ownerProperty = ownerProperty;
}
/**
* Retrieves the return descriptor for the owner of this fetch.
*
* @return The owner
*/
public NonScalarReturn getOwner() {
return owner;
}
/**
* The name of the property on the owner which represents this association.
*
* @return The property name.
*/
public String getOwnerProperty() {
return ownerProperty;
}
}

View File

@ -1,97 +0,0 @@
/*
* 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.loader.custom;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
/**
* Simplified access to JDBC ResultSetMetaData
*
* @author Steve Ebersole
*/
class JdbcResultMetadata {
private final SessionFactoryImplementor factory;
private final ResultSet resultSet;
private final ResultSetMetaData resultSetMetaData;
public JdbcResultMetadata(SessionFactoryImplementor factory, ResultSet resultSet) throws HibernateException {
try {
this.factory = factory;
this.resultSet = resultSet;
this.resultSetMetaData = resultSet.getMetaData();
}
catch( SQLException e ) {
throw new HibernateException( "Could not extract result set metadata", e );
}
}
public int getColumnCount() throws HibernateException {
try {
return resultSetMetaData.getColumnCount();
}
catch( SQLException e ) {
throw new HibernateException( "Could not determine result set column count", e );
}
}
public int resolveColumnPosition(String columnName) throws HibernateException {
try {
return resultSet.findColumn( columnName );
}
catch( SQLException e ) {
throw new HibernateException( "Could not resolve column name in result set [" + columnName + "]", e );
}
}
public String getColumnName(int position) throws HibernateException {
try {
return factory.getDialect().getColumnAliasExtractor().extractColumnAlias( resultSetMetaData, position );
}
catch( SQLException e ) {
throw new HibernateException( "Could not resolve column name [" + position + "]", e );
}
}
public Type getHibernateType(int columnPos) throws SQLException {
int columnType = resultSetMetaData.getColumnType( columnPos );
int scale = resultSetMetaData.getScale( columnPos );
int precision = resultSetMetaData.getPrecision( columnPos );
int length = precision;
if ( columnType == Types.CHAR && precision == 0 ) {
length = resultSetMetaData.getColumnDisplaySize( columnPos );
}
final String hibernateTypeName = factory.getDialect().getHibernateTypeName(
columnType,
length,
precision,
scale
);
if ( hibernateTypeName != null ) {
return factory.getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( hibernateTypeName );
}
final SqlTypeDescriptor columnSqlTypeDescriptor = factory.getTypeConfiguration()
.getSqlTypeDescriptorRegistry()
.getDescriptor( columnType );
final BasicJavaDescriptor<Object> relationalJtd = columnSqlTypeDescriptor.getJdbcRecommendedJavaTypeMapping( factory.getTypeConfiguration() );
return factory.getTypeConfiguration().getBasicTypeRegistry().resolve( relationalJtd, columnSqlTypeDescriptor );
}
}

View File

@ -1,41 +0,0 @@
/*
* 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.loader.custom;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.Type;
/**
* Represents non-scalar returns within the custom query. Most of the heavy lifting for non-scalar results
* is done within Loader itself.
*
* @author Steve Ebersole
*/
public class NonScalarResultColumnProcessor implements ResultColumnProcessor {
private final int position;
public NonScalarResultColumnProcessor(int position) {
this.position = position;
}
@Override
public void performDiscovery(JdbcResultMetadata metadata, List<Type> types, List<String> aliases) {
// nothing to discover for non-scalar results
}
@Override
public Object extract(Object[] data, ResultSet resultSet, SharedSessionContractImplementor session)
throws SQLException, HibernateException {
return data[ position ];
}
}

View File

@ -1,35 +0,0 @@
/*
* 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.loader.custom;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
/**
* Represents some non-scalar (entity/collection) return within the query result.
*
* @author Steve Ebersole
*/
public abstract class NonScalarReturn implements Return {
private final String alias;
private final LockMode lockMode;
public NonScalarReturn(String alias, LockMode lockMode) {
this.alias = alias;
if ( alias == null ) {
throw new HibernateException("alias must be specified");
}
this.lockMode = lockMode;
}
public String getAlias() {
return alias;
}
public LockMode getLockMode() {
return lockMode;
}
}

View File

@ -1,50 +0,0 @@
/*
* 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.loader.custom;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.Type;
/** Processor for each "column" in a custom query result. May map to more than one physical column in the JDBC ResultSert.
*
* @author Steve Ebersole
*/
interface ResultColumnProcessor {
/**
* Perform discovery, if needed. Typically discovery activities include looking up the column name in the
* ResultSet or JDBC type codes.
*
* @param metadata Delegate for accessing metadata about the JDBC ResultSet
* @param types The building List of types
* @param aliases The building list of column names/aliases
*
* @throws SQLException Indicates a problem accessing the JDBC objects
* @throws HibernateException Indicates a higher-level problem already categorized by Hibernate
*/
void performDiscovery(JdbcResultMetadata metadata, List<Type> types, List<String> aliases)
throws SQLException, HibernateException;
/**
* Perform The extraction
*
* @param data All non-scalar results (handled at a higher level than these processors)
* @param resultSet The JDBC result set.
* @param session The Hibernate Session
*
* @return The extracted value
*
* @throws SQLException Indicates a problem accessing the JDBC objects
* @throws HibernateException Indicates a higher-level problem already categorized by Hibernate
*/
Object extract(Object[] data, ResultSet resultSet, SharedSessionContractImplementor session)
throws SQLException, HibernateException;
}

View File

@ -1,89 +0,0 @@
/*
* 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.loader.custom;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* Models an entire "row" of results within a custom query
*
* @author Steve Ebersole
*/
public class ResultRowProcessor {
private final boolean hasScalars;
private ResultColumnProcessor[] columnProcessors;
public ResultRowProcessor(boolean hasScalars, ResultColumnProcessor[] columnProcessors) {
this.hasScalars = hasScalars || ( columnProcessors == null || columnProcessors.length == 0 );
this.columnProcessors = columnProcessors;
}
public ResultColumnProcessor[] getColumnProcessors() {
return columnProcessors;
}
public void prepareForAutoDiscovery(JdbcResultMetadata metadata) throws SQLException {
if ( columnProcessors == null || columnProcessors.length == 0 ) {
int columns = metadata.getColumnCount();
columnProcessors = new ResultColumnProcessor[ columns ];
for ( int i = 1; i <= columns; i++ ) {
columnProcessors[ i - 1 ] = new ScalarResultColumnProcessor( i );
}
}
}
/**
* Build a logical result row.
* <p/>
* At this point, Loader has already processed all non-scalar result data. We
* just need to account for scalar result data here...
*
* @param data Entity data defined as "root returns" and already handled by the
* normal Loader mechanism.
* @param resultSet The JDBC result set (positioned at the row currently being processed).
* @param hasTransformer Does this query have an associated {@link org.hibernate.transform.ResultTransformer}
* @param session The session from which the query request originated.
* @return The logical result row
* @throws java.sql.SQLException
* @throws org.hibernate.HibernateException
*/
public Object buildResultRow(Object[] data, ResultSet resultSet, boolean hasTransformer, SharedSessionContractImplementor session)
throws SQLException, HibernateException {
final Object[] resultRow = buildResultRow( data, resultSet, session );
if ( hasTransformer ) {
return resultRow;
}
else {
return resultRow.length == 1
? resultRow[0]
: resultRow;
}
}
public Object[] buildResultRow(Object[] data, ResultSet resultSet, SharedSessionContractImplementor session)
throws SQLException, HibernateException {
Object[] resultRow;
if ( !hasScalars ) {
resultRow = data;
}
else {
// build an array with indices equal to the total number
// of actual returns in the result Hibernate will return
// for this query (scalars + non-scalars)
resultRow = new Object[ columnProcessors.length ];
for ( int i = 0; i < columnProcessors.length; i++ ) {
resultRow[i] = columnProcessors[i].extract( data, resultSet, session );
}
}
return resultRow;
}
}

View File

@ -1,16 +0,0 @@
/*
* 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.loader.custom;
/**
* Represents a return in a custom query.
*
* @author Steve Ebersole
*/
public interface Return {
}

View File

@ -1,40 +0,0 @@
/*
* 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.loader.custom;
import org.hibernate.LockMode;
import org.hibernate.loader.EntityAliases;
/**
* Represents a return which names a "root" entity.
* <p/>
* A root entity means it is explicitly a "column" in the result, as opposed to
* a fetched association.
*
* @author Steve Ebersole
*/
public class RootReturn extends NonScalarReturn {
private final String entityName;
private final EntityAliases entityAliases;
public RootReturn(
String alias,
String entityName,
EntityAliases entityAliases,
LockMode lockMode) {
super( alias, lockMode );
this.entityName = entityName;
this.entityAliases = entityAliases;
}
public String getEntityName() {
return entityName;
}
public EntityAliases getEntityAliases() {
return entityAliases;
}
}

View File

@ -1,56 +0,0 @@
/*
* 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.loader.custom;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.Type;
/**
* Represents a scalar result within the custom query
*
* @author Steve Ebersole
*/
public class ScalarResultColumnProcessor implements ResultColumnProcessor {
private int position = -1;
private String alias;
private Type type;
public ScalarResultColumnProcessor(int position) {
this.position = position;
}
public ScalarResultColumnProcessor(String alias, Type type) {
this.alias = alias;
this.type = type;
}
@Override
public void performDiscovery(JdbcResultMetadata metadata, List<Type> types, List<String> aliases) throws SQLException {
if ( alias == null ) {
alias = metadata.getColumnName( position );
}
else if ( position < 0 ) {
position = metadata.resolveColumnPosition( alias );
}
if ( type == null ) {
type = metadata.getHibernateType( position );
}
types.add( type );
aliases.add( alias );
}
@Override
public Object extract(Object[] data, ResultSet resultSet, SharedSessionContractImplementor session)
throws SQLException, HibernateException {
return type.nullSafeGet( resultSet, alias, session, null );
}
}

View File

@ -1,31 +0,0 @@
/*
* 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.loader.custom;
import org.hibernate.type.Type;
/**
* Represent a scalar (aka simple value) return within a query result.
*
* @author Steve Ebersole
*/
public class ScalarReturn implements Return {
private final Type type;
private final String columnAlias;
public ScalarReturn(Type type, String columnAlias) {
this.type = type;
this.columnAlias = columnAlias;
}
public Type getType() {
return type;
}
public String getColumnAlias() {
return columnAlias;
}
}

View File

@ -1,16 +0,0 @@
<!--
~ 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>.
-->
<html>
<head></head>
<body>
<p>
This package defines a framework for custom loaders that accept
handwritten SQL
</p>
</body>
</html>

View File

@ -1,37 +0,0 @@
/*
* 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.loader.custom.sql;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.param.ParameterBinder;
/**
* @author Steve Ebersole
*/
public class NamedParamBinder implements ParameterBinder {
private final String name;
public NamedParamBinder(String name) {
this.name = name;
}
@Override
public int bind(
PreparedStatement statement,
QueryParameters qp,
SharedSessionContractImplementor session,
int position) throws SQLException {
final TypedValue typedValue = qp.getNamedParameters().get( name );
typedValue.getType().nullSafeSet( statement, typedValue.getValue(), position, session );
return typedValue.getType().getColumnSpan( session.getFactory() );
}
}

View File

@ -1,37 +0,0 @@
/*
* 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.loader.custom.sql;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.param.ParameterBinder;
/**
* @author Steve Ebersole
*/
public class PositionalParamBinder implements ParameterBinder {
private final int label;
public PositionalParamBinder(int label) {
this.label = label;
}
@Override
public int bind(
PreparedStatement statement,
QueryParameters qp,
SharedSessionContractImplementor session,
int position) throws SQLException {
final TypedValue typedValue = qp.getNamedParameters().get( Integer.toString( label ) );
typedValue.getType().nullSafeSet( statement, typedValue.getValue(), position, session );
return typedValue.getType().getColumnSpan( session.getFactory() );
}
}

View File

@ -1,243 +0,0 @@
/*
* 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.loader.custom.sql;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.loader.custom.CustomQuery;
import org.hibernate.param.ParameterBinder;
import org.hibernate.persister.collection.SQLLoadableCollection;
import org.hibernate.persister.entity.SQLLoadable;
import org.jboss.logging.Logger;
/**
* Implements Hibernate's built-in support for native SQL queries.
* <p/>
* This support is built on top of the notion of "custom queries"...
*
* @author Gavin King
* @author Max Andersen
* @author Steve Ebersole
*/
public class SQLCustomQuery implements CustomQuery, Serializable {
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, SQLCustomQuery.class.getName() );
private final String sql;
private final Set querySpaces = new HashSet();
private final List<ParameterBinder> paramValueBinders;
private final List customQueryReturns = new ArrayList();
public String getSQL() {
return sql;
}
public Set getQuerySpaces() {
return querySpaces;
}
@Override
public List<ParameterBinder > getParameterValueBinders() {
return paramValueBinders;
}
public List getCustomQueryReturns() {
return customQueryReturns;
}
public SQLCustomQuery(
final String sqlQuery,
final NativeSQLQueryReturn[] queryReturns,
final Collection additionalQuerySpaces,
final SessionFactoryImplementor factory) throws HibernateException {
LOG.tracev( "Starting processing of sql query [{0}]", sqlQuery );
SQLQueryReturnProcessor processor = new SQLQueryReturnProcessor(queryReturns, factory);
SQLQueryReturnProcessor.ResultAliasContext aliasContext = processor.process();
// Map[] propertyResultMaps = (Map[]) processor.getPropertyResults().toArray( new Map[0] );
// Map[] collectionResultMaps = (Map[]) processor.getCollectionPropertyResults().toArray( new Map[0] );
//
// List collectionSuffixes = new ArrayList();
// List collectionOwnerAliases = processor.getCollectionOwnerAliases();
// List collectionPersisters = processor.getCollectionPersisters();
// int size = collectionPersisters.size();
// if (size!=0) {
// collectionOwners = new int[size];
// collectionRoles = new String[size];
// //collectionDescriptors = new CollectionAliases[size];
// for ( int i=0; i<size; i++ ) {
// CollectionPersister collectionPersister = (CollectionPersister) collectionPersisters.get(i);
// collectionRoles[i] = ( collectionPersister ).getRole();
// collectionOwners[i] = processor.getAliases().indexOf( collectionOwnerAliases.get(i) );
// String suffix = i + "__";
// collectionSuffixes.add(suffix);
// //collectionDescriptors[i] = new GeneratedCollectionAliases( collectionResultMaps[i], collectionPersister, suffix );
// }
// }
// else {
// collectionRoles = null;
// //collectionDescriptors = null;
// collectionOwners = null;
// }
//
// String[] aliases = ArrayHelper.toStringArray( processor.getAliases() );
// String[] collAliases = ArrayHelper.toStringArray( processor.getCollectionAliases() );
// String[] collSuffixes = ArrayHelper.toStringArray(collectionSuffixes);
//
// SQLLoadable[] entityPersisters = (SQLLoadable[]) processor.getPersisters().toArray( new SQLLoadable[0] );
// SQLLoadableCollection[] collPersisters = (SQLLoadableCollection[]) collectionPersisters.toArray( new SQLLoadableCollection[0] );
// lockModes = (LockMode[]) processor.getLockModes().toArray( new LockMode[0] );
//
// scalarColumnAliases = ArrayHelper.toStringArray( processor.getScalarColumnAliases() );
// scalarTypes = ArrayHelper.toTypeArray( processor.getScalarTypes() );
//
// // need to match the "sequence" of what we return. scalar first, entity last.
// returnAliases = ArrayHelper.join(scalarColumnAliases, aliases);
//
// String[] suffixes = BasicLoader.generateSuffixes(entityPersisters.length);
SQLQueryParser parser = new SQLQueryParser( sqlQuery, new ParserContext( aliasContext ), factory );
this.sql = parser.process();
this.paramValueBinders = parser.getParameterValueBinders();
// SQLQueryParser parser = new SQLQueryParser(
// sqlQuery,
// processor.getAlias2Persister(),
// processor.getAlias2Return(),
// aliases,
// collAliases,
// collPersisters,
// suffixes,
// collSuffixes
// );
//
// sql = parser.process();
//
// namedParameterBindPoints = parser.getNamedParameters();
customQueryReturns.addAll( processor.generateCustomReturns( parser.queryHasAliases() ) );
// // Populate entityNames, entityDescrptors and querySpaces
// entityNames = new String[entityPersisters.length];
// entityDescriptors = new EntityAliases[entityPersisters.length];
// for (int i = 0; i < entityPersisters.length; i++) {
// SQLLoadable persister = entityPersisters[i];
// //alias2Persister.put( aliases[i], persister );
// //TODO: Does not consider any other tables referenced in the query
// ArrayHelper.addAll( querySpaces, persister.getQuerySpaces() );
// entityNames[i] = persister.getEntityName();
// if ( parser.queryHasAliases() ) {
// entityDescriptors[i] = new DefaultEntityAliases(
// propertyResultMaps[i],
// entityPersisters[i],
// suffixes[i]
// );
// }
// else {
// entityDescriptors[i] = new ColumnEntityAliases(
// propertyResultMaps[i],
// entityPersisters[i],
// suffixes[i]
// );
// }
// }
if ( additionalQuerySpaces != null ) {
querySpaces.addAll( additionalQuerySpaces );
}
// if (size!=0) {
// collectionDescriptors = new CollectionAliases[size];
// for ( int i=0; i<size; i++ ) {
// CollectionPersister collectionPersister = (CollectionPersister) collectionPersisters.get(i);
// String suffix = i + "__";
// if( parser.queryHasAliases() ) {
// collectionDescriptors[i] = new GeneratedCollectionAliases( collectionResultMaps[i], collectionPersister, suffix );
// } else {
// collectionDescriptors[i] = new ColumnCollectionAliases( collectionResultMaps[i], (SQLLoadableCollection) collectionPersister );
// }
// }
// }
// else {
// collectionDescriptors = null;
// }
//
//
// // Resolve owners
// Map alias2OwnerAlias = processor.getAlias2OwnerAlias();
// int[] ownersArray = new int[entityPersisters.length];
// for ( int j=0; j < aliases.length; j++ ) {
// String ownerAlias = (String) alias2OwnerAlias.get( aliases[j] );
// if ( StringHelper.isNotEmpty(ownerAlias) ) {
// ownersArray[j] = processor.getAliases().indexOf( ownerAlias );
// }
// else {
// ownersArray[j] = -1;
// }
// }
// if ( ArrayHelper.isAllNegative(ownersArray) ) {
// ownersArray = null;
// }
// this.entityOwners = ownersArray;
}
private static class ParserContext implements SQLQueryParser.ParserContext {
private final SQLQueryReturnProcessor.ResultAliasContext aliasContext;
public ParserContext(SQLQueryReturnProcessor.ResultAliasContext aliasContext) {
this.aliasContext = aliasContext;
}
public boolean isEntityAlias(String alias) {
return getEntityPersisterByAlias( alias ) != null;
}
public SQLLoadable getEntityPersisterByAlias(String alias) {
return aliasContext.getEntityPersister( alias );
}
public String getEntitySuffixByAlias(String alias) {
return aliasContext.getEntitySuffix( alias );
}
public boolean isCollectionAlias(String alias) {
return getCollectionPersisterByAlias( alias ) != null;
}
public SQLLoadableCollection getCollectionPersisterByAlias(String alias) {
return aliasContext.getCollectionPersister( alias );
}
public String getCollectionSuffixByAlias(String alias) {
return aliasContext.getCollectionSuffix( alias );
}
public Map getPropertyResultsMapByAlias(String alias) {
return aliasContext.getPropertyResultsMap( alias );
}
}
}

View File

@ -1,351 +0,0 @@
/*
* 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.loader.custom.sql;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.hibernate.QueryException;
import org.hibernate.query.sql.internal.ParameterParser;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.param.ParameterBinder;
import org.hibernate.persister.collection.SQLLoadableCollection;
import org.hibernate.persister.entity.SQLLoadable;
import org.hibernate.query.sql.spi.ParameterRecognizer;
/**
* @author Gavin King
* @author Max Andersen
* @author Steve Ebersole
* @author Paul Benedict
*/
public class SQLQueryParser {
private static final Pattern PREPARED_STATEMENT_PATTERN = Pattern.compile( "^\\{.*?\\}$" );
private static final String HIBERNATE_PLACEHOLDER_PREFIX = "h-";
private static final String DOMAIN_PLACEHOLDER = "h-domain";
private static final String CATALOG_PLACEHOLDER = "h-catalog";
private static final String SCHEMA_PLACEHOLDER = "h-schema";
private final SessionFactoryImplementor factory;
private final String originalQueryString;
private final ParserContext context;
private long aliasesFound;
private List<ParameterBinder> paramValueBinders;
interface ParserContext {
boolean isEntityAlias(String aliasName);
SQLLoadable getEntityPersisterByAlias(String alias);
String getEntitySuffixByAlias(String alias);
boolean isCollectionAlias(String aliasName);
SQLLoadableCollection getCollectionPersisterByAlias(String alias);
String getCollectionSuffixByAlias(String alias);
Map getPropertyResultsMapByAlias(String alias);
}
public SQLQueryParser(String queryString, ParserContext context, SessionFactoryImplementor factory) {
this.originalQueryString = queryString;
this.context = context;
this.factory = factory;
}
public List<ParameterBinder> getParameterValueBinders() {
return paramValueBinders == null ? Collections.emptyList() : paramValueBinders;
}
public boolean queryHasAliases() {
return aliasesFound>0;
}
protected String getOriginalQueryString() {
return originalQueryString;
}
public String process() {
String processedSql = substituteBrackets( originalQueryString );
processedSql = substituteParams( processedSql );
return processedSql;
}
// TODO: should "record" how many properties we have reffered to - and if we
// don't get'em'all we throw an exception! Way better than trial and error ;)
protected String substituteBrackets(String sqlQuery) throws QueryException {
if ( PREPARED_STATEMENT_PATTERN.matcher( sqlQuery.trim() ).matches() ) {
return sqlQuery;
}
StringBuilder result = new StringBuilder( sqlQuery.length() + 20 );
int left, right;
// replace {....} with corresponding column aliases
for ( int curr = 0; curr < sqlQuery.length(); curr = right + 1 ) {
if ( ( left = sqlQuery.indexOf( '{', curr ) ) < 0 ) {
// No additional open braces found in the string, append the
// rest of the string in its entirety and quit this loop
result.append( sqlQuery.substring( curr ) );
break;
}
// apend everything up until the next encountered open brace
result.append( sqlQuery.substring( curr, left ) );
if ( ( right = sqlQuery.indexOf( '}', left + 1 ) ) < 0 ) {
throw new QueryException( "Unmatched braces for alias path", sqlQuery );
}
final String aliasPath = sqlQuery.substring( left + 1, right );
boolean isPlaceholder = aliasPath.startsWith( HIBERNATE_PLACEHOLDER_PREFIX );
if ( isPlaceholder ) {
// Domain replacement
if ( DOMAIN_PLACEHOLDER.equals( aliasPath ) ) {
final String catalogName = factory.getSettings().getDefaultCatalogName();
if ( catalogName != null ) {
result.append( catalogName );
result.append( "." );
}
final String schemaName = factory.getSettings().getDefaultSchemaName();
if ( schemaName != null ) {
result.append( schemaName );
result.append( "." );
}
}
// Schema replacement
else if ( SCHEMA_PLACEHOLDER.equals( aliasPath ) ) {
final String schemaName = factory.getSettings().getDefaultSchemaName();
if ( schemaName != null ) {
result.append(schemaName);
result.append(".");
}
}
// Catalog replacement
else if ( CATALOG_PLACEHOLDER.equals( aliasPath ) ) {
final String catalogName = factory.getSettings().getDefaultCatalogName();
if ( catalogName != null ) {
result.append( catalogName );
result.append( "." );
}
}
else {
throw new QueryException( "Unknown placeholder ", aliasPath );
}
}
else if (context != null) {
int firstDot = aliasPath.indexOf( '.' );
if ( firstDot == -1 ) {
if ( context.isEntityAlias( aliasPath ) ) {
// it is a simple table alias {foo}
result.append( aliasPath );
aliasesFound++;
}
else {
// passing through anything we do not know : to support jdbc escape sequences HB-898
result.append( '{' ).append(aliasPath).append( '}' );
}
}
else {
final String aliasName = aliasPath.substring( 0, firstDot );
if ( context.isCollectionAlias( aliasName ) ) {
// The current alias is referencing the collection to be eagerly fetched
String propertyName = aliasPath.substring( firstDot + 1 );
result.append( resolveCollectionProperties( aliasName, propertyName ) );
aliasesFound++;
}
else if ( context.isEntityAlias( aliasName ) ) {
// it is a property reference {foo.bar}
String propertyName = aliasPath.substring( firstDot + 1 );
result.append( resolveProperties( aliasName, propertyName ) );
aliasesFound++;
}
else {
// passing through anything we do not know : to support jdbc escape sequences HB-898
result.append( '{' ).append(aliasPath).append( '}' );
}
}
}
else {
result.append( '{' ).append(aliasPath).append( '}' );
}
}
// Possibly handle :something parameters for the query ?
return result.toString();
}
private String resolveCollectionProperties(
String aliasName,
String propertyName) {
Map fieldResults = context.getPropertyResultsMapByAlias( aliasName );
SQLLoadableCollection collectionPersister = context.getCollectionPersisterByAlias( aliasName );
String collectionSuffix = context.getCollectionSuffixByAlias( aliasName );
if ( "*".equals( propertyName ) ) {
if( !fieldResults.isEmpty() ) {
throw new QueryException("Using return-propertys together with * syntax is not supported.");
}
String selectFragment = collectionPersister.selectFragment( aliasName, collectionSuffix );
aliasesFound++;
return selectFragment
+ ", "
+ resolveProperties( aliasName, propertyName );
}
else if ( "element.*".equals( propertyName ) ) {
return resolveProperties( aliasName, "*" );
}
else {
String[] columnAliases;
// Let return-propertys override whatever the persister has for aliases.
columnAliases = ( String[] ) fieldResults.get(propertyName);
if ( columnAliases==null ) {
columnAliases = collectionPersister.getCollectionPropertyColumnAliases( propertyName, collectionSuffix );
}
if ( columnAliases == null || columnAliases.length == 0 ) {
throw new QueryException(
"No column name found for property [" + propertyName + "] for alias [" + aliasName + "]",
originalQueryString
);
}
if ( columnAliases.length != 1 ) {
// TODO: better error message since we actually support composites if names are explicitly listed.
throw new QueryException(
"SQL queries only support properties mapped to a single column - property [" +
propertyName + "] is mapped to " + columnAliases.length + " columns.",
originalQueryString
);
}
aliasesFound++;
return columnAliases[0];
}
}
private String resolveProperties(String aliasName, String propertyName) {
Map fieldResults = context.getPropertyResultsMapByAlias( aliasName );
SQLLoadable persister = context.getEntityPersisterByAlias( aliasName );
String suffix = context.getEntitySuffixByAlias( aliasName );
if ( "*".equals( propertyName ) ) {
if( !fieldResults.isEmpty() ) {
throw new QueryException("Using return-propertys together with * syntax is not supported.");
}
aliasesFound++;
return persister.selectFragment( aliasName, suffix ) ;
}
else {
String[] columnAliases;
// Let return-propertys override whatever the persister has for aliases.
columnAliases = (String[]) fieldResults.get( propertyName );
if ( columnAliases == null ) {
columnAliases = persister.getSubclassPropertyColumnAliases( propertyName, suffix );
}
if ( columnAliases == null || columnAliases.length == 0 ) {
throw new QueryException(
"No column name found for property [" + propertyName + "] for alias [" + aliasName + "]",
originalQueryString
);
}
if ( columnAliases.length != 1 ) {
// TODO: better error message since we actually support composites if names are explicitly listed.
throw new QueryException(
"SQL queries only support properties mapped to a single column - property [" + propertyName + "] is mapped to " + columnAliases.length + " columns.",
originalQueryString
);
}
aliasesFound++;
return columnAliases[0];
}
}
/**
* Substitues JDBC parameter placeholders (?) for all encountered
* parameter specifications. It also tracks the positions of these
* parameter specifications within the query string. This accounts for
* ordinal-params, named-params, and ejb3-positional-params.
*
* @param sqlString The query string.
* @return The SQL query with parameter substitution complete.
*/
private String substituteParams(String sqlString) {
final ParameterSubstitutionRecognizer recognizer = new ParameterSubstitutionRecognizer( factory );
ParameterParser.parse( sqlString, recognizer );
paramValueBinders = recognizer.getParameterValueBinders();
return recognizer.result.toString();
}
public static class ParameterSubstitutionRecognizer implements ParameterRecognizer {
StringBuilder result = new StringBuilder();
int jdbcPositionalParamCount;
private List<ParameterBinder> paramValueBinders;
public ParameterSubstitutionRecognizer(SessionFactoryImplementor factory) {
this.jdbcPositionalParamCount = 1;
}
@Override
public void outParameter(int position) {
result.append( '?' );
}
@Override
public void ordinalParameter(int position) {
result.append( '?' );
registerPositionParamBinder( jdbcPositionalParamCount++ );
}
private void registerPositionParamBinder(int label) {
if ( paramValueBinders == null ) {
paramValueBinders = new ArrayList<>();
}
paramValueBinders.add( new PositionalParamBinder( label ) );
}
@Override
public void jpaPositionalParameter(int name, int position) {
result.append( '?' );
registerPositionParamBinder( name );
}
@Override
public void namedParameter(String name, int position) {
result.append( '?' );
registerNamedParamBinder( name );
}
private void registerNamedParamBinder(String name) {
if ( paramValueBinders == null ) {
paramValueBinders = new ArrayList<>();
}
paramValueBinders.add( new NamedParamBinder( name ) );
}
@Override
public void other(char character) {
result.append( character );
}
public List<ParameterBinder> getParameterValueBinders() {
return paramValueBinders;
}
}
}

View File

@ -1,642 +0,0 @@
/*
* 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.loader.custom.sql;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryCollectionReturn;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryConstructorReturn;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryJoinReturn;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryNonScalarReturn;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryRootReturn;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryScalarReturn;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.loader.BasicLoader;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.loader.ColumnEntityAliases;
import org.hibernate.loader.DefaultEntityAliases;
import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.GeneratedCollectionAliases;
import org.hibernate.loader.custom.CollectionFetchReturn;
import org.hibernate.loader.custom.CollectionReturn;
import org.hibernate.loader.custom.ColumnCollectionAliases;
import org.hibernate.loader.custom.ConstructorReturn;
import org.hibernate.loader.custom.EntityFetchReturn;
import org.hibernate.loader.custom.FetchReturn;
import org.hibernate.loader.custom.NonScalarReturn;
import org.hibernate.loader.custom.Return;
import org.hibernate.loader.custom.RootReturn;
import org.hibernate.loader.custom.ScalarReturn;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.SQLLoadableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.entity.SQLLoadable;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
/**
* Responsible for processing the series of {@link org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn returns}
* defined by a {@link org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification} and
* breaking them down into a series of {@link Return returns} for use within the
* {@link org.hibernate.loader.custom.CustomLoader}.
*
* @author Gavin King
* @author Max Andersen
* @author Steve Ebersole
*/
public class SQLQueryReturnProcessor {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( SQLQueryReturnProcessor.class );
private static final NativeSQLQueryReturn[] NO_RETURNS = new NativeSQLQueryReturn[0];
private NativeSQLQueryReturn[] queryReturns;
// private final List persisters = new ArrayList();
private final Map alias2Return = new HashMap();
private final Map alias2OwnerAlias = new HashMap();
private final Map<String,EntityPersister> alias2Persister = new HashMap<String,EntityPersister>();
private final Map alias2Suffix = new HashMap();
private final Map<String,CollectionPersister> alias2CollectionPersister = new HashMap<String,CollectionPersister>();
private final Map alias2CollectionSuffix = new HashMap();
private final Map entityPropertyResultMaps = new HashMap();
private final Map collectionPropertyResultMaps = new HashMap();
// private final List scalarTypes = new ArrayList();
// private final List scalarColumnAliases = new ArrayList();
private final SessionFactoryImplementor factory;
// private List collectionOwnerAliases = new ArrayList();
// private List collectionAliases = new ArrayList();
// private List collectionPersisters = new ArrayList();
// private List collectionResults = new ArrayList();
private int entitySuffixSeed;
private int collectionSuffixSeed;
public SQLQueryReturnProcessor(NativeSQLQueryReturn[] queryReturns, SessionFactoryImplementor factory) {
this.queryReturns = queryReturns == null ? NO_RETURNS : queryReturns;
this.factory = factory;
}
public class ResultAliasContext {
public SQLLoadable getEntityPersister(String alias) {
return (SQLLoadable) alias2Persister.get( alias );
}
public SQLLoadableCollection getCollectionPersister(String alias) {
return (SQLLoadableCollection) alias2CollectionPersister.get( alias );
}
public String getEntitySuffix(String alias) {
return (String) alias2Suffix.get( alias );
}
public String getCollectionSuffix(String alias) {
return (String) alias2CollectionSuffix.get( alias );
}
public String getOwnerAlias(String alias) {
return (String) alias2OwnerAlias.get( alias );
}
public Map getPropertyResultsMap(String alias) {
return internalGetPropertyResultsMap( alias );
}
public String[] collectQuerySpaces() {
final HashSet<String> spaces = new HashSet<String>();
collectQuerySpaces( spaces );
return spaces.toArray( new String[ spaces.size() ] );
}
public void collectQuerySpaces(Collection<String> spaces) {
for ( EntityPersister persister : alias2Persister.values() ) {
Collections.addAll( spaces, (String[]) persister.getQuerySpaces() );
}
for ( CollectionPersister persister : alias2CollectionPersister.values() ) {
final Type elementType = persister.getElementType();
if ( elementType.isEntityType() && ! elementType.isAnyType() ) {
final Joinable joinable = ( (EntityType) elementType ).getAssociatedJoinable( factory );
Collections.addAll( spaces, (String[]) ( (EntityPersister) joinable ).getQuerySpaces() );
}
}
}
}
private Map internalGetPropertyResultsMap(String alias) {
NativeSQLQueryReturn rtn = ( NativeSQLQueryReturn ) alias2Return.get( alias );
if ( rtn instanceof NativeSQLQueryNonScalarReturn ) {
return ( ( NativeSQLQueryNonScalarReturn ) rtn ).getPropertyResultsMap();
}
else {
return null;
}
}
private boolean hasPropertyResultMap(String alias) {
Map propertyMaps = internalGetPropertyResultsMap( alias );
return propertyMaps != null && ! propertyMaps.isEmpty();
}
public ResultAliasContext process() {
// first, break down the returns into maps keyed by alias
// so that role returns can be more easily resolved to their owners
for ( NativeSQLQueryReturn queryReturn : queryReturns ) {
if ( queryReturn instanceof NativeSQLQueryNonScalarReturn ) {
NativeSQLQueryNonScalarReturn rtn = (NativeSQLQueryNonScalarReturn) queryReturn;
alias2Return.put( rtn.getAlias(), rtn );
if ( rtn instanceof NativeSQLQueryJoinReturn ) {
NativeSQLQueryJoinReturn fetchReturn = (NativeSQLQueryJoinReturn) rtn;
alias2OwnerAlias.put( fetchReturn.getAlias(), fetchReturn.getOwnerAlias() );
}
}
}
// Now, process the returns
for ( NativeSQLQueryReturn queryReturn : queryReturns ) {
processReturn( queryReturn );
}
return new ResultAliasContext();
}
private interface QueryReturnVisitor {
void visitScalarReturn(NativeSQLQueryScalarReturn rtn);
void visitRootReturn(NativeSQLQueryRootReturn rtn);
void visitCollectionReturn(NativeSQLQueryCollectionReturn rtn);
void visitFetch(NativeSQLQueryJoinReturn rtn);
void visitDynamicInstantiation(NativeSQLQueryConstructorReturn rtn);
}
public void visitReturns(QueryReturnVisitor visitor) {
for ( NativeSQLQueryReturn queryReturn : queryReturns ) {
if ( NativeSQLQueryScalarReturn.class.isInstance( queryReturn ) ) {
visitor.visitScalarReturn( (NativeSQLQueryScalarReturn) queryReturn );
}
else if ( NativeSQLQueryRootReturn.class.isInstance( queryReturn ) ) {
visitor.visitRootReturn( (NativeSQLQueryRootReturn) queryReturn );
}
else if ( NativeSQLQueryCollectionReturn.class.isInstance( queryReturn ) ) {
visitor.visitCollectionReturn( (NativeSQLQueryCollectionReturn) queryReturn );
}
else if ( NativeSQLQueryJoinReturn.class.isInstance( queryReturn ) ) {
visitor.visitFetch( (NativeSQLQueryJoinReturn) queryReturn );
}
else if ( NativeSQLQueryConstructorReturn.class.isInstance( queryReturn ) ) {
visitor.visitDynamicInstantiation( (NativeSQLQueryConstructorReturn) queryReturn );
}
else {
throw new IllegalStateException(
"Unrecognized NativeSQLQueryReturn concrete type : " + queryReturn
);
}
}
}
public List<Return> generateCustomReturns(boolean queryHadAliases) {
List<Return> customReturns = new ArrayList<Return>();
Map<String,Return> customReturnsByAlias = new HashMap<String,Return>();
for ( NativeSQLQueryReturn queryReturn : queryReturns ) {
if ( queryReturn instanceof NativeSQLQueryScalarReturn ) {
NativeSQLQueryScalarReturn rtn = (NativeSQLQueryScalarReturn) queryReturn;
customReturns.add( new ScalarReturn( rtn.getType(), rtn.getColumnAlias() ) );
}
else if ( queryReturn instanceof NativeSQLQueryRootReturn ) {
NativeSQLQueryRootReturn rtn = (NativeSQLQueryRootReturn) queryReturn;
String alias = rtn.getAlias();
EntityAliases entityAliases;
if ( queryHadAliases || hasPropertyResultMap( alias ) ) {
entityAliases = new DefaultEntityAliases(
(Map) entityPropertyResultMaps.get( alias ),
(SQLLoadable) alias2Persister.get( alias ),
(String) alias2Suffix.get( alias )
);
}
else {
entityAliases = new ColumnEntityAliases(
(Map) entityPropertyResultMaps.get( alias ),
(SQLLoadable) alias2Persister.get( alias ),
(String) alias2Suffix.get( alias )
);
}
RootReturn customReturn = new RootReturn(
alias,
rtn.getReturnEntityName(),
entityAliases,
rtn.getLockMode()
);
customReturns.add( customReturn );
customReturnsByAlias.put( rtn.getAlias(), customReturn );
}
else if ( queryReturn instanceof NativeSQLQueryCollectionReturn ) {
NativeSQLQueryCollectionReturn rtn = (NativeSQLQueryCollectionReturn) queryReturn;
String alias = rtn.getAlias();
SQLLoadableCollection persister = (SQLLoadableCollection) alias2CollectionPersister.get( alias );
boolean isEntityElements = persister.getElementType().isEntityType();
CollectionAliases collectionAliases;
EntityAliases elementEntityAliases = null;
if ( queryHadAliases || hasPropertyResultMap( alias ) ) {
collectionAliases = new GeneratedCollectionAliases(
(Map) collectionPropertyResultMaps.get( alias ),
(SQLLoadableCollection) alias2CollectionPersister.get( alias ),
(String) alias2CollectionSuffix.get( alias )
);
if ( isEntityElements ) {
elementEntityAliases = new DefaultEntityAliases(
(Map) entityPropertyResultMaps.get( alias ),
(SQLLoadable) alias2Persister.get( alias ),
(String) alias2Suffix.get( alias )
);
}
}
else {
collectionAliases = new ColumnCollectionAliases(
(Map) collectionPropertyResultMaps.get( alias ),
(SQLLoadableCollection) alias2CollectionPersister.get( alias )
);
if ( isEntityElements ) {
elementEntityAliases = new ColumnEntityAliases(
(Map) entityPropertyResultMaps.get( alias ),
(SQLLoadable) alias2Persister.get( alias ),
(String) alias2Suffix.get( alias )
);
}
}
CollectionReturn customReturn = new CollectionReturn(
alias,
rtn.getOwnerEntityName(),
rtn.getOwnerProperty(),
collectionAliases,
elementEntityAliases,
rtn.getLockMode()
);
customReturns.add( customReturn );
customReturnsByAlias.put( rtn.getAlias(), customReturn );
}
else if ( queryReturn instanceof NativeSQLQueryJoinReturn ) {
NativeSQLQueryJoinReturn rtn = (NativeSQLQueryJoinReturn) queryReturn;
String alias = rtn.getAlias();
FetchReturn customReturn;
NonScalarReturn ownerCustomReturn = (NonScalarReturn) customReturnsByAlias.get( rtn.getOwnerAlias() );
if ( alias2CollectionPersister.containsKey( alias ) ) {
SQLLoadableCollection persister = (SQLLoadableCollection) alias2CollectionPersister.get( alias );
boolean isEntityElements = persister.getElementType().isEntityType();
CollectionAliases collectionAliases;
EntityAliases elementEntityAliases = null;
if ( queryHadAliases || hasPropertyResultMap( alias ) ) {
collectionAliases = new GeneratedCollectionAliases(
(Map) collectionPropertyResultMaps.get( alias ),
persister,
(String) alias2CollectionSuffix.get( alias )
);
if ( isEntityElements ) {
elementEntityAliases = new DefaultEntityAliases(
(Map) entityPropertyResultMaps.get( alias ),
(SQLLoadable) alias2Persister.get( alias ),
(String) alias2Suffix.get( alias )
);
}
}
else {
collectionAliases = new ColumnCollectionAliases(
(Map) collectionPropertyResultMaps.get( alias ),
persister
);
if ( isEntityElements ) {
elementEntityAliases = new ColumnEntityAliases(
(Map) entityPropertyResultMaps.get( alias ),
(SQLLoadable) alias2Persister.get( alias ),
(String) alias2Suffix.get( alias )
);
}
}
customReturn = new CollectionFetchReturn(
alias,
ownerCustomReturn,
rtn.getOwnerProperty(),
collectionAliases,
elementEntityAliases,
rtn.getLockMode()
);
}
else {
EntityAliases entityAliases;
if ( queryHadAliases || hasPropertyResultMap( alias ) ) {
entityAliases = new DefaultEntityAliases(
(Map) entityPropertyResultMaps.get( alias ),
(SQLLoadable) alias2Persister.get( alias ),
(String) alias2Suffix.get( alias )
);
}
else {
entityAliases = new ColumnEntityAliases(
(Map) entityPropertyResultMaps.get( alias ),
(SQLLoadable) alias2Persister.get( alias ),
(String) alias2Suffix.get( alias )
);
}
customReturn = new EntityFetchReturn(
alias,
entityAliases,
ownerCustomReturn,
rtn.getOwnerProperty(),
rtn.getLockMode()
);
}
customReturns.add( customReturn );
customReturnsByAlias.put( alias, customReturn );
}
else if ( NativeSQLQueryConstructorReturn.class.isInstance( queryReturn ) ) {
final NativeSQLQueryConstructorReturn constructorReturn = (NativeSQLQueryConstructorReturn) queryReturn;
final ScalarReturn[] scalars = new ScalarReturn[ constructorReturn.getColumnReturns().length ];
int i = 0;
for ( NativeSQLQueryScalarReturn scalarReturn : constructorReturn.getColumnReturns() ) {
scalars[i++] = new ScalarReturn( scalarReturn.getType(), scalarReturn.getColumnAlias() );
}
customReturns.add( new ConstructorReturn( constructorReturn.getTargetClass(), scalars ) );
}
else {
throw new IllegalStateException(
"Unrecognized NativeSQLQueryReturn concrete type : " + queryReturn
);
}
}
return customReturns;
}
public List<Return> generateCallableReturns() {
final List<Return> customReturns = new ArrayList<>();
visitReturns(
new QueryReturnVisitor() {
@Override
public void visitScalarReturn(NativeSQLQueryScalarReturn rtn) {
customReturns.add( new ScalarReturn( rtn.getType(), rtn.getColumnAlias() ) );
}
@Override
public void visitRootReturn(NativeSQLQueryRootReturn rtn) {
customReturns.add(
new RootReturn(
rtn.getAlias(),
rtn.getReturnEntityName(),
new ColumnEntityAliases(
(Map) entityPropertyResultMaps.get( rtn.getAlias() ),
(SQLLoadable) alias2Persister.get( rtn.getAlias() ),
(String) alias2Suffix.get( rtn.getAlias() )
),
rtn.getLockMode()
)
);
}
@Override
public void visitCollectionReturn(NativeSQLQueryCollectionReturn rtn) {
throw new UnsupportedOperationException( "Collection returns not supported for stored procedure mapping" );
}
@Override
public void visitFetch(NativeSQLQueryJoinReturn rtn) {
throw new UnsupportedOperationException( "Collection returns not supported for stored procedure mapping" );
}
@Override
public void visitDynamicInstantiation(NativeSQLQueryConstructorReturn rtn) {
final ScalarReturn[] scalars = new ScalarReturn[ rtn.getColumnReturns().length ];
int i = 0;
for ( NativeSQLQueryScalarReturn scalarReturn : rtn.getColumnReturns() ) {
scalars[i++] = new ScalarReturn( scalarReturn.getType(), scalarReturn.getColumnAlias() );
}
customReturns.add( new ConstructorReturn( rtn.getTargetClass(), scalars ) );
}
}
);
return customReturns;
}
private SQLLoadable getSQLLoadable(String entityName) throws MappingException {
EntityPersister persister = factory.getEntityPersister( entityName );
if ( !(persister instanceof SQLLoadable) ) {
throw new MappingException( "class persister is not SQLLoadable: " + entityName );
}
return (SQLLoadable) persister;
}
private String generateEntitySuffix() {
return BasicLoader.generateSuffixes( entitySuffixSeed++, 1 )[0];
}
private String generateCollectionSuffix() {
return collectionSuffixSeed++ + "__";
}
private void processReturn(NativeSQLQueryReturn rtn) {
if ( rtn instanceof NativeSQLQueryScalarReturn ) {
processScalarReturn( ( NativeSQLQueryScalarReturn ) rtn );
}
else if ( rtn instanceof NativeSQLQueryRootReturn ) {
processRootReturn( ( NativeSQLQueryRootReturn ) rtn );
}
else if ( rtn instanceof NativeSQLQueryCollectionReturn ) {
processCollectionReturn( (NativeSQLQueryCollectionReturn) rtn );
}
else if ( NativeSQLQueryJoinReturn.class.isInstance( rtn ) ) {
processJoinReturn( ( NativeSQLQueryJoinReturn ) rtn );
}
else if ( NativeSQLQueryConstructorReturn.class.isInstance( rtn ) ) {
processConstructorReturn( (NativeSQLQueryConstructorReturn) rtn );
}
else {
throw new IllegalStateException(
"Unrecognized NativeSQLQueryReturn concrete type encountered : " + rtn
);
}
}
private void processConstructorReturn(NativeSQLQueryConstructorReturn rtn) {
//To change body of created methods use File | Settings | File Templates.
}
private void processScalarReturn(NativeSQLQueryScalarReturn typeReturn) {
// scalarColumnAliases.add( typeReturn.getColumnAlias() );
// scalarTypes.add( typeReturn.getType() );
}
private void processRootReturn(NativeSQLQueryRootReturn rootReturn) {
if ( alias2Persister.containsKey( rootReturn.getAlias() ) ) {
// already been processed...
return;
}
SQLLoadable persister = getSQLLoadable( rootReturn.getReturnEntityName() );
addPersister( rootReturn.getAlias(), rootReturn.getPropertyResultsMap(), persister );
}
private void addPersister(String alias, Map propertyResult, SQLLoadable persister) {
alias2Persister.put( alias, persister );
String suffix = generateEntitySuffix();
LOG.tracev( "Mapping alias [{0}] to entity-suffix [{1}]", alias, suffix );
alias2Suffix.put( alias, suffix );
entityPropertyResultMaps.put( alias, propertyResult );
}
private void addCollection(String role, String alias, Map propertyResults) {
SQLLoadableCollection collectionPersister = ( SQLLoadableCollection ) factory.getCollectionPersister( role );
alias2CollectionPersister.put( alias, collectionPersister );
String suffix = generateCollectionSuffix();
LOG.tracev( "Mapping alias [{0}] to collection-suffix [{1}]", alias, suffix );
alias2CollectionSuffix.put( alias, suffix );
collectionPropertyResultMaps.put( alias, propertyResults );
if ( collectionPersister.isOneToMany() || collectionPersister.isManyToMany() ) {
SQLLoadable persister = ( SQLLoadable ) collectionPersister.getElementPersister();
addPersister( alias, filter( propertyResults ), persister );
}
}
private Map filter(Map propertyResults) {
Map result = new HashMap( propertyResults.size() );
String keyPrefix = "element.";
Iterator iter = propertyResults.entrySet().iterator();
while ( iter.hasNext() ) {
Map.Entry element = ( Map.Entry ) iter.next();
String path = ( String ) element.getKey();
if ( path.startsWith( keyPrefix ) ) {
result.put( path.substring( keyPrefix.length() ), element.getValue() );
}
}
return result;
}
private void processCollectionReturn(NativeSQLQueryCollectionReturn collectionReturn) {
// we are initializing an owned collection
//collectionOwners.add( new Integer(-1) );
// collectionOwnerAliases.add( null );
String role = collectionReturn.getOwnerEntityName() + '.' + collectionReturn.getOwnerProperty();
addCollection(
role,
collectionReturn.getAlias(),
collectionReturn.getPropertyResultsMap()
);
}
private void processJoinReturn(NativeSQLQueryJoinReturn fetchReturn) {
String alias = fetchReturn.getAlias();
// if ( alias2Persister.containsKey( alias ) || collectionAliases.contains( alias ) ) {
if ( alias2Persister.containsKey( alias ) || alias2CollectionPersister.containsKey( alias ) ) {
// already been processed...
return;
}
String ownerAlias = fetchReturn.getOwnerAlias();
// Make sure the owner alias is known...
if ( !alias2Return.containsKey( ownerAlias ) ) {
throw new HibernateException( "Owner alias [" + ownerAlias + "] is unknown for alias [" + alias + "]" );
}
// If this return's alias has not been processed yet, do so b4 further processing of this return
if ( !alias2Persister.containsKey( ownerAlias ) ) {
NativeSQLQueryNonScalarReturn ownerReturn = ( NativeSQLQueryNonScalarReturn ) alias2Return.get(ownerAlias);
processReturn( ownerReturn );
}
SQLLoadable ownerPersister = ( SQLLoadable ) alias2Persister.get( ownerAlias );
Type returnType = ownerPersister.getPropertyType( fetchReturn.getOwnerProperty() );
if ( returnType.isCollectionType() ) {
String role = ownerPersister.getEntityName() + '.' + fetchReturn.getOwnerProperty();
addCollection( role, alias, fetchReturn.getPropertyResultsMap() );
// collectionOwnerAliases.add( ownerAlias );
}
else if ( returnType.isEntityType() ) {
EntityType eType = ( EntityType ) returnType;
String returnEntityName = eType.getAssociatedEntityName();
SQLLoadable persister = getSQLLoadable( returnEntityName );
addPersister( alias, fetchReturn.getPropertyResultsMap(), persister );
}
}
// public List getCollectionAliases() {
// return collectionAliases;
// }
//
// /*public List getCollectionOwners() {
// return collectionOwners;
// }*/
//
// public List getCollectionOwnerAliases() {
// return collectionOwnerAliases;
// }
//
// public List getCollectionPersisters() {
// return collectionPersisters;
// }
//
// public Map getAlias2Persister() {
// return alias2Persister;
// }
//
// /*public boolean isCollectionInitializer() {
// return isCollectionInitializer;
// }*/
//
//// public List getPersisters() {
//// return persisters;
//// }
//
// public Map getAlias2OwnerAlias() {
// return alias2OwnerAlias;
// }
//
// public List getScalarTypes() {
// return scalarTypes;
// }
// public List getScalarColumnAliases() {
// return scalarColumnAliases;
// }
//
// public List getPropertyResults() {
// return propertyResults;
// }
//
// public List getCollectionPropertyResults() {
// return collectionResults;
// }
//
//
// public Map getAlias2Return() {
// return alias2Return;
// }
}

View File

@ -1,108 +0,0 @@
/*
* 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.loader.entity;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.OuterJoinLoader;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.Type;
public abstract class AbstractEntityLoader
extends OuterJoinLoader
implements UniqueEntityLoader {
protected final OuterJoinLoadable persister;
protected final Type uniqueKeyType;
protected final String entityName;
public AbstractEntityLoader(
OuterJoinLoadable persister,
Type uniqueKeyType,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
super( factory, loadQueryInfluencers );
this.uniqueKeyType = uniqueKeyType;
this.entityName = persister.getEntityName();
this.persister = persister;
}
@Override
public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session) {
// this form is deprecated!
return load( id, optionalObject, session, LockOptions.NONE );
}
@Override
public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session, LockOptions lockOptions) {
return load( session, id, optionalObject, id, lockOptions );
}
protected Object load(
SharedSessionContractImplementor session,
Object id,
Object optionalObject,
Serializable optionalId,
LockOptions lockOptions) {
List list = loadEntity(
session,
id,
uniqueKeyType,
optionalObject,
entityName,
optionalId,
persister,
lockOptions
);
if ( list.size()==1 ) {
return list.get(0);
}
else if ( list.size()==0 ) {
return null;
}
else {
if ( getCollectionOwners()!=null ) {
return list.get(0);
}
else {
throw new HibernateException(
"More than one row with the given identifier was found: " +
id +
", for class: " +
persister.getEntityName()
);
}
}
}
@Override
protected Object getResultColumnOrRow(
Object[] row,
ResultTransformer transformer,
ResultSet rs,
SharedSessionContractImplementor session) {
return row[ row.length - 1 ];
}
@Override
protected boolean isSingleRowLoader() {
return true;
}
}

View File

@ -1,121 +0,0 @@
/*
* 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.loader.entity;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import org.hibernate.LockOptions;
import org.hibernate.engine.internal.BatchFetchQueueHelper;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.Loader;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
/**
* The base contract for loaders capable of performing batch-fetch loading of entities using multiple primary key
* values in the SQL <tt>WHERE</tt> clause.
*
* @author Gavin King
* @author Steve Ebersole
*
* @see BatchingEntityLoaderBuilder
* @see UniqueEntityLoader
*/
public abstract class BatchingEntityLoader implements UniqueEntityLoader {
private static final Logger log = Logger.getLogger( BatchingEntityLoader.class );
private final EntityPersister persister;
public BatchingEntityLoader(EntityPersister persister) {
this.persister = persister;
}
public EntityPersister persister() {
return persister;
}
@Override
public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session) {
return load( id, optionalObject, session, LockOptions.NONE );
}
protected QueryParameters buildQueryParameters(
Serializable id,
Serializable[] ids,
Object optionalObject,
LockOptions lockOptions) {
Type[] types = new Type[ids.length];
Arrays.fill( types, persister().getIdentifierType() );
QueryParameters qp = new QueryParameters();
qp.setPositionalParameterTypes( types );
qp.setPositionalParameterValues( ids );
qp.setOptionalObject( optionalObject );
qp.setOptionalEntityName( persister().getEntityName() );
qp.setOptionalId( id );
qp.setLockOptions( lockOptions );
return qp;
}
protected Object getObjectFromList(List results, Serializable id, SharedSessionContractImplementor session) {
for ( Object obj : results ) {
final boolean equal = persister.getIdentifierType().isEqual(
id,
session.getContextEntityIdentifier( obj ),
session.getFactory()
);
if ( equal ) {
return obj;
}
}
return null;
}
protected Object doBatchLoad(
Serializable id,
Loader loaderToUse,
SharedSessionContractImplementor session,
Serializable[] ids,
Object optionalObject,
LockOptions lockOptions) {
if ( log.isDebugEnabled() ) {
log.debugf( "Batch loading entity: %s", MessageHelper.infoString( persister, ids, session.getFactory() ) );
}
QueryParameters qp = buildQueryParameters( id, ids, optionalObject, lockOptions );
try {
final List results = loaderToUse.doQueryAndInitializeNonLazyCollections( session, qp, false );
log.debug( "Done entity batch load" );
// The EntityKey for any entity that is not found will remain in the batch.
// Explicitly remove the EntityKeys for entities that were not found to
// avoid including them in future batches that get executed.
BatchFetchQueueHelper.removeNotFoundBatchLoadableEntityKeys(
ids,
results,
persister(),
session
);
return getObjectFromList(results, id, session);
}
catch ( SQLException sqle ) {
throw session.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not load an entity batch: " + MessageHelper.infoString( persister(), ids, session.getFactory() ),
loaderToUse.getSQLString()
);
}
}
}

View File

@ -1,117 +0,0 @@
/*
* 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.loader.entity;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.entity.OuterJoinLoadable;
/**
* The contract for building {@link UniqueEntityLoader} capable of performing batch-fetch loading. Intention
* is to build these instances, by first calling the static {@link #getBuilder}, and then calling the appropriate
* {@link #buildLoader} method.
*
* @author Steve Ebersole
*
* @see org.hibernate.loader.BatchFetchStyle
*/
public abstract class BatchingEntityLoaderBuilder {
public static BatchingEntityLoaderBuilder getBuilder(SessionFactoryImplementor factory) {
switch ( factory.getSettings().getBatchFetchStyle() ) {
case PADDED: {
return PaddedBatchingEntityLoaderBuilder.INSTANCE;
}
case DYNAMIC: {
return DynamicBatchingEntityLoaderBuilder.INSTANCE;
}
default: {
return org.hibernate.loader.entity.plan.LegacyBatchingEntityLoaderBuilder.INSTANCE;
// return LegacyBatchingEntityLoaderBuilder.INSTANCE;
}
}
}
/**
* Builds a batch-fetch capable loader based on the given persister, lock-mode, etc.
*
* @param persister The entity persister
* @param batchSize The maximum number of ids to batch-fetch at once
* @param lockMode The lock mode
* @param factory The SessionFactory
* @param influencers Any influencers that should affect the built query
*
* @return The loader.
*/
public UniqueEntityLoader buildLoader(
OuterJoinLoadable persister,
int batchSize,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
if ( batchSize <= 1 ) {
// no batching
return buildNonBatchingLoader( persister, lockMode, factory, influencers );
}
return buildBatchingLoader( persister, batchSize, lockMode, factory, influencers );
}
protected UniqueEntityLoader buildNonBatchingLoader(
OuterJoinLoadable persister,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return new EntityLoader( persister, lockMode, factory, influencers );
}
protected abstract UniqueEntityLoader buildBatchingLoader(
OuterJoinLoadable persister,
int batchSize,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers);
/**
* Builds a batch-fetch capable loader based on the given persister, lock-options, etc.
*
* @param persister The entity persister
* @param batchSize The maximum number of ids to batch-fetch at once
* @param lockOptions The lock options
* @param factory The SessionFactory
* @param influencers Any influencers that should affect the built query
*
* @return The loader.
*/
public UniqueEntityLoader buildLoader(
OuterJoinLoadable persister,
int batchSize,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
if ( batchSize <= 1 ) {
// no batching
return buildNonBatchingLoader( persister, lockOptions, factory, influencers );
}
return buildBatchingLoader( persister, batchSize, lockOptions, factory, influencers );
}
protected UniqueEntityLoader buildNonBatchingLoader(
OuterJoinLoadable persister,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return new EntityLoader( persister, lockOptions, factory, influencers );
}
protected abstract UniqueEntityLoader buildBatchingLoader(
OuterJoinLoadable persister,
int batchSize,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers);
}

View File

@ -1,56 +0,0 @@
/*
* 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.loader.entity;
import java.util.Collections;
import org.hibernate.FetchMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.CascadingAction;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.AbstractEntityJoinWalker;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.type.AssociationType;
public class CascadeEntityJoinWalker extends AbstractEntityJoinWalker {
private final CascadingAction cascadeAction;
public CascadeEntityJoinWalker(
OuterJoinLoadable persister,
CascadingAction action,
SessionFactoryImplementor factory)
throws MappingException {
super( persister, factory, LoadQueryInfluencers.NONE );
this.cascadeAction = action;
StringBuilder whereCondition = whereString( getAlias(), persister.getIdentifierColumnNames(), 1 )
//include the discriminator and class-level where, but not filters
.append( persister.filterFragment( getAlias(), Collections.EMPTY_MAP ) );
initAll( whereCondition.toString(), "", LockOptions.READ );
}
@Override
protected boolean isJoinedFetchEnabled(AssociationType type, FetchMode config, CascadeStyle cascadeStyle) {
return ( type.isEntityType() || type.isCollectionType() ) &&
( cascadeStyle == null || cascadeStyle.doCascade( cascadeAction ) );
}
@Override
protected boolean isTooManyCollections() {
return countCollectionPersisters( associations ) > 0;
}
@Override
public String getComment() {
return "load " + getPersister().getEntityName();
}
}

View File

@ -1,42 +0,0 @@
/*
* 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.loader.entity;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.CascadingAction;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.JoinWalker;
import org.hibernate.persister.entity.OuterJoinLoadable;
public class CascadeEntityLoader extends AbstractEntityLoader {
public CascadeEntityLoader(
OuterJoinLoadable persister,
CascadingAction action,
SessionFactoryImplementor factory) throws MappingException {
super(
persister,
persister.getIdentifierType(),
factory,
LoadQueryInfluencers.NONE
);
JoinWalker walker = new CascadeEntityJoinWalker(
persister,
action,
factory
);
initFromWalker( walker );
postInstantiate();
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Static select for action %s on entity %s: %s", action, entityName, getSQLString() );
}
}
}

View File

@ -1,119 +0,0 @@
/*
* 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.loader.entity;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.JoinWalker;
import org.hibernate.loader.OuterJoinLoader;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
/**
* @author Gavin King
*/
public class CollectionElementLoader extends OuterJoinLoader {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
CollectionElementLoader.class.getName()
);
private final OuterJoinLoadable persister;
private final Type keyType;
private final Type indexType;
private final String entityName;
public CollectionElementLoader(
QueryableCollection collectionPersister,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
super( factory, loadQueryInfluencers );
this.keyType = collectionPersister.getKeyType();
this.indexType = collectionPersister.getIndexType();
this.persister = (OuterJoinLoadable) collectionPersister.getElementPersister();
this.entityName = persister.getEntityName();
JoinWalker walker = new EntityJoinWalker(
persister,
ArrayHelper.join(
collectionPersister.getKeyColumnNames(),
collectionPersister.toColumns( "index" )
),
1,
LockMode.NONE,
factory,
loadQueryInfluencers
);
initFromWalker( walker );
postInstantiate();
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Static select for entity %s: %s", entityName, getSQLString() );
}
}
public Object loadElement(SharedSessionContractImplementor session, Object key, Object index)
throws HibernateException {
List list = loadEntity(
session,
key,
index,
keyType,
indexType,
persister
);
if ( list.size() == 1 ) {
return list.get( 0 );
}
else if ( list.size() == 0 ) {
return null;
}
else {
if ( getCollectionOwners() != null ) {
return list.get( 0 );
}
else {
throw new HibernateException( "More than one row was found" );
}
}
}
@Override
protected Object getResultColumnOrRow(
Object[] row,
ResultTransformer transformer,
ResultSet rs,
SharedSessionContractImplementor session) {
return row[row.length - 1];
}
@Override
protected boolean isSingleRowLoader() {
return true;
}
}

View File

@ -1,580 +0,0 @@
/*
* 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.loader.entity;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.internal.BatchFetchQueueHelper;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.LoadEvent;
import org.hibernate.event.spi.LoadEventListener;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.loader.ast.spi.AfterLoadAction;
import org.hibernate.persister.entity.MultiLoadOptions;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
/**
* A BatchingEntityLoaderBuilder that builds UniqueEntityLoader instances capable of dynamically building
* its batch-fetch SQL based on the actual number of entity ids waiting to be fetched.
*
* @see Dialect#getDefaultBatchLoadSizingStrategy
*
* @author Steve Ebersole
*/
public class DynamicBatchingEntityLoaderBuilder extends BatchingEntityLoaderBuilder {
private static final Logger log = Logger.getLogger( DynamicBatchingEntityLoaderBuilder.class );
public static final DynamicBatchingEntityLoaderBuilder INSTANCE = new DynamicBatchingEntityLoaderBuilder();
public List multiLoad(
OuterJoinLoadable persister,
Serializable[] ids,
SharedSessionContractImplementor session,
MultiLoadOptions loadOptions) {
if ( loadOptions.isOrderReturnEnabled() ) {
return performOrderedMultiLoad( persister, ids, session, loadOptions );
}
else {
return performUnorderedMultiLoad( persister, ids, session, loadOptions );
}
}
@SuppressWarnings("unchecked")
private List performOrderedMultiLoad(
OuterJoinLoadable persister,
Serializable[] ids,
SharedSessionContractImplementor session,
MultiLoadOptions loadOptions) {
assert loadOptions.isOrderReturnEnabled();
final List result = CollectionHelper.arrayList( ids.length );
final LockOptions lockOptions = (loadOptions.getLockOptions() == null)
? new LockOptions( LockMode.NONE )
: loadOptions.getLockOptions();
Integer batchSize = loadOptions.getBatchSize();
if ( batchSize == null || batchSize <= 0 ) {
batchSize = session.getJdbcServices().getJdbcEnvironment().getDialect().getDefaultBatchLoadSizingStrategy().determineOptimalBatchLoadSize(
persister.getIdentifierType().getColumnSpan( session.getFactory() ),
ids.length
);
}
final List<Object> idsInBatch = new ArrayList<>();
final List<Integer> elementPositionsLoadedByBatch = new ArrayList<>();
for ( int i = 0; i < ids.length; i++ ) {
final Serializable id = ids[i];
final EntityKey entityKey = new EntityKey( id, persister );
if ( loadOptions.isSessionCheckingEnabled() || loadOptions.isSecondLevelCacheCheckingEnabled() ) {
LoadEvent loadEvent = new LoadEvent(
id,
persister.getMappedClass().getName(),
lockOptions,
(EventSource) session
);
Object managedEntity = null;
if ( loadOptions.isSessionCheckingEnabled() ) {
// look for it in the Session first
CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry = CacheEntityLoaderHelper.INSTANCE
.loadFromSessionCache(
loadEvent,
entityKey,
LoadEventListener.GET
);
managedEntity = persistenceContextEntry.getEntity();
if ( managedEntity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() && !persistenceContextEntry
.isManaged() ) {
// put a null in the result
result.add( i, null );
continue;
}
}
if ( managedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) {
// look for it in the SessionFactory
managedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(
loadEvent,
persister,
entityKey
);
}
if ( managedEntity != null ) {
result.add( i, managedEntity );
continue;
}
}
// if we did not hit any of the continues above, then we need to batch
// load the entity state.
idsInBatch.add( ids[i] );
if ( idsInBatch.size() >= batchSize ) {
// we've hit the allotted max-batch-size, perform an "intermediate load"
performOrderedBatchLoad( idsInBatch, lockOptions, persister, session );
}
// Save the EntityKey instance for use later!
result.add( i, entityKey );
elementPositionsLoadedByBatch.add( i );
}
if ( !idsInBatch.isEmpty() ) {
// we still have ids to load from the processing above since the last max-batch-size trigger,
// perform a load for them
performOrderedBatchLoad( idsInBatch, lockOptions, persister, session );
}
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
for ( Integer position : elementPositionsLoadedByBatch ) {
// the element value at this position in the result List should be
// the EntityKey for that entity; reuse it!
final EntityKey entityKey = (EntityKey) result.get( position );
Object entity = persistenceContext.getEntity( entityKey );
if ( entity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() ) {
// make sure it is not DELETED
final EntityEntry entry = persistenceContext.getEntry( entity );
if ( entry.getStatus() == Status.DELETED || entry.getStatus() == Status.GONE ) {
// the entity is locally deleted, and the options ask that we not return such entities...
entity = null;
}
}
result.set( position, entity );
}
return result;
}
private void performOrderedBatchLoad(
List<Object> idsInBatch,
LockOptions lockOptions,
OuterJoinLoadable persister,
SharedSessionContractImplementor session) {
final int batchSize = idsInBatch.size();
final DynamicEntityLoader batchingLoader = new DynamicEntityLoader(
persister,
batchSize,
lockOptions,
session.getFactory(),
session.getLoadQueryInfluencers()
);
final Object[] idsInBatchArray = idsInBatch.toArray( new Object[ idsInBatch.size() ] );
QueryParameters qp = buildMultiLoadQueryParameters( persister, idsInBatchArray, lockOptions );
batchingLoader.doEntityBatchFetch( session, qp, idsInBatchArray );
idsInBatch.clear();
}
@SuppressWarnings("unchecked")
protected List performUnorderedMultiLoad(
OuterJoinLoadable persister,
Serializable[] ids,
SharedSessionContractImplementor session,
MultiLoadOptions loadOptions) {
assert !loadOptions.isOrderReturnEnabled();
final List result = CollectionHelper.arrayList( ids.length );
final LockOptions lockOptions = (loadOptions.getLockOptions() == null)
? new LockOptions( LockMode.NONE )
: loadOptions.getLockOptions();
if ( loadOptions.isSessionCheckingEnabled() || loadOptions.isSecondLevelCacheCheckingEnabled() ) {
// the user requested that we exclude ids corresponding to already managed
// entities from the generated load SQL. So here we will iterate all
// incoming id values and see whether it corresponds to an existing
// entity associated with the PC - if it does we add it to the result
// list immediately and remove its id from the group of ids to load.
boolean foundAnyManagedEntities = false;
final List<Serializable> nonManagedIds = new ArrayList<Serializable>();
for ( Serializable id : ids ) {
final EntityKey entityKey = new EntityKey( id, persister );
LoadEvent loadEvent = new LoadEvent(
id,
persister.getMappedClass().getName(),
lockOptions,
(EventSource) session
);
Object managedEntity = null;
// look for it in the Session first
CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry = CacheEntityLoaderHelper.INSTANCE
.loadFromSessionCache(
loadEvent,
entityKey,
LoadEventListener.GET
);
if ( loadOptions.isSessionCheckingEnabled() ) {
managedEntity = persistenceContextEntry.getEntity();
if ( managedEntity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() && !persistenceContextEntry
.isManaged() ) {
foundAnyManagedEntities = true;
result.add( null );
continue;
}
}
if ( managedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) {
managedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(
loadEvent,
persister,
entityKey
);
}
if ( managedEntity != null ) {
foundAnyManagedEntities = true;
result.add( managedEntity );
}
else {
nonManagedIds.add( id );
}
}
if ( foundAnyManagedEntities ) {
if ( nonManagedIds.isEmpty() ) {
// all of the given ids were already associated with the Session
return result;
}
else {
// over-write the ids to be loaded with the collection of
// just non-managed ones
ids = nonManagedIds.toArray(
(Serializable[]) Array.newInstance(
ids.getClass().getComponentType(),
nonManagedIds.size()
)
);
}
}
}
int numberOfIdsLeft = ids.length;
final int maxBatchSize;
if ( loadOptions.getBatchSize() != null && loadOptions.getBatchSize() > 0 ) {
maxBatchSize = loadOptions.getBatchSize();
}
else {
maxBatchSize = session.getJdbcServices().getJdbcEnvironment().getDialect().getDefaultBatchLoadSizingStrategy().determineOptimalBatchLoadSize(
persister.getIdentifierType().getColumnSpan( session.getFactory() ),
numberOfIdsLeft
);
}
int idPosition = 0;
while ( numberOfIdsLeft > 0 ) {
int batchSize = Math.min( numberOfIdsLeft, maxBatchSize );
final DynamicEntityLoader batchingLoader = new DynamicEntityLoader(
persister,
batchSize,
lockOptions,
session.getFactory(),
session.getLoadQueryInfluencers()
);
Serializable[] idsInBatch = new Serializable[batchSize];
System.arraycopy( ids, idPosition, idsInBatch, 0, batchSize );
QueryParameters qp = buildMultiLoadQueryParameters( persister, idsInBatch, lockOptions );
result.addAll( batchingLoader.doEntityBatchFetch( session, qp, idsInBatch ) );
numberOfIdsLeft = numberOfIdsLeft - batchSize;
idPosition += batchSize;
}
return result;
}
public static QueryParameters buildMultiLoadQueryParameters(
OuterJoinLoadable persister,
Object[] ids,
LockOptions lockOptions) {
Type[] types = new Type[ids.length];
Arrays.fill( types, persister.getIdentifierType() );
QueryParameters qp = new QueryParameters();
qp.setOptionalEntityName( persister.getEntityName() );
qp.setPositionalParameterTypes( types );
qp.setPositionalParameterValues( ids );
qp.setLockOptions( lockOptions );
qp.setOptionalObject( null );
qp.setOptionalId( null );
return qp;
}
@Override
protected UniqueEntityLoader buildBatchingLoader(
OuterJoinLoadable persister,
int batchSize,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return new DynamicBatchingEntityLoader( persister, batchSize, lockMode, factory, influencers );
}
@Override
protected UniqueEntityLoader buildBatchingLoader(
OuterJoinLoadable persister,
int batchSize,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return new DynamicBatchingEntityLoader( persister, batchSize, lockOptions, factory, influencers );
}
public static class DynamicBatchingEntityLoader extends BatchingEntityLoader {
private final int maxBatchSize;
private final UniqueEntityLoader singleKeyLoader;
private final DynamicEntityLoader dynamicLoader;
public DynamicBatchingEntityLoader(
OuterJoinLoadable persister,
int maxBatchSize,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
super( persister );
this.maxBatchSize = maxBatchSize;
this.singleKeyLoader = new EntityLoader( persister, 1, lockMode, factory, loadQueryInfluencers );
this.dynamicLoader = new DynamicEntityLoader( persister, maxBatchSize, lockMode, factory, loadQueryInfluencers );
}
public DynamicBatchingEntityLoader(
OuterJoinLoadable persister,
int maxBatchSize,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
super( persister );
this.maxBatchSize = maxBatchSize;
this.singleKeyLoader = new EntityLoader( persister, 1, lockOptions, factory, loadQueryInfluencers );
this.dynamicLoader = new DynamicEntityLoader( persister, maxBatchSize, lockOptions, factory, loadQueryInfluencers );
}
@Override
public Object load(
Serializable id,
Object optionalObject,
SharedSessionContractImplementor session,
LockOptions lockOptions) {
final Object[] batch = session.getPersistenceContextInternal()
.getBatchFetchQueue()
.getBatchLoadableEntityIds( persister(), id, maxBatchSize );
final int numberOfIds = ArrayHelper.countNonNull( batch );
if ( numberOfIds <= 1 ) {
final Object result = singleKeyLoader.load( id, optionalObject, session );
if ( result == null ) {
// There was no entity with the specified ID. Make sure the EntityKey does not remain
// in the batch to avoid including it in future batches that get executed.
BatchFetchQueueHelper.removeBatchLoadableEntityKey( id, persister(), session );
}
return result;
}
final Serializable[] idsToLoad = new Serializable[numberOfIds];
System.arraycopy( batch, 0, idsToLoad, 0, numberOfIds );
if ( log.isDebugEnabled() ) {
log.debugf( "Batch loading entity: %s", MessageHelper.infoString( persister(), idsToLoad, session.getFactory() ) );
}
QueryParameters qp = buildQueryParameters( id, idsToLoad, optionalObject, lockOptions );
List results = dynamicLoader.doEntityBatchFetch( session, qp, idsToLoad );
// The EntityKey for any entity that is not found will remain in the batch.
// Explicitly remove the EntityKeys for entities that were not found to
// avoid including them in future batches that get executed.
BatchFetchQueueHelper.removeNotFoundBatchLoadableEntityKeys( idsToLoad, results, persister(), session );
return getObjectFromList( results, id, session );
}
}
private static class DynamicEntityLoader extends EntityLoader {
// todo : see the discussion on org.hibernate.loader.collection.DynamicBatchingCollectionInitializerBuilder.DynamicBatchingCollectionLoader
private final String sqlTemplate;
private final String alias;
public DynamicEntityLoader(
OuterJoinLoadable persister,
int maxBatchSize,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
this( persister, maxBatchSize, lockOptions.getLockMode(), factory, loadQueryInfluencers );
}
public DynamicEntityLoader(
OuterJoinLoadable persister,
int maxBatchSize,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
super( persister, -1, lockMode, factory, loadQueryInfluencers );
EntityJoinWalker walker = new EntityJoinWalker(
persister,
persister.getIdentifierColumnNames(),
-1,
lockMode,
factory,
loadQueryInfluencers) {
@Override
protected StringBuilder whereString(String alias, String[] columnNames, int batchSize) {
return StringHelper.buildBatchFetchRestrictionFragment(
alias,
columnNames,
getFactory().getDialect()
);
}
};
initFromWalker( walker );
this.sqlTemplate = walker.getSQLString();
this.alias = walker.getAlias();
postInstantiate();
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"SQL-template for dynamic entity [%s] batch-fetching [%s] : %s",
entityName,
lockMode,
sqlTemplate
);
}
}
@Override
protected boolean isSingleRowLoader() {
return false;
}
@Override
protected boolean isSubselectLoadingEnabled() {
return persister.hasSubselectLoadableCollections();
}
public List doEntityBatchFetch(
SharedSessionContractImplementor session,
QueryParameters queryParameters,
Object[] ids) {
final JdbcServices jdbcServices = session.getJdbcServices();
final String sql = StringHelper.expandBatchIdPlaceholder(
sqlTemplate,
ids,
alias,
persister.getKeyColumnNames(),
jdbcServices.getJdbcEnvironment().getDialect()
);
try {
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
boolean defaultReadOnlyOrig = persistenceContext.isDefaultReadOnly();
if ( queryParameters.isReadOnlyInitialized() ) {
// The read-only/modifiable mode for the query was explicitly set.
// Temporarily set the default read-only/modifiable setting to the query's setting.
persistenceContext.setDefaultReadOnly( queryParameters.isReadOnly() );
}
else {
// The read-only/modifiable setting for the query was not initialized.
// Use the default read-only/modifiable from the persistence context instead.
queryParameters.setReadOnly( persistenceContext.isDefaultReadOnly() );
}
persistenceContext.beforeLoad();
List results;
try {
try {
results = doTheLoad( sql, queryParameters, session );
}
finally {
persistenceContext.afterLoad();
}
persistenceContext.initializeNonLazyCollections();
log.debug( "Done batch load" );
return results;
}
finally {
// Restore the original default
persistenceContext.setDefaultReadOnly( defaultReadOnlyOrig );
}
}
catch ( SQLException sqle ) {
throw jdbcServices.getSqlExceptionHelper().convert(
sqle,
"could not load an entity batch: " + MessageHelper.infoString(
getEntityPersisters()[0],
ids,
session.getFactory()
),
sql
);
}
}
private List doTheLoad(String sql, QueryParameters queryParameters, SharedSessionContractImplementor session) throws SQLException {
final RowSelection selection = queryParameters.getRowSelection();
final int maxRows = LimitHelper.hasMaxRows( selection ) ?
selection.getMaxRows() :
Integer.MAX_VALUE;
final List<AfterLoadAction> afterLoadActions = new ArrayList<>();
final SqlStatementWrapper wrapper = executeQueryStatement( sql, queryParameters, false, afterLoadActions, session );
final ResultSet rs = wrapper.getResultSet();
final Statement st = wrapper.getStatement();
try {
return processResultSet( rs, queryParameters, session, false, null, maxRows, afterLoadActions );
}
finally {
final JdbcCoordinator jdbcCoordinator = session.getJdbcCoordinator();
jdbcCoordinator.getLogicalConnection().getResourceRegistry().release( st );
jdbcCoordinator.afterStatementExecution();
}
}
}
}

View File

@ -1,241 +0,0 @@
/*
* 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.loader.entity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import org.hibernate.FetchMode;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.AbstractEntityJoinWalker;
import org.hibernate.loader.OuterJoinableAssociation;
import org.hibernate.loader.PropertyPath;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.sql.JoinType;
import org.hibernate.type.AssociationType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
/**
* A walker for loaders that fetch entities
*
* @see EntityLoader
* @author Gavin King
*/
public class EntityJoinWalker extends AbstractEntityJoinWalker {
private final LockOptions lockOptions = new LockOptions();
private final int[][] compositeKeyManyToOneTargetIndices;
public EntityJoinWalker(
OuterJoinLoadable persister,
String[] uniqueKey,
int batchSize,
LockMode lockMode,
final SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
super( persister, factory, loadQueryInfluencers );
this.lockOptions.setLockMode(lockMode);
StringBuilder whereCondition = whereString( getAlias(), uniqueKey, batchSize )
//include the discriminator and class-level where, but not filters
.append( persister.filterFragment( getAlias(), Collections.EMPTY_MAP ) );
AssociationInitCallbackImpl callback = new AssociationInitCallbackImpl( factory );
initAll( whereCondition.toString(), "", lockOptions, callback );
this.compositeKeyManyToOneTargetIndices = callback.resolve();
}
public EntityJoinWalker(
OuterJoinLoadable persister,
String[] uniqueKey,
int batchSize,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
super( persister, factory, loadQueryInfluencers );
LockOptions.copy(lockOptions, this.lockOptions);
StringBuilder whereCondition = whereString( getAlias(), uniqueKey, batchSize )
//include the discriminator and class-level where, but not filters
.append( persister.filterFragment( getAlias(), Collections.EMPTY_MAP ) );
AssociationInitCallbackImpl callback = new AssociationInitCallbackImpl( factory );
initAll( whereCondition.toString(), "", lockOptions, callback );
this.compositeKeyManyToOneTargetIndices = callback.resolve();
}
protected JoinType getJoinType(
OuterJoinLoadable persister,
PropertyPath path,
int propertyNumber,
AssociationType associationType,
FetchMode metadataFetchMode,
CascadeStyle metadataCascadeStyle,
String lhsTable,
String[] lhsColumns,
boolean nullable,
int currentDepth) throws MappingException {
// NOTE : we override this form here specifically to account for
// fetch profiles.
// TODO : how to best handle criteria queries?
if ( lockOptions.getLockMode().greaterThan( LockMode.READ ) ) {
return JoinType.NONE;
}
if ( isTooDeep( currentDepth )
|| ( associationType.isCollectionType() && isTooManyCollections() ) ) {
return JoinType.NONE;
}
if ( !isJoinedFetchEnabledInMapping( metadataFetchMode, associationType )
&& !isJoinFetchEnabledByProfile( persister, path, propertyNumber ) ) {
return JoinType.NONE;
}
if ( isDuplicateAssociation( lhsTable, lhsColumns, associationType ) ) {
return JoinType.NONE;
}
return getJoinType( nullable, currentDepth );
}
public String getComment() {
return "load " + getPersister().getEntityName();
}
public int[][] getCompositeKeyManyToOneTargetIndices() {
return compositeKeyManyToOneTargetIndices;
}
private static class AssociationInitCallbackImpl implements AssociationInitCallback {
private final SessionFactoryImplementor factory;
private final HashMap<String,OuterJoinableAssociation> associationsByAlias
= new HashMap<String, OuterJoinableAssociation>();
private final HashMap<String,Integer> positionsByAlias = new HashMap<String, Integer>();
private final ArrayList<String> aliasesForAssociationsWithCompositesIds
= new ArrayList<String>();
public AssociationInitCallbackImpl(SessionFactoryImplementor factory) {
this.factory = factory;
}
public void associationProcessed(OuterJoinableAssociation oja, int position) {
associationsByAlias.put( oja.getRhsAlias(), oja );
positionsByAlias.put( oja.getRhsAlias(), position );
EntityPersister entityPersister = null;
if ( oja.getJoinableType().isCollectionType() ) {
entityPersister = ( ( QueryableCollection) oja.getJoinable() ).getElementPersister();
}
else if ( oja.getJoinableType().isEntityType() ) {
entityPersister = ( EntityPersister ) oja.getJoinable();
}
if ( entityPersister != null
&& entityPersister.getIdentifierType().isComponentType()
&& ! entityPersister.getEntityMetamodel().getIdentifierProperty().isEmbedded()
&& hasAssociation( (CompositeType) entityPersister.getIdentifierType() ) ) {
aliasesForAssociationsWithCompositesIds.add( oja.getRhsAlias() );
}
}
private boolean hasAssociation(CompositeType componentType) {
for ( Type subType : componentType.getSubtypes() ) {
if ( subType.isEntityType() ) {
return true;
}
else if ( subType.isComponentType() && hasAssociation( ( (CompositeType) subType ) ) ) {
return true;
}
}
return false;
}
public int[][] resolve() {
int[][] compositeKeyManyToOneTargetIndices = null;
for ( final String aliasWithCompositeId : aliasesForAssociationsWithCompositesIds ) {
final OuterJoinableAssociation joinWithCompositeId = associationsByAlias.get( aliasWithCompositeId );
final ArrayList<Integer> keyManyToOneTargetIndices = new ArrayList<Integer>();
// for each association with a composite id containing key-many-to-one(s), find the bidirectional side of
// each key-many-to-one (if exists) to see if it is eager as well. If so, we need to track the indices
EntityPersister entityPersister = null;
if ( joinWithCompositeId.getJoinableType().isCollectionType() ) {
entityPersister = ( ( QueryableCollection) joinWithCompositeId.getJoinable() ).getElementPersister();
}
else if ( joinWithCompositeId.getJoinableType().isEntityType() ) {
entityPersister = ( EntityPersister ) joinWithCompositeId.getJoinable();
}
findKeyManyToOneTargetIndices(
keyManyToOneTargetIndices,
joinWithCompositeId,
(CompositeType) entityPersister.getIdentifierType()
);
if ( ! keyManyToOneTargetIndices.isEmpty() ) {
if ( compositeKeyManyToOneTargetIndices == null ) {
compositeKeyManyToOneTargetIndices = new int[ associationsByAlias.size() ][];
}
int position = positionsByAlias.get( aliasWithCompositeId );
compositeKeyManyToOneTargetIndices[position] = new int[ keyManyToOneTargetIndices.size() ];
int i = 0;
for ( int index : keyManyToOneTargetIndices ) {
compositeKeyManyToOneTargetIndices[position][i] = index;
i++;
}
}
}
return compositeKeyManyToOneTargetIndices;
}
private void findKeyManyToOneTargetIndices(
ArrayList<Integer> keyManyToOneTargetIndices,
OuterJoinableAssociation joinWithCompositeId,
CompositeType componentType) {
for ( Type subType : componentType.getSubtypes() ) {
if ( subType.isEntityType() ) {
Integer index = locateKeyManyToOneTargetIndex( joinWithCompositeId, (EntityType) subType );
if ( index != null ) {
keyManyToOneTargetIndices.add( index );
}
}
else if ( subType.isComponentType() ) {
findKeyManyToOneTargetIndices(
keyManyToOneTargetIndices,
joinWithCompositeId,
(CompositeType) subType
);
}
}
}
private Integer locateKeyManyToOneTargetIndex(OuterJoinableAssociation joinWithCompositeId, EntityType keyManyToOneType) {
// the lhs (if one) is a likely candidate
if ( joinWithCompositeId.getLhsAlias() != null ) {
final OuterJoinableAssociation lhs = associationsByAlias.get( joinWithCompositeId.getLhsAlias() );
if ( keyManyToOneType.getAssociatedEntityName( factory ).equals( lhs.getJoinableType().getAssociatedEntityName( factory ) ) ) {
return positionsByAlias.get( lhs.getRhsAlias() );
}
}
// otherwise, seek out OuterJoinableAssociation which are RHS of given OuterJoinableAssociation
// (joinWithCompositeId)
for ( OuterJoinableAssociation oja : associationsByAlias.values() ) {
if ( oja.getLhsAlias() != null && oja.getLhsAlias().equals( joinWithCompositeId.getRhsAlias() ) ) {
if ( keyManyToOneType.equals( oja.getJoinableType() ) ) {
return positionsByAlias.get( oja.getLhsAlias() );
}
}
}
return null;
}
}
}

View File

@ -1,156 +0,0 @@
/*
* 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.loader.entity;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.type.Type;
/**
* Loads an entity instance using outerjoin fetching to fetch associated entities.
* <br>
* The <tt>EntityPersister</tt> must implement <tt>Loadable</tt>. For other entities,
* create a customized subclass of <tt>Loader</tt>.
*
* @author Gavin King
*/
public class EntityLoader extends AbstractEntityLoader {
private final boolean batchLoader;
private final int[][] compositeKeyManyToOneTargetIndices;
public EntityLoader(
OuterJoinLoadable persister,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
this( persister, 1, lockMode, factory, loadQueryInfluencers );
}
public EntityLoader(
OuterJoinLoadable persister,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
this( persister, 1, lockOptions, factory, loadQueryInfluencers );
}
public EntityLoader(
OuterJoinLoadable persister,
int batchSize,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
this(
persister,
persister.getIdentifierColumnNames(),
persister.getIdentifierType(),
batchSize,
lockMode,
factory,
loadQueryInfluencers
);
}
public EntityLoader(
OuterJoinLoadable persister,
int batchSize,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
this(
persister,
persister.getIdentifierColumnNames(),
persister.getIdentifierType(),
batchSize,
lockOptions,
factory,
loadQueryInfluencers
);
}
public EntityLoader(
OuterJoinLoadable persister,
String[] uniqueKey,
Type uniqueKeyType,
int batchSize,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
super( persister, uniqueKeyType, factory, loadQueryInfluencers );
EntityJoinWalker walker = new EntityJoinWalker(
persister,
uniqueKey,
batchSize,
lockMode,
factory,
loadQueryInfluencers
);
initFromWalker( walker );
this.compositeKeyManyToOneTargetIndices = walker.getCompositeKeyManyToOneTargetIndices();
postInstantiate();
batchLoader = batchSize > 1;
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Static select for entity %s [%s]: %s", entityName, lockMode, getSQLString() );
}
}
public EntityLoader(
OuterJoinLoadable persister,
String[] uniqueKey,
Type uniqueKeyType,
int batchSize,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
super( persister, uniqueKeyType, factory, loadQueryInfluencers );
EntityJoinWalker walker = new EntityJoinWalker(
persister,
uniqueKey,
batchSize,
lockOptions,
factory,
loadQueryInfluencers
);
initFromWalker( walker );
this.compositeKeyManyToOneTargetIndices = walker.getCompositeKeyManyToOneTargetIndices();
postInstantiate();
batchLoader = batchSize > 1;
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Static select for entity %s [%s:%s]: %s",
entityName,
lockOptions.getLockMode(),
lockOptions.getTimeOut(),
getSQLString() );
}
}
public Object loadByUniqueKey(SharedSessionContractImplementor session, Object key) {
return load( session, key, null, null, LockOptions.NONE );
}
@Override
protected boolean isSingleRowLoader() {
return !batchLoader;
}
@Override
public int[][] getCompositeKeyManyToOneTargetIndices() {
return compositeKeyManyToOneTargetIndices;
}
}

View File

@ -1,126 +0,0 @@
/*
* 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.loader.entity;
import java.io.Serializable;
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.engine.internal.BatchFetchQueueHelper;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.Loader;
import org.hibernate.persister.entity.OuterJoinLoadable;
/**
* No longer used, see {@link org.hibernate.loader.entity.plan.LegacyBatchingEntityLoaderBuilder} instead.
*
* @author Steve Ebersole
*/
public class LegacyBatchingEntityLoaderBuilder extends BatchingEntityLoaderBuilder {
public static final LegacyBatchingEntityLoaderBuilder INSTANCE = new LegacyBatchingEntityLoaderBuilder();
@Override
protected UniqueEntityLoader buildBatchingLoader(
OuterJoinLoadable persister,
int batchSize,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return new LegacyBatchingEntityLoader( persister, batchSize, lockMode, factory, influencers );
}
@Override
protected UniqueEntityLoader buildBatchingLoader(
OuterJoinLoadable persister,
int batchSize,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return new LegacyBatchingEntityLoader( persister, batchSize, lockOptions, factory, influencers );
}
public static class LegacyBatchingEntityLoader extends BatchingEntityLoader implements UniqueEntityLoader {
private final int[] batchSizes;
private final Loader[] loaders;
public LegacyBatchingEntityLoader(
OuterJoinLoadable persister,
int maxBatchSize,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
super( persister );
this.batchSizes = ArrayHelper.getBatchSizes( maxBatchSize );
this.loaders = new Loader[ batchSizes.length ];
for ( int i = 0; i < batchSizes.length; i++ ) {
this.loaders[i] = new EntityLoader( persister, batchSizes[i], lockMode, factory, loadQueryInfluencers);
}
}
public LegacyBatchingEntityLoader(
OuterJoinLoadable persister,
int maxBatchSize,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
super( persister );
this.batchSizes = ArrayHelper.getBatchSizes( maxBatchSize );
this.loaders = new Loader[ batchSizes.length ];
for ( int i = 0; i < batchSizes.length; i++ ) {
this.loaders[i] = new EntityLoader( persister, batchSizes[i], lockOptions, factory, loadQueryInfluencers);
}
}
@Override
public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session, LockOptions lockOptions) {
final Object[] batch = session.getPersistenceContextInternal()
.getBatchFetchQueue()
.getBatchLoadableEntityIds( persister(), id, batchSizes[0] );
for ( int i = 0; i < batchSizes.length-1; i++) {
final int smallBatchSize = batchSizes[i];
if ( batch[smallBatchSize-1] != null ) {
Serializable[] smallBatch = new Serializable[smallBatchSize];
System.arraycopy(batch, 0, smallBatch, 0, smallBatchSize);
// for now...
final List results = loaders[i].loadEntityBatch(
session,
smallBatch,
persister().getIdentifierType(),
optionalObject,
persister().getEntityName(),
id,
persister(),
lockOptions
);
// The EntityKey for any entity that is not found will remain in the batch.
// Explicitly remove the EntityKeys for entities that were not found to
// avoid including them in future batches that get executed.
BatchFetchQueueHelper.removeNotFoundBatchLoadableEntityKeys(
smallBatch,
results,
persister(),
session
);
return getObjectFromList(results, id, session); //EARLY EXIT
}
}
final Object result = ( (UniqueEntityLoader) loaders[batchSizes.length-1] ).load(id, optionalObject, session);
if ( result == null ) {
// There was no entity with the specified ID. Make sure the EntityKey does not remain
// in the batch to avoid including it in future batches that get executed.
BatchFetchQueueHelper.removeBatchLoadableEntityKey( id, persister(), session );
}
return result;
}
}
}

View File

@ -1,130 +0,0 @@
/*
* 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.loader.entity;
import java.io.Serializable;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.engine.internal.BatchFetchQueueHelper;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.Loader;
import org.hibernate.persister.entity.OuterJoinLoadable;
/**
* @author Steve Ebersole
*/
class PaddedBatchingEntityLoaderBuilder extends BatchingEntityLoaderBuilder {
public static final PaddedBatchingEntityLoaderBuilder INSTANCE = new PaddedBatchingEntityLoaderBuilder();
@Override
protected UniqueEntityLoader buildBatchingLoader(
OuterJoinLoadable persister,
int batchSize,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return new PaddedBatchingEntityLoader( persister, batchSize, lockMode, factory, influencers );
}
@Override
protected UniqueEntityLoader buildBatchingLoader(
OuterJoinLoadable persister,
int batchSize,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return new PaddedBatchingEntityLoader( persister, batchSize, lockOptions, factory, influencers );
}
public static class PaddedBatchingEntityLoader extends BatchingEntityLoader {
private final int[] batchSizes;
private final Loader[] loaders;
public PaddedBatchingEntityLoader(
OuterJoinLoadable persister,
int maxBatchSize,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
super( persister );
this.batchSizes = ArrayHelper.getBatchSizes( maxBatchSize );
this.loaders = new Loader[ batchSizes.length ];
for ( int i = 0; i < batchSizes.length; i++ ) {
this.loaders[i] = new EntityLoader( persister, batchSizes[i], lockMode, factory, loadQueryInfluencers);
}
validate( maxBatchSize );
}
private void validate(int max) {
// these are more indicative of internal problems then user error...
if ( batchSizes[0] != max ) {
throw new HibernateException( "Unexpected batch size spread" );
}
if ( batchSizes[batchSizes.length-1] != 1 ) {
throw new HibernateException( "Unexpected batch size spread" );
}
}
public PaddedBatchingEntityLoader(
OuterJoinLoadable persister,
int maxBatchSize,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
super( persister );
this.batchSizes = ArrayHelper.getBatchSizes( maxBatchSize );
this.loaders = new Loader[ batchSizes.length ];
for ( int i = 0; i < batchSizes.length; i++ ) {
this.loaders[i] = new EntityLoader( persister, batchSizes[i], lockOptions, factory, loadQueryInfluencers);
}
validate( maxBatchSize );
}
@Override
public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session, LockOptions lockOptions) {
final Object[] batch = session.getPersistenceContextInternal()
.getBatchFetchQueue()
.getBatchLoadableEntityIds( persister(), id, batchSizes[0] );
final int numberOfIds = ArrayHelper.countNonNull( batch );
if ( numberOfIds <= 1 ) {
final Object result = ( (UniqueEntityLoader) loaders[batchSizes.length-1] ).load( id, optionalObject, session );
if ( result == null ) {
// There was no entity with the specified ID. Make sure the EntityKey does not remain
// in the batch to avoid including it in future batches that get executed.
BatchFetchQueueHelper.removeBatchLoadableEntityKey( id, persister(), session );
}
return result;
}
// Uses the first batch-size bigger than the number of actual ids in the batch
int indexToUse = batchSizes.length-1;
for ( int i = 0; i < batchSizes.length-1; i++ ) {
if ( batchSizes[i] >= numberOfIds ) {
indexToUse = i;
}
else {
break;
}
}
final Serializable[] idsToLoad = new Serializable[ batchSizes[indexToUse] ];
System.arraycopy( batch, 0, idsToLoad, 0, numberOfIds );
for ( int i = numberOfIds; i < batchSizes[indexToUse]; i++ ) {
idsToLoad[i] = id;
}
return doBatchLoad( id, loaders[indexToUse], session, idsToLoad, optionalObject, lockOptions );
}
}
}

View File

@ -1,50 +0,0 @@
/*
* 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.loader.entity;
import java.io.Serializable;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* Loads entities for a <tt>EntityPersister</tt>
*
* @author Gavin King
* @author Steve Ebersole
*/
public interface UniqueEntityLoader {
/**
* Load an entity instance. If <tt>optionalObject</tt> is supplied,
* load the entity state into the given (uninitialized) object.
*
* @deprecated use {@link #load(java.io.Serializable, Object, SharedSessionContractImplementor, LockOptions)} instead.
*/
@SuppressWarnings( {"JavaDoc"})
@Deprecated
Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session) throws HibernateException;
/**
* Load an entity instance by id. If <tt>optionalObject</tt> is supplied (non-<tt>null</tt>,
* the entity state is loaded into that object instance instead of instantiating a new one.
*
* @param id The id to be loaded
* @param optionalObject The (optional) entity instance in to which to load the state
* @param session The session from which the request originated
* @param lockOptions The lock options.
*
* @return The loaded entity
*
* @throws HibernateException indicates problem performing the load.
*/
Object load(
Serializable id,
Object optionalObject,
SharedSessionContractImplementor session,
LockOptions lockOptions);
}

View File

@ -1,15 +0,0 @@
<!--
~ 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>.
-->
<html>
<head></head>
<body>
<p>
This package defines entity loaders
</p>
</body>
</html>

View File

@ -1,41 +0,0 @@
/*
* 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.loader.entity.plan;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.entity.BatchingEntityLoaderBuilder;
import org.hibernate.loader.entity.UniqueEntityLoader;
import org.hibernate.persister.entity.OuterJoinLoadable;
/**
* Base class for LoadPlan-based BatchingEntityLoaderBuilder implementations. Mainly we handle the common
* "no batching" case here to use the LoadPlan-based EntityLoader
*
* @author Steve Ebersole
*/
public abstract class AbstractBatchingEntityLoaderBuilder extends BatchingEntityLoaderBuilder {
@Override
protected UniqueEntityLoader buildNonBatchingLoader(
OuterJoinLoadable persister,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return EntityLoader.forEntity( persister ).withLockMode( lockMode ).withInfluencers( influencers ).byPrimaryKey();
}
@Override
protected UniqueEntityLoader buildNonBatchingLoader(
OuterJoinLoadable persister,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return EntityLoader.forEntity( persister ).withLockOptions( lockOptions ).withInfluencers( influencers ).byPrimaryKey();
}
}

View File

@ -1,276 +0,0 @@
/*
* 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.loader.entity.plan;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.EffectiveEntityGraph;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.graph.GraphSemantic;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.loader.entity.UniqueEntityLoader;
import org.hibernate.loader.plan.build.internal.FetchGraphLoadPlanBuildingStrategy;
import org.hibernate.loader.plan.build.internal.FetchStyleLoadPlanBuildingAssociationVisitationStrategy;
import org.hibernate.loader.plan.build.internal.LoadGraphLoadPlanBuildingStrategy;
import org.hibernate.loader.plan.build.spi.LoadPlanBuildingAssociationVisitationStrategy;
import org.hibernate.loader.plan.build.spi.MetamodelDrivenLoadPlanBuilder;
import org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader;
import org.hibernate.loader.plan.exec.internal.BatchingLoadQueryDetailsFactory;
import org.hibernate.loader.plan.exec.internal.EntityLoadQueryDetails;
import org.hibernate.loader.plan.exec.query.spi.QueryBuildingParameters;
import org.hibernate.loader.plan.exec.spi.LoadQueryDetails;
import org.hibernate.loader.plan.spi.LoadPlan;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type;
/**
* A UniqueEntityLoader implementation based on using LoadPlans
*
* @author Steve Ebersole
*/
public abstract class AbstractLoadPlanBasedEntityLoader extends AbstractLoadPlanBasedLoader implements UniqueEntityLoader {
private static final CoreMessageLogger log = CoreLogging.messageLogger( AbstractLoadPlanBasedEntityLoader.class );
private final OuterJoinLoadable entityPersister;
private final Type uniqueKeyType;
private final String entityName;
private final EntityLoadQueryDetails staticLoadQuery;
public AbstractLoadPlanBasedEntityLoader(
OuterJoinLoadable entityPersister,
SessionFactoryImplementor factory,
String[] uniqueKeyColumnNames,
Type uniqueKeyType,
QueryBuildingParameters buildingParameters) {
super( factory );
this.entityPersister = entityPersister;
this.uniqueKeyType = uniqueKeyType;
this.entityName = entityPersister.getEntityName();
final LoadPlanBuildingAssociationVisitationStrategy strategy;
final EffectiveEntityGraph effectiveEntityGraph = buildingParameters.getQueryInfluencers().getEffectiveEntityGraph();
if ( effectiveEntityGraph.getSemantic() == GraphSemantic.FETCH ) {
strategy = new FetchGraphLoadPlanBuildingStrategy(
factory,
effectiveEntityGraph.getGraph(),
buildingParameters.getQueryInfluencers(),
buildingParameters.getLockOptions() != null ? buildingParameters.getLockOptions().getLockMode() : buildingParameters.getLockMode()
);
}
else if ( effectiveEntityGraph.getSemantic() == GraphSemantic.LOAD ) {
strategy = new LoadGraphLoadPlanBuildingStrategy(
factory,
effectiveEntityGraph.getGraph(),
buildingParameters.getQueryInfluencers(),
buildingParameters.getLockOptions() != null ? buildingParameters.getLockOptions().getLockMode() : buildingParameters.getLockMode()
);
}
else {
strategy = new FetchStyleLoadPlanBuildingAssociationVisitationStrategy(
factory,
buildingParameters.getQueryInfluencers(),
buildingParameters.getLockOptions() != null ? buildingParameters.getLockOptions().getLockMode() : buildingParameters.getLockMode()
);
}
final LoadPlan plan = MetamodelDrivenLoadPlanBuilder.buildRootEntityLoadPlan( strategy, entityPersister );
this.staticLoadQuery = BatchingLoadQueryDetailsFactory.INSTANCE.makeEntityLoadQueryDetails(
plan,
uniqueKeyColumnNames,
buildingParameters,
factory
);
}
protected AbstractLoadPlanBasedEntityLoader(
OuterJoinLoadable entityPersister,
SessionFactoryImplementor factory,
EntityLoadQueryDetails entityLoaderQueryDetailsTemplate,
Type uniqueKeyType,
QueryBuildingParameters buildingParameters) {
super( factory );
this.entityPersister = entityPersister;
this.uniqueKeyType = uniqueKeyType;
this.entityName = entityPersister.getEntityName();
this.staticLoadQuery = BatchingLoadQueryDetailsFactory.INSTANCE.makeEntityLoadQueryDetails(
entityLoaderQueryDetailsTemplate,
buildingParameters
);
}
@Override
protected LoadQueryDetails getStaticLoadQuery() {
return staticLoadQuery;
}
protected String getEntityName() {
return entityName;
}
/**
* Called by wrappers that batch load entities
* @param persister only needed for logging
* @param lockOptions
*/
public final List loadEntityBatch(
final SharedSessionContractImplementor session,
final Serializable[] ids,
final Type idType,
final Object optionalObject,
final String optionalEntityName,
final Serializable optionalId,
final EntityPersister persister,
LockOptions lockOptions) throws HibernateException {
if ( log.isDebugEnabled() ) {
log.debugf( "Batch loading entity: %s", MessageHelper.infoString( persister, ids, getFactory() ) );
}
final Type[] types = new Type[ids.length];
Arrays.fill( types, idType );
List result;
try {
final QueryParameters qp = new QueryParameters();
qp.setPositionalParameterTypes( types );
qp.setPositionalParameterValues( ids );
qp.setLockOptions( lockOptions );
result = executeLoad(
session,
qp,
staticLoadQuery,
false,
null
);
}
catch ( SQLException sqle ) {
throw getFactory().getSQLExceptionHelper().convert(
sqle,
"could not load an entity batch: " + MessageHelper.infoString( entityPersister, ids, getFactory() ),
staticLoadQuery.getSqlStatement()
);
}
log.debug( "Done entity batch load" );
return result;
}
@Override
public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session) throws HibernateException {
return load( id, optionalObject, session, LockOptions.NONE );
}
@Override
public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session, LockOptions lockOptions) {
final Object result;
try {
final QueryParameters qp = new QueryParameters();
qp.setPositionalParameterTypes( new Type[] { entityPersister.getIdentifierType() } );
qp.setPositionalParameterValues( new Object[] { id } );
qp.setOptionalObject( optionalObject );
qp.setOptionalEntityName( entityPersister.getEntityName() );
qp.setOptionalId( id );
qp.setLockOptions( lockOptions );
final List results = executeLoad(
session,
qp,
staticLoadQuery,
false,
null
);
result = extractEntityResult( results, id );
}
catch ( SQLException sqle ) {
throw session.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not load an entity: " + MessageHelper.infoString(
entityPersister,
id,
entityPersister.getIdentifierType(),
getFactory()
),
staticLoadQuery.getSqlStatement()
);
}
log.debugf( "Done entity load : %s#%s", getEntityName(), id );
return result;
}
/**
* @deprecated {@link #extractEntityResult(List, Serializable)} should be used instead.
*/
@Deprecated
protected Object extractEntityResult(List results) {
return extractEntityResult( results, null );
}
protected Object extractEntityResult(List results, Serializable id) {
if ( results.size() == 0 ) {
return null;
}
else if ( results.size() == 1 ) {
return results.get( 0 );
}
else if ( staticLoadQuery.hasCollectionInitializers() ) {
final Object row = results.get( 0 );
if ( row.getClass().isArray() ) {
// the logical type of the result list is List<Object[]>. See if the contained
// array contains just one element, and return that if so
final Object[] rowArray = (Object[]) row;
if ( rowArray.length == 1 ) {
return rowArray[0];
}
}
else {
return row;
}
}
if ( id == null ) {
throw new HibernateException(
"Unable to interpret given query results in terms of a load-entity query for " +
entityName
);
}
else {
throw new HibernateException(
"More than one row with the given identifier was found: " +
id +
", for class: " +
entityName
);
}
}
protected int[] getNamedParameterLocs(String name) {
throw new AssertionFailure("no named parameters");
}
protected void autoDiscoverTypes(ResultSet rs) {
throw new AssertionFailure("Auto discover types not supported in this loader");
}
}

View File

@ -1,114 +0,0 @@
/*
* 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.loader.entity.plan;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.Loader;
import org.hibernate.loader.entity.UniqueEntityLoader;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
/**
* The base contract for UniqueEntityLoader implementations capable of performing batch-fetch loading of entities
* using multiple primary key values in the SQL <tt>WHERE</tt> clause.
* <p/>
* Typically these are
*
* @author Gavin King
* @author Steve Ebersole
*
* @see org.hibernate.loader.entity.BatchingEntityLoaderBuilder
* @see org.hibernate.loader.entity.UniqueEntityLoader
*/
public abstract class BatchingEntityLoader implements UniqueEntityLoader {
private static final Logger log = Logger.getLogger( BatchingEntityLoader.class );
private final EntityPersister persister;
public BatchingEntityLoader(EntityPersister persister) {
this.persister = persister;
}
public EntityPersister persister() {
return persister;
}
@Override
public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session) {
return load( id, optionalObject, session, LockOptions.NONE );
}
protected QueryParameters buildQueryParameters(
Serializable id,
Serializable[] ids,
Object optionalObject,
LockOptions lockOptions) {
Type[] types = new Type[ids.length];
Arrays.fill( types, persister().getIdentifierType() );
QueryParameters qp = new QueryParameters();
qp.setPositionalParameterTypes( types );
qp.setPositionalParameterValues( ids );
qp.setOptionalObject( optionalObject );
qp.setOptionalEntityName( persister().getEntityName() );
qp.setOptionalId( id );
qp.setLockOptions( lockOptions );
return qp;
}
protected Object getObjectFromList(List results, Serializable id, SharedSessionContractImplementor session) {
for ( Object obj : results ) {
final boolean equal = persister.getIdentifierType().isEqual(
id,
session.getContextEntityIdentifier( obj ),
session.getFactory()
);
if ( equal ) {
return obj;
}
}
return null;
}
protected Object doBatchLoad(
Serializable id,
Loader loaderToUse,
SharedSessionContractImplementor session,
Serializable[] ids,
Object optionalObject,
LockOptions lockOptions) {
if ( log.isDebugEnabled() ) {
log.debugf( "Batch loading entity: %s", MessageHelper.infoString( persister, ids, session.getFactory() ) );
}
QueryParameters qp = buildQueryParameters( id, ids, optionalObject, lockOptions );
try {
final List results = loaderToUse.doQueryAndInitializeNonLazyCollections( session, qp, false );
log.debug( "Done entity batch load" );
return getObjectFromList(results, id, session);
}
catch ( SQLException sqle ) {
throw session.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not load an entity batch: " + MessageHelper.infoString( persister(), ids, session.getFactory() ),
loaderToUse.getSQLString()
);
}
}
}

View File

@ -1,179 +0,0 @@
/*
* 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.loader.entity.plan;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.loader.plan.exec.internal.EntityLoadQueryDetails;
import org.hibernate.loader.plan.exec.query.internal.QueryBuildingParametersImpl;
import org.hibernate.loader.plan.exec.query.spi.QueryBuildingParameters;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
/**
* UniqueEntityLoader implementation that is the main functionality for LoadPlan-based Entity loading.
* <p/>
* Can handle batch-loading as well as non-pk, unique-key loading,
* <p/>
* Much is ultimately delegated to its superclass, AbstractLoadPlanBasedEntityLoader. However:
*
* Loads an entity instance using outerjoin fetching to fetch associated entities.
* <br>
* The <tt>EntityPersister</tt> must implement <tt>Loadable</tt>. For other entities,
* create a customized subclass of <tt>Loader</tt>.
*
* @author Gavin King
* @author Steve Ebersole
* @author Gail Badner
*/
public class EntityLoader extends AbstractLoadPlanBasedEntityLoader {
private static final Logger log = CoreLogging.logger( EntityLoader.class );
public static Builder forEntity(OuterJoinLoadable persister) {
return new Builder( persister );
}
public static class Builder {
private final OuterJoinLoadable persister;
private EntityLoader entityLoaderTemplate;
private int batchSize = 1;
private LoadQueryInfluencers influencers = LoadQueryInfluencers.NONE;
private LockMode lockMode = LockMode.NONE;
private LockOptions lockOptions;
public Builder(OuterJoinLoadable persister) {
this.persister = persister;
}
public Builder withEntityLoaderTemplate(EntityLoader entityLoaderTemplate) {
this.entityLoaderTemplate = entityLoaderTemplate;
return this;
}
public Builder withBatchSize(int batchSize) {
this.batchSize = batchSize;
return this;
}
public Builder withInfluencers(LoadQueryInfluencers influencers) {
this.influencers = influencers;
return this;
}
public Builder withLockMode(LockMode lockMode) {
this.lockMode = lockMode;
return this;
}
public Builder withLockOptions(LockOptions lockOptions) {
this.lockOptions = lockOptions;
return this;
}
public EntityLoader byPrimaryKey() {
return byUniqueKey( persister.getIdentifierColumnNames(), persister.getIdentifierType() );
}
public EntityLoader byUniqueKey(String[] keyColumnNames, Type keyType) {
// capture current values in a new instance of QueryBuildingParametersImpl
if ( entityLoaderTemplate == null ) {
return new EntityLoader(
persister.getFactory(),
persister,
keyColumnNames,
keyType,
new QueryBuildingParametersImpl(
influencers,
batchSize,
lockMode,
lockOptions
)
);
}
else {
return new EntityLoader(
persister.getFactory(),
persister,
entityLoaderTemplate,
keyType,
new QueryBuildingParametersImpl(
influencers,
batchSize,
lockMode,
lockOptions
)
);
}
}
}
private EntityLoader(
SessionFactoryImplementor factory,
OuterJoinLoadable persister,
String[] uniqueKeyColumnNames,
Type uniqueKeyType,
QueryBuildingParameters buildingParameters) throws MappingException {
super( persister, factory, uniqueKeyColumnNames, uniqueKeyType, buildingParameters );
if ( log.isDebugEnabled() ) {
if ( buildingParameters.getLockOptions() != null ) {
log.debugf(
"Static select for entity %s [%s:%s]: %s",
getEntityName(),
buildingParameters.getLockOptions().getLockMode(),
buildingParameters.getLockOptions().getTimeOut(),
getStaticLoadQuery().getSqlStatement()
);
}
else if ( buildingParameters.getLockMode() != null ) {
log.debugf(
"Static select for entity %s [%s]: %s",
getEntityName(),
buildingParameters.getLockMode(),
getStaticLoadQuery().getSqlStatement()
);
}
}
}
private EntityLoader(
SessionFactoryImplementor factory,
OuterJoinLoadable persister,
EntityLoader entityLoaderTemplate,
Type uniqueKeyType,
QueryBuildingParameters buildingParameters) throws MappingException {
super( persister, factory, entityLoaderTemplate.getStaticLoadQuery(), uniqueKeyType, buildingParameters );
if ( log.isDebugEnabled() ) {
if ( buildingParameters.getLockOptions() != null ) {
log.debugf(
"Static select for entity %s [%s:%s]: %s",
getEntityName(),
buildingParameters.getLockOptions().getLockMode(),
buildingParameters.getLockOptions().getTimeOut(),
getStaticLoadQuery().getSqlStatement()
);
}
else if ( buildingParameters.getLockMode() != null ) {
log.debugf(
"Static select for entity %s [%s]: %s",
getEntityName(),
buildingParameters.getLockMode(),
getStaticLoadQuery().getSqlStatement()
);
}
}
}
@Override
protected EntityLoadQueryDetails getStaticLoadQuery() {
return (EntityLoadQueryDetails) super.getStaticLoadQuery();
}
}

View File

@ -1,140 +0,0 @@
/*
* 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.loader.entity.plan;
import java.io.Serializable;
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.engine.internal.BatchFetchQueueHelper;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.entity.UniqueEntityLoader;
import org.hibernate.persister.entity.OuterJoinLoadable;
/**
* LoadPlan-based implementation of the legacy batch loading strategy
*
* @author Steve Ebersole
*/
public class LegacyBatchingEntityLoaderBuilder extends AbstractBatchingEntityLoaderBuilder {
public static final LegacyBatchingEntityLoaderBuilder INSTANCE = new LegacyBatchingEntityLoaderBuilder();
@Override
protected UniqueEntityLoader buildBatchingLoader(
OuterJoinLoadable persister,
int batchSize,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return new LegacyBatchingEntityLoader( persister, batchSize, lockMode, factory, influencers );
}
@Override
protected UniqueEntityLoader buildBatchingLoader(
OuterJoinLoadable persister,
int batchSize,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers influencers) {
return new LegacyBatchingEntityLoader( persister, batchSize, lockOptions, factory, influencers );
}
public static class LegacyBatchingEntityLoader extends BatchingEntityLoader {
private final int[] batchSizes;
private final EntityLoader[] loaders;
public LegacyBatchingEntityLoader(
OuterJoinLoadable persister,
int maxBatchSize,
LockMode lockMode,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
this( persister, maxBatchSize, lockMode, null, factory, loadQueryInfluencers );
}
public LegacyBatchingEntityLoader(
OuterJoinLoadable persister,
int maxBatchSize,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
this( persister, maxBatchSize, null, lockOptions, factory, loadQueryInfluencers );
}
protected LegacyBatchingEntityLoader(
OuterJoinLoadable persister,
int maxBatchSize,
LockMode lockMode,
LockOptions lockOptions,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
super( persister );
this.batchSizes = ArrayHelper.getBatchSizes( maxBatchSize );
this.loaders = new EntityLoader[ batchSizes.length ];
final EntityLoader.Builder entityLoaderBuilder = EntityLoader.forEntity( persister )
.withInfluencers( loadQueryInfluencers )
.withLockMode( lockMode )
.withLockOptions( lockOptions );
// we create a first entity loader to use it as a template for the others
this.loaders[0] = entityLoaderBuilder.withBatchSize( batchSizes[0] ).byPrimaryKey();
for ( int i = 1; i < batchSizes.length; i++ ) {
this.loaders[i] = entityLoaderBuilder.withEntityLoaderTemplate( this.loaders[0] ).withBatchSize( batchSizes[i] ).byPrimaryKey();
}
}
@Override
public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session, LockOptions lockOptions) {
final Object[] batch = session.getPersistenceContextInternal()
.getBatchFetchQueue()
.getBatchLoadableEntityIds( persister(), id, batchSizes[0] );
for ( int i = 0; i < batchSizes.length-1; i++) {
final int smallBatchSize = batchSizes[i];
if ( batch[smallBatchSize-1] != null ) {
Serializable[] smallBatch = new Serializable[smallBatchSize];
System.arraycopy(batch, 0, smallBatch, 0, smallBatchSize);
// for now...
final List results = loaders[i].loadEntityBatch(
session,
smallBatch,
persister().getIdentifierType(),
optionalObject,
persister().getEntityName(),
id,
persister(),
lockOptions
);
// The EntityKey for any entity that is not found will remain in the batch.
// Explicitly remove the EntityKeys for entities that were not found to
// avoid including them in future batches that get executed.
BatchFetchQueueHelper.removeNotFoundBatchLoadableEntityKeys(
smallBatch,
results,
persister(),
session
);
//EARLY EXIT
return getObjectFromList( results, id, session );
}
}
final Object result = ( loaders[batchSizes.length-1] ).load( id, optionalObject, session, lockOptions );
if ( result == null ) {
// There was no entity with the specified ID. Make sure the EntityKey does not remain
// in the batch to avoid including it in future batches that get executed.
BatchFetchQueueHelper.removeBatchLoadableEntityKey( id, persister(), session );
}
return result;
}
}
}

View File

@ -1,15 +0,0 @@
<!--
~ 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>.
-->
<html>
<head></head>
<body>
<p>
This package defines a loader for the AST-based query parser
</p>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More