Permalink
Browse files

feat: support fetching a REF_CURSOR using getObject

Since DatabaseMetaData#supportsRefCursors now reports true
frameworks like Hibernate now use
callableStatement.getObject(int, ResultSet.class) to fetch the
REF_CURSOR.

Only support ResultSet.class as an argument to keep the patch simple.

Closes: #794
  • Loading branch information...
marschall authored and vlsi committed Apr 8, 2017
1 parent 170d9c2 commit 4ab5ccb7a299cfcec8a5b1cddf612d3f828fa157
@@ -691,7 +691,11 @@ public Reader getCharacterStream(String parameterName) throws SQLException {
}
public <T> T getObject(int parameterIndex, Class<T> type) throws SQLException {
throw Driver.notImplemented(this.getClass(), "getObject(int, Class<T>)");
if (type == ResultSet.class) {
return type.cast(getObject(parameterIndex));
}
throw new PSQLException(GT.tr("Unsupported type conversion to {1}.", type),
PSQLState.INVALID_PARAMETER_VALUE);
}
public <T> T getObject(String parameterName, Class<T> type) throws SQLException {
@@ -0,0 +1,94 @@
/*
* Copyright (c) 2017, PostgreSQL Global Development Group
* See the LICENSE file in the project root for more information.
*/
package org.postgresql.test.jdbc42;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.postgresql.test.jdbc2.BaseTest4;
import org.junit.Test;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Tests for JDBC 4.2 features in {@link org.postgresql.jdbc.PgCallableStatement}.
*/
public class Jdbc42CallableStatementTest extends BaseTest4 {
@Override
public void setUp() throws Exception {
super.setUp();
try (Statement stmt = con.createStatement();) {
stmt.execute(
"CREATE OR REPLACE FUNCTION testspg__getResultSetWithoutArg() "
+ "RETURNS refcursor AS ' "
+ "declare ref refcursor;"
+ "begin OPEN ref FOR SELECT 1; RETURN ref; end; ' LANGUAGE plpgsql;");
}
}
final String func = "{ ? = call ";
final String pkgName = "testspg__";
@Override
public void tearDown() throws SQLException {
try (Statement stmt = con.createStatement()) {
stmt.execute("drop FUNCTION testspg__getResultSetWithoutArg ();");
}
super.tearDown();
}
@Test
public void testGetResultSetWithoutArg() throws SQLException {
assumeCallableStatementsSupported();
try (CallableStatement call = con.prepareCall(func + pkgName + "getResultSetWithoutArg () }")) {
con.setAutoCommit(false); // ref cursors only work if auto commit is off
call.registerOutParameter(1, Types.REF_CURSOR);
call.execute();
List<Integer> values = new ArrayList<>(1);
try (ResultSet rs = call.getObject(1, ResultSet.class)) {
while (rs.next()) {
values.add(rs.getInt(1));
}
}
assertEquals(Collections.singletonList(1), values);
} finally {
con.setAutoCommit(true);
}
}
@Test
public void testGetResultSetWithoutArgUnsupportedConversion() throws SQLException {
assumeCallableStatementsSupported();
try (CallableStatement call = con.prepareCall(func + pkgName + "getResultSetWithoutArg () }")) {
con.setAutoCommit(false); // ref cursors only work if auto commit is off
call.registerOutParameter(1, Types.REF_CURSOR);
call.execute();
try {
// this should never be allowed even if more types will be implemented in the future
call.getObject(1, ResultSetMetaData.class);
fail("conversion from ResultSet to ResultSetMetaData should not be supported");
} catch (SQLException e) {
// should reach
}
} finally {
con.setAutoCommit(true);
}
}
}
@@ -15,6 +15,7 @@
CustomizeDefaultFetchSizeTest.class,
GetObject310Test.class,
PreparedStatementTest.class,
Jdbc42CallableStatementTest.class,
GetObject310BinaryTest.class,
SetObject310Test.class})
public class Jdbc42TestSuite {

0 comments on commit 4ab5ccb

Please sign in to comment.