1

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;
}
therobyouknow
  • 6,604
  • 13
  • 56
  • 73
  • 2
    btw, it's a database *handle* (i.e. a way of identifying a database connection), not a *handler* (something that handles something). – ikegami Sep 14 '11 at 17:55

2 Answers2

6
  $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
DVK
  • 126,886
  • 32
  • 213
  • 327
  • +1 and Accepted answer: ($dbhandler) = @_; That was the root cause of my problem. Another question is: is it efficient to pass around the handler (i.e. is it an object) or would it be better to return it as a reference, i.e. new code would be sub connectToDatabase { $databaseHandler = DBI->connect('DBI:mysql:db','db','pwd') or die "Could not connect to database: "; return /$databaseHandler; } and then do: $dbref = connectToDatabase() and deref it by doing ${ dbref } thoughts? – therobyouknow Sep 15 '11 at 12:50
  • PS. that should be ${ $dbref } not ${ dbref } – therobyouknow Sep 15 '11 at 13:02
  • 1
    @Rob - Just as in Java (but for different reasons) there's no "object" being passed around, ever. The value being passed around is **already** a reference to an object, by design of how objects are implemented in the language (in Perl's case, by underlying blessed reference, usually to a hash). So, TL;DR version is "no reason to do `\$databaseHandler;`". – DVK Sep 15 '11 at 16:50
  • 1
    @ROB - ... OK, I fibbed a bit in the last comment in the interests of simplicity - IIRC you can also bless a regular scalar instead of a reference (see inside-out objects), but it doesn't change the answer to your question. "Object" value being passed around is always a blessed scalar, whether a reference or not, and no need exists to take a further reference to it. – DVK Sep 15 '11 at 16:52
  • +1 x2 @DVK good to know about not needing the further reference. I will have to undo it all in the code I just wrote today, in that case. It all worked though! But that's fine. It'll make it more maintainable. – therobyouknow Sep 15 '11 at 21:50
2

You're mixing lexical scope and global scope. my declares a variable as lexical - it cannot be seen outside of its defining scope. Without that, it is (package) global, but you will get a warning about it if you use strict.

so my $databaseHandler inside othermodule1 cannot be seen outside that module. The value can be returned from the function, but that variable name is private to the module.

evil otto
  • 10,348
  • 25
  • 38
  • It might be one of the problems. `use strict`. `use warnings`. – mob Sep 14 '11 at 17:22
  • @mob - I'm not very clear on whether the modules are defined inside the same file as `main` package or not. If they are in the same (my original reading) it's not a problem. If they are NOT, it is, though IMHO stemming from accidentally using the wrong variable name (see my updated answer) and not from intentionally wrong scoping – DVK Sep 14 '11 at 20:50
  • @mob I am use strict use warnings – therobyouknow Sep 15 '11 at 12:52
  • the problem you point out was a typo on my part. I should be returning the handle in connectToDatabase. I've also asked whether it would be efficient or not to return the handle, or a reference to it, using return \$databaseHandler ( into $dbh - which I should really then call $dbhref ) and then deref using ${ $dbh } to get at the handle. Just wondered if I was introducing inefficiency if the handle is an object that I am passing around. – therobyouknow Sep 15 '11 at 12:55
  • +1 @DVK that's not the root problem - you fixed that. Thankyou. But he is right that it is (another) problem, as I've said in my earlier comment I should be returning a value from connectToDatabase - actually this is a typo, my original code does not have this fault. – therobyouknow Sep 15 '11 at 12:57
  • So @evil otto I've +1'd your answer because of that ( I should be returning a value from connectToDatabase ). I did not use original code in this question because the naming includes company specifics. – therobyouknow Sep 15 '11 at 12:59