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

Hello Monks,

I am stumped yet again and need to call upon your infinite knowledge. I have the below sub routine but some of the databases it pulls are not valid so when the main body executes it stops/exits.

What I would like to do is keep the script going even if the connection fails - IE have it move onto the next element in the arary (database).

Right now (as you can see) I tried to put the connect into an if statement in the sub_rortine but it dosen't seem to work. This is new to me so not sure if I should just have something in the body or in the subroutine (like i have below)

#!/usr/bin/perl use strict; use warnings; use DBD::mysql; ###################### #### CONFIG VARS ##### ###################### my $output_file = 'Algo_usage.txt'; ###################### #### PRIVATE VARS #### ###################### my $db_user = 'xxxxx'; my $db_pass = 'xxxxx'; my $ignored_text = "'sech05h','gbts01t','smhb07e','QAITtb01','qait33', +'qa'"; ###################### #### MAIN BODY ####### ###################### select(STDOUT); $| = 1; open OUTPUT, ">$output_file"; select(STDOUT); $| = 1; my @book_db = get_book_databases(); foreach my $bookdb (@book_db) { print "Processing on: $bookdb\n"; my $dbh = DBI->connect("DBI:mysql:database=$bookdb:host=xxxxx",$db +_user,$db_pass,{RaiseError=>1})|| die "$DBI::errstr\n"; my $sql = "SELECT COUNT(ID) FROM Items WHERE Content REGEXP '<valu +e name=\"algorithm\">var'"; my $sth = $dbh->prepare ( $sql ); $sth->execute(); while (my @row = $sth->fetchrow_array()) { if ($row[0] > 0) { my $count = $row[0] ? $row[0] : 0; #Get Book Information { my $dbh1 = DBI->connect("DBI:mysql:database=xxxx:host +=xxxx",$db_user,$db_pass,{RaiseError=>1})|| die "$DBI::errstr\n"; my $sql = "SELECT Name, Abbr, Discipline FROM BookList + WHERE SUBSTRING(DatabaseURL,19) = '$bookdb'"; my $sth = $dbh1->prepare ( $sql ); $sth->execute(); while (my @row = $sth->fetchrow_array()) { print OUTPUT "$row[2]\t$row[0]\t$row[1]\t$count\n" +; } $sth->finish(); $dbh1->disconnect(); } } } $sth->finish(); $dbh->disconnect(); } close OUTPUT; ###################### #### PRIVATE SUBS #### ###################### sub get_book_databases { my @book_database_urls; my $dbh = DBI->connect("DBI:mysql:database=xxxx:host=xxxxx",$db_us +er,$db_pass,{RaiseError=>1})|| die "$DBI::errstr\n"; my $sql = "SELECT DISTINCT SUBSTRING(bl.DatabaseURL,19) FROM BookL +ist AS bl WHERE BookClass='SQL' AND Product IN ('BCTest','TestBank',' +Forms','Homework','PrintedTestBank') AND Enabled='1' AND bl.Abbr NOT +IN ($ignored_text)"; my $sth = $dbh->prepare ( $sql ); $sth->execute(); while (my @row = $sth->fetchrow_array()) { print "Testing $row[0] => "; if (my $dbh1 = DBI->connect("DBI:mysql:database=$row[0]:host=x +xxxx",$db_user,$db_pass,{RaiseError=>1})) { print "SUCCESS\n"; push (@book_database_urls, $row[0]); } else { print "FAILED\n" } } $sth->finish(); $dbh->disconnect(); return @book_database_urls; }

Replies are listed 'Best First'.
Re: How do I keep script live and not abort on fail to connect
by almut (Canon) on Oct 08, 2009 at 00:44 UTC
    if (my $dbh1 = DBI->connect("DBI:mysql:database=$row[0]:host=xxxxx",$d +b_user,$db_pass,{RaiseError=>1})) { print "SUCCESS\n"; push (@book_database_urls, $row[0]); }

    As you've explicitly set RaiseError  ({RaiseError=>1}), the connect will die in case of an error, instead of just returning error codes (i.e. undef in this case).  So, either leave RaiseError at its default value "off", or catch the exception by wrapping the connect call in an eval {...} (see die).

Re: How do I keep script live and not abort on fail to connect
by kennethk (Abbot) on Oct 08, 2009 at 00:39 UTC
    You need to consider how you want your code to flow on a failed connect. Right now, all you connect statements are of the form connect or die, so naturally when a connect fails, your die handler gets called and your script dies. So, rather than calling die, you should use some other form of flow control. If you want exit your current subroutine, perhaps connect or return undef; would suit your needs. If you are in a loop and wish to advance to the next cycle, connect or next; might do what you want (see continue or Foreach Loops for implementation details). Once you've decided how you'd like your script to behave following a failed connect, I'd be happy to help you figure out implementation.

    Update: Disregard, as the heart of your issue is addressed by almut below.

Re: How do I keep script live and not abort on fail to connect
by kdmurphy001 (Sexton) on Oct 08, 2009 at 01:48 UTC
    Excellent. That worked flawlessly. Changed the RaiseError to 0 and die to Next. Thanks yet again!