简体   繁体   English

JDBC:Oracle存储过程返回嵌套表

[英]JDBC: Oracle stored procedure returns nested table

I have a stored procedure in oracle(12c): 我在oracle(12c)中有一个存储过程:

PROCEDURE work(a OUT VARCHAR2, b OUT SYS_REFCURSOR)

When I call the procedure the result of cursor contains rows, the row consists of some primitive values + a custom type: 当我调用该过程时,游标的结果包含行,该行包含一些原始值+一个自定义类型:

CREATE TYPE ELEM AS OBJECT(ElemID INTEGER))
CREATE TYPE LIST AS TABLE OF ELEM

So, the result is something like: 所以,结果如下:

vcursor:
------------------
COL1 COL2 LIST
------------------
A    B    LIST([ELEM],[ELEM])
C    D    LIST([ELEM],[ELEM],[ELEM])
E    F    LIST([ELEM])

There is a tutorial for collections Oracle tutorial (in case link is lost, google for "Working with Oracle Collections"). 有一个收集Oracle教程的教程 (如果链接丢失,google为“使用Oracle Collections”)。 Nothing worked for me so far from this tutorial. 到目前为止,本教程对我没有任何作用。

Here is what I do in the java: 这是我在java中所做的:

Connection conn = ...
CallableStatement statement = conn.prepareCall("{call work()}");
statement.registerOutParameter(1, OracleTypes.VARCHAR);
statement.registerOutParameter(2, OracleTypes.CURSOR);
statement.execute();

ResultSet rs = statement.getResultSet(2);
// here should be the code which retrieves the nested table elements
rs.next()
Array list = rs.getArray(3); //oracle.sql.ARRAY
Object[] elems = (Object[]) list.getArray(); // doesn't work
// I also tried list.getResultSet()

Under debug I do see that if I cast to oracle.sql.ARRAY and call getOracleArray() then I see the correct size and Datum[] array with Struct[], however plain sql methods give me nothing. 在调试中我确实看到如果我转换为oracle.sql.ARRAY并调用getOracleArray()然后我看到正确的大小和带有Struct []的Datum []数组,但是普通的sql方法什么也没给我。 For example getResultSet from array returns a ResultSet with next always returning true, but not having metadata and actual data. 例如,来自数组的getResultSet返回一个ResultSet,其中next始终返回true,但没有元数据和实际数据。 getArray() returns array with numElements = -1, etc.. getArray()返回numElements = -1等的数组。

I tried to play with typeMap with no luck: 我尝试使用typeMap而没有运气:

Map map = conn.getTypeMap();
map.put("ELEM", Elem.class); 
//map.put("SCHEMA.ELEM", Elem.class); 
//map.put("LIST", Elem.class); 
//map.put("SCHEMA.LIST", Elem.class); 
conn.setTypeMap(map);

Please help and advice. 请帮忙和建议。 Thanks in advance. 提前致谢。

I'm afraid I'm struggling to reproduce the behaviour you're seeing. 我担心我正在努力重现你所看到的行为。 I tried to put together some code that would reproduce your problem, but it worked. 我试图整理一些可以重现你的问题的代码,但它确实有效。 The code is below, I hope is it of some use to you. 代码如下,我希望它对你有用。

I used a type map entry for the type ELEM but not for LIST . 我使用了ELEM类型的类型映射条目,但没有使用LIST I also couldn't find the getResultSet(int) method on the CallableStatement interface, so I used getObject(int) instead and casted that to ResultSet . 我也无法在CallableStatement接口上找到getResultSet(int)方法,所以我使用了getObject(int)并将其转换为ResultSet

In case it matters, I'm using Oracle 11g XE 11.2.0.2.0, Java 1.8.0_60, ojdbc7.jar version 12.1.0.2.0 on Windows 10 x64. 如果重要,我在Windows 10 x64上使用Oracle 11g XE 11.2.0.2.0,Java 1.8.0_60,ojdbc7.jar版本12.1.0.2.0。 I also tried versions of ojdbc6.jar and ojdbc5.jar, and they had the same result. 我也尝试过ojdbc6.jar和ojdbc5.jar的版本,它们也有相同的结果。

SQL: SQL:

CREATE TYPE elem AS OBJECT(ElemID INTEGER);
/

CREATE TYPE list AS TABLE OF elem;
/

CREATE OR REPLACE PROCEDURE work(a OUT VARCHAR2, b OUT SYS_REFCURSOR)
AS
BEGIN
  a := 'test 1234';
  OPEN b FOR
    SELECT 'A' AS col1, 'B' AS col2, list(elem(14), elem(17)) FROM DUAL
     UNION ALL
    SELECT 'C' AS col1, 'D' AS col2, list(elem(8), elem(4), elem(11)) FROM DUAL
     UNION ALL
    SELECT 'E' AS col1, 'F' AS col2, list(elem(-1)) FROM DUAL;
END work;
/

Elem.java: Elem.java:

import java.sql.*;

public class Elem implements SQLData {

    private Integer elementId;

    public String getSQLTypeName() { return "ELEM"; }

    public void readSQL(SQLInput input, String typeName) throws SQLException {
        elementId = input.readInt();
    }

    public void writeSQL(SQLOutput output) {
        throw new UnsupportedOperationException();
    }

    public String toString() {
        return "<Element " + elementId + ">";
    }
}

JDBCStructs.java: JDBCStructs.java:

import java.sql.*;
import java.util.*;

public class JDBCStructs {
    public static void main(String[] args) throws Exception {
        Connection c = ...

        Map<String, Class<?>> map = c.getTypeMap();
        map.put("ELEM", Elem.class);
        c.setTypeMap(map);        

        CallableStatement cs = c.prepareCall("{call work(?, ?)}");
        cs.registerOutParameter(1, Types.VARCHAR);
        cs.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR);
        cs.execute();
        String a = cs.getString(1);
        System.out.println("Got string " + a);
        ResultSet rSet = (ResultSet)cs.getObject(2);
        while (rSet.next()) {
            String col1 = rSet.getString(1);
            String col2 = rSet.getString(2);
            Array list = (Array)rSet.getObject(3);
            System.out.println("Got " + col1 + ", " + col2 + " and " + Arrays.toString((Object[])list.getArray()));
        }
    }
}

Output: 输出:

Got string test 1234
Got A, B and [<Element 14>, <Element 17>]
Got C, D and [<Element 8>, <Element 4>, <Element 11>]
Got E, F and [<Element -1>]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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