From: Peter Rabbitson Date: Thu, 1 Sep 2016 18:22:55 +0000 (+0200) Subject: Protect several resolve_relationship_condition() callsites X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=e5c6382908ee65577e53c0771629384d70959a3d;p=dbsrgits%2FDBIx-Class.git Protect several resolve_relationship_condition() callsites Some external use of DBIx::Class::ParameterizedJoinHack revealed a couple sites where the relationship resolution may unexpectedly, yet non-fatally fail. This protects all the reasonable places (partially reverting b47fb9c0), downgrading the exceptions to once-per-callsite warnings. I did not have time to dig to find the underlying problem, there may very well be a real bug lurking around :/ For reproduction of the (now) warnings: see https://github.com/ctrlo/lenio --- diff --git a/lib/DBIx/Class/Relationship/Base.pm b/lib/DBIx/Class/Relationship/Base.pm index cfd23f2..ab18bed 100644 --- a/lib/DBIx/Class/Relationship/Base.pm +++ b/lib/DBIx/Class/Relationship/Base.pm @@ -8,10 +8,16 @@ use base qw/DBIx::Class/; use Scalar::Util qw/weaken blessed/; use DBIx::Class::_Util qw( UNRESOLVABLE_CONDITION DUMMY_ALIASPAIR - dbic_internal_try fail_on_internal_call + dbic_internal_try dbic_internal_catch fail_on_internal_call ); use DBIx::Class::SQLMaker::Util 'extract_equality_conditions'; use DBIx::Class::Carp; + +# FIXME - this should go away +# instead Carp::Skip should export usable keywords or something like that +my $unique_carper; +BEGIN { $unique_carper = \&carp_unique } + use namespace::clean; =head1 NAME @@ -525,8 +531,7 @@ sub related_resultset { my $relcond_is_freeform = ref $rel_info->{cond} eq 'CODE'; - my $jfc = $rsrc->_resolve_relationship_condition( - + my $rrc_args = { rel_name => $rel, self_result_object => $self, @@ -545,8 +550,37 @@ sub related_resultset { # out of an existing object, with the new source being at the head # of the FROM chain. Having a 'me' alias is nothing but expected there foreign_alias => 'me', + }; - )->{join_free_condition}; + my $jfc = ( + # In certain extraordinary circumstances the relationship resolution may + # throw (e.g. when walking through elaborate custom conds) + # In case the object is "real" (i.e. in_storage) we just go ahead and + # let the exception surface. Otherwise we carp and move on. + # + # The elaborate code-duplicating ternary is there because the xsified + # ->in_storage() is orders of magnitude faster than the Try::Tiny-like + # construct below ( perl's low level tooling is truly shit :/ ) + ( $self->in_storage or DBIx::Class::_Util::in_internal_try ) + ? $rsrc->_resolve_relationship_condition($rrc_args)->{join_free_condition} + : dbic_internal_try { + $rsrc->_resolve_relationship_condition($rrc_args)->{join_free_condition} + } + dbic_internal_catch { + $unique_carper->( + "Resolution of relationship '$rel' failed unexpectedly, " + . 'please relay the following error and seek assistance via ' + . DBIx::Class::_ENV_::HELP_URL . ". Encountered error: $_" + ); + + # FIXME - this is questionable + # force skipping re-resolution, and instead just return an UC rset + $relcond_is_freeform = 0; + + # RV + undef; + } + ); my $rel_rset; diff --git a/lib/DBIx/Class/Relationship/ManyToMany.pm b/lib/DBIx/Class/Relationship/ManyToMany.pm index e715f10..2812b6b 100644 --- a/lib/DBIx/Class/Relationship/ManyToMany.pm +++ b/lib/DBIx/Class/Relationship/ManyToMany.pm @@ -7,9 +7,10 @@ use warnings; use DBIx::Class::Carp; use DBIx::Class::_Util qw( quote_sub perlstring ); -# FIXME - this souldn't be needed -my $cu; -BEGIN { $cu = \&carp_unique } +# FIXME - this should go away +# instead Carp::Skip should export usable keywords or something like that +my $unique_carper; +BEGIN { $unique_carper = \&carp_unique } use namespace::clean; @@ -82,7 +83,7 @@ EOC my @extra_meth_qsub_args = ( { '$rel_attrs' => \{ alias => $f_rel, %{ $rel_attrs||{} } }, - '$carp_unique' => \$cu, + '$carp_unique' => \$unique_carper, }, { attributes => [ 'DBIC_method_is_indirect_sugar', diff --git a/lib/DBIx/Class/ResultSource/RowParser.pm b/lib/DBIx/Class/ResultSource/RowParser.pm index 069d331..6540dc7 100644 --- a/lib/DBIx/Class/ResultSource/RowParser.pm +++ b/lib/DBIx/Class/ResultSource/RowParser.pm @@ -10,10 +10,15 @@ use DBIx::Class::ResultSource::RowParser::Util qw( assemble_simple_parser assemble_collapsing_parser ); -use DBIx::Class::_Util 'DUMMY_ALIASPAIR'; +use DBIx::Class::_Util qw( DUMMY_ALIASPAIR dbic_internal_try dbic_internal_catch ); use DBIx::Class::Carp; +# FIXME - this should go away +# instead Carp::Skip should export usable keywords or something like that +my $unique_carper; +BEGIN { $unique_carper = \&carp_unique } + use namespace::clean; # Accepts a prefetch map (one or more relationships for the current source), @@ -187,13 +192,28 @@ sub _resolve_collapse { is_single => ( $inf->{attrs}{accessor} && $inf->{attrs}{accessor} ne 'multi' ), is_inner => ( ( $inf->{attrs}{join_type} || '' ) !~ /^left/i), rsrc => $self->related_source($rel), - fk_map => $self->_resolve_relationship_condition( - rel_name => $rel, + fk_map => ( + dbic_internal_try { + $self->_resolve_relationship_condition( + rel_name => $rel, + + # an API where these are optional would be too cumbersome, + # instead always pass in some dummy values + DUMMY_ALIASPAIR, + )->{identity_map}, + } + dbic_internal_catch { + + $unique_carper->( + "Resolution of relationship '$rel' failed unexpectedly, " + . 'please relay the following error and seek assistance via ' + . DBIx::Class::_ENV_::HELP_URL . ". Encountered error: $_" + ); - # an API where these are optional would be too cumbersome, - # instead always pass in some dummy values - DUMMY_ALIASPAIR, - )->{identity_map}, + # RV + +{} + } + ), }; }