HHH-7387 - Integrate Draft 6 of the JPA 2.1 spec : stored procedure queries
This commit is contained in:
parent
4174c14675
commit
153eb4a913
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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;
|
||||
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* Defines the aspects of query definition that apply to all forms of querying.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface BasicQueryContract {
|
||||
/**
|
||||
* Obtain the FlushMode in effect for this query. By default, the query inherits the FlushMode of the Session
|
||||
* from which is originates.
|
||||
*
|
||||
* @return The query FlushMode.
|
||||
*
|
||||
* @see Session#getFlushMode()
|
||||
* @see FlushMode
|
||||
*/
|
||||
public FlushMode getFlushMode();
|
||||
|
||||
/**
|
||||
* (Re)set the current FlushMode in effect for this query.
|
||||
*
|
||||
* @param flushMode The new FlushMode to use.
|
||||
*
|
||||
* @see #getFlushMode()
|
||||
*/
|
||||
public BasicQueryContract setFlushMode(FlushMode flushMode);
|
||||
|
||||
/**
|
||||
* Obtain the CacheMode in effect for this query. By default, the query inherits the CacheMode of the Session
|
||||
* from which is originates.
|
||||
*
|
||||
* NOTE: The CacheMode here only effects reading/writing of the query cache, not the
|
||||
* entity/collection caches.
|
||||
*
|
||||
* @return The query CacheMode.
|
||||
*
|
||||
* @see Session#getCacheMode()
|
||||
* @see CacheMode
|
||||
*/
|
||||
public CacheMode getCacheMode();
|
||||
|
||||
/**
|
||||
* (Re)set the current CacheMode in effect for this query.
|
||||
*
|
||||
* @param cacheMode The new CacheMode to use.
|
||||
*
|
||||
* @see #getCacheMode()
|
||||
*/
|
||||
public BasicQueryContract setCacheMode(CacheMode cacheMode);
|
||||
|
||||
/**
|
||||
* Are the results of this query eligible for second level query caching? This is different that second level
|
||||
* caching of any returned entities and collections.
|
||||
*
|
||||
* NOTE: the query being "eligible" for caching does not necessarily mean its results will be cached. Second level
|
||||
* query caching still has to be enabled on the {@link SessionFactory} for this to happen. Usually that is
|
||||
* controlled by the {@code hibernate.cache.use_query_cache} configuration setting.
|
||||
*
|
||||
* @return {@code true} if the query results are eligible for caching, {@code false} otherwise.
|
||||
*
|
||||
* @see org.hibernate.cfg.AvailableSettings#USE_QUERY_CACHE
|
||||
*/
|
||||
public boolean isCacheable();
|
||||
|
||||
/**
|
||||
* Enable/disable second level query (result) caching for this query.
|
||||
*
|
||||
* @param cacheable Should the query results be cacheable?
|
||||
*
|
||||
* @see #isCacheable
|
||||
*/
|
||||
public BasicQueryContract setCacheable(boolean cacheable);
|
||||
|
||||
/**
|
||||
* Obtain the name of the second level query cache region in which query results will be stored (if they are
|
||||
* cached, see the discussion on {@link #isCacheable()} for more information). {@code null} indicates that the
|
||||
* default region should be used.
|
||||
*
|
||||
* @return The specified cache region name into which query results should be placed; {@code null} indicates
|
||||
* the default region.
|
||||
*/
|
||||
public String getCacheRegion();
|
||||
|
||||
/**
|
||||
* Set the name of the cache region where query results should be cached (if cached at all).
|
||||
*
|
||||
* @param cacheRegion the name of a query cache region, or {@code null} to indicate that the default region
|
||||
* should be used.
|
||||
*
|
||||
* @see #getCacheRegion()
|
||||
*/
|
||||
public BasicQueryContract setCacheRegion(String cacheRegion);
|
||||
|
||||
/**
|
||||
* Obtain the query timeout <b>in seconds</b>. This value is eventually passed along to the JDBC query via
|
||||
* {@link java.sql.Statement#setQueryTimeout(int)}. Zero indicates no timeout.
|
||||
*
|
||||
* @return The timeout <b>in seconds</b>
|
||||
*
|
||||
* @see java.sql.Statement#getQueryTimeout()
|
||||
* @see java.sql.Statement#setQueryTimeout(int)
|
||||
*/
|
||||
public Integer getTimeout();
|
||||
|
||||
/**
|
||||
* Set the query timeout <b>in seconds</b>.
|
||||
*
|
||||
* NOTE it is important to understand that any value set here is eventually passed directly through to the JDBC
|
||||
* Statement which expressly disallows negative values. So negative values should be avoided as a general rule.
|
||||
*
|
||||
* @param timeout the timeout <b>in seconds</b>
|
||||
*
|
||||
* @see #getTimeout()
|
||||
*/
|
||||
public BasicQueryContract setTimeout(int timeout);
|
||||
|
||||
/**
|
||||
* Obtain the JDBC fetch size hint in effect for this query. This value is eventually passed along to the JDBC
|
||||
* query via {@link java.sql.Statement#setFetchSize(int)}. As defined b y JDBC, this value is a hint to the
|
||||
* driver to indicate how many rows to fetch from the database when more rows are needed.
|
||||
*
|
||||
* NOTE : JDBC expressly defines this value as a hint. It may or may not have any effect on the actual
|
||||
* query execution and ResultSet processing depending on the driver.
|
||||
*
|
||||
* @return The timeout <b>in seconds</b>
|
||||
*
|
||||
* @see java.sql.Statement#getFetchSize()
|
||||
* @see java.sql.Statement#setFetchSize(int)
|
||||
*/
|
||||
public Integer getFetchSize();
|
||||
|
||||
/**
|
||||
* Sets a JDBC fetch size hint for the query.
|
||||
*
|
||||
* @param fetchSize the fetch size hint
|
||||
*
|
||||
* @see #getFetchSize()
|
||||
*/
|
||||
public BasicQueryContract setFetchSize(int fetchSize);
|
||||
|
||||
/**
|
||||
* Should entities and proxies loaded by this Query be put in read-only mode? If the
|
||||
* read-only/modifiable setting was not initialized, then the default
|
||||
* read-only/modifiable setting for the persistence context is returned instead.
|
||||
* @see Query#setReadOnly(boolean)
|
||||
* @see org.hibernate.engine.spi.PersistenceContext#isDefaultReadOnly()
|
||||
*
|
||||
* The read-only/modifiable setting has no impact on entities/proxies returned by the
|
||||
* query that existed in the session before the query was executed.
|
||||
*
|
||||
* @return true, entities and proxies loaded by the query will be put in read-only mode
|
||||
* false, entities and proxies loaded by the query will be put in modifiable mode
|
||||
*/
|
||||
public boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Set the read-only/modifiable mode for entities and proxies
|
||||
* loaded by this Query. This setting overrides the default setting
|
||||
* for the persistence context.
|
||||
* @see org.hibernate.engine.spi.PersistenceContext#isDefaultReadOnly()
|
||||
*
|
||||
* To set the default read-only/modifiable setting used for
|
||||
* entities and proxies that are loaded into the session:
|
||||
* @see org.hibernate.engine.spi.PersistenceContext#setDefaultReadOnly(boolean)
|
||||
* @see org.hibernate.Session#setDefaultReadOnly(boolean)
|
||||
*
|
||||
* Read-only entities are not dirty-checked and snapshots of persistent
|
||||
* state are not maintained. Read-only entities can be modified, but
|
||||
* changes are not persisted.
|
||||
*
|
||||
* When a proxy is initialized, the loaded entity will have the same
|
||||
* read-only/modifiable setting as the uninitialized
|
||||
* proxy has, regardless of the session's current setting.
|
||||
*
|
||||
* The read-only/modifiable setting has no impact on entities/proxies
|
||||
* returned by the query that existed in the session before the query was executed.
|
||||
*
|
||||
* @param readOnly true, entities and proxies loaded by the query will be put in read-only mode
|
||||
* false, entities and proxies loaded by the query will be put in modifiable mode
|
||||
*/
|
||||
public BasicQueryContract setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Return the Hibernate types of the query results.
|
||||
*
|
||||
* @return an array of types
|
||||
*/
|
||||
public Type[] getReturnTypes() throws HibernateException;
|
||||
}
|
|
@ -77,7 +77,7 @@ import org.hibernate.type.Type;
|
|||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public interface Query {
|
||||
public interface Query extends BasicQueryContract {
|
||||
/**
|
||||
* Get the query string.
|
||||
*
|
||||
|
@ -121,139 +121,27 @@ public interface Query {
|
|||
*/
|
||||
public Query setFirstResult(int firstResult);
|
||||
|
||||
/**
|
||||
* Obtain the FlushMode in effect for this query. By default, the query inherits the FlushMode of the Session
|
||||
* from which is originates.
|
||||
*
|
||||
* @return The query FlushMode.
|
||||
*
|
||||
* @see Session#getFlushMode()
|
||||
* @see FlushMode
|
||||
*/
|
||||
public FlushMode getFlushMode();
|
||||
|
||||
/**
|
||||
* (Re)set the current FlushMode in effect for this query.
|
||||
*
|
||||
* @param flushMode The new FlushMode to use.
|
||||
*
|
||||
* @see #getFlushMode()
|
||||
*/
|
||||
@Override
|
||||
public Query setFlushMode(FlushMode flushMode);
|
||||
|
||||
/**
|
||||
* Obtain the CacheMode in effect for this query. By default, the query inherits the CacheMode of the Session
|
||||
* from which is originates.
|
||||
*
|
||||
* NOTE: The CacheMode here only effects reading/writing of the query cache, not the
|
||||
* entity/collection caches.
|
||||
*
|
||||
* @return The query CacheMode.
|
||||
*
|
||||
* @see Session#getCacheMode()
|
||||
* @see CacheMode
|
||||
*/
|
||||
public CacheMode getCacheMode();
|
||||
|
||||
/**
|
||||
* (Re)set the current CacheMode in effect for this query.
|
||||
*
|
||||
* @param cacheMode The new CacheMode to use.
|
||||
*
|
||||
* @see #getCacheMode()
|
||||
*/
|
||||
@Override
|
||||
public Query setCacheMode(CacheMode cacheMode);
|
||||
|
||||
/**
|
||||
* Are the results of this query eligible for second level query caching? This is different that second level
|
||||
* caching of any returned entities and collections.
|
||||
*
|
||||
* NOTE: the query being "eligible" for caching does not necessarily mean its results will be cached. Second level
|
||||
* query caching still has to be enabled on the {@link SessionFactory} for this to happen. Usually that is
|
||||
* controlled by the {@code hibernate.cache.use_query_cache} configuration setting.
|
||||
*
|
||||
* @return {@code true} if the query results are eligible for caching, {@code false} otherwise.
|
||||
*
|
||||
* @see org.hibernate.cfg.AvailableSettings#USE_QUERY_CACHE
|
||||
*/
|
||||
public boolean isCacheable();
|
||||
|
||||
/**
|
||||
* Enable/disable second level query (result) caching for this query.
|
||||
*
|
||||
* @param cacheable Should the query results be cacheable?
|
||||
*
|
||||
* @see #isCacheable
|
||||
*/
|
||||
@Override
|
||||
public Query setCacheable(boolean cacheable);
|
||||
|
||||
/**
|
||||
* Obtain the name of the second level query cache region in which query results will be stored (if they are
|
||||
* cached, see the discussion on {@link #isCacheable()} for more information). {@code null} indicates that the
|
||||
* default region should be used.
|
||||
*
|
||||
* @return The specified cache region name into which query results should be placed; {@code null} indicates
|
||||
* the default region.
|
||||
*/
|
||||
public String getCacheRegion();
|
||||
|
||||
/**
|
||||
* Set the name of the cache region where query results should be cached (if cached at all).
|
||||
*
|
||||
* @param cacheRegion the name of a query cache region, or {@code null} to indicate that the default region
|
||||
* should be used.
|
||||
*
|
||||
* @see #getCacheRegion()
|
||||
*/
|
||||
@Override
|
||||
public Query setCacheRegion(String cacheRegion);
|
||||
|
||||
/**
|
||||
* Obtain the query timeout <b>in seconds</b>. This value is eventually passed along to the JDBC query via
|
||||
* {@link java.sql.Statement#setQueryTimeout(int)}. Zero indicates no timeout.
|
||||
*
|
||||
* @return The timeout <b>in seconds</b>
|
||||
*
|
||||
* @see java.sql.Statement#getQueryTimeout()
|
||||
* @see java.sql.Statement#setQueryTimeout(int)
|
||||
*/
|
||||
public Integer getTimeout();
|
||||
|
||||
/**
|
||||
* Set the query timeout <b>in seconds</b>.
|
||||
*
|
||||
* NOTE it is important to understand that any value set here is eventually passed directly through to the JDBC
|
||||
* Statement which expressly disallows negative values. So negative values should be avoided as a general rule.
|
||||
*
|
||||
* @param timeout the timeout <b>in seconds</b>
|
||||
*
|
||||
* @see #getTimeout()
|
||||
*/
|
||||
@Override
|
||||
public Query setTimeout(int timeout);
|
||||
|
||||
/**
|
||||
* Obtain the JDBC fetch size hint in effect for this query. This value is eventually passed along to the JDBC
|
||||
* query via {@link java.sql.Statement#setFetchSize(int)}. As defined b y JDBC, this value is a hint to the
|
||||
* driver to indicate how many rows to fetch from the database when more rows are needed.
|
||||
*
|
||||
* NOTE : JDBC expressly defines this value as a hint. It may or may not have any effect on the actual
|
||||
* query execution and ResultSet processing depending on the driver.
|
||||
*
|
||||
* @return The timeout <b>in seconds</b>
|
||||
*
|
||||
* @see java.sql.Statement#getFetchSize()
|
||||
* @see java.sql.Statement#setFetchSize(int)
|
||||
*/
|
||||
public Integer getFetchSize();
|
||||
|
||||
/**
|
||||
* Sets a JDBC fetch size hint for the query.
|
||||
*
|
||||
* @param fetchSize the fetch size hint
|
||||
*
|
||||
* @see #getFetchSize()
|
||||
*/
|
||||
@Override
|
||||
public Query setFetchSize(int fetchSize);
|
||||
|
||||
@Override
|
||||
public Query setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Obtains the LockOptions in effect for this query.
|
||||
*
|
||||
|
@ -310,54 +198,6 @@ public interface Query {
|
|||
*/
|
||||
public Query setComment(String comment);
|
||||
|
||||
/**
|
||||
* Should entities and proxies loaded by this Query be put in read-only mode? If the
|
||||
* read-only/modifiable setting was not initialized, then the default
|
||||
* read-only/modifiable setting for the persistence context is returned instead.
|
||||
* @see Query#setReadOnly(boolean)
|
||||
* @see org.hibernate.engine.spi.PersistenceContext#isDefaultReadOnly()
|
||||
*
|
||||
* The read-only/modifiable setting has no impact on entities/proxies returned by the
|
||||
* query that existed in the session before the query was executed.
|
||||
*
|
||||
* @return true, entities and proxies loaded by the query will be put in read-only mode
|
||||
* false, entities and proxies loaded by the query will be put in modifiable mode
|
||||
*/
|
||||
public boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Set the read-only/modifiable mode for entities and proxies
|
||||
* loaded by this Query. This setting overrides the default setting
|
||||
* for the persistence context.
|
||||
* @see org.hibernate.engine.spi.PersistenceContext#isDefaultReadOnly()
|
||||
*
|
||||
* To set the default read-only/modifiable setting used for
|
||||
* entities and proxies that are loaded into the session:
|
||||
* @see org.hibernate.engine.spi.PersistenceContext#setDefaultReadOnly(boolean)
|
||||
* @see org.hibernate.Session#setDefaultReadOnly(boolean)
|
||||
*
|
||||
* Read-only entities are not dirty-checked and snapshots of persistent
|
||||
* state are not maintained. Read-only entities can be modified, but
|
||||
* changes are not persisted.
|
||||
*
|
||||
* When a proxy is initialized, the loaded entity will have the same
|
||||
* read-only/modifiable setting as the uninitialized
|
||||
* proxy has, regardless of the session's current setting.
|
||||
*
|
||||
* The read-only/modifiable setting has no impact on entities/proxies
|
||||
* returned by the query that existed in the session before the query was executed.
|
||||
*
|
||||
* @param readOnly true, entities and proxies loaded by the query will be put in read-only mode
|
||||
* false, entities and proxies loaded by the query will be put in modifiable mode
|
||||
*/
|
||||
public Query setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Return the Hibernate types of the query result set.
|
||||
* @return an array of types
|
||||
*/
|
||||
public Type[] getReturnTypes() throws HibernateException;
|
||||
|
||||
/**
|
||||
* Return the HQL select clause aliases (if any)
|
||||
* @return an array of aliases as strings
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
|
||||
|
@ -48,54 +47,15 @@ import org.hibernate.type.Type;
|
|||
* @author Gavin King
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SQLQuery extends Query {
|
||||
/**
|
||||
* Obtain the list of query spaces (table names) the query is synchronized on. These spaces affect the process
|
||||
* of auto-flushing by determining which entities will be processed by auto-flush based on the table to
|
||||
* which those entities are mapped and which are determined to have pending state changes.
|
||||
*
|
||||
* @return The list of query spaces upon which the query is synchronized.
|
||||
*/
|
||||
public Collection<String> getSynchronizedQuerySpaces();
|
||||
public interface SQLQuery extends Query, SynchronizeableQuery {
|
||||
@Override
|
||||
SQLQuery addSynchronizedQuerySpace(String querySpace);
|
||||
|
||||
/**
|
||||
* Adds a query space (table name) for (a) auto-flush checking and (b) query result cache invalidation checking
|
||||
*
|
||||
* @param querySpace The query space to be auto-flushed for this query.
|
||||
*
|
||||
* @return this, for method chaining
|
||||
*
|
||||
* @see #getSynchronizedQuerySpaces()
|
||||
*/
|
||||
public SQLQuery addSynchronizedQuerySpace(String querySpace);
|
||||
@Override
|
||||
SQLQuery addSynchronizedEntityName(String entityName) throws MappingException;
|
||||
|
||||
/**
|
||||
* Adds an entity name for (a) auto-flush checking and (b) query result cache invalidation checking. Same as
|
||||
* {@link #addSynchronizedQuerySpace} for all tables associated with the given entity.
|
||||
*
|
||||
* @param entityName The name of the entity upon whose defined query spaces we should additionally synchronize.
|
||||
*
|
||||
* @return this, for method chaining
|
||||
*
|
||||
* @throws MappingException Indicates the given name could not be resolved as an entity
|
||||
*
|
||||
* @see #getSynchronizedQuerySpaces()
|
||||
*/
|
||||
public SQLQuery addSynchronizedEntityName(String entityName) throws MappingException;
|
||||
|
||||
/**
|
||||
* Adds an entity for (a) auto-flush checking and (b) query result cache invalidation checking. Same as
|
||||
* {@link #addSynchronizedQuerySpace} for all tables associated with the given entity.
|
||||
*
|
||||
* @param entityClass The class of the entity upon whose defined query spaces we should additionally synchronize.
|
||||
*
|
||||
* @return this, for method chaining
|
||||
*
|
||||
* @throws MappingException Indicates the given class could not be resolved as an entity
|
||||
*
|
||||
* @see #getSynchronizedQuerySpaces()
|
||||
*/
|
||||
public SQLQuery addSynchronizedEntityClass(Class entityClass) throws MappingException;
|
||||
@Override
|
||||
SQLQuery addSynchronizedEntityClass(Class entityClass) throws MappingException;
|
||||
|
||||
/**
|
||||
* Use a predefined named result-set mapping. This might be defined by a {@code <result-set/>} element in a
|
||||
|
|
|
@ -84,6 +84,35 @@ public interface SharedSessionContract extends Serializable {
|
|||
*/
|
||||
public SQLQuery createSQLQuery(String queryString);
|
||||
|
||||
/**
|
||||
* Creates a call to a stored procedure.
|
||||
*
|
||||
* @param procedureName The name of the procedure.
|
||||
*
|
||||
* @return The representation of the procedure call.
|
||||
*/
|
||||
public StoredProcedureCall createStoredProcedureCall(String procedureName);
|
||||
|
||||
/**
|
||||
* Creates a call to a stored procedure with specific result set entity mappings
|
||||
*
|
||||
* @param procedureName The name of the procedure.
|
||||
* @param resultClasses The entity(s) to map the result on to.
|
||||
*
|
||||
* @return The representation of the procedure call.
|
||||
*/
|
||||
public StoredProcedureCall createStoredProcedureCall(String procedureName, Class... resultClasses);
|
||||
|
||||
/**
|
||||
* Creates a call to a stored procedure with specific result set entity mappings
|
||||
*
|
||||
* @param procedureName The name of the procedure.
|
||||
* @param resultSetMappings The explicit result set mapping(s) to use for mapping the results
|
||||
*
|
||||
* @return The representation of the procedure call.
|
||||
*/
|
||||
public StoredProcedureCall createStoredProcedureCall(String procedureName, String... resultSetMappings);
|
||||
|
||||
/**
|
||||
* Create {@link Criteria} instance for the given class (entity or subclasses/implementors)
|
||||
*
|
||||
|
@ -122,4 +151,5 @@ public interface SharedSessionContract extends Serializable {
|
|||
* @return The criteria instance for manipulation and execution
|
||||
*/
|
||||
public Criteria createCriteria(String entityName, String alias);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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;
|
||||
|
||||
import javax.persistence.ParameterMode;
|
||||
import javax.persistence.TemporalType;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface StoredProcedureCall extends BasicQueryContract, SynchronizeableQuery {
|
||||
@Override
|
||||
StoredProcedureCall addSynchronizedQuerySpace(String querySpace);
|
||||
|
||||
@Override
|
||||
StoredProcedureCall addSynchronizedEntityName(String entityName) throws MappingException;
|
||||
|
||||
@Override
|
||||
StoredProcedureCall addSynchronizedEntityClass(Class entityClass) throws MappingException;
|
||||
|
||||
/**
|
||||
* Get the name of the stored procedure to be called.
|
||||
*
|
||||
* @return The procedure name.
|
||||
*/
|
||||
public String getProcedureName();
|
||||
|
||||
|
||||
/**
|
||||
* Register a positional parameter.
|
||||
* All positional parameters must be registered.
|
||||
*
|
||||
* @param position parameter position
|
||||
* @param type type of the parameter
|
||||
* @param mode parameter mode
|
||||
*
|
||||
* @return the same query instance
|
||||
*/
|
||||
StoredProcedureCall registerStoredProcedureParameter(
|
||||
int position,
|
||||
Class type,
|
||||
ParameterMode mode);
|
||||
|
||||
/**
|
||||
* Register a named parameter.
|
||||
* When using parameter names, all parameters must be registered
|
||||
* in the order in which they occur in the parameter list of the
|
||||
* stored procedure.
|
||||
*
|
||||
* @param parameterName name of the parameter as registered or
|
||||
* <p/>
|
||||
* specified in metadata
|
||||
* @param type type of the parameter
|
||||
* @param mode parameter mode
|
||||
*
|
||||
* @return the same query instance
|
||||
*/
|
||||
StoredProcedureCall registerStoredProcedureParameter(
|
||||
String parameterName,
|
||||
Class type,
|
||||
ParameterMode mode);
|
||||
|
||||
/**
|
||||
* Retrieve all registered parameters.
|
||||
*
|
||||
* @return The (immutable) list of all registered parameters.
|
||||
*/
|
||||
public List<StoredProcedureParameter> getRegisteredParameters();
|
||||
|
||||
/**
|
||||
* Retrieve parameter registered by name.
|
||||
*
|
||||
* @param name The name under which the parameter of interest was registered.
|
||||
*
|
||||
* @return The registered parameter.
|
||||
*/
|
||||
public StoredProcedureParameter getRegisteredParameter(String name);
|
||||
public StoredProcedureParameter getRegisteredParameter(int position);
|
||||
|
||||
public StoredProcedureOutputs getOutputs();
|
||||
|
||||
/**
|
||||
* Describes a parameter registered with the stored procedure. Parameters can be either named or positional
|
||||
* as the registration mechanism. Named and positional should not be mixed.
|
||||
*/
|
||||
public static interface StoredProcedureParameter<T> {
|
||||
/**
|
||||
* The name under which this parameter was registered. Can be {@code null} which should indicate that
|
||||
* positional registration was used (and therefore {@link #getPosition()} should return non-null.
|
||||
*
|
||||
* @return The name;
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* The position at which this parameter was registered. Can be {@code null} which should indicate that
|
||||
* named registration was used (and therefore {@link #getName()} should return non-null.
|
||||
*
|
||||
* @return The name;
|
||||
*/
|
||||
public Integer getPosition();
|
||||
|
||||
/**
|
||||
* Obtain the Java type of parameter. This is used to guess the Hibernate type (unless {@link #setHibernateType}
|
||||
* is called explicitly).
|
||||
*
|
||||
* @return The parameter Java type.
|
||||
*/
|
||||
public Class<T> getType();
|
||||
|
||||
/**
|
||||
* Retrieves the parameter "mode" which describes how the parameter is defined in the actual database procedure
|
||||
* definition (is it an INPUT parameter? An OUTPUT parameter? etc).
|
||||
*
|
||||
* @return The parameter mode.
|
||||
*/
|
||||
public ParameterMode getMode();
|
||||
|
||||
/**
|
||||
* Set the Hibernate mapping type for this parameter.
|
||||
*
|
||||
* @param type The Hibernate mapping type.
|
||||
*/
|
||||
public void setHibernateType(Type type);
|
||||
|
||||
/**
|
||||
* Retrieve the binding associated with this parameter. The binding is only relevant for INPUT parameters. Can
|
||||
* return {@code null} if nothing has been bound yet. To bind a value to the parameter use one of the
|
||||
* {@link #bindValue} methods.
|
||||
*
|
||||
* @return The parameter binding
|
||||
*/
|
||||
public StoredProcedureParameterBind getParameterBind();
|
||||
|
||||
/**
|
||||
* Bind a value to the parameter. How this value is bound to the underlying JDBC CallableStatement is
|
||||
* totally dependent on the Hibernate type.
|
||||
*
|
||||
* @param value The value to bind.
|
||||
*/
|
||||
public void bindValue(T value);
|
||||
|
||||
/**
|
||||
* Bind a value to the parameter, using just a specified portion of the DATE/TIME value. It is illegal to call
|
||||
* this form if the parameter is not DATE/TIME type. The Hibernate type is circumvented in this case and
|
||||
* an appropriate "precision" Type is used instead.
|
||||
*
|
||||
* @param value The value to bind
|
||||
* @param explicitTemporalType An explicitly supplied TemporalType.
|
||||
*/
|
||||
public void bindValue(T value, TemporalType explicitTemporalType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes an input value binding for any IN/INOUT parameters.
|
||||
*/
|
||||
public static interface StoredProcedureParameterBind<T> {
|
||||
/**
|
||||
* Retrieves the bound value.
|
||||
*
|
||||
* @return The bound value.
|
||||
*/
|
||||
public T getValue();
|
||||
|
||||
/**
|
||||
* If {@code <T>} represents a DATE/TIME type value, JPA usually allows specifying the particular parts of
|
||||
* the DATE/TIME value to be bound. This value represents the particular part the user requested to be bound.
|
||||
*
|
||||
* @return The explicitly supplied TemporalType.
|
||||
*/
|
||||
public TemporalType getExplicitTemporalType();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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;
|
||||
|
||||
/**
|
||||
* Represents all the outputs of a call to a database stored procedure (or function) through the JDBC
|
||||
* {@link java.sql.CallableStatement} interface.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface StoredProcedureOutputs {
|
||||
/**
|
||||
* Retrieve the value of an OUTPUT parameter by the name under which the parameter was registered.
|
||||
*
|
||||
* @param name The name under which the parameter was registered.
|
||||
*
|
||||
* @return The output value.
|
||||
*
|
||||
* @see StoredProcedureCall#registerStoredProcedureParameter(String, Class, javax.persistence.ParameterMode)
|
||||
*/
|
||||
public Object getOutputParameterValue(String name);
|
||||
|
||||
/**
|
||||
* Retrieve the value of an OUTPUT parameter by the name position under which the parameter was registered.
|
||||
*
|
||||
* @param position The position at which the parameter was registered.
|
||||
*
|
||||
* @return The output value.
|
||||
*
|
||||
* @see StoredProcedureCall#registerStoredProcedureParameter(int, Class, javax.persistence.ParameterMode)
|
||||
*/
|
||||
public Object getOutputParameterValue(int position);
|
||||
|
||||
/**
|
||||
* Are there any more returns associated with this set of outputs?
|
||||
*
|
||||
* @return {@code true} means there are more results available via {@link #getNextReturn()}; {@code false}
|
||||
* indicates that calling {@link #getNextReturn()} will certainly result in an exception.
|
||||
*/
|
||||
public boolean hasMoreReturns();
|
||||
|
||||
/**
|
||||
* Retrieve the next return.
|
||||
*
|
||||
* @return The next return.
|
||||
*/
|
||||
public StoredProcedureReturn getNextReturn();
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Models a stored procedure result that is a result set.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface StoredProcedureResultSetReturn extends StoredProcedureReturn {
|
||||
/**
|
||||
* Consume the underlying {@link java.sql.ResultSet} and return the resulting List.
|
||||
*
|
||||
* @return The consumed ResultSet values.
|
||||
*/
|
||||
public List getResultList();
|
||||
|
||||
/**
|
||||
* Consume the underlying {@link java.sql.ResultSet} with the expectation that there is just a single level of
|
||||
* root returns.
|
||||
*
|
||||
* @return The single result.
|
||||
*/
|
||||
public Object getSingleResult();
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface StoredProcedureReturn {
|
||||
public boolean isResultSet();
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface StoredProcedureUpdateCountReturn extends StoredProcedureReturn {
|
||||
public int getUpdateCount();
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SynchronizeableQuery {
|
||||
/**
|
||||
* Obtain the list of query spaces (table names) the query is synchronized on. These spaces affect the process
|
||||
* of auto-flushing by determining which entities will be processed by auto-flush based on the table to
|
||||
* which those entities are mapped and which are determined to have pending state changes.
|
||||
*
|
||||
* @return The list of query spaces upon which the query is synchronized.
|
||||
*/
|
||||
public Collection<String> getSynchronizedQuerySpaces();
|
||||
|
||||
/**
|
||||
* Adds a query space (table name) for (a) auto-flush checking and (b) query result cache invalidation checking
|
||||
*
|
||||
* @param querySpace The query space to be auto-flushed for this query.
|
||||
*
|
||||
* @return this, for method chaining
|
||||
*
|
||||
* @see #getSynchronizedQuerySpaces()
|
||||
*/
|
||||
public SynchronizeableQuery addSynchronizedQuerySpace(String querySpace);
|
||||
|
||||
/**
|
||||
* Adds an entity name for (a) auto-flush checking and (b) query result cache invalidation checking. Same as
|
||||
* {@link #addSynchronizedQuerySpace} for all tables associated with the given entity.
|
||||
*
|
||||
* @param entityName The name of the entity upon whose defined query spaces we should additionally synchronize.
|
||||
*
|
||||
* @return this, for method chaining
|
||||
*
|
||||
* @throws MappingException Indicates the given name could not be resolved as an entity
|
||||
*
|
||||
* @see #getSynchronizedQuerySpaces()
|
||||
*/
|
||||
public SynchronizeableQuery addSynchronizedEntityName(String entityName) throws MappingException;
|
||||
|
||||
/**
|
||||
* Adds an entity for (a) auto-flush checking and (b) query result cache invalidation checking. Same as
|
||||
* {@link #addSynchronizedQuerySpace} for all tables associated with the given entity.
|
||||
*
|
||||
* @param entityClass The class of the entity upon whose defined query spaces we should additionally synchronize.
|
||||
*
|
||||
* @return this, for method chaining
|
||||
*
|
||||
* @throws MappingException Indicates the given class could not be resolved as an entity
|
||||
*
|
||||
* @see #getSynchronizedQuerySpaces()
|
||||
*/
|
||||
public SynchronizeableQuery addSynchronizedEntityClass(Class entityClass) throws MappingException;
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.BasicQueryContract;
|
||||
import org.hibernate.CacheMode;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.RowSelection;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractBasicQueryContractImpl implements BasicQueryContract {
|
||||
private final SessionImplementor session;
|
||||
|
||||
private FlushMode flushMode;
|
||||
private CacheMode cacheMode;
|
||||
|
||||
private boolean cacheable;
|
||||
private String cacheRegion;
|
||||
private boolean readOnly;
|
||||
private RowSelection selection = new RowSelection();
|
||||
|
||||
protected AbstractBasicQueryContractImpl(SessionImplementor session) {
|
||||
this.session = session;
|
||||
this.readOnly = session.getPersistenceContext().isDefaultReadOnly();
|
||||
}
|
||||
|
||||
protected SessionImplementor session() {
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlushMode getFlushMode() {
|
||||
return flushMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicQueryContract setFlushMode(FlushMode flushMode) {
|
||||
this.flushMode = flushMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheMode getCacheMode() {
|
||||
return cacheMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicQueryContract setCacheMode(CacheMode cacheMode) {
|
||||
this.cacheMode = cacheMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCacheable() {
|
||||
return cacheable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicQueryContract setCacheable(boolean cacheable) {
|
||||
this.cacheable = cacheable;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCacheRegion() {
|
||||
return cacheRegion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicQueryContract setCacheRegion(String cacheRegion) {
|
||||
if ( cacheRegion != null ) {
|
||||
this.cacheRegion = cacheRegion.trim();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicQueryContract setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTimeout() {
|
||||
return selection.getTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicQueryContract setTimeout(int timeout) {
|
||||
selection.setTimeout( timeout );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getFetchSize() {
|
||||
return selection.getFetchSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicQueryContract setFetchSize(int fetchSize) {
|
||||
selection.setFetchSize( fetchSize );
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryParameters buildQueryParametersObject() {
|
||||
QueryParameters qp = new QueryParameters();
|
||||
qp.setRowSelection( selection );
|
||||
qp.setCacheable( cacheable );
|
||||
qp.setCacheRegion( cacheRegion );
|
||||
qp.setReadOnly( readOnly );
|
||||
return qp;
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ import org.hibernate.SQLQuery;
|
|||
import org.hibernate.ScrollableResults;
|
||||
import org.hibernate.SessionException;
|
||||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.StoredProcedureCall;
|
||||
import org.hibernate.cache.spi.CacheKey;
|
||||
import org.hibernate.engine.jdbc.LobCreationContext;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
|
||||
|
@ -235,6 +236,33 @@ public abstract class AbstractSessionImpl implements Serializable, SharedSession
|
|||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
public StoredProcedureCall createStoredProcedureCall(String procedureName) {
|
||||
errorIfClosed();
|
||||
final StoredProcedureCall call = new StoredProcedureCallImpl( this, procedureName );
|
||||
// call.setComment( "Dynamic stored procedure call" );
|
||||
return call;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
public StoredProcedureCall createStoredProcedureCall(String procedureName, Class... resultClasses) {
|
||||
errorIfClosed();
|
||||
final StoredProcedureCall call = new StoredProcedureCallImpl( this, procedureName, resultClasses );
|
||||
// call.setComment( "Dynamic stored procedure call" );
|
||||
return call;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
public StoredProcedureCall createStoredProcedureCall(String procedureName, String... resultSetMappings) {
|
||||
errorIfClosed();
|
||||
final StoredProcedureCall call = new StoredProcedureCallImpl( this, procedureName, resultSetMappings );
|
||||
// call.setComment( "Dynamic stored procedure call" );
|
||||
return call;
|
||||
}
|
||||
|
||||
protected HQLQueryPlan getHQLQueryPlan(String query, boolean shallow) throws HibernateException {
|
||||
return factory.getQueryPlanCache().getHQLQueryPlan( query, shallow, getEnabledFilters() );
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
|
@ -101,44 +100,15 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
|
|||
this.callable = queryDef.isCallable();
|
||||
}
|
||||
|
||||
SQLQueryImpl(
|
||||
final String sql,
|
||||
final String returnAliases[],
|
||||
final Class returnClasses[],
|
||||
final LockMode[] lockModes,
|
||||
final SessionImplementor session,
|
||||
final Collection<String> querySpaces,
|
||||
final FlushMode flushMode,
|
||||
ParameterMetadata parameterMetadata) {
|
||||
// TODO : this constructor form is *only* used from constructor directly below us; can it go away?
|
||||
super( sql, flushMode, session, parameterMetadata );
|
||||
queryReturns = new ArrayList<NativeSQLQueryReturn>( returnAliases.length );
|
||||
for ( int i=0; i<returnAliases.length; i++ ) {
|
||||
NativeSQLQueryRootReturn ret = new NativeSQLQueryRootReturn(
|
||||
returnAliases[i],
|
||||
returnClasses[i].getName(),
|
||||
lockModes==null ? LockMode.NONE : lockModes[i]
|
||||
);
|
||||
queryReturns.add(ret);
|
||||
}
|
||||
this.querySpaces = querySpaces;
|
||||
this.callable = false;
|
||||
}
|
||||
|
||||
SQLQueryImpl(
|
||||
final String sql,
|
||||
final String returnAliases[],
|
||||
final Class returnClasses[],
|
||||
final SessionImplementor session,
|
||||
ParameterMetadata parameterMetadata) {
|
||||
this( sql, returnAliases, returnClasses, null, session, null, null, parameterMetadata );
|
||||
}
|
||||
|
||||
SQLQueryImpl(String sql, SessionImplementor session, ParameterMetadata parameterMetadata) {
|
||||
this( sql, false, session, parameterMetadata );
|
||||
}
|
||||
|
||||
SQLQueryImpl(String sql, boolean callable, SessionImplementor session, ParameterMetadata parameterMetadata) {
|
||||
super( sql, null, session, parameterMetadata );
|
||||
queryReturns = new ArrayList<NativeSQLQueryReturn>();
|
||||
querySpaces = null;
|
||||
callable = false;
|
||||
this.queryReturns = new ArrayList<NativeSQLQueryReturn>();
|
||||
this.querySpaces = null;
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -73,6 +73,7 @@ import org.hibernate.ScrollableResults;
|
|||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionBuilder;
|
||||
import org.hibernate.SessionException;
|
||||
import org.hibernate.StoredProcedureCall;
|
||||
import org.hibernate.engine.spi.SessionOwner;
|
||||
import org.hibernate.SharedSessionBuilder;
|
||||
import org.hibernate.SimpleNaturalIdLoadAccess;
|
||||
|
@ -1742,6 +1743,27 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
|
|||
return super.createSQLQuery( sql );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureCall createStoredProcedureCall(String procedureName) {
|
||||
errorIfClosed();
|
||||
checkTransactionSynchStatus();
|
||||
return super.createStoredProcedureCall( procedureName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureCall createStoredProcedureCall(String procedureName, String... resultSetMappings) {
|
||||
errorIfClosed();
|
||||
checkTransactionSynchStatus();
|
||||
return super.createStoredProcedureCall( procedureName, resultSetMappings );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureCall createStoredProcedureCall(String procedureName, Class... resultClasses) {
|
||||
errorIfClosed();
|
||||
checkTransactionSynchStatus();
|
||||
return super.createStoredProcedureCall( procedureName, resultClasses );
|
||||
}
|
||||
|
||||
public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters)
|
||||
throws HibernateException {
|
||||
errorIfClosed();
|
||||
|
|
|
@ -0,0 +1,555 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.internal;
|
||||
|
||||
import javax.persistence.ParameterMode;
|
||||
import javax.persistence.TemporalType;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.StoredProcedureCall;
|
||||
import org.hibernate.StoredProcedureOutputs;
|
||||
import org.hibernate.cfg.NotYetImplementedException;
|
||||
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.QueryParameters;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.type.DateType;
|
||||
import org.hibernate.type.ProcedureParameterExtractionAware;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class StoredProcedureCallImpl extends AbstractBasicQueryContractImpl implements StoredProcedureCall {
|
||||
private static final Logger log = Logger.getLogger( StoredProcedureCallImpl.class );
|
||||
|
||||
private final String procedureName;
|
||||
private final NativeSQLQueryReturn[] queryReturns;
|
||||
|
||||
private TypeOfParameter typeOfParameters = TypeOfParameter.UNKNOWN;
|
||||
private List<StoredProcedureParameterImplementor> registeredParameters = new ArrayList<StoredProcedureParameterImplementor>();
|
||||
|
||||
private Set<String> synchronizedQuerySpaces;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public StoredProcedureCallImpl(SessionImplementor session, String procedureName) {
|
||||
this( session, procedureName, (List) null );
|
||||
}
|
||||
|
||||
public StoredProcedureCallImpl(SessionImplementor session, String procedureName, List<NativeSQLQueryReturn> queryReturns) {
|
||||
super( session );
|
||||
this.procedureName = procedureName;
|
||||
|
||||
if ( queryReturns == null || queryReturns.isEmpty() ) {
|
||||
this.queryReturns = new NativeSQLQueryReturn[0];
|
||||
}
|
||||
else {
|
||||
this.queryReturns = queryReturns.toArray( new NativeSQLQueryReturn[ queryReturns.size() ] );
|
||||
}
|
||||
}
|
||||
|
||||
public StoredProcedureCallImpl(SessionImplementor session, String procedureName, Class... resultClasses) {
|
||||
this( session, procedureName, collectQueryReturns( resultClasses ) );
|
||||
}
|
||||
|
||||
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 StoredProcedureCallImpl(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 StoredProcedureCallImpl(
|
||||
// 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
|
||||
public String getProcedureName() {
|
||||
return procedureName;
|
||||
}
|
||||
|
||||
NativeSQLQueryReturn[] getQueryReturns() {
|
||||
return queryReturns;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public StoredProcedureCall registerStoredProcedureParameter(int position, Class type, ParameterMode mode) {
|
||||
registerParameter( new PositionalStoredProcedureParameter( this, position, mode, type ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
private void registerParameter(StoredProcedureParameterImplementor parameter) {
|
||||
if ( StringHelper.isNotEmpty( parameter.getName() ) ) {
|
||||
if ( typeOfParameters == TypeOfParameter.POSITIONAL ) {
|
||||
throw new QueryException( "Cannot mix named and positional parameters" );
|
||||
}
|
||||
typeOfParameters = TypeOfParameter.NAMED;
|
||||
registeredParameters.add( parameter );
|
||||
}
|
||||
else if ( parameter.getPosition() != null ) {
|
||||
if ( typeOfParameters == TypeOfParameter.NAMED ) {
|
||||
throw new QueryException( "Cannot mix named and positional parameters" );
|
||||
}
|
||||
typeOfParameters = TypeOfParameter.POSITIONAL;
|
||||
registeredParameters.add( parameter.getPosition(), parameter );
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException( "Given parameter did not define name nor position [" + parameter + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public StoredProcedureCall registerStoredProcedureParameter(String name, Class type, ParameterMode mode) {
|
||||
registerParameter( new NamedStoredProcedureParameter( this, name, mode, type ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public List getRegisteredParameters() {
|
||||
return registeredParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureParameterImplementor getRegisteredParameter(String name) {
|
||||
if ( typeOfParameters != TypeOfParameter.NAMED ) {
|
||||
throw new IllegalArgumentException( "Names were not used to register parameters with this stored procedure call" );
|
||||
}
|
||||
for ( StoredProcedureParameterImplementor parameter : registeredParameters ) {
|
||||
if ( name.equals( parameter.getName() ) ) {
|
||||
return parameter;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException( "Could not locate parameter registered under that name [" + name + "]" ); }
|
||||
|
||||
@Override
|
||||
public StoredProcedureParameterImplementor getRegisteredParameter(int position) {
|
||||
try {
|
||||
return registeredParameters.get( position );
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new QueryException( "Could not locate parameter registered using that position [" + position + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureOutputs getOutputs() {
|
||||
|
||||
// todo : going to need a very specialized Loader for this.
|
||||
// or, might be a good time to look at splitting Loader up into:
|
||||
// 1) building statement objects
|
||||
// 2) executing statement objects
|
||||
// 3) processing result sets
|
||||
|
||||
// for now assume there are no resultClasses nor mappings defined..
|
||||
// TOTAL PROOF-OF-CONCEPT!!!!!!
|
||||
|
||||
final StringBuilder buffer = new StringBuilder().append( "{call " )
|
||||
.append( procedureName )
|
||||
.append( "(" );
|
||||
String sep = "";
|
||||
for ( StoredProcedureParameterImplementor parameter : registeredParameters ) {
|
||||
for ( int i = 0; i < parameter.getSqlTypes().length; i++ ) {
|
||||
buffer.append( sep ).append( "?" );
|
||||
sep = ",";
|
||||
}
|
||||
}
|
||||
buffer.append( ")}" );
|
||||
|
||||
try {
|
||||
final CallableStatement statement = session().getTransactionCoordinator()
|
||||
.getJdbcCoordinator()
|
||||
.getLogicalConnection()
|
||||
.getShareableConnectionProxy()
|
||||
.prepareCall( buffer.toString() );
|
||||
|
||||
// prepare parameters
|
||||
int i = 1;
|
||||
for ( StoredProcedureParameterImplementor parameter : registeredParameters ) {
|
||||
if ( parameter == null ) {
|
||||
throw new QueryException( "Registered stored procedure parameters had gaps" );
|
||||
}
|
||||
|
||||
parameter.prepare( statement, i );
|
||||
i += parameter.getSqlTypes().length;
|
||||
}
|
||||
|
||||
return new StoredProcedureOutputsImpl( this, statement );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw session().getFactory().getSQLExceptionHelper().convert(
|
||||
e,
|
||||
"Error preparing CallableStatement",
|
||||
getProcedureName()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Type[] getReturnTypes() throws HibernateException {
|
||||
throw new NotYetImplementedException();
|
||||
}
|
||||
|
||||
protected Set<String> synchronizedQuerySpaces() {
|
||||
if ( synchronizedQuerySpaces == null ) {
|
||||
synchronizedQuerySpaces = new HashSet<String>();
|
||||
}
|
||||
return synchronizedQuerySpaces;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<String> getSynchronizedQuerySpaces() {
|
||||
if ( synchronizedQuerySpaces == null ) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
else {
|
||||
return Collections.unmodifiableSet( synchronizedQuerySpaces );
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> getSynchronizedQuerySpacesSet() {
|
||||
return (Set<String>) getSynchronizedQuerySpaces();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureCallImpl addSynchronizedQuerySpace(String querySpace) {
|
||||
synchronizedQuerySpaces().add( querySpace );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureCallImpl addSynchronizedEntityName(String entityName) {
|
||||
addSynchronizedQuerySpaces( session().getFactory().getEntityPersister( entityName ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void addSynchronizedQuerySpaces(EntityPersister persister) {
|
||||
synchronizedQuerySpaces().addAll( Arrays.asList( (String[]) persister.getQuerySpaces() ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureCallImpl addSynchronizedEntityClass(Class entityClass) {
|
||||
addSynchronizedQuerySpaces( session().getFactory().getEntityPersister( entityClass.getName() ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryParameters buildQueryParametersObject() {
|
||||
QueryParameters qp = super.buildQueryParametersObject();
|
||||
// both of these are for documentation purposes, they are actually handled directly...
|
||||
qp.setAutoDiscoverScalarTypes( true );
|
||||
qp.setCallable( true );
|
||||
return qp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ternary logic enum
|
||||
*/
|
||||
private static enum TypeOfParameter {
|
||||
NAMED,
|
||||
POSITIONAL,
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
protected static interface StoredProcedureParameterImplementor<T> extends StoredProcedureParameter<T> {
|
||||
public void prepare(CallableStatement statement, int i) throws SQLException;
|
||||
|
||||
public int[] getSqlTypes();
|
||||
|
||||
public T extract(CallableStatement statement);
|
||||
}
|
||||
|
||||
public static abstract class AbstractStoredProcedureParameterImpl<T> implements StoredProcedureParameterImplementor<T> {
|
||||
private final StoredProcedureCallImpl procedureCall;
|
||||
|
||||
private final ParameterMode mode;
|
||||
private final Class<T> type;
|
||||
|
||||
private int startIndex;
|
||||
private Type hibernateType;
|
||||
private int[] sqlTypes;
|
||||
|
||||
private StoredProcedureParameterBindImpl bind;
|
||||
|
||||
protected AbstractStoredProcedureParameterImpl(
|
||||
StoredProcedureCallImpl procedureCall,
|
||||
ParameterMode mode,
|
||||
Class<T> type) {
|
||||
this.procedureCall = procedureCall;
|
||||
this.mode = mode;
|
||||
this.type = type;
|
||||
|
||||
setHibernateType( session().getFactory().getTypeResolver().heuristicType( type.getName() ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPosition() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHibernateType(Type type) {
|
||||
if ( type == null ) {
|
||||
throw new IllegalArgumentException( "Type cannot be null" );
|
||||
}
|
||||
this.hibernateType = type;
|
||||
this.sqlTypes = hibernateType.sqlTypes( session().getFactory() );
|
||||
}
|
||||
|
||||
protected SessionImplementor session() {
|
||||
return procedureCall.session();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare(CallableStatement statement, int startIndex) throws SQLException {
|
||||
if ( mode == ParameterMode.REF_CURSOR ) {
|
||||
throw new NotYetImplementedException( "Support for REF_CURSOR parameters not yet supported" );
|
||||
}
|
||||
|
||||
this.startIndex = startIndex;
|
||||
if ( mode == ParameterMode.IN || mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) {
|
||||
if ( mode == ParameterMode.INOUT || mode == ParameterMode.OUT ) {
|
||||
if ( sqlTypes.length > 1 ) {
|
||||
if ( ProcedureParameterExtractionAware.class.isInstance( hibernateType )
|
||||
&& ( (ProcedureParameterExtractionAware) hibernateType ).canDoExtraction() ) {
|
||||
// the type can handle multi-param extraction...
|
||||
}
|
||||
else {
|
||||
// it cannot...
|
||||
throw new UnsupportedOperationException(
|
||||
"Type [" + hibernateType + "] does support multi-parameter value extraction"
|
||||
);
|
||||
}
|
||||
}
|
||||
for ( int i = 0; i < sqlTypes.length; i++ ) {
|
||||
statement.registerOutParameter( startIndex + i, sqlTypes[i] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( mode == ParameterMode.INOUT || mode == ParameterMode.IN ) {
|
||||
if ( bind == null || bind.getValue() == null ) {
|
||||
log.debugf(
|
||||
"Stored procedure [%s] IN/INOUT parameter [%s] not bound; assuming procedure defines default value",
|
||||
procedureCall.getProcedureName(),
|
||||
this
|
||||
);
|
||||
}
|
||||
else {
|
||||
final Type typeToUse;
|
||||
if ( bind.getExplicitTemporalType() != null && bind.getExplicitTemporalType() == TemporalType.TIMESTAMP ) {
|
||||
typeToUse = hibernateType;
|
||||
}
|
||||
else if ( bind.getExplicitTemporalType() != null && bind.getExplicitTemporalType() == TemporalType.DATE ) {
|
||||
typeToUse = DateType.INSTANCE;
|
||||
}
|
||||
else {
|
||||
typeToUse = hibernateType;
|
||||
}
|
||||
typeToUse.nullSafeSet( statement, bind.getValue(), startIndex, session() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int[] getSqlTypes() {
|
||||
return sqlTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureParameterBind getParameterBind() {
|
||||
return bind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindValue(T value) {
|
||||
this.bind = new StoredProcedureParameterBindImpl<T>( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindValue(T value, TemporalType explicitTemporalType) {
|
||||
if ( explicitTemporalType != null ) {
|
||||
if ( ! isDateTimeType() ) {
|
||||
throw new IllegalArgumentException( "TemporalType should not be specified for non date/time type" );
|
||||
}
|
||||
}
|
||||
this.bind = new StoredProcedureParameterBindImpl<T>( value, explicitTemporalType );
|
||||
}
|
||||
|
||||
private boolean isDateTimeType() {
|
||||
return Date.class.isAssignableFrom( type )
|
||||
|| Calendar.class.isAssignableFrom( type );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public T extract(CallableStatement statement) {
|
||||
try {
|
||||
if ( ProcedureParameterExtractionAware.class.isInstance( hibernateType ) ) {
|
||||
return (T) ( (ProcedureParameterExtractionAware) hibernateType ).extract( statement, startIndex, session() );
|
||||
}
|
||||
else {
|
||||
return (T) statement.getObject( startIndex );
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw procedureCall.session().getFactory().getSQLExceptionHelper().convert(
|
||||
e,
|
||||
"Unable to extract OUT/INOUT parameter value"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class StoredProcedureParameterBindImpl<T> implements StoredProcedureParameterBind<T> {
|
||||
private final T value;
|
||||
private final TemporalType explicitTemporalType;
|
||||
|
||||
public StoredProcedureParameterBindImpl(T value) {
|
||||
this( value, null );
|
||||
}
|
||||
|
||||
public StoredProcedureParameterBindImpl(T value, TemporalType explicitTemporalType) {
|
||||
this.value = value;
|
||||
this.explicitTemporalType = explicitTemporalType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporalType getExplicitTemporalType() {
|
||||
return explicitTemporalType;
|
||||
}
|
||||
}
|
||||
|
||||
public static class NamedStoredProcedureParameter<T> extends AbstractStoredProcedureParameterImpl<T> {
|
||||
private final String name;
|
||||
|
||||
public NamedStoredProcedureParameter(
|
||||
StoredProcedureCallImpl procedureCall,
|
||||
String name,
|
||||
ParameterMode mode,
|
||||
Class<T> type) {
|
||||
super( procedureCall, mode, type );
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PositionalStoredProcedureParameter<T> extends AbstractStoredProcedureParameterImpl<T> {
|
||||
private final Integer position;
|
||||
|
||||
public PositionalStoredProcedureParameter(
|
||||
StoredProcedureCallImpl procedureCall,
|
||||
Integer position,
|
||||
ParameterMode mode,
|
||||
Class<T> type) {
|
||||
super( procedureCall, mode, type );
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.internal;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.StoredProcedureOutputs;
|
||||
import org.hibernate.StoredProcedureResultSetReturn;
|
||||
import org.hibernate.StoredProcedureReturn;
|
||||
import org.hibernate.StoredProcedureUpdateCountReturn;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.loader.custom.CustomLoader;
|
||||
import org.hibernate.loader.custom.CustomQuery;
|
||||
import org.hibernate.loader.custom.Return;
|
||||
import org.hibernate.loader.custom.sql.SQLQueryReturnProcessor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class StoredProcedureOutputsImpl implements StoredProcedureOutputs {
|
||||
private final StoredProcedureCallImpl procedureCall;
|
||||
private final CallableStatement callableStatement;
|
||||
|
||||
private final CustomLoaderExtension loader;
|
||||
|
||||
private CurrentReturnDescriptor currentReturnDescriptor;
|
||||
private boolean executed = false;
|
||||
|
||||
StoredProcedureOutputsImpl(StoredProcedureCallImpl procedureCall, CallableStatement callableStatement) {
|
||||
this.procedureCall = procedureCall;
|
||||
this.callableStatement = callableStatement;
|
||||
|
||||
// For now...
|
||||
this.loader = buildSpecializedCustomLoader( procedureCall );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOutputParameterValue(String name) {
|
||||
return procedureCall.getRegisteredParameter( name ).extract( callableStatement );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOutputParameterValue(int position) {
|
||||
return procedureCall.getRegisteredParameter( position ).extract( callableStatement );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreReturns() {
|
||||
if ( currentReturnDescriptor == null ) {
|
||||
final boolean isResultSet;
|
||||
|
||||
if ( executed ) {
|
||||
try {
|
||||
isResultSet = callableStatement.getMoreResults();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw convert( e, "Error calling CallableStatement.getMoreResults" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
isResultSet = callableStatement.execute();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw convert( e, "Error calling CallableStatement.execute" );
|
||||
}
|
||||
executed = true;
|
||||
}
|
||||
|
||||
int updateCount = -1;
|
||||
if ( ! isResultSet ) {
|
||||
try {
|
||||
updateCount = callableStatement.getUpdateCount();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw convert( e, "Error calling CallableStatement.getUpdateCount" );
|
||||
}
|
||||
}
|
||||
|
||||
currentReturnDescriptor = new CurrentReturnDescriptor( isResultSet, updateCount );
|
||||
}
|
||||
|
||||
return hasMoreResults( currentReturnDescriptor );
|
||||
}
|
||||
|
||||
private boolean hasMoreResults(CurrentReturnDescriptor descriptor) {
|
||||
return currentReturnDescriptor.isResultSet || currentReturnDescriptor.updateCount >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureReturn getNextReturn() {
|
||||
if ( currentReturnDescriptor == null ) {
|
||||
if ( executed ) {
|
||||
throw new IllegalStateException( "Unexpected condition" );
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException( "hasMoreReturns() not called before getNextReturn()" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! hasMoreResults( currentReturnDescriptor ) ) {
|
||||
throw new IllegalStateException( "Results have been exhausted" );
|
||||
}
|
||||
|
||||
CurrentReturnDescriptor copyReturnDescriptor = currentReturnDescriptor;
|
||||
currentReturnDescriptor = null;
|
||||
|
||||
if ( copyReturnDescriptor.isResultSet ) {
|
||||
try {
|
||||
return new ResultSetReturn( this, callableStatement.getResultSet() );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw convert( e, "Error calling CallableStatement.getResultSet" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
return new UpdateCountReturn( this, copyReturnDescriptor.updateCount );
|
||||
}
|
||||
}
|
||||
|
||||
protected JDBCException convert(SQLException e, String message) {
|
||||
return procedureCall.session().getFactory().getSQLExceptionHelper().convert( e, message, procedureCall.getProcedureName() );
|
||||
}
|
||||
|
||||
private static class CurrentReturnDescriptor {
|
||||
private final boolean isResultSet;
|
||||
private final int updateCount;
|
||||
|
||||
private CurrentReturnDescriptor(boolean resultSet, int updateCount) {
|
||||
isResultSet = resultSet;
|
||||
this.updateCount = updateCount;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ResultSetReturn implements StoredProcedureResultSetReturn {
|
||||
private final StoredProcedureOutputsImpl storedProcedureOutputs;
|
||||
private final ResultSet resultSet;
|
||||
|
||||
public ResultSetReturn(StoredProcedureOutputsImpl storedProcedureOutputs, ResultSet resultSet) {
|
||||
this.storedProcedureOutputs = storedProcedureOutputs;
|
||||
this.resultSet = resultSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResultSet() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public List getResultList() {
|
||||
try {
|
||||
return storedProcedureOutputs.loader.processResultSet( resultSet );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw storedProcedureOutputs.convert( e, "Error calling ResultSet.next" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSingleResult() {
|
||||
List results = getResultList();
|
||||
if ( results == null || results.isEmpty() ) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return results.get( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class UpdateCountReturn implements StoredProcedureUpdateCountReturn {
|
||||
private final StoredProcedureOutputsImpl storedProcedureOutputs;
|
||||
private final int updateCount;
|
||||
|
||||
public UpdateCountReturn(StoredProcedureOutputsImpl storedProcedureOutputs, int updateCount) {
|
||||
this.storedProcedureOutputs = storedProcedureOutputs;
|
||||
this.updateCount = updateCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUpdateCount() {
|
||||
return updateCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResultSet() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static CustomLoaderExtension buildSpecializedCustomLoader(final StoredProcedureCallImpl procedureCall) {
|
||||
final SQLQueryReturnProcessor processor = new SQLQueryReturnProcessor(
|
||||
procedureCall.getQueryReturns(),
|
||||
procedureCall.session().getFactory()
|
||||
);
|
||||
processor.process();
|
||||
final List<Return> customReturns = processor.generateCustomReturns( false );
|
||||
|
||||
CustomQuery customQuery = new CustomQuery() {
|
||||
@Override
|
||||
public String getSQL() {
|
||||
return procedureCall.getProcedureName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getQuerySpaces() {
|
||||
return procedureCall.getSynchronizedQuerySpacesSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map getNamedParameterBindPoints() {
|
||||
// no named parameters in terms of embedded in the SQL string
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Return> getCustomQueryReturns() {
|
||||
return customReturns;
|
||||
}
|
||||
};
|
||||
|
||||
return new CustomLoaderExtension(
|
||||
customQuery,
|
||||
procedureCall.buildQueryParametersObject(),
|
||||
procedureCall.session()
|
||||
);
|
||||
}
|
||||
|
||||
private static class CustomLoaderExtension extends CustomLoader {
|
||||
private QueryParameters queryParameters;
|
||||
private SessionImplementor session;
|
||||
|
||||
public CustomLoaderExtension(
|
||||
CustomQuery customQuery,
|
||||
QueryParameters queryParameters,
|
||||
SessionImplementor session) {
|
||||
super( customQuery, session.getFactory() );
|
||||
this.queryParameters = queryParameters;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public List processResultSet(ResultSet resultSet) throws SQLException {
|
||||
super.autoDiscoverTypes( resultSet );
|
||||
return super.processResultSet(
|
||||
resultSet,
|
||||
queryParameters,
|
||||
session,
|
||||
true,
|
||||
null,
|
||||
Integer.MAX_VALUE
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ import java.sql.CallableStatement;
|
|||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
@ -668,12 +669,9 @@ public abstract class Loader {
|
|||
|
||||
applyPostLoadLocks( row, lockModesArray, session );
|
||||
|
||||
return forcedResultTransformer == null ?
|
||||
getResultColumnOrRow( row, queryParameters.getResultTransformer(), resultSet, session ) :
|
||||
forcedResultTransformer.transformTuple(
|
||||
getResultRow( row, resultSet, session ),
|
||||
getResultRowAliases()
|
||||
)
|
||||
return forcedResultTransformer == null
|
||||
? getResultColumnOrRow( row, queryParameters.getResultTransformer(), resultSet, session )
|
||||
: forcedResultTransformer.transformTuple( getResultRow( row, resultSet, session ), getResultRowAliases() )
|
||||
;
|
||||
}
|
||||
|
||||
|
@ -825,11 +823,8 @@ public abstract class Loader {
|
|||
selection.getMaxRows() :
|
||||
Integer.MAX_VALUE;
|
||||
|
||||
final int entitySpan = getEntityPersisters().length;
|
||||
|
||||
final ArrayList hydratedObjects = entitySpan == 0 ? null : new ArrayList( entitySpan * 10 );
|
||||
final ResultSet rs = executeQueryStatement( queryParameters, false, session );
|
||||
final PreparedStatement st = (PreparedStatement) rs.getStatement();
|
||||
final Statement st = rs.getStatement();
|
||||
|
||||
// would be great to move all this below here into another method that could also be used
|
||||
// from the new scrolling stuff.
|
||||
|
@ -837,47 +832,59 @@ public abstract class Loader {
|
|||
// Would need to change the way the max-row stuff is handled (i.e. behind an interface) so
|
||||
// that I could do the control breaking at the means to know when to stop
|
||||
|
||||
final EntityKey optionalObjectKey = getOptionalObjectKey( queryParameters, session );
|
||||
final LockMode[] lockModesArray = getLockModes( queryParameters.getLockOptions() );
|
||||
final boolean createSubselects = isSubselectLoadingEnabled();
|
||||
final List subselectResultKeys = createSubselects ? new ArrayList() : null;
|
||||
final List results = new ArrayList();
|
||||
|
||||
try {
|
||||
handleEmptyCollections( queryParameters.getCollectionKeys(), rs, session );
|
||||
EntityKey[] keys = new EntityKey[entitySpan]; //we can reuse it for each row
|
||||
LOG.trace( "Processing result set" );
|
||||
int count;
|
||||
for ( count = 0; count < maxRows && rs.next(); count++ ) {
|
||||
LOG.debugf( "Result set row: %s", count );
|
||||
Object result = getRowFromResultSet(
|
||||
rs,
|
||||
session,
|
||||
queryParameters,
|
||||
lockModesArray,
|
||||
optionalObjectKey,
|
||||
hydratedObjects,
|
||||
keys,
|
||||
returnProxies,
|
||||
forcedResultTransformer
|
||||
);
|
||||
results.add( result );
|
||||
if ( createSubselects ) {
|
||||
subselectResultKeys.add(keys);
|
||||
keys = new EntityKey[entitySpan]; //can't reuse in this case
|
||||
}
|
||||
}
|
||||
|
||||
LOG.tracev( "Done processing result set ({0} rows)", count );
|
||||
|
||||
return processResultSet( rs, queryParameters, session, returnProxies, forcedResultTransformer, maxRows );
|
||||
}
|
||||
finally {
|
||||
st.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected List processResultSet(
|
||||
ResultSet rs,
|
||||
QueryParameters queryParameters,
|
||||
SessionImplementor session,
|
||||
boolean returnProxies,
|
||||
ResultTransformer forcedResultTransformer,
|
||||
int maxRows) throws SQLException {
|
||||
final int entitySpan = getEntityPersisters().length;
|
||||
final EntityKey optionalObjectKey = getOptionalObjectKey( queryParameters, session );
|
||||
final LockMode[] lockModesArray = getLockModes( queryParameters.getLockOptions() );
|
||||
final boolean createSubselects = isSubselectLoadingEnabled();
|
||||
final List subselectResultKeys = createSubselects ? new ArrayList() : null;
|
||||
final ArrayList hydratedObjects = entitySpan == 0 ? null : new ArrayList( entitySpan * 10 );
|
||||
final List results = new ArrayList();
|
||||
|
||||
handleEmptyCollections( queryParameters.getCollectionKeys(), rs, session );
|
||||
EntityKey[] keys = new EntityKey[entitySpan]; //we can reuse it for each row
|
||||
LOG.trace( "Processing result set" );
|
||||
int count;
|
||||
for ( count = 0; count < maxRows && rs.next(); count++ ) {
|
||||
LOG.debugf( "Result set row: %s", count );
|
||||
Object result = getRowFromResultSet(
|
||||
rs,
|
||||
session,
|
||||
queryParameters,
|
||||
lockModesArray,
|
||||
optionalObjectKey,
|
||||
hydratedObjects,
|
||||
keys,
|
||||
returnProxies,
|
||||
forcedResultTransformer
|
||||
);
|
||||
results.add( result );
|
||||
if ( createSubselects ) {
|
||||
subselectResultKeys.add(keys);
|
||||
keys = new EntityKey[entitySpan]; //can't reuse in this case
|
||||
}
|
||||
}
|
||||
|
||||
LOG.tracev( "Done processing result set ({0} rows)", count );
|
||||
|
||||
initializeEntitiesAndCollections( hydratedObjects, rs, session, queryParameters.isReadOnly( session ) );
|
||||
if ( createSubselects ) createSubselects( subselectResultKeys, queryParameters, session );
|
||||
return results;
|
||||
|
||||
}
|
||||
|
||||
protected boolean isSubselectLoadingEnabled() {
|
||||
|
@ -1060,8 +1067,11 @@ public abstract class Loader {
|
|||
* This empty implementation merely returns its first argument. This is
|
||||
* overridden by some subclasses.
|
||||
*/
|
||||
protected Object getResultColumnOrRow(Object[] row, ResultTransformer transformer, ResultSet rs, SessionImplementor session)
|
||||
throws SQLException, HibernateException {
|
||||
protected Object getResultColumnOrRow(
|
||||
Object[] row,
|
||||
ResultTransformer transformer,
|
||||
ResultSet rs,
|
||||
SessionImplementor session) throws SQLException, HibernateException {
|
||||
return row;
|
||||
}
|
||||
|
||||
|
@ -1069,10 +1079,10 @@ public abstract class Loader {
|
|||
return null;
|
||||
}
|
||||
|
||||
protected Object[] getResultRow(Object[] row,
|
||||
ResultSet rs,
|
||||
SessionImplementor session)
|
||||
throws SQLException, HibernateException {
|
||||
protected Object[] getResultRow(
|
||||
Object[] row,
|
||||
ResultSet rs,
|
||||
SessionImplementor session) throws SQLException, HibernateException {
|
||||
return row;
|
||||
}
|
||||
|
||||
|
@ -1455,7 +1465,7 @@ public abstract class Loader {
|
|||
persister,
|
||||
key.getIdentifier(),
|
||||
session
|
||||
);
|
||||
);
|
||||
|
||||
final Object object;
|
||||
if ( optionalObjectKey != null && key.equals( optionalObjectKey ) ) {
|
||||
|
@ -1687,7 +1697,10 @@ public abstract class Loader {
|
|||
queryParameters.processFilters( getSQLString(), session );
|
||||
|
||||
// Applying LIMIT clause.
|
||||
final LimitHandler limitHandler = getLimitHandler( queryParameters.getFilteredSQL(), queryParameters.getRowSelection() );
|
||||
final LimitHandler limitHandler = getLimitHandler(
|
||||
queryParameters.getFilteredSQL(),
|
||||
queryParameters.getRowSelection()
|
||||
);
|
||||
String sql = limitHandler.getProcessedSql();
|
||||
|
||||
// Adding locks and comments.
|
||||
|
|
|
@ -50,7 +50,7 @@ public interface CustomQuery {
|
|||
*
|
||||
* @return The query spaces
|
||||
*/
|
||||
public Set getQuerySpaces();
|
||||
public Set<String> getQuerySpaces();
|
||||
|
||||
/**
|
||||
* A map representing positions within the supplied {@link #getSQL query} to
|
||||
|
@ -73,5 +73,5 @@ public interface CustomQuery {
|
|||
*
|
||||
* @return List of return descriptors.
|
||||
*/
|
||||
public List getCustomQueryReturns();
|
||||
public List<Return> getCustomQueryReturns();
|
||||
}
|
||||
|
|
|
@ -156,49 +156,49 @@ public class SQLQueryReturnProcessor {
|
|||
public ResultAliasContext process() {
|
||||
// first, break down the returns into maps keyed by alias
|
||||
// so that role returns can be more easily resolved to their owners
|
||||
for ( int i = 0; i < queryReturns.length; i++ ) {
|
||||
if ( queryReturns[i] instanceof NativeSQLQueryNonScalarReturn ) {
|
||||
NativeSQLQueryNonScalarReturn rtn = ( NativeSQLQueryNonScalarReturn ) queryReturns[i];
|
||||
for ( NativeSQLQueryReturn queryReturn : queryReturns ) {
|
||||
if ( queryReturn instanceof NativeSQLQueryNonScalarReturn ) {
|
||||
NativeSQLQueryNonScalarReturn rtn = (NativeSQLQueryNonScalarReturn) queryReturn;
|
||||
alias2Return.put( rtn.getAlias(), rtn );
|
||||
if ( rtn instanceof NativeSQLQueryJoinReturn ) {
|
||||
NativeSQLQueryJoinReturn fetchReturn = ( NativeSQLQueryJoinReturn ) rtn;
|
||||
NativeSQLQueryJoinReturn fetchReturn = (NativeSQLQueryJoinReturn) rtn;
|
||||
alias2OwnerAlias.put( fetchReturn.getAlias(), fetchReturn.getOwnerAlias() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now, process the returns
|
||||
for ( int i = 0; i < queryReturns.length; i++ ) {
|
||||
processReturn( queryReturns[i] );
|
||||
for ( NativeSQLQueryReturn queryReturn : queryReturns ) {
|
||||
processReturn( queryReturn );
|
||||
}
|
||||
|
||||
return new ResultAliasContext();
|
||||
}
|
||||
|
||||
public List generateCustomReturns(boolean queryHadAliases) {
|
||||
List customReturns = new ArrayList();
|
||||
Map customReturnsByAlias = new HashMap();
|
||||
for ( int i = 0; i < queryReturns.length; i++ ) {
|
||||
if ( queryReturns[i] instanceof NativeSQLQueryScalarReturn ) {
|
||||
NativeSQLQueryScalarReturn rtn = ( NativeSQLQueryScalarReturn ) queryReturns[i];
|
||||
public List<Return> generateCustomReturns(boolean queryHadAliases) {
|
||||
List<Return> customReturns = new ArrayList<Return>();
|
||||
Map<String,Return> customReturnsByAlias = new HashMap<String,Return>();
|
||||
for ( NativeSQLQueryReturn queryReturn : queryReturns ) {
|
||||
if ( queryReturn instanceof NativeSQLQueryScalarReturn ) {
|
||||
NativeSQLQueryScalarReturn rtn = (NativeSQLQueryScalarReturn) queryReturn;
|
||||
customReturns.add( new ScalarReturn( rtn.getType(), rtn.getColumnAlias() ) );
|
||||
}
|
||||
else if ( queryReturns[i] instanceof NativeSQLQueryRootReturn ) {
|
||||
NativeSQLQueryRootReturn rtn = ( NativeSQLQueryRootReturn ) queryReturns[i];
|
||||
else if ( queryReturn instanceof NativeSQLQueryRootReturn ) {
|
||||
NativeSQLQueryRootReturn rtn = (NativeSQLQueryRootReturn) queryReturn;
|
||||
String alias = rtn.getAlias();
|
||||
EntityAliases entityAliases;
|
||||
if ( queryHadAliases || hasPropertyResultMap( alias ) ) {
|
||||
entityAliases = new DefaultEntityAliases(
|
||||
( Map ) entityPropertyResultMaps.get( alias ),
|
||||
( SQLLoadable ) alias2Persister.get( alias ),
|
||||
( String ) alias2Suffix.get( alias )
|
||||
(Map) entityPropertyResultMaps.get( alias ),
|
||||
(SQLLoadable) alias2Persister.get( alias ),
|
||||
(String) alias2Suffix.get( alias )
|
||||
);
|
||||
}
|
||||
else {
|
||||
entityAliases = new ColumnEntityAliases(
|
||||
( Map ) entityPropertyResultMaps.get( alias ),
|
||||
( SQLLoadable ) alias2Persister.get( alias ),
|
||||
( String ) alias2Suffix.get( alias )
|
||||
(Map) entityPropertyResultMaps.get( alias ),
|
||||
(SQLLoadable) alias2Persister.get( alias ),
|
||||
(String) alias2Suffix.get( alias )
|
||||
);
|
||||
}
|
||||
RootReturn customReturn = new RootReturn(
|
||||
|
@ -210,37 +210,37 @@ public class SQLQueryReturnProcessor {
|
|||
customReturns.add( customReturn );
|
||||
customReturnsByAlias.put( rtn.getAlias(), customReturn );
|
||||
}
|
||||
else if ( queryReturns[i] instanceof NativeSQLQueryCollectionReturn ) {
|
||||
NativeSQLQueryCollectionReturn rtn = ( NativeSQLQueryCollectionReturn ) queryReturns[i];
|
||||
else if ( queryReturn instanceof NativeSQLQueryCollectionReturn ) {
|
||||
NativeSQLQueryCollectionReturn rtn = (NativeSQLQueryCollectionReturn) queryReturn;
|
||||
String alias = rtn.getAlias();
|
||||
SQLLoadableCollection persister = ( SQLLoadableCollection ) alias2CollectionPersister.get( alias );
|
||||
SQLLoadableCollection persister = (SQLLoadableCollection) alias2CollectionPersister.get( alias );
|
||||
boolean isEntityElements = persister.getElementType().isEntityType();
|
||||
CollectionAliases collectionAliases;
|
||||
EntityAliases elementEntityAliases = null;
|
||||
if ( queryHadAliases || hasPropertyResultMap( alias ) ) {
|
||||
collectionAliases = new GeneratedCollectionAliases(
|
||||
( Map ) collectionPropertyResultMaps.get( alias ),
|
||||
( SQLLoadableCollection ) alias2CollectionPersister.get( alias ),
|
||||
( String ) alias2CollectionSuffix.get( alias )
|
||||
(Map) collectionPropertyResultMaps.get( alias ),
|
||||
(SQLLoadableCollection) alias2CollectionPersister.get( alias ),
|
||||
(String) alias2CollectionSuffix.get( alias )
|
||||
);
|
||||
if ( isEntityElements ) {
|
||||
elementEntityAliases = new DefaultEntityAliases(
|
||||
( Map ) entityPropertyResultMaps.get( alias ),
|
||||
( SQLLoadable ) alias2Persister.get( alias ),
|
||||
( String ) alias2Suffix.get( alias )
|
||||
(Map) entityPropertyResultMaps.get( alias ),
|
||||
(SQLLoadable) alias2Persister.get( alias ),
|
||||
(String) alias2Suffix.get( alias )
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
collectionAliases = new ColumnCollectionAliases(
|
||||
( Map ) collectionPropertyResultMaps.get( alias ),
|
||||
( SQLLoadableCollection ) alias2CollectionPersister.get( alias )
|
||||
(Map) collectionPropertyResultMaps.get( alias ),
|
||||
(SQLLoadableCollection) alias2CollectionPersister.get( alias )
|
||||
);
|
||||
if ( isEntityElements ) {
|
||||
elementEntityAliases = new ColumnEntityAliases(
|
||||
( Map ) entityPropertyResultMaps.get( alias ),
|
||||
( SQLLoadable ) alias2Persister.get( alias ),
|
||||
( String ) alias2Suffix.get( alias )
|
||||
(Map) entityPropertyResultMaps.get( alias ),
|
||||
(SQLLoadable) alias2Persister.get( alias ),
|
||||
(String) alias2Suffix.get( alias )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -249,46 +249,46 @@ public class SQLQueryReturnProcessor {
|
|||
rtn.getOwnerEntityName(),
|
||||
rtn.getOwnerProperty(),
|
||||
collectionAliases,
|
||||
elementEntityAliases,
|
||||
elementEntityAliases,
|
||||
rtn.getLockMode()
|
||||
);
|
||||
customReturns.add( customReturn );
|
||||
customReturnsByAlias.put( rtn.getAlias(), customReturn );
|
||||
}
|
||||
else if ( queryReturns[i] instanceof NativeSQLQueryJoinReturn ) {
|
||||
NativeSQLQueryJoinReturn rtn = ( NativeSQLQueryJoinReturn ) queryReturns[i];
|
||||
else if ( queryReturn instanceof NativeSQLQueryJoinReturn ) {
|
||||
NativeSQLQueryJoinReturn rtn = (NativeSQLQueryJoinReturn) queryReturn;
|
||||
String alias = rtn.getAlias();
|
||||
FetchReturn customReturn;
|
||||
NonScalarReturn ownerCustomReturn = ( NonScalarReturn ) customReturnsByAlias.get( rtn.getOwnerAlias() );
|
||||
NonScalarReturn ownerCustomReturn = (NonScalarReturn) customReturnsByAlias.get( rtn.getOwnerAlias() );
|
||||
if ( alias2CollectionPersister.containsKey( alias ) ) {
|
||||
SQLLoadableCollection persister = ( SQLLoadableCollection ) alias2CollectionPersister.get( alias );
|
||||
SQLLoadableCollection persister = (SQLLoadableCollection) alias2CollectionPersister.get( alias );
|
||||
boolean isEntityElements = persister.getElementType().isEntityType();
|
||||
CollectionAliases collectionAliases;
|
||||
EntityAliases elementEntityAliases = null;
|
||||
if ( queryHadAliases || hasPropertyResultMap( alias ) ) {
|
||||
collectionAliases = new GeneratedCollectionAliases(
|
||||
( Map ) collectionPropertyResultMaps.get( alias ),
|
||||
(Map) collectionPropertyResultMaps.get( alias ),
|
||||
persister,
|
||||
( String ) alias2CollectionSuffix.get( alias )
|
||||
(String) alias2CollectionSuffix.get( alias )
|
||||
);
|
||||
if ( isEntityElements ) {
|
||||
elementEntityAliases = new DefaultEntityAliases(
|
||||
( Map ) entityPropertyResultMaps.get( alias ),
|
||||
( SQLLoadable ) alias2Persister.get( alias ),
|
||||
( String ) alias2Suffix.get( alias )
|
||||
(Map) entityPropertyResultMaps.get( alias ),
|
||||
(SQLLoadable) alias2Persister.get( alias ),
|
||||
(String) alias2Suffix.get( alias )
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
collectionAliases = new ColumnCollectionAliases(
|
||||
( Map ) collectionPropertyResultMaps.get( alias ),
|
||||
(Map) collectionPropertyResultMaps.get( alias ),
|
||||
persister
|
||||
);
|
||||
if ( isEntityElements ) {
|
||||
elementEntityAliases = new ColumnEntityAliases(
|
||||
( Map ) entityPropertyResultMaps.get( alias ),
|
||||
( SQLLoadable ) alias2Persister.get( alias ),
|
||||
( String ) alias2Suffix.get( alias )
|
||||
(Map) entityPropertyResultMaps.get( alias ),
|
||||
(SQLLoadable) alias2Persister.get( alias ),
|
||||
(String) alias2Suffix.get( alias )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -297,7 +297,7 @@ public class SQLQueryReturnProcessor {
|
|||
ownerCustomReturn,
|
||||
rtn.getOwnerProperty(),
|
||||
collectionAliases,
|
||||
elementEntityAliases,
|
||||
elementEntityAliases,
|
||||
rtn.getLockMode()
|
||||
);
|
||||
}
|
||||
|
@ -305,16 +305,16 @@ public class SQLQueryReturnProcessor {
|
|||
EntityAliases entityAliases;
|
||||
if ( queryHadAliases || hasPropertyResultMap( alias ) ) {
|
||||
entityAliases = new DefaultEntityAliases(
|
||||
( Map ) entityPropertyResultMaps.get( alias ),
|
||||
( SQLLoadable ) alias2Persister.get( alias ),
|
||||
( String ) alias2Suffix.get( alias )
|
||||
(Map) entityPropertyResultMaps.get( alias ),
|
||||
(SQLLoadable) alias2Persister.get( alias ),
|
||||
(String) alias2Suffix.get( alias )
|
||||
);
|
||||
}
|
||||
else {
|
||||
entityAliases = new ColumnEntityAliases(
|
||||
( Map ) entityPropertyResultMaps.get( alias ),
|
||||
( SQLLoadable ) alias2Persister.get( alias ),
|
||||
( String ) alias2Suffix.get( alias )
|
||||
(Map) entityPropertyResultMaps.get( alias ),
|
||||
(SQLLoadable) alias2Persister.get( alias ),
|
||||
(String) alias2Suffix.get( alias )
|
||||
);
|
||||
}
|
||||
customReturn = new EntityFetchReturn(
|
||||
|
@ -378,10 +378,6 @@ public class SQLQueryReturnProcessor {
|
|||
addPersister( rootReturn.getAlias(), rootReturn.getPropertyResultsMap(), persister );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param propertyResult
|
||||
* @param persister
|
||||
*/
|
||||
private void addPersister(String alias, Map propertyResult, SQLLoadable persister) {
|
||||
alias2Persister.put( alias, persister );
|
||||
String suffix = generateEntitySuffix();
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
package org.hibernate.type;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -48,12 +49,12 @@ import org.hibernate.type.descriptor.java.MutabilityPlan;
|
|||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* Convenience base class for {@link BasicType} implementations
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractStandardBasicType<T>
|
||||
implements BasicType, StringRepresentableType<T>, XmlRepresentableType<T> {
|
||||
implements BasicType, StringRepresentableType<T>, XmlRepresentableType<T>, ProcedureParameterExtractionAware<T> {
|
||||
|
||||
private static final Size DEFAULT_SIZE = new Size( 19, 2, 255, Size.LobMultiplier.NONE ); // to match legacy behavior
|
||||
private final Size dictatedSize = new Size();
|
||||
|
@ -386,4 +387,32 @@ public abstract class AbstractStandardBasicType<T>
|
|||
? getReplacement( (T) original, (T) target, session )
|
||||
: target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDoExtraction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T extract(CallableStatement statement, int startIndex, final SessionImplementor session) throws SQLException {
|
||||
// todo : have SessionImplementor extend WrapperOptions
|
||||
final WrapperOptions options = new WrapperOptions() {
|
||||
public boolean useStreamForLobBinding() {
|
||||
return Environment.useStreamsForBinary();
|
||||
}
|
||||
|
||||
public LobCreator getLobCreator() {
|
||||
return Hibernate.getLobCreator( session );
|
||||
}
|
||||
|
||||
public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
|
||||
final SqlTypeDescriptor remapped = sqlTypeDescriptor.canBeRemapped()
|
||||
? session.getFactory().getDialect().remapSqlTypeDescriptor( sqlTypeDescriptor )
|
||||
: sqlTypeDescriptor;
|
||||
return remapped == null ? sqlTypeDescriptor : remapped;
|
||||
}
|
||||
};
|
||||
|
||||
return remapSqlTypeDescriptor( options ).getExtractor( javaTypeDescriptor ).extract( statement, startIndex, options );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ package org.hibernate.type;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -55,7 +56,7 @@ import org.hibernate.tuple.component.ComponentTuplizer;
|
|||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class ComponentType extends AbstractType implements CompositeType {
|
||||
public class ComponentType extends AbstractType implements CompositeType, ProcedureParameterExtractionAware {
|
||||
|
||||
private final TypeFactory.TypeScope typeScope;
|
||||
private final String[] propertyNames;
|
||||
|
@ -720,4 +721,55 @@ public class ComponentType extends AbstractType implements CompositeType {
|
|||
"Unable to locate property named " + name + " on " + getReturnedClass().getName()
|
||||
);
|
||||
}
|
||||
|
||||
private Boolean canDoExtraction;
|
||||
|
||||
@Override
|
||||
public boolean canDoExtraction() {
|
||||
if ( canDoExtraction == null ) {
|
||||
canDoExtraction = determineIfProcedureParamExtractionCanBePerformed();
|
||||
}
|
||||
return canDoExtraction;
|
||||
}
|
||||
|
||||
private boolean determineIfProcedureParamExtractionCanBePerformed() {
|
||||
for ( Type propertyType : propertyTypes ) {
|
||||
if ( ! ProcedureParameterExtractionAware.class.isInstance( propertyType ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! ( (ProcedureParameterExtractionAware) propertyType ).canDoExtraction() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object extract(CallableStatement statement, int startIndex, SessionImplementor session) throws SQLException {
|
||||
Object[] values = new Object[propertySpan];
|
||||
|
||||
int currentIndex = startIndex;
|
||||
boolean notNull = false;
|
||||
for ( int i = 0; i < propertySpan; i++ ) {
|
||||
// we know this cast is safe from canDoExtraction
|
||||
final ProcedureParameterExtractionAware propertyType = (ProcedureParameterExtractionAware) propertyTypes[i];
|
||||
final Object value = propertyType.extract( statement, currentIndex, session );
|
||||
if ( value == null ) {
|
||||
if ( isKey ) {
|
||||
return null; //different nullability rules for pk/fk
|
||||
}
|
||||
}
|
||||
else {
|
||||
notNull = true;
|
||||
}
|
||||
values[i] = value;
|
||||
currentIndex += propertyType.getColumnSpan( session.getFactory() );
|
||||
}
|
||||
|
||||
if ( ! notNull ) {
|
||||
values = null;
|
||||
}
|
||||
|
||||
return resolve( values, session, null );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -84,6 +85,11 @@ public class PostgresUUIDType extends AbstractSingleColumnStandardBasicType<UUID
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getObject( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getObject( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.type;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
||||
/**
|
||||
* Optional {@link Type} contract for implementations that are aware of how to extract values from
|
||||
* store procedure OUT/INOUT parameters.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ProcedureParameterExtractionAware<T> extends Type {
|
||||
/**
|
||||
* Can the given instance of this type actually perform the parameter value extractions?
|
||||
*
|
||||
* @return {@code true} indicates that @{link #extract} calls will not fail due to {@link IllegalStateException}.
|
||||
*/
|
||||
public boolean canDoExtraction();
|
||||
|
||||
/**
|
||||
* Perform the extraction
|
||||
*
|
||||
* @param statement The CallableStatement from which to extract the parameter value(s).
|
||||
* @param startIndex The parameter index from which to start extracting; assumes the values (if multiple) are contiguous
|
||||
* @param session The originating session
|
||||
*
|
||||
* @return The extracted value.
|
||||
*
|
||||
* @throws SQLException Indicates an issue calling into the CallableStatement
|
||||
* @throws IllegalStateException Thrown if this method is called on instances that return {@code false} for {@link #canDoExtraction}
|
||||
*/
|
||||
public T extract(CallableStatement statement, int startIndex, SessionImplementor session) throws SQLException;
|
||||
}
|
|
@ -22,11 +22,13 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.type.descriptor;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Contract for extracting a value from a {@link ResultSet}.
|
||||
* Contract for extracting value via JDBC (from {@link ResultSet} or as output param from {@link CallableStatement}).
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -43,4 +45,6 @@ public interface ValueExtractor<X> {
|
|||
* @throws SQLException Indicates a JDBC error occurred.
|
||||
*/
|
||||
public X extract(ResultSet rs, String name, WrapperOptions options) throws SQLException;
|
||||
|
||||
public X extract(CallableStatement rs, int index, WrapperOptions options) throws SQLException;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
@ -58,9 +59,7 @@ public abstract class BasicExtractor<J> implements ValueExtractor<J> {
|
|||
return sqlDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public J extract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
final J value = doExtract( rs, name, options );
|
||||
if ( value == null || rs.wasNull() ) {
|
||||
|
@ -90,4 +89,35 @@ public abstract class BasicExtractor<J> implements ValueExtractor<J> {
|
|||
* @throws SQLException Indicates a problem access the result set
|
||||
*/
|
||||
protected abstract J doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException;
|
||||
|
||||
@Override
|
||||
public J extract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
final J value = doExtract( statement, index, options );
|
||||
if ( value == null || statement.wasNull() ) {
|
||||
LOG.tracev( "Found [null] as procedure output parameter [{0}]", index );
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Found [{0}] as procedure output parameter [{1}]", getJavaDescriptor().extractLoggableRepresentation( value ), index );
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the extraction.
|
||||
* <p/>
|
||||
* Called from {@link #extract}. Null checking of the value (as well as consulting {@link ResultSet#wasNull}) is
|
||||
* done there.
|
||||
*
|
||||
* @param statement The callable statement containing the output parameter
|
||||
* @param index The index (position) of the output parameter
|
||||
* @param options The binding options
|
||||
*
|
||||
* @return The extracted value.
|
||||
*
|
||||
* @throws SQLException Indicates a problem accessing the parameter value
|
||||
*/
|
||||
protected abstract J doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -65,6 +66,11 @@ public class BigIntTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getLong( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getLong( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -68,6 +69,11 @@ public class BitTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getBoolean( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getBoolean( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.Blob;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -117,6 +118,11 @@ public abstract class BlobTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getBlob( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getBlob( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -65,6 +66,11 @@ public class BooleanTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getBoolean( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getBoolean( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Clob;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
|
@ -107,6 +108,11 @@ public abstract class ClobTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getClob( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getClob( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Date;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
|
@ -66,6 +67,11 @@ public class DateTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getDate( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getDate( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -66,6 +67,11 @@ public class DecimalTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getBigDecimal( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getBigDecimal( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -65,6 +66,11 @@ public class DoubleTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getDouble( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getDouble( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -65,6 +66,11 @@ public class IntegerTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getInt( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getInt( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -65,6 +66,11 @@ public class RealTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getFloat( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getFloat( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -65,6 +66,11 @@ public class SmallIntTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getShort( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getShort( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -66,6 +67,11 @@ public class TimeTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getTime( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getTime( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -66,6 +67,11 @@ public class TimestampTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getTimestamp( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getTimestamp( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -68,6 +69,11 @@ public class TinyIntTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getByte( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getByte( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -63,8 +64,12 @@ public class VarbinaryTypeDescriptor implements SqlTypeDescriptor {
|
|||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
final byte[] bytes = rs.getBytes( name );
|
||||
return javaTypeDescriptor.wrap( bytes, options );
|
||||
return javaTypeDescriptor.wrap( rs.getBytes( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getBytes( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -65,6 +66,11 @@ public class VarcharTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getString( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getString( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.test.sql.storedproc;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.SQLQuery;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.StoredProcedureCall;
|
||||
import org.hibernate.StoredProcedureOutputs;
|
||||
import org.hibernate.StoredProcedureResultSetReturn;
|
||||
import org.hibernate.StoredProcedureReturn;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.engine.spi.Mapping;
|
||||
import org.hibernate.mapping.AuxiliaryDatabaseObject;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.testing.junit4.ExtraAssertions;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@RequiresDialect( H2Dialect.class )
|
||||
public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
||||
// this is not working in H2
|
||||
// @Override
|
||||
// protected void configure(Configuration configuration) {
|
||||
// super.configure( configuration );
|
||||
// configuration.addAuxiliaryDatabaseObject(
|
||||
// new AuxiliaryDatabaseObject() {
|
||||
// @Override
|
||||
// public void addDialectScope(String dialectName) {
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean appliesToDialect(Dialect dialect) {
|
||||
// return H2Dialect.class.isInstance( dialect );
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, String defaultSchema) {
|
||||
// return "CREATE ALIAS findUser AS $$\n" +
|
||||
// "import org.h2.tools.SimpleResultSet;\n" +
|
||||
// "import java.sql.*;\n" +
|
||||
// "@CODE\n" +
|
||||
// "ResultSet findUser() {\n" +
|
||||
// " SimpleResultSet rs = new SimpleResultSet();\n" +
|
||||
// " rs.addColumn(\"ID\", Types.INTEGER, 10, 0);\n" +
|
||||
// " rs.addColumn(\"NAME\", Types.VARCHAR, 255, 0);\n" +
|
||||
// " rs.addRow(1, \"Steve\");\n" +
|
||||
// " return rs;\n" +
|
||||
// "}\n" +
|
||||
// "$$";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
|
||||
// return "DROP ALIAS findUser IF EXISTS";
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void baseTest() {
|
||||
Session session = openSession();
|
||||
session.beginTransaction();
|
||||
|
||||
StoredProcedureCall query = session.createStoredProcedureCall( "user");
|
||||
StoredProcedureOutputs outputs = query.getOutputs();
|
||||
assertTrue( "Checking StoredProcedureOutputs has more returns", outputs.hasMoreReturns() );
|
||||
StoredProcedureReturn nextReturn = outputs.getNextReturn();
|
||||
assertNotNull( nextReturn );
|
||||
ExtraAssertions.assertClassAssignability( StoredProcedureResultSetReturn.class, nextReturn.getClass() );
|
||||
StoredProcedureResultSetReturn resultSetReturn = (StoredProcedureResultSetReturn) nextReturn;
|
||||
String name = (String) resultSetReturn.getSingleResult();
|
||||
assertEquals( "SA", name );
|
||||
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.test.typeoverride;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -73,6 +74,16 @@ public class StoredPrefixedStringType
|
|||
}
|
||||
return javaTypeDescriptor.wrap( stringValue.substring( PREFIX.length() ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
String stringValue = statement.getString( index );
|
||||
if ( ! stringValue.startsWith( PREFIX ) ) {
|
||||
throw new AssertionFailure( "Value read from procedure output param does not have prefix." );
|
||||
}
|
||||
return javaTypeDescriptor.wrap( stringValue.substring( PREFIX.length() ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -41,6 +41,7 @@ import javax.persistence.PessimisticLockException;
|
|||
import javax.persistence.PessimisticLockScope;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.QueryTimeoutException;
|
||||
import javax.persistence.StoredProcedureQuery;
|
||||
import javax.persistence.TransactionRequiredException;
|
||||
import javax.persistence.Tuple;
|
||||
import javax.persistence.TupleElement;
|
||||
|
@ -81,10 +82,12 @@ import org.hibernate.SQLQuery;
|
|||
import org.hibernate.Session;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.StaleStateException;
|
||||
import org.hibernate.StoredProcedureCall;
|
||||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.TypeMismatchException;
|
||||
import org.hibernate.UnresolvableObjectException;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.cfg.NotYetImplementedException;
|
||||
import org.hibernate.dialect.lock.LockingStrategyException;
|
||||
import org.hibernate.dialect.lock.OptimisticEntityLockException;
|
||||
import org.hibernate.dialect.lock.PessimisticEntityLockException;
|
||||
|
@ -776,6 +779,38 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery createNamedStoredProcedureQuery(String name) {
|
||||
throw new NotYetImplementedException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery createStoredProcedureQuery(String procedureName) {
|
||||
try {
|
||||
StoredProcedureCall call = getSession().createStoredProcedureCall( procedureName );
|
||||
return new StoredProcedureQueryImpl( call, this );
|
||||
}
|
||||
catch ( HibernateException he ) {
|
||||
throw convert( he );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) {
|
||||
try {
|
||||
StoredProcedureCall call = getSession().createStoredProcedureCall( procedureName, resultClasses );
|
||||
return new StoredProcedureQueryImpl( call, this );
|
||||
}
|
||||
catch ( HibernateException he ) {
|
||||
throw convert( he );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) {
|
||||
throw new NotYetImplementedException();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getReference(Class<T> entityClass, Object primaryKey) {
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,602 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.ejb;
|
||||
|
||||
import javax.persistence.CacheRetrieveMode;
|
||||
import javax.persistence.CacheStoreMode;
|
||||
import javax.persistence.FlushModeType;
|
||||
import javax.persistence.Parameter;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.CacheMode;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.ejb.internal.EntityManagerMessageLogger;
|
||||
import org.hibernate.ejb.util.CacheModeHelper;
|
||||
import org.hibernate.ejb.util.ConfigurationHelper;
|
||||
import org.hibernate.ejb.util.LockModeTypeHelper;
|
||||
|
||||
import static org.hibernate.ejb.QueryHints.HINT_CACHEABLE;
|
||||
import static org.hibernate.ejb.QueryHints.HINT_CACHE_MODE;
|
||||
import static org.hibernate.ejb.QueryHints.HINT_CACHE_REGION;
|
||||
import static org.hibernate.ejb.QueryHints.HINT_COMMENT;
|
||||
import static org.hibernate.ejb.QueryHints.HINT_FETCH_SIZE;
|
||||
import static org.hibernate.ejb.QueryHints.HINT_FLUSH_MODE;
|
||||
import static org.hibernate.ejb.QueryHints.HINT_READONLY;
|
||||
import static org.hibernate.ejb.QueryHints.HINT_TIMEOUT;
|
||||
import static org.hibernate.ejb.QueryHints.SPEC_HINT_TIMEOUT;
|
||||
|
||||
/**
|
||||
* Intended as the base class for all {@link Query} implementations, including {@link TypedQuery} and
|
||||
* {@link javax.persistence.StoredProcedureQuery}. Care should be taken that all changes here fit with all
|
||||
* those usages.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class BaseQueryImpl implements Query {
|
||||
private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(
|
||||
EntityManagerMessageLogger.class,
|
||||
AbstractQueryImpl.class.getName()
|
||||
);
|
||||
|
||||
private final HibernateEntityManagerImplementor entityManager;
|
||||
|
||||
private int firstResult;
|
||||
private int maxResults = -1;
|
||||
private Map<String, Object> hints;
|
||||
|
||||
|
||||
public BaseQueryImpl(HibernateEntityManagerImplementor entityManager) {
|
||||
this.entityManager = entityManager;
|
||||
}
|
||||
|
||||
protected HibernateEntityManagerImplementor entityManager() {
|
||||
return entityManager;
|
||||
}
|
||||
|
||||
|
||||
// Limits (first and max results) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
/**
|
||||
* Apply the given first-result value.
|
||||
*
|
||||
* @param firstResult The specified first-result value.
|
||||
*/
|
||||
protected abstract void applyFirstResult(int firstResult);
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setFirstResult(int firstResult) {
|
||||
if ( firstResult < 0 ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Negative value (" + firstResult + ") passed to setFirstResult"
|
||||
);
|
||||
}
|
||||
this.firstResult = firstResult;
|
||||
applyFirstResult( firstResult );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstResult() {
|
||||
return firstResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given max results value.
|
||||
*
|
||||
* @param maxResults The specified max results
|
||||
*/
|
||||
protected abstract void applyMaxResults(int maxResults);
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setMaxResults(int maxResult) {
|
||||
if ( maxResult < 0 ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Negative value (" + maxResult + ") passed to setMaxResults"
|
||||
);
|
||||
}
|
||||
this.maxResults = maxResult;
|
||||
applyMaxResults( maxResult );
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getSpecifiedMaxResults() {
|
||||
return maxResults;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxResults() {
|
||||
return maxResults == -1
|
||||
? Integer.MAX_VALUE // stupid spec... MAX_VALUE??
|
||||
: maxResults;
|
||||
}
|
||||
|
||||
|
||||
// Hints ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@SuppressWarnings( {"UnusedDeclaration"})
|
||||
public Set<String> getSupportedHints() {
|
||||
return QueryHints.getDefinedHints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getHints() {
|
||||
return hints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the query timeout hint.
|
||||
*
|
||||
* @param timeout The timeout (in seconds!) specified as a hint
|
||||
*
|
||||
* @return {@code true} if the hint was "applied"
|
||||
*/
|
||||
protected abstract boolean applyTimeoutHint(int timeout);
|
||||
|
||||
/**
|
||||
* Apply the lock timeout (in seconds!) hint
|
||||
*
|
||||
* @param timeout The timeout (in seconds!) specified as a hint
|
||||
*
|
||||
* @return {@code true} if the hint was "applied"
|
||||
*/
|
||||
protected abstract boolean applyLockTimeoutHint(int timeout);
|
||||
|
||||
/**
|
||||
* Apply the comment hint.
|
||||
*
|
||||
* @param comment The comment specified as a hint
|
||||
*
|
||||
* @return {@code true} if the hint was "applied"
|
||||
*/
|
||||
protected abstract boolean applyCommentHint(String comment);
|
||||
|
||||
/**
|
||||
* Apply the fetch size hint
|
||||
*
|
||||
* @param fetchSize The fetch size specified as a hint
|
||||
*
|
||||
* @return {@code true} if the hint was "applied"
|
||||
*/
|
||||
protected abstract boolean applyFetchSize(int fetchSize);
|
||||
|
||||
/**
|
||||
* Apply the cacheable (true/false) hint.
|
||||
*
|
||||
* @param isCacheable The value specified as hint
|
||||
*
|
||||
* @return {@code true} if the hint was "applied"
|
||||
*/
|
||||
protected abstract boolean applyCacheableHint(boolean isCacheable);
|
||||
|
||||
/**
|
||||
* Apply the cache region hint
|
||||
*
|
||||
* @param regionName The name of the cache region specified as a hint
|
||||
*
|
||||
* @return {@code true} if the hint was "applied"
|
||||
*/
|
||||
protected abstract boolean applyCacheRegionHint(String regionName);
|
||||
|
||||
/**
|
||||
* Apply the read-only (true/false) hint.
|
||||
*
|
||||
* @param isReadOnly The value specified as hint
|
||||
*
|
||||
* @return {@code true} if the hint was "applied"
|
||||
*/
|
||||
protected abstract boolean applyReadOnlyHint(boolean isReadOnly);
|
||||
|
||||
/**
|
||||
* Apply the CacheMode hint.
|
||||
*
|
||||
* @param cacheMode The CacheMode value specified as a hint.
|
||||
*
|
||||
* @return {@code true} if the hint was "applied"
|
||||
*/
|
||||
protected abstract boolean applyCacheModeHint(CacheMode cacheMode);
|
||||
|
||||
/**
|
||||
* Apply the FlushMode hint.
|
||||
*
|
||||
* @param flushMode The FlushMode value specified as hint
|
||||
*
|
||||
* @return {@code true} if the hint was "applied"
|
||||
*/
|
||||
protected abstract boolean applyFlushModeHint(FlushMode flushMode);
|
||||
|
||||
/**
|
||||
* Can alias-specific lock modes be applied?
|
||||
*
|
||||
* @return {@code true} indicates they can be applied, {@code false} otherwise.
|
||||
*/
|
||||
protected abstract boolean canApplyLockModesHints();
|
||||
|
||||
/**
|
||||
* Apply the alias specific lock modes. Assumes {@link #canApplyLockModesHints()} has already been called and
|
||||
* returned {@code true}.
|
||||
*
|
||||
* @param alias The alias to apply the 'lockMode' to.
|
||||
* @param lockMode The LockMode to apply.
|
||||
*/
|
||||
protected abstract void applyAliasSpecificLockModeHint(String alias, LockMode lockMode);
|
||||
|
||||
@Override
|
||||
@SuppressWarnings( {"deprecation"})
|
||||
public BaseQueryImpl setHint(String hintName, Object value) {
|
||||
boolean applied = false;
|
||||
try {
|
||||
if ( HINT_TIMEOUT.equals( hintName ) ) {
|
||||
applied = applyTimeoutHint( ConfigurationHelper.getInteger( value ) );
|
||||
}
|
||||
else if ( SPEC_HINT_TIMEOUT.equals( hintName ) ) {
|
||||
// convert milliseconds to seconds
|
||||
int timeout = (int)Math.round(ConfigurationHelper.getInteger( value ).doubleValue() / 1000.0 );
|
||||
applied = applyTimeoutHint( timeout );
|
||||
}
|
||||
else if ( AvailableSettings.LOCK_TIMEOUT.equals( hintName ) ) {
|
||||
applied = applyLockTimeoutHint( ConfigurationHelper.getInteger( value ) );
|
||||
}
|
||||
else if ( HINT_COMMENT.equals( hintName ) ) {
|
||||
applied = applyCommentHint( (String) value );
|
||||
}
|
||||
else if ( HINT_FETCH_SIZE.equals( hintName ) ) {
|
||||
applied = applyFetchSize( ConfigurationHelper.getInteger( value ) );
|
||||
}
|
||||
else if ( HINT_CACHEABLE.equals( hintName ) ) {
|
||||
applied = applyCacheableHint( ConfigurationHelper.getBoolean( value ) );
|
||||
}
|
||||
else if ( HINT_CACHE_REGION.equals( hintName ) ) {
|
||||
applied = applyCacheRegionHint( (String) value );
|
||||
}
|
||||
else if ( HINT_READONLY.equals( hintName ) ) {
|
||||
applied = applyReadOnlyHint( ConfigurationHelper.getBoolean( value ) );
|
||||
}
|
||||
else if ( HINT_CACHE_MODE.equals( hintName ) ) {
|
||||
applied = applyCacheModeHint( ConfigurationHelper.getCacheMode( value ) );
|
||||
}
|
||||
else if ( HINT_FLUSH_MODE.equals( hintName ) ) {
|
||||
applied = applyFlushModeHint( ConfigurationHelper.getFlushMode( value ) );
|
||||
}
|
||||
else if ( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE.equals( hintName ) ) {
|
||||
final CacheRetrieveMode retrieveMode = (CacheRetrieveMode) value;
|
||||
|
||||
CacheStoreMode storeMode = hints != null
|
||||
? (CacheStoreMode) hints.get( AvailableSettings.SHARED_CACHE_STORE_MODE )
|
||||
: null;
|
||||
if ( storeMode == null ) {
|
||||
storeMode = (CacheStoreMode) entityManager.getProperties().get( AvailableSettings.SHARED_CACHE_STORE_MODE );
|
||||
}
|
||||
applied = applyCacheModeHint( CacheModeHelper.interpretCacheMode( storeMode, retrieveMode ) );
|
||||
}
|
||||
else if ( AvailableSettings.SHARED_CACHE_STORE_MODE.equals( hintName ) ) {
|
||||
final CacheStoreMode storeMode = (CacheStoreMode) value;
|
||||
|
||||
CacheRetrieveMode retrieveMode = hints != null
|
||||
? (CacheRetrieveMode) hints.get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE )
|
||||
: null;
|
||||
if ( retrieveMode == null ) {
|
||||
retrieveMode = (CacheRetrieveMode) entityManager.getProperties().get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE );
|
||||
}
|
||||
applied = applyCacheModeHint(
|
||||
CacheModeHelper.interpretCacheMode( storeMode, retrieveMode )
|
||||
);
|
||||
}
|
||||
else if ( hintName.startsWith( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE ) ) {
|
||||
if ( canApplyLockModesHints() ) {
|
||||
// extract the alias
|
||||
final String alias = hintName.substring( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE.length() + 1 );
|
||||
// determine the LockMode
|
||||
try {
|
||||
final LockMode lockMode = LockModeTypeHelper.interpretLockMode( value );
|
||||
applyAliasSpecificLockModeHint( alias, lockMode );
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
LOG.unableToDetermineLockModeValue( hintName, value );
|
||||
applied = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
applied = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG.ignoringUnrecognizedQueryHint( hintName );
|
||||
}
|
||||
}
|
||||
catch ( ClassCastException e ) {
|
||||
throw new IllegalArgumentException( "Value for hint" );
|
||||
}
|
||||
|
||||
if ( applied ) {
|
||||
if ( hints == null ) {
|
||||
hints = new HashMap<String,Object>();
|
||||
}
|
||||
hints.put( hintName, value );
|
||||
}
|
||||
else {
|
||||
LOG.debugf( "Skipping unsupported query hint [%s]", hintName );
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// FlushMode ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
private FlushModeType jpaFlushMode;
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setFlushMode(FlushModeType jpaFlushMode) {
|
||||
this.jpaFlushMode = jpaFlushMode;
|
||||
// TODO : treat as hint?
|
||||
if ( jpaFlushMode == FlushModeType.AUTO ) {
|
||||
applyFlushModeHint( FlushMode.AUTO );
|
||||
}
|
||||
else if ( jpaFlushMode == FlushModeType.COMMIT ) {
|
||||
applyFlushModeHint( FlushMode.COMMIT );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings( {"UnusedDeclaration"})
|
||||
protected FlushModeType getSpecifiedFlushMode() {
|
||||
return jpaFlushMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlushModeType getFlushMode() {
|
||||
return jpaFlushMode != null
|
||||
? jpaFlushMode
|
||||
: entityManager.getFlushMode();
|
||||
}
|
||||
|
||||
|
||||
// Parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
private List<ParameterImplementor> parameters;
|
||||
|
||||
/**
|
||||
* Hibernate specific extension to the JPA {@link Parameter} contract.
|
||||
*/
|
||||
protected static interface ParameterImplementor<T> extends Parameter<T> {
|
||||
public boolean isBindable();
|
||||
|
||||
public ParameterValue getBoundValue();
|
||||
}
|
||||
|
||||
protected static class ParameterValue {
|
||||
private final Object value;
|
||||
private final TemporalType specifiedTemporalType;
|
||||
|
||||
public ParameterValue(Object value, TemporalType specifiedTemporalType) {
|
||||
this.value = value;
|
||||
this.specifiedTemporalType = specifiedTemporalType;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public TemporalType getSpecifiedTemporalType() {
|
||||
return specifiedTemporalType;
|
||||
}
|
||||
}
|
||||
|
||||
private Map<ParameterImplementor<?>,ParameterValue> parameterBindingMap;
|
||||
|
||||
private Map<ParameterImplementor<?>,ParameterValue> parameterBindingMap() {
|
||||
if ( parameterBindingMap == null ) {
|
||||
parameterBindingMap = new HashMap<ParameterImplementor<?>, ParameterValue>();
|
||||
}
|
||||
return parameterBindingMap;
|
||||
}
|
||||
|
||||
protected void registerParameter(ParameterImplementor parameter) {
|
||||
if ( parameter == null ) {
|
||||
throw new IllegalArgumentException( "parameter cannot be null" );
|
||||
}
|
||||
|
||||
if ( parameterBindingMap().containsKey( parameter ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
parameterBindingMap().put( parameter, null );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void registerParameterBinding(Parameter parameter, ParameterValue bindValue) {
|
||||
validateParameterBinding( (ParameterImplementor) parameter, bindValue );
|
||||
parameterBindingMap().put( (ParameterImplementor) parameter, bindValue );
|
||||
}
|
||||
|
||||
protected void validateParameterBinding(ParameterImplementor parameter, ParameterValue bindValue) {
|
||||
if ( parameter == null ) {
|
||||
throw new IllegalArgumentException( "parameter cannot be null" );
|
||||
}
|
||||
|
||||
if ( ! parameter.isBindable() ) {
|
||||
throw new IllegalArgumentException( "Parameter [" + parameter + "] not valid for binding" );
|
||||
}
|
||||
|
||||
if ( ! parameterBindingMap().containsKey( parameter ) ) {
|
||||
throw new IllegalArgumentException( "Unknown parameter [" + parameter + "] specified for value binding" );
|
||||
}
|
||||
|
||||
if ( isBound( parameter ) ) {
|
||||
throw new IllegalArgumentException( "Parameter [" + parameter + "] already had bound value" );
|
||||
}
|
||||
|
||||
validateParameterBindingTypes( parameter, bindValue );
|
||||
}
|
||||
|
||||
protected abstract void validateParameterBindingTypes(ParameterImplementor parameter, ParameterValue bindValue);
|
||||
|
||||
protected ParameterValue makeBindValue(Object value) {
|
||||
return new ParameterValue( value, null );
|
||||
}
|
||||
|
||||
protected ParameterValue makeBindValue(Calendar value, TemporalType temporalType) {
|
||||
return new ParameterValue( value, temporalType );
|
||||
}
|
||||
|
||||
protected ParameterValue makeBindValue(Date value, TemporalType temporalType) {
|
||||
return new ParameterValue( value, temporalType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BaseQueryImpl setParameter(Parameter<T> param, T value) {
|
||||
registerParameterBinding( param, makeBindValue( value ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(Parameter<Calendar> param, Calendar value, TemporalType temporalType) {
|
||||
registerParameterBinding( param, makeBindValue( value, temporalType ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(Parameter<Date> param, Date value, TemporalType temporalType) {
|
||||
registerParameterBinding( param, makeBindValue( value, temporalType ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(String name, Object value) {
|
||||
registerParameterBinding( getParameter( name ), makeBindValue( value ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(String name, Calendar value, TemporalType temporalType) {
|
||||
registerParameterBinding( getParameter( name ), makeBindValue( value, temporalType ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(String name, Date value, TemporalType temporalType) {
|
||||
registerParameterBinding( getParameter( name ), makeBindValue( value, temporalType ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(int position, Object value) {
|
||||
registerParameterBinding( getParameter( position ), makeBindValue( value ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(int position, Calendar value, TemporalType temporalType) {
|
||||
registerParameterBinding( getParameter( position ), makeBindValue( value, temporalType ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(int position, Date value, TemporalType temporalType) {
|
||||
registerParameterBinding( getParameter( position ), makeBindValue( value, temporalType ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<Parameter<?>> getParameters() {
|
||||
return (Set<Parameter<?>>) parameterBindingMap().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameter<?> getParameter(String name) {
|
||||
if ( parameterBindingMap() != null ) {
|
||||
for ( ParameterImplementor<?> param : parameterBindingMap.keySet() ) {
|
||||
if ( name.equals( param.getName() ) ) {
|
||||
return param;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException( "Parameter with that name [" + name + "] did not exist" );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Parameter<T> getParameter(String name, Class<T> type) {
|
||||
return (Parameter<T>) getParameter( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameter<?> getParameter(int position) {
|
||||
if ( parameterBindingMap() != null ) {
|
||||
for ( ParameterImplementor<?> param : parameterBindingMap.keySet() ) {
|
||||
if ( position == param.getPosition() ) {
|
||||
return param;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException( "Parameter with that position [" + position + "] did not exist" );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Parameter<T> getParameter(int position, Class<T> type) {
|
||||
return (Parameter<T>) getParameter( position );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBound(Parameter<?> param) {
|
||||
return parameterBindingMap() != null
|
||||
&& parameterBindingMap.get( (ParameterImplementor) param ) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getParameterValue(Parameter<T> param) {
|
||||
if ( parameterBindingMap != null ) {
|
||||
final ParameterValue boundValue = parameterBindingMap.get( (ParameterImplementor) param );
|
||||
if ( boundValue != null ) {
|
||||
return (T) boundValue.getValue();
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException( "Parameter [" + param + "] has not yet been bound" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getParameterValue(String name) {
|
||||
return getParameterValue( getParameter( name ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getParameterValue(int position) {
|
||||
return getParameterValue( getParameter( position ) );
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2009, 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -48,7 +50,6 @@ import org.hibernate.Hibernate;
|
|||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.NotYetImplementedException;
|
||||
import org.hibernate.ejb.criteria.CriteriaBuilderImpl;
|
||||
import org.hibernate.ejb.internal.EntityManagerFactoryRegistry;
|
||||
import org.hibernate.ejb.metamodel.MetamodelImpl;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2009-2011, Red Hat Inc. or third-party contributors as
|
||||
* Copyright (c) 2009, 2011, 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.
|
||||
|
@ -23,24 +23,21 @@
|
|||
*/
|
||||
package org.hibernate.ejb;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.persistence.PersistenceContextType;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.StoredProcedureQuery;
|
||||
import javax.persistence.spi.PersistenceUnitTransactionType;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Interceptor;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.NotYetImplementedException;
|
||||
import org.hibernate.engine.spi.SessionOwner;
|
||||
import org.hibernate.annotations.common.util.ReflectHelper;
|
||||
import org.hibernate.ejb.internal.EntityManagerMessageLogger;
|
||||
import org.hibernate.engine.spi.SessionBuilderImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.engine.spi.SessionOwner;
|
||||
|
||||
/**
|
||||
* Hibernate implementation of {@link javax.persistence.EntityManager}.
|
||||
|
@ -129,26 +126,6 @@ public class EntityManagerImpl extends AbstractEntityManagerImpl implements Sess
|
|||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery createNamedStoredProcedureQuery(String name) {
|
||||
throw new NotYetImplementedException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery createStoredProcedureQuery(String procedureName) {
|
||||
throw new NotYetImplementedException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) {
|
||||
throw new NotYetImplementedException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) {
|
||||
throw new NotYetImplementedException();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
checkEntityManagerFactory();
|
||||
if ( !open ) {
|
||||
|
|
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.ejb;
|
||||
|
||||
import javax.persistence.FlushModeType;
|
||||
import javax.persistence.LockModeType;
|
||||
import javax.persistence.Parameter;
|
||||
import javax.persistence.ParameterMode;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.StoredProcedureQuery;
|
||||
import javax.persistence.TemporalType;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.CacheMode;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.StoredProcedureCall;
|
||||
import org.hibernate.StoredProcedureOutputs;
|
||||
import org.hibernate.StoredProcedureResultSetReturn;
|
||||
import org.hibernate.StoredProcedureReturn;
|
||||
import org.hibernate.StoredProcedureUpdateCountReturn;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredProcedureQuery {
|
||||
private final StoredProcedureCall storedProcedureCall;
|
||||
private StoredProcedureOutputs storedProcedureOutputs;
|
||||
|
||||
public StoredProcedureQueryImpl(StoredProcedureCall storedProcedureCall, HibernateEntityManagerImplementor entityManager) {
|
||||
super( entityManager );
|
||||
this.storedProcedureCall = storedProcedureCall;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean applyTimeoutHint(int timeout) {
|
||||
storedProcedureCall.setTimeout( timeout );
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean applyCacheableHint(boolean isCacheable) {
|
||||
storedProcedureCall.setCacheable( isCacheable );
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean applyCacheRegionHint(String regionName) {
|
||||
storedProcedureCall.setCacheRegion( regionName );
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean applyReadOnlyHint(boolean isReadOnly) {
|
||||
storedProcedureCall.setReadOnly( isReadOnly );
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean applyCacheModeHint(CacheMode cacheMode) {
|
||||
storedProcedureCall.setCacheMode( cacheMode );
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean applyFlushModeHint(FlushMode flushMode) {
|
||||
storedProcedureCall.setFlushMode( flushMode );
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public StoredProcedureQuery registerStoredProcedureParameter(int position, Class type, ParameterMode mode) {
|
||||
storedProcedureCall.registerStoredProcedureParameter( position, type, mode );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery registerStoredProcedureParameter(String parameterName, Class type, ParameterMode mode) {
|
||||
storedProcedureCall.registerStoredProcedureParameter( parameterName, type, mode );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateParameterBindingTypes(ParameterImplementor parameter, ParameterValue bindValue) {
|
||||
}
|
||||
|
||||
|
||||
// covariant returns ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@Override
|
||||
public StoredProcedureQueryImpl setFlushMode(FlushModeType jpaFlushMode) {
|
||||
return (StoredProcedureQueryImpl) super.setFlushMode( jpaFlushMode );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQueryImpl setHint(String hintName, Object value) {
|
||||
return (StoredProcedureQueryImpl) super.setHint( hintName, value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> StoredProcedureQueryImpl setParameter(Parameter<T> param, T value) {
|
||||
return (StoredProcedureQueryImpl) super.setParameter( param, value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQueryImpl setParameter(Parameter<Calendar> param, Calendar value, TemporalType temporalType) {
|
||||
return (StoredProcedureQueryImpl) super.setParameter( param, value, temporalType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQueryImpl setParameter(Parameter<Date> param, Date value, TemporalType temporalType) {
|
||||
return (StoredProcedureQueryImpl) super.setParameter( param, value, temporalType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQueryImpl setParameter(String name, Object value) {
|
||||
return ( StoredProcedureQueryImpl) super.setParameter( name, value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQueryImpl setParameter(String name, Calendar value, TemporalType temporalType) {
|
||||
return (StoredProcedureQueryImpl) super.setParameter( name, value, temporalType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQueryImpl setParameter(String name, Date value, TemporalType temporalType) {
|
||||
return (StoredProcedureQueryImpl) super.setParameter( name, value, temporalType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQueryImpl setParameter(int position, Object value) {
|
||||
return (StoredProcedureQueryImpl) super.setParameter( position, value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQueryImpl setParameter(int position, Calendar value, TemporalType temporalType) {
|
||||
return (StoredProcedureQueryImpl) super.setParameter( position, value, temporalType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQueryImpl setParameter(int position, Date value, TemporalType temporalType) {
|
||||
return (StoredProcedureQueryImpl) super.setParameter( position, value, temporalType );
|
||||
}
|
||||
|
||||
|
||||
// outputs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
private StoredProcedureOutputs outputs() {
|
||||
if ( storedProcedureOutputs == null ) {
|
||||
storedProcedureOutputs = storedProcedureCall.getOutputs();
|
||||
}
|
||||
return storedProcedureOutputs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOutputParameterValue(int position) {
|
||||
return outputs().getOutputParameterValue( position );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOutputParameterValue(String parameterName) {
|
||||
return outputs().getOutputParameterValue( parameterName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute() {
|
||||
return outputs().hasMoreReturns();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate() {
|
||||
return getUpdateCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreResults() {
|
||||
return outputs().hasMoreReturns();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUpdateCount() {
|
||||
final StoredProcedureReturn nextReturn = outputs().getNextReturn();
|
||||
if ( nextReturn.isResultSet() ) {
|
||||
return -1;
|
||||
}
|
||||
return ( (StoredProcedureUpdateCountReturn) nextReturn ).getUpdateCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List getResultList() {
|
||||
final StoredProcedureReturn nextReturn = outputs().getNextReturn();
|
||||
if ( ! nextReturn.isResultSet() ) {
|
||||
return null; // todo : what should be thrown/returned here?
|
||||
}
|
||||
return ( (StoredProcedureResultSetReturn) nextReturn ).getResultList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSingleResult() {
|
||||
final StoredProcedureReturn nextReturn = outputs().getNextReturn();
|
||||
if ( ! nextReturn.isResultSet() ) {
|
||||
return null; // todo : what should be thrown/returned here?
|
||||
}
|
||||
return ( (StoredProcedureResultSetReturn) nextReturn ).getSingleResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> cls) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// ugh ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@Override
|
||||
public Query setLockMode(LockModeType lockMode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockModeType getLockMode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// unsupported hints/calls ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@Override
|
||||
protected void applyFirstResult(int firstResult) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyMaxResults(int maxResults) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canApplyLockModesHints() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyAliasSpecificLockModeHint(String alias, LockMode lockMode) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean applyLockTimeoutHint(int timeout) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean applyCommentHint(String comment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean applyFetchSize(int fetchSize) {
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue