pdt1630 has asked for the wisdom of the Perl Monks concerning the following question:

I'm currently in the middle of rewriting some tools. I "want" to use Oracle Stored Procedures as much as possible. I nailed down calling them, and bringing back 1 row of data, but am stuck on how to return multiple rows of data back. So far I have tried two methods

(1) Binding a cursor for which I get the following error

Can't bind :module_cursor, ora_type 0 not supported by DBD::Oracle at c:\Program Files\Apache Group\Apache\cgi-bin\techArchUtilityModules/OracleUtility.pm line 112.

whose code line looks like:

$csr = $dbh->prepare("BEGIN get_junk(:module_cursor);END;");

$csr->bind_param_inout(":module_cursor", \$sth2, 0, { ora_type => ORA_RSET } );

(2) I've tried using the selectall_arrayref which if I'm reading the DBD documenation right should work, but I can't figure out the syntax on it... ie it nukes it self in place...

So I kind of stuck on where to go... I've used DBMS_OUTPUT in reports in the past... not sure if there is an option in perl...

Curious to hear if anyone has had any luck running stored procs. I guess worst case scenario I have to punt and put all my sql in a common module...

CHEERS

  • Comment on Oracle Stored Procs - DBD - How to return multiple rows

Replies are listed 'Best First'.
Re: Oracle Stored Procs - DBD - How to return multiple rows - USE CURSORS
by pdt1630 (Acolyte) on Jan 09, 2002 at 00:37 UTC
    I finally figured this one... wow is there a lot of bad documentation out there in regards to this... but in a nutshell here is the jist of what needs to happen to get a cursor to work properly...

    1) Create a package of with the stored proc. I've copied a generic one below to use for reference.

    CREATE OR REPLACE PACKAGE table_ids AS TYPE return_cursor IS REF CURSOR; PROCEDURE get_next_session_id(session_cursor OUT return_cursor); END table_ids; / CREATE OR REPLACE PACKAGE BODY table_ids AS PROCEDURE get_next_session_id(session_cursor OUT return_cursor) IS BEGIN OPEN session_cursor FOR SELECT 'S'||lpad(session_id.nextval,5,'0') FROM dual; EXCEPTION WHEN NO_DATA_FOUND THEN raise_application_error(-20000, 'No more rows.'); WHEN OTHERS THEN raise_application_error(-20001, 'There was an undet +erminable error.'); END get_next_session_id;

    2)Use the following example of code to bind param's. This one is setup such that I can use it for any stored proc. If you you're just interested in using it once and a while you can peel out most of the loops...

    sub executeStoredProcTestInfo { $input_parameters = shift; $num_of_output_cursors = shift; $stored_proc_name = shift; $schema = "LOGIN"; $password = "PSWD"; $database = "dbi:Oracle:DBNAME"; $dbh = createConnectionToDB($database, $schema, $password); $sql.= "BEGIN $stored_proc_name("; for ($i=1; $i<=scalar(@$input_parameters)+scalar(@$num_of_output_cu +rsors); $i++) { if($i!= scalar(@$input_parameters)+scalar(@$num_of_output_cursor +s)) { $sql.=":temp_".$i; $sql.=","; } else { $sql.=":temp_".$i; } } $sql.="); END;"; #print $sql,"\n"; $sth = $dbh->prepare($sql); $counter = 1; @var_size_array = @$num_of_output_cursors; @var_input_array = @$input_parameters; foreach $item (@var_input_array) { $var = $counter - 1; $code = "\$sth->bind_param\(\":temp_$counter\", $item \)\;"; eval $code ; #print $code, "\n"; $counter++; } $counter_set = $counter; foreach $item (@$num_of_output_cursors) { $code="\$sth->bind_param_inout(\":temp_$counter\", \\\$temp_$cou +nter, 0, \{ ora_type => ORA_RSET \})\;"; eval $code ; #print $code, "\n"; $counter++; } $sth->execute(); foreach $item (@$num_of_output_cursors) { $code = "\$table = \$temp_$counter_set->fetchall_arrayref\;"; eval $code ; #print $code, "\n"; $counter_set++; } $sth->finish; endConnection($dbh); return $table; }

    3)Run with it... alternatively if you just need to run a stored proc that either has a one row return or no return you could put something together like this example:

    STORED PROC

    CREATE OR REPLACE PROCEDURE get_next_session_id (v_session_id OUT VARCHAR2) IS BEGIN SELECT 'S'||lpad(session_id.nextval,5,'0') INTO v_session_id FROM dual; EXCEPTION WHEN NO_DATA_FOUND THEN raise_application_error(-20000, 'No more rows.'); WHEN OTHERS THEN raise_application_error(-20001, 'There was an undetermi +nable error.'); END get_next_session_id;

    PERL code

    my $rv; my $func = $dbh->prepare(q{ BEGIN get_next_session_id(:rv); END; }); $func->bind_param_inout(":rv", \$rv, 6); $func->execute;

    Finally I want to give credit where credit is due... this is the link where I finally found enough information to put two and two together.

    http://archive.develooper.com/dbi-dev@perl.org/msg00235.html

    CHEERS