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

Hi-

Assume I have a dbi connection handle, $dbh, and I want to turn on the RaiseError flag:

$dbh->{RaiseError} = 1; . execute some code .
So far so good. But now I want to turn it off again, and neither of these metheds seem to work (it continues raising errors) :
$dbh->{RaiseError} = 0; $dbh->{RaiseError} = undef;
Closing and then re-opening the connection or having two connections isn't really the option I'm looking for in this situation.

Can this be done?? Thanks!

Matt

Replies are listed 'Best First'.
Re: Toggling dbi attribute within a connection?
by ikegami (Patriarch) on May 12, 2005 at 16:31 UTC

    Upon creation, a sth inherits the attributes of its dbh. However, changing the attributes of the dbh doesn't change those of a previously created sth. That means if it's a sth method is raising the error, it's the sth's RaiseError you must reset:

    $sth->{RaiseError} = 0;

    456449 confirms this is your problem.

      Ahh! Yes, of course. This makes complete sense. Problem solved. :)

      Thank you.

      Matt
Re: Toggling dbi attribute within a connection?
by Limbic~Region (Chancellor) on May 12, 2005 at 15:11 UTC
    JupiterCrash,
    You are breaking encapsulation. If DBI doesn't provide an mutator method for setting the RaiseError flag then you should expect weird behavior by mucking with the internals. With that said, you might want to try:
    delete $dbh->{RaiseError};
    Update (30 seconds later) After reading more of TFM, it seems that you are encouraged to muck with internals. I find this odd, but after recently porting Config::Tiny from p5 to p6 it isn't the first time I have seen it. DBI gives the example of limiting the scope as follows:
    { local $h->{RaiseError}; # localize and turn off for this block }
    If you can't limit the scope and need to turn it off/on at will, I suggest using delete which was my first guess anyway.

    Cheers - L~R

      Those aren't the internals. It's just a really nasty interface that presents these method calls as hash values using typeglob magic.
        perrin,
        I see. jZed is giving me an education on this in the chatterbox. Thanks.

        Cheers - L~R

        It's just a really nasty interface that presents these method calls as hash values using typeglob magic.

        While it is ugly, it does have it does have the advantage of allowing you to easily localise a setting for a block using local.

      First, thank you very much for the suggestions.

      I had thought that delete $dbh->{RaiseError} might work, too, but it gives this error:

      Can't locate object method "DELETE" via package "DBI::db"

      I had tried (and just tried again) making it local in scope when setting it, as you suggested, and that does not seem to be working either to turn it on only temporarily. (it stays on outside of the scrope)

      This is weird.

      Matt
        Matt,
        First, DELETE is not delete. Second, can you provide a minimal example of the code that you can't get to work per the docs (using naked blocks for scopes).

        Cheers - L~R

Re: Toggling dbi attribute within a connection?
by jZed (Prior) on May 12, 2005 at 15:41 UTC
    Are you sure setting RaiseError to 0 isn't working? Did you also unset PrintError? What is the DBD and what is the error?
      I did not also unset PrintError, but I just tried that, and still no luck. I am using the ODBC DBD at the time, but I believe I had also tried this with Oracle. Basically, I have code which wants RaiseError on for a prepare and execute. Then, I do NOT want it on for the fetches, because there is a fetch that could potentially throw an error. With RaiseError off (what I want) this code works:
      # there is more to fetch, so set this high if ($sth->fetchrow_arrayref) { $extraFetch = 5000000; } else { $extraFetch = $numRowsDisplayed; }
      This fetch could potentially be outside the boundaries of the rows returned. With RaiseError off, I don't die and the conditiom works fine. With RaiseError on, I get this error:

      DBD::ODBC::st fetchrow_arrayref failed: (DBD: no select statement currently executing err=-1)

      If RaiseError could be off at this point, all would be good.

      However there are other areas in my code where I would have this same problem. Typically I will want to encapsulate a few statements in a transaction (with eval) and want RaiseError on for that. Then I will want it off, as there is code that follows which does things along the lines of

      execute($sql) || handle the error

      (where a die being thrown would never get into my "handle the error code)

      Matt
        This prints "1 error 3" for me with PostgreSQL, as I'd expect. I don't have ODBC handy to check.
        #!perl -w $|=1; use strict; use DBI; my $dbh=DBI->connect('dbi:Pg:dbname=test1'); $dbh->{PrintError}=0; $dbh->do('junk'); print "1"; eval { local $dbh->{RaiseError}=1; $dbh->do('junk'); print "2"; }; print " error " if $@; $dbh->do('junk'); print "3";
        if ($sth->fetchrow_arrayref) { $extraFetch = 5000000; } else { $extraFetch = $numRowsDisplayed; }
        You might want to check for $sth->{Active} instead, it should be true if there is more to fetch and false otherwise.