2017-12-08 4 views
2

Ich habe Java/JDBC Aufrufe an gespeicherte Prozeduren mit einigem Erfolg entwickelt. Ich stehe jedoch fest, wenn ein Ausgabeparameter ein Array von Strings ist. Ich war erfolgreich mit skalaren Typen als Eingabe- und Ausgabeparameter, sowie einem Array von Strings als Eingabeparameter.Wie bekomme ich einen Ausgabeparameter für eine gespeicherte Prozedur, der ein Array funktioniert?

Hier ist die PL/SQL-Code ich habe:

TYPE StringArray IS TABLE OF VARCHAR2(32767) INDEX BY BINARY_INTEGER; 

create or replace package body 
test is 
    procedure upper(
    in_array  in StringArray, 
    out_array out StringArray 
) is 
    tmp StringArray := in_array; 
    begin 
    for i in 0..(tmp.count-1) loop 
     tmp(i) := UPPER(tmp(i)); 
    end loop; 
    out_array := tmp; 
    end; 
end test; 

Hier wird der Java-Code ist ich habe:

public void testString(Connection connection) { 
    String[] values = { "alpha", "beta", "gamma" }; 
    try { 
     CallableStatement callableStatement = connection.prepareCall("begin test.upper(?, ?); end;"); 
     DelegatingConnection<OracleConnection> delegatingConnection = (DelegatingConnection<OracleConnection>) new DelegatingConnection(connection); 
     OracleConnection oracleConnection = (OracleConnection) delegatingConnection.getInnermostDelegate(); 
     Array input oracleConnection.createOracleArray("STRINGARRAY", values); 
     callableStatement.setObject("in_array", input); 
     callableStatement.registerOutParameter("out_array", Types.ARRAY, "STRINGARRAY"); 
     callableStatement.execute(); 
     Array output = (Array)callableStatement.getObject("out_array"); 
     String[] result = (String[])output.getArray(); 
     System.out.println("Length: " + result.length); // Prints "Length: 3" 
     System.out.println("First: " + result[0]);  // Prints "First: null" 
    } (catch SQLException e) { 
     // Handle error 
    } 
} 

Wenn ich die PL/SQL gespeicherte Prozedur aus einer SQL-Skript direkt aufrufen es funktioniert . Also ich denke, die gespeicherte Prozedur selbst ist in Ordnung.

Wenn ich die gespeicherte Prozedur über JDBC aufruft, wird sie normal beendet. Mit Debug-Anweisungen habe ich bestätigt, dass values korrekt vom Java-Client an die gespeicherte Prozedur in in_array gesendet wird. Das heißt, ein Array der Länge 3 mit den entsprechenden Werten wird empfangen. Soweit ich das beurteilen kann, wird out_array zurück an den Java-Client gesendet. Es läuft jedoch etwas schief. result ist von Größe 3, aber alle Elemente sind null.

Wenn ich inspiziere output, kann ich sehen, dass es intern eine byte[] der Länge 38 hat. Untersequenzen dieser Bytes zuordnen "ALPHA", "BETA" und "GAMMA". Es sieht also so aus, als ob die Daten es zurück zum Client schaffen, aber es wird nicht korrekt in einen String[] konvertiert.

Was mache ich falsch?

+0

Wo ist das eigentliche Problem Sie konfrontiert. Im PLSQL-Block oder im JAVA-Aufruf. Es ist nicht klar von Ihrer Frage – XING

+0

@ XING Wie am besten kann ich sagen, die PL/SQL ist in Ordnung, da die gespeicherte Prozedur normal abgeschlossen wird. Im Java-Client-Code ist das Ergebnis jedoch ein Array mit der richtigen Länge, jedoch mit "null" -Elementen. Daher werden die Daten auf der Clientseite nicht korrekt transformiert. Darauf basierend denke ich, dass das Problem am Ende von Java liegt, aber man weiß es nie. – dave

+0

Vielleicht Vararrays oder verschachtelte Tabellen anstelle von assoziativen Arrays (Index-by-Tabellen). Sie schrieben in [die Dokumentation] (https://docs.oracle.com/database/121/JJDBC/oraarr.htm#JJDBC28574), dass ihr JDBC-Treiber Varrarrays und verschachtelte Tabellen unterstützt, Index-für-Tabellen sind nirgends in der Dokumentation. – krokodilko

Antwort

2

Sie nicht ein assoziatives Array verwenden - eine Sammlung verwenden:

CREATE TYPE StringArray IS TABLE OF VARCHAR2(4000); 
CREATE TYPE CLOBArray IS TABLE OF CLOB; 

Dann können Sie tun:

public void testString(Connection connection) { 
    String[] values = { "alpha", "beta", "gamma" }; 
    try { 
    OracleConnection oc = (OracleConnection) connection; 

    ARRAY stringArray = oc.createARRAY("STRINGARRAY", values); // Upper case identifier 

    OracleCallableStatement st = (OracleCallableStatement) oc.prepareCall(
     "begin test.upper(:in_array, :out_array); end;" 
    ); 

    st.setARRAYAtName("in_array", stringArray); 
    st.registerOutParameter("out_array", Types.ARRAY, "STRINGARRAY"); // Upper case again 
    st.execute(); 

    String[] result = (String[])st.getARRAY(2).getArray(); 

    System.out.println("Length: " + result.length); 
    System.out.println("First: " + result[0]); 
    } (catch SQLException e) { 
    // Handle error 
    } 
} 

Wenn Sie eine PL/SQL-assoziatives Array als Eingabe in der Prozedur verwenden müssen schreibt dann eine Funktion, die eine Sammlung und gibt ein assoziatives Array des entsprechenden Typs und dann Anruf entgegennimmt, dass:

BEGIN TEST.UPPER(TO_ASSOC_ARRAY(:in_collection), :out_array); END; 

Hinweis: Diese Antwort geht davon aus, den Oracle-Treiber in ojdbc6.jar zu verwenden, der nicht die OracleConnection.createOracleArray() method zu haben scheint, aber es wird hoffentlich portabel sein, oracle.sql.ARRAY zu java.sql.Array zu ändern und die neueren Methoden zu verwenden.

+0

Ich bin mir ziemlich sicher, dass wir 'ojdbc7 verwenden.Glas ". Wird das eine Rolle spielen? Würdest du deine Antwort ändern? – dave

+0

Der Schlüsseltipp - keine assoziativen Arrays verwenden - hat mir geholfen, mein Problem zu lösen. Indem ich einfach den Typ von 'out_array' änderte, konnte ich ein Array von Strings von der gespeicherten Prozedur zurück erhalten. Ich musste keinen Java-Client-Code ändern. – dave

Verwandte Themen