I am trying to understand how I can call a PL/SQL procedure which takes a SYS_REFCURSOR
as IN
parameter.
Consider the following PL/SQL procedure:
print_cursor_contents(myCursor SYS_REFCURSOR , row_count OUT NUMBER);
At the time of binding value to the IN parameter which setXXX
method do I use ?
To me a java Class with individual cursor record fields , as it members and a Array of instances of this class seems the proper way to represent a plsql CURSOR. I get a SQLException when I do this:
I used the following set method
callStmt.setObject(1, curRec);
Here is the exception I got for using the above statement:
Exception occured in the database
Exception message: Invalid column type
java.sql.SQLException: Invalid column type
at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8921)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8396)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:9176)
at oracle.jdbc.driver.OracleCallableStatement.setObject(OracleCallableStatement.java:5024)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:234)
at com.rolta.HrManager.printMaxSalAllDept(HrManager.java:1022)
at com.rolta.HrManager.main(HrManager.java:1116)
Database error code: 17004
I disagree.
If you have a stored function or procedure that either returns a ref cursor or has a ref cursor as an
OUT
parameter, the ref cursor comes out of JDBC as aResultSet
. So, if it were possible to call a stored procedure with aSYS_REFCURSOR
parameter, I'd suspect that aResultSet
would be what you would need to pass.In fact, my suspicions are confirmed. If you take a look at Oracle's extension to
CallableStatement
,OracleCallableStatement
, it inherits asetCursor(int, ResultSet)
method from its superinterfaceOraclePreparedStatement
. Therefore, you could cast theCallableStatement
toOracleCallableStatement
, call thesetCursor
method, and away you go.Except this approach doesn't actually work.
If you try calling
setCursor
on anOracleCallableStatement
, you will get an exceptionjava.sql.SQLException: Unsupported feature
.You can try calling
setObject
with aResultSet
, but you will only get anotherjava.sql.SQLException: Invalid column type
exception.Here's a test class you can run to verify either case. It calls one stored procedure to get a ref cursor (and hence a
ResultSet
) and then tries to pass it to the other:(The two procedures in the
java_ref_curs_test
take a singleSYS_REFCURSOR
parameter:get_ref_cursor
returns a ref cursor andprint_refcursor
takes one as a parameter but does nothing with it.)So, which
setXXX
method should you use? I would say none of them. What you are asking for is not possible directly.It may still be possible to call this procedure, but you will have to create the ref cursor in PL/SQL, not in Java, and then pass it to your procedure.
For example, I could use the following PL/SQL block to call the two procedures used in the above example:
You can fairly easily run this from JDBC: put it in a string and pass it to
Statement.executeUpdate()
.