@@ -19,7 +19,7 @@ use DBIx::Class::Carp;
19
19
use DBIx::Class::_Util qw(
20
20
UNRESOLVABLE_CONDITION
21
21
dbic_internal_try fail_on_internal_call
22
- refdesc emit_loud_diag
22
+ refdesc emit_loud_diag dump_value
23
23
) ;
24
24
use DBIx::Class::SQLMaker::Util qw( normalize_sqla_condition extract_equality_conditions ) ;
25
25
use DBIx::Class::ResultSource::FromSpec::Util ' fromspec_columns_info' ;
@@ -2238,6 +2238,7 @@ Internals::SvREADONLY($UNRESOLVABLE_CONDITION => 1);
2238
2238
# # returns a hash
2239
2239
# condition => (a valid *likely fully qualified* sqla cond structure)
2240
2240
# identity_map => (a hashref of foreign-to-self *unqualified* column equality names)
2241
+ # identity_map_matches_condition => (boolean, indicates whether the entire condition is expressed in the identity-map)
2241
2242
# join_free_condition => (a valid *fully qualified* sqla cond structure, maybe unset)
2242
2243
# inferred_values => (in case of an available join_free condition, this is a hashref of
2243
2244
# *unqualified* column/value *EQUALITY* pairs, representing an amalgamation
@@ -2591,29 +2592,51 @@ sub _resolve_relationship_condition {
2591
2592
" Unable to complete value inferrence - $exception_rel_id results in expression(s) instead of definitive values: %s " ,
2592
2593
do {
2593
2594
# FIXME - used for diag only, but still icky
2594
- my $sqlm = $self -> schema-> storage-> sql_maker;
2595
+ my $sqlm =
2596
+ dbic_internal_try { $self -> schema-> storage-> sql_maker }
2597
+ ||
2598
+ (
2599
+ require DBIx::Class::SQLMaker
2600
+ and
2601
+ DBIx::Class::SQLMaker-> new
2602
+ )
2603
+ ;
2595
2604
local $sqlm -> {quote_char };
2596
2605
local $sqlm -> {_dequalify_idents } = 1;
2597
2606
($sqlm -> _recurse_where({ -and => \@nonvalues }))[0]
2598
2607
}
2599
2608
)) if @nonvalues ;
2600
2609
2601
-
2602
2610
$ret -> {inferred_values } ||= {};
2603
2611
2604
2612
$ret -> {inferred_values }{$_ } = $args -> {infer_values_based_on }{$_ }
2605
2613
for keys %{$args -> {infer_values_based_on }};
2606
2614
}
2607
2615
2616
+ my $identity_map_incomplete ;
2617
+
2608
2618
# add the identities based on the main condition
2609
2619
# (may already be there, since easy to calculate on the fly in the HASH case)
2610
2620
if ( ! $ret -> {identity_map } ) {
2611
2621
2612
2622
my $col_eqs = extract_equality_conditions($ret -> {condition });
2613
2623
2624
+ $identity_map_incomplete ++ if (
2625
+ $ret -> {condition } eq UNRESOLVABLE_CONDITION
2626
+ or
2627
+ (
2628
+ keys %{$ret -> {condition }}
2629
+ !=
2630
+ keys %$col_eqs
2631
+ )
2632
+ );
2633
+
2614
2634
my $colinfos ;
2615
2635
for my $lhs (keys %$col_eqs ) {
2616
2636
2637
+ # start with the assumption it won't work
2638
+ $identity_map_incomplete ++;
2639
+
2617
2640
next if $col_eqs -> {$lhs } eq UNRESOLVABLE_CONDITION;
2618
2641
2619
2642
# there is no way to know who is right and who is left in a cref
@@ -2626,8 +2649,17 @@ sub _resolve_relationship_condition {
2626
2649
2627
2650
next unless $colinfos -> {$lhs }; # someone is engaging in witchcraft
2628
2651
2629
- if ( my $rhs_ref = is_literal_value( $col_eqs -> {$lhs } ) ) {
2630
-
2652
+ if ( my $rhs_ref =
2653
+ (
2654
+ ref $col_eqs -> {$lhs } eq ' HASH'
2655
+ and
2656
+ keys %{$col_eqs -> {$lhs }} == 1
2657
+ and
2658
+ exists $col_eqs -> {$lhs }{-ident}
2659
+ )
2660
+ ? [ $col_eqs -> {$lhs }{-ident} ] # repack to match the RV of is_literal_value
2661
+ : is_literal_value( $col_eqs -> {$lhs } )
2662
+ ) {
2631
2663
if (
2632
2664
$colinfos -> {$rhs_ref -> [0]}
2633
2665
and
@@ -2637,6 +2669,9 @@ sub _resolve_relationship_condition {
2637
2669
? ( $ret -> {identity_map }{$colinfos -> {$lhs }{-colname}} = $colinfos -> {$rhs_ref -> [0]}{-colname} )
2638
2670
: ( $ret -> {identity_map }{$colinfos -> {$rhs_ref -> [0]}{-colname}} = $colinfos -> {$lhs }{-colname} )
2639
2671
;
2672
+
2673
+ # well, what do you know!
2674
+ $identity_map_incomplete --;
2640
2675
}
2641
2676
}
2642
2677
elsif (
@@ -2656,6 +2691,10 @@ sub _resolve_relationship_condition {
2656
2691
}
2657
2692
}
2658
2693
2694
+ $ret -> {identity_map_matches_condition } = ($identity_map_incomplete ? 0 : 1)
2695
+ if $ret -> {identity_map };
2696
+
2697
+
2659
2698
# FIXME - temporary, to fool the idiotic check in SQLMaker::_join_condition
2660
2699
$ret -> {condition } = { -and => [ $ret -> {condition } ] } unless (
2661
2700
$ret -> {condition } eq UNRESOLVABLE_CONDITION
@@ -2667,6 +2706,50 @@ sub _resolve_relationship_condition {
2667
2706
)
2668
2707
);
2669
2708
2709
+
2710
+ if ( DBIx::Class::_ENV_::ASSERT_NO_INCONSISTENT_RELATIONSHIP_RESOLUTION ) {
2711
+
2712
+ my $sqlm =
2713
+ dbic_internal_try { $self -> schema-> storage-> sql_maker }
2714
+ ||
2715
+ (
2716
+ require DBIx::Class::SQLMaker
2717
+ and
2718
+ DBIx::Class::SQLMaker-> new
2719
+ )
2720
+ ;
2721
+
2722
+ local $sqlm -> {_dequalify_idents } = 1;
2723
+
2724
+ my ($cond_as_sql , $identmap_as_sql ) = map
2725
+ { join ' : ' , map { defined $_ ? $_ : ' {UNDEF}' } $sqlm -> _recurse_where($_ ) }
2726
+ (
2727
+ $ret -> {condition },
2728
+
2729
+ { map {
2730
+ # inverse because of how the idmap is declared
2731
+ $ret -> {identity_map }{$_ } => { -ident => $_ }
2732
+ } keys %{$ret -> {identity_map }} },
2733
+ )
2734
+ ;
2735
+
2736
+ emit_loud_diag(
2737
+ confess => 1,
2738
+ msg => sprintf (
2739
+ " Resolution of %s produced inconsistent metadata:\n\n "
2740
+ . " returned value of 'identity_map_matches_condition': %s \n "
2741
+ . " returned 'condition' rendered as de-qualified SQL: %s \n "
2742
+ . " returned 'identity_map' rendered as de-qualified SQL: %s \n\n "
2743
+ . " The condition declared on the misclassified relationship is: %s " ,
2744
+ $exception_rel_id ,
2745
+ ( $ret -> {identity_map_matches_condition } || 0 ),
2746
+ $cond_as_sql ,
2747
+ $identmap_as_sql ,
2748
+ dump_value( $rel_info -> {cond } ),
2749
+ ),
2750
+ ) if ( $ret -> {identity_map_matches_condition } xor ( $cond_as_sql eq $identmap_as_sql ) );
2751
+ }
2752
+
2670
2753
$ret ;
2671
2754
}
2672
2755
0 commit comments