Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??
my $crid = $crm->db->selectrow_array
$crid is undef

Why am I not surprised? Let's RTFM:

selectrow_array
@row_ary = $dbh->selectrow_array($statement); @row_ary = $dbh->selectrow_array($statement, \%attr); @row_ary = $dbh->selectrow_array($statement, \%attr, @bind_values);

This utility method combines "prepare", "execute" and "fetchrow_array" into a single call. If called in a list context, it returns the first row of data from the statement. The $statement parameter can be a previously prepared statement handle, in which case the prepare is skipped.

If any method fails, and "RaiseError" is not set, selectrow_array will return an empty list.

If called in a scalar context for a statement handle that has more than one column, it is undefined whether the driver will return the value of the first column or the last. So don't do that. Also, in a scalar context, an undef is returned if there are no more rows or if an error occurred. That undef can't be distinguished from an undef returned because the first field value was NULL. For these reasons you should exercise some caution if you use selectrow_array in a scalar context, or just don't do that.

Let me shorten that a little bit for weary eyes:

  • selectrow_array() is designed to be called in LIST context
  • selectrow_array() returns an empty LIST on error
  • Behaviour in scalar context is not well-defined
  • In scalar context, you can't tell the difference between an error and NULL returned
  • DBI warns not just once, but twice twice to AVOID SCALAR CONTEXT for call selectrow_array()

Now, error handling. DBI offers a tedious, error-prone and highly annoying way of error handling, and a smart and lazy way of error handling.

The tedious way is to add an extra error check to almost any DBI method call. Just like you would have to do in assembler or in C. You need to study the DBI documentation to find out how each method behaves on error. And yes, they do behave differently.

Or, you could have DBI and perl do all of that grunt work for you, by just adding RaiseError => 1 to the attribute hash of connect(). That automatically adds error checks to all methods, and all methods will handle errors in the same way: They die instead of returning special error indicator values. And that's almost always exactly what you want. It's also extremely useful for doing transactions, see "Transactions" in the DBI documentation. This is copied right out of that section:

use Try::Tiny; $dbh->{AutoCommit} = 0; # enable transactions, if possible $dbh->{RaiseError} = 1; try { foo(...) # do lots of work here bar(...) # including inserts baz(...) # and updates $dbh->commit; # commit the changes if we get this far } catch { warn "Transaction aborted because $_"; # Try::Tiny copies $@ into +$_ # now rollback to undo the incomplete changes # but do it in an eval{} as it may also fail eval { $dbh->rollback }; # add other application on-error-clean-up code here };

(You could also do without Try::Tiny, by using an eval BLOCK that returns a true value:)

$dbh->{AutoCommit} = 0; # enable transactions, if possible $dbh->{RaiseError} = 1; eval { foo(...) # do lots of work here bar(...) # including inserts baz(...) # and updates $dbh->commit; # commit the changes if we get this far 1; } or do { warn "Transaction aborted because $@"; # now rollback to undo the incomplete changes # but do it in an eval{} as it may also fail eval { $dbh->rollback }; # add other application on-error-clean-up code here };

There are rare cases when you expect an SQL statement to fail (like testing if a table exists by simply using it in an SQL statement). Wrap them into eval BLOCK or try/catch and you are done.

And finally, doing database stuff in a web context with RaiseError set. Yes, an uncaught (i.e. unhandled) database error will kill your program, resulting in an ugly "500 Internal Server Error" or something similar. That's a good thing. It tells you that your code still has errors. As I wrote: If you expect database errors, wrap them in eval BLOCK or try/catch. For a simple-minded CGI, wrapping all of the database stuff in a big eval BLOCK and returning a "database oopsie" page on error is often acceptable.

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

In reply to Re^3: Recalcitrant placeholders by afoken
in thread Recalcitrant placeholders by Bod

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (4)
As of 2022-01-25 17:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    In 2022, my preferred method to securely store passwords is:












    Results (67 votes). Check out past polls.

    Notices?