HHH-8222 - Implement @NamedStoredProcedureQuery binding

This commit is contained in:
Steve Ebersole 2013-05-09 14:47:58 -05:00
parent 40373412e0
commit 8c95a6077a
26 changed files with 1275 additions and 111 deletions

View File

@ -26,6 +26,7 @@ package org.hibernate;
import java.io.Serializable; import java.io.Serializable;
import org.hibernate.procedure.ProcedureCall; import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.ProcedureCallMemento;
/** /**
* Contract methods shared between {@link Session} and {@link StatelessSession}. * Contract methods shared between {@link Session} and {@link StatelessSession}.
@ -86,6 +87,17 @@ public interface SharedSessionContract extends Serializable {
*/ */
public SQLQuery createSQLQuery(String queryString); public SQLQuery createSQLQuery(String queryString);
/**
* Gets a ProcedureCall based on a named template
*
* @param name The name given to the template
*
* @return The ProcedureCall
*
* @see javax.persistence.NamedStoredProcedureQuery
*/
public ProcedureCall getNamedProcedureCall(String name);
/** /**
* Creates a call to a stored procedure. * Creates a call to a stored procedure.
* *
@ -154,5 +166,4 @@ public interface SharedSessionContract extends Serializable {
* @return The criteria instance for manipulation and execution * @return The criteria instance for manipulation and execution
*/ */
public Criteria createCriteria(String entityName, String alias); public Criteria createCriteria(String entityName, String alias);
} }

View File

@ -68,6 +68,8 @@ import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery; import javax.persistence.NamedNativeQuery;
import javax.persistence.NamedQueries; import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery; import javax.persistence.NamedQuery;
import javax.persistence.NamedStoredProcedureQueries;
import javax.persistence.NamedStoredProcedureQuery;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.OneToOne; import javax.persistence.OneToOne;
import javax.persistence.OrderColumn; import javax.persistence.OrderColumn;
@ -253,6 +255,28 @@ public final class AnnotationBinder {
} }
} }
} }
{
final List<NamedStoredProcedureQuery> annotations =
(List<NamedStoredProcedureQuery>) defaults.get( NamedStoredProcedureQuery.class );
if ( annotations != null ) {
for ( NamedStoredProcedureQuery annotation : annotations ) {
QueryBinder.bindNamedStoredProcedureQuery( annotation, mappings );
}
}
}
{
final List<NamedStoredProcedureQueries> annotations =
(List<NamedStoredProcedureQueries>) defaults.get( NamedStoredProcedureQueries.class );
if ( annotations != null ) {
for ( NamedStoredProcedureQueries annotation : annotations ) {
for ( NamedStoredProcedureQuery queryAnnotation : annotation.value() ) {
QueryBinder.bindNamedStoredProcedureQuery( queryAnnotation, mappings );
}
}
}
}
} }
public static void bindPackage(String packageName, Mappings mappings) { public static void bindPackage(String packageName, Mappings mappings) {
@ -358,6 +382,24 @@ public final class AnnotationBinder {
); );
QueryBinder.bindNativeQueries( ann, mappings ); QueryBinder.bindNativeQueries( ann, mappings );
} }
// NamedStoredProcedureQuery handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
final NamedStoredProcedureQuery annotation = annotatedElement.getAnnotation( NamedStoredProcedureQuery.class );
if ( annotation != null ) {
QueryBinder.bindNamedStoredProcedureQuery( annotation, mappings );
}
}
// NamedStoredProcedureQueries handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
final NamedStoredProcedureQueries annotation = annotatedElement.getAnnotation( NamedStoredProcedureQueries.class );
if ( annotation != null ) {
for ( NamedStoredProcedureQuery queryAnnotation : annotation.value() ) {
QueryBinder.bindNamedStoredProcedureQuery( queryAnnotation, mappings );
}
}
}
} }
private static IdGenerator buildIdGenerator(java.lang.annotation.Annotation ann, Mappings mappings) { private static IdGenerator buildIdGenerator(java.lang.annotation.Annotation ann, Mappings mappings) {

View File

@ -81,6 +81,7 @@ import org.hibernate.annotations.common.reflection.java.JavaReflectionManager;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl; import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl;
import org.hibernate.cfg.annotations.NamedProcedureCallDefinition;
import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider; import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver; import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
@ -214,6 +215,7 @@ public class Configuration implements Serializable {
protected Map<String, NamedQueryDefinition> namedQueries; protected Map<String, NamedQueryDefinition> namedQueries;
protected Map<String, NamedSQLQueryDefinition> namedSqlQueries; protected Map<String, NamedSQLQueryDefinition> namedSqlQueries;
protected Map<String, NamedProcedureCallDefinition> namedProcedureCallMap;
protected Map<String, ResultSetMappingDefinition> sqlResultSetMappings; protected Map<String, ResultSetMappingDefinition> sqlResultSetMappings;
protected Map<String, TypeDef> typeDefs; protected Map<String, TypeDef> typeDefs;
@ -1772,6 +1774,10 @@ public class Configuration implements Serializable {
return namedQueries; return namedQueries;
} }
public Map<String, NamedProcedureCallDefinition> getNamedProcedureCallMap() {
return namedProcedureCallMap;
}
/** /**
* Create a {@link SessionFactory} using the properties and mappings in this configuration. The * Create a {@link SessionFactory} using the properties and mappings in this configuration. The
* {@link SessionFactory} will be immutable, so changes made to {@code this} {@link Configuration} after * {@link SessionFactory} will be immutable, so changes made to {@code this} {@link Configuration} after
@ -2764,7 +2770,7 @@ public class Configuration implements Serializable {
public Table getTable(String schema, String catalog, String name) { public Table getTable(String schema, String catalog, String name) {
String key = Table.qualify(catalog, schema, name); String key = Table.qualify(catalog, schema, name);
return tables.get(key); return tables.get( key );
} }
public Iterator<Table> iterateTables() { public Iterator<Table> iterateTables() {
@ -2870,6 +2876,16 @@ public class Configuration implements Serializable {
namedSqlQueries.put( name.intern(), query ); namedSqlQueries.put( name.intern(), query );
} }
@Override
public void addNamedProcedureCallDefinition(NamedProcedureCallDefinition definition)
throws DuplicateMappingException {
final String name = definition.getRegisteredName();
final NamedProcedureCallDefinition previous = namedProcedureCallMap.put( name, definition );
if ( previous != null ) {
throw new DuplicateMappingException( "named stored procedure query", name );
}
}
public void addDefaultSQLQuery(String name, NamedSQLQueryDefinition query) { public void addDefaultSQLQuery(String name, NamedSQLQueryDefinition query) {
applySQLQuery( name, query ); applySQLQuery( name, query );
defaultNamedNativeQueryNames.add( name ); defaultNamedNativeQueryNames.add( name );

View File

@ -37,6 +37,7 @@ import org.hibernate.MappingException;
import org.hibernate.annotations.AnyMetaDef; import org.hibernate.annotations.AnyMetaDef;
import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.cfg.annotations.NamedProcedureCallDefinition;
import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.NamedQueryDefinition; import org.hibernate.engine.spi.NamedQueryDefinition;
@ -338,6 +339,15 @@ public interface Mappings {
*/ */
public void addSQLQuery(String name, NamedSQLQueryDefinition query) throws DuplicateMappingException; public void addSQLQuery(String name, NamedSQLQueryDefinition query) throws DuplicateMappingException;
/**
* Adds metadata for a named stored procedure call to this repository.
*
* @param definition The procedure call information
*
* @throws DuplicateMappingException If a query already exists with that name.
*/
public void addNamedProcedureCallDefinition(NamedProcedureCallDefinition definition) throws DuplicateMappingException;
/** /**
* Get the metadata for a named SQL result set mapping. * Get the metadata for a named SQL result set mapping.
* *

View File

@ -0,0 +1,237 @@
/*
* 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
*/
package org.hibernate.cfg.annotations;
import javax.persistence.NamedStoredProcedureQuery;
import javax.persistence.ParameterMode;
import javax.persistence.QueryHint;
import javax.persistence.StoredProcedureParameter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryRootReturn;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.SessionFactoryImpl;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.procedure.ProcedureCallMemento;
import org.hibernate.procedure.internal.ParameterStrategy;
import org.hibernate.procedure.internal.ProcedureCallMementoImpl;
import org.hibernate.procedure.internal.Util;
import static org.hibernate.procedure.internal.ProcedureCallMementoImpl.ParameterMemento;
/**
* Holds all the information needed from a named procedure call declaration in order to create a
* {@link org.hibernate.procedure.internal.ProcedureCallImpl}
*
* @author Steve Ebersole
*
* @see javax.persistence.NamedStoredProcedureQuery
*/
public class NamedProcedureCallDefinition {
private final String registeredName;
private final String procedureName;
private final Class[] resultClasses;
private final String[] resultSetMappings;
private final ParameterDefinitions parameterDefinitions;
private final Map<String,Object> hints;
NamedProcedureCallDefinition(NamedStoredProcedureQuery annotation) {
this.registeredName = annotation.name();
this.procedureName = annotation.procedureName();
this.resultClasses = annotation.resultClasses();
this.resultSetMappings = annotation.resultSetMappings();
this.parameterDefinitions = new ParameterDefinitions( annotation.parameters() );
this.hints = extract( annotation.hints() );
final boolean specifiesResultClasses = resultClasses != null && resultClasses.length > 0;
final boolean specifiesResultSetMappings = resultSetMappings != null && resultSetMappings.length > 0;
if ( specifiesResultClasses && specifiesResultSetMappings ) {
throw new MappingException(
String.format(
"NamedStoredProcedureQuery [%s] specified both resultClasses and resultSetMappings",
registeredName
)
);
}
}
private Map<String, Object> extract(QueryHint[] hints) {
if ( hints == null || hints.length == 0 ) {
return Collections.emptyMap();
}
final Map<String,Object> hintsMap = new HashMap<String, Object>();
for ( QueryHint hint : hints ) {
hintsMap.put( hint.name(), hint.value() );
}
return hintsMap;
}
public String getRegisteredName() {
return registeredName;
}
public String getProcedureName() {
return procedureName;
}
public ProcedureCallMemento toMemento(
final SessionFactoryImpl sessionFactory,
final Map<String,ResultSetMappingDefinition> resultSetMappingDefinitions) {
final List<NativeSQLQueryReturn> collectedQueryReturns = new ArrayList<NativeSQLQueryReturn>();
final Set<String> collectedQuerySpaces = new HashSet<String>();
final boolean specifiesResultClasses = resultClasses != null && resultClasses.length > 0;
final boolean specifiesResultSetMappings = resultSetMappings != null && resultSetMappings.length > 0;
if ( specifiesResultClasses ) {
Util.resolveResultClasses(
new Util.ResultClassesResolutionContext() {
@Override
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory;
}
@Override
public void addQueryReturns(NativeSQLQueryReturn... queryReturns) {
Collections.addAll( collectedQueryReturns, queryReturns );
}
@Override
public void addQuerySpaces(String... spaces) {
Collections.addAll( collectedQuerySpaces, spaces );
}
},
resultClasses
);
}
else if ( specifiesResultSetMappings ) {
Util.resolveResultSetMappings(
new Util.ResultSetMappingResolutionContext() {
@Override
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory;
}
@Override
public ResultSetMappingDefinition findResultSetMapping(String name) {
return resultSetMappingDefinitions.get( name );
}
@Override
public void addQueryReturns(NativeSQLQueryReturn... queryReturns) {
Collections.addAll( collectedQueryReturns, queryReturns );
}
@Override
public void addQuerySpaces(String... spaces) {
Collections.addAll( collectedQuerySpaces, spaces );
}
},
resultSetMappings
);
}
return new ProcedureCallMementoImpl(
procedureName,
collectedQueryReturns.toArray( new NativeSQLQueryReturn[ collectedQueryReturns.size() ] ),
parameterDefinitions.getParameterStrategy(),
parameterDefinitions.toMementos( sessionFactory ),
collectedQuerySpaces,
hints
);
}
static class ParameterDefinitions {
private final ParameterStrategy parameterStrategy;
private final ParameterDefinition[] parameterDefinitions;
ParameterDefinitions(StoredProcedureParameter[] parameters) {
if ( parameters == null || parameters.length == 0 ) {
parameterStrategy = ParameterStrategy.POSITIONAL;
parameterDefinitions = new ParameterDefinition[0];
}
else {
parameterStrategy = StringHelper.isNotEmpty( parameters[0].name() )
? ParameterStrategy.NAMED
: ParameterStrategy.POSITIONAL;
parameterDefinitions = new ParameterDefinition[ parameters.length ];
for ( int i = 0; i < parameters.length; i++ ) {
parameterDefinitions[i] = new ParameterDefinition( i, parameters[i] );
}
}
}
public ParameterStrategy getParameterStrategy() {
return parameterStrategy;
}
public List<ParameterMemento> toMementos(SessionFactoryImpl sessionFactory) {
final List<ParameterMemento> mementos = new ArrayList<ParameterMemento>();
for ( ParameterDefinition definition : parameterDefinitions ) {
definition.toMemento( sessionFactory );
}
return mementos;
}
}
static class ParameterDefinition {
private final Integer position;
private final String name;
private final ParameterMode parameterMode;
private final Class type;
ParameterDefinition(int position, StoredProcedureParameter annotation) {
this.position = position;
this.name = normalize( annotation.name() );
this.parameterMode = annotation.mode();
this.type = annotation.type();
}
public ParameterMemento toMemento(SessionFactoryImpl sessionFactory) {
return new ParameterMemento(
position,
name,
parameterMode,
type,
sessionFactory.getTypeResolver().heuristicType( type.getName() )
);
}
}
private static String normalize(String name) {
return StringHelper.isNotEmpty( name ) ? name : null;
}
}

View File

@ -28,6 +28,7 @@ import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery; import javax.persistence.NamedNativeQuery;
import javax.persistence.NamedQueries; import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery; import javax.persistence.NamedQuery;
import javax.persistence.NamedStoredProcedureQuery;
import javax.persistence.QueryHint; import javax.persistence.QueryHint;
import javax.persistence.SqlResultSetMapping; import javax.persistence.SqlResultSetMapping;
import javax.persistence.SqlResultSetMappings; import javax.persistence.SqlResultSetMappings;
@ -331,6 +332,20 @@ public abstract class QueryBinder {
} }
} }
public static void bindNamedStoredProcedureQuery(NamedStoredProcedureQuery annotation, Mappings mappings) {
if ( annotation == null ) {
return;
}
if ( BinderHelper.isEmptyAnnotationValue( annotation.name() ) ) {
throw new AnnotationException( "A named query must have a name when used in class or package level" );
}
final NamedProcedureCallDefinition def = new NamedProcedureCallDefinition( annotation );
mappings.addNamedProcedureCallDefinition( def );
LOG.debugf( "Bound named stored procedure query : %s => %s", def.getRegisteredName(), def.getProcedureName() );
}
public static void bindSqlResultsetMappings(SqlResultSetMappings ann, Mappings mappings, boolean isDefault) { public static void bindSqlResultsetMappings(SqlResultSetMappings ann, Mappings mappings, boolean isDefault) {
if ( ann == null ) return; if ( ann == null ) return;
for (SqlResultSetMapping rs : ann.value()) { for (SqlResultSetMapping rs : ann.value()) {

View File

@ -380,22 +380,31 @@ public class SessionDelegatorBaseImpl implements SessionImplementor, Session {
// Delegates to Session // Delegates to Session
@Override
public Transaction beginTransaction() { public Transaction beginTransaction() {
return session.beginTransaction(); return session.beginTransaction();
} }
@Override
public Transaction getTransaction() { public Transaction getTransaction() {
return session.getTransaction(); return session.getTransaction();
} }
@Override
public Query createQuery(String queryString) { public Query createQuery(String queryString) {
return session.createQuery( queryString ); return session.createQuery( queryString );
} }
@Override
public SQLQuery createSQLQuery(String queryString) { public SQLQuery createSQLQuery(String queryString) {
return session.createSQLQuery( queryString ); return session.createSQLQuery( queryString );
} }
@Override
public ProcedureCall getNamedProcedureCall(String name) {
return session.getNamedProcedureCall( name );
}
@Override @Override
public ProcedureCall createStoredProcedureCall(String procedureName) { public ProcedureCall createStoredProcedureCall(String procedureName) {
return session.createStoredProcedureCall( procedureName ); return session.createStoredProcedureCall( procedureName );
@ -411,298 +420,372 @@ public class SessionDelegatorBaseImpl implements SessionImplementor, Session {
return session.createStoredProcedureCall( procedureName, resultSetMappings ); return session.createStoredProcedureCall( procedureName, resultSetMappings );
} }
@Override
public Criteria createCriteria(Class persistentClass) { public Criteria createCriteria(Class persistentClass) {
return session.createCriteria( persistentClass ); return session.createCriteria( persistentClass );
} }
@Override
public Criteria createCriteria(Class persistentClass, String alias) { public Criteria createCriteria(Class persistentClass, String alias) {
return session.createCriteria( persistentClass, alias ); return session.createCriteria( persistentClass, alias );
} }
@Override
public Criteria createCriteria(String entityName) { public Criteria createCriteria(String entityName) {
return session.createCriteria( entityName ); return session.createCriteria( entityName );
} }
@Override
public Criteria createCriteria(String entityName, String alias) { public Criteria createCriteria(String entityName, String alias) {
return session.createCriteria( entityName, alias ); return session.createCriteria( entityName, alias );
} }
@Override
public SharedSessionBuilder sessionWithOptions() { public SharedSessionBuilder sessionWithOptions() {
return session.sessionWithOptions(); return session.sessionWithOptions();
} }
@Override
public SessionFactory getSessionFactory() { public SessionFactory getSessionFactory() {
return session.getSessionFactory(); return session.getSessionFactory();
} }
@Override
public Connection close() throws HibernateException { public Connection close() throws HibernateException {
return session.close(); return session.close();
} }
@Override
public void cancelQuery() throws HibernateException { public void cancelQuery() throws HibernateException {
session.cancelQuery(); session.cancelQuery();
} }
@Override
public boolean isDirty() throws HibernateException { public boolean isDirty() throws HibernateException {
return session.isDirty(); return session.isDirty();
} }
@Override
public boolean isDefaultReadOnly() { public boolean isDefaultReadOnly() {
return session.isDefaultReadOnly(); return session.isDefaultReadOnly();
} }
@Override
public void setDefaultReadOnly(boolean readOnly) { public void setDefaultReadOnly(boolean readOnly) {
session.setDefaultReadOnly( readOnly ); session.setDefaultReadOnly( readOnly );
} }
@Override
public Serializable getIdentifier(Object object) { public Serializable getIdentifier(Object object) {
return session.getIdentifier( object ); return session.getIdentifier( object );
} }
@Override
public boolean contains(Object object) { public boolean contains(Object object) {
return session.contains( object ); return session.contains( object );
} }
@Override
public void evict(Object object) { public void evict(Object object) {
session.evict( object ); session.evict( object );
} }
@Override
public Object load(Class theClass, Serializable id, LockMode lockMode) { public Object load(Class theClass, Serializable id, LockMode lockMode) {
return session.load( theClass, id, lockMode ); return session.load( theClass, id, lockMode );
} }
@Override
public Object load(Class theClass, Serializable id, LockOptions lockOptions) { public Object load(Class theClass, Serializable id, LockOptions lockOptions) {
return session.load( theClass, id, lockOptions ); return session.load( theClass, id, lockOptions );
} }
@Override
public Object load(String entityName, Serializable id, LockMode lockMode) { public Object load(String entityName, Serializable id, LockMode lockMode) {
return session.load( entityName, id, lockMode ); return session.load( entityName, id, lockMode );
} }
@Override
public Object load(String entityName, Serializable id, LockOptions lockOptions) { public Object load(String entityName, Serializable id, LockOptions lockOptions) {
return session.load( entityName, id, lockOptions ); return session.load( entityName, id, lockOptions );
} }
@Override
public Object load(Class theClass, Serializable id) { public Object load(Class theClass, Serializable id) {
return session.load( theClass, id ); return session.load( theClass, id );
} }
@Override
public Object load(String entityName, Serializable id) { public Object load(String entityName, Serializable id) {
return session.load( entityName, id ); return session.load( entityName, id );
} }
@Override
public void load(Object object, Serializable id) { public void load(Object object, Serializable id) {
session.load( object, id ); session.load( object, id );
} }
@Override
public void replicate(Object object, ReplicationMode replicationMode) { public void replicate(Object object, ReplicationMode replicationMode) {
session.replicate( object, replicationMode ); session.replicate( object, replicationMode );
} }
@Override
public void replicate(String entityName, Object object, ReplicationMode replicationMode) { public void replicate(String entityName, Object object, ReplicationMode replicationMode) {
session.replicate( entityName, object, replicationMode ); session.replicate( entityName, object, replicationMode );
} }
@Override
public Serializable save(Object object) { public Serializable save(Object object) {
return session.save( object ); return session.save( object );
} }
@Override
public Serializable save(String entityName, Object object) { public Serializable save(String entityName, Object object) {
return session.save( entityName, object ); return session.save( entityName, object );
} }
@Override
public void saveOrUpdate(Object object) { public void saveOrUpdate(Object object) {
session.saveOrUpdate( object ); session.saveOrUpdate( object );
} }
@Override
public void saveOrUpdate(String entityName, Object object) { public void saveOrUpdate(String entityName, Object object) {
session.saveOrUpdate( entityName, object ); session.saveOrUpdate( entityName, object );
} }
@Override
public void update(Object object) { public void update(Object object) {
session.update( object ); session.update( object );
} }
@Override
public void update(String entityName, Object object) { public void update(String entityName, Object object) {
session.update( entityName, object ); session.update( entityName, object );
} }
@Override
public Object merge(Object object) { public Object merge(Object object) {
return session.merge( object ); return session.merge( object );
} }
@Override
public Object merge(String entityName, Object object) { public Object merge(String entityName, Object object) {
return session.merge( entityName, object ); return session.merge( entityName, object );
} }
@Override
public void persist(Object object) { public void persist(Object object) {
session.persist( object ); session.persist( object );
} }
@Override
public void persist(String entityName, Object object) { public void persist(String entityName, Object object) {
session.persist( entityName, object ); session.persist( entityName, object );
} }
@Override
public void delete(Object object) { public void delete(Object object) {
session.delete( object ); session.delete( object );
} }
@Override
public void delete(String entityName, Object object) { public void delete(String entityName, Object object) {
session.delete( entityName, object ); session.delete( entityName, object );
} }
@Override
public void lock(Object object, LockMode lockMode) { public void lock(Object object, LockMode lockMode) {
session.lock( object, lockMode ); session.lock( object, lockMode );
} }
@Override
public void lock(String entityName, Object object, LockMode lockMode) { public void lock(String entityName, Object object, LockMode lockMode) {
session.lock( entityName, object, lockMode ); session.lock( entityName, object, lockMode );
} }
@Override
public LockRequest buildLockRequest(LockOptions lockOptions) { public LockRequest buildLockRequest(LockOptions lockOptions) {
return session.buildLockRequest( lockOptions ); return session.buildLockRequest( lockOptions );
} }
@Override
public void refresh(Object object) { public void refresh(Object object) {
session.refresh( object ); session.refresh( object );
} }
@Override
public void refresh(String entityName, Object object) { public void refresh(String entityName, Object object) {
session.refresh( entityName, object ); session.refresh( entityName, object );
} }
@Override
public void refresh(Object object, LockMode lockMode) { public void refresh(Object object, LockMode lockMode) {
session.refresh( object, lockMode ); session.refresh( object, lockMode );
} }
@Override
public void refresh(Object object, LockOptions lockOptions) { public void refresh(Object object, LockOptions lockOptions) {
session.refresh( object, lockOptions ); session.refresh( object, lockOptions );
} }
@Override
public void refresh(String entityName, Object object, LockOptions lockOptions) { public void refresh(String entityName, Object object, LockOptions lockOptions) {
session.refresh( entityName, object, lockOptions ); session.refresh( entityName, object, lockOptions );
} }
@Override
public LockMode getCurrentLockMode(Object object) { public LockMode getCurrentLockMode(Object object) {
return session.getCurrentLockMode( object ); return session.getCurrentLockMode( object );
} }
@Override
public Query createFilter(Object collection, String queryString) { public Query createFilter(Object collection, String queryString) {
return session.createFilter( collection, queryString ); return session.createFilter( collection, queryString );
} }
@Override
public void clear() { public void clear() {
session.clear(); session.clear();
} }
@Override
public Object get(Class clazz, Serializable id) { public Object get(Class clazz, Serializable id) {
return session.get( clazz, id ); return session.get( clazz, id );
} }
@Override
public Object get(Class clazz, Serializable id, LockMode lockMode) { public Object get(Class clazz, Serializable id, LockMode lockMode) {
return session.get( clazz, id, lockMode ); return session.get( clazz, id, lockMode );
} }
@Override
public Object get(Class clazz, Serializable id, LockOptions lockOptions) { public Object get(Class clazz, Serializable id, LockOptions lockOptions) {
return session.get( clazz, id, lockOptions ); return session.get( clazz, id, lockOptions );
} }
@Override
public Object get(String entityName, Serializable id) { public Object get(String entityName, Serializable id) {
return session.get( entityName, id ); return session.get( entityName, id );
} }
@Override
public Object get(String entityName, Serializable id, LockMode lockMode) { public Object get(String entityName, Serializable id, LockMode lockMode) {
return session.get( entityName, id, lockMode ); return session.get( entityName, id, lockMode );
} }
@Override
public Object get(String entityName, Serializable id, LockOptions lockOptions) { public Object get(String entityName, Serializable id, LockOptions lockOptions) {
return session.get( entityName, id, lockOptions ); return session.get( entityName, id, lockOptions );
} }
@Override
public String getEntityName(Object object) { public String getEntityName(Object object) {
return session.getEntityName( object ); return session.getEntityName( object );
} }
@Override
public IdentifierLoadAccess byId(String entityName) { public IdentifierLoadAccess byId(String entityName) {
return session.byId( entityName ); return session.byId( entityName );
} }
@Override
public IdentifierLoadAccess byId(Class entityClass) { public IdentifierLoadAccess byId(Class entityClass) {
return session.byId( entityClass ); return session.byId( entityClass );
} }
@Override
public NaturalIdLoadAccess byNaturalId(String entityName) { public NaturalIdLoadAccess byNaturalId(String entityName) {
return session.byNaturalId( entityName ); return session.byNaturalId( entityName );
} }
@Override
public NaturalIdLoadAccess byNaturalId(Class entityClass) { public NaturalIdLoadAccess byNaturalId(Class entityClass) {
return session.byNaturalId( entityClass ); return session.byNaturalId( entityClass );
} }
@Override
public SimpleNaturalIdLoadAccess bySimpleNaturalId(String entityName) { public SimpleNaturalIdLoadAccess bySimpleNaturalId(String entityName) {
return session.bySimpleNaturalId( entityName ); return session.bySimpleNaturalId( entityName );
} }
@Override
public SimpleNaturalIdLoadAccess bySimpleNaturalId(Class entityClass) { public SimpleNaturalIdLoadAccess bySimpleNaturalId(Class entityClass) {
return session.bySimpleNaturalId( entityClass ); return session.bySimpleNaturalId( entityClass );
} }
@Override
public Filter enableFilter(String filterName) { public Filter enableFilter(String filterName) {
return session.enableFilter( filterName ); return session.enableFilter( filterName );
} }
@Override
public Filter getEnabledFilter(String filterName) { public Filter getEnabledFilter(String filterName) {
return session.getEnabledFilter( filterName ); return session.getEnabledFilter( filterName );
} }
@Override
public void disableFilter(String filterName) { public void disableFilter(String filterName) {
session.disableFilter( filterName ); session.disableFilter( filterName );
} }
@Override
public SessionStatistics getStatistics() { public SessionStatistics getStatistics() {
return session.getStatistics(); return session.getStatistics();
} }
@Override
public boolean isReadOnly(Object entityOrProxy) { public boolean isReadOnly(Object entityOrProxy) {
return session.isReadOnly( entityOrProxy ); return session.isReadOnly( entityOrProxy );
} }
@Override
public void setReadOnly(Object entityOrProxy, boolean readOnly) { public void setReadOnly(Object entityOrProxy, boolean readOnly) {
session.setReadOnly( entityOrProxy, readOnly ); session.setReadOnly( entityOrProxy, readOnly );
} }
@Override
public void doWork(Work work) throws HibernateException { public void doWork(Work work) throws HibernateException {
session.doWork( work ); session.doWork( work );
} }
@Override
public <T> T doReturningWork(ReturningWork<T> work) throws HibernateException { public <T> T doReturningWork(ReturningWork<T> work) throws HibernateException {
return session.doReturningWork( work ); return session.doReturningWork( work );
} }
@Override
public Connection disconnect() { public Connection disconnect() {
return session.disconnect(); return session.disconnect();
} }
@Override
public void reconnect(Connection connection) { public void reconnect(Connection connection) {
session.reconnect( connection ); session.reconnect( connection );
} }
@Override
public boolean isFetchProfileEnabled(String name) throws UnknownProfileException { public boolean isFetchProfileEnabled(String name) throws UnknownProfileException {
return session.isFetchProfileEnabled( name ); return session.isFetchProfileEnabled( name );
} }
@Override
public void enableFetchProfile(String name) throws UnknownProfileException { public void enableFetchProfile(String name) throws UnknownProfileException {
session.enableFetchProfile( name ); session.enableFetchProfile( name );
} }
@Override
public void disableFetchProfile(String name) throws UnknownProfileException { public void disableFetchProfile(String name) throws UnknownProfileException {
session.disableFetchProfile( name ); session.disableFetchProfile( name );
} }
@Override
public TypeHelper getTypeHelper() { public TypeHelper getTypeHelper() {
return session.getTypeHelper(); return session.getTypeHelper();
} }
@Override
public LobHelper getLobHelper() { public LobHelper getLobHelper() {
return session.getLobHelper(); return session.getLobHelper();
} }

View File

@ -51,6 +51,7 @@ import org.hibernate.id.IdentifierGenerator;
import org.hibernate.internal.NamedQueryRepository; import org.hibernate.internal.NamedQueryRepository;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.procedure.ProcedureCallMemento;
import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.ServiceRegistryImplementor;

View File

@ -27,6 +27,7 @@ import java.io.Serializable;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
@ -59,6 +60,7 @@ import org.hibernate.jdbc.WorkExecutorVisitable;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider; import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.hibernate.procedure.ProcedureCallMemento;
import org.hibernate.procedure.internal.ProcedureCallImpl; import org.hibernate.procedure.internal.ProcedureCallImpl;
import org.hibernate.type.Type; import org.hibernate.type.Type;
@ -67,11 +69,11 @@ import org.hibernate.type.Type;
* *
* @author Gavin King * @author Gavin King
*/ */
public abstract class AbstractSessionImpl implements Serializable, SharedSessionContract, public abstract class AbstractSessionImpl
SessionImplementor, TransactionContext { implements Serializable, SharedSessionContract, SessionImplementor, TransactionContext {
protected transient SessionFactoryImpl factory; protected transient SessionFactoryImpl factory;
private final String tenantIdentifier; private final String tenantIdentifier;
private boolean closed = false; private boolean closed;
protected AbstractSessionImpl(SessionFactoryImpl factory, String tenantIdentifier) { protected AbstractSessionImpl(SessionFactoryImpl factory, String tenantIdentifier) {
this.factory = factory; this.factory = factory;
@ -218,7 +220,7 @@ public abstract class AbstractSessionImpl implements Serializable, SharedSession
@Override @Override
public Query createQuery(String queryString) { public Query createQuery(String queryString) {
errorIfClosed(); errorIfClosed();
QueryImpl query = new QueryImpl( final QueryImpl query = new QueryImpl(
queryString, queryString,
this, this,
getHQLQueryPlan( queryString, false ).getParameterMetadata() getHQLQueryPlan( queryString, false ).getParameterMetadata()
@ -230,7 +232,7 @@ public abstract class AbstractSessionImpl implements Serializable, SharedSession
@Override @Override
public SQLQuery createSQLQuery(String sql) { public SQLQuery createSQLQuery(String sql) {
errorIfClosed(); errorIfClosed();
SQLQueryImpl query = new SQLQueryImpl( final SQLQueryImpl query = new SQLQueryImpl(
sql, sql,
this, this,
factory.getQueryPlanCache().getSQLParameterMetadata( sql ) factory.getQueryPlanCache().getSQLParameterMetadata( sql )
@ -239,6 +241,22 @@ public abstract class AbstractSessionImpl implements Serializable, SharedSession
return query; return query;
} }
@Override
@SuppressWarnings("UnnecessaryLocalVariable")
public ProcedureCall getNamedProcedureCall(String name) {
errorIfClosed();
final ProcedureCallMemento memento = factory.getNamedQueryRepository().getNamedProcedureCallMemento( name );
if ( memento == null ) {
throw new IllegalArgumentException(
"Could not find named stored procedure call with that registration name : " + name
);
}
final ProcedureCall procedureCall = memento.makeProcedureCall( this );
// procedureCall.setComment( "Named stored procedure call [" + name + "]" );
return procedureCall;
}
@Override @Override
@SuppressWarnings("UnnecessaryLocalVariable") @SuppressWarnings("UnnecessaryLocalVariable")
public ProcedureCall createStoredProcedureCall(String procedureName) { public ProcedureCall createStoredProcedureCall(String procedureName) {

View File

@ -25,20 +25,20 @@ package org.hibernate.internal;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.List;
import java.util.Map; import java.util.Map;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.query.spi.QueryPlanCache; import org.hibernate.engine.query.spi.QueryPlanCache;
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification; import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
import org.hibernate.engine.spi.NamedQueryDefinition; import org.hibernate.engine.spi.NamedQueryDefinition;
import org.hibernate.engine.spi.NamedSQLQueryDefinition; import org.hibernate.engine.spi.NamedSQLQueryDefinition;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.procedure.ProcedureCallMemento;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -46,14 +46,17 @@ import org.hibernate.internal.util.collections.CollectionHelper;
public class NamedQueryRepository { public class NamedQueryRepository {
private static final Logger log = Logger.getLogger( NamedQueryRepository.class ); private static final Logger log = Logger.getLogger( NamedQueryRepository.class );
private final Map<String, ResultSetMappingDefinition> namedSqlResultSetMappingMap;
private volatile Map<String, NamedQueryDefinition> namedQueryDefinitionMap; private volatile Map<String, NamedQueryDefinition> namedQueryDefinitionMap;
private volatile Map<String, NamedSQLQueryDefinition> namedSqlQueryDefinitionMap; private volatile Map<String, NamedSQLQueryDefinition> namedSqlQueryDefinitionMap;
private final Map<String, ResultSetMappingDefinition> namedSqlResultSetMappingMap; private volatile Map<String, ProcedureCallMemento> procedureCallMementoMap;
public NamedQueryRepository( public NamedQueryRepository(
Iterable<NamedQueryDefinition> namedQueryDefinitions, Iterable<NamedQueryDefinition> namedQueryDefinitions,
Iterable<NamedSQLQueryDefinition> namedSqlQueryDefinitions, Iterable<NamedSQLQueryDefinition> namedSqlQueryDefinitions,
Iterable<ResultSetMappingDefinition> namedSqlResultSetMappings) { Iterable<ResultSetMappingDefinition> namedSqlResultSetMappings,
List<ProcedureCallMemento> namedProcedureCalls) {
final HashMap<String, NamedQueryDefinition> namedQueryDefinitionMap = new HashMap<String, NamedQueryDefinition>(); final HashMap<String, NamedQueryDefinition> namedQueryDefinitionMap = new HashMap<String, NamedQueryDefinition>();
for ( NamedQueryDefinition namedQueryDefinition : namedQueryDefinitions ) { for ( NamedQueryDefinition namedQueryDefinition : namedQueryDefinitions ) {
namedQueryDefinitionMap.put( namedQueryDefinition.getName(), namedQueryDefinition ); namedQueryDefinitionMap.put( namedQueryDefinition.getName(), namedQueryDefinition );
@ -83,6 +86,10 @@ public class NamedQueryRepository {
return namedSqlQueryDefinitionMap.get( queryName ); return namedSqlQueryDefinitionMap.get( queryName );
} }
public ProcedureCallMemento getNamedProcedureCallMemento(String name) {
return procedureCallMementoMap.get( name );
}
public ResultSetMappingDefinition getResultSetMappingDefinition(String mappingName) { public ResultSetMappingDefinition getResultSetMappingDefinition(String mappingName) {
return namedSqlResultSetMappingMap.get( mappingName ); return namedSqlResultSetMappingMap.get( mappingName );
} }
@ -127,6 +134,20 @@ public class NamedQueryRepository {
this.namedSqlQueryDefinitionMap = Collections.unmodifiableMap( copy ); this.namedSqlQueryDefinitionMap = Collections.unmodifiableMap( copy );
} }
public synchronized void registerNamedProcedureCallMemento(String name, ProcedureCallMemento memento) {
final Map<String, ProcedureCallMemento> copy = CollectionHelper.makeCopy( procedureCallMementoMap );
final ProcedureCallMemento previous = copy.put( name, memento );
if ( previous != null ) {
log.debugf(
"registering named procedure call definition [%s] overriding previously registered definition [%s]",
name,
previous
);
}
this.procedureCallMementoMap = Collections.unmodifiableMap( copy );
}
public Map<String,HibernateException> checkNamedQueries(QueryPlanCache queryPlanCache) { public Map<String,HibernateException> checkNamedQueries(QueryPlanCache queryPlanCache) {
Map<String,HibernateException> errors = new HashMap<String,HibernateException>(); Map<String,HibernateException> errors = new HashMap<String,HibernateException>();

View File

@ -35,6 +35,7 @@ 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.Iterator;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
@ -82,6 +83,7 @@ import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment; import org.hibernate.cfg.Environment;
import org.hibernate.cfg.Settings; import org.hibernate.cfg.Settings;
import org.hibernate.cfg.SettingsFactory; import org.hibernate.cfg.SettingsFactory;
import org.hibernate.cfg.annotations.NamedProcedureCallDefinition;
import org.hibernate.context.internal.JTASessionContext; import org.hibernate.context.internal.JTASessionContext;
import org.hibernate.context.internal.ManagedSessionContext; import org.hibernate.context.internal.ManagedSessionContext;
import org.hibernate.context.internal.ThreadLocalSessionContext; import org.hibernate.context.internal.ThreadLocalSessionContext;
@ -133,6 +135,7 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable; import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.Queryable; import org.hibernate.persister.entity.Queryable;
import org.hibernate.persister.spi.PersisterFactory; import org.hibernate.persister.spi.PersisterFactory;
import org.hibernate.procedure.ProcedureCallMemento;
import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.ServiceRegistryImplementor;
@ -455,7 +458,8 @@ public final class SessionFactoryImpl
this.namedQueryRepository = new NamedQueryRepository( this.namedQueryRepository = new NamedQueryRepository(
cfg.getNamedQueries().values(), cfg.getNamedQueries().values(),
cfg.getNamedSQLQueries().values(), cfg.getNamedSQLQueries().values(),
cfg.getSqlResultSetMappings().values() cfg.getSqlResultSetMappings().values(),
toProcedureCallMementos( cfg.getNamedProcedureCallMap(), cfg.getSqlResultSetMappings() )
); );
imports = new HashMap<String,String>( cfg.getImports() ); imports = new HashMap<String,String>( cfg.getImports() );
@ -576,6 +580,18 @@ public final class SessionFactoryImpl
this.observer.sessionFactoryCreated( this ); this.observer.sessionFactoryCreated( this );
} }
private List<ProcedureCallMemento> toProcedureCallMementos(
Map<String, NamedProcedureCallDefinition> definitions,
Map<String, ResultSetMappingDefinition> resultSetMappingMap) {
final List<ProcedureCallMemento> rtn = new ArrayList<ProcedureCallMemento>();
if ( definitions != null ) {
for ( NamedProcedureCallDefinition definition : definitions.values() ) {
rtn.add( definition.toMemento( this, resultSetMappingMap ) );
}
}
return rtn;
}
private JdbcConnectionAccess buildLocalConnectionAccess() { private JdbcConnectionAccess buildLocalConnectionAccess() {
return new JdbcConnectionAccess() { return new JdbcConnectionAccess() {
@Override @Override
@ -854,7 +870,8 @@ public final class SessionFactoryImpl
namedQueryRepository = new NamedQueryRepository( namedQueryRepository = new NamedQueryRepository(
metadata.getNamedQueryDefinitions(), metadata.getNamedQueryDefinitions(),
metadata.getNamedNativeQueryDefinitions(), metadata.getNamedNativeQueryDefinitions(),
metadata.getResultSetMappingDefinitions() metadata.getResultSetMappingDefinitions(),
null
); );
imports = new HashMap<String,String>(); imports = new HashMap<String,String>();

View File

@ -27,6 +27,7 @@ import java.util.ArrayList;
import java.util.Collection; 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.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -131,6 +132,17 @@ public final class CollectionHelper {
return new ArrayList<T>( anticipatedSize ); return new ArrayList<T>( anticipatedSize );
} }
public static <T> Set<T> makeCopy(Set<T> source) {
if ( source == null ) {
return null;
}
final int size = source.size();
final Set<T> copy = new HashSet<T>( size + 1 );
copy.addAll( source );
return copy;
}
public static boolean isEmpty(Collection collection) { public static boolean isEmpty(Collection collection) {
return collection == null || collection.isEmpty(); return collection == null || collection.isEmpty();
} }

View File

@ -24,7 +24,10 @@
*/ */
package org.hibernate.loader.custom.sql; package org.hibernate.loader.custom.sql;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -56,9 +59,12 @@ import org.hibernate.loader.custom.NonScalarReturn;
import org.hibernate.loader.custom.Return; import org.hibernate.loader.custom.Return;
import org.hibernate.loader.custom.RootReturn; import org.hibernate.loader.custom.RootReturn;
import org.hibernate.loader.custom.ScalarReturn; import org.hibernate.loader.custom.ScalarReturn;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.SQLLoadableCollection; import org.hibernate.persister.collection.SQLLoadableCollection;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.entity.SQLLoadable; import org.hibernate.persister.entity.SQLLoadable;
import org.hibernate.type.AssociationType;
import org.hibernate.type.EntityType; import org.hibernate.type.EntityType;
import org.hibernate.type.Type; import org.hibernate.type.Type;
@ -84,10 +90,10 @@ public class SQLQueryReturnProcessor {
private final Map alias2Return = new HashMap(); private final Map alias2Return = new HashMap();
private final Map alias2OwnerAlias = new HashMap(); private final Map alias2OwnerAlias = new HashMap();
private final Map alias2Persister = new HashMap(); private final Map<String,EntityPersister> alias2Persister = new HashMap<String,EntityPersister>();
private final Map alias2Suffix = new HashMap(); private final Map alias2Suffix = new HashMap();
private final Map alias2CollectionPersister = new HashMap(); private final Map<String,CollectionPersister> alias2CollectionPersister = new HashMap<String,CollectionPersister>();
private final Map alias2CollectionSuffix = new HashMap(); private final Map alias2CollectionSuffix = new HashMap();
private final Map entityPropertyResultMaps = new HashMap(); private final Map entityPropertyResultMaps = new HashMap();
@ -112,7 +118,7 @@ public class SQLQueryReturnProcessor {
this.factory = factory; this.factory = factory;
} }
/*package*/ class ResultAliasContext { public class ResultAliasContext {
public SQLLoadable getEntityPersister(String alias) { public SQLLoadable getEntityPersister(String alias) {
return ( SQLLoadable ) alias2Persister.get( alias ); return ( SQLLoadable ) alias2Persister.get( alias );
} }
@ -136,6 +142,25 @@ public class SQLQueryReturnProcessor {
public Map getPropertyResultsMap(String alias) { public Map getPropertyResultsMap(String alias) {
return internalGetPropertyResultsMap( alias ); return internalGetPropertyResultsMap( alias );
} }
public String[] collectQuerySpaces() {
final HashSet<String> spaces = new HashSet<String>();
collectQuerySpaces( spaces );
return spaces.toArray( new String[ spaces.size() ] );
}
public void collectQuerySpaces(Collection<String> spaces) {
for ( EntityPersister persister : alias2Persister.values() ) {
Collections.addAll( spaces, (String[]) persister.getQuerySpaces() );
}
for ( CollectionPersister persister : alias2CollectionPersister.values() ) {
final Type elementType = persister.getElementType();
if ( elementType.isEntityType() && ! elementType.isAnyType() ) {
final Joinable joinable = ( (EntityType) elementType ).getAssociatedJoinable( factory );
Collections.addAll( spaces, (String[]) ( (EntityPersister) joinable ).getQuerySpaces() );
}
}
}
} }
private Map internalGetPropertyResultsMap(String alias) { private Map internalGetPropertyResultsMap(String alias) {

View File

@ -25,6 +25,7 @@ package org.hibernate.procedure;
import javax.persistence.ParameterMode; import javax.persistence.ParameterMode;
import java.util.List; import java.util.List;
import java.util.Map;
import org.hibernate.BasicQueryContract; import org.hibernate.BasicQueryContract;
import org.hibernate.MappingException; import org.hibernate.MappingException;
@ -58,6 +59,7 @@ public interface ProcedureCall extends BasicQueryContract, SynchronizeableQuery
* @param position The position * @param position The position
* @param type The Java type of the parameter * @param type The Java type of the parameter
* @param mode The parameter mode (in, out, inout) * @param mode The parameter mode (in, out, inout)
* @param <T> The parameterized Java type of the parameter.
* *
* @return The parameter registration memento * @return The parameter registration memento
*/ */
@ -89,8 +91,12 @@ public interface ProcedureCall extends BasicQueryContract, SynchronizeableQuery
* @param parameterName The parameter name * @param parameterName The parameter name
* @param type The Java type of the parameter * @param type The Java type of the parameter
* @param mode The parameter mode (in, out, inout) * @param mode The parameter mode (in, out, inout)
* @param <T> The parameterized Java type of the parameter.
* *
* @return The parameter registration memento * @return The parameter registration memento
*
* @throws NamedParametersNotSupportedException When the underlying database is known to not support
* named procedure parameters.
*/ */
public <T> ParameterRegistration<T> registerParameter(String parameterName, Class<T> type, ParameterMode mode) public <T> ParameterRegistration<T> registerParameter(String parameterName, Class<T> type, ParameterMode mode)
throws NamedParametersNotSupportedException; throws NamedParametersNotSupportedException;
@ -103,6 +109,9 @@ public interface ProcedureCall extends BasicQueryContract, SynchronizeableQuery
* @param mode The parameter mode (in, out, inout) * @param mode The parameter mode (in, out, inout)
* *
* @return The parameter registration memento * @return The parameter registration memento
*
* @throws NamedParametersNotSupportedException When the underlying database is known to not support
* named procedure parameters.
*/ */
public ProcedureCall registerParameter0(String parameterName, Class type, ParameterMode mode) public ProcedureCall registerParameter0(String parameterName, Class type, ParameterMode mode)
throws NamedParametersNotSupportedException; throws NamedParametersNotSupportedException;
@ -133,4 +142,12 @@ public interface ProcedureCall extends BasicQueryContract, SynchronizeableQuery
*/ */
public ProcedureResult getResult(); public ProcedureResult getResult();
/**
* Extract the disconnected representation of this call. Used in HEM to allow redefining a named query
*
* @param hints The hints to incorporate into the memento
*
* @return The memento
*/
public ProcedureCallMemento extractMemento(Map<String, Object> hints);
} }

View File

@ -0,0 +1,63 @@
/*
* 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
*/
package org.hibernate.procedure;
import java.util.Map;
import org.hibernate.Session;
import org.hibernate.engine.spi.SessionImplementor;
/**
* Represents a "memento" of a ProcedureCall
*
* @author Steve Ebersole
*/
public interface ProcedureCallMemento {
/**
* Convert the memento back into an executable (connected) form.
*
* @param session The session to connect the procedure call to
*
* @return The executable call
*/
public ProcedureCall makeProcedureCall(Session session);
/**
* Convert the memento back into an executable (connected) form.
*
* @param session The session to connect the procedure call to
*
* @return The executable call
*/
public ProcedureCall makeProcedureCall(SessionImplementor session);
/**
* Access to any hints associated with the memento.
* <p/>
* IMPL NOTE : exposed separately because only HEM needs access to this.
*
* @return The hints.
*/
public Map<String, Object> getHintsMap();
}

View File

@ -43,6 +43,8 @@ import org.hibernate.type.ProcedureParameterExtractionAware;
import org.hibernate.type.Type; import org.hibernate.type.Type;
/** /**
* Abstract implementation of ParameterRegistration/ParameterRegistrationImplementor
*
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public abstract class AbstractParameterRegistrationImpl<T> implements ParameterRegistrationImplementor<T> { public abstract class AbstractParameterRegistrationImpl<T> implements ParameterRegistrationImplementor<T> {
@ -62,28 +64,53 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
private Type hibernateType; private Type hibernateType;
private int[] sqlTypes; private int[] sqlTypes;
// positional constructors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
protected AbstractParameterRegistrationImpl( protected AbstractParameterRegistrationImpl(
ProcedureCallImpl procedureCall, ProcedureCallImpl procedureCall,
Integer position, Integer position,
ParameterMode mode,
Class<T> type) {
this( procedureCall, position, null, mode, type );
}
protected AbstractParameterRegistrationImpl(
ProcedureCallImpl procedureCall,
Integer position,
ParameterMode mode,
Class<T> type, Class<T> type,
ParameterMode mode) { Type hibernateType) {
this( procedureCall, position, null, type, mode ); this( procedureCall, position, null, mode, type, hibernateType );
}
// named constructors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
protected AbstractParameterRegistrationImpl(
ProcedureCallImpl procedureCall,
String name,
ParameterMode mode,
Class<T> type) {
this( procedureCall, null, name, mode, type );
} }
protected AbstractParameterRegistrationImpl( protected AbstractParameterRegistrationImpl(
ProcedureCallImpl procedureCall, ProcedureCallImpl procedureCall,
String name, String name,
ParameterMode mode,
Class<T> type, Class<T> type,
ParameterMode mode) { Type hibernateType) {
this( procedureCall, null, name, type, mode ); this( procedureCall, null, name, mode, type, hibernateType );
} }
private AbstractParameterRegistrationImpl( private AbstractParameterRegistrationImpl(
ProcedureCallImpl procedureCall, ProcedureCallImpl procedureCall,
Integer position, Integer position,
String name, String name,
ParameterMode mode,
Class<T> type, Class<T> type,
ParameterMode mode) { Type hibernateType) {
this.procedureCall = procedureCall; this.procedureCall = procedureCall;
this.position = position; this.position = position;
@ -92,7 +119,23 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
this.mode = mode; this.mode = mode;
this.type = type; this.type = type;
setHibernateType( session().getFactory().getTypeResolver().heuristicType( type.getName() ) ); setHibernateType( hibernateType );
}
private AbstractParameterRegistrationImpl(
ProcedureCallImpl procedureCall,
Integer position,
String name,
ParameterMode mode,
Class<T> type) {
this(
procedureCall,
position,
name,
mode,
type,
procedureCall.getSession().getFactory().getTypeResolver().heuristicType( type.getName() )
);
} }
protected SessionImplementor session() { protected SessionImplementor session() {
@ -119,6 +162,11 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
return mode; return mode;
} }
@Override
public Type getHibernateType() {
return hibernateType;
}
@Override @Override
public void setHibernateType(Type type) { public void setHibernateType(Type type) {
if ( type == null ) { if ( type == null ) {
@ -129,6 +177,7 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
} }
@Override @Override
@SuppressWarnings("unchecked")
public ParameterBind<T> getBind() { public ParameterBind<T> getBind() {
return bind; return bind;
} }
@ -175,11 +224,12 @@ public abstract class AbstractParameterRegistrationImpl<T> implements ParameterR
if ( mode == ParameterMode.IN || mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) { if ( mode == ParameterMode.IN || mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) {
if ( mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) { if ( mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) {
if ( sqlTypes.length > 1 ) { if ( sqlTypes.length > 1 ) {
if ( ProcedureParameterExtractionAware.class.isInstance( hibernateType ) // there is more than one column involved; see if the Hibernate Type can handle
&& ( (ProcedureParameterExtractionAware) hibernateType ).canDoExtraction() ) { // multi-param extraction...
// the type can handle multi-param extraction... final boolean canHandleMultiParamExtraction =
} ProcedureParameterExtractionAware.class.isInstance( hibernateType )
else { && ( (ProcedureParameterExtractionAware) hibernateType ).canDoExtraction();
if ( ! canHandleMultiParamExtraction ) {
// it cannot... // it cannot...
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"Type [" + hibernateType + "] does support multi-parameter value extraction" "Type [" + hibernateType + "] does support multi-parameter value extraction"

View File

@ -25,15 +25,28 @@ package org.hibernate.procedure.internal;
import javax.persistence.ParameterMode; import javax.persistence.ParameterMode;
import org.hibernate.type.Type;
/** /**
* Represents a registered named parameter
*
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class NamedParameterRegistration<T> extends AbstractParameterRegistrationImpl<T> { public class NamedParameterRegistration<T> extends AbstractParameterRegistrationImpl<T> {
public NamedParameterRegistration( NamedParameterRegistration(
ProcedureCallImpl procedureCall, ProcedureCallImpl procedureCall,
String name, String name,
ParameterMode mode,
Class<T> type) {
super( procedureCall, name, mode, type );
}
NamedParameterRegistration(
ProcedureCallImpl procedureCall,
String name,
ParameterMode mode,
Class<T> type, Class<T> type,
ParameterMode mode) { Type hibernateType) {
super( procedureCall, name, type, mode ); super( procedureCall, name, mode, type, hibernateType );
} }
} }

View File

@ -27,15 +27,45 @@ import java.sql.CallableStatement;
import java.sql.SQLException; import java.sql.SQLException;
import org.hibernate.procedure.ParameterRegistration; import org.hibernate.procedure.ParameterRegistration;
import org.hibernate.type.Type;
/** /**
* Additional internal contract for ParameterRegistration
*
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface ParameterRegistrationImplementor<T> extends ParameterRegistration<T> { public interface ParameterRegistrationImplementor<T> extends ParameterRegistration<T> {
/**
* Prepare for execution.
*
* @param statement The statement about to be executed
* @param i The parameter index for this registration (used for positional)
*
* @throws SQLException Indicates a problem accessing the statement object
*/
public void prepare(CallableStatement statement, int i) throws SQLException; public void prepare(CallableStatement statement, int i) throws SQLException;
/**
* Access to the Hibernate type for this parameter registration
*
* @return The Hibernate Type
*/
public Type getHibernateType();
/**
* Access to the SQL type(s) for this parameter
*
* @return The SQL types (JDBC type codes)
*/
public int[] getSqlTypes(); public int[] getSqlTypes();
/**
* Extract value from the statement after execution (used for OUT/INOUT parameters).
*
* @param statement The callable statement
*
* @return The extracted value
*/
public T extract(CallableStatement statement); public T extract(CallableStatement statement);
} }

View File

@ -27,7 +27,16 @@ package org.hibernate.procedure.internal;
* The style/strategy of parameter registration used in a particular procedure call definition. * The style/strategy of parameter registration used in a particular procedure call definition.
*/ */
public enum ParameterStrategy { public enum ParameterStrategy {
/**
* The parameters are named
*/
NAMED, NAMED,
/**
* The parameters are positional
*/
POSITIONAL, POSITIONAL,
/**
* We do not (yet) know
*/
UNKNOWN UNKNOWN
} }

View File

@ -25,15 +25,28 @@ package org.hibernate.procedure.internal;
import javax.persistence.ParameterMode; import javax.persistence.ParameterMode;
import org.hibernate.type.Type;
/** /**
* Represents a registered positional parameter
*
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class PositionalParameterRegistration<T> extends AbstractParameterRegistrationImpl<T> { public class PositionalParameterRegistration<T> extends AbstractParameterRegistrationImpl<T> {
public PositionalParameterRegistration( PositionalParameterRegistration(
ProcedureCallImpl procedureCall, ProcedureCallImpl procedureCall,
Integer position, Integer position,
ParameterMode mode,
Class<T> type) {
super( procedureCall, position, mode, type );
}
PositionalParameterRegistration(
ProcedureCallImpl procedureCall,
Integer position,
ParameterMode mode,
Class<T> type, Class<T> type,
ParameterMode mode) { Type hibernateType) {
super( procedureCall, position, type, mode ); super( procedureCall, position, mode, type, hibernateType );
} }
} }

View File

@ -31,25 +31,28 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.QueryException; import org.hibernate.QueryException;
import org.hibernate.cfg.NotYetImplementedException; import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.jdbc.spi.ExtractedDatabaseMetaData; import org.hibernate.engine.jdbc.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn; import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryRootReturn;
import org.hibernate.engine.spi.QueryParameters; import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.AbstractBasicQueryContractImpl; import org.hibernate.internal.AbstractBasicQueryContractImpl;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.NamedParametersNotSupportedException; import org.hibernate.procedure.NamedParametersNotSupportedException;
import org.hibernate.procedure.ParameterRegistration; import org.hibernate.procedure.ParameterRegistration;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.ProcedureCallMemento;
import org.hibernate.procedure.ProcedureResult; import org.hibernate.procedure.ProcedureResult;
import org.hibernate.result.spi.ResultContext; import org.hibernate.result.spi.ResultContext;
import org.hibernate.type.Type; import org.hibernate.type.Type;
@ -60,6 +63,10 @@ import org.hibernate.type.Type;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements ProcedureCall, ResultContext { public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements ProcedureCall, ResultContext {
private static final Logger log = Logger.getLogger( ProcedureCallImpl.class );
private static final NativeSQLQueryReturn[] NO_RETURNS = new NativeSQLQueryReturn[0];
private final String procedureName; private final String procedureName;
private final NativeSQLQueryReturn[] queryReturns; private final NativeSQLQueryReturn[] queryReturns;
@ -70,74 +77,167 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
private ProcedureResultImpl outputs; private ProcedureResultImpl outputs;
/**
@SuppressWarnings("unchecked") * The no-returns form.
*
* @param session The session
* @param procedureName The name of the procedure to call
*/
public ProcedureCallImpl(SessionImplementor session, String procedureName) { public ProcedureCallImpl(SessionImplementor session, String procedureName) {
this( session, procedureName, (List) null ); super( session );
this.procedureName = procedureName;
this.queryReturns = NO_RETURNS;
} }
public ProcedureCallImpl(SessionImplementor session, String procedureName, List<NativeSQLQueryReturn> queryReturns) { /**
* The result Class(es) return form
*
* @param session The session
* @param procedureName The name of the procedure to call
* @param resultClasses The classes making up the result
*/
public ProcedureCallImpl(final SessionImplementor session, String procedureName, Class... resultClasses) {
super( session ); super( session );
this.procedureName = procedureName; this.procedureName = procedureName;
if ( queryReturns == null || queryReturns.isEmpty() ) { final List<NativeSQLQueryReturn> collectedQueryReturns = new ArrayList<NativeSQLQueryReturn>();
this.queryReturns = new NativeSQLQueryReturn[0]; final Set<String> collectedQuerySpaces = new HashSet<String>();
Util.resolveResultClasses(
new Util.ResultClassesResolutionContext() {
@Override
public SessionFactoryImplementor getSessionFactory() {
return session.getFactory();
}
@Override
public void addQueryReturns(NativeSQLQueryReturn... queryReturns) {
Collections.addAll( collectedQueryReturns, queryReturns );
}
@Override
public void addQuerySpaces(String... spaces) {
Collections.addAll( collectedQuerySpaces, spaces );
}
},
resultClasses
);
this.queryReturns = collectedQueryReturns.toArray( new NativeSQLQueryReturn[ collectedQueryReturns.size() ] );
this.synchronizedQuerySpaces = collectedQuerySpaces;
}
/**
* The result-set-mapping(s) return form
*
* @param session The session
* @param procedureName The name of the procedure to call
* @param resultSetMappings The names of the result set mappings making up the result
*/
public ProcedureCallImpl(final SessionImplementor session, String procedureName, String... resultSetMappings) {
super( session );
this.procedureName = procedureName;
final List<NativeSQLQueryReturn> collectedQueryReturns = new ArrayList<NativeSQLQueryReturn>();
final Set<String> collectedQuerySpaces = new HashSet<String>();
Util.resolveResultSetMappings(
new Util.ResultSetMappingResolutionContext() {
@Override
public SessionFactoryImplementor getSessionFactory() {
return session.getFactory();
}
@Override
public ResultSetMappingDefinition findResultSetMapping(String name) {
return session.getFactory().getResultSetMapping( name );
}
@Override
public void addQueryReturns(NativeSQLQueryReturn... queryReturns) {
Collections.addAll( collectedQueryReturns, queryReturns );
}
@Override
public void addQuerySpaces(String... spaces) {
Collections.addAll( collectedQuerySpaces, spaces );
}
},
resultSetMappings
);
this.queryReturns = collectedQueryReturns.toArray( new NativeSQLQueryReturn[ collectedQueryReturns.size() ] );
this.synchronizedQuerySpaces = collectedQuerySpaces;
}
/**
* The named/stored copy constructor
*
* @param session The session
* @param memento The named/stored memento
*/
@SuppressWarnings("unchecked")
ProcedureCallImpl(SessionImplementor session, ProcedureCallMementoImpl memento) {
super( session );
this.procedureName = memento.getProcedureName();
this.queryReturns = memento.getQueryReturns();
this.synchronizedQuerySpaces = Util.copy( memento.getSynchronizedQuerySpaces() );
this.parameterStrategy = memento.getParameterStrategy();
if ( parameterStrategy == ParameterStrategy.UNKNOWN ) {
// nothing else to do in this case
return;
}
final List<ProcedureCallMementoImpl.ParameterMemento> storedRegistrations = memento.getParameterDeclarations();
if ( storedRegistrations == null ) {
// most likely a problem if ParameterStrategy is not UNKNOWN...
log.debugf(
"ParameterStrategy was [%s] on named copy [%s], but no parameters stored",
parameterStrategy,
procedureName
);
return;
}
final List<ParameterRegistrationImplementor<?>> parameterRegistrations =
CollectionHelper.arrayList( storedRegistrations.size() );
for ( ProcedureCallMementoImpl.ParameterMemento storedRegistration : storedRegistrations ) {
final ParameterRegistrationImplementor<?> registration;
if ( StringHelper.isNotEmpty( storedRegistration.getName() ) ) {
if ( parameterStrategy != ParameterStrategy.NAMED ) {
throw new IllegalStateException(
"Found named stored procedure parameter associated with positional parameters"
);
}
registration = new NamedParameterRegistration(
this,
storedRegistration.getName(),
storedRegistration.getMode(),
storedRegistration.getType(),
storedRegistration.getHibernateType()
);
} }
else { else {
this.queryReturns = queryReturns.toArray( new NativeSQLQueryReturn[ queryReturns.size() ] ); if ( parameterStrategy != ParameterStrategy.POSITIONAL ) {
throw new IllegalStateException(
"Found named stored procedure parameter associated with positional parameters"
);
} }
registration = new PositionalParameterRegistration(
this,
storedRegistration.getPosition(),
storedRegistration.getMode(),
storedRegistration.getType(),
storedRegistration.getHibernateType()
);
} }
parameterRegistrations.add( registration );
public ProcedureCallImpl(SessionImplementor session, String procedureName, Class... resultClasses) {
this( session, procedureName, collectQueryReturns( resultClasses ) );
} }
this.registeredParameters = parameterRegistrations;
private static List<NativeSQLQueryReturn> collectQueryReturns(Class[] resultClasses) {
if ( resultClasses == null || resultClasses.length == 0 ) {
return null;
} }
List<NativeSQLQueryReturn> queryReturns = new ArrayList<NativeSQLQueryReturn>( resultClasses.length );
int i = 1;
for ( Class resultClass : resultClasses ) {
queryReturns.add( new NativeSQLQueryRootReturn( "alias" + i, resultClass.getName(), LockMode.READ ) );
i++;
}
return queryReturns;
}
public ProcedureCallImpl(SessionImplementor session, String procedureName, String... resultSetMappings) {
this( session, procedureName, collectQueryReturns( session, resultSetMappings ) );
}
private static List<NativeSQLQueryReturn> collectQueryReturns(SessionImplementor session, String[] resultSetMappings) {
if ( resultSetMappings == null || resultSetMappings.length == 0 ) {
return null;
}
List<NativeSQLQueryReturn> queryReturns = new ArrayList<NativeSQLQueryReturn>( resultSetMappings.length );
for ( String resultSetMapping : resultSetMappings ) {
ResultSetMappingDefinition mapping = session.getFactory().getResultSetMapping( resultSetMapping );
if ( mapping == null ) {
throw new MappingException( "Unknown SqlResultSetMapping [" + resultSetMapping + "]" );
}
queryReturns.addAll( Arrays.asList( mapping.getQueryReturns() ) );
}
return queryReturns;
}
// public ProcedureCallImpl(
// SessionImplementor session,
// String procedureName,
// List<StoredProcedureParameter> parameters) {
// // this form is intended for named stored procedure calls.
// // todo : introduce a NamedProcedureCallDefinition object to hold all needed info and pass that in here; will help with EM.addNamedQuery as well..
// this( session, procedureName );
// for ( StoredProcedureParameter parameter : parameters ) {
// registerParameter( (StoredProcedureParameterImplementor) parameter );
// }
// }
@Override @Override
public SessionImplementor getSession() { public SessionImplementor getSession() {
return super.session(); return super.session();
@ -165,7 +265,8 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> ParameterRegistration<T> registerParameter(int position, Class<T> type, ParameterMode mode) { public <T> ParameterRegistration<T> registerParameter(int position, Class<T> type, ParameterMode mode) {
final PositionalParameterRegistration parameterRegistration = new PositionalParameterRegistration( this, position, type, mode ); final PositionalParameterRegistration parameterRegistration =
new PositionalParameterRegistration( this, position, mode, type );
registerParameter( parameterRegistration ); registerParameter( parameterRegistration );
return parameterRegistration; return parameterRegistration;
} }
@ -233,7 +334,8 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> ParameterRegistration<T> registerParameter(String name, Class<T> type, ParameterMode mode) { public <T> ParameterRegistration<T> registerParameter(String name, Class<T> type, ParameterMode mode) {
final NamedParameterRegistration parameterRegistration = new NamedParameterRegistration( this, name, type, mode ); final NamedParameterRegistration parameterRegistration
= new NamedParameterRegistration( this, name, mode, type );
registerParameter( parameterRegistration ); registerParameter( parameterRegistration );
return parameterRegistration; return parameterRegistration;
} }
@ -329,6 +431,12 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
throw new NotYetImplementedException(); throw new NotYetImplementedException();
} }
/**
* Use this form instead of {@link #getSynchronizedQuerySpaces()} when you want to make sure the
* underlying Set is instantiated (aka, on add)
*
* @return The spaces
*/
protected Set<String> synchronizedQuerySpaces() { protected Set<String> synchronizedQuerySpaces() {
if ( synchronizedQuerySpaces == null ) { if ( synchronizedQuerySpaces == null ) {
synchronizedQuerySpaces = new HashSet<String>(); synchronizedQuerySpaces = new HashSet<String>();
@ -374,6 +482,7 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
return buildQueryParametersObject(); return buildQueryParametersObject();
} }
@Override
public QueryParameters buildQueryParametersObject() { public QueryParameters buildQueryParametersObject() {
QueryParameters qp = super.buildQueryParametersObject(); QueryParameters qp = super.buildQueryParametersObject();
// both of these are for documentation purposes, they are actually handled directly... // both of these are for documentation purposes, they are actually handled directly...
@ -382,8 +491,13 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
return qp; return qp;
} }
/**
* Collects any parameter registrations which indicate a REF_CURSOR parameter type/mode.
*
* @return The collected REF_CURSOR type parameters.
*/
public ParameterRegistrationImplementor[] collectRefCursorParameters() { public ParameterRegistrationImplementor[] collectRefCursorParameters() {
List<ParameterRegistrationImplementor> refCursorParams = new ArrayList<ParameterRegistrationImplementor>(); final List<ParameterRegistrationImplementor> refCursorParams = new ArrayList<ParameterRegistrationImplementor>();
for ( ParameterRegistrationImplementor param : registeredParameters ) { for ( ParameterRegistrationImplementor param : registeredParameters ) {
if ( param.getMode() == ParameterMode.REF_CURSOR ) { if ( param.getMode() == ParameterMode.REF_CURSOR ) {
refCursorParams.add( param ); refCursorParams.add( param );
@ -391,4 +505,29 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
} }
return refCursorParams.toArray( new ParameterRegistrationImplementor[refCursorParams.size()] ); return refCursorParams.toArray( new ParameterRegistrationImplementor[refCursorParams.size()] );
} }
@Override
public ProcedureCallMemento extractMemento(Map<String, Object> hints) {
return new ProcedureCallMementoImpl(
procedureName,
Util.copy( queryReturns ),
parameterStrategy,
toParameterMementos( registeredParameters ),
Util.copy( synchronizedQuerySpaces ),
Util.copy( hints )
);
}
private static List<ProcedureCallMementoImpl.ParameterMemento> toParameterMementos(List<ParameterRegistrationImplementor<?>> registeredParameters) {
if ( registeredParameters == null ) {
return null;
}
final List<ProcedureCallMementoImpl.ParameterMemento> copy = CollectionHelper.arrayList( registeredParameters.size() );
for ( ParameterRegistrationImplementor registration : registeredParameters ) {
copy.add( ProcedureCallMementoImpl.ParameterMemento.fromRegistration( registration ) );
}
return copy;
}
} }

View File

@ -0,0 +1,169 @@
/*
* 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
*/
package org.hibernate.procedure.internal;
import javax.persistence.ParameterMode;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.ProcedureCallMemento;
import org.hibernate.type.Type;
/**
* Implementation of ProcedureCallMemento
*
* @author Steve Ebersole
*/
public class ProcedureCallMementoImpl implements ProcedureCallMemento {
private final String procedureName;
private final NativeSQLQueryReturn[] queryReturns;
private final ParameterStrategy parameterStrategy;
private final List<ParameterMemento> parameterDeclarations;
private final Set<String> synchronizedQuerySpaces;
private final Map<String,Object> hintsMap;
public ProcedureCallMementoImpl(
String procedureName,
NativeSQLQueryReturn[] queryReturns,
ParameterStrategy parameterStrategy,
List<ParameterMemento> parameterDeclarations,
Set<String> synchronizedQuerySpaces,
Map<String,Object> hintsMap) {
this.procedureName = procedureName;
this.queryReturns = queryReturns;
this.parameterStrategy = parameterStrategy;
this.parameterDeclarations = parameterDeclarations;
this.synchronizedQuerySpaces = synchronizedQuerySpaces;
this.hintsMap = hintsMap;
}
@Override
public ProcedureCall makeProcedureCall(Session session) {
return new ProcedureCallImpl( (SessionImplementor) session, this );
}
@Override
public ProcedureCall makeProcedureCall(SessionImplementor session) {
return new ProcedureCallImpl( session, this );
}
public String getProcedureName() {
return procedureName;
}
public NativeSQLQueryReturn[] getQueryReturns() {
return queryReturns;
}
public ParameterStrategy getParameterStrategy() {
return parameterStrategy;
}
public List<ParameterMemento> getParameterDeclarations() {
return parameterDeclarations;
}
public Set<String> getSynchronizedQuerySpaces() {
return synchronizedQuerySpaces;
}
@Override
public Map<String, Object> getHintsMap() {
return hintsMap;
}
/**
* A "disconnected" copy of the metadata for a parameter, that can be used in ProcedureCallMementoImpl.
*/
public static class ParameterMemento {
private final Integer position;
private final String name;
private final ParameterMode mode;
private final Class type;
private final Type hibernateType;
/**
* Create the memento
*
* @param position The parameter position
* @param name The parameter name
* @param mode The parameter mode
* @param type The Java type of the parameter
* @param hibernateType The Hibernate Type.
*/
public ParameterMemento(int position, String name, ParameterMode mode, Class type, Type hibernateType) {
this.position = position;
this.name = name;
this.mode = mode;
this.type = type;
this.hibernateType = hibernateType;
}
public Integer getPosition() {
return position;
}
public String getName() {
return name;
}
public ParameterMode getMode() {
return mode;
}
public Class getType() {
return type;
}
public Type getHibernateType() {
return hibernateType;
}
/**
* Build a ParameterMemento from the given parameter registration
*
* @param registration The parameter registration from a ProcedureCall
*
* @return The memento
*/
public static ParameterMemento fromRegistration(ParameterRegistrationImplementor registration) {
return new ParameterMemento(
registration.getPosition(),
registration.getName(),
registration.getMode(),
registration.getType(),
registration.getHibernateType()
);
}
}
}

View File

@ -0,0 +1,116 @@
/*
* 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
*/
package org.hibernate.procedure.internal;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryRootReturn;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.loader.custom.sql.SQLQueryReturnProcessor;
import org.hibernate.persister.entity.EntityPersister;
/**
* @author Steve Ebersole
*/
public class Util {
private Util() {
}
/**
* Makes a copy of the given query return array.
*
* @param queryReturns The returns to copy
*
* @return The copy
*/
static NativeSQLQueryReturn[] copy(NativeSQLQueryReturn[] queryReturns) {
if ( queryReturns == null ) {
return new NativeSQLQueryReturn[0];
}
final NativeSQLQueryReturn[] copy = new NativeSQLQueryReturn[ queryReturns.length ];
System.arraycopy( queryReturns, 0, copy, 0, queryReturns.length );
return copy;
}
public static Set<String> copy(Set<String> synchronizedQuerySpaces) {
return CollectionHelper.makeCopy( synchronizedQuerySpaces );
}
public static Map<String,Object> copy(Map<String, Object> hints) {
return CollectionHelper.makeCopy( hints );
}
public static interface ResultSetMappingResolutionContext {
public SessionFactoryImplementor getSessionFactory();
public ResultSetMappingDefinition findResultSetMapping(String name);
public void addQueryReturns(NativeSQLQueryReturn... queryReturns);
public void addQuerySpaces(String... spaces);
}
public static void resolveResultSetMappings(ResultSetMappingResolutionContext context, String... resultSetMappingNames) {
for ( String resultSetMappingName : resultSetMappingNames ) {
final ResultSetMappingDefinition mapping = context.findResultSetMapping( resultSetMappingName );
if ( mapping == null ) {
throw new MappingException( "Unknown SqlResultSetMapping [" + resultSetMappingName + "]" );
}
context.addQueryReturns( mapping.getQueryReturns() );
final SQLQueryReturnProcessor processor =
new SQLQueryReturnProcessor( mapping.getQueryReturns(), context.getSessionFactory() );
final SQLQueryReturnProcessor.ResultAliasContext processResult = processor.process();
context.addQuerySpaces( processResult.collectQuerySpaces() );
}
}
public static interface ResultClassesResolutionContext {
public SessionFactoryImplementor getSessionFactory();
public void addQueryReturns(NativeSQLQueryReturn... queryReturns);
public void addQuerySpaces(String... spaces);
}
public static void resolveResultClasses(ResultClassesResolutionContext context, Class... resultClasses) {
int i = 1;
for ( Class resultClass : resultClasses ) {
context.addQueryReturns(
new NativeSQLQueryRootReturn( "alias" + i, resultClass.getName(), LockMode.READ )
);
try {
final EntityPersister persister = context.getSessionFactory().getEntityPersister( resultClass.getName() );
context.addQuerySpaces( (String[]) persister.getQuerySpaces() );
}
catch (Exception ignore) {
}
}
}
}

View File

@ -75,6 +75,7 @@ import org.hibernate.jpa.internal.metamodel.MetamodelImpl;
import org.hibernate.jpa.internal.util.PersistenceUtilHelper; import org.hibernate.jpa.internal.util.PersistenceUtilHelper;
import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PersistentClass;
import org.hibernate.metadata.ClassMetadata; import org.hibernate.metadata.ClassMetadata;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
/** /**
@ -284,19 +285,25 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
throw new IllegalStateException( "EntityManagerFactory is closed" ); throw new IllegalStateException( "EntityManagerFactory is closed" );
} }
if ( ! HibernateQuery.class.isInstance( query ) ) { if ( StoredProcedureQueryImpl.class.isInstance( query ) ) {
final ProcedureCall procedureCall = ( (StoredProcedureQueryImpl) query ).getHibernateProcedureCall();
sessionFactory.getNamedQueryRepository().registerNamedProcedureCallMemento( name, procedureCall.extractMemento( query.getHints() ) );
}
else if ( ! HibernateQuery.class.isInstance( query ) ) {
throw new PersistenceException( "Cannot use query non-Hibernate EntityManager query as basis for named query" ); throw new PersistenceException( "Cannot use query non-Hibernate EntityManager query as basis for named query" );
} }
else {
// create and register the proper NamedQueryDefinition... // create and register the proper NamedQueryDefinition...
final org.hibernate.Query hibernateQuery = ( (HibernateQuery) query ).getHibernateQuery(); final org.hibernate.Query hibernateQuery = ( (HibernateQuery) query ).getHibernateQuery();
if ( org.hibernate.SQLQuery.class.isInstance( hibernateQuery ) ) { if ( org.hibernate.SQLQuery.class.isInstance( hibernateQuery ) ) {
final NamedSQLQueryDefinition namedQueryDefinition = extractSqlQueryDefinition( ( org.hibernate.SQLQuery ) hibernateQuery, name ); sessionFactory.registerNamedSQLQueryDefinition(
sessionFactory.registerNamedSQLQueryDefinition( name, namedQueryDefinition ); name,
extractSqlQueryDefinition( (org.hibernate.SQLQuery) hibernateQuery, name )
);
} }
else { else {
final NamedQueryDefinition namedQueryDefinition = extractHqlQueryDefinition( hibernateQuery, name ); sessionFactory.registerNamedQueryDefinition( name, extractHqlQueryDefinition( hibernateQuery, name ) );
sessionFactory.registerNamedQueryDefinition( name, namedQueryDefinition ); }
} }
} }

View File

@ -298,6 +298,10 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
return false; return false;
} }
public ProcedureCall getHibernateProcedureCall() {
return procedureCall;
}
private static class ParameterRegistrationImpl<T> implements ParameterRegistration<T> { private static class ParameterRegistrationImpl<T> implements ParameterRegistration<T> {
private final org.hibernate.procedure.ParameterRegistration<T> nativeParamRegistration; private final org.hibernate.procedure.ParameterRegistration<T> nativeParamRegistration;

View File

@ -124,6 +124,7 @@ import org.hibernate.jpa.internal.TransactionImpl;
import org.hibernate.jpa.internal.util.CacheModeHelper; import org.hibernate.jpa.internal.util.CacheModeHelper;
import org.hibernate.jpa.internal.util.ConfigurationHelper; import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.jpa.internal.util.LockModeTypeHelper; import org.hibernate.jpa.internal.util.LockModeTypeHelper;
import org.hibernate.procedure.ProcedureCallMemento;
import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.HibernateProxy;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.transform.BasicTransformerAdapter; import org.hibernate.transform.BasicTransformerAdapter;
@ -820,7 +821,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
public Query createNativeQuery(String sqlString, String resultSetMapping) { public Query createNativeQuery(String sqlString, String resultSetMapping) {
checkOpen(); checkOpen();
try { try {
SQLQuery q = internalGetSession().createSQLQuery( sqlString ); final SQLQuery q = internalGetSession().createSQLQuery( sqlString );
q.setResultSetMapping( resultSetMapping ); q.setResultSetMapping( resultSetMapping );
return new QueryImpl( q, this ); return new QueryImpl( q, this );
} }
@ -832,15 +833,30 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
@Override @Override
public StoredProcedureQuery createNamedStoredProcedureQuery(String name) { public StoredProcedureQuery createNamedStoredProcedureQuery(String name) {
checkOpen(); checkOpen();
throw new NotYetImplementedException(); final ProcedureCallMemento memento = ( (SessionImplementor) internalGetSession() ).getFactory()
.getNamedQueryRepository().getNamedProcedureCallMemento( name );
if ( memento == null ) {
throw new IllegalArgumentException( "No @NamedStoredProcedureQuery was found with that name : " + name );
}
final ProcedureCall procedureCall = memento.makeProcedureCall( internalGetSession() );
final StoredProcedureQueryImpl jpaImpl = new StoredProcedureQueryImpl( procedureCall, this );
// apply hints
if ( memento.getHintsMap() != null ) {
for ( Map.Entry<String,Object> hintEntry : memento.getHintsMap().entrySet() ) {
jpaImpl.setHint( hintEntry.getKey(), hintEntry.getValue() );
}
}
return jpaImpl;
} }
@Override @Override
public StoredProcedureQuery createStoredProcedureQuery(String procedureName) { public StoredProcedureQuery createStoredProcedureQuery(String procedureName) {
checkOpen(); checkOpen();
try { try {
ProcedureCall procedureCall = internalGetSession().createStoredProcedureCall( procedureName ); return new StoredProcedureQueryImpl(
return new StoredProcedureQueryImpl( procedureCall, this ); internalGetSession().createStoredProcedureCall( procedureName ),
this
);
} }
catch ( HibernateException he ) { catch ( HibernateException he ) {
throw convert( he ); throw convert( he );
@ -851,8 +867,10 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) { public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) {
checkOpen(); checkOpen();
try { try {
ProcedureCall procedureCall = internalGetSession().createStoredProcedureCall( procedureName, resultClasses ); return new StoredProcedureQueryImpl(
return new StoredProcedureQueryImpl( procedureCall, this ); internalGetSession().createStoredProcedureCall( procedureName, resultClasses ),
this
);
} }
catch ( HibernateException he ) { catch ( HibernateException he ) {
throw convert( he ); throw convert( he );
@ -862,7 +880,15 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
@Override @Override
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) { public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) {
checkOpen(); checkOpen();
throw new NotYetImplementedException(); try {
return new StoredProcedureQueryImpl(
internalGetSession().createStoredProcedureCall( procedureName, resultSetMappings ),
this
);
}
catch ( HibernateException he ) {
throw convert( he );
}
} }
@Override @Override