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

Maniacal Monks,

This typical DBI routine:

#!/usr/bin/perl -w use CGI; use CGI::Carp qw(fatalsToBrowser); use DBI; print "Content-type: text/html\n\n"; $db_datasource = "DBI:mysql:$db_name:$db_host"; $dbh = DBI->connect($db_datasource, $db_user_name, $db_password) or di +e("Could not connect!".$dbh -> errstr); print "Successfully connected to database $db_name on host $db_host<p> +\n"; $dbh->disconnect or warn "Disconnection failed: $!\n";
is producing the error:

Can't call method "errstr" on an undefined value

But I could have sworn I just defined $dbh. What gives?

Thanks.




Forget that fear of gravity,
Get a little savagery in your life.

Replies are listed 'Best First'.
Re: Can't call method "errstr" on an undefined value
by davorg (Chancellor) on Jan 22, 2007 at 15:23 UTC
    $dbh = DBI->connect($db_datasource, $db_user_name, $db_password) or die("Could not connect!".$dbh -> errstr);

    If the connect call fails then $dbh will be undefined (i.e. it will contain the value "undef") - so trying to call a method on it will be doomed to failure.

    In this case you want to access errstr as a package variable.

    $dbh = DBI->connect($db_datasource, $db_user_name, $db_password) or die("Could not connect!" . $DBI::errstr);

    Update: Maybe you should have tried checking the DBI documentation as the examples for connect show this usage.

    --
    <http://dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: Can't call method "errstr" on an undefined value
by kyle (Abbot) on Jan 22, 2007 at 15:25 UTC

    The connect call failed, returning an undefined value for $dbh, so you have to use $DBI::errstr to find the error. See the DBI documentation for details.

Re: Can't call method "errstr" on an undefined value
by punch_card_don (Curate) on Jan 22, 2007 at 15:30 UTC
    Yes - that did it.

    Thanks a bunch.




    Forget that fear of gravity,
    Get a little savagery in your life.

      Things like this might strike you another couple of times. And basically the only thing I can say about this is RTFM. But that's too unfriendly. Besides, it is not helpful at all.

      I am not familiar with the DBI modules at all, but as soon as I saw that you where trying to $scalar = Package->constructor or $scalar->method I realised what the cause of the error must've been.

      The funny thing is that, in a way, you noticed it yourself too.

      But I could have sworn I just defined $dbh. What gives?

      Well, did you define it? "Yes," you say, "look: $dbh = DBI->connect(...)"

      Agreed, that looks like you're defining something. Fortunately you're aware some error might occur and you're checking for that...

      ... only to get Perl to complain! Undefined value, wtf?

      Now, this is the time to look at how Perl modules and simple functions often work: on success they return something true (in this case a DBI object). On failure they return something false, mostly undef.

      That is a nifty feature that allows for structures like

      if (doSomething) { print "it worked"; } else { print "oh no"); }
      or even doSomething or print "oh no"

      That, you know. Or at least you use it: $dbh = DBI->connect(...) or die(...);

      Well. To get the code after or to be executed, the code before or must evaluate to a false value. I guess you know that too.

      If DBI->connect simply succeeds, it just returns an object. That can never be false.

      But if we ever want to get to the part after the or, then DBI->connect must return a false value. By definition, this can never be an object. So the $dbh->errstr can never work there.

      I started this reply with stating that you should peek into the manual. Have a look at the documention DBI's connect method.

      If the connect fails (see below), it returns undef and sets both $DBI::err and $DBI::errstr. (It does not explicitly set $!.) You should generally test the return status of connect and print $DBI::errstr if it has failed.

      Besides that the direct answer to your question is just there, it also explicitely states that connect returns undef on failure - you already knew that, as I pointed out - and undef of course never has any methods on it.

      Keep that in mind: if you can do $scalar = something() or doSomethingElse(), then generally $scalar will not hold the value it would've had if something was just succesful.

      I'm sorry if I sounded somewhat patronizing. I'm also sorry if I offended anyone, especially you, punch_card_don, when I said you just need to RTFM. So far for my futile attempt at a disclaimer.