alex.TT2 has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I'm trying to call a stored procedure in an Oracle database multiple times and have them run in parallel using Parallel::ForkManager. To do so, I've created multiple database and statement handles that will be called one at a time within the parallel loop based on the loop counter value. However, I continue to receive multiple instances of the following error each time I run the program:

DBD::Oracle::db do failed: handle 2 is owned by thread 158fe8 not current thread 3c30cb8 (handles can't be shared between threads and your driver may need a CLONE method added) at test6.pl line ...

The code is below. What am I doing wrong?

Thank you for your help!

#!/usr/bin/perl use Parallel::ForkManager; use DBI; use strict; my $dbh=DBI->connect("dbi:Oracle:dbname","username","password",{RaiseE +rror => 1 , PrintError => 0}); my $dbh1=DBI->connect("dbi:Oracle:dbname","username","password",{Raise +Error => 1 , PrintError => 0}); my $dbh2=DBI->connect("dbi:Oracle:dbname","username","password",{Raise +Error => 1 , PrintError => 0}); my $dbh3=DBI->connect("dbi:Oracle:dbname","username","password",{Raise +Error => 1 , PrintError => 0}); my ($sth1, $sth2, $sth3); # statement handles my ($sqlstmt1, $sqlstmt2, $sqlstmt3); # statements to be execut +ed my @num_array = ("1", "2", "3"); my $mid = $#num_array; my $t = localtime(); my $pm = new Parallel::ForkManager($mid + 1); for (my $mid_cnt = 0; $mid_cnt <= $mid; $mid_cnt++) { $pm->start and sleep 30 and next; ## Beginning of parallel +process. print $x "For Number $num_array[$mid_cnt]:\n"; if ($num_array[$mid_cnt] == 0) { $t = localtime(); print "Calling procedure for Number $num_array[$mid_cnt] at $t +\n"; $sqlstmt1 = "BEGIN TEST_PROC($num_array[$mid_cnt]); end;"; $sth1 = $dbh1->do($sqlstmt1) or die $dbh1->errstr; $t = localtime(); print "Done with procedure for Number $num_array[$mid_cnt] at +$t\n\n"; } elsif ($num_array[$mid_cnt] == 1) { $t = localtime(); print "Calling procedure for Number $num_array[$mid_cnt] at $t +\n"; $sqlstmt2 = "BEGIN TEST_PROC($num_array[$mid_cnt]); end;"; $sth2 = $dbh2->do($sqlstmt2) or die $dbh2->errstr; $t = localtime(); print "Done with procedure for Number $num_array[$mid_cnt] at +$t\n\n"; } else { $t = localtime(); print "Calling procedure for Number $num_array[$mid_cnt] at $t +\n"; $sqlstmt3 = "BEGIN TEST_PROC($num_array[$mid_cnt]); end;"; $sth3 = $dbh3->do($sqlstmt3) or die $dbh3->errstr; $t = localtime(); print "Done with procedure for Number $num_array[$mid_cnt] at +$t\n\n"; } $pm->finish; ## End of parallel process. } $pm->wait_all_children; $dbh1 -> disconnect; $dbh2 -> disconnect; $dbh3 -> disconnect;
  • Comment on Error Using Multiple Database Handles (DBD::Oracle::db do failed: handle 2 is owned by thread...)
  • Download Code

Replies are listed 'Best First'.
Re: Error Using Multiple Database Handles (DBD::Oracle::db do failed: handle 2 is owned by thread...)
by ikegami (Patriarch) on Jan 06, 2011 at 20:59 UTC
    What happens when you have two people talking to the third at the same time? A communication failure. You're using the same socket in two processes. Create your database connections in the same process that uses them.
Re: Error Using Multiple Database Handles (DBD::Oracle::db do failed: handle 2 is owned by thread...)
by Anonyrnous Monk (Hermit) on Jan 06, 2011 at 21:07 UTC

    I think the DBI/DBD checks if a method is being called from the same thread or process that the respective handle was created in (see the docs). In other words, it croaks in your case, because the do method is being called from a cloned/forked process as created by Parallel::ForkManager...

    You probably need to create a pool of persistent processes (or threads) and open the handles after having forked. Then delegate your queries to the appropriate processes in the pool.

Re: Error Using Multiple Database Handles (DBD::Oracle::db do failed: handle 2 is owned by thread...)
by alex.TT2 (Initiate) on Jan 08, 2011 at 23:32 UTC
    Thanks for the replies. I setup the db handles in forked subroutines, and everything went as expected.