Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Can't get multiple Parallel::ForkManager threads connecting to DBD::Pg database

by perlygapes (Sexton)
on Jul 21, 2021 at 14:02 UTC ( [id://11135267]=perlquestion: print w/replies, xml ) Need Help??

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

Beloved Brewing Brethren Beholding Bitwise Borders,

This follows on from my previous questions regarding Parallel::ForkManager and DBD::Pg.
I have posted this to Stackoverflow, but haven't got a working answer...
I am trying to create DB connections from multiple child threads, each of which is spawned as a child using Parallel::ForkManager.
I cannot get this to work. I basically keep having the same sharing error - DBH cannot be shared between threads.

Here is my example. I have included both a create_dbh and a clone_dbh sub-routine as options. Neither work.
SQL TABLE SCRIPT:
CREATE TABLE mytable ( field1 varchar(24) NULL, field2 varchar(24) NULL, field3 varchar(24) NULL, field4 varchar(24) NULL, field5 varchar(24) NULL, pk serial NOT NULL, CONSTRAINT mytable_pk PRIMARY KEY (pk) );
PERL SCRIPT
use 5.24.0; use strict; use warnings; use Parallel::ForkManager; use SQL::Abstract; use DBI ':sql_types'; use DBD::Pg qw/:pg_types/; #@codes = ("A"); # testing single thread my @codes = ("A","B","F","M","S"); # testing multi-thread my %varset; ################################################################ # connect to db ################################################################ my $dsn = 'DBI:Pg:dbname=$ENV{DB_NAME}'; my $userid = $ENV{DBI_USER}; my $sesame = $ENV{DBI_PASS}; my %dbh; # hash for storing dbh handles my $dbh = DBI->connect($dsn, $userid, $sesame, { AutoCommit => 1, RaiseError => 1, PrintError => 1 }) or die "Connection failed!\n" . $DBI::errstr; ################################################################ # test db connection ################################################################ my $me = $dbh->{Driver}{Name}; my $sversion = $dbh->{pg_server_version}; print "DBI is version $DBI::VERSION, " . "I am $me, " . "version of DBD::Pg is $DBD::Pg::VERSION, " . "server is $sversion\n"; print "Name: $dbh->{Name}\n"; ################################################################ # prepare array and hash for matching db columns ################################################################ my %columns; # hash for persistent mapping of column-values my @columns; # deterministic - $values[$columns{$column}]; set_columns(); # define column<->value mapping for db table my $placeholders = join(", ", map { '?' } @columns); ################################################################ # Build the SELECT SQL statement ################################################################ my $sql_select_statement = qq(SELECT count(*) FROM mytable WHERE id = ?;); ################################################################ # Build the INSERT SQL statement ################################################################ my $sql_insert_statement = "INSERT INTO mytable (" . join(", ", @columns) # column names . ") VALUES ($placeholders)"; ################################################################ # create clones of database handle and SQL statements for threads ################################################################ my %sth_select_code; my %sth_insert_code; #for my $code (@codes) { # $dbh{$code} = $dbh->clone(); # # prepare the SELECT statement handle # $sth_select_code{$code} = $dbh{$code}->prepare_cached($sql_select +_statement); # # prepare the INSERT statement handle # $sth_insert_code{$code} = $dbh{$code}->prepare_cached($sql_insert +_statement); #} ################################################################ # create Parallel::ForkManager object for @codes ################################################################ my $optimization = Parallel::ForkManager->new(scalar @codes); $optimization->run_on_start(sub{ my ($pid,$ident) = @_; print "Starting $ident under process id $pid\n"; }); $optimization->run_on_finish(sub{ my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_; }); my $thread_count = 0; OPTIMIZATION: for my $code (@codes) { $thread_count++; print "Thread $thread_count running for $code\n"; # fork optimization threads - per code $optimization->start($code) and next OPTIMIZATION; if ($code =~ m/A/i) { sub_a("A"); } elsif ($code =~ m/B/i) { sub_b("B"); } elsif ($code =~ m/F/i) { sub_f("F"); } elsif ($code =~ m/M/i) { sub_m("M"); } elsif ($code =~ m/S/i) { sub_s("S"); } print "\$optimization->finish on child $code\n"; $optimization->finish(0); } print "\$optimization->wait_all_children() is waiting...\n"; $optimization->wait_all_children(); ################################################################ # disconnect from database ################################################################ for my $code (@codes) { $sth_select_code{$code}->finish(); $sth_insert_code{$code}->finish(); $dbh{$code}->disconnect; } $dbh->disconnect; ################################################################ # end ################################################################ exit; ################################################################ sub sub_a { ################################################################ my $code = shift; # Code my @values; # clone_dbh($code); create_dbh($code); # my ($dbh, $sel_sth, $ins_sth) = create_dbh($code); # generate values specific to A $varset{field2} = 'a_f1'; # for illustrative purposes $varset{field3} = 'a_f2'; $varset{field4} = 'a_f3'; $varset{field5} = 'a_f4'; foreach my $key (keys %varset) { my $column = $key; # the column name as key my $value = $varset{$key}; # the column value (field variable +) $values[$columns{$column}] = $value; # add to list of column v +alues } $values[0] = $code; write_to_db($code, @values); } ################################################################ sub sub_b { ################################################################ my $code = shift; # Code my @values; # clone_dbh($code); create_dbh($code); # my ($dbh, $sel_sth, $ins_sth) = create_dbh($code); # generate values specific to B $varset{field2} = 'b_f1'; # for illustrative purposes $varset{field3} = 'b_f2'; $varset{field4} = 'b_f3'; $varset{field5} = 'b_f4'; foreach my $key (keys %varset) { my $column = $key; # the column name as key my $value = $varset{$key}; # the column value (field variable +) $values[$columns{$column}] = $value; # add to list of column v +alues } $values[0] = $code; write_to_db($code, @values); } ################################################################ sub sub_f { ################################################################ my $code = shift; # Code my @values; # clone_dbh($code); create_dbh($code); # my ($dbh, $sel_sth, $ins_sth) = create_dbh($code); # generate values specific to F $varset{field2} = 'f_f1'; # for illustrative purposes $varset{field3} = 'f_f2'; $varset{field4} = 'f_f3'; $varset{field5} = 'f_f4'; foreach my $key (keys %varset) { my $column = $key; # the column name as key my $value = $varset{$key}; # the column value (field variable +) $values[$columns{$column}] = $value; # add to list of column v +alues } $values[0] = $code; write_to_db($code, @values); } ################################################################ sub sub_m { ################################################################ my $code = shift; # Code my @values; # clone_dbh($code); create_dbh($code); # my ($dbh, $sel_sth, $ins_sth) = create_dbh($code); # generate values specific to M $varset{field2} = 'm_f1'; # for illustrative purposes $varset{field3} = 'm_f2'; $varset{field4} = 'm_f3'; $varset{field5} = 'm_f4'; foreach my $key (keys %varset) { my $column = $key; # the column name as key my $value = $varset{$key}; # the column value (field variable +) $values[$columns{$column}] = $value; # add to list of column v +alues } $values[0] = $code; write_to_db($code, @values); } ################################################################ sub sub_s { ################################################################ my $code = shift; # Code my @values; # clone_dbh($code); create_dbh($code); # my ($dbh, $sel_sth, $ins_sth) = create_dbh($code); # generate values specific to S $varset{field2} = 's_f1'; # for illustrative purposes $varset{field3} = 's_f2'; $varset{field4} = 's_f3'; $varset{field5} = 's_f4'; foreach my $key (keys %varset) { my $column = $key; # the column name as key my $value = $varset{$key}; # the column value (field variable +) $values[$columns{$column}] = $value; # add to list of column v +alues } $values[0] = $code; write_to_db($code, @values); } ################################################################ sub create_dbh { ################################################################ my $code = shift; $dbh{$code} = DBI->connect($dsn, $userid, $sesame, { AutoCommit => 1, RaiseError => 1, PrintError => 1 }) or die "Connection failed!\n" . $DBI::errstr; # did it work? are we there yet? my $me = $dbh{$code}->{Driver}{Name}; my $sversion = $dbh{$code}->{pg_server_version}; print "DBI is version $DBI::VERSION, " . "I am $me, " . "version of DBD::Pg is $DBD::Pg::VERSION, " . "server is $sversion\n"; print "Name: $dbh->{Name}\n"; # prepare the SELECT statement handle $sth_select_code{$code} = $dbh{$code}->prepare_cached($sql_select_ +statement); # prepare the INSERT statement handle $sth_insert_code{$code} = $dbh{$code}->prepare_cached($sql_insert_ +statement); } ################################################################ sub clone_dbh { ################################################################ my $code = shift; $dbh{$code} = $dbh->clone(); # prepare the SELECT statement handle $sth_select_code{$code} = $dbh{$code}->prepare_cached($sql_select_ +statement); # prepare the INSERT statement handle $sth_insert_code{$code} = $dbh{$code}->prepare_cached($sql_insert_ +statement); } ################################################################ sub write_to_db { ################################################################ my ($code, @values) = shift @_; my $rv_code = $sth_select_code{$code}->execute($code); if($rv_code < 0) { print $DBI::errstr; } my @row = $sth_select_code{$code}->fetchrow_array(); # if the SELECT found no existing records for this strategy, then +INSERT it unless ($row[0] > 0) { # INSERT settings into 'mytable' $sth_insert_code{$code}->execute(@values); } } ################################################################ sub set_columns { ################################################################ $columns{field1} = 0; $columns{field2} = 1; $columns{field3} = 2; $columns{field4} = 3; $columns{field5} = 4; $columns[0] = 'field1'; $columns[1] = 'field2'; $columns[2] = 'field3'; $columns[3] = 'field4'; $columns[4] = 'field5'; }
Do I have to pass dbh and statement handles to the create_dbh sub explicitly from within the calling sub_x thread?
Do I have to return the handles or handle_refs from create_dbh back to calling sub_x thread?
I don't know how to get around this, but it seems like a lexical scope or object/memory access issue.

Any advice?

Replies are listed 'Best First'.
Re: Can't get multiple Parallel::ForkManager threads connecting to DBD::Pg database
by Corion (Patriarch) on Jul 21, 2021 at 14:17 UTC

    Usually, database drivers don't like fork(), or rather, you should create the database connection after forking.

    If you move creating the database connection into your fork loop (or maybe into run_on_start), maybe things start working?

      I got it working using the following code.

      In short, this code creates multiple threads (maybe processes, not sure) using `Parallel::ForkManager`, and each thread gets it's own database handle and associated statement handles.
      It abstracts `dbh` and `statement` handle creation to a sub, and also `db write` and `db handle close` functions.
      use 5.24.0; use strict; use warnings; use Parallel::ForkManager; use SQL::Abstract; use DBI ':sql_types'; use DBD::Pg qw/:pg_types/; #my @codes = ("A"); # testing single thread my @codes = ("A","B","F","M","S"); # testing multi-thread my %varset; ################################################################ # get db connection info ################################################################ my $dsn = 'DBI:Pg:dbname=mt4_test'; my $userid = $ENV{DBI_USER}; my $sesame = $ENV{DBI_PASS}; my %dbh; # hash for storing dbh handles ################################################################ # prepare array and hash for matching db columns ################################################################ my %columns; # hash for persistent mapping of column-values my @columns; # deterministic - $values[$columns{$column}]; set_columns(); # define column<->value mapping for db table my $placeholders = join(", ", map { '?' } @columns); ################################################################ # Build the SELECT SQL statement ################################################################ my $sql_select_statement = qq(SELECT count(*) FROM mytable WHERE field1 = ?;); ################################################################ # Build the INSERT SQL statement ################################################################ my $sql_insert_statement = "INSERT INTO mytable (" . join(", ", @columns) # column names . ") VALUES ($placeholders)"; ################################################################ # hash for storing SQL statement handles for threads ################################################################ my %sth_select_code; my %sth_insert_code; ################################################################ # create Parallel::ForkManager object for @codes ################################################################ my $optimization = Parallel::ForkManager->new(scalar @codes); $optimization->run_on_start(sub{ my ($pid,$ident) = @_; print "Starting $ident under process id $pid\n"; }); $optimization->run_on_finish(sub{ my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_; }); my $thread_count = 0; OPTIMIZATION: for my $code (@codes) { $thread_count++; print "Thread $thread_count running for $code\n"; # fork optimization threads - per code if (scalar @codes > 1) { $optimization->start($code) and next OPTIMIZATION; } else { $optimization->start($code); } launch_sub($code); print "\$optimization->finish on child $code\n"; $optimization->finish(0); } print "\$optimization->wait_all_children() is waiting...\n"; $optimization->wait_all_children(); ################################################################ # THE END ################################################################ exit; ################################################################ ################################################################ sub launch_sub { ################################################################ my $code = shift; if ($code =~ m/A/i) { sub_a("A"); } elsif ($code =~ m/B/i) { sub_b("B"); } elsif ($code =~ m/F/i) { sub_f("F"); } elsif ($code =~ m/M/i) { sub_m("M"); } elsif ($code =~ m/S/i) { sub_s("S"); } } ################################################################ sub sub_a { ################################################################ my $code = shift; # Code my @values; my ($dbh, $sel_sth, $ins_sth) = create_dbh(\$dbh{$code},\$sth_sele +ct_code{$code},\$sth_insert_code{$code}); # generate values specific to A $varset{field2} = 'a_f1'; # for illustrative purposes $varset{field3} = 'a_f2'; $varset{field4} = 'a_f3'; $varset{field5} = 'a_f4'; foreach my $key (keys %varset) { my $column = $key; # the column name as key my $value = $varset{$key}; # the column value (field variable +) $values[$columns{$column}] = $value; # add to list of column v +alues } $values[0] = $code; write_to_db($code, @values); disconnect_dbh(\$dbh{$code},\$sth_select_code{$code},\$sth_insert_ +code{$code}); } ################################################################ sub sub_b { ################################################################ my $code = shift; # Code my @values; my ($dbh, $sel_sth, $ins_sth) = create_dbh(\$dbh{$code},\$sth_sele +ct_code{$code},\$sth_insert_code{$code}); # generate values specific to B $varset{field2} = 'b_f1'; # for illustrative purposes $varset{field3} = 'b_f2'; $varset{field4} = 'b_f3'; $varset{field5} = 'b_f4'; foreach my $key (keys %varset) { my $column = $key; # the column name as key my $value = $varset{$key}; # the column value (field variable +) $values[$columns{$column}] = $value; # add to list of column v +alues } $values[0] = $code; write_to_db($code, @values); disconnect_dbh(\$dbh{$code},\$sth_select_code{$code},\$sth_insert_ +code{$code}); } ################################################################ sub sub_f { ################################################################ my $code = shift; # Code my @values; my ($dbh, $sel_sth, $ins_sth) = create_dbh(\$dbh{$code},\$sth_sele +ct_code{$code},\$sth_insert_code{$code}); # generate values specific to F $varset{field2} = 'f_f1'; # for illustrative purposes $varset{field3} = 'f_f2'; $varset{field4} = 'f_f3'; $varset{field5} = 'f_f4'; foreach my $key (keys %varset) { my $column = $key; # the column name as key my $value = $varset{$key}; # the column value (field variable +) $values[$columns{$column}] = $value; # add to list of column v +alues } $values[0] = $code; write_to_db($code, @values); disconnect_dbh(\$dbh{$code},\$sth_select_code{$code},\$sth_insert_ +code{$code}); } ################################################################ sub sub_m { ################################################################ my $code = shift; # Code my @values; my ($dbh, $sel_sth, $ins_sth) = create_dbh(\$dbh{$code},\$sth_sele +ct_code{$code},\$sth_insert_code{$code}); # generate values specific to M $varset{field2} = 'm_f1'; # for illustrative purposes $varset{field3} = 'm_f2'; $varset{field4} = 'm_f3'; $varset{field5} = 'm_f4'; foreach my $key (keys %varset) { my $column = $key; # the column name as key my $value = $varset{$key}; # the column value (field variable +) $values[$columns{$column}] = $value; # add to list of column v +alues } $values[0] = $code; write_to_db($code, @values); disconnect_dbh(\$dbh{$code},\$sth_select_code{$code},\$sth_insert_ +code{$code}); } ################################################################ sub sub_s { ################################################################ my $code = shift; # Code my @values; my ($dbh, $sel_sth, $ins_sth) = create_dbh(\$dbh{$code},\$sth_sele +ct_code{$code},\$sth_insert_code{$code}); # generate values specific to S $varset{field2} = 's_f1'; # for illustrative purposes $varset{field3} = 's_f2'; $varset{field4} = 's_f3'; $varset{field5} = 's_f4'; foreach my $key (keys %varset) { my $column = $key; # the column name as key my $value = $varset{$key}; # the column value (field variable +) $values[$columns{$column}] = $value; # add to list of column v +alues } $values[0] = $code; write_to_db($code, @values); disconnect_dbh(\$dbh{$code},\$sth_select_code{$code},\$sth_insert_ +code{$code}); } ################################################################ sub create_dbh { ################################################################ my $dbh_ref = shift; my $sel_ref = shift; my $ins_ref = shift; ${$dbh_ref} = DBI->connect($dsn, $userid, $sesame, { AutoCommit => 1, RaiseError => 1, PrintError => 1 }) or die "Connection failed!\n" . $DBI::errstr; # did it work? are we there yet? my $me = ${$dbh_ref}->{Driver}{Name}; my $sversion = ${$dbh_ref}->{pg_server_version}; print "DBI is version $DBI::VERSION, " . "I am $me, " . "version of DBD::Pg is $DBD::Pg::VERSION, " . "server is $sversion\n"; print "Name: ${$dbh_ref}->{Name}\n"; # prepare the SELECT statement handle ${$sel_ref} = ${$dbh_ref}->prepare_cached($sql_select_statement); # prepare the INSERT statement handle ${$ins_ref} = ${$dbh_ref}->prepare_cached($sql_insert_statement); } ################################################################ sub write_to_db { ################################################################ my ($code, @values) = @_; my $rv_code = $sth_select_code{$code}->execute($code); say "SQL SELECT for $code: rv_code = $rv_code"; if($rv_code < 0) { print $DBI::errstr; } my @row = $sth_select_code{$code}->fetchrow_array(); # if the SELECT found no existing records for this strategy, then +INSERT it unless ($row[0] > 0) { # INSERT settings into 'mytable' $sth_insert_code{$code}->execute(@values); say "SQL INSERT for $code"; } } ################################################################ sub disconnect_dbh { ################################################################ my $dbh_ref = shift; my $sel_ref = shift; my $ins_ref = shift; ${$sel_ref}->finish(); ${$ins_ref}->finish(); ${$dbh_ref}->disconnect; say "disconnected dbh_ref: $dbh_ref"; } ################################################################ sub set_columns { ################################################################ $columns{field1} = 0; $columns{field2} = 1; $columns{field3} = 2; $columns{field4} = 3; $columns{field5} = 4; $columns[0] = 'field1'; $columns[1] = 'field2'; $columns[2] = 'field3'; $columns[3] = 'field4'; $columns[4] = 'field5'; }
Re: Can't get multiple Parallel::ForkManager threads connecting to DBD::Pg database
by NetWallah (Canon) on Jul 22, 2021 at 04:04 UTC
    There is a similar, reasonable answer on StackOverflow relating to Postgres parallel access via python.

    You can't sanely share a DB connection across processes like that. You can sort-of share a connection between threads, but only if you make sure the connection is only used by one thread at a time. That won't work between processes because there's client-side state for the connection stored in the client's address space.

                    "The difficult we do today; the impossible takes a little longer."

Re: Can't get multiple Parallel::ForkManager threads connecting to DBD::Pg database
by karlgoethebier (Abbot) on Jul 24, 2021 at 11:26 UTC

    Just an idea. Or a study or a sketch. As you like:

    #!/usr/bin/env perl use strict; use warnings; use threads; use MCE::Hobo; use MCE::Shared; use DBI; use Data::Dump; use feature qw(say); use constant AMOUNT => 1; use constant MAX => 100; use constant DB => qq(dbi:SQLite:testomato.db); say qq($0 $$); sleep AMOUNT; my $shared = MCE::Shared->array(); my $cores = MCE::Util::get_ncpu(); MCE::Hobo->init( max_workers => $cores ); for my $id ( 1 .. MAX ) { my $hobo = MCE::Hobo->create( \&task ); say qq( $id ) . $hobo -> pid(); } MCE::Hobo->wait_all(); my $result = $shared->export; dd $result; sub task { my $db = DBI->connect( DB, "", "") or die DBI->errstr; my $result = $db->selectall_arrayref("SELECT * FROM fubar"); $db -> disconnect; $shared -> push($result); sleep AMOUNT; } __END__

    The flow can be nicely observed in the process table.

    Here is how to generate the example db:

    Karls-Mac-mini:db karl$ sqlite3 testomato.db "create table if not exis +ts fubar(id INTEGER PRIMARY KEY, name TEXT, surname TEXT);" Karls-Mac-mini:db karl$ sqlite3 testomato.db "insert into fubar (name, + surname) values ('karl','goethebier');" Karls-Mac-mini:db karl$ sqlite3 testomato.db "select * from fubar"; 1|karl|goethebier Karls-Mac-mini:db karl$

    As i don't have Postgres on my box and i don't want it i used SQLite to show the basic idea. A database is a database. I don't know if this example is helpful. But i guess at least it might be interesting. Best regards.

    «The Crux of the Biscuit is the Apostrophe»

Re: Can't get multiple Parallel::ForkManager threads connecting to DBD::Pg database
by karlgoethebier (Abbot) on Jul 27, 2021 at 13:44 UTC
Re: Can't get multiple Parallel::ForkManager threads connecting to DBD::Pg database
by karlgoethebier (Abbot) on Jul 22, 2021 at 08:51 UTC
    «…multiple child threads…»

    BTW and just for my understanding and my mental health: As you use Parallel::ForkManager you fork. The name is the program. You don’t start new threads but another process. As far as I remember. And it may be that this has something to do with my Denglish. Who knows. Best regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

      The error output indicates these are different threads, but I am aware that the process-to-thread relationship is like a parent-children relationship (one parent to many children). So these may or may not be separate processes.
      Here is the output:
      USERNAME@COMPUTER C:\Users\USERNAME\eclipse-workspace\Project-X # C:\Users\USERNAME\eclipse-workspace\WORKSPACE\dbi_test.pl DBI is version 1.643, I am Pg, version of DBD::Pg is 3.10.4, server is + 120002 Name: dbname=db_name Thread 1 running for A Starting A under process id -6452 Thread 2 running for B Starting B under process id -8912 Thread 3 running for F DBD::Pg::db clone failed: handle 2 is owned by thread 33b7e8 not curre +nt thread 3f29dc8 (handles can't be shared between threads and your d +river may need a CLONE method added) at C:\Users\USERNAME\eclipse-wor +kspace\WORKSPACE\dbi_test.pl line 297. DBI is version 1.643, I am Pg, version of DBD::Pg is 3.10.4, server is + 120002 DBD::Pg::db FETCH failed: handle 2 is owned by thread 33b7e8 not curre +nt thread 36a1cd8 (handles can't be shared between threads and your d +river may need a CLONE method added) at C:\Users\USERNAME\eclipse-wor +kspace\WORKSPACE\dbi_test.pl line 281. Starting F under process id -8840 Thread 4 running for M DBD::Pg::db clone failed: handle 2 is owned by thread 33b7e8 not curre +nt thread 59f55b8 (handles can't be shared between threads and your d +river may need a CLONE method added) at C:\Users\USERNAME\eclipse-wor +kspace\WORKSPACE\dbi_test.pl line 297. Starting M under process id -9280 Thread 5 running for S DBD::Pg::db clone failed: handle 2 is owned by thread 33b7e8 not curre +nt thread 5d7ed18 (handles can't be shared between threads and your d +river may need a CLONE method added) at C:\Users\USERNAME\eclipse-wor +kspace\WORKSPACE\dbi_test.pl line 297. Starting S under process id -10640 $optimization->wait_all_children() is waiting... DBD::Pg::db clone failed: handle 2 is owned by thread 33b7e8 not curre +nt thread 5d7b358 (handles can't be shared between threads and your d +river may need a CLONE method added) at C:\Users\USERNAME\eclipse-wor +kspace\WORKSPACE\dbi_test.pl line 297. Can't call method "finish" on an undefined value at C:\Users\USERNAME\ +eclipse-workspace\WORKSPACE\dbi_test.pl line 126. USERNAME@COMPUTER C:\Users\USERNAME\eclipse-workspace\Project-X #

        Apples and pears…

        # YOU Thread 1 running for A Starting A under process id -6452 Thread 2 running for B Starting B under process id -8912 Thread 3 running for F # FROM HERE DBD::Pg DBD::Pg::db clone failed: handle 2 is owned by thread 33b7e8 not curre +nt thread 3f29dc8 (handles can't be shared between threads and your d +river may need a CLONE method added) at C:\Users\USERNAME\eclipse-wor +kspace\WORKSPACE\dbi_test.pl line 297.

        «The Crux of the Biscuit is the Apostrophe»

A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11135267]
Approved by philipbailey
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (7)
As of 2024-04-18 07:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found