- ::Storage::DBI now correctly preserves a parent $dbh from
terminating children, even during interpreter-global
out-of-order destruction
+ - All DBIC exception-handling switched to Try::Tiny
- Add DBIx::Class::FilterColumn for non-ref filtering
- InflateColumn::DateTime support for MSSQL via DBD::Sybase
- Millisecond precision support for MSSQL datetimes for
'Data::Dumper::Concise' => '1.000',
'Scope::Guard' => '0.03',
'Context::Preserve' => '0.01',
+ 'Try::Tiny' => '0.04',
};
# this is so we can order requires alphabetically
sub _attr_cache {
my $self = shift;
my $cache = $self->can('__attr_cache') ? $self->__attr_cache : {};
- my $rest = eval { $self->next::method };
- return $@ ? $cache : { %$cache, %$rest };
+
+ return {
+ %$cache,
+ %{ $self->maybe::next::method || {} },
+ };
}
1;
Tom Hukins
+tonvoon: Ton Voon <tonvoon@cpan.org>
+
triode: Pete Gamache <gamache@cpan.org>
typester: Daisuke Murase <typester@cpan.org>
sub _build_config {
my ($self) = @_;
- eval { require Config::Any }
- or die ("Config::Any is required to parse the config file.\n");
+ try { require Config::Any }
+ catch { die ("Config::Any is required to parse the config file.\n") };
my $cfg = Config::Any->load_files ( {files => [$self->config_file], use_ext =>1, flatten_to_hash=>1});
use strict;
use warnings;
-use Carp::Clan qw/^DBIx::Class/;
+use Carp::Clan qw/^DBIx::Class|^Try::Tiny/;
use Scalar::Util qw/blessed/;
+use Try::Tiny;
use overload
'""' => sub { shift->{msg} },
L<Carp::Clan/croak>.
DBIx::Class::Exception->throw('Foo');
- eval { ... }; DBIx::Class::Exception->throw($@) if $@;
+ try { ... } catch { DBIx::Class::Exception->throw(shift) }
=cut
# use Carp::Clan's croak if we're not stack tracing
if(!$stacktrace) {
- local $@;
- eval { croak $msg };
- $msg = $@
+ try { croak $msg } catch { $msg = shift };
}
else {
$msg = Carp::longmess($msg);
use warnings;
use base qw/DBIx::Class/;
use Carp::Clan qw/^DBIx::Class/;
+use Try::Tiny;
=head1 NAME
inflate => sub {
my ($value, $obj) = @_;
- my $dt = eval { $obj->_inflate_to_datetime( $value, \%info ) };
- if (my $err = $@ ) {
- return undef if ($undef_if_invalid);
- $self->throw_exception ("Error while inflating ${value} for ${column} on ${self}: $err");
- }
-
- return $obj->_post_inflate_datetime( $dt, \%info );
+ my $dt = try
+ { $obj->_inflate_to_datetime( $value, \%info ) }
+ catch {
+ $self->throw_exception ("Error while inflating ${value} for ${column} on ${self}: $_")
+ unless $undef_if_invalid;
+ undef; # rv
+ };
+
+ return (defined $dt)
+ ? $obj->_post_inflate_datetime( $dt, \%info )
+ : undef
+ ;
},
deflate => sub {
my ($value, $obj) = @_;
return $genus->species;
};
+ use Try::Tiny;
my $rs;
- eval {
+ try {
$rs = $schema->txn_do($coderef1);
- };
-
- if ($@) { # Transaction failed
+ } catch {
+ # Transaction failed
die "the sky is falling!" #
- if ($@ =~ /Rollback failed/); # Rollback failed
+ if ($_ =~ /Rollback failed/); # Rollback failed
deal_with_failed_transaction();
- }
+ };
Note: by default C<txn_do> will re-run the coderef one more time if an
error occurs due to client disconnection (e.g. the server is bounced).
my $schema = MySchema->connect("dbi:Pg:dbname=my_db");
# Start a transaction. Every database change from here on will only be
- # committed into the database if the eval block succeeds.
- eval {
+ # committed into the database if the try block succeeds.
+ use Try::Tiny;
+ my $exception;
+ try {
$schema->txn_do(sub {
# SQL: BEGIN WORK;
for (1..10) {
# Start a nested transaction, which in fact sets a savepoint.
- eval {
+ try {
$schema->txn_do(sub {
# SQL: SAVEPOINT savepoint_0;
# WHERE ( id = 42 );
}
});
- };
- if ($@) {
+ } catch {
# SQL: ROLLBACK TO SAVEPOINT savepoint_0;
# There was an error while creating a $thing. Depending on the error
# changes related to the creation of this $thing
# Abort the whole job
- if ($@ =~ /horrible_problem/) {
+ if ($_ =~ /horrible_problem/) {
print "something horrible happend, aborting job!";
- die $@; # rethrow error
+ die $_; # rethrow error
}
# Ignore this $thing, report the error, and continue with the
# next $thing
- print "Cannot create thing: $@";
+ print "Cannot create thing: $_";
}
# There was no error, so save all changes since the last
# savepoint.
# SQL: RELEASE SAVEPOINT savepoint_0;
}
});
- };
- if ($@) {
+ } catch {
+ $exception = $_;
+ }
+
+ if ($caught) {
# There was an error while handling the $job. Rollback all changes
# since the transaction started, including the already committed
# ('released') savepoints. There will be neither a new $job nor any
# SQL: ROLLBACK;
- print "ERROR: $@\n";
+ print "ERROR: $exception\n";
}
else {
# There was no error while handling the $job. Commit all changes.
In this example it might be hard to see where the rollbacks, releases and
commits are happening, but it works just the same as for plain L<<txn_do>>: If
-the C<eval>-block around C<txn_do> fails, a rollback is issued. If the C<eval>
+the C<try>-block around C<txn_do> fails, a rollback is issued. If the C<try>
succeeds, the transaction is committed (or the savepoint released).
While you can get more fine-grained control using C<svp_begin>, C<svp_release>
use Scalar::Util ();
use base qw/DBIx::Class/;
+use Try::Tiny;
=head1 NAME
# condition resolution may fail if an incomplete master-object prefetch
# is encountered - that is ok during prefetch construction (not yet in_storage)
- my $cond = eval { $source->_resolve_condition( $rel_info->{cond}, $rel, $self ) };
- if (my $err = $@) {
+ my $cond = try {
+ $source->_resolve_condition( $rel_info->{cond}, $rel, $self )
+ }
+ catch {
if ($self->in_storage) {
- $self->throw_exception ($err);
- }
- else {
- $cond = $DBIx::Class::ResultSource::UNRESOLVABLE_CONDITION;
+ $self->throw_exception ($_);
}
- }
+
+ $DBIx::Class::ResultSource::UNRESOLVABLE_CONDITION; # RV
+ };
if ($cond eq $DBIx::Class::ResultSource::UNRESOLVABLE_CONDITION) {
my $reverse = $source->reverse_relationship_info($rel);
use strict;
use warnings;
+use Try::Tiny;
our %_pod_inherit_config =
(
# no join condition or just a column name
if (!ref $cond) {
$class->ensure_class_loaded($f_class);
- my %f_primaries = map { $_ => 1 } eval { $f_class->_pri_cols };
- $class->throw_exception(
- "Can't infer join condition for ${rel} on ${class}: $@"
- ) if $@;
+ my %f_primaries = map { $_ => 1 } try { $f_class->_pri_cols }
+ catch {
+ $class->throw_exception( "Can't infer join condition for ${rel} on ${class}: $_");
+ };
my ($pri, $too_many) = keys %f_primaries;
$class->throw_exception(
use strict;
use warnings;
+use Try::Tiny;
our %_pod_inherit_config =
(
unless (ref $cond) {
$class->ensure_class_loaded($f_class);
- my ($pri, $too_many) = eval { $class->_pri_cols };
- $class->throw_exception(
- "Can't infer join condition for ${rel} on ${class}: $@"
- ) if $@;
+ my ($pri, $too_many) = try { $class->_pri_cols }
+ catch {
+ $class->throw_exception("Can't infer join condition for ${rel} on ${class}: $_");
+ };
$class->throw_exception(
"has_many can only infer join for a single primary key; ".
$guess = "using our class name '$class' as foreign key";
}
- my $f_class_loaded = eval { $f_class->columns };
+ my $f_class_loaded = try { $f_class->columns };
$class->throw_exception(
"No such column ${f_key} on foreign class ${f_class} ($guess)"
) if $f_class_loaded && !$f_class->has_column($f_key);
use strict;
use warnings;
use Carp::Clan qw/^DBIx::Class/;
+use Try::Tiny;
our %_pod_inherit_config =
(
"${class} has none"
) if !defined $pri && (!defined $cond || !length $cond);
- my $f_class_loaded = eval { $f_class->columns };
+ my $f_class_loaded = try { $f_class->columns };
my ($f_key,$too_many,$guess);
if (defined $cond && length $cond) {
$f_key = $cond;
sub _get_primary_key {
my ( $class, $target_class ) = @_;
$target_class ||= $class;
- my ($pri, $too_many) = eval { $target_class->_pri_cols };
- $class->throw_exception(
- "Can't infer join condition on ${target_class}: $@"
- ) if $@;
+ my ($pri, $too_many) = try { $target_class->_pri_cols }
+ catch {
+ $class->throw_exception("Can't infer join condition on ${target_class}: $_");
+ };
$class->throw_exception(
"might_have/has_one can only infer join for a single primary key; ".
use DBIx::Class::Exception;
use Carp::Clan qw/^DBIx::Class/;
+use Try::Tiny;
use base qw/DBIx::Class/;
$self->{_columns_info_loaded}++;
my $info = {};
my $lc_info = {};
- # eval for the case of storage without table
- eval { $info = $self->storage->columns_info_for( $self->from ) };
- unless ($@) {
+
+ # try for the case of storage without table
+ try {
+ $info = $self->storage->columns_info_for( $self->from );
for my $realcol ( keys %{$info} ) {
$lc_info->{lc $realcol} = $info->{$realcol};
}
%{ $info->{$col} || $lc_info->{lc $col} || {} }
};
}
- }
+ };
}
return $self->_columns->{$column};
}
return $self;
- # XXX disabled. doesn't work properly currently. skip in tests.
+# XXX disabled. doesn't work properly currently. skip in tests.
my $f_source = $self->schema->source($f_source_name);
unless ($f_source) {
}
return unless $f_source; # Can't test rel without f_source
- eval { $self->_resolve_join($rel, 'me', {}, []) };
-
- if ($@) { # If the resolve failed, back out and re-throw the error
- delete $rels{$rel}; #
+ try { $self->_resolve_join($rel, 'me', {}, []) }
+ catch {
+ # If the resolve failed, back out and re-throw the error
+ delete $rels{$rel};
$self->_relationships(\%rels);
- $self->throw_exception("Error creating relationship $rel: $@");
- }
+ $self->throw_exception("Error creating relationship $rel: $_");
+ };
+
1;
}
use DBIx::Class::Exception;
use Scalar::Util ();
+use Try::Tiny;
###
### Internal method
my ($self, $column, $new_value) = @_;
# if we can't get an ident condition on first try - mark the object as unidentifiable
- $self->{_orig_ident} ||= (eval { $self->ident_condition }) || {};
+ $self->{_orig_ident} ||= (try { $self->ident_condition }) || {};
my $old_value = $self->get_column($column);
$new_value = $self->store_column($column, $new_value);
use DBIx::Class::Exception;
use Carp::Clan qw/^DBIx::Class/;
+use Try::Tiny;
use Scalar::Util ();
use File::Spec;
use Sub::Name ();
$storage_class = 'DBIx::Class::Storage'.$storage_class
if $storage_class =~ m/^::/;
- eval { $self->ensure_class_loaded ($storage_class) };
- $self->throw_exception(
- "No arguments to load_classes and couldn't load ${storage_class} ($@)"
- ) if $@;
+ try {
+ $self->ensure_class_loaded ($storage_class);
+ }
+ catch {
+ $self->throw_exception(
+ "No arguments to load_classes and couldn't load ${storage_class} ($_)"
+ );
+ };
my $storage = $storage_class->new($self=>$args);
$storage->connect_info(\@info);
$self->storage($storage);
unless ($INC{"DBIx/Class/CDBICompat.pm"} || $warn++);
my $base = 'DBIx::Class::ResultSetProxy';
- eval "require ${base};";
- $self->throw_exception
- ("No arguments to load_classes and couldn't load ${base} ($@)")
- if $@;
+ try {
+ eval "require ${base};"
+ }
+ catch {
+ $self->throw_exception
+ ("No arguments to load_classes and couldn't load ${base} ($_)")
+ };
if ($self eq $target) {
# Pathological case, largely caused by the docs on early C::M::DBIC::Plain
use Carp::Clan qw/^DBIx::Class/;
use Time::HiRes qw/gettimeofday/;
+use Try::Tiny;
__PACKAGE__->mk_classdata('_filedata');
__PACKAGE__->mk_classdata('upgrade_directory');
my ($self, $rs) = @_;
my $vtable = $self->{vschema}->resultset('Table');
- my $version = eval {
+ my $version = try {
$vtable->search({}, { order_by => { -desc => 'installed' }, rows => 1 } )
->get_column ('version')
->next;
{
my ($self, $rs) = @_;
- my $c = eval {
- $rs->search({ 1, 0 })->count;
- };
- return 0 if $@ || !defined $c;
+ my $c = try { $rs->search({ 1, 0 })->count };
- return 1;
+ return (defined $c) ? 1 : 0;
}
1;
use Scalar::Util();
use IO::File;
use DBIx::Class::Storage::TxnScopeGuard;
+use Try::Tiny;
__PACKAGE__->mk_group_accessors('simple' => qw/debug debugobj schema/);
__PACKAGE__->mk_group_accessors('inherited' => 'cursor_class');
};
my $rs;
- eval {
+ try {
$rs = $schema->txn_do($coderef);
- };
-
- if ($@) { # Transaction failed
+ } catch {
+ my $error = shift;
+ # Transaction failed
die "something terrible has happened!" #
- if ($@ =~ /Rollback failed/); # Rollback failed
+ if ($error =~ /Rollback failed/); # Rollback failed
deal_with_failed_transaction();
- }
+ };
In a nested transaction (calling txn_do() from within a txn_do() coderef) only
the outermost transaction will issue a L</txn_commit>, and txn_do() can be
$self->txn_begin; # If this throws an exception, no rollback is needed
my $wantarray = wantarray; # Need to save this since the context
- # inside the eval{} block is independent
+ # inside the try{} block is independent
# of the context that called txn_do()
- eval {
+ try {
# Need to differentiate between scalar/list context to allow for
# returning a list in scalar context to get the size of the list
$coderef->(@args);
}
$self->txn_commit;
- };
-
- if ($@) {
- my $error = $@;
+ }
+ catch {
+ my $error = shift;
- eval {
+ try {
$self->txn_rollback;
- };
-
- if ($@) {
- my $rollback_error = $@;
+ } catch {
my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
$self->throw_exception($error) # propagate nested rollback
- if $rollback_error =~ /$exception_class/;
+ if $_ =~ /$exception_class/;
$self->throw_exception(
- "Transaction aborted: $error. Rollback failed: ${rollback_error}"
+ "Transaction aborted: $error. Rollback failed: $_"
);
- } else {
- $self->throw_exception($error); # txn failed but rollback succeeded
}
- }
+ $self->throw_exception($error); # txn failed but rollback succeeded
+ };
return $wantarray ? @return_values : $return_value;
}
use List::Util();
use Data::Dumper::Concise();
use Sub::Name ();
-
+use Try::Tiny;
use File::Path ();
__PACKAGE__->mk_group_accessors('simple' =>
# some databases need this to stop spewing warnings
if (my $dbh = $self->_dbh) {
- local $@;
- eval {
+ try {
%{ $dbh->{CachedKids} } = ();
$dbh->disconnect;
};
my $dbh = $self->_get_dbh;
- return $self->$code($dbh, @_) if $self->{_in_dbh_do}
- || $self->{transaction_depth};
+ return $self->$code($dbh, @_)
+ if ( $self->{_in_dbh_do} || $self->{transaction_depth} );
local $self->{_in_dbh_do} = 1;
- my @result;
- my $want_array = wantarray;
+ my @args = @_;
+ try {
+ return $self->$code ($dbh, @args);
+ } catch {
+ $self->throw_exception($_) if $self->connected;
- eval {
+ # We were not connected - reconnect and retry, but let any
+ # exception fall right through this time
+ carp "Retrying $code after catching disconnected exception: $_"
+ if $ENV{DBIC_DBIRETRY_DEBUG};
- if($want_array) {
- @result = $self->$code($dbh, @_);
- }
- elsif(defined $want_array) {
- $result[0] = $self->$code($dbh, @_);
- }
- else {
- $self->$code($dbh, @_);
- }
+ $self->_populate_dbh;
+ $self->$code($self->_dbh, @args);
};
-
- # ->connected might unset $@ - copy
- my $exception = $@;
- if(!$exception) { return $want_array ? @result : $result[0] }
-
- $self->throw_exception($exception) if $self->connected;
-
- # We were not connected - reconnect and retry, but let any
- # exception fall right through this time
- carp "Retrying $code after catching disconnected exception: $exception"
- if $ENV{DBIC_DBIRETRY_DEBUG};
- $self->_populate_dbh;
- $self->$code($self->_dbh, @_);
}
# This is basically a blend of dbh_do above and DBIx::Class::Storage::txn_do.
my $tried = 0;
while(1) {
- eval {
+ my $exception;
+ my @args = @_;
+ try {
$self->_get_dbh;
$self->txn_begin;
if($want_array) {
- @result = $coderef->(@_);
+ @result = $coderef->(@args);
}
elsif(defined $want_array) {
- $result[0] = $coderef->(@_);
+ $result[0] = $coderef->(@args);
}
else {
- $coderef->(@_);
+ $coderef->(@args);
}
$self->txn_commit;
+ } catch {
+ $exception = $_;
};
- # ->connected might unset $@ - copy
- my $exception = $@;
- if(!$exception) { return $want_array ? @result : $result[0] }
+ if(! defined $exception) { return $want_array ? @result : $result[0] }
if($tried++ || $self->connected) {
- eval { $self->txn_rollback };
- my $rollback_exception = $@;
- if($rollback_exception) {
+ my $rollback_exception;
+ try { $self->txn_rollback } catch { $rollback_exception = shift };
+ if(defined $rollback_exception) {
my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
$self->throw_exception($exception) # propagate nested rollback
if $rollback_exception =~ /$exception_class/;
my %info;
- my $server_version = do {
- local $@; # might be happenin in some sort of destructor
- eval { $self->_get_server_version };
- };
+ my $server_version = try { $self->_get_server_version };
if (defined $server_version) {
$info{dbms_version} = $server_version;
$DBI::connect_via = 'connect';
}
- eval {
+ try {
if(ref $info[0] eq 'CODE') {
$dbh = $info[0]->();
}
$dbh = DBI->connect(@info);
}
- if($dbh && !$self->unsafe) {
+ if (!$dbh) {
+ die $DBI::errstr;
+ }
+
+ unless ($self->unsafe) {
my $weak_self = $self;
Scalar::Util::weaken($weak_self);
$dbh->{HandleError} = sub {
$dbh->{RaiseError} = 1;
$dbh->{PrintError} = 0;
}
+ }
+ catch {
+ $self->throw_exception("DBI Connection failed: $_")
+ }
+ finally {
+ $DBI::connect_via = $old_connect_via if $old_connect_via;
};
- $DBI::connect_via = $old_connect_via if $old_connect_via;
-
- $self->throw_exception("DBI Connection failed: " . ($@||$DBI::errstr))
- if !$dbh || $@;
-
$self->_dbh_autocommit($dbh->{AutoCommit});
-
$dbh;
}
sub txn_rollback {
my $self = shift;
my $dbh = $self->_dbh;
- eval {
+ try {
if ($self->{transaction_depth} == 1) {
$self->debugobj->txn_rollback()
if ($self->debug);
else {
die DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION->new;
}
- };
- if ($@) {
- my $error = $@;
- my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
- $error =~ /$exception_class/ and $self->throw_exception($error);
- # ensure that a failed rollback resets the transaction depth
- $self->{transaction_depth} = $self->_dbh_autocommit ? 0 : 1;
- $self->throw_exception($error);
}
+ catch {
+ my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
+
+ if ($_ !~ /$exception_class/) {
+ # ensure that a failed rollback resets the transaction depth
+ $self->{transaction_depth} = $self->_dbh_autocommit ? 0 : 1;
+ }
+
+ $self->throw_exception($_)
+ };
}
sub _dbh_rollback {
if ($opts->{returning}) {
my @ret_cols = @{$opts->{returning}};
- my @ret_vals = eval {
+ my @ret_vals = try {
local $SIG{__WARN__} = sub {};
my @r = $sth->fetchrow_array;
$sth->finish;
$placeholder_index++;
}
- my $rv = eval {
- $self->_dbh_execute_array($sth, $tuple_status, @extra);
+ my ($rv, $err);
+ try {
+ $rv = $self->_dbh_execute_array($sth, $tuple_status, @extra);
+ }
+ catch {
+ $err = shift;
+ }
+ finally {
+ # Statement must finish even if there was an exception.
+ try {
+ $sth->finish
+ }
+ catch {
+ $err = shift unless defined $err
+ };
};
- my $err = $@ || $sth->errstr;
-# Statement must finish even if there was an exception.
- eval { $sth->finish };
- $err = $@ unless $err;
+ $err = $sth->errstr
+ if (! defined $err and $sth->err);
- if ($err) {
+ if (defined $err) {
my $i = 0;
++$i while $i <= $#$tuple_status && !ref $tuple_status->[$i];
}),
);
}
+
return $rv;
}
sub _dbh_execute_inserts_with_no_binds {
my ($self, $sth, $count) = @_;
- eval {
+ my $err;
+ try {
my $dbh = $self->_get_dbh;
local $dbh->{RaiseError} = 1;
local $dbh->{PrintError} = 0;
$sth->execute foreach 1..$count;
+ }
+ catch {
+ $err = shift;
+ }
+ finally {
+ # Make sure statement is finished even if there was an exception.
+ try {
+ $sth->finish
+ }
+ catch {
+ $err = shift unless defined $err;
+ };
};
- my $exception = $@;
-
-# Make sure statement is finished even if there was an exception.
- eval { $sth->finish };
- $exception = $@ unless $exception;
- $self->throw_exception($exception) if $exception;
+ $self->throw_exception($err) if defined $err;
return $count;
}
if ($dbh->can('column_info')) {
my %result;
- eval {
+ my $caught;
+ try {
my ($schema,$tab) = $table =~ /^(.+?)\.(.+)$/ ? ($1,$2) : (undef,$table);
my $sth = $dbh->column_info( undef,$schema, $tab, '%' );
$sth->execute();
$result{$col_name} = \%column_info;
}
+ } catch {
+ $caught = 1;
};
- return \%result if !$@ && scalar keys %result;
+ return \%result if !$caught && scalar keys %result;
}
my %result;
sub _dbh_last_insert_id {
my ($self, $dbh, $source, $col) = @_;
- my $id = eval { $dbh->last_insert_id (undef, undef, $source->name, $col) };
+ my $id = try { $dbh->last_insert_id (undef, undef, $source->name, $col) };
return $id if defined $id;
# some drivers provide a $dbh attribute (e.g. Sybase and $dbh->{syb_dynamic_supported})
# but it is inaccurate more often than not
- eval {
+ return try {
local $dbh->{PrintError} = 0;
local $dbh->{RaiseError} = 1;
$dbh->do('select ?', {}, 1);
+ 1;
+ }
+ catch {
+ 0;
};
- return $@ ? 0 : 1;
}
# Check if placeholders bound to non-string types throw exceptions
my $self = shift;
my $dbh = $self->_get_dbh;
- eval {
+ return try {
local $dbh->{PrintError} = 0;
local $dbh->{RaiseError} = 1;
# this specifically tests a bind that is NOT a string
$dbh->do('select 1 where 1 = ?', {}, 1);
+ 1;
+ }
+ catch {
+ 0;
};
- return $@ ? 0 : 1;
}
=head2 sqlt_type
return if($line =~ /^COMMIT/m);
return if $line =~ /^\s+$/; # skip whitespace only
$self->_query_start($line);
- eval {
+ try {
# do a dbh_do cycle here, as we need some error checking in
# place (even though we will ignore errors)
$self->dbh_do (sub { $_[1]->do($line) });
+ } catch {
+ carp qq{$_ (running "${line}")};
};
- if ($@) {
- carp qq{$@ (running "${line}")};
- }
$self->_query_end($line);
};
my @statements = $schema->deployment_statements($type, undef, $dir, { %{ $sqltargs || {} }, no_comments => 1 } );
DBIx::Class::Storage::DBI::ADO;
use base 'DBIx::Class::Storage::DBI';
+use Try::Tiny;
sub _rebless {
my $self = shift;
# XXX This should be using an OpenSchema method of some sort, but I don't know
# how.
# Current version is stolen from Sybase.pm
- my $dbtype = eval {
- @{$self->_get_dbh
+ try {
+ my $dbtype = @{$self->_get_dbh
->selectrow_arrayref(qq{sp_server_info \@attribute_id=1})
- }[2]
- };
+ }[2];
- unless ($@) {
$dbtype =~ s/\W/_/gi;
my $subclass = "DBIx::Class::Storage::DBI::ADO::${dbtype}";
if ($self->load_optional_class($subclass) && !$self->isa($subclass)) {
bless $self, $subclass;
$self->_rebless;
}
- }
+ };
}
# Here I was just experimenting with ADO cursor types, left in as a comment in
use base qw/DBIx::Class::Cursor/;
+use Try::Tiny;
+
__PACKAGE__->mk_group_accessors('simple' =>
qw/sth/
);
my ($self) = @_;
# No need to care about failures here
- eval { $self->sth->finish if $self->sth && $self->sth->{Active} };
+ try { $self->sth->finish }
+ if $self->sth && $self->sth->{Active};
$self->_soft_reset;
return undef;
}
my ($self) = @_;
# None of the reasons this would die matter if we're in DESTROY anyways
- local $@;
- eval { $self->sth->finish if $self->sth && $self->sth->{Active} };
+ try { $self->sth->finish }
+ if $self->sth && $self->sth->{Active};
}
1;
use base qw/DBIx::Class::Storage::DBI/;
use mro 'c3';
use List::Util();
+use Try::Tiny;
=head1 NAME
local $dbh->{RaiseError} = 1;
local $dbh->{PrintError} = 0;
- eval {
+ return try {
$dbh->do('select 1 from rdb$database');
+ 1;
+ } catch {
+ 0;
};
-
- return $@ ? 0 : 1;
}
# We want dialect 3 for new features and quoting to work, DBD::InterBase uses
use base qw/DBIx::Class::Storage::DBI::UniqueIdentifier/;
use mro 'c3';
+use Try::Tiny;
use List::Util();
);
my $dbh = $self->_get_dbh;
- eval { $dbh->do ($sql) };
- if ($@) {
+ try { $dbh->do ($sql) }
+ catch {
$self->throw_exception (sprintf "Error executing '%s': %s",
$sql,
$dbh->errstr,
);
- }
+ };
}
sub _unset_identity_insert {
# this should bring back the result of SELECT SCOPE_IDENTITY() we tacked
# on in _prep_for_execute above
- my ($identity) = eval { $sth->fetchrow_array };
+ my ($identity) = try { $sth->fetchrow_array };
# SCOPE_IDENTITY failed, but we can do something else
if ( (! $identity) && $self->_identity_method) {
# stored procedures like xp_msver, or version detection failed for some
# other reason.
# So, we use a query to check if RNO is implemented.
- $have_rno = 1 if (eval { local $@; ($self->_get_dbh
- ->selectrow_array('SELECT row_number() OVER (ORDER BY rand())')
- )[0] });
+ try {
+ $self->_get_dbh->selectrow_array('SELECT row_number() OVER (ORDER BY rand())');
+ $have_rno = 1;
+ };
}
$self->{_sql_maker_opts} = {
local $dbh->{RaiseError} = 1;
local $dbh->{PrintError} = 0;
- eval {
+ return try {
$dbh->do('select 1');
+ 1;
+ } catch {
+ 0;
};
-
- return $@ ? 0 : 1;
}
package # hide from PAUSE
use base qw/DBIx::Class::Storage::DBI/;
use mro 'c3';
+use Try::Tiny;
sub _rebless {
- my ($self) = @_;
-
- my $dbtype = eval { $self->_get_dbh->get_info(17) };
-
- unless ( $@ ) {
- # Translate the backend name into a perl identifier
- $dbtype =~ s/\W/_/gi;
- my $subclass = "DBIx::Class::Storage::DBI::ODBC::${dbtype}";
- if ($self->load_optional_class($subclass) && !$self->isa($subclass)) {
- bless $self, $subclass;
- $self->_rebless;
- }
+ my ($self) = @_;
+
+ try {
+ my $dbtype = $self->_get_dbh->get_info(17);
+
+ # Translate the backend name into a perl identifier
+ $dbtype =~ s/\W/_/gi;
+ my $subclass = "DBIx::Class::Storage::DBI::ODBC::${dbtype}";
+
+ if ($self->load_optional_class($subclass) && !$self->isa($subclass)) {
+ bless $self, $subclass;
+ $self->_rebless;
}
+ };
}
1;
use List::Util();
use Scalar::Util ();
+use Try::Tiny;
__PACKAGE__->mk_group_accessors(simple => qw/
_using_dynamic_cursors
my $self = shift;
my $dbh = $self->_get_dbh;
- eval {
+ try {
local $dbh->{RaiseError} = 1;
local $dbh->{PrintError} = 0;
$dbh->do('SELECT @@IDENTITY');
- };
- if ($@) {
+ } catch {
$self->throw_exception (<<'EOF');
Your drivers do not seem to support dynamic cursors (odbc_cursortype => 2),
if you're using FreeTDS, make sure to set tds_version to 8.0 or greater.
EOF
- }
+ };
$self->_using_dynamic_cursors(1);
$self->_identity_method('@@identity');
use base qw/DBIx::Class::Storage::DBI/;
use mro 'c3';
+use Try::Tiny;
sub _rebless {
my ($self) = @_;
- my $version = eval { $self->_get_dbh->get_info(18); };
+ try {
+ my $version = $self->_get_dbh->get_info(18);
- if ( !$@ ) {
- my ($major, $minor, $patchlevel) = split(/\./, $version);
+ my ($major, $minor, $patchlevel) = split(/\./, $version);
- # Default driver
- my $class = $major <= 8
- ? 'DBIx::Class::Storage::DBI::Oracle::WhereJoins'
- : 'DBIx::Class::Storage::DBI::Oracle::Generic';
+ # Default driver
+ my $class = $major <= 8
+ ? 'DBIx::Class::Storage::DBI::Oracle::WhereJoins'
+ : 'DBIx::Class::Storage::DBI::Oracle::Generic';
- $self->ensure_class_loaded ($class);
- bless $self, $class;
- }
+ $self->ensure_class_loaded ($class);
+ bless $self, $class;
+ };
}
1;
use warnings;
use Scope::Guard ();
use Context::Preserve ();
+use Try::Tiny;
=head1 NAME
$sqltargs->{quote_table_names} = $quote_char ? 1 : 0;
$sqltargs->{quote_field_names} = $quote_char ? 1 : 0;
- my $oracle_version = eval { $self->_get_dbh->get_info(18) };
+ my $oracle_version = try { $self->_get_dbh->get_info(18) };
$sqltargs->{producer_args}{oracle_version} = $oracle_version;
local $dbh->{RaiseError} = 1;
local $dbh->{PrintError} = 0;
- eval {
+ return try {
$dbh->do('select 1 from dual');
+ 1;
+ } catch {
+ 0;
};
-
- return $@ ? 0 : 1;
}
sub _dbh_execute {
my ($dbh, $op, $extra_bind, $ident, $bind_attributes, @args) = @_;
my $wantarray = wantarray;
-
- my (@res, $exception, $retried);
-
- RETRY: {
- do {
- eval {
- if ($wantarray) {
- @res = $self->next::method(@_);
- } else {
- $res[0] = $self->next::method(@_);
- }
- };
- $exception = $@;
- if ($exception =~ /ORA-01003/) {
+ my ($retried, @res);
+ my $next = $self->next::can;
+ do {
+ try {
+ if ($wantarray) {
+ @res = $self->$next($dbh, $op, $extra_bind, $ident, $bind_attributes, @args);
+ }
+ else {
+ $res[0] = $self->$next($dbh, $op, $extra_bind, $ident, $bind_attributes, @args);
+ }
+ $retried++;
+ }
+ catch {
+ if (/ORA-01003/) {
# ORA-01003: no statement parsed (someone changed the table somehow,
# invalidating your cursor.)
my ($sql, $bind) = $self->_prep_for_execute($op, $extra_bind, $ident, \@args);
delete $dbh->{CachedKids}{$sql};
- } else {
- last RETRY;
}
- } while (not $retried++);
- }
-
- $self->throw_exception($exception) if $exception;
+ else {
+ $self->throw_exception($_);
+ }
+ };
+ } while (not $retried++);
- $wantarray ? @res : $res[0]
+ return $wantarray ? @res : $res[0];
}
=head2 get_autoinc_seq
$self->dbh_do('_dbh_get_autoinc_seq', $source, $col);
}
-=head2 columns_info_for
-
-This wraps the superclass version of this method to force table
-names to uppercase
-
-=cut
-
-sub columns_info_for {
- my ($self, $table) = @_;
-
- $self->next::method($table);
-}
-
=head2 datetime_parser_type
This sets the proper DateTime::Format module for use with
use Scalar::Util 'reftype';
use Hash::Merge;
use List::Util qw/min max reduce/;
+use Try::Tiny;
use namespace::clean -except => 'meta';
my @result;
my $want_array = wantarray;
- eval {
+ try {
if($want_array) {
@result = $coderef->(@args);
} elsif(defined $want_array) {
} else {
$coderef->(@args);
}
+ } catch {
+ $self->throw_exception("coderef returned an error: $_");
+ } finally {
+ ##Reset to the original state
+ $self->read_handler($current);
};
- ##Reset to the original state
- $self->read_handler($current);
-
- ##Exception testing has to come last, otherwise you might leave the
- ##read_handler set to master.
-
- if($@) {
- $self->throw_exception("coderef returned an error: $@");
- } else {
- return $want_array ? @result : $result[0];
- }
+ return $want_array ? @result : $result[0];
}
=head2 set_reliable_storage
use Carp::Clan qw/^DBIx::Class/;
use MooseX::Types::Moose qw/Num Int ClassName HashRef/;
use DBIx::Class::Storage::DBI::Replicated::Types 'DBICStorageDBI';
+use Try::Tiny;
use namespace::clean -except => 'meta';
sub _safely {
my ($self, $replicant, $name, $code) = @_;
- eval {
- $code->()
- };
- if ($@) {
+ return try {
+ $code->();
+ 1;
+ } catch {
$replicant->debugobj->print(sprintf(
"Exception trying to $name for replicant %s, error is %s",
- $replicant->_dbi_connect_info->[0], $@)
+ $replicant->_dbi_connect_info->[0], $_)
);
- return undef;
- }
-
- return 1;
+ undef;
+ };
}
=head2 connected_replicants
requires qw/_query_start/;
use namespace::clean -except => 'meta';
+use Try::Tiny;
=head1 NAME
around '_query_start' => sub {
my ($method, $self, $sql, @bind) = @_;
- my $dsn = eval { $self->dsn } || $self->_dbi_connect_info->[0];
+ my $dsn = (try { $self->dsn }) || $self->_dbi_connect_info->[0];
my($op, $rest) = (($sql=~m/^(\w+)(.+)$/),'NOP', 'NO SQL');
my $storage_type = $self->can('active') ? 'REPLICANT' : 'MASTER';
if ((reftype($dsn)||'') ne 'CODE') {
"$op [DSN_$storage_type=$dsn]$rest";
}
- elsif (my $id = eval { $self->id }) {
+ elsif (my $id = try { $self->id }) {
"$op [$storage_type=$id]$rest";
}
else {
use base qw/DBIx::Class::Storage::DBI::UniqueIdentifier/;
use mro 'c3';
use List::Util ();
+use Try::Tiny;
__PACKAGE__->mk_group_accessors(simple => qw/
_identity
my $table_name = $source->from;
$table_name = $$table_name if ref $table_name;
- my ($identity) = eval {
- local $@; $dbh->selectrow_array("SELECT GET_IDENTITY('$table_name')")
+ my ($identity) = try {
+ $dbh->selectrow_array("SELECT GET_IDENTITY('$table_name')")
};
if (defined $identity) {
sub build_datetime_parser {
my $self = shift;
my $type = "DateTime::Format::Strptime";
- eval "use ${type}";
- $self->throw_exception("Couldn't load ${type}: $@") if $@;
+ try {
+ eval "require ${type}"
+ }
+ catch {
+ $self->throw_exception("Couldn't load ${type}: $_");
+ };
+
return $type->new( pattern => '%Y-%m-%d %H:%M:%S.%6N' );
}
use strict;
use warnings;
+use Try::Tiny;
use base qw/DBIx::Class::Storage::DBI/;
sub _rebless {
my $self = shift;
- my $dbtype = eval {
- @{$self->_get_dbh->selectrow_arrayref(qq{sp_server_info \@attribute_id=1})}[2]
+ my $dbtype;
+ try {
+ $dbtype = @{$self->_get_dbh->selectrow_arrayref(qq{sp_server_info \@attribute_id=1})}[2]
+ } catch {
+ $self->throw_exception("Unable to estable connection to determine database type: $_")
};
- $self->throw_exception("Unable to estable connection to determine database type: $@")
- if $@;
-
if ($dbtype) {
$dbtype =~ s/\W/_/gi;
if ($dbh->{syb_no_child_con}) {
# if extra connections are not allowed, then ->ping is reliable
- my $ping = eval { $dbh->ping };
- return $@ ? 0 : $ping;
+ return try { $dbh->ping } catch { 0; };
}
- eval {
+ return try {
# XXX if the main connection goes stale, does opening another for this statement
# really determine anything?
$dbh->do('select 1');
+ 1;
+ } catch {
+ 0;
};
-
- return $@ ? 0 : 1;
}
sub _set_max_connect {
sub set_textsize {
my $self = shift;
- my $text_size = shift ||
- eval { $self->_dbi_connect_info->[-1]->{LongReadLen} } ||
+ my $text_size =
+ shift
+ ||
+ try { $self->_dbi_connect_info->[-1]->{LongReadLen} }
+ ||
32768; # the DBD::Sybase default
return unless defined $text_size;
use List::Util();
use Sub::Name();
use Data::Dumper::Concise();
+use Try::Tiny;
__PACKAGE__->mk_group_accessors('simple' =>
qw/_identity _blob_log_on_update _writer_storage _is_extra_storage
return 0;
});
- eval {
+ my $exception;
+ try {
my $bulk = $self->_bulk_storage;
my $guard = $bulk->txn_scope_guard;
);
$bulk->_query_end($sql);
+ } catch {
+ $exception = shift;
};
- my $exception = $@;
DBD::Sybase::set_cslib_cb($orig_cslib_cb);
if ($exception =~ /-Y option/) {
sub _update_blobs {
my ($self, $source, $blob_cols, $where) = @_;
- my @primary_cols = eval { $source->_pri_cols };
- $self->throw_exception("Cannot update TEXT/IMAGE column(s): $@")
- if $@;
+ my @primary_cols = try
+ { $source->_pri_cols }
+ catch {
+ $self->throw_exception("Cannot update TEXT/IMAGE column(s): $_")
+ };
# check if we're updating a single row by PK
my $pk_cols_in_where = 0;
my $table = $source->name;
my %row = %$row;
- my @primary_cols = eval { $source->_pri_cols} ;
- $self->throw_exception("Cannot update TEXT/IMAGE column(s): $@")
- if $@;
+ my @primary_cols = try
+ { $source->_pri_cols }
+ catch {
+ $self->throw_exception("Cannot update TEXT/IMAGE column(s): $_")
+ };
$self->throw_exception('Cannot update TEXT/IMAGE column(s) without primary key values')
if ((grep { defined $row{$_} } @primary_cols) != @primary_cols);
my $sth = $cursor->sth;
if (not $sth) {
-
$self->throw_exception(
"Could not find row in table '$table' for blob update:\n"
. Data::Dumper::Concise::Dumper (\%where)
);
}
- eval {
+ try {
do {
$sth->func('CS_GET', 1, 'ct_data_info') or die $sth->errstr;
} while $sth->fetch;
$sth->func($blob, length($blob), 'ct_send_data') or die $sth->errstr;
$sth->func('ct_finish_send') or die $sth->errstr;
- };
- my $exception = $@;
- $sth->finish if $sth;
- if ($exception) {
+ }
+ catch {
if ($self->using_freetds) {
$self->throw_exception (
- 'TEXT/IMAGE operation failed, probably because you are using FreeTDS: '
- . $exception
+ "TEXT/IMAGE operation failed, probably because you are using FreeTDS: $_"
);
- } else {
- $self->throw_exception($exception);
+ }
+ else {
+ $self->throw_exception($_);
}
}
+ finally {
+ $sth->finish if $sth;
+ };
}
}
use strict;
use warnings;
use Carp::Clan qw/^DBIx::Class/;
+use Try::Tiny;
sub new {
my ($class, $storage) = @_;
carp 'A DBIx::Class::Storage::TxnScopeGuard went out of scope without explicit commit or error. Rolling back.'
unless $exception;
- eval { $storage->txn_rollback };
- my $rollback_exception = $@;
+ my $rollback_exception;
+ try { $storage->txn_rollback }
+ catch { $rollback_exception = shift };
- if ($rollback_exception && $rollback_exception !~ /DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION/) {
+ if (defined $rollback_exception && $rollback_exception !~ /DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION/) {
if ($exception) {
$exception = "Transaction aborted: ${exception} "
."Rollback failed: ${rollback_exception}";
use Exporter;
use SQL::Translator::Utils qw(debug normalize_name);
-use Carp::Clan qw/^SQL::Translator|^DBIx::Class/;
+use Carp::Clan qw/^SQL::Translator|^DBIx::Class|^Try::Tiny/;
use Scalar::Util ();
+use Try::Tiny;
use base qw(Exporter);
croak 'No DBIx::Class::Schema' unless ($dbicschema);
if (!ref $dbicschema) {
- eval "use $dbicschema;";
- croak "Can't load $dbicschema ($@)" if($@);
+ try {
+ eval "require $dbicschema;"
+ }
+ catch {
+ croak "Can't load $dbicschema ($_)";
+ }
}
my $schema = $tr->schema;
use Test::More;
use Test::Exception;
+use Scope::Guard ();
use lib qw(t/lib);
use DBICTest;
[ $dsn2, $user2, $pass2 ],
);
-my @handles_to_clean;
+my $schema;
foreach my $info (@info) {
my ($dsn, $user, $pass) = @$info;
next unless $dsn;
- my $schema = DBICTest::Schema->clone;
+ $schema = DBICTest::Schema->clone;
$schema->connection($dsn, $user, $pass, {
on_connect_call => [ 'datetime_setup' ],
});
- push @handles_to_clean, $schema->storage->dbh;
+ my $sg = Scope::Guard->new(\&cleanup);
# coltype, col, date
my @dt_types = (
->search({ trackid => $row->trackid }, { select => [$col] })
->first
);
- is( $row->$col, $dt, 'DateTime roundtrip' );
+ is( $row->$col, $dt, "$type roundtrip" );
is $row->$col->nanosecond, $dt->nanosecond,
'nanoseconds survived' if 0+$dt->nanosecond;
done_testing;
# clean up our mess
-END {
- foreach my $dbh (@handles_to_clean) {
+sub cleanup {
+ if (my $dbh = $schema->storage->dbh) {
eval { $dbh->do("DROP TABLE $_") } for qw/track/;
}
}