in reply to DBI not erroring out on Insert

I did some test code of my own. This is with SQLite instead of MySQL, but this is so simple that results should be the same.

The code should fail at the prepare statement (see my test code below). If you have a valid $dbh handle, the prepare simply won't work if in your case column "column2" does not exist, in my case column "abc".

I would include an "or die" clause on the connect() like I did below because you are not guaranteed to have the 'RaiseError' in effect unless the connect succeeds. Think about it, if you omitted say the user name field, the connect() is going to fail and things won't work so well interpreting the attribute hash as a password string! In other words, don't rely on 'RaiseError' working until you are sure that the statement that set that attribute itself worked! Your code may be going wrong right at the connect!

I did some tests with and without "use strict" and "use warnings". This made no difference in the error that I got in this simple test. However there are run time aspects to those and the DBI does work with standard $SIG(__WARN__} and $SIG{__DIE__} signal handlers, so I would leave this extra warning stuff on unless there is an unusual performance requirement and even then don't turn it off until after testing is complete.

#!/usr/bin/perl -w use strict; #result the same without strict or warnings use DBI; my $dbfile = "./SomeDB.sqlite"; my %attr = ( RaiseError => 1); #auto die with error printout my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile","","",\%attr) or die "Couldn't connect to database: " . DBI->errstr; my $s2 = $dbh->prepare("INSERT INTO logs ('abc') VALUES ('xyzzy')"); $s2->execute(); __END__ DBD::SQLite::db prepare failed: table logs has no column named abc process exits with error code 2 in my environment...
At the end of the day, a single connect statement and a single prepare statement is enough to demonstrate what happens when an SQL INSERT into a non-existent column (in an existing table, in my case the "logs" table) is attempted.

Replies are listed 'Best First'.
Re^2: DBI not erroring out on Insert
by chromatic (Archbishop) on Sep 13, 2011 at 20:35 UTC
    I would include an "or die" clause on the connect() like I did below because you are not guaranteed to have the 'RaiseError' in effect unless the connect succeeds.

    Read the source code of DBI's connect method. It will use Carp to croak when RaiseError is in effect if the connection failed.


    Improve your skills with Modern Perl: the free book.

      We are way off the original topic now... I did look at the DBI source code as chromatic suggested... I guess this is the sort of thing where everybody can claim "victory" depending upon their point of view!

      The code in DBI's connect() related to RaiseError:

      unless ( $attr->{HandleError} && $attr->{HandleError}->($msg, $drh, $dbh)) { Carp::croak($msg) if $attr->{RaiseError}; Carp::carp ($msg) if $attr->{PrintError}; }
      Ok, fair enough. If RaiseError is true, then the DBI croaks on an error.

      I was pondering a different question. I was wondering what happens if connect() fails because the arguments supplied are are of wrong number or type - in a more general case, what happens if the arg list is such that the DBI connect cannot recognize that RaiseError is intended to be 'on'? That case is handled by this DBI code:

      Carp::croak('Usage: $class->connect([$dsn [,$user [,$passwd [,\%attr]] +]])') if (ref $old_driver or ($attr and not ref $attr) or ref $pass);
      So I guess a more accurate description of what the DBI does: The DBI will croak no matter what the state of RaiseError if it detects an invalid argument list to connect(). I also found out through testing that if you misspell "Raiseerror", the DBI also croaks - it will croak for any syntax error that is detected (the spec doesn't say this, but the code does it).

      I'm testing right now with SQLite which doesn't have users or passwords so there are scenarios with MySQL that I am unable to test.

      At the end of the day, if I omit the "or die" clause to a connect (which also specifies the RaiseError attribute), then I would have to be 100% sure that the "or die" code can never be executed under any circumstance. I can't prove that and that is certainly not part of the public specification.

      Now I know that the "hey Mom, Jimmy's mom let's him to X" (the other guys do it defense) is pretty weak, but I learned my "bad" habit about this from Programming the Perl DBI" by Alligator Descartes and Tim Bunce.

      I think that I am on very solid ground with my current practice and recommendations.

      Back to original question in the original post!!!
      I still have not found any way at all for a prepare of the INSERT statement to succeed where one of the columns does not exist in the table.

        Do you think what you found out about connect/RaiseError that is not documented is worth adding to the DBI pod? I've not seen a discussion on what is raised by DBI during connect if RaiseError is set or not before. I have a commit bit on DBI if you have any suggestions.

Re^2: DBI not erroring out on Insert
by chromatic (Archbishop) on Sep 11, 2011 at 21:20 UTC
    However there are run time aspects to those and the DBI does work with standard $SIG(__WARN__} and $SIG{__DIE__} signal handlers

    Both strict and warnings are lexical pragmas. If enabling them in this test program causes DBI to behave differently, either DBI or the Perl 5 core has a strange bug.

    Improve your skills with Modern Perl: the free book.

      I think we are getting off of the issue of the OP (Original Post). I was a bit sloppy in terminology. Ok.

      I could not find any difference in behavior in the 2 lines of code that are relevant to OP's post as regards to: "-w" vs "use warnings;".

      If we want to get into exactly how the "-w command line option" and "use warnings;" differ, then I would suggest that a new thread get started. For folks who want to know more, here are a couple of links: -w vs use warnings and use warnings;.

      I think that we are getting "off topic".
      My main point is that the attribute "RaiseError" does work and I suspect that it didn't because the statement that set that did not work. I have been unable to find any other scenario in my testing.

      Now of course there could be a situation that I haven't found, but I'm reporting 2 lines of code and asking the OP to run my code. The "-w" or "use warnings;" issue is minor and does not affect my test results; having said that, I test all my code with the command line -w version.