Skip Menu |

This queue is for tickets about the DBIx-Class CPAN distribution.

Report information
The Basics
Id: 88610
Status: open
Priority: 0/
Queue: DBIx-Class

People
Owner: Nobody in particular
Requestors: lamoz [...] adriver.ru
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: exception_action behavior distinction in create vs populate
Used to set exception_action to catch mysql 'retry transaction' exceptions. This is working with $rs->create, but not $rs->populate. See test in attach
Subject: populate_test.pl
#!/usr/bin/perl use Test::Most; { package MyX; use Exception::Class ( 'MyX', {}, 'MyX::ConstraintFail', { isa => 'MyX' } ); } { package MySchema::MyResult; use base 'DBIx::Class'; __PACKAGE__->load_components( qw/ Core / ); __PACKAGE__->table( 'foo' ); __PACKAGE__->add_columns( id => { data_type => 'int', is_nullable => 0, }, ); __PACKAGE__->set_primary_key(qw/ id /); } { package MySchema; use base 'DBIx::Class::Schema'; __PACKAGE__->load_classes( 'MyResult' ); __PACKAGE__->exception_action( sub { my $e = shift; if ( ref( $e ) ) { die $e; } if ( $DBI::err && $DBI::err == 19 ) { MyX::ConstraintFail->throw( "Abort due to constraint violation" ); } MyX->throw( "Something went wrong with DB: $e" ); } ); } my $schema = MySchema->connect( 'dbi:SQLite:dbname=:memory:' ); $schema->deploy(); my $rs = $schema->resultset('MyResult'); throws_ok{ $rs->create({ id => 1}); $rs->create({ id => 1}); } 'MyX::ConstraintFail'; $rs->delete; throws_ok{ $rs->populate([{id => 1},{id => 1}]); } 'MyX::ConstraintFail'; done_testing;
On Wed Sep 11 08:50:03 2013, lamoz wrote: Show quoted text
> Used to set exception_action to catch mysql 'retry transaction' > exceptions. This is working with $rs->create, but not $rs->populate. > See test in attach
Sorry for the late reply. I do not think it is possible at the moment to use exception_action in this manner, as there is *another* statement that gets executed between the failure and the return, namely: https://github.com/dbsrgits/dbix-class/blob/master/lib/DBIx/Class/Storage/DBI.pm#L2299 Aside from that DBI's execute_for_fetch() (which is used by populate internaly) does not set $DBI::err in the same manner as a plain execute() does, so even if the above was somehow avoided, you'd still not be able to figure out what happened... Do you have ideas what we could do differently given all this info?
From: lamoz [...] adriver.ru
Show quoted text
> Do you have ideas what we could do differently given all this info?
I am definitely not advanced DBIC user. I can only think of getting error vector into some kind of hook to merge them by myself based on my logic and to propagate them further.
Subject: Re: [rt.cpan.org #88610] exception_action behavior distinction in create vs populate
Date: Tue, 14 Jan 2014 07:30:16 +0000
To: "Konstantin A. Pustovalov via RT" <bug-DBIx-Class [...] rt.cpan.org>
From: Peter Rabbitson <ribasushi [...] cpan.org>
On Tue, Jan 14, 2014 at 02:12:38AM -0500, Konstantin A. Pustovalov via RT wrote: Show quoted text
> Queue: DBIx-Class > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=88610 > >
> > Do you have ideas what we could do differently given all this info?
> > I am definitely not advanced DBIC user. I can only think of getting error vector into some kind of hook to merge them by myself based on my logic and to propagate them further.
I meant to ask something slightly different - given that we use execute_for_fetch, and there may be *multiple* errors in one batch - what do you think should be done? Leaving the question of DBIC aside - if you were to write it with DBI alone, while still using execute_for_fetch - what would your code roughly look like? Cheers
From: lamoz [...] adriver.ru
Show quoted text
> I meant to ask something slightly different - given that we use > execute_for_fetch, and there may be *multiple* errors in one batch - > what do you think should be done? Leaving the question of DBIC aside - > if you were to write it with DBI alone, while still using > execute_for_fetch - what would your code roughly look like?
maybe: $sth->execute_for_fetch( $tuple_cb, \@status ); eval{ $sth->finish }; my $finish_failed; $finish_failed = FinishFailedX->new() if $@ ne ''; my @errors = grep { ref $_ } @tuple_status; my @x = map { make_exception($_) } @errors; push @x, $finish_failed if $finish_failed; die merge_exceptions( @x ) if @x;