HHH-8022 - Reading REF CURSOR

This commit is contained in:
Lukasz Antoniak 2013-03-05 23:13:41 +01:00 committed by Brett Meyer
parent 9edc30f9f0
commit c69fde0c6d
4 changed files with 185 additions and 1 deletions

View File

@ -44,6 +44,11 @@ public class ResultSetReturnImpl implements ResultSetReturn {
@Override
public ResultSet extract(PreparedStatement statement) {
// sql logged by StatementPreparerImpl
if ( statement instanceof CallableStatement ) {
// we actually need to extract from callable statement
CallableStatement callableStatement = (CallableStatement) statement;
return extract( callableStatement );
}
try {
ResultSet rs = statement.executeQuery();
postExtract( rs );

View File

@ -40,7 +40,8 @@ import java.sql.Statement;
public interface ResultSetReturn {
/**
* Extract the ResultSet from the statement.
* Extract the ResultSet from the statement. If user passes {@link CallableStatement}
* reference, method calls {@link #extract(CallableStatement)} internally.
*
* @param statement
*

View File

@ -0,0 +1,103 @@
package org.hibernate.test.sql.refcursor;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.ResultSetReturn;
import org.hibernate.engine.jdbc.spi.StatementPreparer;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.jdbc.Work;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@RequiresDialect( Oracle8iDialect.class )
public class CursorFromCallableTest extends BaseCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { NumValue.class };
}
@Before
public void createRefCursorFunction() {
executeStatement( "CREATE OR REPLACE FUNCTION f_test_return_cursor RETURN SYS_REFCURSOR " +
"IS " +
" l_Cursor SYS_REFCURSOR; " +
"BEGIN " +
" OPEN l_Cursor FOR " +
" SELECT 1 AS BOT_NUM " +
" , 'Line 1' AS BOT_VALUE " +
" FROM DUAL " +
" UNION " +
" SELECT 2 AS BOT_NUM " +
" , 'Line 2' AS BOT_VALUE " +
" FROM DUAL; " +
" RETURN(l_Cursor); " +
"END f_test_return_cursor;" );
}
@After
public void dropRefCursorFunction() {
executeStatement( "DROP FUNCTION f_test_return_cursor" );
}
@Test
@TestForIssue( jiraKey = "HHH-8022" )
public void testReadResultSetFromRefCursor() {
Session session = openSession();
session.getTransaction().begin();
Assert.assertEquals(
Arrays.asList( new NumValue( 1, "Line 1" ), new NumValue( 2, "Line 2" ) ),
session.getNamedQuery( "NumValue.getSomeValues" ).list()
);
session.getTransaction().commit();
session.close();
}
private void executeStatement(final String sql) {
final Session session = openSession();
session.getTransaction().begin();
session.doWork( new Work() {
@Override
public void execute(Connection connection) throws SQLException {
final JdbcCoordinator jdbcCoordinator = ( (SessionImplementor) session ).getTransactionCoordinator().getJdbcCoordinator();
final StatementPreparer statementPreparer = jdbcCoordinator.getStatementPreparer();
final ResultSetReturn resultSetReturn = jdbcCoordinator.getResultSetReturn();
PreparedStatement preparedStatement = null;
try {
preparedStatement = statementPreparer.prepareStatement( sql );
resultSetReturn.execute( preparedStatement );
}
finally {
if ( preparedStatement != null ) {
try {
jdbcCoordinator.release( preparedStatement );
}
catch ( Throwable ignore ) {
// ignore...
}
}
}
}
} );
session.getTransaction().commit();
session.close();
}
}

View File

@ -0,0 +1,75 @@
package org.hibernate.test.sql.refcursor;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;
import javax.persistence.QueryHint;
import javax.persistence.Table;
@Entity
@Table(name = "BOT_NUMVALUE")
@NamedNativeQueries({
@NamedNativeQuery(name = "NumValue.getSomeValues",
query = "{ ? = call f_test_return_cursor() }",
resultClass = NumValue.class, hints = { @QueryHint(name = "org.hibernate.callable", value = "true") })
})
public class NumValue implements Serializable {
@Id
@Column(name = "BOT_NUM", nullable = false)
private long num;
@Column(name = "BOT_VALUE")
private String value;
public NumValue() {
}
public NumValue(long num, String value) {
this.num = num;
this.value = value;
}
@Override
public boolean equals(Object o) {
if ( this == o ) return true;
if ( !( o instanceof NumValue ) ) return false;
NumValue numValue = (NumValue) o;
if ( num != numValue.num ) return false;
if ( value != null ? !value.equals( numValue.value ) : numValue.value != null ) return false;
return true;
}
@Override
public int hashCode() {
int result = (int) ( num ^ ( num >>> 32 ) );
result = 31 * result + ( value != null ? value.hashCode() : 0 );
return result;
}
@Override
public String toString() {
return "NumValue(num = " + num + ", value = " + value + ")";
}
public long getNum() {
return num;
}
public void setNum(long num) {
this.num = num;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}