sub commit () { ($T || ${ caller() . '::T' })->commit; goto END_XACTION; } sub rollback () { ($T || ${ caller() . '::T' })->rollback; goto END_XACTION; } sub transaction (&) { my ($block) = @_; local $T = ${ caller() . '::T' } or croak "\$T not set"; local $@; eval { $T->begin_work; $block->(); }; $@ ? rollback : commit; END_XACTION: die $@ . "commit not safe after errors, transaction rolled back" if $@; } #### sub commit { require Carp; Carp::croak("Can't commit outside a transaction"); } sub rollback { require Carp; Carp::croak("Can't rollback outside a transaction"); } sub transaction (&) { my ($block) = @_; my $caller = caller(); local *{"${caller}::commit"} = sub { die "!COMMIT\n" }; local *{"${caller}::rollback"} = sub { die "!ROLLBACK\n" }; local $@; eval { $T->begin_work; $block->(); }; if(!$@ or $@ eq "!COMMIT\n") { ${"${caller}::T"}->commit; } elsif($@ eq "!ROLLBACK\n") { ${"${caller}::T"}->rollback; } else { ${"${caller}::T"}->rollback; require Carp; Carp::croak($@ . "commit not safe after errors, transaction rolled back"); } }