package Common::DBI::st::timeout; # magic to support getting/setting attributes on the returned statement handle use overload fallback => 1, '%{}' => sub { $_[0]->sth }; use base 'Common::Thing'; __PACKAGE__->make_attributes( qw( timeout sth ) ); sub _init { my ( $self, %parms ) = @_; $self->SUPER::_init(); $self->seed( \%parms ); } # redispatch methods to DBI::st, applying timeout if so requested sub AUTOLOAD { my ($self, @args) = @_; my ($class, $method) = (our $AUTOLOAD) =~ /(.*)::(.*)/s; my $timeout = $self->timeout(); my @results; my $wantarray = wantarray; my $sth = $self->sth(); my $timed_out = Common::DBI::_timeout_call( $timeout, sub { if ($wantarray) { @results = $sth->$method(@args); } elsif (defined $wantarray) { $results[0] = $sth->$method(@args); } else { $sth->$method(@args); } } ); if ($timed_out) { my $dbh = $sth->{'Database'}; my $driver = $dbh->{'Driver'}{'Name'}; # Oracle 9i blows up if you try accessing it after a timeout if ($driver eq 'Oracle') { $dbh->{'Active'} = 0; $sth->{'Active'} = 0; } die Common::Exception->new( 'Common::DBI::StatementTimeout', { 'driver' => $driver, 'database' => $dbh->{'Name'}, 'method' => $method, } ); } return( $wantarray ? @results : $results[0] ); } 1;