use DBIx::Class::Carp;
use Try::Tiny;
use Scalar::Util qw/weaken blessed/;
-use DBIx::Class::_Util qw(refcount quote_sub);
+use DBIx::Class::_Util qw(
+ refcount quote_sub scope_guard
+ is_exception dbic_internal_try
+);
use Devel::GlobalDestruction;
use namespace::clean;
my $me = shift;
my $rs_class = ref ($_[0]) || $_[0];
- return try {
+ return dbic_internal_try {
$rs_class->result_source_instance
} catch {
$me->throw_exception (
$storage_class =~ s/^::/DBIx::Class::Storage::/;
- try {
+ dbic_internal_try {
$self->ensure_class_loaded ($storage_class);
}
catch {
=cut
sub throw_exception {
- my $self = shift;
+ my ($self, @args) = @_;
+
+ if (
+ ! DBIx::Class::_Util::in_internal_try()
+ and
+ my $act = $self->exception_action
+ ) {
+
+ my $guard_disarmed;
+
+ my $guard = scope_guard {
+ return if $guard_disarmed;
+ local $SIG{__WARN__};
+ Carp::cluck("
+ !!! DBIx::Class INTERNAL PANIC !!!
+
+The exception_action() handler installed on '$self'
+aborted the stacktrace below via a longjmp (either via Return::Multilevel or
+plain goto, or Scope::Upper or something equally nefarious). There currently
+is nothing safe DBIx::Class can do, aside from displaying this error. A future
+version ( 0.082900, when available ) will reduce the cases in which the
+handler is invoked, but this is neither a complete solution, nor can it do
+anything for other software that might be affected by a similar problem.
+
+ !!! FIX YOUR ERROR HANDLING !!!
- if (my $act = $self->exception_action) {
- if ($act->(@_)) {
- DBIx::Class::Exception->throw(
+This guard was activated beginning"
+ );
+ };
+
+ eval {
+ # if it throws - good, we'll assign to @args in the end
+ # if it doesn't - do different things depending on RV truthiness
+ if( $act->(@args) ) {
+ $args[0] = (
"Invocation of the exception_action handler installed on $self did *not*"
.' result in an exception. DBIx::Class is unable to function without a reliable'
- .' exception mechanism, ensure that exception_action does not hide exceptions'
- ." (original error: $_[0])"
- );
+ .' exception mechanism, ensure your exception_action does not hide exceptions'
+ ." (original error: $args[0])"
+ );
+ }
+ else {
+ carp_unique (
+ "The exception_action handler installed on $self returned false instead"
+ .' of throwing an exception. This behavior has been deprecated, adjust your'
+ .' handler to always rethrow the supplied error'
+ );
+ }
+
+ 1;
}
- carp_unique (
- "The exception_action handler installed on $self returned false instead"
- .' of throwing an exception. This behavior has been deprecated, adjust your'
- .' handler to always rethrow the supplied error.'
+ or
+
+ # We call this to get the necessary warnings emitted and disregard the RV
+ # as it's definitely an exception if we got as far as this do{} block
+ is_exception(
+ $args[0] = $@
);
+
+ # Done guarding against https://github.com/PerlDancer/Dancer2/issues/1125
+ $guard_disarmed = 1;
}
- DBIx::Class::Exception->throw($_[0], $self->stacktrace);
+ DBIx::Class::Exception->throw( $args[0], $self->stacktrace );
}
=head2 deploy
sub thaw {
my ($self, $obj) = @_;
local $DBIx::Class::ResultSourceHandle::thaw_schema = $self;
- require Storable;
return Storable::thaw($obj);
}
=cut
sub freeze {
- require Storable;
return Storable::nfreeze($_[1]);
}
sub dclone {
my ($self, $obj) = @_;
local $DBIx::Class::ResultSourceHandle::thaw_schema = $self;
- require Storable;
return Storable::dclone($obj);
}
return $source if $params->{extra};
my $rs_class = $source->result_class;
- if ($rs_class and my $rsrc = try { $rs_class->result_source_instance } ) {
+ if ($rs_class and my $rsrc = dbic_internal_try { $rs_class->result_source_instance } ) {
my %map = %{$self->class_mappings};
if (
exists $map{$rs_class}
my $global_phase_destroy;
sub DESTROY {
+ ### NO detected_reinvoked_destructor check
+ ### This code very much relies on being called multuple times
+
return if $global_phase_destroy ||= in_global_destruction;
my $self = shift;
last;
}
}
+
+ # Dummy NEXTSTATE ensuring the all temporaries on the stack are garbage
+ # collected before leaving this scope. Depending on the code above, this
+ # may very well be just a preventive measure guarding future modifications
+ undef;
}
sub _unregister_source {
carp_once "compose_connection deprecated as of 0.08000"
unless $INC{"DBIx/Class/CDBICompat.pm"};
- my $base = 'DBIx::Class::ResultSetProxy';
- try {
- eval "require ${base};"
+ dbic_internal_try {
+ require DBIx::Class::ResultSetProxy;
}
catch {
$self->throw_exception
- ("No arguments to load_classes and couldn't load ${base} ($_)")
+ ("No arguments to load_classes and couldn't load DBIx::Class::ResultSetProxy ($_)")
};
if ($self eq $target) {
foreach my $source_name ($self->sources) {
my $source = $self->source($source_name);
my $class = $source->result_class;
- $self->inject_base($class, $base);
+ $self->inject_base($class, 'DBIx::Class::ResultSetProxy');
$class->mk_classdata(resultset_instance => $source->resultset);
$class->mk_classdata(class_resolver => $self);
}
return $self;
}
- my $schema = $self->compose_namespace($target, $base);
+ my $schema = $self->compose_namespace($target, 'DBIx::Class::ResultSetProxy');
quote_sub "${target}::schema", '$s', { '$s' => \$schema };
$schema->connection(@info);
return $schema;
}
-1;
-
-=head1 AUTHOR AND CONTRIBUTORS
+=head1 FURTHER QUESTIONS?
-See L<AUTHOR|DBIx::Class/AUTHOR> and L<CONTRIBUTORS|DBIx::Class/CONTRIBUTORS> in DBIx::Class
+Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
-=head1 LICENSE
+=head1 COPYRIGHT AND LICENSE
-You may distribute this code under the same terms as Perl itself.
+This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
+by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
+redistribute it and/or modify it under the same terms as the
+L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
=cut
+
+1;