Ik heb net hetzelfde probleem gehad en heb nu een oplossing. In principe zijn er twee problemen. De eerste is dat Oracle vereist dat u het de naam van het arraytype vertelt wanneer de uitvoerparameter wordt geregistreerd. De tweede is hoe je Groovy kunt overtuigen om je dat te laten doen. Gelukkig lijkt het erop dat de Groovy-ontwerpers hieraan hebben gedacht en je toestaan om groovy.sql.Sql te subklassen om in de parameterinstelling te haken.
Ik gebruik het voorbeeldtype en de opgeslagen procedure in dit antwoord op een vergelijkbare vraag op JDBC-niveau:
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
Nu hebben we een paar nieuwe Groovy-lessen nodig:
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)
}
}
}
Het gebruik hiervan is vrij eenvoudig. U wilt waarschijnlijk dat de Oracle-documentatie over arrays de resulterende gegevensstructuren begrijpt.
// 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
}
}