Извлечение типа таблицы Oracle из хранимой процедуры с использованием JDBC
Я пытаюсь понять различные способы получения табличных данных из хранимых процедур/функций Oracle с помощью JDBC. Этими шестью способами являются следующие:
- процедура возвращает тип таблицы уровня схемы как параметр OUT
- процедура возвращает тип таблицы уровня пакета как параметр OUT
- процедура возвращает тип курсора уровня пакета как параметр OUT
- возвращает тип таблицы уровня схемы
- функция возвращает тип таблицы уровня пакета
- возвращающая тип курсора уровня пакета
Вот несколько примеров в PL/SQL:
-- schema-level table type
CREATE TYPE t_type AS OBJECT (val VARCHAR(4));
CREATE TYPE t_table AS TABLE OF t_type;
CREATE OR REPLACE PACKAGE t_package AS
-- package level table type
TYPE t_table IS TABLE OF some_table%rowtype;
-- package level cursor type
TYPE t_cursor IS REF CURSOR;
END library_types;
-- and example procedures:
CREATE PROCEDURE p_1 (result OUT t_table);
CREATE PROCEDURE p_2 (result OUT t_package.t_table);
CREATE PROCEDURE p_3 (result OUT t_package.t_cursor);
CREATE FUNCTION f_4 RETURN t_table;
CREATE FUNCTION f_5 RETURN t_package.t_table;
CREATE FUNCTION f_6 RETURN t_package.t_cursor;
Мне удалось вызвать 3, 4 и 6 с помощью JDBC:
// Not OK: p_1 and p_2
CallableStatement call = connection.prepareCall("{ call p_1(?) }");
call.registerOutParameter(1, OracleTypes.CURSOR);
call.execute(); // Raises PLS-00306. Obviously CURSOR is the wrong type
// OK: p_3
CallableStatement call = connection.prepareCall("{ call p_3(?) }");
call.registerOutParameter(1, OracleTypes.CURSOR);
call.execute();
ResultSet rs = (ResultSet) call.getObject(1); // Cursor results
// OK: f_4
PreparedStatement stmt = connection.prepareStatement("select * from table(f_4)");
ResultSet rs = stmt.executeQuery();
// Not OK: f_5
PreparedStatement stmt = connection.prepareStatement("select * from table(f_5)");
stmt.executeQuery(); // Raises ORA-00902: Invalid data type
// OK: f_6
CallableStatement call = connection.prepareCall("{ ? = call f_6 }");
call.registerOutParameter(1, OracleTypes.CURSOR);
call.execute();
ResultSet rs = (ResultSet) call.getObject(1); // Cursor results
Так что, очевидно, у меня проблемы с пониманием
- Как получить типы таблиц уровня схемы и уровня пакета из параметров OUT в хранимых процедурах
- Как получить типы таблиц уровня на основе хранимых функций
Я не могу найти никакой документации по этому поводу, так как каждый всегда использует курсоры вместо типов таблиц. Может, потому что это невозможно? Я предпочитаю типы таблиц, потому что они формально определены и могут быть обнаружены с использованием представлений словаря (по крайней мере, типов таблиц уровня схемы).
Примечание: очевидно, я мог бы написать функцию-обертку, возвращающую параметры OUT и типы таблиц уровня пакета. Но я предпочел бы чистое решение.
Ответы
Ответ 1
Вы не можете получить доступ к объектам PLSQL (случаи 2 и 5 = объекты уровня пакета) из java, см. "java - передача массива в хранимой процедуре oracle" . Однако вы можете обращаться к типам SQL (случаи 1 и 4).
Чтобы получить параметры OUT из PL/SQL в java, вы можете использовать метод, описанный в один из потоков Tom Kyte, используя OracleCallableStatement. У вашего кода будет дополнительный шаг, так как вы извлекаете таблицу объекта вместо таблицы VARCHAR.
Здесь демонстрационная таблица с использованием таблицы SQL-объекта, сначала настройка:
SQL> CREATE TYPE t_type AS OBJECT (val VARCHAR(4));
2 /
Type created
SQL> CREATE TYPE t_table AS TABLE OF t_type;
2 /
Type created
SQL> CREATE OR REPLACE PROCEDURE p_sql_type (p_out OUT t_table) IS
2 BEGIN
3 p_out := t_table(t_type('a'), t_type('b'));
4 END;
5 /
Procedure created
Действительный класс java (используя dbms_output.put_line
для журнала, потому что я буду называть его из SQL, используйте System.out.println
, если он вызван из java):
SQL> CREATE OR REPLACE
2 AND COMPILE JAVA SOURCE NAMED "ArrayDemo"
3 as
4 import java.sql.*;
5 import oracle.sql.*;
6 import oracle.jdbc.driver.*;
7
8 public class ArrayDemo {
9
10 private static void log(String s) throws SQLException {
11 PreparedStatement ps =
12 new OracleDriver().defaultConnection().prepareStatement
13 ( "begin dbms_output.put_line(:x); end;" );
14 ps.setString(1, s);
15 ps.execute();
16 ps.close();
17 }
18
19 public static void getArray() throws SQLException {
20
21 Connection conn = new OracleDriver().defaultConnection();
22
23 OracleCallableStatement cs =
24 (OracleCallableStatement)conn.prepareCall
25 ( "begin p_sql_type(?); end;" );
26 cs.registerOutParameter(1, OracleTypes.ARRAY, "T_TABLE");
27 cs.execute();
28 ARRAY array_to_pass = cs.getARRAY(1);
29
30 /*showing content*/
31 Datum[] elements = array_to_pass.getOracleArray();
32
33 for (int i=0;i<elements.length;i++){
34 Object[] element = ((STRUCT) elements[i]).getAttributes();
35 String value = (String)element[0];
36 log("array(" + i + ").val=" + value);
37 }
38 }
39 }
40 /
Java created
Позвольте называть его:
SQL> CREATE OR REPLACE
2 PROCEDURE show_java_calling_plsql
3 AS LANGUAGE JAVA
4 NAME 'ArrayDemo.getArray()';
5 /
Procedure created
SQL> EXEC show_java_calling_plsql;
array(0).val=a
array(1).val=b
Ответ 2
Вы также можете использовать нижеследующий
public List<EmployeeBean> fetchDataFromSPForRM(String sInputDate) {
List<EmployeeBean> employeeList = new ArrayList<EmployeeBean>();
Connection dbCon = null;
ResultSet data = null;
CallableStatement cstmt = null;
try {
dbCon = DBUtil.getDBConnection();
String sqlQuery = "{? = call PKG_HOLD_RELEASE.FN_RM_PDD_LIST()}";
cstmt = dbCon.prepareCall(sqlQuery);
cstmt.registerOutParameter(1, OracleTypes.CURSOR);
cstmt.execute();
data = (ResultSet) cstmt.getObject(1);
while(data.next()){
EmployeeBean employee = new EmployeeBean();
employee.setEmpID(data.getString(1));
employee.setSubBusinessUnitId((Integer)data.getObject(2));
employee.setMonthOfIncentive((Integer)data.getObject(3));
employee.setPIPStatus(data.getString(5));
employee.setInvestigationStatus(data.getString(6));
employee.setEmpStatus(data.getString(7));
employee.setPortfolioPercentage((Integer)data.getObject(8));
employee.setIncentive((Double)data.getObject(9));
employee.setTotalSysemHoldAmt((Double)data.getObject(10));
employee.setTotalManualHoldAmt((Double)data.getObject(11));
employeeList.add(employee);
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(data != null){
data.close();
data = null;
}
if(cstmt != null){
cstmt.close();
cstmt = null;
}
if(dbCon != null){
dbCon.close();
dbCon = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return employeeList;
}