简体   繁体   中英

Get table return value from PL/SQL stored function using JDBC

I have a PL/SQL stored function which returns a table of integers:

CREATE TYPE INT_TABLE IS TABLE OF INTEGER;

CREATE FUNCTION f (someParam IN INTEGER) RETURN INT_TABLE IS ...

I wish to use JDBC to retrieve the result of this function so that I can iterate through the integers in some way, be it a ResultSet , int[] , or whatever.

The function f performs modifications to the database, so it cannot be called in a query such as SELECT f(42) FROM DUAL; . The return value exists to inform the caller of the primary keys for the rows that it modified. I presumably must use a CallableStatement , but can't figure out exactly how. Taking inspiration from here , I have tried:

CallableStatement cs = conn.prepareCall("{? = call f(42)}");
cs.registerOutParameter(1, Types.ARRAY);
cs.execute();
ResultSet rs = cs.getArray(1).getResultSet();

However, this resulted in java.sql.SQLException: Invalid argument(s) in call on the registerOutParameter line. I haven't been able to determine what this error actually means, as the docs are quite general on the exceptions that may be thrown.

I've spent hours googling and am at quite a loss as to how to proceed. Is it possible to extract a table type into Java? If not, is there some other way of returning multiple integers from the PL/SQL function that can be extracted into Java?

I'm answering my own question after figuring it out.

I was very close to the solution; I'd just missed specifying the type name in the registerOutParameter call. The final solution therefore looks like:

cs = conn.prepareCall("{? = call f(42)}");
cs.registerOutParameter(1, Types.ARRAY, "INT_TABLE");
cs.execute();
ResultSet rs = cs.getArray(1).getResultSet();

This is native JDBC and does not require any of the Oracle extensions.

One other thing that tripped me up was the structure of this ResultSet . It contains two columns; the first is the index and the second is the value ( documentation link ). Therefore, if you want to extract the elements of the array, you need to call rs.getInt(2) for each row rather than rs.getInt(1) .

If one instead wanted the result as a plain array rather than a ResultSet, the corresponding type is java.math.BigDecimal , so it would be

...
cs.execute();
BigDecimal[] array = (BigDecimal[])(cs.getArray(1).getArray());

Yes, from oracle can return table of integer or others types. I think, you need define oracle type

On order: 1.create type and function

CREATE TYPE array_int IS TABLE OF INTEGER;

CREATE OR REPLACE FUNCTION get_array (v_id IN INTEGER) 
RETURN array_int
IS
res array_int := array_int(1,2,3,4);
begin 
  return res; 
end;

AND Java

    ArrayList r_list = new ArrayList();          
    ArrayDescriptor arrayInt = ArrayDescriptor.createDescriptor("ARRAY_INT", con); //to oracle type
    ARRAY iarray = new ARRAY(arrayInt, con, r_list.toArray());
    OracleCallableStatement cst = (OracleCallableStatement) con.prepareCall(
            "{call ?:= get_array(?)");
    cst.registerOutParameter(1, OracleTypes.ARRAY, "ARRAY_INT");
    cst.setInt(2, 1);
    cst.execute();
    iarray = cst.getARRAY(1);
    cst.close();

    Object[] pObjects = (Object[]) iarray.getArray();
    for (int i = 0; i < pObjects.length; i++) {
        System.out.print(pObjects[i]);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM