HHH-8211 - Checkstyle and FindBugs fix-ups

This commit is contained in:
Steve Ebersole 2013-05-21 17:54:14 -05:00
parent f2073113fc
commit 286800ec34
21 changed files with 571 additions and 312 deletions

View File

@ -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 );
} }
@ -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,9 +346,9 @@ 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(),

View File

@ -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;

View File

@ -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(
@ -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;

View File

@ -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() );
} }

View File

@ -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;

View File

@ -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;

View File

@ -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() + "}]";
} }

View File

@ -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 );
} }

View File

@ -0,0 +1,4 @@
/**
* Models the fetch profiles defined by the application
*/
package org.hibernate.engine.profile;

View File

@ -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,6 +38,15 @@ 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,

View File

@ -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();
@ -165,6 +179,17 @@ 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 {
@ -172,13 +197,15 @@ public class HQLQueryPlan implements Serializable {
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,6 +250,17 @@ 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 {
@ -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];
} }
@ -251,6 +289,16 @@ 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 {
@ -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,20 +343,22 @@ 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,
@ -309,8 +369,8 @@ public class HQLQueryPlan implements Serializable {
); );
} }
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,8 +385,14 @@ 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;
} }

View File

@ -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;
} }

View File

@ -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,27 +150,32 @@ 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 );
@ -184,7 +185,18 @@ public class NativeSQLQueryPlan implements Serializable {
} }
} }
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 );
@ -196,18 +208,15 @@ public class NativeSQLQueryPlan implements Serializable {
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;

View File

@ -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;

View File

@ -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.

View File

@ -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();
} }

View File

@ -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,9 +136,9 @@ 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 );
@ -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;

View File

@ -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;
}
}

View File

@ -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
); );
@ -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 );
@ -359,7 +412,6 @@ public class QueryPlanCache implements Serializable {
} }
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 )

View File

@ -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;
} }

View File

@ -0,0 +1,4 @@
/**
* Defines support for query plans and stored metadata about queries
*/
package org.hibernate.engine.query.spi;