HHH-7914 - Improve new stored procedure call support
This commit is contained in:
parent
0713cea180
commit
5de1677ce7
|
@ -25,6 +25,8 @@ package org.hibernate;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import org.hibernate.procedure.Call;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contract methods shared between {@link Session} and {@link StatelessSession}
|
* Contract methods shared between {@link Session} and {@link StatelessSession}
|
||||||
*
|
*
|
||||||
|
@ -91,17 +93,18 @@ public interface SharedSessionContract extends Serializable {
|
||||||
*
|
*
|
||||||
* @return The representation of the procedure call.
|
* @return The representation of the procedure call.
|
||||||
*/
|
*/
|
||||||
public StoredProcedureCall createStoredProcedureCall(String procedureName);
|
public Call createStoredProcedureCall(String procedureName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a call to a stored procedure with specific result set entity mappings
|
* Creates a call to a stored procedure with specific result set entity mappings. Each class named
|
||||||
|
* is considered a "root return".
|
||||||
*
|
*
|
||||||
* @param procedureName The name of the procedure.
|
* @param procedureName The name of the procedure.
|
||||||
* @param resultClasses The entity(s) to map the result on to.
|
* @param resultClasses The entity(s) to map the result on to.
|
||||||
*
|
*
|
||||||
* @return The representation of the procedure call.
|
* @return The representation of the procedure call.
|
||||||
*/
|
*/
|
||||||
public StoredProcedureCall createStoredProcedureCall(String procedureName, Class... resultClasses);
|
public Call createStoredProcedureCall(String procedureName, Class... resultClasses);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a call to a stored procedure with specific result set entity mappings
|
* Creates a call to a stored procedure with specific result set entity mappings
|
||||||
|
@ -111,7 +114,7 @@ public interface SharedSessionContract extends Serializable {
|
||||||
*
|
*
|
||||||
* @return The representation of the procedure call.
|
* @return The representation of the procedure call.
|
||||||
*/
|
*/
|
||||||
public StoredProcedureCall createStoredProcedureCall(String procedureName, String... resultSetMappings);
|
public Call createStoredProcedureCall(String procedureName, String... resultSetMappings);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create {@link Criteria} instance for the given class (entity or subclasses/implementors)
|
* Create {@link Criteria} instance for the given class (entity or subclasses/implementors)
|
||||||
|
|
|
@ -1,198 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.internal.StoredProcedureCallImpl;
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -37,7 +37,7 @@ import org.hibernate.SQLQuery;
|
||||||
import org.hibernate.ScrollableResults;
|
import org.hibernate.ScrollableResults;
|
||||||
import org.hibernate.SessionException;
|
import org.hibernate.SessionException;
|
||||||
import org.hibernate.SharedSessionContract;
|
import org.hibernate.SharedSessionContract;
|
||||||
import org.hibernate.StoredProcedureCall;
|
import org.hibernate.procedure.Call;
|
||||||
import org.hibernate.cache.spi.CacheKey;
|
import org.hibernate.cache.spi.CacheKey;
|
||||||
import org.hibernate.engine.jdbc.LobCreationContext;
|
import org.hibernate.engine.jdbc.LobCreationContext;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
|
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
|
||||||
|
@ -59,6 +59,7 @@ import org.hibernate.jdbc.WorkExecutorVisitable;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||||
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
|
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
|
||||||
|
import org.hibernate.procedure.internal.CallImpl;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -240,27 +241,27 @@ public abstract class AbstractSessionImpl implements Serializable, SharedSession
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||||
public StoredProcedureCall createStoredProcedureCall(String procedureName) {
|
public Call createStoredProcedureCall(String procedureName) {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
final StoredProcedureCall call = new StoredProcedureCallImpl( this, procedureName );
|
final Call call = new CallImpl( this, procedureName );
|
||||||
// call.setComment( "Dynamic stored procedure call" );
|
// call.setComment( "Dynamic stored procedure call" );
|
||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||||
public StoredProcedureCall createStoredProcedureCall(String procedureName, Class... resultClasses) {
|
public Call createStoredProcedureCall(String procedureName, Class... resultClasses) {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
final StoredProcedureCall call = new StoredProcedureCallImpl( this, procedureName, resultClasses );
|
final Call call = new CallImpl( this, procedureName, resultClasses );
|
||||||
// call.setComment( "Dynamic stored procedure call" );
|
// call.setComment( "Dynamic stored procedure call" );
|
||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||||
public StoredProcedureCall createStoredProcedureCall(String procedureName, String... resultSetMappings) {
|
public Call createStoredProcedureCall(String procedureName, String... resultSetMappings) {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
final StoredProcedureCall call = new StoredProcedureCallImpl( this, procedureName, resultSetMappings );
|
final Call call = new CallImpl( this, procedureName, resultSetMappings );
|
||||||
// call.setComment( "Dynamic stored procedure call" );
|
// call.setComment( "Dynamic stored procedure call" );
|
||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ import org.hibernate.ScrollableResults;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.SessionBuilder;
|
import org.hibernate.SessionBuilder;
|
||||||
import org.hibernate.SessionException;
|
import org.hibernate.SessionException;
|
||||||
import org.hibernate.StoredProcedureCall;
|
import org.hibernate.procedure.Call;
|
||||||
import org.hibernate.engine.spi.SessionOwner;
|
import org.hibernate.engine.spi.SessionOwner;
|
||||||
import org.hibernate.SharedSessionBuilder;
|
import org.hibernate.SharedSessionBuilder;
|
||||||
import org.hibernate.SimpleNaturalIdLoadAccess;
|
import org.hibernate.SimpleNaturalIdLoadAccess;
|
||||||
|
@ -141,7 +141,6 @@ import org.hibernate.event.spi.ResolveNaturalIdEventListener;
|
||||||
import org.hibernate.event.spi.SaveOrUpdateEvent;
|
import org.hibernate.event.spi.SaveOrUpdateEvent;
|
||||||
import org.hibernate.event.spi.SaveOrUpdateEventListener;
|
import org.hibernate.event.spi.SaveOrUpdateEventListener;
|
||||||
import org.hibernate.internal.CriteriaImpl.CriterionEntry;
|
import org.hibernate.internal.CriteriaImpl.CriterionEntry;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
|
||||||
import org.hibernate.jdbc.ReturningWork;
|
import org.hibernate.jdbc.ReturningWork;
|
||||||
import org.hibernate.jdbc.Work;
|
import org.hibernate.jdbc.Work;
|
||||||
import org.hibernate.jdbc.WorkExecutor;
|
import org.hibernate.jdbc.WorkExecutor;
|
||||||
|
@ -1743,21 +1742,21 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StoredProcedureCall createStoredProcedureCall(String procedureName) {
|
public Call createStoredProcedureCall(String procedureName) {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
checkTransactionSynchStatus();
|
checkTransactionSynchStatus();
|
||||||
return super.createStoredProcedureCall( procedureName );
|
return super.createStoredProcedureCall( procedureName );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StoredProcedureCall createStoredProcedureCall(String procedureName, String... resultSetMappings) {
|
public Call createStoredProcedureCall(String procedureName, String... resultSetMappings) {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
checkTransactionSynchStatus();
|
checkTransactionSynchStatus();
|
||||||
return super.createStoredProcedureCall( procedureName, resultSetMappings );
|
return super.createStoredProcedureCall( procedureName, resultSetMappings );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StoredProcedureCall createStoredProcedureCall(String procedureName, Class... resultClasses) {
|
public Call createStoredProcedureCall(String procedureName, Class... resultClasses) {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
checkTransactionSynchStatus();
|
checkTransactionSynchStatus();
|
||||||
return super.createStoredProcedureCall( procedureName, resultClasses );
|
return super.createStoredProcedureCall( procedureName, resultClasses );
|
||||||
|
|
|
@ -1,608 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.jdbc.spi.ExtractedDatabaseMetaData;
|
|
||||||
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.engine.jdbc.cursor.spi.RefCursorSupport;
|
|
||||||
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() ) ) {
|
|
||||||
prepareForNamedParameters();
|
|
||||||
}
|
|
||||||
else if ( parameter.getPosition() != null ) {
|
|
||||||
prepareForPositionalParameters();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException( "Given parameter did not define name nor position [" + parameter + "]" );
|
|
||||||
}
|
|
||||||
registeredParameters.add( parameter );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void prepareForPositionalParameters() {
|
|
||||||
if ( typeOfParameters == TypeOfParameter.NAMED ) {
|
|
||||||
throw new QueryException( "Cannot mix named and positional parameters" );
|
|
||||||
}
|
|
||||||
typeOfParameters = TypeOfParameter.POSITIONAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void prepareForNamedParameters() {
|
|
||||||
if ( typeOfParameters == TypeOfParameter.POSITIONAL ) {
|
|
||||||
throw new QueryException( "Cannot mix named and positional parameters" );
|
|
||||||
}
|
|
||||||
if ( typeOfParameters == null ) {
|
|
||||||
// protect to only do this check once
|
|
||||||
final ExtractedDatabaseMetaData databaseMetaData = session().getTransactionCoordinator()
|
|
||||||
.getJdbcCoordinator()
|
|
||||||
.getLogicalConnection()
|
|
||||||
.getJdbcServices()
|
|
||||||
.getExtractedMetaDataSupport();
|
|
||||||
if ( ! databaseMetaData.supportsNamedParameters() ) {
|
|
||||||
throw new QueryException(
|
|
||||||
"Named stored procedure parameters used, but JDBC driver does not support named parameters"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
typeOfParameters = TypeOfParameter.NAMED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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<StoredProcedureParameter> getRegisteredParameters() {
|
|
||||||
return new ArrayList<StoredProcedureParameter>( 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public StoredProcedureParameterImplementor[] collectRefCursorParameters() {
|
|
||||||
List<StoredProcedureParameterImplementor> refCursorParams = new ArrayList<StoredProcedureParameterImplementor>();
|
|
||||||
for ( StoredProcedureParameterImplementor param : registeredParameters ) {
|
|
||||||
if ( param.getMode() == ParameterMode.REF_CURSOR ) {
|
|
||||||
refCursorParams.add( param );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return refCursorParams.toArray( new StoredProcedureParameterImplementor[refCursorParams.size()] );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// we have a REF_CURSOR type param
|
|
||||||
if ( procedureCall.typeOfParameters == TypeOfParameter.NAMED ) {
|
|
||||||
session().getFactory().getServiceRegistry()
|
|
||||||
.getService( RefCursorSupport.class )
|
|
||||||
.registerRefCursorParameter( statement, getName() );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
session().getFactory().getServiceRegistry()
|
|
||||||
.getService( RefCursorSupport.class )
|
|
||||||
.registerRefCursorParameter( statement, getPosition() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
if ( mode == ParameterMode.IN ) {
|
|
||||||
throw new QueryException( "IN parameter not valid for output extraction" );
|
|
||||||
}
|
|
||||||
else if ( mode == ParameterMode.REF_CURSOR ) {
|
|
||||||
throw new QueryException( "REF_CURSOR parameters should be accessed via results" );
|
|
||||||
}
|
|
||||||
|
|
||||||
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,136 @@
|
||||||
|
/*
|
||||||
|
* 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.procedure;
|
||||||
|
|
||||||
|
import javax.persistence.ParameterMode;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.BasicQueryContract;
|
||||||
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.SynchronizeableQuery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines support for executing database stored procedures and functions
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface Call extends BasicQueryContract, SynchronizeableQuery {
|
||||||
|
@Override
|
||||||
|
public Call addSynchronizedQuerySpace(String querySpace);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Call addSynchronizedEntityName(String entityName) throws MappingException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Call addSynchronizedEntityClass(Class entityClass) throws MappingException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of the stored procedure to be called.
|
||||||
|
*
|
||||||
|
* @return The procedure name.
|
||||||
|
*/
|
||||||
|
public String getProcedureName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic form for registering a positional parameter.
|
||||||
|
*
|
||||||
|
* @param position The position
|
||||||
|
* @param type The Java type of the parameter
|
||||||
|
* @param mode The parameter mode (in, out, inout)
|
||||||
|
*
|
||||||
|
* @return The parameter registration memento
|
||||||
|
*/
|
||||||
|
public <T> ParameterRegistration<T> registerParameter(int position, Class<T> type, ParameterMode mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chained form of {@link #registerParameter(int, Class, javax.persistence.ParameterMode)}
|
||||||
|
*
|
||||||
|
* @param position The position
|
||||||
|
* @param type The Java type of the parameter
|
||||||
|
* @param mode The parameter mode (in, out, inout)
|
||||||
|
*
|
||||||
|
* @return {@code this}, for method chaining
|
||||||
|
*/
|
||||||
|
public Call registerParameter0(int position, Class type, ParameterMode mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a previously registered parameter memento by the position under which it was registered.
|
||||||
|
*
|
||||||
|
* @param position The parameter position
|
||||||
|
*
|
||||||
|
* @return The parameter registration memento
|
||||||
|
*/
|
||||||
|
public ParameterRegistration getParameterRegistration(int position);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic form for registering a named parameter.
|
||||||
|
*
|
||||||
|
* @param parameterName The parameter name
|
||||||
|
* @param type The Java type of the parameter
|
||||||
|
* @param mode The parameter mode (in, out, inout)
|
||||||
|
*
|
||||||
|
* @return The parameter registration memento
|
||||||
|
*/
|
||||||
|
public <T> ParameterRegistration<T> registerParameter(String parameterName, Class<T> type, ParameterMode mode)
|
||||||
|
throws NamedParametersNotSupportedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chained form of {@link #registerParameter(String, Class, javax.persistence.ParameterMode)}
|
||||||
|
*
|
||||||
|
* @param parameterName The parameter name
|
||||||
|
* @param type The Java type of the parameter
|
||||||
|
* @param mode The parameter mode (in, out, inout)
|
||||||
|
*
|
||||||
|
* @return The parameter registration memento
|
||||||
|
*/
|
||||||
|
public Call registerParameter0(String parameterName, Class type, ParameterMode mode)
|
||||||
|
throws NamedParametersNotSupportedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a previously registered parameter memento by the name under which it was registered.
|
||||||
|
*
|
||||||
|
* @param name The parameter name
|
||||||
|
*
|
||||||
|
* @return The parameter registration memento
|
||||||
|
*/
|
||||||
|
public ParameterRegistration getParameterRegistration(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve all registered parameters.
|
||||||
|
*
|
||||||
|
* @return The (immutable) list of all registered parameters.
|
||||||
|
*/
|
||||||
|
public List<ParameterRegistration> getRegisteredParameters();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves access to outputs of this procedure call. Can be called multiple times, returning the same
|
||||||
|
* Output instance each time.
|
||||||
|
* <p/>
|
||||||
|
* Note that the procedure will not actually be executed until the outputs are actually accessed.
|
||||||
|
*
|
||||||
|
* @return The outputs representation
|
||||||
|
*/
|
||||||
|
public Outputs getOutputs();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.procedure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface InOutParameterRegistration<T> extends InParameterRegistration<T>, OutParameterRegistration<T> {
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Inc.
|
* distributed under license by Red Hat Inc.
|
||||||
|
@ -21,11 +21,10 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate;
|
package org.hibernate.procedure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface StoredProcedureReturn {
|
public interface InParameterRegistration<T> extends ParameterRegistration<T> {
|
||||||
public boolean isResultSet();
|
|
||||||
}
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.procedure;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown to indicate that an attempt was made to register a stored procedure named parameter, but the underlying
|
||||||
|
* database reports to not support named parameters.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class NamedParametersNotSupportedException extends HibernateException {
|
||||||
|
public NamedParametersNotSupportedException(String message) {
|
||||||
|
super( message );
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Inc.
|
* distributed under license by Red Hat Inc.
|
||||||
|
@ -21,11 +21,10 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate;
|
package org.hibernate.procedure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface StoredProcedureUpdateCountReturn extends StoredProcedureReturn {
|
public interface OutParameterRegistration<T> extends ParameterRegistration<T> {
|
||||||
public int getUpdateCount();
|
|
||||||
}
|
}
|
|
@ -21,7 +21,7 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate;
|
package org.hibernate.procedure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents all the outputs of a call to a database stored procedure (or function) through the JDBC
|
* Represents all the outputs of a call to a database stored procedure (or function) through the JDBC
|
||||||
|
@ -29,7 +29,22 @@ package org.hibernate;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface StoredProcedureOutputs {
|
public interface Outputs {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the value of an OUTPUT parameter by the parameter's registration memento.
|
||||||
|
* <p/>
|
||||||
|
* Should NOT be called for parameters registered as REF_CURSOR. REF_CURSOR parameters should be
|
||||||
|
* accessed via the returns (see {@link #getNextReturn}
|
||||||
|
*
|
||||||
|
* @param parameterRegistration The parameter's registration memento.
|
||||||
|
*
|
||||||
|
* @return The output value.
|
||||||
|
*
|
||||||
|
* @see Call#registerParameter(String, Class, javax.persistence.ParameterMode)
|
||||||
|
*/
|
||||||
|
public <T> T getOutputParameterValue(ParameterRegistration<T> parameterRegistration);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the value of an OUTPUT parameter by the name under which the parameter was registered.
|
* Retrieve the value of an OUTPUT parameter by the name under which the parameter was registered.
|
||||||
*
|
*
|
||||||
|
@ -37,7 +52,7 @@ public interface StoredProcedureOutputs {
|
||||||
*
|
*
|
||||||
* @return The output value.
|
* @return The output value.
|
||||||
*
|
*
|
||||||
* @see StoredProcedureCall#registerStoredProcedureParameter(String, Class, javax.persistence.ParameterMode)
|
* @see Call#registerParameter(String, Class, javax.persistence.ParameterMode)
|
||||||
*/
|
*/
|
||||||
public Object getOutputParameterValue(String name);
|
public Object getOutputParameterValue(String name);
|
||||||
|
|
||||||
|
@ -48,7 +63,7 @@ public interface StoredProcedureOutputs {
|
||||||
*
|
*
|
||||||
* @return The output value.
|
* @return The output value.
|
||||||
*
|
*
|
||||||
* @see StoredProcedureCall#registerStoredProcedureParameter(int, Class, javax.persistence.ParameterMode)
|
* @see Call#registerParameter(int, Class, javax.persistence.ParameterMode)
|
||||||
*/
|
*/
|
||||||
public Object getOutputParameterValue(int position);
|
public Object getOutputParameterValue(int position);
|
||||||
|
|
||||||
|
@ -65,5 +80,5 @@ public interface StoredProcedureOutputs {
|
||||||
*
|
*
|
||||||
* @return The next return.
|
* @return The next return.
|
||||||
*/
|
*/
|
||||||
public StoredProcedureReturn getNextReturn();
|
public Return getNextReturn();
|
||||||
}
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.procedure;
|
||||||
|
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes an input value binding for any IN/INOUT parameters.
|
||||||
|
*/
|
||||||
|
public interface ParameterBind<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,37 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.procedure;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown to indicate a misuse of a {@link ParameterRegistration}
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class ParameterMisuseException extends HibernateException {
|
||||||
|
public ParameterMisuseException(String message) {
|
||||||
|
super( message );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.procedure;
|
||||||
|
|
||||||
|
import javax.persistence.ParameterMode;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface ParameterRegistration<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 ParameterBind 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);
|
||||||
|
}
|
|
@ -21,7 +21,7 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate;
|
package org.hibernate.procedure;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ import java.util.List;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface StoredProcedureResultSetReturn extends StoredProcedureReturn {
|
public interface ResultSetReturn extends Return {
|
||||||
/**
|
/**
|
||||||
* Consume the underlying {@link java.sql.ResultSet} and return the resulting List.
|
* Consume the underlying {@link java.sql.ResultSet} and return the resulting List.
|
||||||
*
|
*
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* 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.procedure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common contract for procedure call results which can be either results ({@link ResultSetReturn}) or update
|
||||||
|
* counts ({@link UpdateCountReturn}).
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface Return {
|
||||||
|
/**
|
||||||
|
* Determine if this return is a result (castable to {@link ResultSetReturn}). The alternative is that it is
|
||||||
|
* an update count (castable to {@link UpdateCountReturn}).
|
||||||
|
*
|
||||||
|
* @return {@code true} indicates that {@code this} can be safely cast to {@link ResultSetReturn}), other wise
|
||||||
|
* it can be cast to {@link UpdateCountReturn}.
|
||||||
|
*/
|
||||||
|
public boolean isResultSet();
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* 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.procedure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models a stored procedure result that is a result set.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface UpdateCountReturn extends Return {
|
||||||
|
/**
|
||||||
|
* Retrieve the associated update count
|
||||||
|
*
|
||||||
|
* @return The update count
|
||||||
|
*/
|
||||||
|
public int getUpdateCount();
|
||||||
|
}
|
|
@ -0,0 +1,267 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.procedure.internal;
|
||||||
|
|
||||||
|
import javax.persistence.ParameterMode;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.NotYetImplementedException;
|
||||||
|
import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport;
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.procedure.ParameterBind;
|
||||||
|
import org.hibernate.procedure.ParameterMisuseException;
|
||||||
|
import org.hibernate.type.DateType;
|
||||||
|
import org.hibernate.type.ProcedureParameterExtractionAware;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public abstract class AbstractParameterRegistrationImpl<T> implements ParameterRegistrationImplementor<T> {
|
||||||
|
private static final Logger log = Logger.getLogger( AbstractParameterRegistrationImpl.class );
|
||||||
|
|
||||||
|
private final CallImpl procedureCall;
|
||||||
|
|
||||||
|
private final Integer position;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private final ParameterMode mode;
|
||||||
|
private final Class<T> type;
|
||||||
|
|
||||||
|
private ParameterBindImpl bind;
|
||||||
|
|
||||||
|
private int startIndex;
|
||||||
|
private Type hibernateType;
|
||||||
|
private int[] sqlTypes;
|
||||||
|
|
||||||
|
protected AbstractParameterRegistrationImpl(
|
||||||
|
CallImpl procedureCall,
|
||||||
|
Integer position,
|
||||||
|
Class<T> type,
|
||||||
|
ParameterMode mode) {
|
||||||
|
this( procedureCall, position, null, type, mode );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractParameterRegistrationImpl(
|
||||||
|
CallImpl procedureCall,
|
||||||
|
String name,
|
||||||
|
Class<T> type,
|
||||||
|
ParameterMode mode) {
|
||||||
|
this( procedureCall, null, name, type, mode );
|
||||||
|
}
|
||||||
|
|
||||||
|
private AbstractParameterRegistrationImpl(
|
||||||
|
CallImpl procedureCall,
|
||||||
|
Integer position,
|
||||||
|
String name,
|
||||||
|
Class<T> type,
|
||||||
|
ParameterMode mode) {
|
||||||
|
this.procedureCall = procedureCall;
|
||||||
|
|
||||||
|
this.position = position;
|
||||||
|
this.name = name;
|
||||||
|
|
||||||
|
this.mode = mode;
|
||||||
|
this.type = type;
|
||||||
|
|
||||||
|
setHibernateType( session().getFactory().getTypeResolver().heuristicType( type.getName() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SessionImplementor session() {
|
||||||
|
return procedureCall.session();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParameterBind getParameterBind() {
|
||||||
|
return bind;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindValue(T value) {
|
||||||
|
validateBindability();
|
||||||
|
this.bind = new ParameterBindImpl<T>( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateBindability() {
|
||||||
|
if ( ! canBind() ) {
|
||||||
|
throw new ParameterMisuseException( "Cannot bind value to non-input parameter : " + this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canBind() {
|
||||||
|
return mode == ParameterMode.IN || mode == ParameterMode.INOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindValue(T value, TemporalType explicitTemporalType) {
|
||||||
|
validateBindability();
|
||||||
|
if ( explicitTemporalType != null ) {
|
||||||
|
if ( ! isDateTimeType() ) {
|
||||||
|
throw new IllegalArgumentException( "TemporalType should not be specified for non date/time type" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.bind = new ParameterBindImpl<T>( value, explicitTemporalType );
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDateTimeType() {
|
||||||
|
return Date.class.isAssignableFrom( type )
|
||||||
|
|| Calendar.class.isAssignableFrom( type );
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 ) {
|
||||||
|
// the user did not bind a value to the parameter being processed. That might be ok *if* the
|
||||||
|
// procedure as defined in the database defines a default value for that parameter.
|
||||||
|
// Unfortunately there is not a way to reliably know through JDBC metadata whether a procedure
|
||||||
|
// parameter defines a default value. So we simply allow the procedure execution to happen
|
||||||
|
// assuming that the database will complain appropriately if not setting the given parameter
|
||||||
|
// bind value is an error.
|
||||||
|
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() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// we have a REF_CURSOR type param
|
||||||
|
if ( procedureCall.getParameterStrategy() == ParameterStrategy.NAMED ) {
|
||||||
|
session().getFactory().getServiceRegistry()
|
||||||
|
.getService( RefCursorSupport.class )
|
||||||
|
.registerRefCursorParameter( statement, getName() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
session().getFactory().getServiceRegistry()
|
||||||
|
.getService( RefCursorSupport.class )
|
||||||
|
.registerRefCursorParameter( statement, getPosition() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getSqlTypes() {
|
||||||
|
return sqlTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public T extract(CallableStatement statement) {
|
||||||
|
if ( mode == ParameterMode.IN ) {
|
||||||
|
throw new ParameterMisuseException( "IN parameter not valid for output extraction" );
|
||||||
|
}
|
||||||
|
else if ( mode == ParameterMode.REF_CURSOR ) {
|
||||||
|
throw new ParameterMisuseException( "REF_CURSOR parameters should be accessed via results" );
|
||||||
|
}
|
||||||
|
|
||||||
|
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"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,389 @@
|
||||||
|
/*
|
||||||
|
* 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.procedure.internal;
|
||||||
|
|
||||||
|
import javax.persistence.ParameterMode;
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.LockMode;
|
||||||
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.QueryException;
|
||||||
|
import org.hibernate.cfg.NotYetImplementedException;
|
||||||
|
import org.hibernate.engine.ResultSetMappingDefinition;
|
||||||
|
import org.hibernate.engine.jdbc.spi.ExtractedDatabaseMetaData;
|
||||||
|
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.AbstractBasicQueryContractImpl;
|
||||||
|
import org.hibernate.internal.util.StringHelper;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.procedure.Call;
|
||||||
|
import org.hibernate.procedure.NamedParametersNotSupportedException;
|
||||||
|
import org.hibernate.procedure.ParameterRegistration;
|
||||||
|
import org.hibernate.procedure.Outputs;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard implementation of {@link Call}
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class CallImpl extends AbstractBasicQueryContractImpl implements Call {
|
||||||
|
private final String procedureName;
|
||||||
|
private final NativeSQLQueryReturn[] queryReturns;
|
||||||
|
|
||||||
|
private ParameterStrategy parameterStrategy = ParameterStrategy.UNKNOWN;
|
||||||
|
private List<ParameterRegistrationImplementor<?>> registeredParameters = new ArrayList<ParameterRegistrationImplementor<?>>();
|
||||||
|
|
||||||
|
private Set<String> synchronizedQuerySpaces;
|
||||||
|
|
||||||
|
private OutputsImpl outputs;
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public CallImpl(SessionImplementor session, String procedureName) {
|
||||||
|
this( session, procedureName, (List) null );
|
||||||
|
}
|
||||||
|
|
||||||
|
public CallImpl(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 CallImpl(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 CallImpl(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 CallImpl(
|
||||||
|
// 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 SessionImplementor session() {
|
||||||
|
// provide access to delegates
|
||||||
|
return super.session();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParameterStrategy getParameterStrategy() {
|
||||||
|
return parameterStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProcedureName() {
|
||||||
|
return procedureName;
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeSQLQueryReturn[] getQueryReturns() {
|
||||||
|
return queryReturns;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> ParameterRegistration<T> registerParameter(int position, Class<T> type, ParameterMode mode) {
|
||||||
|
final PositionalParameterRegistration parameterRegistration = new PositionalParameterRegistration( this, position, type, mode );
|
||||||
|
registerParameter( parameterRegistration );
|
||||||
|
return parameterRegistration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Call registerParameter0(int position, Class type, ParameterMode mode) {
|
||||||
|
registerParameter( position, type, mode );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerParameter(ParameterRegistrationImplementor parameter) {
|
||||||
|
if ( StringHelper.isNotEmpty( parameter.getName() ) ) {
|
||||||
|
prepareForNamedParameters();
|
||||||
|
}
|
||||||
|
else if ( parameter.getPosition() != null ) {
|
||||||
|
prepareForPositionalParameters();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException( "Given parameter did not define name or position [" + parameter + "]" );
|
||||||
|
}
|
||||||
|
registeredParameters.add( parameter );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareForPositionalParameters() {
|
||||||
|
if ( parameterStrategy == ParameterStrategy.NAMED ) {
|
||||||
|
throw new QueryException( "Cannot mix named and positional parameters" );
|
||||||
|
}
|
||||||
|
parameterStrategy = ParameterStrategy.POSITIONAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareForNamedParameters() {
|
||||||
|
if ( parameterStrategy == ParameterStrategy.POSITIONAL ) {
|
||||||
|
throw new QueryException( "Cannot mix named and positional parameters" );
|
||||||
|
}
|
||||||
|
if ( parameterStrategy == null ) {
|
||||||
|
// protect to only do this check once
|
||||||
|
final ExtractedDatabaseMetaData databaseMetaData = session().getTransactionCoordinator()
|
||||||
|
.getJdbcCoordinator()
|
||||||
|
.getLogicalConnection()
|
||||||
|
.getJdbcServices()
|
||||||
|
.getExtractedMetaDataSupport();
|
||||||
|
if ( ! databaseMetaData.supportsNamedParameters() ) {
|
||||||
|
throw new NamedParametersNotSupportedException(
|
||||||
|
"Named stored procedure parameters used, but JDBC driver does not support named parameters"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
parameterStrategy = ParameterStrategy.NAMED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParameterRegistrationImplementor getParameterRegistration(int position) {
|
||||||
|
if ( parameterStrategy != ParameterStrategy.POSITIONAL ) {
|
||||||
|
throw new IllegalArgumentException( "Positions were not used to register parameters with this stored procedure call" );
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return registeredParameters.get( position );
|
||||||
|
}
|
||||||
|
catch ( Exception e ) {
|
||||||
|
throw new QueryException( "Could not locate parameter registered using that position [" + position + "]" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> ParameterRegistration<T> registerParameter(String name, Class<T> type, ParameterMode mode) {
|
||||||
|
final NamedParameterRegistration parameterRegistration = new NamedParameterRegistration( this, name, type, mode );
|
||||||
|
registerParameter( parameterRegistration );
|
||||||
|
return parameterRegistration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Call registerParameter0(String name, Class type, ParameterMode mode) {
|
||||||
|
registerParameter( name, type, mode );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParameterRegistrationImplementor getParameterRegistration(String name) {
|
||||||
|
if ( parameterStrategy != ParameterStrategy.NAMED ) {
|
||||||
|
throw new IllegalArgumentException( "Names were not used to register parameters with this stored procedure call" );
|
||||||
|
}
|
||||||
|
for ( ParameterRegistrationImplementor parameter : registeredParameters ) {
|
||||||
|
if ( name.equals( parameter.getName() ) ) {
|
||||||
|
return parameter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException( "Could not locate parameter registered under that name [" + name + "]" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public List<ParameterRegistration> getRegisteredParameters() {
|
||||||
|
return new ArrayList<ParameterRegistration>( registeredParameters );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Outputs getOutputs() {
|
||||||
|
if ( outputs == null ) {
|
||||||
|
outputs = buildOutputs();
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OutputsImpl buildOutputs() {
|
||||||
|
// 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 ( ParameterRegistrationImplementor 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 ( ParameterRegistrationImplementor parameter : registeredParameters ) {
|
||||||
|
if ( parameter == null ) {
|
||||||
|
throw new QueryException( "Registered stored procedure parameters had gaps" );
|
||||||
|
}
|
||||||
|
|
||||||
|
parameter.prepare( statement, i );
|
||||||
|
i += parameter.getSqlTypes().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new OutputsImpl( 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 CallImpl addSynchronizedQuerySpace(String querySpace) {
|
||||||
|
synchronizedQuerySpaces().add( querySpace );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CallImpl addSynchronizedEntityName(String entityName) {
|
||||||
|
addSynchronizedQuerySpaces( session().getFactory().getEntityPersister( entityName ) );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addSynchronizedQuerySpaces(EntityPersister persister) {
|
||||||
|
synchronizedQuerySpaces().addAll( Arrays.asList( (String[]) persister.getQuerySpaces() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CallImpl 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParameterRegistrationImplementor[] collectRefCursorParameters() {
|
||||||
|
List<ParameterRegistrationImplementor> refCursorParams = new ArrayList<ParameterRegistrationImplementor>();
|
||||||
|
for ( ParameterRegistrationImplementor param : registeredParameters ) {
|
||||||
|
if ( param.getMode() == ParameterMode.REF_CURSOR ) {
|
||||||
|
refCursorParams.add( param );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return refCursorParams.toArray( new ParameterRegistrationImplementor[refCursorParams.size()] );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.procedure.internal;
|
||||||
|
|
||||||
|
import javax.persistence.ParameterMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class NamedParameterRegistration<T> extends AbstractParameterRegistrationImpl<T> {
|
||||||
|
public NamedParameterRegistration(
|
||||||
|
CallImpl procedureCall,
|
||||||
|
String name,
|
||||||
|
Class<T> type,
|
||||||
|
ParameterMode mode) {
|
||||||
|
super( procedureCall, name, type, mode );
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,7 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.internal;
|
package org.hibernate.procedure.internal;
|
||||||
|
|
||||||
import java.sql.CallableStatement;
|
import java.sql.CallableStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
|
@ -32,27 +32,24 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.hibernate.JDBCException;
|
import org.hibernate.JDBCException;
|
||||||
import org.hibernate.StoredProcedureOutputs;
|
import org.hibernate.procedure.Outputs;
|
||||||
import org.hibernate.StoredProcedureResultSetReturn;
|
import org.hibernate.procedure.ParameterRegistration;
|
||||||
import org.hibernate.StoredProcedureReturn;
|
import org.hibernate.procedure.Return;
|
||||||
import org.hibernate.StoredProcedureUpdateCountReturn;
|
|
||||||
import org.hibernate.engine.spi.QueryParameters;
|
import org.hibernate.engine.spi.QueryParameters;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.internal.StoredProcedureCallImpl.StoredProcedureParameterImplementor;
|
|
||||||
import org.hibernate.loader.custom.CustomLoader;
|
import org.hibernate.loader.custom.CustomLoader;
|
||||||
import org.hibernate.loader.custom.CustomQuery;
|
import org.hibernate.loader.custom.CustomQuery;
|
||||||
import org.hibernate.loader.custom.Return;
|
|
||||||
import org.hibernate.loader.custom.sql.SQLQueryReturnProcessor;
|
import org.hibernate.loader.custom.sql.SQLQueryReturnProcessor;
|
||||||
import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport;
|
import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class StoredProcedureOutputsImpl implements StoredProcedureOutputs {
|
public class OutputsImpl implements Outputs {
|
||||||
private final StoredProcedureCallImpl procedureCall;
|
private final CallImpl procedureCall;
|
||||||
private final CallableStatement callableStatement;
|
private final CallableStatement callableStatement;
|
||||||
|
|
||||||
private final StoredProcedureParameterImplementor[] refCursorParameters;
|
private final ParameterRegistrationImplementor[] refCursorParameters;
|
||||||
private final CustomLoaderExtension loader;
|
private final CustomLoaderExtension loader;
|
||||||
|
|
||||||
private CurrentReturnDescriptor currentReturnDescriptor;
|
private CurrentReturnDescriptor currentReturnDescriptor;
|
||||||
|
@ -60,7 +57,7 @@ public class StoredProcedureOutputsImpl implements StoredProcedureOutputs {
|
||||||
private boolean executed = false;
|
private boolean executed = false;
|
||||||
private int refCursorParamIndex = 0;
|
private int refCursorParamIndex = 0;
|
||||||
|
|
||||||
StoredProcedureOutputsImpl(StoredProcedureCallImpl procedureCall, CallableStatement callableStatement) {
|
OutputsImpl(CallImpl procedureCall, CallableStatement callableStatement) {
|
||||||
this.procedureCall = procedureCall;
|
this.procedureCall = procedureCall;
|
||||||
this.callableStatement = callableStatement;
|
this.callableStatement = callableStatement;
|
||||||
|
|
||||||
|
@ -69,14 +66,19 @@ public class StoredProcedureOutputsImpl implements StoredProcedureOutputs {
|
||||||
this.loader = buildSpecializedCustomLoader( procedureCall );
|
this.loader = buildSpecializedCustomLoader( procedureCall );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T getOutputParameterValue(ParameterRegistration<T> parameterRegistration) {
|
||||||
|
return ( (ParameterRegistrationImplementor<T>) parameterRegistration ).extract( callableStatement );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getOutputParameterValue(String name) {
|
public Object getOutputParameterValue(String name) {
|
||||||
return procedureCall.getRegisteredParameter( name ).extract( callableStatement );
|
return procedureCall.getParameterRegistration( name ).extract( callableStatement );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getOutputParameterValue(int position) {
|
public Object getOutputParameterValue(int position) {
|
||||||
return procedureCall.getRegisteredParameter( position ).extract( callableStatement );
|
return procedureCall.getParameterRegistration( position ).extract( callableStatement );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -125,7 +127,7 @@ public class StoredProcedureOutputsImpl implements StoredProcedureOutputs {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StoredProcedureReturn getNextReturn() {
|
public Return getNextReturn() {
|
||||||
if ( currentReturnDescriptor == null ) {
|
if ( currentReturnDescriptor == null ) {
|
||||||
if ( executed ) {
|
if ( executed ) {
|
||||||
throw new IllegalStateException( "Unexpected condition" );
|
throw new IllegalStateException( "Unexpected condition" );
|
||||||
|
@ -157,7 +159,7 @@ public class StoredProcedureOutputsImpl implements StoredProcedureOutputs {
|
||||||
this.refCursorParamIndex++;
|
this.refCursorParamIndex++;
|
||||||
ResultSet resultSet;
|
ResultSet resultSet;
|
||||||
int refCursorParamIndex = copyReturnDescriptor.refCursorParamIndex;
|
int refCursorParamIndex = copyReturnDescriptor.refCursorParamIndex;
|
||||||
StoredProcedureParameterImplementor refCursorParam = refCursorParameters[refCursorParamIndex];
|
ParameterRegistrationImplementor refCursorParam = refCursorParameters[refCursorParamIndex];
|
||||||
if ( refCursorParam.getName() != null ) {
|
if ( refCursorParam.getName() != null ) {
|
||||||
resultSet = procedureCall.session().getFactory().getServiceRegistry()
|
resultSet = procedureCall.session().getFactory().getServiceRegistry()
|
||||||
.getService( RefCursorSupport.class )
|
.getService( RefCursorSupport.class )
|
||||||
|
@ -192,11 +194,11 @@ public class StoredProcedureOutputsImpl implements StoredProcedureOutputs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ResultSetReturn implements StoredProcedureResultSetReturn {
|
private static class ResultSetReturn implements org.hibernate.procedure.ResultSetReturn {
|
||||||
private final StoredProcedureOutputsImpl storedProcedureOutputs;
|
private final OutputsImpl storedProcedureOutputs;
|
||||||
private final ResultSet resultSet;
|
private final ResultSet resultSet;
|
||||||
|
|
||||||
public ResultSetReturn(StoredProcedureOutputsImpl storedProcedureOutputs, ResultSet resultSet) {
|
public ResultSetReturn(OutputsImpl storedProcedureOutputs, ResultSet resultSet) {
|
||||||
this.storedProcedureOutputs = storedProcedureOutputs;
|
this.storedProcedureOutputs = storedProcedureOutputs;
|
||||||
this.resultSet = resultSet;
|
this.resultSet = resultSet;
|
||||||
}
|
}
|
||||||
|
@ -229,12 +231,12 @@ public class StoredProcedureOutputsImpl implements StoredProcedureOutputs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class UpdateCountReturn implements StoredProcedureUpdateCountReturn {
|
private class UpdateCountReturn implements org.hibernate.procedure.UpdateCountReturn {
|
||||||
private final StoredProcedureOutputsImpl storedProcedureOutputs;
|
private final OutputsImpl procedureOutputs;
|
||||||
private final int updateCount;
|
private final int updateCount;
|
||||||
|
|
||||||
public UpdateCountReturn(StoredProcedureOutputsImpl storedProcedureOutputs, int updateCount) {
|
public UpdateCountReturn(OutputsImpl procedureOutputs, int updateCount) {
|
||||||
this.storedProcedureOutputs = storedProcedureOutputs;
|
this.procedureOutputs = procedureOutputs;
|
||||||
this.updateCount = updateCount;
|
this.updateCount = updateCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,13 +251,13 @@ public class StoredProcedureOutputsImpl implements StoredProcedureOutputs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CustomLoaderExtension buildSpecializedCustomLoader(final StoredProcedureCallImpl procedureCall) {
|
private static CustomLoaderExtension buildSpecializedCustomLoader(final CallImpl procedureCall) {
|
||||||
final SQLQueryReturnProcessor processor = new SQLQueryReturnProcessor(
|
final SQLQueryReturnProcessor processor = new SQLQueryReturnProcessor(
|
||||||
procedureCall.getQueryReturns(),
|
procedureCall.getQueryReturns(),
|
||||||
procedureCall.session().getFactory()
|
procedureCall.session().getFactory()
|
||||||
);
|
);
|
||||||
processor.process();
|
processor.process();
|
||||||
final List<Return> customReturns = processor.generateCustomReturns( false );
|
final List<org.hibernate.loader.custom.Return> customReturns = processor.generateCustomReturns( false );
|
||||||
|
|
||||||
CustomQuery customQuery = new CustomQuery() {
|
CustomQuery customQuery = new CustomQuery() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -275,7 +277,7 @@ public class StoredProcedureOutputsImpl implements StoredProcedureOutputs {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Return> getCustomQueryReturns() {
|
public List<org.hibernate.loader.custom.Return> getCustomQueryReturns() {
|
||||||
return customReturns;
|
return customReturns;
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.procedure.internal;
|
||||||
|
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
import org.hibernate.procedure.ParameterBind;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the {@link ParameterBind} contract.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class ParameterBindImpl<T> implements ParameterBind<T> {
|
||||||
|
private final T value;
|
||||||
|
private final TemporalType explicitTemporalType;
|
||||||
|
|
||||||
|
public ParameterBindImpl(T value) {
|
||||||
|
this( value, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParameterBindImpl(T value, TemporalType explicitTemporalType) {
|
||||||
|
this.value = value;
|
||||||
|
this.explicitTemporalType = explicitTemporalType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TemporalType getExplicitTemporalType() {
|
||||||
|
return explicitTemporalType;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.procedure.internal;
|
||||||
|
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.hibernate.procedure.ParameterRegistration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface ParameterRegistrationImplementor<T> extends ParameterRegistration<T> {
|
||||||
|
public void prepare(CallableStatement statement, int i) throws SQLException;
|
||||||
|
|
||||||
|
public int[] getSqlTypes();
|
||||||
|
|
||||||
|
public T extract(CallableStatement statement);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.procedure.internal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The style/strategy of parameter registration used in a particular procedure call definition.
|
||||||
|
*/
|
||||||
|
public enum ParameterStrategy {
|
||||||
|
NAMED,
|
||||||
|
POSITIONAL,
|
||||||
|
UNKNOWN
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.procedure.internal;
|
||||||
|
|
||||||
|
import javax.persistence.ParameterMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class PositionalParameterRegistration<T> extends AbstractParameterRegistrationImpl<T> {
|
||||||
|
public PositionalParameterRegistration(
|
||||||
|
CallImpl procedureCall,
|
||||||
|
Integer position,
|
||||||
|
Class<T> type,
|
||||||
|
ParameterMode mode) {
|
||||||
|
super( procedureCall, position, type, mode );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package org.hibernate.procedure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines support for executing database stored procedures and functions and accessing its outputs.
|
||||||
|
* <p/>
|
||||||
|
* First a reference to {@link Call} is obtained through one of the overloaded
|
||||||
|
* {@link org.hibernate.Session#createStoredProcedureCall} methods. The Call reference is then used to "configure"
|
||||||
|
* the procedure call (set timeouts, etc) and to perform parameter registration. All procedure parameters that the
|
||||||
|
* application wants to use must be registered. For all IN and INOUT parameters, values can then be bound.
|
||||||
|
* <p/>
|
||||||
|
* At this point we are ready to execute the procedure call and start accessing the outputs. This is done by first
|
||||||
|
* calling the {@link Call#getOutputs()} method. The underlying JDBC call is executed as needed. The pattern to
|
||||||
|
* access the returns is iterating through the outputs while {@link Outputs#hasMoreReturns()} returns {@code true} and
|
||||||
|
* calling {@link Outputs#getNextReturn()} during iteration:
|
||||||
|
* <code>
|
||||||
|
* Call call = session.createStoredProcedureCall( "some_procedure" );
|
||||||
|
* ...
|
||||||
|
* Outputs = call.getOutputs();
|
||||||
|
* while ( call.hasMoreReturns() ) {
|
||||||
|
* final Return rtn = call.getNextReturn();
|
||||||
|
* if ( rtn.isResultSet() ) {
|
||||||
|
* handleResultSetReturn( (ResultSetReturn) rtn );
|
||||||
|
* }
|
||||||
|
* else {
|
||||||
|
* handleUpdateCountReturn( (UpdateCountReturn) rtn );
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </code>
|
||||||
|
* <p/>
|
||||||
|
* Finally output parameters can be accessed using the overloaded {@link Outputs#getOutputParameterValue} methods.
|
||||||
|
* For portability amongst databases, it is advised to access the output parameters after all returns have been
|
||||||
|
* processed.
|
||||||
|
*
|
||||||
|
* @see org.hibernate.Session#createStoredProcedureCall(String)
|
||||||
|
* @see org.hibernate.Session#createStoredProcedureCall(String, Class[])
|
||||||
|
* @see org.hibernate.Session#createStoredProcedureCall(String, String...)
|
||||||
|
*/
|
|
@ -23,24 +23,21 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.sql.storedproc;
|
package org.hibernate.test.sql.storedproc;
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.ParameterMode;
|
||||||
import javax.persistence.Id;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.JDBCException;
|
||||||
import org.hibernate.SQLQuery;
|
|
||||||
import org.hibernate.Session;
|
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.cfg.Configuration;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.dialect.H2Dialect;
|
|
||||||
import org.hibernate.engine.spi.Mapping;
|
import org.hibernate.engine.spi.Mapping;
|
||||||
import org.hibernate.mapping.AuxiliaryDatabaseObject;
|
import org.hibernate.mapping.AuxiliaryDatabaseObject;
|
||||||
|
import org.hibernate.procedure.Call;
|
||||||
|
import org.hibernate.procedure.Outputs;
|
||||||
|
import org.hibernate.procedure.ResultSetReturn;
|
||||||
|
import org.hibernate.procedure.Return;
|
||||||
|
import org.hibernate.dialect.H2Dialect;
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.hibernate.testing.RequiresDialect;
|
import org.hibernate.testing.RequiresDialect;
|
||||||
|
@ -50,67 +47,289 @@ import org.hibernate.testing.junit4.ExtraAssertions;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
@RequiresDialect( H2Dialect.class )
|
@RequiresDialect( H2Dialect.class )
|
||||||
public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
||||||
// this is not working in H2
|
@Override
|
||||||
// @Override
|
protected void configure(Configuration configuration) {
|
||||||
// protected void configure(Configuration configuration) {
|
super.configure( configuration );
|
||||||
// super.configure( configuration );
|
configuration.addAuxiliaryDatabaseObject(
|
||||||
// configuration.addAuxiliaryDatabaseObject(
|
new AuxiliaryDatabaseObject() {
|
||||||
// new AuxiliaryDatabaseObject() {
|
@Override
|
||||||
// @Override
|
public void addDialectScope(String dialectName) {
|
||||||
// public void addDialectScope(String dialectName) {
|
}
|
||||||
// }
|
|
||||||
//
|
@Override
|
||||||
// @Override
|
public boolean appliesToDialect(Dialect dialect) {
|
||||||
// public boolean appliesToDialect(Dialect dialect) {
|
return H2Dialect.class.isInstance( dialect );
|
||||||
// return H2Dialect.class.isInstance( dialect );
|
}
|
||||||
// }
|
|
||||||
//
|
@Override
|
||||||
// @Override
|
public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, String defaultSchema) {
|
||||||
// public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, String defaultSchema) {
|
return "CREATE ALIAS findOneUser AS $$\n" +
|
||||||
// return "CREATE ALIAS findUser AS $$\n" +
|
"import org.h2.tools.SimpleResultSet;\n" +
|
||||||
// "import org.h2.tools.SimpleResultSet;\n" +
|
"import java.sql.*;\n" +
|
||||||
// "import java.sql.*;\n" +
|
"@CODE\n" +
|
||||||
// "@CODE\n" +
|
"ResultSet findOneUser() {\n" +
|
||||||
// "ResultSet findUser() {\n" +
|
" SimpleResultSet rs = new SimpleResultSet();\n" +
|
||||||
// " SimpleResultSet rs = new SimpleResultSet();\n" +
|
" rs.addColumn(\"ID\", Types.INTEGER, 10, 0);\n" +
|
||||||
// " rs.addColumn(\"ID\", Types.INTEGER, 10, 0);\n" +
|
" rs.addColumn(\"NAME\", Types.VARCHAR, 255, 0);\n" +
|
||||||
// " rs.addColumn(\"NAME\", Types.VARCHAR, 255, 0);\n" +
|
" rs.addRow(1, \"Steve\");\n" +
|
||||||
// " rs.addRow(1, \"Steve\");\n" +
|
" return rs;\n" +
|
||||||
// " return rs;\n" +
|
"}\n" +
|
||||||
// "}\n" +
|
"$$";
|
||||||
// "$$";
|
}
|
||||||
// }
|
|
||||||
//
|
@Override
|
||||||
// @Override
|
public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
|
||||||
// public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
|
return "DROP ALIAS findUser IF EXISTS";
|
||||||
// return "DROP ALIAS findUser IF EXISTS";
|
}
|
||||||
// }
|
}
|
||||||
// }
|
);
|
||||||
// );
|
|
||||||
// }
|
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 findUsers AS $$\n" +
|
||||||
|
"import org.h2.tools.SimpleResultSet;\n" +
|
||||||
|
"import java.sql.*;\n" +
|
||||||
|
"@CODE\n" +
|
||||||
|
"ResultSet findUsers() {\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" +
|
||||||
|
" rs.addRow(2, \"John\");\n" +
|
||||||
|
" rs.addRow(3, \"Jane\");\n" +
|
||||||
|
" return rs;\n" +
|
||||||
|
"}\n" +
|
||||||
|
"$$";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
|
||||||
|
return "DROP ALIAS findUser IF EXISTS";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
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 findUserRange AS $$\n" +
|
||||||
|
"import org.h2.tools.SimpleResultSet;\n" +
|
||||||
|
"import java.sql.*;\n" +
|
||||||
|
"@CODE\n" +
|
||||||
|
"ResultSet findUserRange(int start, int end) {\n" +
|
||||||
|
" SimpleResultSet rs = new SimpleResultSet();\n" +
|
||||||
|
" rs.addColumn(\"ID\", Types.INTEGER, 10, 0);\n" +
|
||||||
|
" rs.addColumn(\"NAME\", Types.VARCHAR, 255, 0);\n" +
|
||||||
|
" for ( int i = start; i < end; i++ ) {\n" +
|
||||||
|
" rs.addRow(1, \"User \" + i );\n" +
|
||||||
|
" }\n" +
|
||||||
|
" return rs;\n" +
|
||||||
|
"}\n" +
|
||||||
|
"$$";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
|
||||||
|
return "DROP ALIAS findUser IF EXISTS";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void baseTest() {
|
public void baseTest() {
|
||||||
Session session = openSession();
|
Session session = openSession();
|
||||||
session.beginTransaction();
|
session.beginTransaction();
|
||||||
|
|
||||||
StoredProcedureCall query = session.createStoredProcedureCall( "user");
|
Call query = session.createStoredProcedureCall( "user");
|
||||||
StoredProcedureOutputs outputs = query.getOutputs();
|
Outputs outputs = query.getOutputs();
|
||||||
assertTrue( "Checking StoredProcedureOutputs has more returns", outputs.hasMoreReturns() );
|
assertTrue( "Checking Outputs has more returns", outputs.hasMoreReturns() );
|
||||||
StoredProcedureReturn nextReturn = outputs.getNextReturn();
|
Return nextReturn = outputs.getNextReturn();
|
||||||
assertNotNull( nextReturn );
|
assertNotNull( nextReturn );
|
||||||
ExtraAssertions.assertClassAssignability( StoredProcedureResultSetReturn.class, nextReturn.getClass() );
|
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
||||||
StoredProcedureResultSetReturn resultSetReturn = (StoredProcedureResultSetReturn) nextReturn;
|
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
||||||
String name = (String) resultSetReturn.getSingleResult();
|
String name = (String) resultSetReturn.getSingleResult();
|
||||||
assertEquals( "SA", name );
|
assertEquals( "SA", name );
|
||||||
|
|
||||||
session.getTransaction().commit();
|
session.getTransaction().commit();
|
||||||
session.close();
|
session.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSingleResultTuple() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
|
||||||
|
Call query = session.createStoredProcedureCall( "findOneUser" );
|
||||||
|
Outputs outputs = query.getOutputs();
|
||||||
|
assertTrue( "Checking Outputs has more returns", outputs.hasMoreReturns() );
|
||||||
|
Return nextReturn = outputs.getNextReturn();
|
||||||
|
assertNotNull( nextReturn );
|
||||||
|
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
||||||
|
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
||||||
|
Object result = resultSetReturn.getSingleResult();
|
||||||
|
ExtraAssertions.assertTyping( Object[].class, result );
|
||||||
|
String name = (String) ( (Object[]) result )[1];
|
||||||
|
assertEquals( "Steve", name );
|
||||||
|
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetResultListTuple() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
|
||||||
|
Call query = session.createStoredProcedureCall( "findUsers" );
|
||||||
|
Outputs outputs = query.getOutputs();
|
||||||
|
assertTrue( "Checking Outputs has more returns", outputs.hasMoreReturns() );
|
||||||
|
Return nextReturn = outputs.getNextReturn();
|
||||||
|
assertNotNull( nextReturn );
|
||||||
|
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
||||||
|
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
||||||
|
List results = resultSetReturn.getResultList();
|
||||||
|
assertEquals( 3, results.size() );
|
||||||
|
|
||||||
|
for ( Object result : results ) {
|
||||||
|
ExtraAssertions.assertTyping( Object[].class, result );
|
||||||
|
Integer id = (Integer) ( (Object[]) result )[0];
|
||||||
|
String name = (String) ( (Object[]) result )[1];
|
||||||
|
if ( id.equals( 1 ) ) {
|
||||||
|
assertEquals( "Steve", name );
|
||||||
|
}
|
||||||
|
else if ( id.equals( 2 ) ) {
|
||||||
|
assertEquals( "John", name );
|
||||||
|
}
|
||||||
|
else if ( id.equals( 3 ) ) {
|
||||||
|
assertEquals( "Jane", name );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fail( "Unexpected id value found [" + id + "]" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInParametersByName() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
|
||||||
|
Call query = session.createStoredProcedureCall( "findUserRange" );
|
||||||
|
query.registerParameter( "start", Integer.class, ParameterMode.IN ).bindValue( 1 );
|
||||||
|
query.registerParameter( "end", Integer.class, ParameterMode.IN ).bindValue( 2 );
|
||||||
|
Outputs outputs = query.getOutputs();
|
||||||
|
assertTrue( "Checking Outputs has more returns", outputs.hasMoreReturns() );
|
||||||
|
Return nextReturn = outputs.getNextReturn();
|
||||||
|
assertNotNull( nextReturn );
|
||||||
|
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
||||||
|
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
||||||
|
List results = resultSetReturn.getResultList();
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
Object result = results.get( 0 );
|
||||||
|
ExtraAssertions.assertTyping( Object[].class, result );
|
||||||
|
Integer id = (Integer) ( (Object[]) result )[0];
|
||||||
|
String name = (String) ( (Object[]) result )[1];
|
||||||
|
assertEquals( 1, (int) id );
|
||||||
|
assertEquals( "User 1", name );
|
||||||
|
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInParametersByPosition() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
|
||||||
|
Call query = session.createStoredProcedureCall( "findUserRange" );
|
||||||
|
query.registerParameter( 1, Integer.class, ParameterMode.IN ).bindValue( 1 );
|
||||||
|
query.registerParameter( 2, Integer.class, ParameterMode.IN ).bindValue( 2 );
|
||||||
|
Outputs outputs = query.getOutputs();
|
||||||
|
assertTrue( "Checking Outputs has more returns", outputs.hasMoreReturns() );
|
||||||
|
Return nextReturn = outputs.getNextReturn();
|
||||||
|
assertNotNull( nextReturn );
|
||||||
|
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
||||||
|
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
||||||
|
List results = resultSetReturn.getResultList();
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
Object result = results.get( 0 );
|
||||||
|
ExtraAssertions.assertTyping( Object[].class, result );
|
||||||
|
Integer id = (Integer) ( (Object[]) result )[0];
|
||||||
|
String name = (String) ( (Object[]) result )[1];
|
||||||
|
assertEquals( 1, (int) id );
|
||||||
|
assertEquals( "User 1", name );
|
||||||
|
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInParametersNotSet() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
|
||||||
|
// since the procedure does not define defaults for parameters this should result in SQLExceptions on
|
||||||
|
// execution
|
||||||
|
|
||||||
|
{
|
||||||
|
Call query = session.createStoredProcedureCall( "findUserRange" );
|
||||||
|
query.registerParameter( 1, Integer.class, ParameterMode.IN );
|
||||||
|
query.registerParameter( 2, Integer.class, ParameterMode.IN ).bindValue( 2 );
|
||||||
|
Outputs outputs = query.getOutputs();
|
||||||
|
try {
|
||||||
|
outputs.hasMoreReturns();
|
||||||
|
fail( "Expecting failure due to missing parameter bind" );
|
||||||
|
}
|
||||||
|
catch (JDBCException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Call query = session.createStoredProcedureCall( "findUserRange" );
|
||||||
|
query.registerParameter( "start", Integer.class, ParameterMode.IN );
|
||||||
|
query.registerParameter( "end", Integer.class, ParameterMode.IN ).bindValue( 2 );
|
||||||
|
Outputs outputs = query.getOutputs();
|
||||||
|
try {
|
||||||
|
outputs.hasMoreReturns();
|
||||||
|
fail( "Expecting failure due to missing parameter bind" );
|
||||||
|
}
|
||||||
|
catch (JDBCException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,11 +37,11 @@ import java.util.List;
|
||||||
import org.hibernate.CacheMode;
|
import org.hibernate.CacheMode;
|
||||||
import org.hibernate.FlushMode;
|
import org.hibernate.FlushMode;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.StoredProcedureCall;
|
import org.hibernate.procedure.Call;
|
||||||
import org.hibernate.StoredProcedureOutputs;
|
import org.hibernate.procedure.Outputs;
|
||||||
import org.hibernate.StoredProcedureResultSetReturn;
|
import org.hibernate.procedure.ResultSetReturn;
|
||||||
import org.hibernate.StoredProcedureReturn;
|
import org.hibernate.procedure.Return;
|
||||||
import org.hibernate.StoredProcedureUpdateCountReturn;
|
import org.hibernate.procedure.UpdateCountReturn;
|
||||||
import org.hibernate.jpa.spi.BaseQueryImpl;
|
import org.hibernate.jpa.spi.BaseQueryImpl;
|
||||||
import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
|
import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
|
||||||
|
|
||||||
|
@ -49,60 +49,61 @@ import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredProcedureQuery {
|
public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredProcedureQuery {
|
||||||
private final StoredProcedureCall storedProcedureCall;
|
private final Call procedureCall;
|
||||||
private StoredProcedureOutputs storedProcedureOutputs;
|
private Outputs procedureOutputs;
|
||||||
|
|
||||||
public StoredProcedureQueryImpl(StoredProcedureCall storedProcedureCall, HibernateEntityManagerImplementor entityManager) {
|
public StoredProcedureQueryImpl(Call procedureCall, HibernateEntityManagerImplementor entityManager) {
|
||||||
super( entityManager );
|
super( entityManager );
|
||||||
this.storedProcedureCall = storedProcedureCall;
|
this.procedureCall = procedureCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean applyTimeoutHint(int timeout) {
|
protected boolean applyTimeoutHint(int timeout) {
|
||||||
storedProcedureCall.setTimeout( timeout );
|
procedureCall.setTimeout( timeout );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean applyCacheableHint(boolean isCacheable) {
|
protected boolean applyCacheableHint(boolean isCacheable) {
|
||||||
storedProcedureCall.setCacheable( isCacheable );
|
procedureCall.setCacheable( isCacheable );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean applyCacheRegionHint(String regionName) {
|
protected boolean applyCacheRegionHint(String regionName) {
|
||||||
storedProcedureCall.setCacheRegion( regionName );
|
procedureCall.setCacheRegion( regionName );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean applyReadOnlyHint(boolean isReadOnly) {
|
protected boolean applyReadOnlyHint(boolean isReadOnly) {
|
||||||
storedProcedureCall.setReadOnly( isReadOnly );
|
procedureCall.setReadOnly( isReadOnly );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean applyCacheModeHint(CacheMode cacheMode) {
|
protected boolean applyCacheModeHint(CacheMode cacheMode) {
|
||||||
storedProcedureCall.setCacheMode( cacheMode );
|
procedureCall.setCacheMode( cacheMode );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean applyFlushModeHint(FlushMode flushMode) {
|
protected boolean applyFlushModeHint(FlushMode flushMode) {
|
||||||
storedProcedureCall.setFlushMode( flushMode );
|
procedureCall.setFlushMode( flushMode );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public StoredProcedureQuery registerStoredProcedureParameter(int position, Class type, ParameterMode mode) {
|
public StoredProcedureQuery registerStoredProcedureParameter(int position, Class type, ParameterMode mode) {
|
||||||
storedProcedureCall.registerStoredProcedureParameter( position, type, mode );
|
procedureCall.registerParameter( position, type, mode );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public StoredProcedureQuery registerStoredProcedureParameter(String parameterName, Class type, ParameterMode mode) {
|
public StoredProcedureQuery registerStoredProcedureParameter(String parameterName, Class type, ParameterMode mode) {
|
||||||
storedProcedureCall.registerStoredProcedureParameter( parameterName, type, mode );
|
procedureCall.registerParameter( parameterName, type, mode );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,11 +172,11 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
|
||||||
|
|
||||||
// outputs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// outputs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
private StoredProcedureOutputs outputs() {
|
private Outputs outputs() {
|
||||||
if ( storedProcedureOutputs == null ) {
|
if ( procedureOutputs == null ) {
|
||||||
storedProcedureOutputs = storedProcedureCall.getOutputs();
|
procedureOutputs = procedureCall.getOutputs();
|
||||||
}
|
}
|
||||||
return storedProcedureOutputs;
|
return procedureOutputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -205,29 +206,29 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getUpdateCount() {
|
public int getUpdateCount() {
|
||||||
final StoredProcedureReturn nextReturn = outputs().getNextReturn();
|
final Return nextReturn = outputs().getNextReturn();
|
||||||
if ( nextReturn.isResultSet() ) {
|
if ( nextReturn.isResultSet() ) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return ( (StoredProcedureUpdateCountReturn) nextReturn ).getUpdateCount();
|
return ( (UpdateCountReturn) nextReturn ).getUpdateCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List getResultList() {
|
public List getResultList() {
|
||||||
final StoredProcedureReturn nextReturn = outputs().getNextReturn();
|
final Return nextReturn = outputs().getNextReturn();
|
||||||
if ( ! nextReturn.isResultSet() ) {
|
if ( ! nextReturn.isResultSet() ) {
|
||||||
return null; // todo : what should be thrown/returned here?
|
return null; // todo : what should be thrown/returned here?
|
||||||
}
|
}
|
||||||
return ( (StoredProcedureResultSetReturn) nextReturn ).getResultList();
|
return ( (ResultSetReturn) nextReturn ).getResultList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getSingleResult() {
|
public Object getSingleResult() {
|
||||||
final StoredProcedureReturn nextReturn = outputs().getNextReturn();
|
final Return nextReturn = outputs().getNextReturn();
|
||||||
if ( ! nextReturn.isResultSet() ) {
|
if ( ! nextReturn.isResultSet() ) {
|
||||||
return null; // todo : what should be thrown/returned here?
|
return null; // todo : what should be thrown/returned here?
|
||||||
}
|
}
|
||||||
return ( (StoredProcedureResultSetReturn) nextReturn ).getSingleResult();
|
return ( (ResultSetReturn) nextReturn ).getSingleResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -83,7 +83,7 @@ import org.hibernate.SQLQuery;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.StaleObjectStateException;
|
import org.hibernate.StaleObjectStateException;
|
||||||
import org.hibernate.StaleStateException;
|
import org.hibernate.StaleStateException;
|
||||||
import org.hibernate.StoredProcedureCall;
|
import org.hibernate.procedure.Call;
|
||||||
import org.hibernate.TransientObjectException;
|
import org.hibernate.TransientObjectException;
|
||||||
import org.hibernate.TypeMismatchException;
|
import org.hibernate.TypeMismatchException;
|
||||||
import org.hibernate.UnresolvableObjectException;
|
import org.hibernate.UnresolvableObjectException;
|
||||||
|
@ -813,7 +813,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
@Override
|
@Override
|
||||||
public StoredProcedureQuery createStoredProcedureQuery(String procedureName) {
|
public StoredProcedureQuery createStoredProcedureQuery(String procedureName) {
|
||||||
try {
|
try {
|
||||||
StoredProcedureCall call = getSession().createStoredProcedureCall( procedureName );
|
Call call = getSession().createStoredProcedureCall( procedureName );
|
||||||
return new StoredProcedureQueryImpl( call, this );
|
return new StoredProcedureQueryImpl( call, this );
|
||||||
}
|
}
|
||||||
catch ( HibernateException he ) {
|
catch ( HibernateException he ) {
|
||||||
|
@ -824,7 +824,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
@Override
|
@Override
|
||||||
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) {
|
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) {
|
||||||
try {
|
try {
|
||||||
StoredProcedureCall call = getSession().createStoredProcedureCall( procedureName, resultClasses );
|
Call call = getSession().createStoredProcedureCall( procedureName, resultClasses );
|
||||||
return new StoredProcedureQueryImpl( call, this );
|
return new StoredProcedureQueryImpl( call, this );
|
||||||
}
|
}
|
||||||
catch ( HibernateException he ) {
|
catch ( HibernateException he ) {
|
||||||
|
|
Loading…
Reference in New Issue