Search code examples
perlsqlitexml-parsingperl-module

Error Message: Can't call method "do" on an undefined value


# #################################################
#       Subroutine to add data to the table BlastSearch
#       Could be redone to be more general, but it seems more 
#       efficient to add data as it is pulled from the xml.
# ################################################# 
sub addData {
    my (@data, $dbhandle) = @_;
    print join(", ", @data) . "\n";
    my $sqlcmd = "insert into BlastSearch values('" . join("','",@data) . "')";
    $dbhandle->do($sqlcmd) or die $DBI::errstr;
}

This give the error message "Can't call method "do" on an undefined value." Is there anything in this particular method that is causing the problem? I can add more of the script if needed. My only guess is that it has to do with '@data,' which is filled in the code below:

# #################################################
#       Subroutine to find the:
#           Accession id
#           e-value (Hsp_evalue)
#           number of identites (Hsp_identity)
#       of the top five matches.
# #################################################
sub parseBlastXML {
    my ($file, $dbhandle) = @_;
    my $xml = new XML::Simple();
    my $data = $xml->XMLin($file, forcearray=>[qw(Hit)], keyattr=>[]);
    my $entry_node = $data->{BlastOutput_iterations};
    my $iterhit = $entry_node->{Iteration}->{Iteration_hits}->{Hit};

    #quick find of uniprotID
    my $uniProtID = substr($file, 0, 6);

    my $count = 0;
    foreach my $val (@$iterhit) {
        my @dataarray;
        if ($val->{Hit_hsps} && $count < 5) {
            print "\n";
            print "Hit accession: " . $val->{Hit_accession} . "\n"; 
            print "e-value: " . $val->{Hit_hsps}->{Hsp}->{Hsp_evalue} . "\n"; 
            print "number of ID's: " . $val->{Hit_hsps}->{Hsp}->{Hsp_identity} . "\n";
            push(@dataarray, $val->{Hit_accession}); 
            push(@dataarray, $val->{Hit_hsps}->{Hsp}->{Hsp_evalue}); 
            push(@dataarray, $val->{Hit_hsps}->{Hsp}->{Hsp_identity});
            push(@dataarray, $uniProtID);

            addData(@dataarray, $dbhandle);

            $count ++;
        }
    }
    return $data;
}

Solution

  • The following is a bug as @data will always slurp all the values in @_, leaving $dbhandle undefined.

    sub addData {
        my (@data, $dbhandle) = @_;    # $dbhandle will always be undefined
    

    To fix, you need to reorder your arguments, and always have the array last in the assignment.

    sub addData {
        my ( $dbhandle, @data ) = @_;
    
        ...;
    }
    
    sub parseBlastXML {
        ...;
        addData( $dbhandle, @dataarray );
    

    Note: it would also be possible to pop the dbh off the end of the parameter list. However, such a coding style is not a good idea.