HHH-8211 - Checkstyle and FindBugs fix-ups
This commit is contained in:
parent
f2073113fc
commit
286800ec34
|
@ -62,7 +62,7 @@ public class CollectionLoadContext {
|
||||||
|
|
||||||
private final LoadContexts loadContexts;
|
private final LoadContexts loadContexts;
|
||||||
private final ResultSet resultSet;
|
private final ResultSet resultSet;
|
||||||
private Set localLoadingCollectionKeys = new HashSet();
|
private Set<CollectionKey> localLoadingCollectionKeys = new HashSet<CollectionKey>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a collection load context for the given result set.
|
* Creates a collection load context for the given result set.
|
||||||
|
@ -119,12 +119,13 @@ public class CollectionLoadContext {
|
||||||
if ( collection != null ) {
|
if ( collection != null ) {
|
||||||
if ( collection.wasInitialized() ) {
|
if ( collection.wasInitialized() ) {
|
||||||
LOG.trace( "Collection already initialized; ignoring" );
|
LOG.trace( "Collection already initialized; ignoring" );
|
||||||
return null; // ignore this row of results! Note the early exit
|
// ignore this row of results! Note the early exit
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
LOG.trace( "Collection not yet initialized; initializing" );
|
LOG.trace( "Collection not yet initialized; initializing" );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Object owner = loadContexts.getPersistenceContext().getCollectionOwner( key, persister );
|
final Object owner = loadContexts.getPersistenceContext().getCollectionOwner( key, persister );
|
||||||
final boolean newlySavedEntity = owner != null
|
final boolean newlySavedEntity = owner != null
|
||||||
&& loadContexts.getPersistenceContext().getEntry( owner ).getStatus() != Status.LOADING;
|
&& loadContexts.getPersistenceContext().getEntry( owner ).getStatus() != Status.LOADING;
|
||||||
if ( newlySavedEntity ) {
|
if ( newlySavedEntity ) {
|
||||||
|
@ -162,7 +163,7 @@ public class CollectionLoadContext {
|
||||||
* @param persister The persister for which to complete loading.
|
* @param persister The persister for which to complete loading.
|
||||||
*/
|
*/
|
||||||
public void endLoadingCollections(CollectionPersister persister) {
|
public void endLoadingCollections(CollectionPersister persister) {
|
||||||
SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
|
final SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
|
||||||
if ( !loadContexts.hasLoadingCollectionEntries()
|
if ( !loadContexts.hasLoadingCollectionEntries()
|
||||||
&& localLoadingCollectionKeys.isEmpty() ) {
|
&& localLoadingCollectionKeys.isEmpty() ) {
|
||||||
return;
|
return;
|
||||||
|
@ -174,17 +175,17 @@ public class CollectionLoadContext {
|
||||||
// internal loadingCollections map for matches and store those matches
|
// internal loadingCollections map for matches and store those matches
|
||||||
// in a temp collection. the temp collection is then used to "drive"
|
// in a temp collection. the temp collection is then used to "drive"
|
||||||
// the #endRead processing.
|
// the #endRead processing.
|
||||||
List matches = null;
|
List<LoadingCollectionEntry> matches = null;
|
||||||
Iterator iter = localLoadingCollectionKeys.iterator();
|
final Iterator itr = localLoadingCollectionKeys.iterator();
|
||||||
while ( iter.hasNext() ) {
|
while ( itr.hasNext() ) {
|
||||||
final CollectionKey collectionKey = (CollectionKey) iter.next();
|
final CollectionKey collectionKey = (CollectionKey) itr.next();
|
||||||
final LoadingCollectionEntry lce = loadContexts.locateLoadingCollectionEntry( collectionKey );
|
final LoadingCollectionEntry lce = loadContexts.locateLoadingCollectionEntry( collectionKey );
|
||||||
if ( lce == null ) {
|
if ( lce == null ) {
|
||||||
LOG.loadingCollectionKeyNotFound( collectionKey );
|
LOG.loadingCollectionKeyNotFound( collectionKey );
|
||||||
}
|
}
|
||||||
else if ( lce.getResultSet() == resultSet && lce.getPersister() == persister ) {
|
else if ( lce.getResultSet() == resultSet && lce.getPersister() == persister ) {
|
||||||
if ( matches == null ) {
|
if ( matches == null ) {
|
||||||
matches = new ArrayList();
|
matches = new ArrayList<LoadingCollectionEntry>();
|
||||||
}
|
}
|
||||||
matches.add( lce );
|
matches.add( lce );
|
||||||
if ( lce.getCollection().getOwner() == null ) {
|
if ( lce.getCollection().getOwner() == null ) {
|
||||||
|
@ -201,7 +202,7 @@ public class CollectionLoadContext {
|
||||||
|
|
||||||
// todo : i'd much rather have this done from #endLoadingCollection(CollectionPersister,LoadingCollectionEntry)...
|
// todo : i'd much rather have this done from #endLoadingCollection(CollectionPersister,LoadingCollectionEntry)...
|
||||||
loadContexts.unregisterLoadingCollectionXRef( collectionKey );
|
loadContexts.unregisterLoadingCollectionXRef( collectionKey );
|
||||||
iter.remove();
|
itr.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,29 +218,35 @@ public class CollectionLoadContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void endLoadingCollections(CollectionPersister persister, List matchedCollectionEntries) {
|
private void endLoadingCollections(CollectionPersister persister, List<LoadingCollectionEntry> matchedCollectionEntries) {
|
||||||
final boolean debugEnabled = LOG.isDebugEnabled();
|
final boolean debugEnabled = LOG.isDebugEnabled();
|
||||||
if ( matchedCollectionEntries == null ) {
|
if ( matchedCollectionEntries == null ) {
|
||||||
if ( debugEnabled ) LOG.debugf( "No collections were found in result set for role: %s", persister.getRole() );
|
if ( debugEnabled ) {
|
||||||
|
LOG.debugf( "No collections were found in result set for role: %s", persister.getRole() );
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int count = matchedCollectionEntries.size();
|
final int count = matchedCollectionEntries.size();
|
||||||
if ( debugEnabled ) LOG.debugf("%s collections were found in result set for role: %s", count, persister.getRole());
|
if ( debugEnabled ) {
|
||||||
|
LOG.debugf( "%s collections were found in result set for role: %s", count, persister.getRole() );
|
||||||
for ( int i = 0; i < count; i++ ) {
|
|
||||||
LoadingCollectionEntry lce = ( LoadingCollectionEntry ) matchedCollectionEntries.get( i );
|
|
||||||
endLoadingCollection( lce, persister );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( debugEnabled ) LOG.debugf( "%s collections initialized for role: %s", count, persister.getRole() );
|
for ( LoadingCollectionEntry matchedCollectionEntry : matchedCollectionEntries ) {
|
||||||
|
endLoadingCollection( matchedCollectionEntry, persister );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( debugEnabled ) {
|
||||||
|
LOG.debugf( "%s collections initialized for role: %s", count, persister.getRole() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void endLoadingCollection(LoadingCollectionEntry lce, CollectionPersister persister) {
|
private void endLoadingCollection(LoadingCollectionEntry lce, CollectionPersister persister) {
|
||||||
LOG.tracev( "Ending loading collection [{0}]", lce );
|
LOG.tracev( "Ending loading collection [{0}]", lce );
|
||||||
final SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
|
final SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
|
||||||
|
|
||||||
boolean hasNoQueuedAdds = lce.getCollection().endRead(); // warning: can cause a recursive calls! (proxy initialization)
|
// warning: can cause a recursive calls! (proxy initialization)
|
||||||
|
final boolean hasNoQueuedAdds = lce.getCollection().endRead();
|
||||||
|
|
||||||
if ( persister.getCollectionType().hasHolder() ) {
|
if ( persister.getCollectionType().hasHolder() ) {
|
||||||
getLoadContext().getPersistenceContext().addCollectionHolder( lce.getCollection() );
|
getLoadContext().getPersistenceContext().addCollectionHolder( lce.getCollection() );
|
||||||
|
@ -257,11 +264,14 @@ public class CollectionLoadContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// add to cache if:
|
||||||
boolean addToCache = hasNoQueuedAdds && // there were no queued additions
|
boolean addToCache =
|
||||||
persister.hasCache() && // and the role has a cache
|
// there were no queued additions
|
||||||
session.getCacheMode().isPutEnabled() &&
|
hasNoQueuedAdds
|
||||||
!ce.isDoremove(); // and this is not a forced initialization during flush
|
// and the role has a cache
|
||||||
|
&& persister.hasCache()
|
||||||
|
// and this is not a forced initialization during flush
|
||||||
|
&& session.getCacheMode().isPutEnabled() && !ce.isDoremove();
|
||||||
if ( addToCache ) {
|
if ( addToCache ) {
|
||||||
addCollectionToCache( lce, persister );
|
addCollectionToCache( lce, persister );
|
||||||
}
|
}
|
||||||
|
@ -269,11 +279,11 @@ public class CollectionLoadContext {
|
||||||
if ( LOG.isDebugEnabled() ) {
|
if ( LOG.isDebugEnabled() ) {
|
||||||
LOG.debugf(
|
LOG.debugf(
|
||||||
"Collection fully initialized: %s",
|
"Collection fully initialized: %s",
|
||||||
MessageHelper.collectionInfoString(persister, lce.getCollection(), lce.getKey(), session)
|
MessageHelper.collectionInfoString( persister, lce.getCollection(), lce.getKey(), session )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
|
if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
|
||||||
session.getFactory().getStatisticsImplementor().loadCollection(persister.getRole());
|
session.getFactory().getStatisticsImplementor().loadCollection( persister.getRole() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +312,8 @@ public class CollectionLoadContext {
|
||||||
// currently this works in conjuction with the check on
|
// currently this works in conjuction with the check on
|
||||||
// DefaultInitializeCollectionEventHandler.initializeCollectionFromCache() (which makes sure to not read from
|
// DefaultInitializeCollectionEventHandler.initializeCollectionFromCache() (which makes sure to not read from
|
||||||
// cache with enabled filters).
|
// cache with enabled filters).
|
||||||
return; // EARLY EXIT!!!!!
|
// EARLY EXIT!!!!!
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Object version;
|
final Object version;
|
||||||
|
@ -315,7 +326,7 @@ public class CollectionLoadContext {
|
||||||
// about its owner, that owner should be the same instance as associated with the PC, but we do the
|
// about its owner, that owner should be the same instance as associated with the PC, but we do the
|
||||||
// resolution against the PC anyway just to be safe since the lookup should not be costly.
|
// resolution against the PC anyway just to be safe since the lookup should not be costly.
|
||||||
if ( lce.getCollection() != null ) {
|
if ( lce.getCollection() != null ) {
|
||||||
Object linkedOwner = lce.getCollection().getOwner();
|
final Object linkedOwner = lce.getCollection().getOwner();
|
||||||
if ( linkedOwner != null ) {
|
if ( linkedOwner != null ) {
|
||||||
final Serializable ownerKey = persister.getOwnerEntityPersister().getIdentifier( linkedOwner, session );
|
final Serializable ownerKey = persister.getOwnerEntityPersister().getIdentifier( linkedOwner, session );
|
||||||
collectionOwner = getLoadContext().getPersistenceContext().getCollectionOwner( ownerKey, persister );
|
collectionOwner = getLoadContext().getPersistenceContext().getCollectionOwner( ownerKey, persister );
|
||||||
|
@ -335,11 +346,11 @@ public class CollectionLoadContext {
|
||||||
version = null;
|
version = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionCacheEntry entry = new CollectionCacheEntry( lce.getCollection(), persister );
|
final CollectionCacheEntry entry = new CollectionCacheEntry( lce.getCollection(), persister );
|
||||||
CacheKey cacheKey = session.generateCacheKey( lce.getKey(), persister.getKeyType(), persister.getRole() );
|
final CacheKey cacheKey = session.generateCacheKey( lce.getKey(), persister.getKeyType(), persister.getRole() );
|
||||||
boolean put = persister.getCacheAccessStrategy().putFromLoad(
|
final boolean put = persister.getCacheAccessStrategy().putFromLoad(
|
||||||
cacheKey,
|
cacheKey,
|
||||||
persister.getCacheEntryStructure().structure(entry),
|
persister.getCacheEntryStructure().structure( entry ),
|
||||||
session.getTimestamp(),
|
session.getTimestamp(),
|
||||||
version,
|
version,
|
||||||
factory.getSettings().isMinimalPutsEnabled() && session.getCacheMode()!= CacheMode.REFRESH
|
factory.getSettings().isMinimalPutsEnabled() && session.getCacheMode()!= CacheMode.REFRESH
|
||||||
|
@ -360,7 +371,7 @@ public class CollectionLoadContext {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return super.toString() + "<rs=" + resultSet + ">";
|
return super.toString() + "<rs=" + resultSet + ">";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,8 @@ public class EntityLoadContext {
|
||||||
|
|
||||||
private final LoadContexts loadContexts;
|
private final LoadContexts loadContexts;
|
||||||
private final ResultSet resultSet;
|
private final ResultSet resultSet;
|
||||||
private final List hydratingEntities = new ArrayList( 20 ); // todo : need map? the prob is a proper key, right?
|
// todo : need map? the prob is a proper key, right?
|
||||||
|
private final List hydratingEntities = new ArrayList( 20 );
|
||||||
|
|
||||||
public EntityLoadContext(LoadContexts loadContexts, ResultSet resultSet) {
|
public EntityLoadContext(LoadContexts loadContexts, ResultSet resultSet) {
|
||||||
this.loadContexts = loadContexts;
|
this.loadContexts = loadContexts;
|
||||||
|
|
|
@ -30,24 +30,18 @@ import java.util.IdentityHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
|
|
||||||
import org.hibernate.collection.spi.PersistentCollection;
|
import org.hibernate.collection.spi.PersistentCollection;
|
||||||
import org.hibernate.engine.spi.CollectionKey;
|
import org.hibernate.engine.spi.CollectionKey;
|
||||||
import org.hibernate.engine.spi.PersistenceContext;
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.internal.CoreLogging;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.util.collections.IdentityMap;
|
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.pretty.MessageHelper;
|
import org.hibernate.pretty.MessageHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps {@link ResultSet result-sets} to specific contextual data related to processing that result set
|
* Maps {@link ResultSet result-sets} to specific contextual data related to processing that result set
|
||||||
* <p/>
|
* <p/>
|
||||||
* Implementation note: internally an {@link IdentityMap} is used to maintain the mappings mainly because I'd
|
|
||||||
* rather not be dependent upon potentially bad {@link Object#equals} and {@link Object#hashCode} implementations on
|
|
||||||
* the JDBC result sets
|
|
||||||
* <p/>
|
|
||||||
* Considering the JDBC-redesign work, would further like this contextual info not mapped separately, but available
|
* Considering the JDBC-redesign work, would further like this contextual info not mapped separately, but available
|
||||||
* based on the result set being processed. This would also allow maintaining a single mapping as we could reliably
|
* based on the result set being processed. This would also allow maintaining a single mapping as we could reliably
|
||||||
* get notification of the result-set closing...
|
* get notification of the result-set closing...
|
||||||
|
@ -55,8 +49,7 @@ import org.hibernate.pretty.MessageHelper;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class LoadContexts {
|
public class LoadContexts {
|
||||||
|
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( LoadContexts.class );
|
||||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, LoadContexts.class.getName());
|
|
||||||
|
|
||||||
private final PersistenceContext persistenceContext;
|
private final PersistenceContext persistenceContext;
|
||||||
private Map<ResultSet,CollectionLoadContext> collectionLoadContexts;
|
private Map<ResultSet,CollectionLoadContext> collectionLoadContexts;
|
||||||
|
@ -101,11 +94,11 @@ public class LoadContexts {
|
||||||
*/
|
*/
|
||||||
public void cleanup(ResultSet resultSet) {
|
public void cleanup(ResultSet resultSet) {
|
||||||
if ( collectionLoadContexts != null ) {
|
if ( collectionLoadContexts != null ) {
|
||||||
CollectionLoadContext collectionLoadContext = collectionLoadContexts.remove( resultSet );
|
final CollectionLoadContext collectionLoadContext = collectionLoadContexts.remove( resultSet );
|
||||||
collectionLoadContext.cleanup();
|
collectionLoadContext.cleanup();
|
||||||
}
|
}
|
||||||
if ( entityLoadContexts != null ) {
|
if ( entityLoadContexts != null ) {
|
||||||
EntityLoadContext entityLoadContext = entityLoadContexts.remove( resultSet );
|
final EntityLoadContext entityLoadContext = entityLoadContexts.remove( resultSet );
|
||||||
entityLoadContext.cleanup();
|
entityLoadContext.cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +184,7 @@ public class LoadContexts {
|
||||||
* @return The loading collection, or null if not found.
|
* @return The loading collection, or null if not found.
|
||||||
*/
|
*/
|
||||||
public PersistentCollection locateLoadingCollection(CollectionPersister persister, Serializable ownerKey) {
|
public PersistentCollection locateLoadingCollection(CollectionPersister persister, Serializable ownerKey) {
|
||||||
LoadingCollectionEntry lce = locateLoadingCollectionEntry( new CollectionKey( persister, ownerKey ) );
|
final LoadingCollectionEntry lce = locateLoadingCollectionEntry( new CollectionKey( persister, ownerKey ) );
|
||||||
if ( lce != null ) {
|
if ( lce != null ) {
|
||||||
if ( LOG.isTraceEnabled() ) {
|
if ( LOG.isTraceEnabled() ) {
|
||||||
LOG.tracef(
|
LOG.tracef(
|
||||||
|
@ -246,13 +239,13 @@ public class LoadContexts {
|
||||||
if ( !hasRegisteredLoadingCollectionEntries() ) {
|
if ( !hasRegisteredLoadingCollectionEntries() ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
xrefLoadingCollectionEntries.remove(key);
|
xrefLoadingCollectionEntries.remove( key );
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings( {"UnusedDeclaration"})
|
@SuppressWarnings( {"UnusedDeclaration"})
|
||||||
Map getLoadingCollectionXRefs() {
|
Map getLoadingCollectionXRefs() {
|
||||||
return xrefLoadingCollectionEntries;
|
return xrefLoadingCollectionEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -271,7 +264,7 @@ public class LoadContexts {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
LOG.tracev( "Attempting to locate loading collection entry [{0}] in any result-set context", key );
|
LOG.tracev( "Attempting to locate loading collection entry [{0}] in any result-set context", key );
|
||||||
LoadingCollectionEntry rtn = xrefLoadingCollectionEntries.get( key );
|
final LoadingCollectionEntry rtn = xrefLoadingCollectionEntries.get( key );
|
||||||
if ( rtn == null ) {
|
if ( rtn == null ) {
|
||||||
LOG.tracev( "Collection [{0}] not located in load context", key );
|
LOG.tracev( "Collection [{0}] not located in load context", key );
|
||||||
}
|
}
|
||||||
|
@ -291,6 +284,13 @@ public class LoadContexts {
|
||||||
// Entity load contexts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// Entity load contexts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// * currently, not yet used...
|
// * currently, not yet used...
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently unused
|
||||||
|
*
|
||||||
|
* @param resultSet The result set
|
||||||
|
*
|
||||||
|
* @return The entity load context
|
||||||
|
*/
|
||||||
@SuppressWarnings( {"UnusedDeclaration"})
|
@SuppressWarnings( {"UnusedDeclaration"})
|
||||||
public EntityLoadContext getEntityLoadContext(ResultSet resultSet) {
|
public EntityLoadContext getEntityLoadContext(ResultSet resultSet) {
|
||||||
EntityLoadContext context = null;
|
EntityLoadContext context = null;
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class LoadingCollectionEntry {
|
||||||
private final Serializable key;
|
private final Serializable key;
|
||||||
private final PersistentCollection collection;
|
private final PersistentCollection collection;
|
||||||
|
|
||||||
public LoadingCollectionEntry(
|
LoadingCollectionEntry(
|
||||||
ResultSet resultSet,
|
ResultSet resultSet,
|
||||||
CollectionPersister persister,
|
CollectionPersister persister,
|
||||||
Serializable key,
|
Serializable key,
|
||||||
|
@ -68,6 +68,7 @@ public class LoadingCollectionEntry {
|
||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getClass().getName() + "<rs=" + resultSet + ", coll=" + MessageHelper.collectionInfoString( persister.getRole(), key ) + ">@" + Integer.toHexString( hashCode() );
|
return getClass().getName() + "<rs=" + resultSet + ", coll=" + MessageHelper.collectionInfoString( persister.getRole(), key ) + ">@" + Integer.toHexString( hashCode() );
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal classes used to track loading of data, potentially across multiple ResultSets
|
||||||
|
*/
|
||||||
|
package org.hibernate.engine.loading.internal;
|
|
@ -34,6 +34,12 @@ public class Association {
|
||||||
private final String associationPath;
|
private final String associationPath;
|
||||||
private final String role;
|
private final String role;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a association defining what is to be fetched.
|
||||||
|
*
|
||||||
|
* @param owner The entity owning the association
|
||||||
|
* @param associationPath The path of the association, from the entity
|
||||||
|
*/
|
||||||
public Association(EntityPersister owner, String associationPath) {
|
public Association(EntityPersister owner, String associationPath) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.associationPath = associationPath;
|
this.associationPath = associationPath;
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.engine.profile;
|
package org.hibernate.engine.profile;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Models an individual fetch within a profile.
|
* Models an individual fetch within a profile.
|
||||||
*
|
*
|
||||||
|
@ -33,6 +32,12 @@ public class Fetch {
|
||||||
private final Association association;
|
private final Association association;
|
||||||
private final Style style;
|
private final Style style;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a Fetch
|
||||||
|
*
|
||||||
|
* @param association The association to be fetched
|
||||||
|
* @param style How to fetch it
|
||||||
|
*/
|
||||||
public Fetch(Association association, Style style) {
|
public Fetch(Association association, Style style) {
|
||||||
this.association = association;
|
this.association = association;
|
||||||
this.style = style;
|
this.style = style;
|
||||||
|
@ -54,7 +59,13 @@ public class Fetch {
|
||||||
* needed for other things as well anyway).
|
* needed for other things as well anyway).
|
||||||
*/
|
*/
|
||||||
public enum Style {
|
public enum Style {
|
||||||
|
/**
|
||||||
|
* Fetch via a join
|
||||||
|
*/
|
||||||
JOIN( "join" ),
|
JOIN( "join" ),
|
||||||
|
/**
|
||||||
|
* Fetch via a subsequent select
|
||||||
|
*/
|
||||||
SELECT( "select" );
|
SELECT( "select" );
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
@ -63,10 +74,18 @@ public class Fetch {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a style given an externalized string representation
|
||||||
|
*
|
||||||
|
* @param name The externalized representation
|
||||||
|
*
|
||||||
|
* @return The style; {@link #JOIN} is returned if not recognized
|
||||||
|
*/
|
||||||
public static Style parse(String name) {
|
public static Style parse(String name) {
|
||||||
if ( SELECT.name.equals( name ) ) {
|
if ( SELECT.name.equals( name ) ) {
|
||||||
return SELECT;
|
return SELECT;
|
||||||
|
@ -78,6 +97,7 @@ public class Fetch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Fetch[" + style + "{" + association.getRole() + "}]";
|
return "Fetch[" + style + "{" + association.getRole() + "}]";
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,11 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.engine.profile;
|
package org.hibernate.engine.profile;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.hibernate.internal.CoreLogging;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.type.BagType;
|
import org.hibernate.type.BagType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
@ -41,21 +40,17 @@ import org.hibernate.type.Type;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class FetchProfile {
|
public class FetchProfile {
|
||||||
|
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( FetchProfile.class );
|
||||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, FetchProfile.class.getName());
|
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private Map<String,Fetch> fetches = new HashMap<String,Fetch>();
|
private Map<String,Fetch> fetches = new HashMap<String,Fetch>();
|
||||||
|
|
||||||
private boolean containsJoinFetchedCollection = false;
|
private boolean containsJoinFetchedCollection;
|
||||||
private boolean containsJoinFetchedBag = false;
|
private boolean containsJoinFetchedBag;
|
||||||
private Fetch bagJoinFetch;
|
private Fetch bagJoinFetch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A 'fetch profile' is uniquely named within a
|
* Constructs a FetchProfile, supplying its unique name (unique within the SessionFactory).
|
||||||
* {@link SessionFactoryImplementor SessionFactory}, thus it is also
|
|
||||||
* uniquely and easily identifiable within that
|
|
||||||
* {@link SessionFactoryImplementor SessionFactory}.
|
|
||||||
*
|
*
|
||||||
* @param name The name under which we are bound in the sessionFactory
|
* @param name The name under which we are bound in the sessionFactory
|
||||||
*/
|
*/
|
||||||
|
@ -91,7 +86,7 @@ public class FetchProfile {
|
||||||
*/
|
*/
|
||||||
public void addFetch(final Fetch fetch) {
|
public void addFetch(final Fetch fetch) {
|
||||||
final String fetchAssociactionRole = fetch.getAssociation().getRole();
|
final String fetchAssociactionRole = fetch.getAssociation().getRole();
|
||||||
Type associationType = fetch.getAssociation().getOwner().getPropertyType( fetch.getAssociation().getAssociationPath() );
|
final Type associationType = fetch.getAssociation().getOwner().getPropertyType( fetch.getAssociation().getAssociationPath() );
|
||||||
if ( associationType.isCollectionType() ) {
|
if ( associationType.isCollectionType() ) {
|
||||||
LOG.tracev( "Handling request to add collection fetch [{0}]", fetchAssociactionRole );
|
LOG.tracev( "Handling request to add collection fetch [{0}]", fetchAssociactionRole );
|
||||||
|
|
||||||
|
@ -103,7 +98,8 @@ public class FetchProfile {
|
||||||
if ( BagType.class.isInstance( associationType ) ) {
|
if ( BagType.class.isInstance( associationType ) ) {
|
||||||
if ( containsJoinFetchedCollection ) {
|
if ( containsJoinFetchedCollection ) {
|
||||||
LOG.containsJoinFetchedCollection( fetchAssociactionRole );
|
LOG.containsJoinFetchedCollection( fetchAssociactionRole );
|
||||||
return; // EARLY EXIT!!!
|
// EARLY EXIT!!!
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +140,13 @@ public class FetchProfile {
|
||||||
return fetches;
|
return fetches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the fetch associated with the given role.
|
||||||
|
*
|
||||||
|
* @param role The role identifying the fetch
|
||||||
|
*
|
||||||
|
* @return The fetch, or {@code null} if a matching one was not found
|
||||||
|
*/
|
||||||
public Fetch getFetchByRole(String role) {
|
public Fetch getFetchByRole(String role) {
|
||||||
return fetches.get( role );
|
return fetches.get( role );
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Models the fetch profiles defined by the application
|
||||||
|
*/
|
||||||
|
package org.hibernate.engine.profile;
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,9 +20,9 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.engine.query.spi;
|
package org.hibernate.engine.query.spi;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -38,12 +38,21 @@ public class FilterQueryPlan extends HQLQueryPlan implements Serializable {
|
||||||
|
|
||||||
private final String collectionRole;
|
private final String collectionRole;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a query plan for an HQL filter
|
||||||
|
*
|
||||||
|
* @param hql The HQL fragment
|
||||||
|
* @param collectionRole The collection role being filtered
|
||||||
|
* @param shallow Is the query shallow?
|
||||||
|
* @param enabledFilters All enabled filters from the Session
|
||||||
|
* @param factory The factory
|
||||||
|
*/
|
||||||
public FilterQueryPlan(
|
public FilterQueryPlan(
|
||||||
String hql,
|
String hql,
|
||||||
String collectionRole,
|
String collectionRole,
|
||||||
boolean shallow,
|
boolean shallow,
|
||||||
Map enabledFilters,
|
Map enabledFilters,
|
||||||
SessionFactoryImplementor factory) {
|
SessionFactoryImplementor factory) {
|
||||||
super( hql, collectionRole, shallow, enabledFilters, factory );
|
super( hql, collectionRole, shallow, enabledFilters, factory );
|
||||||
this.collectionRole = collectionRole;
|
this.collectionRole = collectionRole;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.hibernate.Filter;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.ScrollableResults;
|
import org.hibernate.ScrollableResults;
|
||||||
|
@ -47,6 +46,7 @@ import org.hibernate.hql.spi.FilterTranslator;
|
||||||
import org.hibernate.hql.spi.ParameterTranslations;
|
import org.hibernate.hql.spi.ParameterTranslations;
|
||||||
import org.hibernate.hql.spi.QueryTranslator;
|
import org.hibernate.hql.spi.QueryTranslator;
|
||||||
import org.hibernate.hql.spi.QueryTranslatorFactory;
|
import org.hibernate.hql.spi.QueryTranslatorFactory;
|
||||||
|
import org.hibernate.internal.CoreLogging;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
import org.hibernate.internal.util.collections.EmptyIterator;
|
import org.hibernate.internal.util.collections.EmptyIterator;
|
||||||
|
@ -60,11 +60,10 @@ import org.hibernate.type.Type;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class HQLQueryPlan implements Serializable {
|
public class HQLQueryPlan implements Serializable {
|
||||||
|
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( HQLQueryPlan.class );
|
||||||
|
|
||||||
// TODO : keep separate notions of QT[] here for shallow/non-shallow queries...
|
// TODO : keep separate notions of QT[] here for shallow/non-shallow queries...
|
||||||
|
|
||||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, HQLQueryPlan.class.getName());
|
|
||||||
|
|
||||||
private final String sourceQuery;
|
private final String sourceQuery;
|
||||||
private final QueryTranslator[] translators;
|
private final QueryTranslator[] translators;
|
||||||
private final String[] sqlStrings;
|
private final String[] sqlStrings;
|
||||||
|
@ -73,17 +72,32 @@ public class HQLQueryPlan implements Serializable {
|
||||||
private final ReturnMetadata returnMetadata;
|
private final ReturnMetadata returnMetadata;
|
||||||
private final Set querySpaces;
|
private final Set querySpaces;
|
||||||
|
|
||||||
private final Set enabledFilterNames;
|
private final Set<String> enabledFilterNames;
|
||||||
private final boolean shallow;
|
private final boolean shallow;
|
||||||
|
|
||||||
public HQLQueryPlan(String hql, boolean shallow, Map enabledFilters, SessionFactoryImplementor factory) {
|
/**
|
||||||
|
* Constructs a HQLQueryPlan
|
||||||
|
*
|
||||||
|
* @param hql The HQL query
|
||||||
|
* @param shallow Whether the execution is to be shallow or not
|
||||||
|
* @param enabledFilters The enabled filters (we only keep the names)
|
||||||
|
* @param factory The factory
|
||||||
|
*/
|
||||||
|
public HQLQueryPlan(String hql, boolean shallow, Map<String,Filter> enabledFilters, SessionFactoryImplementor factory) {
|
||||||
this( hql, null, shallow, enabledFilters, factory );
|
this( hql, null, shallow, enabledFilters, factory );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HQLQueryPlan(String hql, String collectionRole, boolean shallow, Map enabledFilters, SessionFactoryImplementor factory){
|
@SuppressWarnings("unchecked")
|
||||||
|
protected HQLQueryPlan(
|
||||||
|
String hql,
|
||||||
|
String collectionRole,
|
||||||
|
boolean shallow,
|
||||||
|
Map<String,Filter> enabledFilters,
|
||||||
|
SessionFactoryImplementor factory) {
|
||||||
this.sourceQuery = hql;
|
this.sourceQuery = hql;
|
||||||
this.shallow = shallow;
|
this.shallow = shallow;
|
||||||
Set copy = new HashSet();
|
|
||||||
|
final Set<String> copy = new HashSet<String>();
|
||||||
copy.addAll( enabledFilters.keySet() );
|
copy.addAll( enabledFilters.keySet() );
|
||||||
this.enabledFilterNames = java.util.Collections.unmodifiableSet( copy );
|
this.enabledFilterNames = java.util.Collections.unmodifiableSet( copy );
|
||||||
|
|
||||||
|
@ -91,8 +105,8 @@ public class HQLQueryPlan implements Serializable {
|
||||||
final int length = concreteQueryStrings.length;
|
final int length = concreteQueryStrings.length;
|
||||||
this.translators = new QueryTranslator[length];
|
this.translators = new QueryTranslator[length];
|
||||||
|
|
||||||
List<String> sqlStringList = new ArrayList<String>();
|
final List<String> sqlStringList = new ArrayList<String>();
|
||||||
Set combinedQuerySpaces = new HashSet();
|
final Set combinedQuerySpaces = new HashSet();
|
||||||
|
|
||||||
final boolean hasCollectionRole = (collectionRole == null);
|
final boolean hasCollectionRole = (collectionRole == null);
|
||||||
final Map querySubstitutions = factory.getSettings().getQuerySubstitutions();
|
final Map querySubstitutions = factory.getSettings().getQuerySubstitutions();
|
||||||
|
@ -107,7 +121,7 @@ public class HQLQueryPlan implements Serializable {
|
||||||
else {
|
else {
|
||||||
translators[i] = queryTranslatorFactory
|
translators[i] = queryTranslatorFactory
|
||||||
.createFilterTranslator( hql, concreteQueryStrings[i], enabledFilters, factory );
|
.createFilterTranslator( hql, concreteQueryStrings[i], enabledFilters, factory );
|
||||||
( ( FilterTranslator ) translators[i] ).compile( collectionRole, querySubstitutions, shallow );
|
( (FilterTranslator) translators[i] ).compile( collectionRole, querySubstitutions, shallow );
|
||||||
}
|
}
|
||||||
combinedQuerySpaces.addAll( translators[i].getQuerySpaces() );
|
combinedQuerySpaces.addAll( translators[i].getQuerySpaces() );
|
||||||
sqlStringList.addAll( translators[i].collectSqlStrings() );
|
sqlStringList.addAll( translators[i].collectSqlStrings() );
|
||||||
|
@ -165,20 +179,33 @@ public class HQLQueryPlan implements Serializable {
|
||||||
return shallow;
|
return shallow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coordinates the efforts to perform a list across all the included query translators.
|
||||||
|
*
|
||||||
|
* @param queryParameters The query parameters
|
||||||
|
* @param session The session
|
||||||
|
*
|
||||||
|
* @return The query result list
|
||||||
|
*
|
||||||
|
* @throws HibernateException Indicates a problem performing the query
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public List performList(
|
public List performList(
|
||||||
QueryParameters queryParameters,
|
QueryParameters queryParameters,
|
||||||
SessionImplementor session) throws HibernateException {
|
SessionImplementor session) throws HibernateException {
|
||||||
if ( LOG.isTraceEnabled() ) {
|
if ( LOG.isTraceEnabled() ) {
|
||||||
LOG.tracev( "Find: {0}", getSourceQuery() );
|
LOG.tracev( "Find: {0}", getSourceQuery() );
|
||||||
queryParameters.traceParameters( session.getFactory() );
|
queryParameters.traceParameters( session.getFactory() );
|
||||||
}
|
}
|
||||||
boolean hasLimit = queryParameters.getRowSelection() != null &&
|
|
||||||
queryParameters.getRowSelection().definesLimits();
|
final boolean hasLimit = queryParameters.getRowSelection() != null
|
||||||
boolean needsLimit = hasLimit && translators.length > 1;
|
&& queryParameters.getRowSelection().definesLimits();
|
||||||
QueryParameters queryParametersToUse;
|
final boolean needsLimit = hasLimit && translators.length > 1;
|
||||||
|
|
||||||
|
final QueryParameters queryParametersToUse;
|
||||||
if ( needsLimit ) {
|
if ( needsLimit ) {
|
||||||
LOG.needsLimit();
|
LOG.needsLimit();
|
||||||
RowSelection selection = new RowSelection();
|
final RowSelection selection = new RowSelection();
|
||||||
selection.setFetchSize( queryParameters.getRowSelection().getFetchSize() );
|
selection.setFetchSize( queryParameters.getRowSelection().getFetchSize() );
|
||||||
selection.setTimeout( queryParameters.getRowSelection().getTimeout() );
|
selection.setTimeout( queryParameters.getRowSelection().getTimeout() );
|
||||||
queryParametersToUse = queryParameters.createCopyUsing( selection );
|
queryParametersToUse = queryParameters.createCopyUsing( selection );
|
||||||
|
@ -187,12 +214,12 @@ public class HQLQueryPlan implements Serializable {
|
||||||
queryParametersToUse = queryParameters;
|
queryParametersToUse = queryParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
List combinedResults = new ArrayList();
|
final List combinedResults = new ArrayList();
|
||||||
IdentitySet distinction = new IdentitySet();
|
final IdentitySet distinction = new IdentitySet();
|
||||||
int includedCount = -1;
|
int includedCount = -1;
|
||||||
translator_loop:
|
translator_loop:
|
||||||
for ( QueryTranslator translator : translators ) {
|
for ( QueryTranslator translator : translators ) {
|
||||||
List tmp = translator.list( session, queryParametersToUse );
|
final List tmp = translator.list( session, queryParametersToUse );
|
||||||
if ( needsLimit ) {
|
if ( needsLimit ) {
|
||||||
// NOTE : firstRow is zero-based
|
// NOTE : firstRow is zero-based
|
||||||
final int first = queryParameters.getRowSelection().getFirstRow() == null
|
final int first = queryParameters.getRowSelection().getFirstRow() == null
|
||||||
|
@ -223,9 +250,20 @@ public class HQLQueryPlan implements Serializable {
|
||||||
return combinedResults;
|
return combinedResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coordinates the efforts to perform an iterate across all the included query translators.
|
||||||
|
*
|
||||||
|
* @param queryParameters The query parameters
|
||||||
|
* @param session The session
|
||||||
|
*
|
||||||
|
* @return The query result iterator
|
||||||
|
*
|
||||||
|
* @throws HibernateException Indicates a problem performing the query
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public Iterator performIterate(
|
public Iterator performIterate(
|
||||||
QueryParameters queryParameters,
|
QueryParameters queryParameters,
|
||||||
EventSource session) throws HibernateException {
|
EventSource session) throws HibernateException {
|
||||||
if ( LOG.isTraceEnabled() ) {
|
if ( LOG.isTraceEnabled() ) {
|
||||||
LOG.tracev( "Iterate: {0}", getSourceQuery() );
|
LOG.tracev( "Iterate: {0}", getSourceQuery() );
|
||||||
queryParameters.traceParameters( session.getFactory() );
|
queryParameters.traceParameters( session.getFactory() );
|
||||||
|
@ -234,8 +272,8 @@ public class HQLQueryPlan implements Serializable {
|
||||||
return EmptyIterator.INSTANCE;
|
return EmptyIterator.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final boolean many = translators.length > 1;
|
||||||
Iterator[] results = null;
|
Iterator[] results = null;
|
||||||
boolean many = translators.length > 1;
|
|
||||||
if ( many ) {
|
if ( many ) {
|
||||||
results = new Iterator[translators.length];
|
results = new Iterator[translators.length];
|
||||||
}
|
}
|
||||||
|
@ -248,12 +286,22 @@ public class HQLQueryPlan implements Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return many ? new JoinedIterator(results) : result;
|
return many ? new JoinedIterator( results ) : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coordinates the efforts to perform a scroll across all the included query translators.
|
||||||
|
*
|
||||||
|
* @param queryParameters The query parameters
|
||||||
|
* @param session The session
|
||||||
|
*
|
||||||
|
* @return The query result iterator
|
||||||
|
*
|
||||||
|
* @throws HibernateException Indicates a problem performing the query
|
||||||
|
*/
|
||||||
public ScrollableResults performScroll(
|
public ScrollableResults performScroll(
|
||||||
QueryParameters queryParameters,
|
QueryParameters queryParameters,
|
||||||
SessionImplementor session) throws HibernateException {
|
SessionImplementor session) throws HibernateException {
|
||||||
if ( LOG.isTraceEnabled() ) {
|
if ( LOG.isTraceEnabled() ) {
|
||||||
LOG.tracev( "Iterate: {0}", getSourceQuery() );
|
LOG.tracev( "Iterate: {0}", getSourceQuery() );
|
||||||
queryParameters.traceParameters( session.getFactory() );
|
queryParameters.traceParameters( session.getFactory() );
|
||||||
|
@ -268,6 +316,16 @@ public class HQLQueryPlan implements Serializable {
|
||||||
return translators[0].scroll( queryParameters, session );
|
return translators[0].scroll( queryParameters, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coordinates the efforts to perform an execution across all the included query translators.
|
||||||
|
*
|
||||||
|
* @param queryParameters The query parameters
|
||||||
|
* @param session The session
|
||||||
|
*
|
||||||
|
* @return The aggregated "affected row" count
|
||||||
|
*
|
||||||
|
* @throws HibernateException Indicates a problem performing the execution
|
||||||
|
*/
|
||||||
public int performExecuteUpdate(QueryParameters queryParameters, SessionImplementor session)
|
public int performExecuteUpdate(QueryParameters queryParameters, SessionImplementor session)
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
if ( LOG.isTraceEnabled() ) {
|
if ( LOG.isTraceEnabled() ) {
|
||||||
|
@ -285,32 +343,34 @@ public class HQLQueryPlan implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ParameterMetadata buildParameterMetadata(ParameterTranslations parameterTranslations, String hql) {
|
private ParameterMetadata buildParameterMetadata(ParameterTranslations parameterTranslations, String hql) {
|
||||||
long start = System.currentTimeMillis();
|
final long start = System.currentTimeMillis();
|
||||||
ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( hql );
|
final ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( hql );
|
||||||
long end = System.currentTimeMillis();
|
final long end = System.currentTimeMillis();
|
||||||
|
|
||||||
if ( LOG.isTraceEnabled() ) {
|
if ( LOG.isTraceEnabled() ) {
|
||||||
LOG.tracev( "HQL param location recognition took {0} mills ({1})", ( end - start ), hql );
|
LOG.tracev( "HQL param location recognition took {0} mills ({1})", ( end - start ), hql );
|
||||||
}
|
}
|
||||||
|
|
||||||
int ordinalParamCount = parameterTranslations.getOrdinalParameterCount();
|
int ordinalParamCount = parameterTranslations.getOrdinalParameterCount();
|
||||||
int[] locations = ArrayHelper.toIntArray( recognizer.getOrdinalParameterLocationList() );
|
final int[] locations = ArrayHelper.toIntArray( recognizer.getOrdinalParameterLocationList() );
|
||||||
if ( parameterTranslations.supportsOrdinalParameterMetadata() && locations.length != ordinalParamCount ) {
|
if ( parameterTranslations.supportsOrdinalParameterMetadata() && locations.length != ordinalParamCount ) {
|
||||||
throw new HibernateException( "ordinal parameter mismatch" );
|
throw new HibernateException( "ordinal parameter mismatch" );
|
||||||
}
|
}
|
||||||
ordinalParamCount = locations.length;
|
ordinalParamCount = locations.length;
|
||||||
OrdinalParameterDescriptor[] ordinalParamDescriptors = new OrdinalParameterDescriptor[ordinalParamCount];
|
|
||||||
|
final OrdinalParameterDescriptor[] ordinalParamDescriptors = new OrdinalParameterDescriptor[ordinalParamCount];
|
||||||
for ( int i = 1; i <= ordinalParamCount; i++ ) {
|
for ( int i = 1; i <= ordinalParamCount; i++ ) {
|
||||||
ordinalParamDescriptors[ i - 1 ] = new OrdinalParameterDescriptor(
|
ordinalParamDescriptors[ i - 1 ] = new OrdinalParameterDescriptor(
|
||||||
i,
|
i,
|
||||||
parameterTranslations.supportsOrdinalParameterMetadata()
|
parameterTranslations.supportsOrdinalParameterMetadata()
|
||||||
? parameterTranslations.getOrdinalParameterExpectedType( i )
|
? parameterTranslations.getOrdinalParameterExpectedType( i )
|
||||||
: null,
|
: null,
|
||||||
locations[ i - 1 ]
|
locations[ i - 1 ]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, NamedParameterDescriptor> namedParamDescriptorMap = new HashMap<String, NamedParameterDescriptor>();
|
final Map<String, NamedParameterDescriptor> namedParamDescriptorMap = new HashMap<String, NamedParameterDescriptor>();
|
||||||
Map<String, ParamLocationRecognizer.NamedParameterDescription> map = recognizer.getNamedParameterDescriptionMap();
|
final Map<String, ParamLocationRecognizer.NamedParameterDescription> map = recognizer.getNamedParameterDescriptionMap();
|
||||||
for ( final String name : map.keySet() ) {
|
for ( final String name : map.keySet() ) {
|
||||||
final ParamLocationRecognizer.NamedParameterDescription description = map.get( name );
|
final ParamLocationRecognizer.NamedParameterDescription description = map.get( name );
|
||||||
namedParamDescriptorMap.put(
|
namedParamDescriptorMap.put(
|
||||||
|
@ -325,9 +385,15 @@ public class HQLQueryPlan implements Serializable {
|
||||||
}
|
}
|
||||||
return new ParameterMetadata( ordinalParamDescriptors, namedParamDescriptorMap );
|
return new ParameterMetadata( ordinalParamDescriptors, namedParamDescriptorMap );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access to the underlying translators associated with this query
|
||||||
|
*
|
||||||
|
* @return The translators
|
||||||
|
*/
|
||||||
public QueryTranslator[] getTranslators() {
|
public QueryTranslator[] getTranslators() {
|
||||||
QueryTranslator[] copy = new QueryTranslator[translators.length];
|
final QueryTranslator[] copy = new QueryTranslator[translators.length];
|
||||||
System.arraycopy(translators, 0, copy, 0, copy.length);
|
System.arraycopy( translators, 0, copy, 0, copy.length );
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,9 +20,9 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.engine.query.spi;
|
package org.hibernate.engine.query.spi;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
@ -38,6 +38,14 @@ public class NamedParameterDescriptor implements Serializable {
|
||||||
private final int[] sourceLocations;
|
private final int[] sourceLocations;
|
||||||
private final boolean jpaStyle;
|
private final boolean jpaStyle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a NamedParameterDescriptor
|
||||||
|
*
|
||||||
|
* @param name The name of the parameter
|
||||||
|
* @param expectedType The expected type of the parameter, according to the translator
|
||||||
|
* @param sourceLocations The locations of the named parameters (aye aye aye)
|
||||||
|
* @param jpaStyle Was the parameter a JPA style "named parameter"?
|
||||||
|
*/
|
||||||
public NamedParameterDescriptor(String name, Type expectedType, int[] sourceLocations, boolean jpaStyle) {
|
public NamedParameterDescriptor(String name, Type expectedType, int[] sourceLocations, boolean jpaStyle) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.expectedType = expectedType;
|
this.expectedType = expectedType;
|
||||||
|
@ -61,6 +69,11 @@ public class NamedParameterDescriptor implements Serializable {
|
||||||
return jpaStyle;
|
return jpaStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the parameters expected type
|
||||||
|
*
|
||||||
|
* @param type The new expected type
|
||||||
|
*/
|
||||||
public void resetExpectedType(Type type) {
|
public void resetExpectedType(Type type) {
|
||||||
this.expectedType = type;
|
this.expectedType = type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,6 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.action.internal.BulkOperationCleanupAction;
|
import org.hibernate.action.internal.BulkOperationCleanupAction;
|
||||||
|
@ -41,6 +39,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.engine.spi.TypedValue;
|
import org.hibernate.engine.spi.TypedValue;
|
||||||
import org.hibernate.event.spi.EventSource;
|
import org.hibernate.event.spi.EventSource;
|
||||||
|
import org.hibernate.internal.CoreLogging;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
import org.hibernate.loader.custom.sql.SQLCustomQuery;
|
import org.hibernate.loader.custom.sql.SQLCustomQuery;
|
||||||
|
@ -52,10 +51,7 @@ import org.hibernate.type.Type;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class NativeSQLQueryPlan implements Serializable {
|
public class NativeSQLQueryPlan implements Serializable {
|
||||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( NativeSQLQueryPlan.class );
|
||||||
CoreMessageLogger.class,
|
|
||||||
NativeSQLQueryPlan.class.getName()
|
|
||||||
);
|
|
||||||
|
|
||||||
private final String sourceQuery;
|
private final String sourceQuery;
|
||||||
private final SQLCustomQuery customQuery;
|
private final SQLCustomQuery customQuery;
|
||||||
|
@ -87,7 +83,7 @@ public class NativeSQLQueryPlan implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private int[] getNamedParameterLocs(String name) throws QueryException {
|
private int[] getNamedParameterLocs(String name) throws QueryException {
|
||||||
Object loc = customQuery.getNamedParameterBindPoints().get( name );
|
final Object loc = customQuery.getNamedParameterBindPoints().get( name );
|
||||||
if ( loc == null ) {
|
if ( loc == null ) {
|
||||||
throw new QueryException(
|
throw new QueryException(
|
||||||
"Named parameter does not appear in Query: " + name,
|
"Named parameter does not appear in Query: " + name,
|
||||||
|
@ -154,60 +150,73 @@ public class NativeSQLQueryPlan implements Serializable {
|
||||||
final SessionImplementor session) throws SQLException {
|
final SessionImplementor session) throws SQLException {
|
||||||
if ( namedParams != null ) {
|
if ( namedParams != null ) {
|
||||||
// assumes that types are all of span 1
|
// assumes that types are all of span 1
|
||||||
Iterator iter = namedParams.entrySet().iterator();
|
final Iterator iter = namedParams.entrySet().iterator();
|
||||||
int result = 0;
|
int result = 0;
|
||||||
while ( iter.hasNext() ) {
|
while ( iter.hasNext() ) {
|
||||||
Map.Entry e = (Map.Entry) iter.next();
|
final Map.Entry e = (Map.Entry) iter.next();
|
||||||
String name = (String) e.getKey();
|
final String name = (String) e.getKey();
|
||||||
TypedValue typedval = (TypedValue) e.getValue();
|
final TypedValue typedval = (TypedValue) e.getValue();
|
||||||
int[] locs = getNamedParameterLocs( name );
|
final int[] locs = getNamedParameterLocs( name );
|
||||||
for (int i = 0; i < locs.length; i++) {
|
for ( int loc : locs ) {
|
||||||
LOG.debugf("bindNamedParameters() %s -> %s [%s]", typedval.getValue(), name, locs[i] + start);
|
LOG.debugf( "bindNamedParameters() %s -> %s [%s]", typedval.getValue(), name, loc + start );
|
||||||
typedval.getType().nullSafeSet( ps, typedval.getValue(),
|
typedval.getType().nullSafeSet(
|
||||||
locs[i] + start, session );
|
ps,
|
||||||
|
typedval.getValue(),
|
||||||
|
loc + start,
|
||||||
|
session
|
||||||
|
);
|
||||||
}
|
}
|
||||||
result += locs.length;
|
result += locs.length;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void coordinateSharedCacheCleanup(SessionImplementor session) {
|
protected void coordinateSharedCacheCleanup(SessionImplementor session) {
|
||||||
BulkOperationCleanupAction action = new BulkOperationCleanupAction( session, getCustomQuery().getQuerySpaces() );
|
final BulkOperationCleanupAction action = new BulkOperationCleanupAction( session, getCustomQuery().getQuerySpaces() );
|
||||||
|
|
||||||
if ( session.isEventSource() ) {
|
if ( session.isEventSource() ) {
|
||||||
( ( EventSource ) session ).getActionQueue().addAction( action );
|
( (EventSource) session ).getActionQueue().addAction( action );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
action.getAfterTransactionCompletionProcess().doAfterTransactionCompletion( true, session );
|
action.getAfterTransactionCompletionProcess().doAfterTransactionCompletion( true, session );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int performExecuteUpdate(QueryParameters queryParameters,
|
/**
|
||||||
|
* 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,
|
||||||
SessionImplementor session) throws HibernateException {
|
SessionImplementor session) throws HibernateException {
|
||||||
|
|
||||||
coordinateSharedCacheCleanup( session );
|
coordinateSharedCacheCleanup( session );
|
||||||
|
|
||||||
if(queryParameters.isCallable()) {
|
if ( queryParameters.isCallable() ) {
|
||||||
throw new IllegalArgumentException("callable not yet supported for native queries");
|
throw new IllegalArgumentException("callable not yet supported for native queries");
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
PreparedStatement ps;
|
PreparedStatement ps;
|
||||||
try {
|
try {
|
||||||
queryParameters.processFilters( this.customQuery.getSQL(),
|
queryParameters.processFilters( this.customQuery.getSQL(), session );
|
||||||
session );
|
final String sql = queryParameters.getFilteredSQL();
|
||||||
String sql = queryParameters.getFilteredSQL();
|
|
||||||
|
|
||||||
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
|
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int col = 1;
|
int col = 1;
|
||||||
col += bindPositionalParameters( ps, queryParameters, col,
|
col += bindPositionalParameters( ps, queryParameters, col, session );
|
||||||
session );
|
col += bindNamedParameters( ps, queryParameters.getNamedParameters(), col, session );
|
||||||
col += bindNamedParameters( ps, queryParameters
|
|
||||||
.getNamedParameters(), col, session );
|
|
||||||
result = session.getTransactionCoordinator().getJdbcCoordinator().getResultSetReturn().executeUpdate( ps );
|
result = session.getTransactionCoordinator().getJdbcCoordinator().getResultSetReturn().executeUpdate( ps );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -218,7 +227,10 @@ public class NativeSQLQueryPlan implements Serializable {
|
||||||
}
|
}
|
||||||
catch (SQLException sqle) {
|
catch (SQLException sqle) {
|
||||||
throw session.getFactory().getSQLExceptionHelper().convert(
|
throw session.getFactory().getSQLExceptionHelper().convert(
|
||||||
sqle, "could not execute native bulk manipulation query", this.sourceQuery );
|
sqle,
|
||||||
|
"could not execute native bulk manipulation query",
|
||||||
|
this.sourceQuery
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,14 +20,16 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.engine.query.spi;
|
package org.hibernate.engine.query.spi;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Descriptor regarding an ordinal parameter.
|
||||||
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class OrdinalParameterDescriptor implements Serializable {
|
public class OrdinalParameterDescriptor implements Serializable {
|
||||||
|
@ -35,6 +37,13 @@ public class OrdinalParameterDescriptor implements Serializable {
|
||||||
private final Type expectedType;
|
private final Type expectedType;
|
||||||
private final int sourceLocation;
|
private final int sourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an ordinal parameter descriptor.
|
||||||
|
*
|
||||||
|
* @param ordinalPosition The ordinal position
|
||||||
|
* @param expectedType The expected type of the parameter
|
||||||
|
* @param sourceLocation The location of the parameter
|
||||||
|
*/
|
||||||
public OrdinalParameterDescriptor(int ordinalPosition, Type expectedType, int sourceLocation) {
|
public OrdinalParameterDescriptor(int ordinalPosition, Type expectedType, int sourceLocation) {
|
||||||
this.ordinalPosition = ordinalPosition;
|
this.ordinalPosition = ordinalPosition;
|
||||||
this.expectedType = expectedType;
|
this.expectedType = expectedType;
|
||||||
|
|
|
@ -38,12 +38,14 @@ import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ParamLocationRecognizer implements ParameterParser.Recognizer {
|
public class ParamLocationRecognizer implements ParameterParser.Recognizer {
|
||||||
|
/**
|
||||||
|
* Internal representation of a recognized named parameter
|
||||||
|
*/
|
||||||
public static class NamedParameterDescription {
|
public static class NamedParameterDescription {
|
||||||
private final boolean jpaStyle;
|
private final boolean jpaStyle;
|
||||||
private final List<Integer> positions = new ArrayList<Integer>();
|
private final List<Integer> positions = new ArrayList<Integer>();
|
||||||
|
|
||||||
public NamedParameterDescription(boolean jpaStyle) {
|
NamedParameterDescription(boolean jpaStyle) {
|
||||||
this.jpaStyle = jpaStyle;
|
this.jpaStyle = jpaStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +73,7 @@ public class ParamLocationRecognizer implements ParameterParser.Recognizer {
|
||||||
* @return The generated recognizer, with journaled location info.
|
* @return The generated recognizer, with journaled location info.
|
||||||
*/
|
*/
|
||||||
public static ParamLocationRecognizer parseLocations(String query) {
|
public static ParamLocationRecognizer parseLocations(String query) {
|
||||||
ParamLocationRecognizer recognizer = new ParamLocationRecognizer();
|
final ParamLocationRecognizer recognizer = new ParamLocationRecognizer();
|
||||||
ParameterParser.parse( query, recognizer );
|
ParameterParser.parse( query, recognizer );
|
||||||
return recognizer;
|
return recognizer;
|
||||||
}
|
}
|
||||||
|
@ -88,8 +90,8 @@ public class ParamLocationRecognizer implements ParameterParser.Recognizer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of ordinal parameter locations. The list elements
|
* Returns the list of ordinal parameter locations. The list elements
|
||||||
* are Integers, representing the location for that given ordinal. Thus
|
* are Integers, representing the location for that given ordinal. Thus calling
|
||||||
* {@link #getOrdinalParameterLocationList()}.elementAt(n) represents the
|
* {@code getOrdinalParameterLocationList().elementAt(n)} represents the
|
||||||
* location for the nth parameter.
|
* location for the nth parameter.
|
||||||
*
|
*
|
||||||
* @return The list of ordinal parameter locations.
|
* @return The list of ordinal parameter locations.
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,9 +20,9 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.engine.query.spi;
|
package org.hibernate.engine.query.spi;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -37,33 +37,35 @@ import org.hibernate.type.Type;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ParameterMetadata implements Serializable {
|
public class ParameterMetadata implements Serializable {
|
||||||
|
|
||||||
private static final OrdinalParameterDescriptor[] EMPTY_ORDINALS = new OrdinalParameterDescriptor[0];
|
private static final OrdinalParameterDescriptor[] EMPTY_ORDINALS = new OrdinalParameterDescriptor[0];
|
||||||
|
|
||||||
private final OrdinalParameterDescriptor[] ordinalDescriptors;
|
private final OrdinalParameterDescriptor[] ordinalDescriptors;
|
||||||
private final Map namedDescriptorMap;
|
private final Map<String,NamedParameterDescriptor> namedDescriptorMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a ParameterMetadata container.
|
* Instantiates a ParameterMetadata container.
|
||||||
*
|
*
|
||||||
* @param ordinalDescriptors
|
* @param ordinalDescriptors Descriptors of the ordinal parameters
|
||||||
* @param namedDescriptorMap
|
* @param namedDescriptorMap Descriptors of the named parameters
|
||||||
*/
|
*/
|
||||||
public ParameterMetadata(OrdinalParameterDescriptor[] ordinalDescriptors, Map namedDescriptorMap) {
|
public ParameterMetadata(
|
||||||
|
OrdinalParameterDescriptor[] ordinalDescriptors,
|
||||||
|
Map<String,NamedParameterDescriptor> namedDescriptorMap) {
|
||||||
if ( ordinalDescriptors == null ) {
|
if ( ordinalDescriptors == null ) {
|
||||||
this.ordinalDescriptors = EMPTY_ORDINALS;
|
this.ordinalDescriptors = EMPTY_ORDINALS;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
OrdinalParameterDescriptor[] copy = new OrdinalParameterDescriptor[ ordinalDescriptors.length ];
|
final OrdinalParameterDescriptor[] copy = new OrdinalParameterDescriptor[ ordinalDescriptors.length ];
|
||||||
System.arraycopy( ordinalDescriptors, 0, copy, 0, ordinalDescriptors.length );
|
System.arraycopy( ordinalDescriptors, 0, copy, 0, ordinalDescriptors.length );
|
||||||
this.ordinalDescriptors = copy;
|
this.ordinalDescriptors = copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( namedDescriptorMap == null ) {
|
if ( namedDescriptorMap == null ) {
|
||||||
this.namedDescriptorMap = java.util.Collections.EMPTY_MAP;
|
this.namedDescriptorMap = java.util.Collections.emptyMap();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int size = ( int ) ( ( namedDescriptorMap.size() / .75 ) + 1 );
|
final int size = (int) ( ( namedDescriptorMap.size() / .75 ) + 1 );
|
||||||
Map copy = new HashMap( size );
|
final Map<String,NamedParameterDescriptor> copy = new HashMap<String,NamedParameterDescriptor>( size );
|
||||||
copy.putAll( namedDescriptorMap );
|
copy.putAll( namedDescriptorMap );
|
||||||
this.namedDescriptorMap = java.util.Collections.unmodifiableMap( copy );
|
this.namedDescriptorMap = java.util.Collections.unmodifiableMap( copy );
|
||||||
}
|
}
|
||||||
|
@ -73,39 +75,107 @@ public class ParameterMetadata implements Serializable {
|
||||||
return ordinalDescriptors.length;
|
return ordinalDescriptors.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the descriptor for an ordinal parameter given its position
|
||||||
|
*
|
||||||
|
* @param position The position (1 based)
|
||||||
|
*
|
||||||
|
* @return The ordinal parameter descriptor
|
||||||
|
*
|
||||||
|
* @throws QueryParameterException If the position is out of range
|
||||||
|
*/
|
||||||
public OrdinalParameterDescriptor getOrdinalParameterDescriptor(int position) {
|
public OrdinalParameterDescriptor getOrdinalParameterDescriptor(int position) {
|
||||||
if ( position < 1 || position > ordinalDescriptors.length ) {
|
if ( position < 1 || position > ordinalDescriptors.length ) {
|
||||||
String error = "Position beyond number of declared ordinal parameters. " +
|
throw new QueryParameterException(
|
||||||
"Remember that ordinal parameters are 1-based! Position: " + position;
|
"Position beyond number of declared ordinal parameters. " +
|
||||||
throw new QueryParameterException( error );
|
"Remember that ordinal parameters are 1-based! Position: " + position
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return ordinalDescriptors[position - 1];
|
return ordinalDescriptors[position - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated.
|
||||||
|
*
|
||||||
|
* @param position The position
|
||||||
|
*
|
||||||
|
* @return The type
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link OrdinalParameterDescriptor#getExpectedType()} from the
|
||||||
|
* {@link #getOrdinalParameterDescriptor} return instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public Type getOrdinalParameterExpectedType(int position) {
|
public Type getOrdinalParameterExpectedType(int position) {
|
||||||
return getOrdinalParameterDescriptor( position ).getExpectedType();
|
return getOrdinalParameterDescriptor( position ).getExpectedType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated.
|
||||||
|
*
|
||||||
|
* @param position The position
|
||||||
|
*
|
||||||
|
* @return The source location
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link OrdinalParameterDescriptor#getSourceLocation()} from the
|
||||||
|
* {@link #getOrdinalParameterDescriptor} return instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public int getOrdinalParameterSourceLocation(int position) {
|
public int getOrdinalParameterSourceLocation(int position) {
|
||||||
return getOrdinalParameterDescriptor( position ).getSourceLocation();
|
return getOrdinalParameterDescriptor( position ).getSourceLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access to the names of all named parameters
|
||||||
|
*
|
||||||
|
* @return The named parameter names
|
||||||
|
*/
|
||||||
public Set getNamedParameterNames() {
|
public Set getNamedParameterNames() {
|
||||||
return namedDescriptorMap.keySet();
|
return namedDescriptorMap.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the descriptor for a named parameter given the name
|
||||||
|
*
|
||||||
|
* @param name The name of the parameter to locate
|
||||||
|
*
|
||||||
|
* @return The named parameter descriptor
|
||||||
|
*
|
||||||
|
* @throws QueryParameterException If the name could not be resolved to a named parameter
|
||||||
|
*/
|
||||||
public NamedParameterDescriptor getNamedParameterDescriptor(String name) {
|
public NamedParameterDescriptor getNamedParameterDescriptor(String name) {
|
||||||
NamedParameterDescriptor meta = ( NamedParameterDescriptor ) namedDescriptorMap.get( name );
|
final NamedParameterDescriptor meta = namedDescriptorMap.get( name );
|
||||||
if ( meta == null ) {
|
if ( meta == null ) {
|
||||||
throw new QueryParameterException( "could not locate named parameter [" + name + "]" );
|
throw new QueryParameterException( "could not locate named parameter [" + name + "]" );
|
||||||
}
|
}
|
||||||
return meta;
|
return meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated.
|
||||||
|
*
|
||||||
|
* @param name The name of the parameter
|
||||||
|
*
|
||||||
|
* @return The type
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link NamedParameterDescriptor#getExpectedType()} from the
|
||||||
|
* {@link #getNamedParameterDescriptor} return instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public Type getNamedParameterExpectedType(String name) {
|
public Type getNamedParameterExpectedType(String name) {
|
||||||
return getNamedParameterDescriptor( name ).getExpectedType();
|
return getNamedParameterDescriptor( name ).getExpectedType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated.
|
||||||
|
*
|
||||||
|
* @param name The name of the parameter
|
||||||
|
*
|
||||||
|
* @return The type
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link NamedParameterDescriptor#getSourceLocations()} from the
|
||||||
|
* {@link #getNamedParameterDescriptor} return instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public int[] getNamedParameterSourceLocations(String name) {
|
public int[] getNamedParameterSourceLocations(String name) {
|
||||||
return getNamedParameterDescriptor( name ).getSourceLocations();
|
return getNamedParameterDescriptor( name ).getSourceLocations();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,9 +20,9 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.engine.query.spi;
|
package org.hibernate.engine.query.spi;
|
||||||
|
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.hql.internal.classic.ParserHelper;
|
import org.hibernate.hql.internal.classic.ParserHelper;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
|
@ -36,12 +36,45 @@ import org.hibernate.internal.util.StringHelper;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ParameterParser {
|
public class ParameterParser {
|
||||||
|
/**
|
||||||
|
* Maybe better named a Journaler. Essentially provides a callback contract for things that recognize parameters
|
||||||
|
*/
|
||||||
public static interface Recognizer {
|
public static interface Recognizer {
|
||||||
|
/**
|
||||||
|
* Called when an output parameter is recognized
|
||||||
|
*
|
||||||
|
* @param position The position within the query
|
||||||
|
*/
|
||||||
public void outParameter(int position);
|
public void outParameter(int position);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an ordinal parameter is recognized
|
||||||
|
*
|
||||||
|
* @param position The position within the query
|
||||||
|
*/
|
||||||
public void ordinalParameter(int position);
|
public void ordinalParameter(int position);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a named parameter is recognized
|
||||||
|
*
|
||||||
|
* @param name The recognized parameter name
|
||||||
|
* @param position The position within the query
|
||||||
|
*/
|
||||||
public void namedParameter(String name, int position);
|
public void namedParameter(String name, int position);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a JPA-style named parameter is recognized
|
||||||
|
*
|
||||||
|
* @param name The name of the JPA-style parameter
|
||||||
|
* @param position The position within the query
|
||||||
|
*/
|
||||||
public void jpaPositionalParameter(String name, int position);
|
public void jpaPositionalParameter(String name, int position);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a character that is not a parameter (or part of a parameter dfinition) is recognized.
|
||||||
|
*
|
||||||
|
* @param character The recognized character
|
||||||
|
*/
|
||||||
public void other(char character);
|
public void other(char character);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,13 +97,13 @@ public class ParameterParser {
|
||||||
* @throws QueryException Indicates unexpected parameter conditions.
|
* @throws QueryException Indicates unexpected parameter conditions.
|
||||||
*/
|
*/
|
||||||
public static void parse(String sqlString, Recognizer recognizer) throws QueryException {
|
public static void parse(String sqlString, Recognizer recognizer) throws QueryException {
|
||||||
boolean hasMainOutputParameter = startsWithEscapeCallTemplate( sqlString );
|
final boolean hasMainOutputParameter = startsWithEscapeCallTemplate( sqlString );
|
||||||
boolean foundMainOutputParam = false;
|
boolean foundMainOutputParam = false;
|
||||||
|
|
||||||
int stringLength = sqlString.length();
|
final int stringLength = sqlString.length();
|
||||||
boolean inQuote = false;
|
boolean inQuote = false;
|
||||||
for ( int indx = 0; indx < stringLength; indx++ ) {
|
for ( int indx = 0; indx < stringLength; indx++ ) {
|
||||||
char c = sqlString.charAt( indx );
|
final char c = sqlString.charAt( indx );
|
||||||
if ( inQuote ) {
|
if ( inQuote ) {
|
||||||
if ( '\'' == c ) {
|
if ( '\'' == c ) {
|
||||||
inQuote = false;
|
inQuote = false;
|
||||||
|
@ -88,9 +121,9 @@ public class ParameterParser {
|
||||||
else {
|
else {
|
||||||
if ( c == ':' ) {
|
if ( c == ':' ) {
|
||||||
// named parameter
|
// named parameter
|
||||||
int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS_BITSET, indx + 1 );
|
final int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS_BITSET, indx + 1 );
|
||||||
int chopLocation = right < 0 ? sqlString.length() : right;
|
final int chopLocation = right < 0 ? sqlString.length() : right;
|
||||||
String param = sqlString.substring( indx + 1, chopLocation );
|
final String param = sqlString.substring( indx + 1, chopLocation );
|
||||||
if ( StringHelper.isEmpty( param ) ) {
|
if ( StringHelper.isEmpty( param ) ) {
|
||||||
throw new QueryException(
|
throw new QueryException(
|
||||||
"Space is not allowed after parameter prefix ':' [" + sqlString + "]"
|
"Space is not allowed after parameter prefix ':' [" + sqlString + "]"
|
||||||
|
@ -103,12 +136,12 @@ public class ParameterParser {
|
||||||
// could be either an ordinal or JPA-positional parameter
|
// could be either an ordinal or JPA-positional parameter
|
||||||
if ( indx < stringLength - 1 && Character.isDigit( sqlString.charAt( indx + 1 ) ) ) {
|
if ( indx < stringLength - 1 && Character.isDigit( sqlString.charAt( indx + 1 ) ) ) {
|
||||||
// a peek ahead showed this as an JPA-positional parameter
|
// a peek ahead showed this as an JPA-positional parameter
|
||||||
int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS, indx + 1 );
|
final int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS, indx + 1 );
|
||||||
int chopLocation = right < 0 ? sqlString.length() : right;
|
final int chopLocation = right < 0 ? sqlString.length() : right;
|
||||||
String param = sqlString.substring( indx + 1, chopLocation );
|
final String param = sqlString.substring( indx + 1, chopLocation );
|
||||||
// make sure this "name" is an integral
|
// make sure this "name" is an integral
|
||||||
try {
|
try {
|
||||||
Integer.valueOf( param );
|
Integer.valueOf( param );
|
||||||
}
|
}
|
||||||
catch( NumberFormatException e ) {
|
catch( NumberFormatException e ) {
|
||||||
throw new QueryException( "JPA-style positional param was not an integral ordinal" );
|
throw new QueryException( "JPA-style positional param was not an integral ordinal" );
|
||||||
|
@ -133,12 +166,19 @@ public class ParameterParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposed as public solely for use from tests
|
||||||
|
*
|
||||||
|
* @param sqlString The SQL string to check
|
||||||
|
*
|
||||||
|
* @return true/false
|
||||||
|
*/
|
||||||
public static boolean startsWithEscapeCallTemplate(String sqlString) {
|
public static boolean startsWithEscapeCallTemplate(String sqlString) {
|
||||||
if ( ! ( sqlString.startsWith( "{" ) && sqlString.endsWith( "}" ) ) ) {
|
if ( ! ( sqlString.startsWith( "{" ) && sqlString.endsWith( "}" ) ) ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int chopLocation = sqlString.indexOf( "call" );
|
final int chopLocation = sqlString.indexOf( "call" );
|
||||||
if ( chopLocation <= 0 ) {
|
if ( chopLocation <= 0 ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -147,7 +187,8 @@ public class ParameterParser {
|
||||||
final String fixture = "?=call";
|
final String fixture = "?=call";
|
||||||
int fixturePosition = 0;
|
int fixturePosition = 0;
|
||||||
boolean matches = true;
|
boolean matches = true;
|
||||||
for ( int i = 0, max = checkString.length(); i < max; i++ ) {
|
final int max = checkString.length();
|
||||||
|
for ( int i = 0; i < max; i++ ) {
|
||||||
final char c = Character.toLowerCase( checkString.charAt( i ) );
|
final char c = Character.toLowerCase( checkString.charAt( i ) );
|
||||||
if ( Character.isWhitespace( c ) ) {
|
if ( Character.isWhitespace( c ) ) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
|
||||||
* indicated by the @author tags or express copyright attribution
|
|
||||||
* statements applied by the authors. All third-party contributions are
|
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
|
||||||
*
|
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
|
||||||
* Lesser General Public License, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
|
||||||
* for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this distribution; if not, write to:
|
|
||||||
* Free Software Foundation, Inc.
|
|
||||||
* 51 Franklin Street, Fifth Floor
|
|
||||||
* Boston, MA 02110-1301 USA
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package org.hibernate.engine.query.spi;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.hibernate.type.Type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines metadata regarding a translated HQL or native-SQL query.
|
|
||||||
*
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public class QueryMetadata implements Serializable {
|
|
||||||
private final String sourceQuery;
|
|
||||||
private final ParameterMetadata parameterMetadata;
|
|
||||||
private final String[] returnAliases;
|
|
||||||
private final Type[] returnTypes;
|
|
||||||
private final Set querySpaces;
|
|
||||||
|
|
||||||
public QueryMetadata(
|
|
||||||
String sourceQuery,
|
|
||||||
ParameterMetadata parameterMetadata,
|
|
||||||
String[] returnAliases,
|
|
||||||
Type[] returnTypes,
|
|
||||||
Set querySpaces) {
|
|
||||||
this.sourceQuery = sourceQuery;
|
|
||||||
this.parameterMetadata = parameterMetadata;
|
|
||||||
this.returnAliases = returnAliases;
|
|
||||||
this.returnTypes = returnTypes;
|
|
||||||
this.querySpaces = querySpaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the source HQL or native-SQL query.
|
|
||||||
*
|
|
||||||
* @return The source query.
|
|
||||||
*/
|
|
||||||
public String getSourceQuery() {
|
|
||||||
return sourceQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ParameterMetadata getParameterMetadata() {
|
|
||||||
return parameterMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return source query select clause aliases (if any)
|
|
||||||
*
|
|
||||||
* @return an array of aliases as strings.
|
|
||||||
*/
|
|
||||||
public String[] getReturnAliases() {
|
|
||||||
return returnAliases;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An array of types describing the returns of the source query.
|
|
||||||
*
|
|
||||||
* @return The return type array.
|
|
||||||
*/
|
|
||||||
public Type[] getReturnTypes() {
|
|
||||||
return returnTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The set of query spaces affected by this source query.
|
|
||||||
*
|
|
||||||
* @return The set of query spaces.
|
|
||||||
*/
|
|
||||||
public Set getQuerySpaces() {
|
|
||||||
return querySpaces;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -28,17 +28,16 @@ import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.hibernate.Filter;
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.cfg.Environment;
|
import org.hibernate.cfg.Environment;
|
||||||
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
|
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.internal.CoreLogging;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.FilterImpl;
|
import org.hibernate.internal.FilterImpl;
|
||||||
import org.hibernate.internal.util.collections.BoundedConcurrentHashMap;
|
import org.hibernate.internal.util.collections.BoundedConcurrentHashMap;
|
||||||
|
@ -54,8 +53,7 @@ import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class QueryPlanCache implements Serializable {
|
public class QueryPlanCache implements Serializable {
|
||||||
|
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( QueryPlanCache.class );
|
||||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, QueryPlanCache.class.getName());
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default strong reference count.
|
* The default strong reference count.
|
||||||
|
@ -65,11 +63,14 @@ public class QueryPlanCache implements Serializable {
|
||||||
* The default soft reference count.
|
* The default soft reference count.
|
||||||
*/
|
*/
|
||||||
public static final int DEFAULT_QUERY_PLAN_MAX_COUNT = 2048;
|
public static final int DEFAULT_QUERY_PLAN_MAX_COUNT = 2048;
|
||||||
|
|
||||||
private final SessionFactoryImplementor factory;
|
private final SessionFactoryImplementor factory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the cache of the actual plans...
|
* the cache of the actual plans...
|
||||||
*/
|
*/
|
||||||
private final BoundedConcurrentHashMap queryPlanCache;
|
private final BoundedConcurrentHashMap queryPlanCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* simple cache of param metadata based on query string. Ideally, the original "user-supplied query"
|
* simple cache of param metadata based on query string. Ideally, the original "user-supplied query"
|
||||||
* string should be used to obtain this metadata (i.e., not the para-list-expanded query string) to avoid
|
* string should be used to obtain this metadata (i.e., not the para-list-expanded query string) to avoid
|
||||||
|
@ -80,6 +81,12 @@ public class QueryPlanCache implements Serializable {
|
||||||
*/
|
*/
|
||||||
private final BoundedConcurrentHashMap<String,ParameterMetadata> parameterMetadataCache;
|
private final BoundedConcurrentHashMap<String,ParameterMetadata> parameterMetadataCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the QueryPlanCache to be used by the given SessionFactory
|
||||||
|
*
|
||||||
|
* @param factory The SessionFactory
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public QueryPlanCache(final SessionFactoryImplementor factory) {
|
public QueryPlanCache(final SessionFactoryImplementor factory) {
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
|
|
||||||
|
@ -135,15 +142,17 @@ public class QueryPlanCache implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ParameterMetadata buildParameterMetadata(String query){
|
private ParameterMetadata buildParameterMetadata(String query){
|
||||||
ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( query );
|
final ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( query );
|
||||||
|
|
||||||
final int size = recognizer.getOrdinalParameterLocationList().size();
|
final int size = recognizer.getOrdinalParameterLocationList().size();
|
||||||
OrdinalParameterDescriptor[] ordinalDescriptors = new OrdinalParameterDescriptor[ size ];
|
final OrdinalParameterDescriptor[] ordinalDescriptors = new OrdinalParameterDescriptor[ size ];
|
||||||
for ( int i = 0; i < size; i++ ) {
|
for ( int i = 0; i < size; i++ ) {
|
||||||
final Integer position = recognizer.getOrdinalParameterLocationList().get( i );
|
final Integer position = recognizer.getOrdinalParameterLocationList().get( i );
|
||||||
ordinalDescriptors[i] = new OrdinalParameterDescriptor( i, null, position );
|
ordinalDescriptors[i] = new OrdinalParameterDescriptor( i, null, position );
|
||||||
}
|
}
|
||||||
Map<String, NamedParameterDescriptor> namedParamDescriptorMap = new HashMap<String, NamedParameterDescriptor>();
|
|
||||||
Map<String, ParamLocationRecognizer.NamedParameterDescription> map = recognizer.getNamedParameterDescriptionMap();
|
final Map<String, NamedParameterDescriptor> namedParamDescriptorMap = new HashMap<String, NamedParameterDescriptor>();
|
||||||
|
final Map<String, ParamLocationRecognizer.NamedParameterDescription> map = recognizer.getNamedParameterDescriptionMap();
|
||||||
for ( final String name : map.keySet() ) {
|
for ( final String name : map.keySet() ) {
|
||||||
final ParamLocationRecognizer.NamedParameterDescription description = map.get( name );
|
final ParamLocationRecognizer.NamedParameterDescription description = map.get( name );
|
||||||
namedParamDescriptorMap.put(
|
namedParamDescriptorMap.put(
|
||||||
|
@ -159,9 +168,22 @@ public class QueryPlanCache implements Serializable {
|
||||||
return new ParameterMetadata( ordinalDescriptors, namedParamDescriptorMap );
|
return new ParameterMetadata( ordinalDescriptors, namedParamDescriptorMap );
|
||||||
}
|
}
|
||||||
|
|
||||||
public HQLQueryPlan getHQLQueryPlan( String queryString, boolean shallow, Map enabledFilters)
|
/**
|
||||||
|
* Get the query plan for the given HQL query, creating it and caching it if not already cached
|
||||||
|
*
|
||||||
|
* @param queryString The HQL query string
|
||||||
|
* @param shallow Whether the execution will be shallow
|
||||||
|
* @param enabledFilters The filters enabled on the Session
|
||||||
|
*
|
||||||
|
* @return The query plan
|
||||||
|
*
|
||||||
|
* @throws QueryException Indicates a problem translating the query
|
||||||
|
* @throws MappingException Indicates a problem translating the query
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public HQLQueryPlan getHQLQueryPlan(String queryString, boolean shallow, Map<String,Filter> enabledFilters)
|
||||||
throws QueryException, MappingException {
|
throws QueryException, MappingException {
|
||||||
HQLQueryPlanKey key = new HQLQueryPlanKey( queryString, shallow, enabledFilters );
|
final HQLQueryPlanKey key = new HQLQueryPlanKey( queryString, shallow, enabledFilters );
|
||||||
HQLQueryPlan value = (HQLQueryPlan) queryPlanCache.get( key );
|
HQLQueryPlan value = (HQLQueryPlan) queryPlanCache.get( key );
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
LOG.tracev( "Unable to locate HQL query plan in cache; generating ({0})", queryString );
|
LOG.tracev( "Unable to locate HQL query plan in cache; generating ({0})", queryString );
|
||||||
|
@ -173,37 +195,69 @@ public class QueryPlanCache implements Serializable {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the query plan for the given collection HQL filter fragment, creating it and caching it if not already cached
|
||||||
public FilterQueryPlan getFilterQueryPlan(String filterString, String collectionRole, boolean shallow, Map enabledFilters)
|
*
|
||||||
throws QueryException, MappingException {
|
* @param filterString The HQL filter fragment
|
||||||
FilterQueryPlanKey key = new FilterQueryPlanKey( filterString, collectionRole, shallow, enabledFilters );
|
* @param collectionRole The collection being filtered
|
||||||
|
* @param shallow Whether the execution will be shallow
|
||||||
|
* @param enabledFilters The filters enabled on the Session
|
||||||
|
*
|
||||||
|
* @return The query plan
|
||||||
|
*
|
||||||
|
* @throws QueryException Indicates a problem translating the query
|
||||||
|
* @throws MappingException Indicates a problem translating the query
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public FilterQueryPlan getFilterQueryPlan(
|
||||||
|
String filterString,
|
||||||
|
String collectionRole,
|
||||||
|
boolean shallow,
|
||||||
|
Map<String,Filter> enabledFilters) throws QueryException, MappingException {
|
||||||
|
final FilterQueryPlanKey key = new FilterQueryPlanKey( filterString, collectionRole, shallow, enabledFilters );
|
||||||
FilterQueryPlan value = (FilterQueryPlan) queryPlanCache.get( key );
|
FilterQueryPlan value = (FilterQueryPlan) queryPlanCache.get( key );
|
||||||
if(value == null){
|
if ( value == null ) {
|
||||||
LOG.tracev( "Unable to locate collection-filter query plan in cache; generating ({0} : {1} )",
|
LOG.tracev(
|
||||||
collectionRole, filterString );
|
"Unable to locate collection-filter query plan in cache; generating ({0} : {1} )",
|
||||||
|
collectionRole,
|
||||||
|
filterString
|
||||||
|
);
|
||||||
value = new FilterQueryPlan( filterString, collectionRole, shallow, enabledFilters,factory );
|
value = new FilterQueryPlan( filterString, collectionRole, shallow, enabledFilters,factory );
|
||||||
queryPlanCache.putIfAbsent( key, value );
|
queryPlanCache.putIfAbsent( key, value );
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
LOG.tracev( "Located collection-filter query plan in cache ({0} : {1})", collectionRole, filterString );
|
LOG.tracev( "Located collection-filter query plan in cache ({0} : {1})", collectionRole, filterString );
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the query plan for a native SQL query, creating it and caching it if not already cached
|
||||||
|
*
|
||||||
|
* @param spec The native SQL query specification
|
||||||
|
*
|
||||||
|
* @return The query plan
|
||||||
|
*
|
||||||
|
* @throws QueryException Indicates a problem translating the query
|
||||||
|
* @throws MappingException Indicates a problem translating the query
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public NativeSQLQueryPlan getNativeSQLQueryPlan(final NativeSQLQuerySpecification spec) {
|
public NativeSQLQueryPlan getNativeSQLQueryPlan(final NativeSQLQuerySpecification spec) {
|
||||||
NativeSQLQueryPlan value = (NativeSQLQueryPlan) queryPlanCache.get( spec );
|
NativeSQLQueryPlan value = (NativeSQLQueryPlan) queryPlanCache.get( spec );
|
||||||
if(value == null){
|
if ( value == null ) {
|
||||||
LOG.tracev( "Unable to locate native-sql query plan in cache; generating ({0})", spec.getQueryString() );
|
LOG.tracev( "Unable to locate native-sql query plan in cache; generating ({0})", spec.getQueryString() );
|
||||||
value = new NativeSQLQueryPlan( spec, factory);
|
value = new NativeSQLQueryPlan( spec, factory);
|
||||||
queryPlanCache.putIfAbsent( spec, value );
|
queryPlanCache.putIfAbsent( spec, value );
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
LOG.tracev( "Located native-sql query plan in cache ({0})", spec.getQueryString() );
|
LOG.tracev( "Located native-sql query plan in cache ({0})", spec.getQueryString() );
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
//clean up QueryPlanCache when Sessionfactory is closed
|
* clean up QueryPlanCache when SessionFactory is closed
|
||||||
|
*/
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
LOG.trace( "Cleaning QueryPlan Cache" );
|
LOG.trace( "Cleaning QueryPlan Cache" );
|
||||||
queryPlanCache.clear();
|
queryPlanCache.clear();
|
||||||
|
@ -223,7 +277,7 @@ public class QueryPlanCache implements Serializable {
|
||||||
filterKeys = Collections.emptySet();
|
filterKeys = Collections.emptySet();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Set<DynamicFilterKey> tmp = new HashSet<DynamicFilterKey>(
|
final Set<DynamicFilterKey> tmp = new HashSet<DynamicFilterKey>(
|
||||||
CollectionHelper.determineProperSizing( enabledFilters ),
|
CollectionHelper.determineProperSizing( enabledFilters ),
|
||||||
CollectionHelper.LOAD_FACTOR
|
CollectionHelper.LOAD_FACTOR
|
||||||
);
|
);
|
||||||
|
@ -248,7 +302,7 @@ public class QueryPlanCache implements Serializable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final HQLQueryPlanKey that = ( HQLQueryPlanKey ) o;
|
final HQLQueryPlanKey that = (HQLQueryPlanKey) o;
|
||||||
|
|
||||||
return shallow == that.shallow
|
return shallow == that.shallow
|
||||||
&& filterKeys.equals( that.filterKeys )
|
&& filterKeys.equals( that.filterKeys )
|
||||||
|
@ -306,8 +360,7 @@ public class QueryPlanCache implements Serializable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicFilterKey that = ( DynamicFilterKey ) o;
|
final DynamicFilterKey that = (DynamicFilterKey) o;
|
||||||
|
|
||||||
return filterName.equals( that.filterName )
|
return filterName.equals( that.filterName )
|
||||||
&& parameterMetadata.equals( that.parameterMetadata );
|
&& parameterMetadata.equals( that.parameterMetadata );
|
||||||
|
|
||||||
|
@ -336,7 +389,7 @@ public class QueryPlanCache implements Serializable {
|
||||||
this.filterNames = Collections.emptySet();
|
this.filterNames = Collections.emptySet();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Set<String> tmp = new HashSet<String>();
|
final Set<String> tmp = new HashSet<String>();
|
||||||
tmp.addAll( enabledFilters.keySet() );
|
tmp.addAll( enabledFilters.keySet() );
|
||||||
this.filterNames = Collections.unmodifiableSet( tmp );
|
this.filterNames = Collections.unmodifiableSet( tmp );
|
||||||
|
|
||||||
|
@ -358,8 +411,7 @@ public class QueryPlanCache implements Serializable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final FilterQueryPlanKey that = ( FilterQueryPlanKey ) o;
|
final FilterQueryPlanKey that = (FilterQueryPlanKey) o;
|
||||||
|
|
||||||
return shallow == that.shallow
|
return shallow == that.shallow
|
||||||
&& filterNames.equals( that.filterNames )
|
&& filterNames.equals( that.filterNames )
|
||||||
&& query.equals( that.query )
|
&& query.equals( that.query )
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,21 +20,23 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.engine.query.spi;
|
package org.hibernate.engine.query.spi;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Metadata about the query return(s).
|
||||||
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ReturnMetadata implements Serializable {
|
public class ReturnMetadata implements Serializable {
|
||||||
private final String[] returnAliases;
|
private final String[] returnAliases;
|
||||||
private final Type[] returnTypes;
|
private final Type[] returnTypes;
|
||||||
|
|
||||||
public ReturnMetadata(String[] returnAliases, Type[] returnTypes) {
|
ReturnMetadata(String[] returnAliases, Type[] returnTypes) {
|
||||||
this.returnAliases = returnAliases;
|
this.returnAliases = returnAliases;
|
||||||
this.returnTypes = returnTypes;
|
this.returnTypes = returnTypes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Defines support for query plans and stored metadata about queries
|
||||||
|
*/
|
||||||
|
package org.hibernate.engine.query.spi;
|
Loading…
Reference in New Issue