Search code examples
perlfunctionscopedbiprepare

In Perl does the object/handle returned from DBI->connect go out of scope if passed between functions (by return or input param)?


I get this error

Can't call method "prepare" without a package or object reference at ... [in createSqlTable line starting with my $execute].

with code similar to the following (snippets):

use othermodule1;
use othermodule2;

my $dbh = othermodule1::connectToDatabase();

if ( defined $databaseHandler )
{
  print "\ndatabaseHandler is defined here after calling connectToDatabase\n";
}

othermodule2::setDatabaseHandler( $databaseHandler );

othermodule2::createSqlTable();

othermodule1:

my $databaseHandler = unset;

sub connectToDatabase
{
  $databaseHandler = DBI->connect('DBI:mysql:db','db','pwd') or die "Could not    connect to database: ";
}

othermodule2:

my $dbhandler = unset;

sub setDatabaseHandler
{
  $dbhandler = @_;
}


sub createSqlTable()
{
  my $query = "CREATE TABLE atable ( a CHAR(30) NULL, b CHAR(30) NULL )"; # etc...

  my $execute = $dbhandler ->prepare($myquery) or die "Couldn't prepare statement: " . $dbhandler->errstr;
  $execute->execute or die "Couldn't execute statement: " . $dbhandler->errstr;
}

Solution

  •   $dbhandler = @_;
    

    Is the problem. You are assigning in a scalar context - so the value of scalar(@_) will be assigned to $dbhandler - in this case, 1, since you passed 1-element parameter list.

    It should be: ($dbhandler) = @_; to use the list context or as an alternate idiom, $dbhandler = shift;

    Contrast:

    $ perl -e 'sub x { $x = @_ ; print "$x\n"} ; x(33);'
    1
    $ perl -e 'sub x { ($x) = @_ ; print "$x\n"} ; x(33);'
    33
    

    A second, unrelated problem, is that you misnamed your variable. You have $dbh in main script yet after assigning it you keep using $databaseHandler instead.

    if ( defined $databaseHandler )  # BAD
    if ( defined $dbh )              # GOOD
    

    The above mistake (using $databaseHandler instead of $dbh) does not show up/matter if your modules are defined in the same file as your main script above it, because first module's my $databaseHandler declaration places that variable in scope of the rest of the file (main script included). But it will STOP working, if your module is in its own file (second example below)

    $ cat /tmp/p1.pm
    package p1;
    my $v = undef;
    sub x {
        $v = 3;
    }
    1;
    $ cat /tmp/x1.pl
    use p1;
    my $c = p1::x();
    my $v_print =  defined $v ? $v : "_UNDEF_";
    print "v=$v_print\nc=$c\n";
    
    $ perl -I /tmp /tmp/x1.pl
    v=_UNDEF_
    c=3
    
    ###############################################
    
    $ cat /tmp/x2.pl
    package p1;
    my $v = undef;
    sub x {
        $v = 3;
    }
    1; # END package p1
    package main;
    my $c = p1::x();
    my $v_print =  defined $v ? $v : "_UNDEF_";
    print "v=$v_print\nc=$c\n";
    
    $ perl /tmp/x2.pl
    v=3
    c=3