package org.hibernate.loader;
import java.io.Serializable;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.QueryException;
import org.hibernate.ScrollMode;
import org.hibernate.Session;
import org.hibernate.StaleObjectStateException;
import org.hibernate.WrongClassException;
import org.hibernate.cache.spi.FilterKey;
import org.hibernate.cache.spi.QueryKey;
import org.hibernate.cache.spi.QueryResultsCache;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.entry.CacheEntry;
import org.hibernate.cache.spi.entry.ReferenceCacheEntryImpl;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.dialect.pagination.NoopLimitHandler;
import org.hibernate.engine.internal.CacheHelper;
import org.hibernate.engine.internal.TwoPhaseLoad;
import org.hibernate.engine.jdbc.ColumnNameCache;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.EntityUniqueKey;
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.SubselectFetch;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.PostLoadEvent;
import org.hibernate.event.spi.PreLoadEvent;
import org.hibernate.hql.internal.HolderInstantiator;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.FetchingScrollableResultsImpl;
import org.hibernate.internal.ScrollableResultsImpl;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.UniqueKeyLoadable;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.transform.CacheableResultTransformer;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.AssociationType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.hibernate.type.VersionType;
public abstract class Loader {
public static final String SELECT = "select";
public static final String SELECT_DISTINCT = "select distinct";
protected static final CoreMessageLogger LOG = CoreLogging.messageLogger( Loader.class );
protected static final boolean DEBUG_ENABLED = LOG.isDebugEnabled();
private final SessionFactoryImplementor factory;
private volatile ColumnNameCache columnNameCache;
private final boolean referenceCachingEnabled;
private boolean isJdbc4 = true;
public Loader(SessionFactoryImplementor factory) {
this.factory = factory;
this.referenceCachingEnabled = factory.getSessionFactoryOptions().isDirectReferenceCacheEntriesEnabled();
}
public abstract String getSQLString();
protected abstract Loadable[] getEntityPersisters();
protected boolean[] getEntityEagerPropertyFetches() {
return null;
}
protected int[] getOwners() {
return null;
}
protected EntityType[] getOwnerAssociationTypes() {
return null;
}
protected CollectionPersister[] getCollectionPersisters() {
return null;
}
protected int[] getCollectionOwners() {
return null;
}
protected int[][] getCompositeKeyManyToOneTargetIndices() {
return null;
}
protected abstract LockMode[] getLockModes(LockOptions lockOptions);
protected String applyLocks(
String sql,
QueryParameters parameters,
Dialect dialect,
List<AfterLoadAction> afterLoadActions) throws HibernateException {
return sql;
}
protected boolean upgradeLocks() {
return false;
}
protected boolean isSingleRowLoader() {
return false;
}
protected String[] getAliases() {
return null;
}
protected String preprocessSQL(
String sql,
QueryParameters parameters,
SessionFactoryImplementor sessionFactory,
List<AfterLoadAction> afterLoadActions) throws HibernateException {
Dialect dialect = sessionFactory.getServiceRegistry().getService( JdbcServices.class ).getDialect();
sql = applyLocks( sql, parameters, dialect, afterLoadActions );
sql = dialect.addSqlHintOrComment(
sql,
parameters,
sessionFactory.getSessionFactoryOptions().isCommentsEnabled()
);
return processDistinctKeyword( sql, parameters );
}
protected boolean shouldUseFollowOnLocking(
QueryParameters parameters,
Dialect dialect,
List<AfterLoadAction> afterLoadActions) {
if ( ( parameters.getLockOptions().getFollowOnLocking() == null && dialect.useFollowOnLocking( parameters ) ) ||
( parameters.getLockOptions().getFollowOnLocking() != null && parameters.getLockOptions().getFollowOnLocking() ) ) {
final LockMode lockMode = determineFollowOnLockMode( parameters.getLockOptions() );
final LockOptions lockOptions = new LockOptions( lockMode );
if ( lockOptions.getLockMode() != LockMode.UPGRADE_SKIPLOCKED ) {
if ( lockOptions.getLockMode() != LockMode.NONE ) {
LOG.usingFollowOnLocking();
}
lockOptions.setTimeOut( parameters.getLockOptions().getTimeOut() );
lockOptions.setScope( parameters.getLockOptions().getScope() );
afterLoadActions.add(
new AfterLoadAction() {
@Override
public void afterLoad(SharedSessionContractImplementor session, Object entity, Loadable persister) {
( (Session) session ).buildLockRequest( lockOptions ).lock(
persister.getEntityName(),
entity
);
}
}
);
parameters.setLockOptions( new LockOptions() );
return true;
}
}
return false;
}
protected LockMode determineFollowOnLockMode(LockOptions lockOptions) {
final LockMode lockModeToUse = lockOptions.findGreatestLockMode();
if ( lockOptions.hasAliasSpecificLockModes() ) {
if ( lockOptions.getLockMode() == LockMode.NONE && lockModeToUse == LockMode.NONE ) {
return lockModeToUse;
}
else {
LOG.aliasSpecificLockingWithFollowOnLocking( lockModeToUse );
}
}
return lockModeToUse;
}
public List doQueryAndInitializeNonLazyCollections(
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final boolean returnProxies) throws HibernateException, SQLException {
return doQueryAndInitializeNonLazyCollections(
session,
queryParameters,
returnProxies,
null
);
}
public List doQueryAndInitializeNonLazyCollections(
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final boolean returnProxies,
final ResultTransformer forcedResultTransformer)
throws HibernateException, SQLException {
final PersistenceContext persistenceContext = session.getPersistenceContext();
boolean defaultReadOnlyOrig = persistenceContext.isDefaultReadOnly();
if ( queryParameters.isReadOnlyInitialized() ) {
persistenceContext.setDefaultReadOnly( queryParameters.isReadOnly() );
}
else {
queryParameters.setReadOnly( persistenceContext.isDefaultReadOnly() );
}
persistenceContext.beforeLoad();
List result;
try {
try {
result = doQuery( session, queryParameters, returnProxies, forcedResultTransformer );
}
finally {
persistenceContext.afterLoad();
}
persistenceContext.initializeNonLazyCollections();
}
finally {
persistenceContext.setDefaultReadOnly( defaultReadOnlyOrig );
}
return result;
}
public Object loadSingleRow(
final ResultSet resultSet,
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final boolean returnProxies) throws HibernateException {
final int entitySpan = getEntityPersisters().length;
final List hydratedObjects = entitySpan == 0 ?
null : new ArrayList( entitySpan );
final Object result;
try {
result = getRowFromResultSet(
resultSet,
session,
queryParameters,
getLockModes( queryParameters.getLockOptions() ),
null,
hydratedObjects,
new EntityKey[entitySpan],
returnProxies
);
}
catch (SQLException sqle) {
throw factory.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not read next row of results",
getSQLString()
);
}
initializeEntitiesAndCollections(
hydratedObjects,
resultSet,
session,
queryParameters.isReadOnly( session )
);
session.getPersistenceContext().initializeNonLazyCollections();
return result;
}
private Object sequentialLoad(
final ResultSet resultSet,
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final boolean returnProxies,
final EntityKey keyToRead) throws HibernateException {
final int entitySpan = getEntityPersisters().length;
final List hydratedObjects = entitySpan == 0 ?
null : new ArrayList( entitySpan );
Object result = null;
final EntityKey[] loadedKeys = new EntityKey[entitySpan];
try {
do {
Object loaded = getRowFromResultSet(
resultSet,
session,
queryParameters,
getLockModes( queryParameters.getLockOptions() ),
null,
hydratedObjects,
loadedKeys,
returnProxies
);
if ( !keyToRead.equals( loadedKeys[0] ) ) {
throw new AssertionFailure(
String.format(
"Unexpected key read for row; expected [%s]; actual [%s]",
keyToRead,
loadedKeys[0]
)
);
}
if ( result == null ) {
result = loaded;
}
}
while ( resultSet.next() &&
isCurrentRowForSameEntity( keyToRead, 0, resultSet, session ) );
}
catch (SQLException sqle) {
throw factory.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not doAfterTransactionCompletion sequential read of results (forward)",
getSQLString()
);
}
initializeEntitiesAndCollections(
hydratedObjects,
resultSet,
session,
queryParameters.isReadOnly( session )
);
session.getPersistenceContext().initializeNonLazyCollections();
return result;
}
private boolean isCurrentRowForSameEntity(
final EntityKey keyToRead,
final int persisterIndex,
final ResultSet resultSet,
final SharedSessionContractImplementor session) throws SQLException {
EntityKey currentRowKey = getKeyFromResultSet(
persisterIndex, getEntityPersisters()[persisterIndex], null, resultSet, session
);
return keyToRead.equals( currentRowKey );
}
public Object loadSequentialRowsForward(
final ResultSet resultSet,
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final boolean returnProxies) throws HibernateException {
try {
if ( resultSet.isAfterLast() ) {
return null;
}
if ( resultSet.isBeforeFirst() ) {
resultSet.next();
}
final EntityKey currentKey = getKeyFromResultSet(
0,
getEntityPersisters()[0],
null,
resultSet,
session
);
return sequentialLoad( resultSet, session, queryParameters, returnProxies, currentKey );
}
catch (SQLException sqle) {
throw factory.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not perform sequential read of results (forward)",
getSQLString()
);
}
}
public Object loadSequentialRowsReverse(
final ResultSet resultSet,
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final boolean returnProxies,
final boolean isLogicallyAfterLast) throws HibernateException {
try {
if ( resultSet.isFirst() ) {
return null;
}
EntityKey keyToRead = null;
if ( resultSet.isAfterLast() && isLogicallyAfterLast ) {
resultSet.last();
keyToRead = getKeyFromResultSet(
0,
getEntityPersisters()[0],
null,
resultSet,
session
);
}
else {
resultSet.previous();
boolean firstPass = true;
final EntityKey lastKey = getKeyFromResultSet(
0,
getEntityPersisters()[0],
null,
resultSet,
session
);
while ( resultSet.previous() ) {
EntityKey checkKey = getKeyFromResultSet(
0,
getEntityPersisters()[0],
null,
resultSet,
session
);
if ( firstPass ) {
firstPass = false;
keyToRead = checkKey;
}
if ( !lastKey.equals( checkKey ) ) {
break;
}
}
}
while ( resultSet.previous() ) {
EntityKey checkKey = getKeyFromResultSet(
0,
getEntityPersisters()[0],
null,
resultSet,
session
);
if ( !keyToRead.equals( checkKey ) ) {
break;
}
}
resultSet.next();
return sequentialLoad( resultSet, session, queryParameters, returnProxies, keyToRead );
}
catch (SQLException sqle) {
throw factory.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not doAfterTransactionCompletion sequential read of results (forward)",
getSQLString()
);
}
}
private static EntityKey getOptionalObjectKey(QueryParameters queryParameters, SharedSessionContractImplementor session) {
final Object optionalObject = queryParameters.getOptionalObject();
final Serializable optionalId = queryParameters.getOptionalId();
final String optionalEntityName = queryParameters.getOptionalEntityName();
if ( optionalObject != null && optionalEntityName != null ) {
return session.generateEntityKey(
optionalId, session.getEntityPersister(
optionalEntityName,
optionalObject
)
);
}
else {
return null;
}
}
private Object getRowFromResultSet(
final ResultSet resultSet,
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final LockMode[] lockModesArray,
final EntityKey optionalObjectKey,
final List hydratedObjects,
final EntityKey[] keys,
boolean returnProxies) throws SQLException, HibernateException {
return getRowFromResultSet(
resultSet,
session,
queryParameters,
lockModesArray,
optionalObjectKey,
hydratedObjects,
keys,
returnProxies,
null
);
}
private Object getRowFromResultSet(
final ResultSet resultSet,
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final LockMode[] lockModesArray,
final EntityKey optionalObjectKey,
final List hydratedObjects,
final EntityKey[] keys,
boolean returnProxies,
ResultTransformer forcedResultTransformer) throws SQLException, HibernateException {
final Loadable[] persisters = getEntityPersisters();
final int entitySpan = persisters.length;
extractKeysFromResultSet(
persisters,
queryParameters,
resultSet,
session,
keys,
lockModesArray,
hydratedObjects
);
registerNonExists( keys, persisters, session );
Object[] row = getRow(
resultSet,
persisters,
keys,
queryParameters.getOptionalObject(),
optionalObjectKey,
lockModesArray,
hydratedObjects,
session
);
readCollectionElements( row, resultSet, session );
if ( returnProxies ) {
for ( int i = 0; i < entitySpan; i++ ) {
Object entity = row[i];
Object proxy = session.getPersistenceContext().proxyFor( persisters[i], keys[i], entity );
if ( entity != proxy ) {
( (HibernateProxy) proxy ).getHibernateLazyInitializer().setImplementation( entity );
row[i] = proxy;
}
}
}
applyPostLoadLocks( row, lockModesArray, session );
return forcedResultTransformer == null
? getResultColumnOrRow( row, queryParameters.getResultTransformer(), resultSet, session )
: forcedResultTransformer.transformTuple(
getResultRow( row, resultSet, session ),
getResultRowAliases()
)
;
}
protected void (
Loadable[] persisters,
QueryParameters queryParameters,
ResultSet resultSet,
SharedSessionContractImplementor session,
EntityKey[] keys,
LockMode[] lockModes,
List hydratedObjects) throws SQLException {
final int entitySpan = persisters.length;
final int numberOfPersistersToProcess;
final Serializable optionalId = queryParameters.getOptionalId();
if ( isSingleRowLoader() && optionalId != null ) {
keys[entitySpan - 1] = session.generateEntityKey( optionalId, persisters[entitySpan - 1] );
numberOfPersistersToProcess = entitySpan - 1;
}
else {
numberOfPersistersToProcess = entitySpan;
}
final Object[] hydratedKeyState = new Object[numberOfPersistersToProcess];
for ( int i = 0; i < numberOfPersistersToProcess; i++ ) {
final Type idType = persisters[i].getIdentifierType();
hydratedKeyState[i] = idType.hydrate(
resultSet,
getEntityAliases()[i].getSuffixedKeyAliases(),
session,
null
);
}
for ( int i = 0; i < numberOfPersistersToProcess; i++ ) {
final Type idType = persisters[i].getIdentifierType();
if ( idType.isComponentType() && getCompositeKeyManyToOneTargetIndices() != null ) {
int[] keyManyToOneTargetIndices = getCompositeKeyManyToOneTargetIndices()[i];
if ( keyManyToOneTargetIndices != null ) {
for ( int targetIndex : keyManyToOneTargetIndices ) {
if ( targetIndex < numberOfPersistersToProcess ) {
final Type targetIdType = persisters[targetIndex].getIdentifierType();
final Serializable targetId = (Serializable) targetIdType.resolve(
hydratedKeyState[targetIndex],
session,
null
);
keys[targetIndex] = session.generateEntityKey( targetId, persisters[targetIndex] );
}
Object object = session.getEntityUsingInterceptor( keys[targetIndex] );
if ( object != null ) {
instanceAlreadyLoaded(
resultSet,
targetIndex,
persisters[targetIndex],
keys[targetIndex],
object,
lockModes[targetIndex],
session
);
}
else {
instanceNotYetLoaded(
resultSet,
targetIndex,
persisters[targetIndex],
getEntityAliases()[targetIndex].getRowIdAlias(),
keys[targetIndex],
lockModes[targetIndex],
getOptionalObjectKey( queryParameters, session ),
queryParameters.getOptionalObject(),
hydratedObjects,
session
);
}
}
}
}
final Serializable resolvedId;
if ( hydratedKeyState[i] != null ) {
resolvedId = (Serializable) idType.resolve( hydratedKeyState[i], session, null );
}
else {
resolvedId = null;
}
keys[i] = resolvedId == null ? null : session.generateEntityKey( resolvedId, persisters[i] );
}
}
protected void applyPostLoadLocks(Object[] row, LockMode[] lockModesArray, SharedSessionContractImplementor session) {
}
private void readCollectionElements(Object[] row, ResultSet resultSet, SharedSessionContractImplementor session)
throws SQLException, HibernateException {
final CollectionPersister[] collectionPersisters = getCollectionPersisters();
if ( collectionPersisters != null ) {
final CollectionAliases[] descriptors = getCollectionAliases();
final int[] collectionOwners = getCollectionOwners();
for ( int i = 0; i < collectionPersisters.length; i++ ) {
final boolean hasCollectionOwners = collectionOwners != null &&
collectionOwners[i] > -1;
final Object owner = hasCollectionOwners ?
row[collectionOwners[i]] :
null;
final CollectionPersister collectionPersister = collectionPersisters[i];
final Serializable key;
if ( owner == null ) {
key = null;
}
else {
key = collectionPersister.getCollectionType().getKeyOfOwner( owner, session );
}
readCollectionElement(
owner,
key,
collectionPersister,
descriptors[i],
resultSet,
session
);
}
}
}
private List doQuery(
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final boolean returnProxies,
final ResultTransformer forcedResultTransformer) throws SQLException, HibernateException {
final RowSelection selection = queryParameters.getRowSelection();
final int maxRows = LimitHelper.hasMaxRows( selection ) ?
selection.getMaxRows() :
Integer.MAX_VALUE;
final List<AfterLoadAction> afterLoadActions = new ArrayList<AfterLoadAction>();
final SqlStatementWrapper wrapper = executeQueryStatement( queryParameters, false, afterLoadActions, session );
final ResultSet rs = wrapper.getResultSet();
final Statement st = wrapper.getStatement();
try {
return processResultSet(
rs,
queryParameters,
session,
returnProxies,
forcedResultTransformer,
maxRows,
afterLoadActions
);
}
finally {
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( st );
session.getJdbcCoordinator().afterStatementExecution();
}
}
protected List processResultSet(
ResultSet rs,
QueryParameters queryParameters,
SharedSessionContractImplementor session,
boolean returnProxies,
ResultTransformer forcedResultTransformer,
int maxRows,
List<AfterLoadAction> afterLoadActions) throws SQLException {
final int entitySpan = getEntityPersisters().length;
final EntityKey optionalObjectKey = getOptionalObjectKey( queryParameters, session );
final LockMode[] lockModesArray = getLockModes( queryParameters.getLockOptions() );
final boolean createSubselects = isSubselectLoadingEnabled();
final List subselectResultKeys = createSubselects ? new ArrayList() : null;
final ArrayList hydratedObjects = entitySpan == 0 ? null : new ArrayList( entitySpan * 10 );
final List results = new ArrayList();
handleEmptyCollections( queryParameters.getCollectionKeys(), rs, session );
EntityKey[] keys = new EntityKey[entitySpan];
LOG.trace( "Processing result set" );
int count;
for ( count = 0; count < maxRows && rs.next(); count++ ) {
if ( DEBUG_ENABLED ) {
LOG.debugf( "Result set row: %s", count );
}
Object result = getRowFromResultSet(
rs,
session,
queryParameters,
lockModesArray,
optionalObjectKey,
hydratedObjects,
keys,
returnProxies,
forcedResultTransformer
);
results.add( result );
if ( createSubselects ) {
subselectResultKeys.add( keys );
keys = new EntityKey[entitySpan];
}
}
LOG.tracev( "Done processing result set ({0} rows)", count );
initializeEntitiesAndCollections(
hydratedObjects,
rs,
session,
queryParameters.isReadOnly( session ),
afterLoadActions
);
if ( createSubselects ) {
createSubselects( subselectResultKeys, queryParameters, session );
}
return results;
}
protected boolean isSubselectLoadingEnabled() {
return false;
}
protected boolean hasSubselectLoadableCollections() {
final Loadable[] loadables = getEntityPersisters();
for ( Loadable loadable : loadables ) {
if ( loadable.hasSubselectLoadableCollections() ) {
return true;
}
}
return false;
}
private static Set[] transpose(List keys) {
Set[] result = new Set[( (EntityKey[]) keys.get( 0 ) ).length];
for ( int j = 0; j < result.length; j++ ) {
result[j] = new HashSet( keys.size() );
for ( Object key : keys ) {
result[j].add( ( (EntityKey[]) key )[j] );
}
}
return result;
}
private void createSubselects(List keys, QueryParameters queryParameters, SharedSessionContractImplementor session) {
if ( keys.size() > 1 ) {
Set[] keySets = transpose( keys );
Map namedParameterLocMap = buildNamedParameterLocMap( queryParameters );
final Loadable[] loadables = getEntityPersisters();
final String[] aliases = getAliases();
final String subselectQueryString = SubselectFetch.createSubselectFetchQueryFragment( queryParameters );
for ( Object key : keys ) {
final EntityKey[] rowKeys = (EntityKey[]) key;
for ( int i = 0; i < rowKeys.length; i++ ) {
if ( rowKeys[i] != null && loadables[i].hasSubselectLoadableCollections() ) {
SubselectFetch subselectFetch = new SubselectFetch(
subselectQueryString,
aliases[i],
loadables[i],
queryParameters,
keySets[i],
namedParameterLocMap
);
session.getPersistenceContext()
.getBatchFetchQueue()
.addSubselect( rowKeys[i], subselectFetch );
}
}
}
}
}
private Map buildNamedParameterLocMap(QueryParameters queryParameters) {
if ( queryParameters.getNamedParameters() != null ) {
final Map namedParameterLocMap = new HashMap();
for ( String name : queryParameters.getNamedParameters().keySet() ) {
namedParameterLocMap.put(
name,
getNamedParameterLocs( name )
);
}
return namedParameterLocMap;
}
else {
return null;
}
}
private void initializeEntitiesAndCollections(
final List hydratedObjects,
final Object resultSetId,
final SharedSessionContractImplementor session,
final boolean readOnly) throws HibernateException {
initializeEntitiesAndCollections(
hydratedObjects,
resultSetId,
session,
readOnly,
Collections.emptyList()
);
}
private void initializeEntitiesAndCollections(
final List hydratedObjects,
final Object resultSetId,
final SharedSessionContractImplementor session,
final boolean readOnly,
List<AfterLoadAction> afterLoadActions) throws HibernateException {
final CollectionPersister[] collectionPersisters = getCollectionPersisters();
if ( collectionPersisters != null ) {
for ( CollectionPersister collectionPersister : collectionPersisters ) {
if ( collectionPersister.isArray() ) {
endCollectionLoad( resultSetId, session, collectionPersister );
}
}
}
final PreLoadEvent pre;
final PostLoadEvent post;
if ( session.isEventSource() ) {
pre = new PreLoadEvent( (EventSource) session );
post = new PostLoadEvent( (EventSource) session );
}
else {
pre = null;
post = null;
}
if ( hydratedObjects != null ) {
int hydratedObjectsSize = hydratedObjects.size();
LOG.tracev( "Total objects hydrated: {0}", hydratedObjectsSize );
for ( Object hydratedObject : hydratedObjects ) {
TwoPhaseLoad.initializeEntity( hydratedObject, readOnly, session, pre );
}
}
if ( collectionPersisters != null ) {
for ( CollectionPersister collectionPersister : collectionPersisters ) {
if ( !collectionPersister.isArray() ) {
endCollectionLoad( resultSetId, session, collectionPersister );
}
}
}
if ( hydratedObjects != null ) {
for ( Object hydratedObject : hydratedObjects ) {
TwoPhaseLoad.postLoad( hydratedObject, session, post );
if ( afterLoadActions != null ) {
for ( AfterLoadAction afterLoadAction : afterLoadActions ) {
final EntityEntry entityEntry = session.getPersistenceContext().getEntry( hydratedObject );
if ( entityEntry == null ) {
throw new HibernateException(
"Could not locate EntityEntry immediately after two-phase load"
);
}
afterLoadAction.afterLoad( session, hydratedObject, (Loadable) entityEntry.getPersister() );
}
}
}
}
}
private void endCollectionLoad(
final Object resultSetId,
final SharedSessionContractImplementor session,
final CollectionPersister collectionPersister) {
session.getPersistenceContext()
.getLoadContexts()
.getCollectionLoadContext( (ResultSet) resultSetId )
.endLoadingCollections( collectionPersister );
}
protected ResultTransformer resolveResultTransformer(ResultTransformer resultTransformer) {
return resultTransformer;
}
protected List getResultList(List results, ResultTransformer resultTransformer) throws QueryException {
return results;
}
protected boolean areResultSetRowsTransformedImmediately() {
return false;
}
protected String[] getResultRowAliases() {
return null;
}
protected Object getResultColumnOrRow(
Object[] row,
ResultTransformer transformer,
ResultSet rs,
SharedSessionContractImplementor session) throws SQLException, HibernateException {
return row;
}
protected boolean[] includeInResultRow() {
return null;
}
protected Object[] getResultRow(
Object[] row,
ResultSet rs,
SharedSessionContractImplementor session) throws SQLException, HibernateException {
return row;
}
private void registerNonExists(
final EntityKey[] keys,
final Loadable[] persisters,
final SharedSessionContractImplementor session) {
final int[] owners = getOwners();
if ( owners != null ) {
EntityType[] ownerAssociationTypes = getOwnerAssociationTypes();
for ( int i = 0; i < keys.length; i++ ) {
int owner = owners[i];
if ( owner > -1 ) {
EntityKey ownerKey = keys[owner];
if ( keys[i] == null && ownerKey != null ) {
final PersistenceContext persistenceContext = session.getPersistenceContext();
boolean isOneToOneAssociation = ownerAssociationTypes != null &&
ownerAssociationTypes[i] != null &&
ownerAssociationTypes[i].isOneToOne();
if ( isOneToOneAssociation ) {
persistenceContext.addNullProperty(
ownerKey,
ownerAssociationTypes[i].getPropertyName()
);
}
}
}
}
}
}
private void readCollectionElement(
final Object optionalOwner,
final Serializable optionalKey,
final CollectionPersister persister,
final CollectionAliases descriptor,
final ResultSet rs,
final SharedSessionContractImplementor session)
throws HibernateException, SQLException {
final PersistenceContext persistenceContext = session.getPersistenceContext();
final Serializable collectionRowKey = (Serializable) persister.readKey(
rs,
descriptor.getSuffixedKeyAliases(),
session
);
if ( collectionRowKey != null ) {
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Found row of collection: %s",
MessageHelper.collectionInfoString( persister, collectionRowKey, getFactory() )
);
}
Object owner = optionalOwner;
if ( owner == null ) {
owner = persistenceContext.getCollectionOwner( collectionRowKey, persister );
if ( owner == null ) {
}
}
PersistentCollection rowCollection = persistenceContext.getLoadContexts()
.getCollectionLoadContext( rs )
.getLoadingCollection( persister, collectionRowKey );
if ( rowCollection != null ) {
rowCollection.readFrom( rs, persister, descriptor, owner );
}
}
else if ( optionalKey != null ) {
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Result set contains (possibly empty) collection: %s",
MessageHelper.collectionInfoString( persister, optionalKey, getFactory() )
);
}
persistenceContext.getLoadContexts()
.getCollectionLoadContext( rs )
.getLoadingCollection( persister, optionalKey );
}
}
private void handleEmptyCollections(
final Serializable[] keys,
final Object resultSetId,
final SharedSessionContractImplementor session) {
if ( keys != null ) {
final boolean debugEnabled = LOG.isDebugEnabled();
CollectionPersister[] collectionPersisters = getCollectionPersisters();
for ( CollectionPersister collectionPersister : collectionPersisters ) {
for ( Serializable key : keys ) {
if ( debugEnabled ) {
LOG.debugf(
"Result set contains (possibly empty) collection: %s",
MessageHelper.collectionInfoString( collectionPersister, key, getFactory() )
);
}
session.getPersistenceContext()
.getLoadContexts()
.getCollectionLoadContext( (ResultSet) resultSetId )
.getLoadingCollection( collectionPersister, key );
}
}
}
}
private EntityKey getKeyFromResultSet(
final int i,
final Loadable persister,
final Serializable id,
final ResultSet rs,
final SharedSessionContractImplementor session) throws HibernateException, SQLException {
Serializable resultId;
if ( isSingleRowLoader() && id != null ) {
resultId = id;
}
else {
final Type idType = persister.getIdentifierType();
resultId = (Serializable) idType.nullSafeGet(
rs,
getEntityAliases()[i].getSuffixedKeyAliases(),
session,
null
);
final boolean idIsResultId = id != null &&
resultId != null &&
idType.isEqual( id, resultId, factory );
if ( idIsResultId ) {
resultId = id;
}
}
return resultId == null ? null : session.generateEntityKey( resultId, persister );
}
private void checkVersion(
final int i,
final Loadable persister,
final Serializable id,
final Object entity,
final ResultSet rs,
final SharedSessionContractImplementor session) throws HibernateException, SQLException {
Object version = session.getPersistenceContext().getEntry( entity ).getVersion();
if ( version != null ) {
final VersionType versionType = persister.getVersionType();
final Object currentVersion = versionType.nullSafeGet(
rs,
getEntityAliases()[i].getSuffixedVersionAliases(),
session,
null
);
if ( !versionType.isEqual( version, currentVersion ) ) {
if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
session.getFactory().getStatistics().optimisticFailure( persister.getEntityName() );
}
throw new StaleObjectStateException( persister.getEntityName(), id );
}
}
}
private Object[] getRow(
final ResultSet rs,
final Loadable[] persisters,
final EntityKey[] keys,
final Object optionalObject,
final EntityKey optionalObjectKey,
final LockMode[] lockModes,
final List hydratedObjects,
final SharedSessionContractImplementor session) throws HibernateException, SQLException {
final int cols = persisters.length;
final EntityAliases[] descriptors = getEntityAliases();
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Result row: %s", StringHelper.toString( keys ) );
}
final Object[] rowResults = new Object[cols];
for ( int i = 0; i < cols; i++ ) {
Object object = null;
EntityKey key = keys[i];
if ( keys[i] == null ) {
}
else {
object = session.getEntityUsingInterceptor( key );
if ( object != null ) {
instanceAlreadyLoaded(
rs,
i,
persisters[i],
key,
object,
lockModes[i],
session
);
}
else {
object = instanceNotYetLoaded(
rs,
i,
persisters[i],
descriptors[i].getRowIdAlias(),
key,
lockModes[i],
optionalObjectKey,
optionalObject,
hydratedObjects,
session
);
}
}
rowResults[i] = object;
}
return rowResults;
}
private void instanceAlreadyLoaded(
final ResultSet rs,
final int i,
final Loadable persister,
final EntityKey key,
final Object object,
final LockMode requestedLockMode,
final SharedSessionContractImplementor session)
throws HibernateException, SQLException {
if ( !persister.isInstance( object ) ) {
throw new WrongClassException(
"loaded object was of wrong class " + object.getClass(),
key.getIdentifier(),
persister.getEntityName()
);
}
if ( LockMode.NONE != requestedLockMode && upgradeLocks() ) {
final EntityEntry entry = session.getPersistenceContext().getEntry( object );
if ( entry.getLockMode().lessThan( requestedLockMode ) ) {
if ( persister.isVersioned() ) {
checkVersion( i, persister, key.getIdentifier(), object, rs, session );
}
entry.setLockMode( requestedLockMode );
}
}
}
private Object instanceNotYetLoaded(
final ResultSet rs,
final int i,
final Loadable persister,
final String rowIdAlias,
final EntityKey key,
final LockMode lockMode,
final EntityKey optionalObjectKey,
final Object optionalObject,
final List hydratedObjects,
final SharedSessionContractImplementor session)
throws HibernateException, SQLException {
final String instanceClass = getInstanceClass(
rs,
i,
persister,
key.getIdentifier(),
session
);
if ( session.getCacheMode().isGetEnabled() && persister.canUseReferenceCacheEntries() ) {
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey(
key.getIdentifier(),
persister,
session.getFactory(),
session.getTenantIdentifier()
);
final Object cachedEntry = CacheHelper.fromSharedCache( session, ck, cache );
if ( cachedEntry != null ) {
CacheEntry entry = (CacheEntry) persister.getCacheEntryStructure().destructure( cachedEntry, factory );
return ( (ReferenceCacheEntryImpl) entry ).getReference();
}
}
final Object object;
if ( optionalObjectKey != null && key.equals( optionalObjectKey ) ) {
object = optionalObject;
}
else {
object = session.instantiate( instanceClass, key.getIdentifier() );
}
LockMode acquiredLockMode = lockMode == LockMode.NONE ? LockMode.READ : lockMode;
loadFromResultSet(
rs,
i,
object,
instanceClass,
key,
rowIdAlias,
acquiredLockMode,
persister,
session
);
hydratedObjects.add( object );
return object;
}
private boolean isEagerPropertyFetchEnabled(int i) {
boolean[] array = getEntityEagerPropertyFetches();
return array != null && array[i];
}
private void loadFromResultSet(
final ResultSet rs,
final int i,
final Object object,
final String instanceEntityName,
final EntityKey key,
final String rowIdAlias,
final LockMode lockMode,
final Loadable rootPersister,
final SharedSessionContractImplementor session) throws SQLException, HibernateException {
final Serializable id = key.getIdentifier();
final Loadable persister = (Loadable) getFactory().getEntityPersister( instanceEntityName );
if ( LOG.isTraceEnabled() ) {
LOG.tracef(
"Initializing object from ResultSet: %s",
MessageHelper.infoString(
persister,
id,
getFactory()
)
);
}
boolean fetchAllPropertiesRequested = isEagerPropertyFetchEnabled( i );
TwoPhaseLoad.addUninitializedEntity(
key,
object,
persister,
lockMode,
session
);
final String[][] cols = persister == rootPersister ?
getEntityAliases()[i].getSuffixedPropertyAliases() :
getEntityAliases()[i].getSuffixedPropertyAliases( persister );
final Object[] values = persister.hydrate(
rs,
id,
object,
rootPersister,
cols,
fetchAllPropertiesRequested,
session
);
final Object rowId = persister.hasRowId() ? rs.getObject( rowIdAlias ) : null;
final AssociationType[] ownerAssociationTypes = getOwnerAssociationTypes();
if ( ownerAssociationTypes != null && ownerAssociationTypes[i] != null ) {
String ukName = ownerAssociationTypes[i].getRHSUniqueKeyPropertyName();
if ( ukName != null ) {
final int index = ( (UniqueKeyLoadable) persister ).getPropertyIndex( ukName );
final Type type = persister.getPropertyTypes()[index];
EntityUniqueKey euk = new EntityUniqueKey(
rootPersister.getEntityName(),
ukName,
type.semiResolve( values[index], session, object ),
type,
persister.getEntityMode(),
session.getFactory()
);
session.getPersistenceContext().addEntity( euk, object );
}
}
TwoPhaseLoad.postHydrate(
persister,
id,
values,
rowId,
object,
lockMode,
session
);
}
private String getInstanceClass(
final ResultSet rs,
final int i,
final Loadable persister,
final Serializable id,
final SharedSessionContractImplementor session) throws HibernateException, SQLException {
if ( persister.hasSubclasses() ) {
final Object discriminatorValue = persister.getDiscriminatorType().nullSafeGet(
rs,
getEntityAliases()[i].getSuffixedDiscriminatorAlias(),
session,
null
);
final String result = persister.getSubclassForDiscriminatorValue( discriminatorValue );
if ( result == null ) {
throw new WrongClassException(
"Discriminator: " + discriminatorValue,
id,
persister.getEntityName()
);
}
return result;
}
else {
return persister.getEntityName();
}
}
private void advance(final ResultSet rs, final RowSelection selection) throws SQLException {
final int firstRow = LimitHelper.getFirstRow( selection );
if ( firstRow != 0 ) {
if ( getFactory().getSessionFactoryOptions().isScrollableResultSetsEnabled() ) {
rs.absolute( firstRow );
}
else {
for ( int m = 0; m < firstRow; m++ ) {
rs.next();
}
}
}
}
protected LimitHandler getLimitHandler(RowSelection selection) {
final LimitHandler limitHandler = getFactory().getDialect().getLimitHandler();
return LimitHelper.useLimit( limitHandler, selection ) ? limitHandler : NoopLimitHandler.INSTANCE;
}
private ScrollMode getScrollMode(
boolean scroll,
boolean hasFirstRow,
boolean useLimitOffSet,
QueryParameters queryParameters) {
final boolean canScroll = getFactory().getSessionFactoryOptions().isScrollableResultSetsEnabled();
if ( canScroll ) {
if ( scroll ) {
return queryParameters.getScrollMode();
}
if ( hasFirstRow && !useLimitOffSet ) {
return ScrollMode.SCROLL_INSENSITIVE;
}
}
return null;
}
protected SqlStatementWrapper executeQueryStatement(
final QueryParameters queryParameters,
final boolean scroll,
List<AfterLoadAction> afterLoadActions,
final SharedSessionContractImplementor session) throws SQLException {
return executeQueryStatement( getSQLString(), queryParameters, scroll, afterLoadActions, session );
}
protected SqlStatementWrapper executeQueryStatement(
String sqlStatement,
QueryParameters queryParameters,
boolean scroll,
List<AfterLoadAction> afterLoadActions,
SharedSessionContractImplementor session) throws SQLException {
queryParameters.processFilters( sqlStatement, session );
final LimitHandler limitHandler = getLimitHandler(
queryParameters.getRowSelection()
);
String sql = limitHandler.processSql( queryParameters.getFilteredSQL(), queryParameters.getRowSelection() );
sql = preprocessSQL( sql, queryParameters, getFactory(), afterLoadActions );
final PreparedStatement st = prepareQueryStatement( sql, queryParameters, limitHandler, scroll, session );
final ResultSet rs;
if( queryParameters.isCallable() && isTypeOf( st, CallableStatement.class ) ) {
final CallableStatement cs = st.unwrap( CallableStatement.class );
rs = getResultSet(
cs,
queryParameters.getRowSelection(),
limitHandler,
queryParameters.hasAutoDiscoverScalarTypes(),
session
);
}
else {
rs = getResultSet(
st,
queryParameters.getRowSelection(),
limitHandler,
queryParameters.hasAutoDiscoverScalarTypes(),
session
);
}
return new SqlStatementWrapper(
st,
rs
);
}
private boolean isTypeOf(final Statement statement, final Class<? extends Statement> type) {
if ( isJdbc4 ) {
try {
return statement.isWrapperFor( type );
}
catch (SQLException e) {
}
catch (Throwable e) {
isJdbc4 = false;
}
}
return type.isInstance( statement );
}
protected final PreparedStatement prepareQueryStatement(
String sql,
final QueryParameters queryParameters,
final LimitHandler limitHandler,
final boolean scroll,
final SharedSessionContractImplementor session) throws SQLException, HibernateException {
final Dialect dialect = getFactory().getDialect();
final RowSelection selection = queryParameters.getRowSelection();
final boolean useLimit = LimitHelper.useLimit( limitHandler, selection );
final boolean hasFirstRow = LimitHelper.hasFirstRow( selection );
final boolean useLimitOffset = hasFirstRow && useLimit && limitHandler.supportsLimitOffset();
final boolean callable = queryParameters.isCallable();
final ScrollMode scrollMode = getScrollMode( scroll, hasFirstRow, useLimitOffset, queryParameters );
PreparedStatement st = session.getJdbcCoordinator().getStatementPreparer().prepareQueryStatement(
sql,
callable,
scrollMode
);
try {
int col = 1;
col += limitHandler.bindLimitParametersAtStartOfQuery( selection, st, col );
if ( callable ) {
col = dialect.registerResultSetOutParameter( (CallableStatement) st, col );
}
col += bindParameterValues( st, queryParameters, col, session );
col += limitHandler.bindLimitParametersAtEndOfQuery( selection, st, col );
limitHandler.setMaxRows( selection, st );
if ( selection != null ) {
if ( selection.getTimeout() != null ) {
st.setQueryTimeout( selection.getTimeout() );
}
if ( selection.getFetchSize() != null ) {
st.setFetchSize( selection.getFetchSize() );
}
}
LockOptions lockOptions = queryParameters.getLockOptions();
if ( lockOptions != null ) {
if ( lockOptions.getTimeOut() != LockOptions.WAIT_FOREVER ) {
if ( !dialect.supportsLockTimeouts() ) {
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Lock timeout [%s] requested but dialect reported to not support lock timeouts",
lockOptions.getTimeOut()
);
}
}
else if ( dialect.isLockTimeoutParameterized() ) {
st.setInt( col++, lockOptions.getTimeOut() );
}
}
}
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Bound [{0}] parameters total", col );
}
}
catch (SQLException | HibernateException e) {
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( st );
session.getJdbcCoordinator().afterStatementExecution();
throw e;
}
return st;
}
protected int bindParameterValues(
PreparedStatement statement,
QueryParameters queryParameters,
int startIndex,
SharedSessionContractImplementor session) throws SQLException {
int span = 0;
span += bindPositionalParameters( statement, queryParameters, startIndex, session );
span += bindNamedParameters( statement, queryParameters.getNamedParameters(), startIndex + span, session );
return span;
}
protected int bindPositionalParameters(
final PreparedStatement statement,
final QueryParameters queryParameters,
final int startIndex,
final SharedSessionContractImplementor session) throws SQLException, HibernateException {
final Object[] values = queryParameters.getFilteredPositionalParameterValues();
final Type[] types = queryParameters.getFilteredPositionalParameterTypes();
int span = 0;
for ( int i = 0; i < values.length; i++ ) {
types[i].nullSafeSet( statement, values[i], startIndex + span, session );
span += types[i].getColumnSpan( getFactory() );
}
return span;
}
protected int bindNamedParameters(
final PreparedStatement statement,
final Map<String, TypedValue> namedParams,
final int startIndex,
final SharedSessionContractImplementor session) throws SQLException, HibernateException {
int result = 0;
if ( CollectionHelper.isEmpty( namedParams ) ) {
return result;
}
for ( String name : namedParams.keySet() ) {
TypedValue typedValue = namedParams.get( name );
int columnSpan = typedValue.getType().getColumnSpan( getFactory() );
int[] locs = getNamedParameterLocs( name );
for ( int loc : locs ) {
if ( DEBUG_ENABLED ) {
LOG.debugf(
"bindNamedParameters() %s -> %s [%s]",
typedValue.getValue(),
name,
loc + startIndex
);
}
int start = loc * columnSpan + startIndex;
typedValue.getType().nullSafeSet( statement, typedValue.getValue(), start, session );
}
result += locs.length;
}
return result;
}
public int[] getNamedParameterLocs(String name) {
throw new AssertionFailure( "no named parameters" );
}
protected final ResultSet getResultSet(
final PreparedStatement st,
final RowSelection selection,
final LimitHandler limitHandler,
final boolean autodiscovertypes,
final SharedSessionContractImplementor session) throws SQLException, HibernateException {
try {
ResultSet rs = session.getJdbcCoordinator().getResultSetReturn().extract( st );
return processResultSet(rs, selection, limitHandler, autodiscovertypes, session);
}
catch (SQLException | HibernateException e) {
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( st );
session.getJdbcCoordinator().afterStatementExecution();
throw e;
}
}
protected final ResultSet getResultSet(
final CallableStatement st,
final RowSelection selection,
final LimitHandler limitHandler,
final boolean autodiscovertypes,
final SharedSessionContractImplementor session) throws SQLException, HibernateException {
try {
ResultSet rs = session.getJdbcCoordinator().getResultSetReturn().extract( st );
return processResultSet(rs, selection, limitHandler, autodiscovertypes, session);
}
catch (SQLException | HibernateException e) {
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( st );
session.getJdbcCoordinator().afterStatementExecution();
throw e;
}
}
private ResultSet processResultSet(
ResultSet rs,
final RowSelection selection,
final LimitHandler limitHandler,
final boolean autodiscovertypes,
final SharedSessionContractImplementor session
) throws SQLException, HibernateException {
rs = wrapResultSetIfEnabled( rs, session );
if ( !limitHandler.supportsLimitOffset() || !LimitHelper.useLimit( limitHandler, selection ) ) {
advance( rs, selection );
}
if ( autodiscovertypes ) {
autoDiscoverTypes( rs );
}
return rs;
}
protected void autoDiscoverTypes(ResultSet rs) {
throw new AssertionFailure( "Auto discover types not supported in this loader" );
}
private ResultSet wrapResultSetIfEnabled(final ResultSet rs, final SharedSessionContractImplementor session) {
if ( session.getFactory().getSessionFactoryOptions().isWrapResultSetsEnabled() ) {
try {
LOG.debugf( "Wrapping result set [%s]", rs );
return session.getFactory()
.getServiceRegistry()
.getService( JdbcServices.class )
.getResultSetWrapper().wrap( rs, retreiveColumnNameToIndexCache( rs ) );
}
catch (SQLException e) {
LOG.unableToWrapResultSet( e );
return rs;
}
}
else {
return rs;
}
}
private ColumnNameCache retreiveColumnNameToIndexCache(final ResultSet rs) throws SQLException {
final ColumnNameCache cache = columnNameCache;
if ( cache == null ) {
LOG.trace( "Building columnName -> columnIndex cache" );
columnNameCache = new ColumnNameCache( rs.getMetaData().getColumnCount() );
return columnNameCache;
}
else {
return cache;
}
}
protected final List loadEntity(
final SharedSessionContractImplementor session,
final Object id,
final Type identifierType,
final Object optionalObject,
final String optionalEntityName,
final Serializable optionalIdentifier,
final EntityPersister persister,
LockOptions lockOptions) throws HibernateException {
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Loading entity: %s", MessageHelper.infoString( persister, id, identifierType, getFactory() ) );
}
List result;
try {
QueryParameters qp = new QueryParameters();
qp.setPositionalParameterTypes( new Type[] {identifierType} );
qp.setPositionalParameterValues( new Object[] {id} );
qp.setOptionalObject( optionalObject );
qp.setOptionalEntityName( optionalEntityName );
qp.setOptionalId( optionalIdentifier );
qp.setLockOptions( lockOptions );
result = doQueryAndInitializeNonLazyCollections( session, qp, false );
}
catch (SQLException sqle) {
final Loadable[] persisters = getEntityPersisters();
throw factory.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not load an entity: " +
MessageHelper.infoString(
persisters[persisters.length - 1],
id,
identifierType,
getFactory()
),
getSQLString()
);
}
LOG.debug( "Done entity load" );
return result;
}
protected final List loadEntity(
final SharedSessionContractImplementor session,
final Object key,
final Object index,
final Type keyType,
final Type indexType,
final EntityPersister persister) throws HibernateException {
LOG.debug( "Loading collection element by index" );
List result;
try {
result = doQueryAndInitializeNonLazyCollections(
session,
new QueryParameters(
new Type[] {keyType, indexType},
new Object[] {key, index}
),
false
);
}
catch (SQLException sqle) {
throw factory.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not load collection element by index",
getSQLString()
);
}
LOG.debug( "Done entity load" );
return result;
}
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() ) );
}
Type[] types = new Type[ids.length];
Arrays.fill( types, idType );
List result;
try {
QueryParameters qp = new QueryParameters();
qp.setPositionalParameterTypes( types );
qp.setPositionalParameterValues( ids );
qp.setOptionalObject( optionalObject );
qp.setOptionalEntityName( optionalEntityName );
qp.setOptionalId( optionalId );
qp.setLockOptions( lockOptions );
result = doQueryAndInitializeNonLazyCollections( session, qp, false );
}
catch (SQLException sqle) {
throw factory.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not load an entity batch: " +
MessageHelper.infoString( getEntityPersisters()[0], ids, getFactory() ),
getSQLString()
);
}
LOG.debug( "Done entity batch load" );
return result;
}
public final void loadCollection(
final SharedSessionContractImplementor session,
final Serializable id,
final Type type) throws HibernateException {
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Loading collection: %s",
MessageHelper.collectionInfoString( getCollectionPersisters()[0], id, getFactory() )
);
}
Serializable[] ids = new Serializable[] {id};
try {
doQueryAndInitializeNonLazyCollections(
session,
new QueryParameters( new Type[] {type}, ids, ids ),
true
);
}
catch (SQLException sqle) {
throw factory.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not initialize a collection: " +
MessageHelper.collectionInfoString( getCollectionPersisters()[0], id, getFactory() ),
getSQLString()
);
}
LOG.debug( "Done loading collection" );
}
public final void loadCollectionBatch(
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() )
);
}
Type[] idTypes = new Type[ids.length];
Arrays.fill( idTypes, type );
try {
doQueryAndInitializeNonLazyCollections(
session,
new QueryParameters( idTypes, ids, ids ),
true
);
}
catch (SQLException sqle) {
throw factory.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not initialize a collection batch: " +
MessageHelper.collectionInfoString( getCollectionPersisters()[0], ids, getFactory() ),
getSQLString()
);
}
LOG.debug( "Done batch load" );
}
protected final void loadCollectionSubselect(
final SharedSessionContractImplementor session,
final Serializable[] ids,
final Object[] parameterValues,
final Type[] parameterTypes,
final Map<String, TypedValue> namedParameters,
final Type type) throws HibernateException {
final Type[] idTypes = new Type[ids.length];
Arrays.fill( idTypes, type );
try {
doQueryAndInitializeNonLazyCollections(
session,
new QueryParameters( parameterTypes, parameterValues, namedParameters, ids ),
true
);
}
catch (SQLException sqle) {
throw factory.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not load collection by subselect: " +
MessageHelper.collectionInfoString( getCollectionPersisters()[0], ids, getFactory() ),
getSQLString()
);
}
}
protected List list(
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final Set<Serializable> querySpaces,
final Type[] resultTypes) throws HibernateException {
final boolean cacheable = factory.getSessionFactoryOptions().isQueryCacheEnabled() &&
queryParameters.isCacheable();
if ( cacheable ) {
return listUsingQueryCache( session, queryParameters, querySpaces, resultTypes );
}
else {
return listIgnoreQueryCache( session, queryParameters );
}
}
private List listIgnoreQueryCache(SharedSessionContractImplementor session, QueryParameters queryParameters) {
return getResultList( doList( session, queryParameters ), queryParameters.getResultTransformer() );
}
private List listUsingQueryCache(
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final Set<Serializable> querySpaces,
final Type[] resultTypes) {
QueryResultsCache queryCache = factory.getCache().getQueryResultsCache( queryParameters.getCacheRegion() );
QueryKey key = generateQueryKey( session, queryParameters );
if ( querySpaces == null || querySpaces.size() == 0 ) {
LOG.tracev( "Unexpected querySpaces is {0}", ( querySpaces == null ? querySpaces : "empty" ) );
}
else {
LOG.tracev( "querySpaces is {0}", querySpaces );
}
List result = getResultFromQueryCache(
session,
queryParameters,
querySpaces,
resultTypes,
queryCache,
key
);
if ( result == null ) {
result = doList( session, queryParameters, key.getResultTransformer() );
putResultInQueryCache(
session,
queryParameters,
resultTypes,
queryCache,
key,
result
);
}
ResultTransformer resolvedTransformer = resolveResultTransformer( queryParameters.getResultTransformer() );
if ( resolvedTransformer != null ) {
result = (
areResultSetRowsTransformedImmediately() ?
key.getResultTransformer().retransformResults(
result,
getResultRowAliases(),
queryParameters.getResultTransformer(),
includeInResultRow()
) :
key.getResultTransformer().untransformToTuples(
result
)
);
}
return getResultList( result, queryParameters.getResultTransformer() );
}
private QueryKey generateQueryKey(
SharedSessionContractImplementor session,
QueryParameters queryParameters) {
return QueryKey.generateQueryKey(
getSQLString(),
queryParameters,
FilterKey.createFilterKeys( session.getLoadQueryInfluencers().getEnabledFilters() ),
session,
createCacheableResultTransformer( queryParameters )
);
}
private CacheableResultTransformer createCacheableResultTransformer(QueryParameters queryParameters) {
return CacheableResultTransformer.create(
queryParameters.getResultTransformer(),
getResultRowAliases(),
includeInResultRow()
);
}
private List getResultFromQueryCache(
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final Set<Serializable> querySpaces,
final Type[] resultTypes,
final QueryResultsCache queryCache,
final QueryKey key) {
List result = null;
if ( session.getCacheMode().isGetEnabled() ) {
boolean isImmutableNaturalKeyLookup =
queryParameters.isNaturalKeyLookup() &&
resultTypes.length == 1 &&
resultTypes[0].isEntityType() &&
getEntityPersister( EntityType.class.cast( resultTypes[0] ) )
.getEntityMetamodel()
.hasImmutableNaturalId();
final PersistenceContext persistenceContext = session.getPersistenceContext();
boolean defaultReadOnlyOrig = persistenceContext.isDefaultReadOnly();
if ( queryParameters.isReadOnlyInitialized() ) {
persistenceContext.setDefaultReadOnly( queryParameters.isReadOnly() );
}
else {
queryParameters.setReadOnly( persistenceContext.isDefaultReadOnly() );
}
try {
result = queryCache.get(
key,
querySpaces,
key.getResultTransformer().getCachedResultTypes( resultTypes ),
session
);
}
finally {
persistenceContext.setDefaultReadOnly( defaultReadOnlyOrig );
}
if ( factory.getStatistics().isStatisticsEnabled() ) {
if ( result == null ) {
factory.getStatistics().queryCacheMiss( getQueryIdentifier(), queryCache.getRegion().getName() );
}
else {
factory.getStatistics().queryCacheHit( getQueryIdentifier(), queryCache.getRegion().getName() );
}
}
}
return result;
}
private EntityPersister getEntityPersister(EntityType entityType) {
return factory.getMetamodel().entityPersister( entityType.getAssociatedEntityName() );
}
protected void putResultInQueryCache(
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final Type[] resultTypes,
final QueryResultsCache queryCache,
final QueryKey key,
final List result) {
if ( session.getCacheMode().isPutEnabled() ) {
boolean put = queryCache.put(
key,
result,
key.getResultTransformer().getCachedResultTypes( resultTypes ),
session
);
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatistics().queryCachePut( getQueryIdentifier(), queryCache.getRegion().getName() );
}
}
}
protected List doList(final SharedSessionContractImplementor session, final QueryParameters queryParameters)
throws HibernateException {
return doList( session, queryParameters, null );
}
private List doList(
final SharedSessionContractImplementor session,
final QueryParameters queryParameters,
final ResultTransformer forcedResultTransformer)
throws HibernateException {
final boolean stats = getFactory().getStatistics().isStatisticsEnabled();
long startTime = 0;
if ( stats ) {
startTime = System.nanoTime();
}
List result;
try {
result = doQueryAndInitializeNonLazyCollections( session, queryParameters, true, forcedResultTransformer );
}
catch (SQLException sqle) {
throw factory.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not execute query",
getSQLString()
);
}
if ( stats ) {
final long endTime = System.nanoTime();
final long milliseconds = TimeUnit.MILLISECONDS.convert( endTime - startTime, TimeUnit.NANOSECONDS );
getFactory().getStatistics().queryExecuted(
getQueryIdentifier(),
result.size(),
milliseconds
);
}
return result;
}
protected void checkScrollability() throws HibernateException {
}
protected boolean needsFetchingScroll() {
return false;
}
protected ScrollableResultsImplementor scroll(
final QueryParameters queryParameters,
final Type[] returnTypes,
final HolderInstantiator holderInstantiator,
final SharedSessionContractImplementor session) throws HibernateException {
checkScrollability();
final boolean stats = getQueryIdentifier() != null &&
getFactory().getStatistics().isStatisticsEnabled();
long startTime = 0;
if ( stats ) {
startTime = System.nanoTime();
}
try {
final SqlStatementWrapper wrapper = executeQueryStatement(
queryParameters,
true,
new ArrayList<AfterLoadAction>(),
session
);
final ResultSet rs = wrapper.getResultSet();
final PreparedStatement st = (PreparedStatement) wrapper.getStatement();
if ( stats ) {
final long endTime = System.nanoTime();
final long milliseconds = TimeUnit.MILLISECONDS.convert( endTime - startTime, TimeUnit.NANOSECONDS );
getFactory().getStatistics().queryExecuted(
getQueryIdentifier(),
0,
milliseconds
);
}
if ( needsFetchingScroll() ) {
return new FetchingScrollableResultsImpl(
rs,
st,
session,
this,
queryParameters,
returnTypes,
holderInstantiator
);
}
else {
return new ScrollableResultsImpl(
rs,
st,
session,
this,
queryParameters,
returnTypes,
holderInstantiator
);
}
}
catch (SQLException sqle) {
throw factory.getJdbcServices().getSqlExceptionHelper().convert(
sqle,
"could not execute query using scroll",
getSQLString()
);
}
}
protected void postInstantiate() {
}
protected abstract EntityAliases[] getEntityAliases();
protected abstract CollectionAliases[] getCollectionAliases();
protected String getQueryIdentifier() {
return null;
}
public final SessionFactoryImplementor getFactory() {
return factory;
}
@Override
public String toString() {
return getClass().getName() + '(' + getSQLString() + ')';
}
protected static class SqlStatementWrapper {
private final Statement statement;
private final ResultSet resultSet;
private SqlStatementWrapper(Statement statement, ResultSet resultSet) {
this.resultSet = resultSet;
this.statement = statement;
}
public ResultSet getResultSet() {
return resultSet;
}
public Statement getStatement() {
return statement;
}
}
protected String processDistinctKeyword(
String sql,
QueryParameters parameters) {
if ( !parameters.isPassDistinctThrough() ) {
if ( sql.startsWith( SELECT_DISTINCT ) ) {
return SELECT + sql.substring( SELECT_DISTINCT.length() );
}
}
return sql;
}
}