Tôi vừa phải đối mặt với vấn đề tương tự và bây giờ có một giải pháp. Về cơ bản có hai vấn đề. Đầu tiên là Oracle yêu cầu bạn cho nó biết tên của kiểu mảng khi tham số đầu ra được đăng ký. Thứ hai là làm thế nào để thuyết phục Groovy để bạn làm điều đó. May mắn thay, có vẻ như các nhà thiết kế Groovy đã nghĩ ra điều này và cho phép bạn phân lớp groovy.sql.Sql để kết nối vào cài đặt tham số.
Tôi sẽ sử dụng loại ví dụ và quy trình được lưu trữ trong câu trả lời này cho một câu hỏi tương tự ở cấp JDBC:
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
Bây giờ chúng ta cần một vài lớp Groovy mới:
import groovy.sql.*
import java.sql.CallableStatement
import java.sql.PreparedStatement
import java.sql.SQLException
import oracle.jdbc.driver.*
class OracleArrayOutParameter implements OutParameter {
String typeName
int getType() {
OracleTypes.ARRAY
}
}
class OracleArrayAwareSql extends Sql {
OracleArrayAwareSql(Sql parent) {
super(parent)
}
void setObject(PreparedStatement statement, int i, Object value) throws SQLException {
if (value instanceof OracleArrayOutParameter) {
try {
OracleArrayOutParameter out = (OracleArrayOutParameter) value;
((CallableStatement) statement).registerOutParameter(i, out.getType(), out.typeName);
} catch (ClassCastException e) {
throw new SQLException("Cannot register out parameter.");
}
}
else {
super.setObject(statement, i, value)
}
}
}
Việc sử dụng chúng khá đơn giản. Có thể bạn sẽ muốn tài liệu Oracle về mảng để hiểu cấu trúc dữ liệu kết quả.
// First create a "normal" groovysqlSql instance, using whatever method you like
def parent = Sql.newInstance("jdbc:oracle:thin:@host:port:sid", "user", "password", "oracle.jdbc.OracleDriver")
// Then create an OracleArrayAwareSql instance giving that parent instance as a parameter
def sql = new OracleArrayAwareSql(parent)
// Now define an OracleArrayOutParameter naming the array type
def tTableParam = new OracleArrayOutParameter(typeName: 'T_TABLE')
// And make a stored procedure call as usual
sql.call("{call p_sql_type(${tTableParam})}") { out ->
// The returned parameter is of type oracle.sql.ARRAY
out.array.each { struct ->
println struct.attributes
}
}