PDA

View Full Version : ADO(C#) -> ODBC -> Procedure -> CL und zurück



Seiten : [1] 2

jogisarge
16-09-08, 09:53
Hallo zusammen,

ich möchte per ADO/ODBC aus C# eine SQL-Procedure auf der i5 mit Parametern aufrufen.
Die procedure erwartet einen PArameter und ruft ein CL auf.

Procedure-Code:


CREATE PROCEDURE TEST/SQLPROD(IN PARMIN CHAR ( 100))
LANGUAGE CL NOT DETERMINISTIC NO SQL EXTERNAL NAME
TEST/SQLMAIL PARAMETER STYLE GENERAL


Das funktioniert soweit.
Mein C# Code:


OdbcCommand sqlcmd2 = new OdbcCommand("CALL SQLPROD ('wert')", con);
sqlcmd2.ExecuteScalar();


Nun würde ich gerne die Prozedur um einen out-Parameter erweitern.
Kann mir jemand Tipps geben. wie das geht.
(Den Parameter in der Prozedur zu deklarieren ist mir klar, aber wie ruft man das Ganze dann auf ?)

Gruß jogi

Fuerchau
16-09-08, 10:05
Es gibt 2 Methoden:
a) als Prozedur mit 2 Parametern
b) als Funktion mit Returnwert

Als Prozedur musst du das ODBCCommand explizit anlegen und die einzelnen Parameter spezifizieren (IN, INOUT, OUT), ein ExecuteScalar geht dann nicht mehr.
Du benötigst einen Execute und kannst das Ergebnis aus dem ODBCCommand entnehmen.

Als Funktion sieht der Call dann so aus:
"? CALL SQLFUNC (?)"
Auch hier explizite Parameterdeklaration, ob ExecuteScalar dann geht, weiß ich nicht, aber Execute mit Auswertung des Parameters geht auf jeden Fall.

Soweit ich weiß, geht ExecuteScalar nur auf Resultset's.

jogisarge
16-09-08, 11:20
Hallo nochmal,

danke soweit.

Nun habe ich meinen Aufruf so geändert:


OdbcCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "{ CALL SQLPROD2(? , ?) }";
OdbcParameter p1 = cmd.CreateParameter();
p1.Value = "test";
p1.Direction = ParameterDirection.Input;
p1.OdbcType = OdbcType.NVarChar;
OdbcParameter p2 = cmd.CreateParameter();
p2.OdbcType = OdbcType.NVarChar;
p2.Direction = ParameterDirection.Output;
cmd.Parameters.Add(p1);
cmd.Parameters.Add(p2);
cmd.ExecuteNonQuery();

Da es keinen cmd.Execute gibt, muss es wohl mit ExecuteNonQuery gehen !?
LAut der MSDN soll das gehen !

Momentan bekomme ich aber den Fehler in C#:


String[2]: die Size-Eigenschaft hat den ungültigen Wert 0.


Wie kann ich denn prüfen, ob die Prozedur überhaupt was zurückliefert bzw. vom CL empfängt ?


Gruß jogi

Fuerchau
16-09-08, 14:16
Schau dir doch mal den Fehler genau an:
Du musst die max. erwartete Länge des P2 noch angeben, denn diese Angabe fehlt ja wohl.

jogisarge
17-09-08, 07:20
ok, danke, jetzt geht es.

:) :)

jogisarge
17-09-08, 15:10
Ähm, ich müsste nochmal nachfragen.

Auf unserer 520 V5R3, konnte ich die Prozedur nicht/nicht richtig erstellen.

Ich versuche folgende Prozedur zu erstellen:


CREATE PROCEDURE ARTLIB/PROC1(OUT param CHAR (1 ))
LANGUAGE CL NOT DETERMINISTIC NO SQL EXTERNAL NAME
ARTLIB/ITASQLSTS PARAMETER STYLE GENERAL


Nachdem ersteller kommt folgende Meldung:


Nachricht . . . : Routine PROC1 wurde erstellt, kann aber nicht
gesichert oder zurückgespeichert werden.
Ursache . . . . : Die Routine PROC1 wurde erfolgreich in ARTLIB mit
dem spezifischen Namen PROC1 erstellt, aber die Attribute der Routine
konnten nicht in dem zugeordenten Programm- oder Serviceprogrammobjekt
gespeichert werden. Wird das *PGM- oder *SRVPGM-Objekt gesichert und dann
zurückgespeichert, werden die SQL-Kataloge nicht mit den Attributen für
diese Routine aktualisiert.
Beim Versuch, das zugeordnete Programm- oder Serviceprogrammobjekt mit den
Attributen der Routine zu aktualisieren, wurde eine der folgenden
Bedingungen festgestellt:
-- Das Schema des externen Programms ist QSYS.
-- Das externe Programm war nicht vorhanden, als die Anweisung CREATE
abgesetzt wurde.
-- Das externe Programm war kein ILE *PGM oder *SRVPGM.
-- Das externe Programm enthielt keine einzige SQL-Anweisung.
Fehlerbeseitigung: Die Routine wurde erstellt, aber sofern nicht alle der
folgenden Bedingungen erfüllt sind, kann die Routine nicht gesichert oder
zurückgespeichert werden.
-- Das Schema des externen Programms darf nicht QSYS sein.
-- Sicherstellen, dass das externe Programm existiert, wenn die Anweisung
CREATE abgesetzt wird.
-- Sicherstellen, dass das externe Programm ein ILE *PGM oder *SRVPGM ist.
-- Sicherstellen, dass das externe Programm oder Serviceprogramm
mindestens eine SQL-Anweisung enthält.


Kann mir jemand sagen, was da schief läuft ?

Gruß jogi

Fuerchau
17-09-08, 16:07
Das bedeutet nur soviel, dass SQL-Eigenschaften nicht dem Programmobjekt direkt zugeordnet werden konnten.
Wenn du also das Programmobjekt später auf eine andere Maschine kopierst, ist der "Create Procedure" dort zu wiederholen.

Machst du ganz einfach ein CLLE daraus, geht die Definition mit dem Objekt mit.

Ansonsten hat das keine Auswirkungen, die Prozedur ist ganz normal ausführbar.

jogisarge
17-09-08, 16:33
Ok, dann ändere ich das.

Wenn ich aber versuche die Prozedur aufzurufen(aus C#), dann kommt folgendes:


ERROR [42S02] [IBM][iSeries Access ODBC-Treiber][DB2 UDB]SQL0204 -
PROCTABSTS der Art *N in nicht gefunden.

Fuerchau
17-09-08, 17:28
Dazu gibts 2 Möglichkeiten:
a) die Prozedur ist nicht in der SQL-Defaultlib
b) du hast den call nicht qualifiziert "call mylib.myprc"
c) die Parametertypisierung stimmt nicht

zu a)
SQL legt automatisch eine Standardlib (User) fest oder du gibst eine Standardlib vor, dann muss die Prozedur auch dort liegen.

zu b)
Qualifiziere deinen Aufruf mit der Lib.

zu c)
Als Parameter musst du GENAU den Typ und die Länge angeben, den deine Prozedur erwartet. Es reicht da nicht, nur den Parameter zu defiieren.
Nur wenn die Parameter GENAU passen, kann die Prozedur gefunden werden.
Hintergrund:
Du kannst mehrere gleiche Prozedurnamen mit unterschiedlichen Parametern definieren.

Du kannst allerdings auch casten:

call mylib.myproc (cast ? as char(1), ...)

jogisarge
17-09-08, 18:32
Variante b war es.
Tausend Dank !!!!!!!!!!!!!!!