Току що се сблъсках със същия проблем и сега имам решение. По принцип има два проблема. Първото е, че Oracle изисква да му кажете името на типа масив, когато изходният параметър е регистриран. Второто е как да убедите Groovy да ви позволи да направите това. За щастие изглежда, че дизайнерите на Groovy са помислили за това и ви позволяват да подкласа groovy.sql.Sql, за да се свържете с настройката на параметрите.
Ще използвам примерния тип и съхранената процедура в този отговор на подобен въпрос на ниво 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
Сега имаме нужда от няколко нови класа Groovy:
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)
}
}
}
Използването им е доста лесно. Вероятно ще искате документацията на Oracle за масивите, за да разберете получените структури от данни.
// 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
}
}