tags:

views:

192

answers:

6

Why does this code fail silently? How do I get it to show me exactly what the SQL error is?

$dbh=DBI->connect($db_name,$db_user,$db_pass);

I modified the code to look like this:

$dbh=DBI->connect($db_name,$db_user,$db_pass)
    or die("could not connect to db: $db_name");

Which instead of allowing me to use $dbh unassigned, it will fail as expected, but it does not tell me exactly why it's failing. The values of $db_name etc, are all set with valid values as far as I can see.

I know the real error (the MySQL server is actually not running) but for future reference, I'd like to see the true error in case I am causing an auth failure for example.

+1  A: 

Aha, the error is stored in $DBI::errstr, so I can modify my code like so:

$dbh=DBI->connect($db_name,$db_user,$db_pass)
    or die("could not connect to db: $DBI::errstr");

According to the documentation, it fails silently by design.

nbolton
You don't have to assume. It's explained in the DBI docs. :)
brian d foy
@brian Ah, of course. How silly of me, I should always re-read the documentation to make sure I don't miss anything.
nbolton
+1  A: 

Pass RaiseError => 1 as an option when connecting, then your script will die on errors. My Perl shop has a standard configuration of:

{
  RaiseError => 1,
  PrintError => 0,
  AutoCommit => 1,
  mysql_auto_reconnect => 1,
}
rjh
Nice. How do I set a standard configuration?
nbolton
There might be an official way; you could subclass DBI and override the connect method. Our projects have their own specialised DBH-dispensing modules that load configuration from YAML.
rjh
No problem, thanks for the tip.
nbolton
I also hide the DBI stuff behind application level code. If you decide to switch to RoseDB or something else later, the application level code stays the same although the implementation differs. Whether it's subclasses or delegation, it's still hiding the details so your application is loosely coupled to it. :)
brian d foy
A: 

Your use of 'or' is a syntax error. The listed code should not run at all.

You want:

$dbh=DBI->connect($db_name,$db_user,$db_pass) 
    or die("could not connect to db: $db_name");

Note that or die... is part of the original statement, not a new statement.

Nicholas Knight
Oops, typo. Well spotted. I've corrected this now. But maybe your answer should have been a comment?
nbolton
Don't type in code. Cut and paste the actual code that you are using. I've mentioned this a few times already, but you're sorta abusing people's time to answer the problem you present, like the syntax error, rather than showing the actual code you are using. You can get better answers and ease the burden on the people giving you free help, so please do so. :)
brian d foy
@brian Yes you're totally right, I'm so sorry to have wasted your time; I can only imagine how much you hate nagging me about this. ;)
nbolton
+6  A: 

You're not seeing why the connect fails because you aren't doing what the DBI show you to do. The error will be in the $DBI::errstr variable:

$dbh = DBI->connect($data_source, $username, $password)
     or die $DBI::errstr;

Ensure you read the documentation for any functions or methods that you want to use. :)

brian d foy
Okie dokes, I will use this from now on.
nbolton
I now see your own answer. I suspect you discovered it at the same time I was writing it because I think you submitted your answer slightly before mine. Don't feel bad about accepting your answer if its the right one (not that I'm complaining) :)
brian d foy
Haha, don't worry, I like your code better.
nbolton
A: 

Try including the value of $! in your die message.

$dbh = DBI->connect($db_name, $db_user, $db_pass)
  or die("could not connect to db ($db_name): $!");

See $! in perldoc perlvar.

fredden
Ah, interesting.
nbolton
A: 

Here's my usage of rjh's answer. I think I prefer this over the die approach, but not sure yet...

$dbh = DBI->connect($data_source, $username, $password, { RaiseError => 1 });
nbolton