massaging error messages

massaging error messages

am 24.02.2007 22:20:35 von oudeis

I'm trying to change the text of error messages, for example the following:

DBD::SQLite::db do failed: table X already exists(1) at dbdimp.c line 269

From the user's point of view, "table X already exists" is valuable
information, but "at dbdimp.c line 269" is useless.

I've attempted to do this using the HandleError attribute with a function:

sub handle_error {
$_[0] =~ s/ at dbdimp.c line \d+//;
print STDERR "db error: $_[0]\n"; # for debug
return 0;
}

The print statement shows the handler is changing the error text, but
the contents of $DBI:errstr on return from an offending statement show
the original text.

How can I do this?

- Will

Re: massaging error messages

am 25.02.2007 16:36:07 von Tim.Bunce

On Sat, Feb 24, 2007 at 09:20:35PM +0000, Will Parsons wrote:
> I'm trying to change the text of error messages, for example the following:
>
> DBD::SQLite::db do failed: table X already exists(1) at dbdimp.c line 269
>
> >From the user's point of view, "table X already exists" is valuable
> information, but "at dbdimp.c line 269" is useless.
>
> I've attempted to do this using the HandleError attribute with a function:
>
> sub handle_error {
> $_[0] =~ s/ at dbdimp.c line \d+//;
> print STDERR "db error: $_[0]\n"; # for debug
> return 0;
> }
>
> The print statement shows the handler is changing the error text, but
> the contents of $DBI:errstr on return from an offending statement show
> the original text.
>
> How can I do this?

Umm. I'd expect it to work. $_[0] is the same SV that's passed to
warn/croak for PrintError/RaiseError.

If you send me a patch that moves the HandleError tests from t/10examp.t
into a separate file and adds a new test for this problem, then I'll
try to fix it :)

Having said that, I don't see any value in the _sqlite_error() function
in DBD::SQLite adding the file and line number into the error message.

In fact the code needs changing anyway to use the newer way to record
errors. That'll mean you could use the DBI's SetErrHandler hook.
I'll do that and post a patch including the above change.

Tim.

Re: massaging error messages

am 25.02.2007 23:29:39 von Tim.Bunce

On Sun, Feb 25, 2007 at 03:36:07PM +0000, Tim Bunce wrote:
> On Sat, Feb 24, 2007 at 09:20:35PM +0000, Will Parsons wrote:
> > I'm trying to change the text of error messages, for example the following:
> >
> > DBD::SQLite::db do failed: table X already exists(1) at dbdimp.c line 269
> >
> > >From the user's point of view, "table X already exists" is valuable
> > information, but "at dbdimp.c line 269" is useless.
> >
> > I've attempted to do this using the HandleError attribute with a function:
> >
> > sub handle_error {
> > $_[0] =~ s/ at dbdimp.c line \d+//;
> > print STDERR "db error: $_[0]\n"; # for debug
> > return 0;
> > }
> >
> > The print statement shows the handler is changing the error text, but
> > the contents of $DBI:errstr on return from an offending statement show
> > the original text.
> >
> > How can I do this?
>
> Umm. I'd expect it to work. $_[0] is the same SV that's passed to
> warn/croak for PrintError/RaiseError.
>
> If you send me a patch that moves the HandleError tests from t/10examp.t
> into a separate file and adds a new test for this problem, then I'll
> try to fix it :)
>
> Having said that, I don't see any value in the _sqlite_error() function
> in DBD::SQLite adding the file and line number into the error message.
>
> In fact the code needs changing anyway to use the newer way to record
> errors. That'll mean you could use the DBI's SetErrHandler hook.
> I'll do that and post a patch including the above change.

Here's the patch.

Matt, I hope you approve.

Funnily enough, adding the tests found a bug in the way the DBI set_err
function handles HandleSetErr (fixed in the next release).

Tim.

diff -ru DBD-SQLite-1.13/dbdimp.c DBD-SQLite-1.13.tim1/dbdimp.c
--- DBD-SQLite-1.13/dbdimp.c 2006-09-08 05:50:50.000000000 +0100
+++ DBD-SQLite-1.13.tim1/dbdimp.c 2007-02-25 22:02:19.000000000 +0000
@@ -36,11 +36,7 @@
_sqlite_error(char *file, int line, SV *h, imp_xxh_t *imp_xxh, int rc, char *what)
{
dTHR;
-
- SV *errstr = DBIc_ERRSTR(imp_xxh);
- sv_setiv(DBIc_ERR(imp_xxh), (IV)rc);
- sv_setpv(errstr, what);
- sv_catpvf(errstr, "(%d) at %s line %d", rc, file, line);
+ DBIh_SET_ERR_CHAR(h, imp_xxh, NULL, rc, what, NULL, NULL);

if (DBIS->debug >= 3) {
PerlIO_printf(DBILOGFP, "sqlite error %d recorded: %s at %s line %d\n",
@@ -441,7 +437,7 @@
{
int pos;
if (!SvIOK(param)) {
- int len;
+ STRLEN len;
char *paramstring;
paramstring = SvPV(param, len);
if( paramstring[len] == 0 && strlen(paramstring) == len) {
diff -ru DBD-SQLite-1.13/t/06error.t DBD-SQLite-1.13.tim1/t/06error.t
--- DBD-SQLite-1.13/t/06error.t 2002-09-08 13:18:46.000000000 +0100
+++ DBD-SQLite-1.13.tim1/t/06error.t 2007-02-25 22:26:03.000000000 +0000
@@ -1,20 +1,37 @@
use Test;
-BEGIN { plan tests => 2 }
+BEGIN { plan tests => 8 }
use DBI;

+my @set_err;
+
unlink('foo');
-my $db = DBI->connect('dbi:SQLite:foo', '', '', { RaiseError => 1, PrintError => 0 });
+my $db = DBI->connect('dbi:SQLite:foo', '', '', {
+ RaiseError => 1,
+ PrintError => 0,
+ HandleSetErr => sub { push @set_err,$_[2]; return 0; },
+});
+
eval {
$db->do('ssdfsdf sdf sd sdfsdfdsf sdfsdf');
};
-ok($@);
+my $err = $@;
+ok($err);
+ok($err, qr/syntax error/);
+ok($DBI::err);
+ok($DBI::errstr);

$db->do('create table testerror (a, b)');
$db->do('insert into testerror values (1, 2)');
$db->do('insert into testerror values (3, 4)');

$db->do('create unique index testerror_idx on testerror (a)');
+@set_err = ();
eval {
$db->do('insert into testerror values (1, 5)');
};
-ok($@);
+$err = $@;
+ok($err);
+ok($err, qr/column a is not unique/);
+ok(scalar @set_err, 1);
+ok("@set_err", qr/column a is not unique/);
+@set_err = ();