In a recent project i need to write a very complex query that,depending on input parameters, have to compose itself. SELECT, FROM, WHERE and ORDER BY clauses were all builded dinamically. For this reason i chose to write a Stored Procedure that achieved this goal.
This one,basically, build the query choosing between a lot of conditions given by input parameters.
At the end of computing job, it open a cursor with the builded query and return it.
The question that this post try to answers is “How can i use a Cursor returned by a PL/SQL Stored Procedure in Java?”
The first step is to declare in PL/SQL a REF CURSOR Type.
I show you a small example of a sub-program that use a REF CURSOR Type
CREATE OR REPLACE PACKAGE BODY TEST_CURSOR AS TYPE REF_CUR_TYPE IS REF CURSOR; PROCEDURE storeProcedureTest( INPUT_NUM IN NUMBER, REF_CUR_INSTANCE OUT REF_CUR_TYPE ) IS sqlString VARCHAR(100); BEGIN sqlString := 'SELECT * FROM'; IF INPUT_NUM=1 THEN sqlString := sqlString || ' table1'; ELSE sqlString := sqlString || ' table2'; ENDIF; OPEN REF_CUR_INSTANCE FOR sqlString; END storeProcedureTest;
In this very basically stored procedure you have INPUT_NUM that specify on which table you will execute the query. This is a little example that shows a dynamically builded query.
At the TYPE DECLARATION section i define a REF CURSOR type. This say to Oracle that each REF_CUR_TYPE variable is a pointer to a CURSOR.
In the declaration i could make it strongly typed, explicitly defining which kind of rowtype the CURSOR have to return.
TYPE REF_CUR_TYPE IS REF CURSOR RETURN CURSOR_TABLE_TEST%ROWTYPE
At the end Stored Procedure opens REF_CUR_INSTANCE with the builded query. Explicitly note that i DON’T close CURSOR because i want to visit it on Java.
On Java i have to call stored procedure with CallableStatement, registering output Cursor variable. An Oracle Cursor is mapped in Java with java.sql.ResultSet class.
Connection con = null; CallableStatement callableStmt = null; ResultSet rs = null; try { Class.forName("oracle.jdbc.driver.OracleDriver"); con=DriverManager.getConnection( "jdbc:oracle:thin:@address:1521:database_name", "username", "password"); callableStmt = con.prepareCall("{ call TEST_CURSOR.storeProcedureTest(?,?) }"); // set the INPUT_NUM parameter callableStmt.setInt(1, 1); // register the type of the out parameter for CURSOR callableStmt.registerOutParameter(2, OracleTypes.CURSOR); //execute stored procedure callableStmt.execute() //get cursor output rs = callableStmt.getObject(2); while (rs.next){ //do something useful on cursor } } catch (ClassNotFoundException ex) { ex.printStackTrace(); } catch (SQLException ex) { ex.printStackTrace(); } finally { try { rs.close(); callableStmt.close(); con.close(); } catch (SQLException ex) { ex.printStackTrace(); } }
