Aufruf einer Oracle-Funktion mittels Perl
Matthias
- perl
Hallo,
vielleicht kann mir hier jemand einen kleinen Tip geben, ich kriege es einfach nicht auf die Reihe :-(
Ich habe in Oracle eine Funktion in einem Package definiert:
IMPORT (FUNCTION) <return value> VARCHAR2 OUT
IMPORT ID NUMBER IN
IMPORT BRUTTO NUMBER IN
IMPORT NETTO NUMBER IN
IMPORT BESCHREIBUNG VARCHAR2 IN
IMPORT FIRMA VARCHAR2 IN
IMPORT X NUMBER IN
IMPORT Y NUMBER IN
IMPORT Z NUMBER IN
IMPORT ACHSE VARCHAR2 IN
IMPORT EINGANG VARCHAR2 IN
IMPORT FEHLER VARCHAR2 IN
IMPORT DATEI_1 BLOB IN
IMPORT DATEI_2 BLOB IN
Über PL/SQL kann ich die Funktion ohne Fehler wie folgt aufrufen:
declare
out VARCHAR2(500);
begin
out := my_func(123, null, null, null, null, null, null, null, null, 'BEISPIEL', 'TEST', null, null);
dbms_output.put_line('Function returns ' || out || '.');
end;
Das gleiche mittels DBI in Perl sieht so aus:
my $out;
my $sth = ${dbh}->prepare("BEGIN ? := my_func(?,?,?,?,?,?,?,?,?,?,?,?,?); END;") || exit 1;
${sth}->execute($out, $id, undef, undef, undef, undef, undef, undef, undef, undef, $eingang, $fehler, undef, undef) || exit 1;
id, eingang und fehler sind gleich wie oben.
Beim Aufruf erhalte ich allerdings den folgenden Fehler:
DBD::Oracle::st execute failed: ORA-06550: line 1, column 14:
PLS-00306: wrong number or types of arguments in call to 'MY_FUNC'
ORA-06550: line 1, column 14:
PLS-00306: wrong number or types of arguments in call to 'MY_FUNC'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored (DBD ERROR: error possibly near <*> indicator at char 13 in 'BEGIN :p1 := <*>my_func(:p2,:p3,:p4,:p5,:p6,:p7,:p8,:p9,:p10,:p11,:p12,:p13,:p14); END;') [for Statement "BEGIN ? := my_func(?,?,?,?,?,?,?,?,?,?,?,?,?); END;" with ParamValues: :p5=undef, :p12='TEST', :p8=undef, :p14=undef, :p10=undef, :p13=undef, :p2='123', :p3=undef, :p6=undef, :p7=undef, :p1=undef, :p4=undef, :p9=undef, :p11='BEISPIEL'] at ./test.pl line 91.
Anzahl und Typ der Argumente stimmt imho. Ich steh hier total auf dem Schlauch.
Vielen Dank im voraus,
Matthias
Moin Moin!
Ausgabe-Parameter kannst Du nicht einfach an execute() übergeben, denn dann zählen sie nur als Eingabeparameter. Dir fehlt bind_param_inout(), siehe auch PL/SQL-Examples in DBD::Oracle.
Alexander
Hallo Alexander,
vielen Dank für Deinen Tipp. Ich habe das Programm jetzt wir folgt abgeändert, ich erhalte aber immer noch die gleiche Fehlermeldung:
my $sth = $dbh->prepare("BEGIN :out := my_func(:p1, :p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9, :p10, :p11, :p12, :p13); END;") || exit 1;
${sth}->bind_param(":p1", $id);
${sth}->bind_param(":p2", undef);
${sth}->bind_param(":p3", undef);
${sth}->bind_param(":p4", undef);
${sth}->bind_param(":p5", undef);
${sth}->bind_param(":p6", undef);
${sth}->bind_param(":p7", undef);
${sth}->bind_param(":p8", undef);
${sth}->bind_param(":p9", undef);
${sth}->bind_param(":p10", $eingang);
${sth}->bind_param(":p11", $fehler);
${sth}->bind_param(":p12", undef);
${sth}->bind_param(":p13", undef);
${sth}->bind_param_inout(":out", $out, 500);
${sth}->execute;
Hast Du noch einen Tipp, was ich hier falsch mache?
Vielen Dank im voraus,
Matthias
Moin Moin!
Hallo Alexander,
vielen Dank für Deinen Tipp. Ich habe das Programm jetzt wir folgt abgeändert, ich erhalte aber immer noch die gleiche Fehlermeldung:
Diese? "DBD::Oracle::st execute failed: ORA-06550: line 1, column 14:
PLS-00306: wrong number or types of arguments in call to 'MY_FUNC'"
Dann würde ich mal nachsehen, wie MY_FUNC definiert ist. Ganz offensichtlich hat Oracle mit der Anzahl oder dem Typ der Parameter ein Problem.
my $sth = $dbh->prepare("BEGIN :out := my_func(:p1, :p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9, :p10, :p11, :p12, :p13); END;") || exit 1;
${sth}->bind_param(":p1", $id);
${sth}->bind_param(":p2", undef);
${sth}->bind_param(":p3", undef);
${sth}->bind_param(":p4", undef);
${sth}->bind_param(":p5", undef);
${sth}->bind_param(":p6", undef);
${sth}->bind_param(":p7", undef);
${sth}->bind_param(":p8", undef);
${sth}->bind_param(":p9", undef);
${sth}->bind_param(":p10", $eingang);
${sth}->bind_param(":p11", $fehler);
${sth}->bind_param(":p12", undef);
${sth}->bind_param(":p13", undef);${sth}->bind_param_inout(":out", $out, 500);
${sth}->execute;
Das sieht auf den ersten Blick ok aus, soll heißen: 13 Parameter und bind_param_inout() für den Rückgabewert. ABER: Weil Du bei bind_param() keine expliziten Typangaben machst (dritter Parameter fehlt), wird DBI bzw. DBD::Oracle irgendeinen Default-Typ nehmen, bei DBD::Oracle ist das ohne weitere Einstellungen VARCHAR2.
Deine Oracle-Funktion hat aber auch noch einige NUMBER- und BLOB-Argumente, und ich schätze, dass Oracle keinen Bock hat, die VARCHAR2s automatisch umzuwandeln.
Ruf also bind_param() mit einem zum jeweiligen Parameter passenden Datentyp auf. Das ist in der Doku von DBD::Oracle ziemlich ausführlich beschrieben.
Übrigens ist dort auch noch eine Perle zum dritten Parameter von bind_param_inout() zu finden: >>The third parameter of bind_param_inout_array, (0 in the example), "maxlen" is required by DBI but not used by DBD::Oracle.<<
Wenn Du also nur mit Oracle arbeiten willst, kannst Du Dir das Größenraten komplett sparen, immer 0 nehmen, und Oracle / DBD::Oracle den Rest machen lassen.
Alexander
Hallo Alexander,
vielen Dank für deine Hilfe, jetzt geht es.
Deine Oracle-Funktion hat aber auch noch einige NUMBER- und BLOB-Argumente, und ich schätze, dass Oracle keinen Bock hat, die VARCHAR2s automatisch umzuwandeln.
Genau das war das Problem.
Viele Grüße,
Matthias
Moin Moin!
vielen Dank für deine Hilfe, jetzt geht es.
Na also. Es lohnt sich also doch, gelegentlich mal die Dokumentation gelesen zu haben. ;-)
Deine Oracle-Funktion hat aber auch noch einige NUMBER- und BLOB-Argumente, und ich schätze, dass Oracle keinen Bock hat, die VARCHAR2s automatisch umzuwandeln.
Genau das war das Problem.
Naja, wenn ich fies wäre, würde ich sagen, dass Du die Doku von DBI und DBD::Oracle nicht genau genug gelesen hast. Das ist allerdings wirklich eine Menge Stoff, und einige kleinere Details versteht man erst, wenn man sich lange genug mit dem DBI befaßt hat.
Ganz allgemein gesagt ist einer der Tricks vom DBI, sich möglichst alle Daten von der jeweiligen Datenbank als String anliefern zu lassen und umgekehrt alle Daten als String in die Datenbank zu schieben. Die Umwandlung in irgendetwas anderes (Zahl, BLOB, Datum) erledigt dann jede Seite (Perl, Datenbank) für sich. Im SQL-Umfeld ist das der "natürliche" Weg, mit Daten umzugehen, und auch Perl hat damit nur sehr selten Probleme.
Alexander