HHH-8395 - JPA StoredProcedureQuery#getUpdateCount should prefer return -1 rather than throw exceptions
This commit is contained in:
parent
33b7e9f441
commit
cd1c80b82d
|
@ -613,23 +613,7 @@ public class CustomLoader extends Loader {
|
||||||
rowProcessor.columnProcessors[i].performDiscovery( metadata, types, aliases );
|
rowProcessor.columnProcessors[i].performDiscovery( metadata, types, aliases );
|
||||||
}
|
}
|
||||||
|
|
||||||
// lets make sure we did not end up with duplicate aliases. this can occur when the user supplied query
|
validateAliases( aliases );
|
||||||
// did not rename same-named columns. e.g.:
|
|
||||||
// select u.username, u2.username from t_user u, t_user u2 ...
|
|
||||||
//
|
|
||||||
// the above will lead to an unworkable situation in most cases (the difference is how the driver/db
|
|
||||||
// handle this situation. But if the 'aliases' variable contains duplicate names, then we have that
|
|
||||||
// troublesome condition, so lets throw an error. See HHH-5992
|
|
||||||
final HashSet<String> aliasesSet = new HashSet<String>();
|
|
||||||
for ( String alias : aliases ) {
|
|
||||||
boolean alreadyExisted = !aliasesSet.add( alias );
|
|
||||||
if ( alreadyExisted ) {
|
|
||||||
throw new NonUniqueDiscoveredSqlAliasException(
|
|
||||||
"Encountered a duplicated sql alias [" + alias +
|
|
||||||
"] during auto-discovery of a native-sql query"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resultTypes = ArrayHelper.toTypeArray( types );
|
resultTypes = ArrayHelper.toTypeArray( types );
|
||||||
transformerAliases = ArrayHelper.toStringArray( aliases );
|
transformerAliases = ArrayHelper.toStringArray( aliases );
|
||||||
|
@ -639,6 +623,30 @@ public class CustomLoader extends Loader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateAliases(List<String> aliases) {
|
||||||
|
// lets make sure we did not end up with duplicate aliases. this can occur when the user supplied query
|
||||||
|
// did not rename same-named columns. e.g.:
|
||||||
|
// select u.username, u2.username from t_user u, t_user u2 ...
|
||||||
|
//
|
||||||
|
// the above will lead to an unworkable situation in most cases (the difference is how the driver/db
|
||||||
|
// handle this situation. But if the 'aliases' variable contains duplicate names, then we have that
|
||||||
|
// troublesome condition, so lets throw an error. See HHH-5992
|
||||||
|
final HashSet<String> aliasesSet = new HashSet<String>();
|
||||||
|
for ( String alias : aliases ) {
|
||||||
|
validateAlias( alias );
|
||||||
|
boolean alreadyExisted = !aliasesSet.add( alias );
|
||||||
|
if ( alreadyExisted ) {
|
||||||
|
throw new NonUniqueDiscoveredSqlAliasException(
|
||||||
|
"Encountered a duplicated sql alias [" + alias +
|
||||||
|
"] during auto-discovery of a native-sql query"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void validateAlias(String alias) {
|
||||||
|
}
|
||||||
|
|
||||||
private static class Metadata {
|
private static class Metadata {
|
||||||
private final SessionFactoryImplementor factory;
|
private final SessionFactoryImplementor factory;
|
||||||
private final ResultSet resultSet;
|
private final ResultSet resultSet;
|
||||||
|
|
|
@ -134,11 +134,12 @@ public interface ProcedureCall extends BasicQueryContract, SynchronizeableQuery
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves access to outputs of this procedure call. Can be called multiple times, returning the same
|
* Retrieves access to outputs of this procedure call. Can be called multiple times, returning the same
|
||||||
* Output instance each time.
|
* ProcedureResult instance each time.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Note that the procedure will not actually be executed until the outputs are actually accessed.
|
* If the procedure call has not actually be executed yet, it will be executed and then the ProcedureResult
|
||||||
|
* will be returned.
|
||||||
*
|
*
|
||||||
* @return The outputs representation
|
* @return The ProcedureResult representation
|
||||||
*/
|
*/
|
||||||
public ProcedureResult getResult();
|
public ProcedureResult getResult();
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ import org.hibernate.Session;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a "memento" of a ProcedureCall
|
* Represents a "memento" (disconnected, externalizable form) of a ProcedureCall
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -385,6 +385,11 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
||||||
// for now assume there are no resultClasses nor mappings defined..
|
// for now assume there are no resultClasses nor mappings defined..
|
||||||
// TOTAL PROOF-OF-CONCEPT!!!!!!
|
// TOTAL PROOF-OF-CONCEPT!!!!!!
|
||||||
|
|
||||||
|
// todo : how to identify calls which should be in the form `{? = call procName...}` ??? (note leading param marker)
|
||||||
|
// more than likely this will need to be a method on the native API. I can see this as a trigger to
|
||||||
|
// both: (1) add the `? = ` part and also (2) register a REFCURSOR parameter for DBs (Oracle, PGSQL) that
|
||||||
|
// need it.
|
||||||
|
|
||||||
final StringBuilder buffer = new StringBuilder().append( "{call " )
|
final StringBuilder buffer = new StringBuilder().append( "{call " )
|
||||||
.append( procedureName )
|
.append( procedureName )
|
||||||
.append( "(" );
|
.append( "(" );
|
||||||
|
|
|
@ -25,9 +25,7 @@ package org.hibernate.procedure.internal;
|
||||||
|
|
||||||
import java.sql.CallableStatement;
|
import java.sql.CallableStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
import org.hibernate.JDBCException;
|
|
||||||
import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport;
|
import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport;
|
||||||
import org.hibernate.procedure.ParameterRegistration;
|
import org.hibernate.procedure.ParameterRegistration;
|
||||||
import org.hibernate.procedure.ProcedureResult;
|
import org.hibernate.procedure.ProcedureResult;
|
||||||
|
@ -70,19 +68,25 @@ public class ProcedureResultImpl extends ResultImpl implements ProcedureResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected CurrentReturnDescriptor buildCurrentReturnDescriptor(boolean isResultSet, int updateCount) {
|
protected CurrentReturnState buildCurrentReturnDescriptor(boolean isResultSet, int updateCount) {
|
||||||
return new ProcedureCurrentReturnDescriptor( isResultSet, updateCount, refCursorParamIndex );
|
return new ProcedureCurrentReturnState( isResultSet, updateCount, refCursorParamIndex );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean hasMoreReturns(CurrentReturnDescriptor descriptor) {
|
protected boolean hasMoreReturns(CurrentReturnState descriptor) {
|
||||||
return super.hasMoreReturns( descriptor )
|
return super.hasMoreReturns( descriptor )
|
||||||
|| ( (ProcedureCurrentReturnDescriptor) descriptor ).refCursorParamIndex < refCursorParameters.length;
|
|| ( (ProcedureCurrentReturnState) descriptor ).refCursorParamIndex < refCursorParameters.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Return buildExtendedReturn(CurrentReturnDescriptor returnDescriptor) {
|
protected boolean hasExtendedReturns(CurrentReturnState currentReturnState) {
|
||||||
|
return ProcedureCurrentReturnState.class.isInstance( currentReturnState )
|
||||||
|
&& ( (ProcedureCurrentReturnState) currentReturnState ).refCursorParamIndex < refCursorParameters.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Return buildExtendedReturn(CurrentReturnState returnDescriptor) {
|
||||||
this.refCursorParamIndex++;
|
this.refCursorParamIndex++;
|
||||||
final int refCursorParamIndex = ( (ProcedureCurrentReturnDescriptor) returnDescriptor ).refCursorParamIndex;
|
final int refCursorParamIndex = ( (ProcedureCurrentReturnState) returnDescriptor ).refCursorParamIndex;
|
||||||
final ParameterRegistrationImplementor refCursorParam = refCursorParameters[refCursorParamIndex];
|
final ParameterRegistrationImplementor refCursorParam = refCursorParameters[refCursorParamIndex];
|
||||||
ResultSet resultSet;
|
ResultSet resultSet;
|
||||||
if ( refCursorParam.getName() != null ) {
|
if ( refCursorParam.getName() != null ) {
|
||||||
|
@ -95,21 +99,13 @@ public class ProcedureResultImpl extends ResultImpl implements ProcedureResult {
|
||||||
.getService( RefCursorSupport.class )
|
.getService( RefCursorSupport.class )
|
||||||
.getResultSet( callableStatement, refCursorParam.getPosition() );
|
.getResultSet( callableStatement, refCursorParam.getPosition() );
|
||||||
}
|
}
|
||||||
return new ResultSetReturn( this, resultSet );
|
return new ResultSetReturnImpl( extractResults( resultSet ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JDBCException convert(SQLException e, String message) {
|
protected class ProcedureCurrentReturnState extends CurrentReturnState {
|
||||||
return procedureCall.getSession().getFactory().getSQLExceptionHelper().convert(
|
|
||||||
e,
|
|
||||||
message,
|
|
||||||
procedureCall.getProcedureName()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static class ProcedureCurrentReturnDescriptor extends CurrentReturnDescriptor {
|
|
||||||
private final int refCursorParamIndex;
|
private final int refCursorParamIndex;
|
||||||
|
|
||||||
private ProcedureCurrentReturnDescriptor(boolean isResultSet, int updateCount, int refCursorParamIndex) {
|
private ProcedureCurrentReturnState(boolean isResultSet, int updateCount, int refCursorParamIndex) {
|
||||||
super( isResultSet, updateCount );
|
super( isResultSet, updateCount );
|
||||||
this.refCursorParamIndex = refCursorParamIndex;
|
this.refCursorParamIndex = refCursorParamIndex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,4 +32,8 @@ public class NoMoreReturnsException extends HibernateException {
|
||||||
public NoMoreReturnsException(String message) {
|
public NoMoreReturnsException(String message) {
|
||||||
super( message );
|
super( message );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NoMoreReturnsException() {
|
||||||
|
super( "Results have been exhausted" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,13 @@ package org.hibernate.result;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface Result {
|
public interface Result {
|
||||||
|
/**
|
||||||
|
* Retrieve the current return.
|
||||||
|
*
|
||||||
|
* @return The current return.
|
||||||
|
*/
|
||||||
|
public Return getCurrentReturn();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Are there any more returns associated with this result?
|
* Are there any more returns associated with this result?
|
||||||
*
|
*
|
||||||
|
@ -42,9 +49,12 @@ public interface Result {
|
||||||
public boolean hasMoreReturns();
|
public boolean hasMoreReturns();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the next return.
|
* Retrieve the next return
|
||||||
*
|
*
|
||||||
* @return The next return.
|
* @return The next return.
|
||||||
|
*
|
||||||
|
* @throws NoMoreReturnsException Thrown if there are no more returns associated with this Result, as would
|
||||||
|
* have been indicated by a {@code false} return from {@link #hasMoreReturns()}.
|
||||||
*/
|
*/
|
||||||
public Return getNextReturn() throws NoMoreReturnsException;
|
public Return getNextReturn() throws NoMoreReturnsException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,9 @@ import org.hibernate.loader.custom.sql.SQLQueryReturnProcessor;
|
||||||
import org.hibernate.loader.spi.AfterLoadAction;
|
import org.hibernate.loader.spi.AfterLoadAction;
|
||||||
import org.hibernate.result.NoMoreReturnsException;
|
import org.hibernate.result.NoMoreReturnsException;
|
||||||
import org.hibernate.result.Result;
|
import org.hibernate.result.Result;
|
||||||
|
import org.hibernate.result.ResultSetReturn;
|
||||||
import org.hibernate.result.Return;
|
import org.hibernate.result.Return;
|
||||||
|
import org.hibernate.result.UpdateCountReturn;
|
||||||
import org.hibernate.result.spi.ResultContext;
|
import org.hibernate.result.spi.ResultContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,102 +53,101 @@ public class ResultImpl implements Result {
|
||||||
private final PreparedStatement jdbcStatement;
|
private final PreparedStatement jdbcStatement;
|
||||||
private final CustomLoaderExtension loader;
|
private final CustomLoaderExtension loader;
|
||||||
|
|
||||||
private CurrentReturnDescriptor currentReturnDescriptor;
|
private CurrentReturnState currentReturnState;
|
||||||
|
|
||||||
private boolean executed = false;
|
|
||||||
|
|
||||||
public ResultImpl(ResultContext context, PreparedStatement jdbcStatement) {
|
public ResultImpl(ResultContext context, PreparedStatement jdbcStatement) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.jdbcStatement = jdbcStatement;
|
this.jdbcStatement = jdbcStatement;
|
||||||
|
|
||||||
// For now...
|
// For now... but see the LoadPlan work; eventually this should just be a ResultSetProcessor.
|
||||||
this.loader = buildSpecializedCustomLoader( context );
|
this.loader = buildSpecializedCustomLoader( context );
|
||||||
|
|
||||||
|
try {
|
||||||
|
final boolean isResultSet = jdbcStatement.execute();
|
||||||
|
currentReturnState = buildCurrentReturnDescriptor( isResultSet );
|
||||||
|
}
|
||||||
|
catch (SQLException e) {
|
||||||
|
throw convert( e, "Error calling CallableStatement.getMoreResults" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CurrentReturnState buildCurrentReturnDescriptor(boolean isResultSet) {
|
||||||
|
int updateCount = -1;
|
||||||
|
if ( ! isResultSet ) {
|
||||||
|
try {
|
||||||
|
updateCount = jdbcStatement.getUpdateCount();
|
||||||
|
}
|
||||||
|
catch (SQLException e) {
|
||||||
|
throw convert( e, "Error calling CallableStatement.getUpdateCount" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildCurrentReturnDescriptor( isResultSet, updateCount );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CurrentReturnState buildCurrentReturnDescriptor(boolean isResultSet, int updateCount) {
|
||||||
|
return new CurrentReturnState( isResultSet, updateCount );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Return getCurrentReturn() {
|
||||||
|
if ( currentReturnState == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return currentReturnState.getReturn();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasMoreReturns() {
|
public boolean hasMoreReturns() {
|
||||||
if ( currentReturnDescriptor == null ) {
|
// prepare the next return state
|
||||||
final boolean isResultSet;
|
try {
|
||||||
|
final boolean isResultSet = jdbcStatement.getMoreResults();
|
||||||
if ( executed ) {
|
currentReturnState = buildCurrentReturnDescriptor( isResultSet );
|
||||||
try {
|
}
|
||||||
isResultSet = jdbcStatement.getMoreResults();
|
catch (SQLException e) {
|
||||||
}
|
throw convert( e, "Error calling CallableStatement.getMoreResults" );
|
||||||
catch (SQLException e) {
|
|
||||||
throw convert( e, "Error calling CallableStatement.getMoreResults" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
isResultSet = jdbcStatement.execute();
|
|
||||||
}
|
|
||||||
catch (SQLException e) {
|
|
||||||
throw convert( e, "Error calling CallableStatement.execute" );
|
|
||||||
}
|
|
||||||
executed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int updateCount = -1;
|
|
||||||
if ( ! isResultSet ) {
|
|
||||||
try {
|
|
||||||
updateCount = jdbcStatement.getUpdateCount();
|
|
||||||
}
|
|
||||||
catch (SQLException e) {
|
|
||||||
throw convert( e, "Error calling CallableStatement.getUpdateCount" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentReturnDescriptor = buildCurrentReturnDescriptor( isResultSet, updateCount );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasMoreReturns( currentReturnDescriptor );
|
return hasMoreReturns( currentReturnState );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CurrentReturnDescriptor buildCurrentReturnDescriptor(boolean isResultSet, int updateCount) {
|
protected boolean hasMoreReturns(CurrentReturnState descriptor) {
|
||||||
return new CurrentReturnDescriptor( isResultSet, updateCount );
|
return descriptor != null && ( descriptor.isResultSet() || descriptor.getUpdateCount() >= 0 );
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean hasMoreReturns(CurrentReturnDescriptor descriptor) {
|
|
||||||
return descriptor.isResultSet
|
|
||||||
|| descriptor.updateCount >= 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Return getNextReturn() {
|
public Return getNextReturn() {
|
||||||
if ( currentReturnDescriptor == null ) {
|
if ( !hasMoreReturns() ) {
|
||||||
if ( executed ) {
|
|
||||||
throw new IllegalStateException( "Unexpected condition" );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalStateException( "hasMoreReturns() not called before getNextReturn()" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! hasMoreReturns( currentReturnDescriptor ) ) {
|
|
||||||
throw new NoMoreReturnsException( "Results have been exhausted" );
|
throw new NoMoreReturnsException( "Results have been exhausted" );
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentReturnDescriptor copyReturnDescriptor = currentReturnDescriptor;
|
return getCurrentReturn();
|
||||||
currentReturnDescriptor = null;
|
}
|
||||||
|
|
||||||
if ( copyReturnDescriptor.isResultSet ) {
|
protected boolean hasExtendedReturns(CurrentReturnState currentReturnState) {
|
||||||
try {
|
return false;
|
||||||
return new ResultSetReturn( this, jdbcStatement.getResultSet() );
|
}
|
||||||
}
|
|
||||||
catch (SQLException e) {
|
private List extractCurrentResults() {
|
||||||
throw convert( e, "Error calling CallableStatement.getResultSet" );
|
try {
|
||||||
}
|
return extractResults( jdbcStatement.getResultSet() );
|
||||||
}
|
}
|
||||||
else if ( copyReturnDescriptor.updateCount >= 0 ) {
|
catch (SQLException e) {
|
||||||
return new UpdateCountReturn( this, copyReturnDescriptor.updateCount );
|
throw convert( e, "Error calling CallableStatement.getResultSet" );
|
||||||
}
|
|
||||||
else {
|
|
||||||
return buildExtendedReturn( copyReturnDescriptor );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Return buildExtendedReturn(CurrentReturnDescriptor copyReturnDescriptor) {
|
protected List extractResults(ResultSet resultSet) {
|
||||||
throw new NoMoreReturnsException( "Results have been exhausted" );
|
try {
|
||||||
|
return loader.processResultSet( resultSet );
|
||||||
|
}
|
||||||
|
catch (SQLException e) {
|
||||||
|
throw convert( e, "Error extracting results from CallableStatement" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Return buildExtendedReturn(CurrentReturnState copyReturnDescriptor) {
|
||||||
|
throw new NoMoreReturnsException();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JDBCException convert(SQLException e, String message) {
|
protected JDBCException convert(SQLException e, String message) {
|
||||||
|
@ -157,23 +158,55 @@ public class ResultImpl implements Result {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class CurrentReturnDescriptor {
|
/**
|
||||||
|
* Encapsulates the information needed to interpret the current return within a result
|
||||||
|
*/
|
||||||
|
protected class CurrentReturnState {
|
||||||
private final boolean isResultSet;
|
private final boolean isResultSet;
|
||||||
private final int updateCount;
|
private final int updateCount;
|
||||||
|
|
||||||
protected CurrentReturnDescriptor(boolean isResultSet, int updateCount) {
|
private Return rtn;
|
||||||
|
|
||||||
|
protected CurrentReturnState(boolean isResultSet, int updateCount) {
|
||||||
this.isResultSet = isResultSet;
|
this.isResultSet = isResultSet;
|
||||||
this.updateCount = updateCount;
|
this.updateCount = updateCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isResultSet() {
|
||||||
|
return isResultSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUpdateCount() {
|
||||||
|
return updateCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Return getReturn() {
|
||||||
|
if ( rtn == null ) {
|
||||||
|
rtn = buildReturn();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Return buildReturn() {
|
||||||
|
if ( isResultSet() ) {
|
||||||
|
return new ResultSetReturnImpl( extractCurrentResults() );
|
||||||
|
}
|
||||||
|
else if ( getUpdateCount() >= 0 ) {
|
||||||
|
return new UpdateCountReturnImpl( updateCount );
|
||||||
|
}
|
||||||
|
else if ( hasExtendedReturns( currentReturnState ) ) {
|
||||||
|
return buildExtendedReturn( currentReturnState );
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NoMoreReturnsException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class ResultSetReturn implements org.hibernate.result.ResultSetReturn {
|
protected static class ResultSetReturnImpl implements ResultSetReturn {
|
||||||
private final ResultImpl storedProcedureOutputs;
|
private final List results;
|
||||||
private final ResultSet resultSet;
|
|
||||||
|
|
||||||
public ResultSetReturn(ResultImpl storedProcedureOutputs, ResultSet resultSet) {
|
public ResultSetReturnImpl(List results) {
|
||||||
this.storedProcedureOutputs = storedProcedureOutputs;
|
this.results = results;
|
||||||
this.resultSet = resultSet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -184,17 +217,12 @@ public class ResultImpl implements Result {
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public List getResultList() {
|
public List getResultList() {
|
||||||
try {
|
return results;
|
||||||
return storedProcedureOutputs.loader.processResultSet( resultSet );
|
|
||||||
}
|
|
||||||
catch (SQLException e) {
|
|
||||||
throw storedProcedureOutputs.convert( e, "Error calling ResultSet.next" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getSingleResult() {
|
public Object getSingleResult() {
|
||||||
List results = getResultList();
|
final List results = getResultList();
|
||||||
if ( results == null || results.isEmpty() ) {
|
if ( results == null || results.isEmpty() ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -204,12 +232,10 @@ public class ResultImpl implements Result {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class UpdateCountReturn implements org.hibernate.result.UpdateCountReturn {
|
protected static class UpdateCountReturnImpl implements UpdateCountReturn {
|
||||||
private final ResultImpl result;
|
|
||||||
private final int updateCount;
|
private final int updateCount;
|
||||||
|
|
||||||
public UpdateCountReturn(ResultImpl result, int updateCount) {
|
public UpdateCountReturnImpl(int updateCount) {
|
||||||
this.result = result;
|
|
||||||
this.updateCount = updateCount;
|
this.updateCount = updateCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,6 +292,9 @@ public class ResultImpl implements Result {
|
||||||
private QueryParameters queryParameters;
|
private QueryParameters queryParameters;
|
||||||
private SessionImplementor session;
|
private SessionImplementor session;
|
||||||
|
|
||||||
|
// temp
|
||||||
|
private final CustomQuery customQuery;
|
||||||
|
|
||||||
public CustomLoaderExtension(
|
public CustomLoaderExtension(
|
||||||
CustomQuery customQuery,
|
CustomQuery customQuery,
|
||||||
QueryParameters queryParameters,
|
QueryParameters queryParameters,
|
||||||
|
@ -273,6 +302,8 @@ public class ResultImpl implements Result {
|
||||||
super( customQuery, session.getFactory() );
|
super( customQuery, session.getFactory() );
|
||||||
this.queryParameters = queryParameters;
|
this.queryParameters = queryParameters;
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
|
||||||
|
this.customQuery = customQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo : this would be a great way to add locking to stored procedure support (at least where returning entities).
|
// todo : this would be a great way to add locking to stored procedure support (at least where returning entities).
|
||||||
|
@ -289,5 +320,12 @@ public class ResultImpl implements Result {
|
||||||
Collections.<AfterLoadAction>emptyList()
|
Collections.<AfterLoadAction>emptyList()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void validateAlias(String alias) {
|
||||||
|
System.out.println(
|
||||||
|
"TEMPORARY... discovered result set alias from stored procedure [" + alias + "] : " + customQuery.getSQL()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ import org.hibernate.testing.RequiresDialect;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
import org.hibernate.testing.junit4.ExtraAssertions;
|
import org.hibernate.testing.junit4.ExtraAssertions;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||||
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;
|
||||||
|
@ -171,11 +172,9 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
ProcedureCall query = session.createStoredProcedureCall( "user");
|
ProcedureCall query = session.createStoredProcedureCall( "user");
|
||||||
ProcedureResult procedureResult = query.getResult();
|
ProcedureResult procedureResult = query.getResult();
|
||||||
assertTrue( "Checking ProcedureResult has more returns", procedureResult.hasMoreReturns() );
|
Return currentReturn = procedureResult.getCurrentReturn();
|
||||||
Return nextReturn = procedureResult.getNextReturn();
|
assertNotNull( currentReturn );
|
||||||
assertNotNull( nextReturn );
|
ResultSetReturn resultSetReturn = assertTyping( ResultSetReturn.class, currentReturn );
|
||||||
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
|
||||||
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
|
||||||
String name = (String) resultSetReturn.getSingleResult();
|
String name = (String) resultSetReturn.getSingleResult();
|
||||||
assertEquals( "SA", name );
|
assertEquals( "SA", name );
|
||||||
|
|
||||||
|
@ -190,13 +189,11 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
ProcedureCall query = session.createStoredProcedureCall( "findOneUser" );
|
ProcedureCall query = session.createStoredProcedureCall( "findOneUser" );
|
||||||
ProcedureResult procedureResult = query.getResult();
|
ProcedureResult procedureResult = query.getResult();
|
||||||
assertTrue( "Checking ProcedureResult has more returns", procedureResult.hasMoreReturns() );
|
Return currentReturn = procedureResult.getCurrentReturn();
|
||||||
Return nextReturn = procedureResult.getNextReturn();
|
assertNotNull( currentReturn );
|
||||||
assertNotNull( nextReturn );
|
ResultSetReturn resultSetReturn = assertTyping( ResultSetReturn.class, currentReturn );
|
||||||
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
|
||||||
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
|
||||||
Object result = resultSetReturn.getSingleResult();
|
Object result = resultSetReturn.getSingleResult();
|
||||||
ExtraAssertions.assertTyping( Object[].class, result );
|
assertTyping( Object[].class, result );
|
||||||
String name = (String) ( (Object[]) result )[1];
|
String name = (String) ( (Object[]) result )[1];
|
||||||
assertEquals( "Steve", name );
|
assertEquals( "Steve", name );
|
||||||
|
|
||||||
|
@ -211,16 +208,14 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
ProcedureCall query = session.createStoredProcedureCall( "findUsers" );
|
ProcedureCall query = session.createStoredProcedureCall( "findUsers" );
|
||||||
ProcedureResult procedureResult = query.getResult();
|
ProcedureResult procedureResult = query.getResult();
|
||||||
assertTrue( "Checking ProcedureResult has more returns", procedureResult.hasMoreReturns() );
|
Return currentReturn = procedureResult.getCurrentReturn();
|
||||||
Return nextReturn = procedureResult.getNextReturn();
|
assertNotNull( currentReturn );
|
||||||
assertNotNull( nextReturn );
|
ResultSetReturn resultSetReturn = assertTyping( ResultSetReturn.class, currentReturn );
|
||||||
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
|
||||||
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
|
||||||
List results = resultSetReturn.getResultList();
|
List results = resultSetReturn.getResultList();
|
||||||
assertEquals( 3, results.size() );
|
assertEquals( 3, results.size() );
|
||||||
|
|
||||||
for ( Object result : results ) {
|
for ( Object result : results ) {
|
||||||
ExtraAssertions.assertTyping( Object[].class, result );
|
assertTyping( Object[].class, result );
|
||||||
Integer id = (Integer) ( (Object[]) result )[0];
|
Integer id = (Integer) ( (Object[]) result )[0];
|
||||||
String name = (String) ( (Object[]) result )[1];
|
String name = (String) ( (Object[]) result )[1];
|
||||||
if ( id.equals( 1 ) ) {
|
if ( id.equals( 1 ) ) {
|
||||||
|
@ -250,15 +245,13 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
||||||
query.registerParameter( "start", Integer.class, ParameterMode.IN ).bindValue( 1 );
|
query.registerParameter( "start", Integer.class, ParameterMode.IN ).bindValue( 1 );
|
||||||
query.registerParameter( "end", Integer.class, ParameterMode.IN ).bindValue( 2 );
|
query.registerParameter( "end", Integer.class, ParameterMode.IN ).bindValue( 2 );
|
||||||
ProcedureResult procedureResult = query.getResult();
|
ProcedureResult procedureResult = query.getResult();
|
||||||
assertTrue( "Checking ProcedureResult has more returns", procedureResult.hasMoreReturns() );
|
Return currentReturn = procedureResult.getCurrentReturn();
|
||||||
Return nextReturn = procedureResult.getNextReturn();
|
assertNotNull( currentReturn );
|
||||||
assertNotNull( nextReturn );
|
ResultSetReturn resultSetReturn = assertTyping( ResultSetReturn.class, currentReturn );
|
||||||
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
|
||||||
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
|
||||||
List results = resultSetReturn.getResultList();
|
List results = resultSetReturn.getResultList();
|
||||||
assertEquals( 1, results.size() );
|
assertEquals( 1, results.size() );
|
||||||
Object result = results.get( 0 );
|
Object result = results.get( 0 );
|
||||||
ExtraAssertions.assertTyping( Object[].class, result );
|
assertTyping( Object[].class, result );
|
||||||
Integer id = (Integer) ( (Object[]) result )[0];
|
Integer id = (Integer) ( (Object[]) result )[0];
|
||||||
String name = (String) ( (Object[]) result )[1];
|
String name = (String) ( (Object[]) result )[1];
|
||||||
assertEquals( 1, (int) id );
|
assertEquals( 1, (int) id );
|
||||||
|
@ -277,15 +270,13 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
||||||
query.registerParameter( 1, Integer.class, ParameterMode.IN ).bindValue( 1 );
|
query.registerParameter( 1, Integer.class, ParameterMode.IN ).bindValue( 1 );
|
||||||
query.registerParameter( 2, Integer.class, ParameterMode.IN ).bindValue( 2 );
|
query.registerParameter( 2, Integer.class, ParameterMode.IN ).bindValue( 2 );
|
||||||
ProcedureResult procedureResult = query.getResult();
|
ProcedureResult procedureResult = query.getResult();
|
||||||
assertTrue( "Checking ProcedureResult has more returns", procedureResult.hasMoreReturns() );
|
Return currentReturn = procedureResult.getCurrentReturn();
|
||||||
Return nextReturn = procedureResult.getNextReturn();
|
assertNotNull( currentReturn );
|
||||||
assertNotNull( nextReturn );
|
ResultSetReturn resultSetReturn = assertTyping( ResultSetReturn.class, currentReturn );
|
||||||
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
|
||||||
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
|
||||||
List results = resultSetReturn.getResultList();
|
List results = resultSetReturn.getResultList();
|
||||||
assertEquals( 1, results.size() );
|
assertEquals( 1, results.size() );
|
||||||
Object result = results.get( 0 );
|
Object result = results.get( 0 );
|
||||||
ExtraAssertions.assertTyping( Object[].class, result );
|
assertTyping( Object[].class, result );
|
||||||
Integer id = (Integer) ( (Object[]) result )[0];
|
Integer id = (Integer) ( (Object[]) result )[0];
|
||||||
String name = (String) ( (Object[]) result )[1];
|
String name = (String) ( (Object[]) result )[1];
|
||||||
assertEquals( 1, (int) id );
|
assertEquals( 1, (int) id );
|
||||||
|
@ -307,9 +298,8 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
||||||
ProcedureCall query = session.createStoredProcedureCall( "findUserRange" );
|
ProcedureCall query = session.createStoredProcedureCall( "findUserRange" );
|
||||||
query.registerParameter( 1, Integer.class, ParameterMode.IN );
|
query.registerParameter( 1, Integer.class, ParameterMode.IN );
|
||||||
query.registerParameter( 2, Integer.class, ParameterMode.IN ).bindValue( 2 );
|
query.registerParameter( 2, Integer.class, ParameterMode.IN ).bindValue( 2 );
|
||||||
ProcedureResult procedureResult = query.getResult();
|
|
||||||
try {
|
try {
|
||||||
procedureResult.hasMoreReturns();
|
query.getResult();
|
||||||
fail( "Expecting failure due to missing parameter bind" );
|
fail( "Expecting failure due to missing parameter bind" );
|
||||||
}
|
}
|
||||||
catch (JDBCException expected) {
|
catch (JDBCException expected) {
|
||||||
|
@ -320,9 +310,8 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
||||||
ProcedureCall query = session.createStoredProcedureCall( "findUserRange" );
|
ProcedureCall query = session.createStoredProcedureCall( "findUserRange" );
|
||||||
query.registerParameter( "start", Integer.class, ParameterMode.IN );
|
query.registerParameter( "start", Integer.class, ParameterMode.IN );
|
||||||
query.registerParameter( "end", Integer.class, ParameterMode.IN ).bindValue( 2 );
|
query.registerParameter( "end", Integer.class, ParameterMode.IN ).bindValue( 2 );
|
||||||
ProcedureResult procedureResult = query.getResult();
|
|
||||||
try {
|
try {
|
||||||
procedureResult.hasMoreReturns();
|
query.getResult();
|
||||||
fail( "Expecting failure due to missing parameter bind" );
|
fail( "Expecting failure due to missing parameter bind" );
|
||||||
}
|
}
|
||||||
catch (JDBCException expected) {
|
catch (JDBCException expected) {
|
||||||
|
|
|
@ -25,8 +25,11 @@ package org.hibernate.jpa.internal;
|
||||||
|
|
||||||
import javax.persistence.FlushModeType;
|
import javax.persistence.FlushModeType;
|
||||||
import javax.persistence.LockModeType;
|
import javax.persistence.LockModeType;
|
||||||
|
import javax.persistence.NoResultException;
|
||||||
|
import javax.persistence.NonUniqueResultException;
|
||||||
import javax.persistence.Parameter;
|
import javax.persistence.Parameter;
|
||||||
import javax.persistence.ParameterMode;
|
import javax.persistence.ParameterMode;
|
||||||
|
import javax.persistence.PersistenceException;
|
||||||
import javax.persistence.Query;
|
import javax.persistence.Query;
|
||||||
import javax.persistence.StoredProcedureQuery;
|
import javax.persistence.StoredProcedureQuery;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
|
@ -197,7 +200,8 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean execute() {
|
public boolean execute() {
|
||||||
return outputs().hasMoreReturns();
|
final Return rtn = outputs().getCurrentReturn();
|
||||||
|
return rtn != null && ResultSetReturn.class.isInstance( rtn );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -212,34 +216,76 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getUpdateCount() {
|
public int getUpdateCount() {
|
||||||
final Return nextReturn = outputs().getNextReturn();
|
final Return rtn = outputs().getCurrentReturn();
|
||||||
if ( nextReturn.isResultSet() ) {
|
if ( rtn == null ) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if ( UpdateCountReturn.class.isInstance( rtn ) ) {
|
||||||
|
return ( (UpdateCountReturn) rtn ).getUpdateCount();
|
||||||
|
}
|
||||||
|
else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return ( (UpdateCountReturn) nextReturn ).getUpdateCount();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List getResultList() {
|
public List getResultList() {
|
||||||
final Return nextReturn = outputs().getNextReturn();
|
final Return rtn = outputs().getCurrentReturn();
|
||||||
if ( ! nextReturn.isResultSet() ) {
|
if ( ! ResultSetReturn.class.isInstance( rtn ) ) {
|
||||||
return null; // todo : what should be thrown/returned here?
|
throw new IllegalStateException( "Current CallableStatement was not a ResultSet, but getResultList was called" );
|
||||||
}
|
}
|
||||||
return ( (ResultSetReturn) nextReturn ).getResultList();
|
|
||||||
|
if ( outputs().hasMoreReturns() ) {
|
||||||
|
outputs().getNextReturn();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( (ResultSetReturn) rtn ).getResultList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getSingleResult() {
|
public Object getSingleResult() {
|
||||||
final Return nextReturn = outputs().getNextReturn();
|
final List resultList = getResultList();
|
||||||
if ( ! nextReturn.isResultSet() ) {
|
if ( resultList == null || resultList.isEmpty() ) {
|
||||||
return null; // todo : what should be thrown/returned here?
|
throw new NoResultException(
|
||||||
|
String.format(
|
||||||
|
"Call to stored procedure [%s] returned no results",
|
||||||
|
procedureCall.getProcedureName()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return ( (ResultSetReturn) nextReturn ).getSingleResult();
|
else if ( resultList.size() > 1 ) {
|
||||||
|
throw new NonUniqueResultException(
|
||||||
|
String.format(
|
||||||
|
"Call to stored procedure [%s] returned multiple results",
|
||||||
|
procedureCall.getProcedureName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultList.get( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T unwrap(Class<T> cls) {
|
public <T> T unwrap(Class<T> cls) {
|
||||||
return null;
|
if ( ProcedureCall.class.isAssignableFrom( cls ) ) {
|
||||||
|
return (T) procedureCall;
|
||||||
|
}
|
||||||
|
else if ( ProcedureResult.class.isAssignableFrom( cls ) ) {
|
||||||
|
return (T) outputs();
|
||||||
|
}
|
||||||
|
else if ( BaseQueryImpl.class.isAssignableFrom( cls ) ) {
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new PersistenceException(
|
||||||
|
String.format(
|
||||||
|
"Unsure how to unwrap %s impl [%s] as requested type [%s]",
|
||||||
|
StoredProcedureQuery.class.getSimpleName(),
|
||||||
|
this.getClass().getName(),
|
||||||
|
cls.getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -44,31 +44,43 @@ import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests various JPA usage scenarios for performing stored procedures.
|
* Tests various JPA usage scenarios for performing stored procedures. Inspired by the awesomely well-done JPA TCK
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
@RequiresDialect( H2Dialect.class )
|
@RequiresDialect( H2Dialect.class )
|
||||||
@FailureExpected( jiraKey = "HHH-8389", message = "Waiting clarification from EG" )
|
|
||||||
public class JpaUsageTest extends BaseEntityManagerFunctionalTestCase {
|
public class JpaUsageTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
/**
|
|
||||||
* Some tests inspired by the awesomely well-done JPA TCK
|
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
public void testJpaUsage1() {
|
public void testMultipleGetUpdateCountCalls() {
|
||||||
EntityManager em = getOrCreateEntityManager();
|
EntityManager em = getOrCreateEntityManager();
|
||||||
em.getTransaction().begin();
|
em.getTransaction().begin();
|
||||||
|
|
||||||
StoredProcedureQuery query = em.createStoredProcedureQuery( "findOneUser", User.class );
|
StoredProcedureQuery query = em.createStoredProcedureQuery( "findOneUser" );
|
||||||
// this is what the TCK attempts to do, don't shoot the messenger...
|
// this is what the TCK attempts to do, don't shoot the messenger...
|
||||||
query.getUpdateCount();
|
query.getUpdateCount();
|
||||||
// yep, twice
|
// yep, twice
|
||||||
int updateCount = query.getUpdateCount();
|
int updateCount = query.getUpdateCount();
|
||||||
|
|
||||||
|
em.getTransaction().commit();
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicScalarResults() {
|
||||||
|
EntityManager em = getOrCreateEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
|
||||||
|
StoredProcedureQuery query = em.createStoredProcedureQuery( "findOneUser" );
|
||||||
|
boolean isResult = query.execute();
|
||||||
|
assertTrue( isResult );
|
||||||
|
int updateCount = query.getUpdateCount();
|
||||||
|
|
||||||
boolean results = false;
|
boolean results = false;
|
||||||
do {
|
do {
|
||||||
List list = query.getResultList();
|
List list = query.getResultList();
|
||||||
|
assertEquals( 1, list.size() );
|
||||||
|
|
||||||
results = query.hasMoreResults();
|
results = query.hasMoreResults();
|
||||||
// and it only sets the updateCount once lol
|
// and it only sets the updateCount once lol
|
||||||
} while ( results || updateCount != -1);
|
} while ( results || updateCount != -1);
|
||||||
|
@ -78,15 +90,15 @@ public class JpaUsageTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testJpaUsage2() {
|
@FailureExpected( jiraKey = "HHH-8398" )
|
||||||
|
public void testResultClassHandling() {
|
||||||
EntityManager em = getOrCreateEntityManager();
|
EntityManager em = getOrCreateEntityManager();
|
||||||
em.getTransaction().begin();
|
em.getTransaction().begin();
|
||||||
|
|
||||||
StoredProcedureQuery query = em.createStoredProcedureQuery( "findOneUser", User.class );
|
StoredProcedureQuery query = em.createStoredProcedureQuery( "findOneUser", User.class );
|
||||||
boolean isResult = query.execute();
|
boolean isResult = query.execute();
|
||||||
assertTrue( isResult );
|
assertTrue( isResult );
|
||||||
// int updateCount = query.getUpdateCount();
|
int updateCount = query.getUpdateCount();
|
||||||
int updateCount = -1;
|
|
||||||
|
|
||||||
boolean results = false;
|
boolean results = false;
|
||||||
do {
|
do {
|
||||||
|
@ -122,7 +134,7 @@ public class JpaUsageTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
" return rs;\n" +
|
" return rs;\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
"$$";
|
"$$";
|
||||||
public static final String DROP_CMD = "DROP ALIAS findUser IF EXISTS";
|
public static final String DROP_CMD = "DROP ALIAS findOneUser IF EXISTS";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void afterEntityManagerFactoryBuilt() {
|
protected void afterEntityManagerFactoryBuilt() {
|
||||||
|
@ -130,6 +142,7 @@ public class JpaUsageTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void execute(String sql) {
|
private void execute(String sql) {
|
||||||
|
System.out.println( "Executing SQL : " + sql );
|
||||||
final SessionFactoryImplementor sf = entityManagerFactory().unwrap( SessionFactoryImplementor.class );
|
final SessionFactoryImplementor sf = entityManagerFactory().unwrap( SessionFactoryImplementor.class );
|
||||||
final Connection conn;
|
final Connection conn;
|
||||||
try {
|
try {
|
||||||
|
@ -153,14 +166,13 @@ public class JpaUsageTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (SQLException e) {
|
catch (SQLException e) {
|
||||||
throw new RuntimeException( "Unable to execute SQL : " + sql );
|
throw new RuntimeException( "Unable to execute SQL : " + sql, e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void releaseResources() {
|
public void releaseResources() {
|
||||||
execute( DROP_CMD );
|
execute( DROP_CMD );
|
||||||
|
|
||||||
super.releaseResources();
|
super.releaseResources();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue