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 ResultSet resultSet;
private Set localLoadingCollectionKeys = new HashSet();
private Set<CollectionKey> localLoadingCollectionKeys = new HashSet<CollectionKey>();
/**
* Creates a collection load context for the given result set.
@ -119,12 +119,13 @@ public class CollectionLoadContext {
if ( collection != null ) {
if ( collection.wasInitialized() ) {
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" );
}
else {
Object owner = loadContexts.getPersistenceContext().getCollectionOwner( key, persister );
final Object owner = loadContexts.getPersistenceContext().getCollectionOwner( key, persister );
final boolean newlySavedEntity = owner != null
&& loadContexts.getPersistenceContext().getEntry( owner ).getStatus() != Status.LOADING;
if ( newlySavedEntity ) {
@ -162,7 +163,7 @@ public class CollectionLoadContext {
* @param persister The persister for which to complete loading.
*/
public void endLoadingCollections(CollectionPersister persister) {
SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
final SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
if ( !loadContexts.hasLoadingCollectionEntries()
&& localLoadingCollectionKeys.isEmpty() ) {
return;
@ -174,17 +175,17 @@ public class CollectionLoadContext {
// internal loadingCollections map for matches and store those matches
// in a temp collection. the temp collection is then used to "drive"
// the #endRead processing.
List matches = null;
Iterator iter = localLoadingCollectionKeys.iterator();
while ( iter.hasNext() ) {
final CollectionKey collectionKey = (CollectionKey) iter.next();
List<LoadingCollectionEntry> matches = null;
final Iterator itr = localLoadingCollectionKeys.iterator();
while ( itr.hasNext() ) {
final CollectionKey collectionKey = (CollectionKey) itr.next();
final LoadingCollectionEntry lce = loadContexts.locateLoadingCollectionEntry( collectionKey );
if ( lce == null ) {
LOG.loadingCollectionKeyNotFound( collectionKey );
}
else if ( lce.getResultSet() == resultSet && lce.getPersister() == persister ) {
if ( matches == null ) {
matches = new ArrayList();
matches = new ArrayList<LoadingCollectionEntry>();
}
matches.add( lce );
if ( lce.getCollection().getOwner() == null ) {
@ -201,7 +202,7 @@ public class CollectionLoadContext {
// todo : i'd much rather have this done from #endLoadingCollection(CollectionPersister,LoadingCollectionEntry)...
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();
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;
}
final int count = matchedCollectionEntries.size();
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 were found in result set for role: %s", count, persister.getRole() );
}
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) {
LOG.tracev( "Ending loading collection [{0}]", lce );
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() ) {
getLoadContext().getPersistenceContext().addCollectionHolder( lce.getCollection() );
@ -255,13 +262,16 @@ public class CollectionLoadContext {
// getLoadContext().getPersistenceContext().getBatchFetchQueue().removeBatchLoadableCollection(ce);
// }
}
boolean addToCache = hasNoQueuedAdds && // there were no queued additions
persister.hasCache() && // and the role has a cache
session.getCacheMode().isPutEnabled() &&
!ce.isDoremove(); // and this is not a forced initialization during flush
// add to cache if:
boolean addToCache =
// there were no queued additions
hasNoQueuedAdds
// and the role has a cache
&& persister.hasCache()
// and this is not a forced initialization during flush
&& session.getCacheMode().isPutEnabled() && !ce.isDoremove();
if ( addToCache ) {
addCollectionToCache( lce, persister );
}
@ -269,11 +279,11 @@ public class CollectionLoadContext {
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"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() ) {
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
// DefaultInitializeCollectionEventHandler.initializeCollectionFromCache() (which makes sure to not read from
// cache with enabled filters).
return; // EARLY EXIT!!!!!
// EARLY EXIT!!!!!
return;
}
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
// resolution against the PC anyway just to be safe since the lookup should not be costly.
if ( lce.getCollection() != null ) {
Object linkedOwner = lce.getCollection().getOwner();
final Object linkedOwner = lce.getCollection().getOwner();
if ( linkedOwner != null ) {
final Serializable ownerKey = persister.getOwnerEntityPersister().getIdentifier( linkedOwner, session );
collectionOwner = getLoadContext().getPersistenceContext().getCollectionOwner( ownerKey, persister );
@ -335,11 +346,11 @@ public class CollectionLoadContext {
version = null;
}
CollectionCacheEntry entry = new CollectionCacheEntry( lce.getCollection(), persister );
CacheKey cacheKey = session.generateCacheKey( lce.getKey(), persister.getKeyType(), persister.getRole() );
boolean put = persister.getCacheAccessStrategy().putFromLoad(
final CollectionCacheEntry entry = new CollectionCacheEntry( lce.getCollection(), persister );
final CacheKey cacheKey = session.generateCacheKey( lce.getKey(), persister.getKeyType(), persister.getRole() );
final boolean put = persister.getCacheAccessStrategy().putFromLoad(
cacheKey,
persister.getCacheEntryStructure().structure(entry),
persister.getCacheEntryStructure().structure( entry ),
session.getTimestamp(),
version,
factory.getSettings().isMinimalPutsEnabled() && session.getCacheMode()!= CacheMode.REFRESH
@ -360,7 +371,7 @@ public class CollectionLoadContext {
@Override
public String toString() {
public String toString() {
return super.toString() + "<rs=" + resultSet + ">";
}
}

View File

@ -41,7 +41,8 @@ public class EntityLoadContext {
private final LoadContexts loadContexts;
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) {
this.loadContexts = loadContexts;

View File

@ -30,24 +30,18 @@ import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import org.jboss.logging.Logger;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.IdentityMap;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.pretty.MessageHelper;
/**
* Maps {@link ResultSet result-sets} to specific contextual data related to processing that result set
* <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
* 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...
@ -55,8 +49,7 @@ import org.hibernate.pretty.MessageHelper;
* @author Steve Ebersole
*/
public class LoadContexts {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, LoadContexts.class.getName());
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( LoadContexts.class );
private final PersistenceContext persistenceContext;
private Map<ResultSet,CollectionLoadContext> collectionLoadContexts;
@ -101,11 +94,11 @@ public class LoadContexts {
*/
public void cleanup(ResultSet resultSet) {
if ( collectionLoadContexts != null ) {
CollectionLoadContext collectionLoadContext = collectionLoadContexts.remove( resultSet );
final CollectionLoadContext collectionLoadContext = collectionLoadContexts.remove( resultSet );
collectionLoadContext.cleanup();
}
if ( entityLoadContexts != null ) {
EntityLoadContext entityLoadContext = entityLoadContexts.remove( resultSet );
final EntityLoadContext entityLoadContext = entityLoadContexts.remove( resultSet );
entityLoadContext.cleanup();
}
}
@ -191,7 +184,7 @@ public class LoadContexts {
* @return The loading collection, or null if not found.
*/
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 ( LOG.isTraceEnabled() ) {
LOG.tracef(
@ -246,13 +239,13 @@ public class LoadContexts {
if ( !hasRegisteredLoadingCollectionEntries() ) {
return;
}
xrefLoadingCollectionEntries.remove(key);
}
xrefLoadingCollectionEntries.remove( key );
}
@SuppressWarnings( {"UnusedDeclaration"})
Map getLoadingCollectionXRefs() {
return xrefLoadingCollectionEntries;
}
return xrefLoadingCollectionEntries;
}
/**
@ -271,7 +264,7 @@ public class LoadContexts {
return null;
}
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 ) {
LOG.tracev( "Collection [{0}] not located in load context", key );
}
@ -291,6 +284,13 @@ public class LoadContexts {
// Entity load contexts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// * currently, not yet used...
/**
* Currently unused
*
* @param resultSet The result set
*
* @return The entity load context
*/
@SuppressWarnings( {"UnusedDeclaration"})
public EntityLoadContext getEntityLoadContext(ResultSet resultSet) {
EntityLoadContext context = null;

View File

@ -41,7 +41,7 @@ public class LoadingCollectionEntry {
private final Serializable key;
private final PersistentCollection collection;
public LoadingCollectionEntry(
LoadingCollectionEntry(
ResultSet resultSet,
CollectionPersister persister,
Serializable key,
@ -68,6 +68,7 @@ public class LoadingCollectionEntry {
return collection;
}
@Override
public String toString() {
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 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) {
this.owner = owner;
this.associationPath = associationPath;

View File

@ -23,7 +23,6 @@
*/
package org.hibernate.engine.profile;
/**
* Models an individual fetch within a profile.
*
@ -33,6 +32,12 @@ public class Fetch {
private final Association association;
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) {
this.association = association;
this.style = style;
@ -54,7 +59,13 @@ public class Fetch {
* needed for other things as well anyway).
*/
public enum Style {
/**
* Fetch via a join
*/
JOIN( "join" ),
/**
* Fetch via a subsequent select
*/
SELECT( "select" );
private final String name;
@ -63,10 +74,18 @@ public class Fetch {
this.name = name;
}
@Override
public String toString() {
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) {
if ( SELECT.name.equals( name ) ) {
return SELECT;
@ -78,6 +97,7 @@ public class Fetch {
}
}
@Override
public String toString() {
return "Fetch[" + style + "{" + association.getRole() + "}]";
}

View File

@ -22,12 +22,11 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.profile;
import java.util.HashMap;
import java.util.Map;
import org.jboss.logging.Logger;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.type.BagType;
import org.hibernate.type.Type;
@ -41,21 +40,17 @@ import org.hibernate.type.Type;
* @author Steve Ebersole
*/
public class FetchProfile {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, FetchProfile.class.getName());
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( FetchProfile.class );
private final String name;
private Map<String,Fetch> fetches = new HashMap<String,Fetch>();
private boolean containsJoinFetchedCollection = false;
private boolean containsJoinFetchedBag = false;
private boolean containsJoinFetchedCollection;
private boolean containsJoinFetchedBag;
private Fetch bagJoinFetch;
/**
* A 'fetch profile' is uniquely named within a
* {@link SessionFactoryImplementor SessionFactory}, thus it is also
* uniquely and easily identifiable within that
* {@link SessionFactoryImplementor SessionFactory}.
* Constructs a FetchProfile, supplying its unique name (unique within 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) {
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() ) {
LOG.tracev( "Handling request to add collection fetch [{0}]", fetchAssociactionRole );
@ -103,7 +98,8 @@ public class FetchProfile {
if ( BagType.class.isInstance( associationType ) ) {
if ( containsJoinFetchedCollection ) {
LOG.containsJoinFetchedCollection( fetchAssociactionRole );
return; // EARLY EXIT!!!
// EARLY EXIT!!!
return;
}
}
@ -144,6 +140,13 @@ public class FetchProfile {
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) {
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
*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* 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.Map;
@ -38,12 +38,21 @@ public class FilterQueryPlan extends HQLQueryPlan implements Serializable {
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(
String hql,
String collectionRole,
boolean shallow,
Map enabledFilters,
SessionFactoryImplementor factory) {
String collectionRole,
boolean shallow,
Map enabledFilters,
SessionFactoryImplementor factory) {
super( hql, collectionRole, shallow, enabledFilters, factory );
this.collectionRole = collectionRole;
}

View File

@ -32,8 +32,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.logging.Logger;
import org.hibernate.Filter;
import org.hibernate.HibernateException;
import org.hibernate.QueryException;
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.QueryTranslator;
import org.hibernate.hql.spi.QueryTranslatorFactory;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.EmptyIterator;
@ -60,11 +60,10 @@ import org.hibernate.type.Type;
* @author Steve Ebersole
*/
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...
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, HQLQueryPlan.class.getName());
private final String sourceQuery;
private final QueryTranslator[] translators;
private final String[] sqlStrings;
@ -73,17 +72,32 @@ public class HQLQueryPlan implements Serializable {
private final ReturnMetadata returnMetadata;
private final Set querySpaces;
private final Set enabledFilterNames;
private final Set<String> enabledFilterNames;
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 );
}
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.shallow = shallow;
Set copy = new HashSet();
final Set<String> copy = new HashSet<String>();
copy.addAll( enabledFilters.keySet() );
this.enabledFilterNames = java.util.Collections.unmodifiableSet( copy );
@ -91,8 +105,8 @@ public class HQLQueryPlan implements Serializable {
final int length = concreteQueryStrings.length;
this.translators = new QueryTranslator[length];
List<String> sqlStringList = new ArrayList<String>();
Set combinedQuerySpaces = new HashSet();
final List<String> sqlStringList = new ArrayList<String>();
final Set combinedQuerySpaces = new HashSet();
final boolean hasCollectionRole = (collectionRole == null);
final Map querySubstitutions = factory.getSettings().getQuerySubstitutions();
@ -107,7 +121,7 @@ public class HQLQueryPlan implements Serializable {
else {
translators[i] = queryTranslatorFactory
.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() );
sqlStringList.addAll( translators[i].collectSqlStrings() );
@ -165,20 +179,33 @@ public class HQLQueryPlan implements Serializable {
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(
QueryParameters queryParameters,
SessionImplementor session) throws HibernateException {
SessionImplementor session) throws HibernateException {
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Find: {0}", getSourceQuery() );
queryParameters.traceParameters( session.getFactory() );
}
boolean hasLimit = queryParameters.getRowSelection() != null &&
queryParameters.getRowSelection().definesLimits();
boolean needsLimit = hasLimit && translators.length > 1;
QueryParameters queryParametersToUse;
final boolean hasLimit = queryParameters.getRowSelection() != null
&& queryParameters.getRowSelection().definesLimits();
final boolean needsLimit = hasLimit && translators.length > 1;
final QueryParameters queryParametersToUse;
if ( needsLimit ) {
LOG.needsLimit();
RowSelection selection = new RowSelection();
final RowSelection selection = new RowSelection();
selection.setFetchSize( queryParameters.getRowSelection().getFetchSize() );
selection.setTimeout( queryParameters.getRowSelection().getTimeout() );
queryParametersToUse = queryParameters.createCopyUsing( selection );
@ -187,12 +214,12 @@ public class HQLQueryPlan implements Serializable {
queryParametersToUse = queryParameters;
}
List combinedResults = new ArrayList();
IdentitySet distinction = new IdentitySet();
final List combinedResults = new ArrayList();
final IdentitySet distinction = new IdentitySet();
int includedCount = -1;
translator_loop:
for ( QueryTranslator translator : translators ) {
List tmp = translator.list( session, queryParametersToUse );
final List tmp = translator.list( session, queryParametersToUse );
if ( needsLimit ) {
// NOTE : firstRow is zero-based
final int first = queryParameters.getRowSelection().getFirstRow() == null
@ -223,9 +250,20 @@ public class HQLQueryPlan implements Serializable {
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(
QueryParameters queryParameters,
EventSource session) throws HibernateException {
EventSource session) throws HibernateException {
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Iterate: {0}", getSourceQuery() );
queryParameters.traceParameters( session.getFactory() );
@ -234,8 +272,8 @@ public class HQLQueryPlan implements Serializable {
return EmptyIterator.INSTANCE;
}
final boolean many = translators.length > 1;
Iterator[] results = null;
boolean many = translators.length > 1;
if ( many ) {
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(
QueryParameters queryParameters,
SessionImplementor session) throws HibernateException {
SessionImplementor session) throws HibernateException {
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Iterate: {0}", getSourceQuery() );
queryParameters.traceParameters( session.getFactory() );
@ -268,6 +316,16 @@ public class HQLQueryPlan implements Serializable {
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)
throws HibernateException {
if ( LOG.isTraceEnabled() ) {
@ -285,32 +343,34 @@ public class HQLQueryPlan implements Serializable {
}
private ParameterMetadata buildParameterMetadata(ParameterTranslations parameterTranslations, String hql) {
long start = System.currentTimeMillis();
ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( hql );
long end = System.currentTimeMillis();
final long start = System.currentTimeMillis();
final ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( hql );
final long end = System.currentTimeMillis();
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "HQL param location recognition took {0} mills ({1})", ( end - start ), hql );
}
int ordinalParamCount = parameterTranslations.getOrdinalParameterCount();
int[] locations = ArrayHelper.toIntArray( recognizer.getOrdinalParameterLocationList() );
final int[] locations = ArrayHelper.toIntArray( recognizer.getOrdinalParameterLocationList() );
if ( parameterTranslations.supportsOrdinalParameterMetadata() && locations.length != ordinalParamCount ) {
throw new HibernateException( "ordinal parameter mismatch" );
}
ordinalParamCount = locations.length;
OrdinalParameterDescriptor[] ordinalParamDescriptors = new OrdinalParameterDescriptor[ordinalParamCount];
final OrdinalParameterDescriptor[] ordinalParamDescriptors = new OrdinalParameterDescriptor[ordinalParamCount];
for ( int i = 1; i <= ordinalParamCount; i++ ) {
ordinalParamDescriptors[ i - 1 ] = new OrdinalParameterDescriptor(
i,
parameterTranslations.supportsOrdinalParameterMetadata()
? parameterTranslations.getOrdinalParameterExpectedType( i )
: null,
locations[ i - 1 ]
parameterTranslations.supportsOrdinalParameterMetadata()
? parameterTranslations.getOrdinalParameterExpectedType( i )
: null,
locations[ i - 1 ]
);
}
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() ) {
final ParamLocationRecognizer.NamedParameterDescription description = map.get( name );
namedParamDescriptorMap.put(
@ -325,9 +385,15 @@ public class HQLQueryPlan implements Serializable {
}
return new ParameterMetadata( ordinalParamDescriptors, namedParamDescriptorMap );
}
/**
* Access to the underlying translators associated with this query
*
* @return The translators
*/
public QueryTranslator[] getTranslators() {
QueryTranslator[] copy = new QueryTranslator[translators.length];
System.arraycopy(translators, 0, copy, 0, copy.length);
final QueryTranslator[] copy = new QueryTranslator[translators.length];
System.arraycopy( translators, 0, copy, 0, copy.length );
return copy;
}

View File

@ -1,10 +1,10 @@
/*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* 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 org.hibernate.type.Type;
@ -38,6 +38,14 @@ public class NamedParameterDescriptor implements Serializable {
private final int[] sourceLocations;
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) {
this.name = name;
this.expectedType = expectedType;
@ -61,6 +69,11 @@ public class NamedParameterDescriptor implements Serializable {
return jpaStyle;
}
/**
* Set the parameters expected type
*
* @param type The new expected type
*/
public void resetExpectedType(Type type) {
this.expectedType = type;
}

View File

@ -30,8 +30,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.QueryException;
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.TypedValue;
import org.hibernate.event.spi.EventSource;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.custom.sql.SQLCustomQuery;
@ -52,10 +51,7 @@ import org.hibernate.type.Type;
* @author Steve Ebersole
*/
public class NativeSQLQueryPlan implements Serializable {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
NativeSQLQueryPlan.class.getName()
);
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( NativeSQLQueryPlan.class );
private final String sourceQuery;
private final SQLCustomQuery customQuery;
@ -87,7 +83,7 @@ public class NativeSQLQueryPlan implements Serializable {
}
private int[] getNamedParameterLocs(String name) throws QueryException {
Object loc = customQuery.getNamedParameterBindPoints().get( name );
final Object loc = customQuery.getNamedParameterBindPoints().get( name );
if ( loc == null ) {
throw new QueryException(
"Named parameter does not appear in Query: " + name,
@ -154,60 +150,73 @@ public class NativeSQLQueryPlan implements Serializable {
final SessionImplementor session) throws SQLException {
if ( namedParams != null ) {
// assumes that types are all of span 1
Iterator iter = namedParams.entrySet().iterator();
final Iterator iter = namedParams.entrySet().iterator();
int result = 0;
while ( iter.hasNext() ) {
Map.Entry e = (Map.Entry) iter.next();
String name = (String) e.getKey();
TypedValue typedval = (TypedValue) e.getValue();
int[] locs = getNamedParameterLocs( name );
for (int i = 0; i < locs.length; i++) {
LOG.debugf("bindNamedParameters() %s -> %s [%s]", typedval.getValue(), name, locs[i] + start);
typedval.getType().nullSafeSet( ps, typedval.getValue(),
locs[i] + start, session );
final Map.Entry e = (Map.Entry) iter.next();
final String name = (String) e.getKey();
final TypedValue typedval = (TypedValue) e.getValue();
final int[] locs = getNamedParameterLocs( name );
for ( int loc : locs ) {
LOG.debugf( "bindNamedParameters() %s -> %s [%s]", typedval.getValue(), name, loc + start );
typedval.getType().nullSafeSet(
ps,
typedval.getValue(),
loc + start,
session
);
}
result += locs.length;
}
return result;
}
return 0;
return 0;
}
protected void coordinateSharedCacheCleanup(SessionImplementor session) {
BulkOperationCleanupAction action = new BulkOperationCleanupAction( session, getCustomQuery().getQuerySpaces() );
final BulkOperationCleanupAction action = new BulkOperationCleanupAction( session, getCustomQuery().getQuerySpaces() );
if ( session.isEventSource() ) {
( ( EventSource ) session ).getActionQueue().addAction( action );
( (EventSource) session ).getActionQueue().addAction( action );
}
else {
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 {
coordinateSharedCacheCleanup( session );
if(queryParameters.isCallable()) {
if ( queryParameters.isCallable() ) {
throw new IllegalArgumentException("callable not yet supported for native queries");
}
int result = 0;
PreparedStatement ps;
try {
queryParameters.processFilters( this.customQuery.getSQL(),
session );
String sql = queryParameters.getFilteredSQL();
queryParameters.processFilters( this.customQuery.getSQL(), session );
final String sql = queryParameters.getFilteredSQL();
ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
try {
int col = 1;
col += bindPositionalParameters( ps, queryParameters, col,
session );
col += bindNamedParameters( ps, queryParameters
.getNamedParameters(), col, session );
col += bindPositionalParameters( ps, queryParameters, col, session );
col += bindNamedParameters( ps, queryParameters.getNamedParameters(), col, session );
result = session.getTransactionCoordinator().getJdbcCoordinator().getResultSetReturn().executeUpdate( ps );
}
finally {
@ -218,7 +227,10 @@ public class NativeSQLQueryPlan implements Serializable {
}
catch (SQLException sqle) {
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;

View File

@ -1,10 +1,10 @@
/*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,14 +20,16 @@
* 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 org.hibernate.type.Type;
/**
* Descriptor regarding an ordinal parameter.
*
* @author Steve Ebersole
*/
public class OrdinalParameterDescriptor implements Serializable {
@ -35,6 +37,13 @@ public class OrdinalParameterDescriptor implements Serializable {
private final Type expectedType;
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) {
this.ordinalPosition = ordinalPosition;
this.expectedType = expectedType;

View File

@ -38,12 +38,14 @@ import org.hibernate.internal.util.collections.ArrayHelper;
* @author Steve Ebersole
*/
public class ParamLocationRecognizer implements ParameterParser.Recognizer {
/**
* Internal representation of a recognized named parameter
*/
public static class NamedParameterDescription {
private final boolean jpaStyle;
private final List<Integer> positions = new ArrayList<Integer>();
public NamedParameterDescription(boolean jpaStyle) {
NamedParameterDescription(boolean jpaStyle) {
this.jpaStyle = jpaStyle;
}
@ -71,7 +73,7 @@ public class ParamLocationRecognizer implements ParameterParser.Recognizer {
* @return The generated recognizer, with journaled location info.
*/
public static ParamLocationRecognizer parseLocations(String query) {
ParamLocationRecognizer recognizer = new ParamLocationRecognizer();
final ParamLocationRecognizer recognizer = new ParamLocationRecognizer();
ParameterParser.parse( query, recognizer );
return recognizer;
}
@ -88,8 +90,8 @@ public class ParamLocationRecognizer implements ParameterParser.Recognizer {
/**
* Returns the list of ordinal parameter locations. The list elements
* are Integers, representing the location for that given ordinal. Thus
* {@link #getOrdinalParameterLocationList()}.elementAt(n) represents the
* are Integers, representing the location for that given ordinal. Thus calling
* {@code getOrdinalParameterLocationList().elementAt(n)} represents the
* location for the nth parameter.
*
* @return The list of ordinal parameter locations.

View File

@ -1,10 +1,10 @@
/*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* 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.HashMap;
import java.util.Map;
@ -37,33 +37,35 @@ import org.hibernate.type.Type;
* @author Steve Ebersole
*/
public class ParameterMetadata implements Serializable {
private static final OrdinalParameterDescriptor[] EMPTY_ORDINALS = new OrdinalParameterDescriptor[0];
private final OrdinalParameterDescriptor[] ordinalDescriptors;
private final Map namedDescriptorMap;
private final Map<String,NamedParameterDescriptor> namedDescriptorMap;
/**
* Instantiates a ParameterMetadata container.
*
* @param ordinalDescriptors
* @param namedDescriptorMap
* @param ordinalDescriptors Descriptors of the ordinal parameters
* @param namedDescriptorMap Descriptors of the named parameters
*/
public ParameterMetadata(OrdinalParameterDescriptor[] ordinalDescriptors, Map namedDescriptorMap) {
public ParameterMetadata(
OrdinalParameterDescriptor[] ordinalDescriptors,
Map<String,NamedParameterDescriptor> namedDescriptorMap) {
if ( ordinalDescriptors == null ) {
this.ordinalDescriptors = EMPTY_ORDINALS;
}
else {
OrdinalParameterDescriptor[] copy = new OrdinalParameterDescriptor[ ordinalDescriptors.length ];
final OrdinalParameterDescriptor[] copy = new OrdinalParameterDescriptor[ ordinalDescriptors.length ];
System.arraycopy( ordinalDescriptors, 0, copy, 0, ordinalDescriptors.length );
this.ordinalDescriptors = copy;
}
if ( namedDescriptorMap == null ) {
this.namedDescriptorMap = java.util.Collections.EMPTY_MAP;
this.namedDescriptorMap = java.util.Collections.emptyMap();
}
else {
int size = ( int ) ( ( namedDescriptorMap.size() / .75 ) + 1 );
Map copy = new HashMap( size );
final int size = (int) ( ( namedDescriptorMap.size() / .75 ) + 1 );
final Map<String,NamedParameterDescriptor> copy = new HashMap<String,NamedParameterDescriptor>( size );
copy.putAll( namedDescriptorMap );
this.namedDescriptorMap = java.util.Collections.unmodifiableMap( copy );
}
@ -73,39 +75,107 @@ public class ParameterMetadata implements Serializable {
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) {
if ( position < 1 || position > ordinalDescriptors.length ) {
String error = "Position beyond number of declared ordinal parameters. " +
"Remember that ordinal parameters are 1-based! Position: " + position;
throw new QueryParameterException( error );
throw new QueryParameterException(
"Position beyond number of declared ordinal parameters. " +
"Remember that ordinal parameters are 1-based! Position: " + position
);
}
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) {
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) {
return getOrdinalParameterDescriptor( position ).getSourceLocation();
}
/**
* Access to the names of all named parameters
*
* @return The named parameter names
*/
public Set getNamedParameterNames() {
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) {
NamedParameterDescriptor meta = ( NamedParameterDescriptor ) namedDescriptorMap.get( name );
final NamedParameterDescriptor meta = namedDescriptorMap.get( name );
if ( meta == null ) {
throw new QueryParameterException( "could not locate named parameter [" + name + "]" );
}
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) {
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) {
return getNamedParameterDescriptor( name ).getSourceLocations();
}

View File

@ -1,10 +1,10 @@
/*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.engine.query.spi;
import org.hibernate.QueryException;
import org.hibernate.hql.internal.classic.ParserHelper;
import org.hibernate.internal.util.StringHelper;
@ -36,12 +36,45 @@ import org.hibernate.internal.util.StringHelper;
* @author Steve Ebersole
*/
public class ParameterParser {
/**
* Maybe better named a Journaler. Essentially provides a callback contract for things that recognize parameters
*/
public static interface Recognizer {
/**
* Called when an output parameter is recognized
*
* @param position The position within the query
*/
public void outParameter(int position);
/**
* Called when an ordinal parameter is recognized
*
* @param position The position within the query
*/
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);
/**
* 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);
/**
* 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);
}
@ -64,13 +97,13 @@ public class ParameterParser {
* @throws QueryException Indicates unexpected parameter conditions.
*/
public static void parse(String sqlString, Recognizer recognizer) throws QueryException {
boolean hasMainOutputParameter = startsWithEscapeCallTemplate( sqlString );
final boolean hasMainOutputParameter = startsWithEscapeCallTemplate( sqlString );
boolean foundMainOutputParam = false;
int stringLength = sqlString.length();
final int stringLength = sqlString.length();
boolean inQuote = false;
for ( int indx = 0; indx < stringLength; indx++ ) {
char c = sqlString.charAt( indx );
final char c = sqlString.charAt( indx );
if ( inQuote ) {
if ( '\'' == c ) {
inQuote = false;
@ -88,9 +121,9 @@ public class ParameterParser {
else {
if ( c == ':' ) {
// named parameter
int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS_BITSET, indx + 1 );
int chopLocation = right < 0 ? sqlString.length() : right;
String param = sqlString.substring( indx + 1, chopLocation );
final int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS_BITSET, indx + 1 );
final int chopLocation = right < 0 ? sqlString.length() : right;
final String param = sqlString.substring( indx + 1, chopLocation );
if ( StringHelper.isEmpty( param ) ) {
throw new QueryException(
"Space is not allowed after parameter prefix ':' [" + sqlString + "]"
@ -103,12 +136,12 @@ public class ParameterParser {
// could be either an ordinal or JPA-positional parameter
if ( indx < stringLength - 1 && Character.isDigit( sqlString.charAt( indx + 1 ) ) ) {
// a peek ahead showed this as an JPA-positional parameter
int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS, indx + 1 );
int chopLocation = right < 0 ? sqlString.length() : right;
String param = sqlString.substring( indx + 1, chopLocation );
final int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS, indx + 1 );
final int chopLocation = right < 0 ? sqlString.length() : right;
final String param = sqlString.substring( indx + 1, chopLocation );
// make sure this "name" is an integral
try {
Integer.valueOf( param );
Integer.valueOf( param );
}
catch( NumberFormatException e ) {
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) {
if ( ! ( sqlString.startsWith( "{" ) && sqlString.endsWith( "}" ) ) ) {
return false;
}
int chopLocation = sqlString.indexOf( "call" );
final int chopLocation = sqlString.indexOf( "call" );
if ( chopLocation <= 0 ) {
return false;
}
@ -147,7 +187,8 @@ public class ParameterParser {
final String fixture = "?=call";
int fixturePosition = 0;
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 ) );
if ( Character.isWhitespace( c ) ) {
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.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.jboss.logging.Logger;
import org.hibernate.Filter;
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.FilterImpl;
import org.hibernate.internal.util.collections.BoundedConcurrentHashMap;
@ -54,9 +53,8 @@ import org.hibernate.internal.util.config.ConfigurationHelper;
* @author Steve Ebersole
*/
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.
*/
@ -65,11 +63,14 @@ public class QueryPlanCache implements Serializable {
* The default soft reference count.
*/
public static final int DEFAULT_QUERY_PLAN_MAX_COUNT = 2048;
private final SessionFactoryImplementor factory;
/**
* the cache of the actual plans...
*/
private final BoundedConcurrentHashMap queryPlanCache;
/**
* 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
@ -80,6 +81,12 @@ public class QueryPlanCache implements Serializable {
*/
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) {
this.factory = factory;
@ -135,15 +142,17 @@ public class QueryPlanCache implements Serializable {
}
private ParameterMetadata buildParameterMetadata(String query){
ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( query );
final ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( query );
final int size = recognizer.getOrdinalParameterLocationList().size();
OrdinalParameterDescriptor[] ordinalDescriptors = new OrdinalParameterDescriptor[ size ];
final OrdinalParameterDescriptor[] ordinalDescriptors = new OrdinalParameterDescriptor[ size ];
for ( int i = 0; i < size; i++ ) {
final Integer position = recognizer.getOrdinalParameterLocationList().get( i );
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() ) {
final ParamLocationRecognizer.NamedParameterDescription description = map.get( name );
namedParamDescriptorMap.put(
@ -159,9 +168,22 @@ public class QueryPlanCache implements Serializable {
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 {
HQLQueryPlanKey key = new HQLQueryPlanKey( queryString, shallow, enabledFilters );
final HQLQueryPlanKey key = new HQLQueryPlanKey( queryString, shallow, enabledFilters );
HQLQueryPlan value = (HQLQueryPlan) queryPlanCache.get( key );
if ( value == null ) {
LOG.tracev( "Unable to locate HQL query plan in cache; generating ({0})", queryString );
@ -173,37 +195,69 @@ public class QueryPlanCache implements Serializable {
return value;
}
public FilterQueryPlan getFilterQueryPlan(String filterString, String collectionRole, boolean shallow, Map enabledFilters)
throws QueryException, MappingException {
FilterQueryPlanKey key = new FilterQueryPlanKey( filterString, collectionRole, shallow, enabledFilters );
/**
* Get the query plan for the given collection HQL filter fragment, creating it and caching it if not already cached
*
* @param filterString The HQL filter fragment
* @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 );
if(value == null){
LOG.tracev( "Unable to locate collection-filter query plan in cache; generating ({0} : {1} )",
collectionRole, filterString );
if ( value == null ) {
LOG.tracev(
"Unable to locate collection-filter query plan in cache; generating ({0} : {1} )",
collectionRole,
filterString
);
value = new FilterQueryPlan( filterString, collectionRole, shallow, enabledFilters,factory );
queryPlanCache.putIfAbsent( key, value );
} else {
}
else {
LOG.tracev( "Located collection-filter query plan in cache ({0} : {1})", collectionRole, filterString );
}
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) {
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() );
value = new NativeSQLQueryPlan( spec, factory);
queryPlanCache.putIfAbsent( spec, value );
} else {
}
else {
LOG.tracev( "Located native-sql query plan in cache ({0})", spec.getQueryString() );
}
return value;
}
//clean up QueryPlanCache when Sessionfactory is closed
/**
* clean up QueryPlanCache when SessionFactory is closed
*/
public void cleanup() {
LOG.trace( "Cleaning QueryPlan Cache" );
queryPlanCache.clear();
@ -223,7 +277,7 @@ public class QueryPlanCache implements Serializable {
filterKeys = Collections.emptySet();
}
else {
Set<DynamicFilterKey> tmp = new HashSet<DynamicFilterKey>(
final Set<DynamicFilterKey> tmp = new HashSet<DynamicFilterKey>(
CollectionHelper.determineProperSizing( enabledFilters ),
CollectionHelper.LOAD_FACTOR
);
@ -248,7 +302,7 @@ public class QueryPlanCache implements Serializable {
return false;
}
final HQLQueryPlanKey that = ( HQLQueryPlanKey ) o;
final HQLQueryPlanKey that = (HQLQueryPlanKey) o;
return shallow == that.shallow
&& filterKeys.equals( that.filterKeys )
@ -306,8 +360,7 @@ public class QueryPlanCache implements Serializable {
return false;
}
DynamicFilterKey that = ( DynamicFilterKey ) o;
final DynamicFilterKey that = (DynamicFilterKey) o;
return filterName.equals( that.filterName )
&& parameterMetadata.equals( that.parameterMetadata );
@ -336,7 +389,7 @@ public class QueryPlanCache implements Serializable {
this.filterNames = Collections.emptySet();
}
else {
Set<String> tmp = new HashSet<String>();
final Set<String> tmp = new HashSet<String>();
tmp.addAll( enabledFilters.keySet() );
this.filterNames = Collections.unmodifiableSet( tmp );
@ -358,8 +411,7 @@ public class QueryPlanCache implements Serializable {
return false;
}
final FilterQueryPlanKey that = ( FilterQueryPlanKey ) o;
final FilterQueryPlanKey that = (FilterQueryPlanKey) o;
return shallow == that.shallow
&& filterNames.equals( that.filterNames )
&& query.equals( that.query )

View File

@ -1,10 +1,10 @@
/*
* 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
* 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,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,21 +20,23 @@
* 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 org.hibernate.type.Type;
/**
* Metadata about the query return(s).
*
* @author Steve Ebersole
*/
public class ReturnMetadata implements Serializable {
private final String[] returnAliases;
private final Type[] returnTypes;
public ReturnMetadata(String[] returnAliases, Type[] returnTypes) {
ReturnMetadata(String[] returnAliases, Type[] returnTypes) {
this.returnAliases = returnAliases;
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;