Reduce to a warning the find-with-NULL-key exception from b7743dab
Peter Rabbitson [Fri, 14 Jan 2011 11:41:42 +0000 (12:41 +0100)]
Changes
lib/DBIx/Class/ResultSet.pm
t/61findnot.t

diff --git a/Changes b/Changes
index 2f6f95b..b675310 100644 (file)
--- a/Changes
+++ b/Changes
@@ -3,6 +3,10 @@ Revision history for DBIx::Class
     * New Features / Changes
         - Schema/resultsource instances are now crossreferenced via a new
           system guaranteeing leak-free mutually assuered destruction
+        - Switch to a warning when find() is invoked with both a 'key'
+          argument and a NULL-containing condition to satisfy the named
+          constraint. Previously (starting with 0.08124) an exception was
+          thrown.
 
     * Fixes
         - Revert default selection to being lazy again (eagerness introduced
index 5c862e3..d826e03 100644 (file)
@@ -739,7 +739,7 @@ sub find {
       }++;
 
       push @unique_queries, try {
-        $self->_build_unique_cond ($c_name, $call_cond)
+        $self->_build_unique_cond ($c_name, $call_cond, 'croak_on_nulls')
       } || ();
     }
 
@@ -797,8 +797,9 @@ sub _qualify_cond_columns {
   return \%aliased;
 }
 
+my $callsites_warned_ucond;
 sub _build_unique_cond {
-  my ($self, $constraint_name, $extra_cond) = @_;
+  my ($self, $constraint_name, $extra_cond, $croak_on_null) = @_;
 
   my @c_cols = $self->result_source->unique_constraint_columns($constraint_name);
 
@@ -810,15 +811,45 @@ sub _build_unique_cond {
   };
 
   # trim out everything not in $columns
-  $final_cond = { map { $_ => $final_cond->{$_} } @c_cols };
-
-  if (my @missing = grep { ! defined $final_cond->{$_} } (@c_cols) ) {
+  $final_cond = { map {
+    exists $final_cond->{$_}
+      ? ( $_ => $final_cond->{$_} )
+      : ()
+  } @c_cols };
+
+  if (my @missing = grep
+    { ! ($croak_on_null ? defined $final_cond->{$_} : exists $final_cond->{$_}) }
+    (@c_cols)
+  ) {
     $self->throw_exception( sprintf ( "Unable to satisfy requested constraint '%s', no values for column(s): %s",
       $constraint_name,
       join (', ', map { "'$_'" } @missing),
     ) );
   }
 
+  if (
+    !$croak_on_null
+      and
+    !$ENV{DBIC_NULLABLE_KEY_NOWARN}
+      and
+    my @undefs = grep { ! defined $final_cond->{$_} } (keys %$final_cond)
+  ) {
+    my $callsite = do {
+      my $w;
+      local $SIG{__WARN__} = sub { $w = shift };
+      carp;
+      $w
+    };
+
+    carp ( sprintf (
+      "NULL/undef values supplied for requested unique constraint '%s' (NULL "
+    . 'values in column(s): %s). This is almost certainly not what you wanted, '
+    . 'though you can set DBIC_NULLABLE_KEY_NOWARN to disable this warning.',
+      $constraint_name,
+      join (', ', map { "'$_'" } @undefs),
+    )) unless $callsites_warned_ucond->{$callsite}++;
+  }
+
   return $final_cond;
 }
 
index 6d23dc9..d7dde4d 100644 (file)
@@ -52,19 +52,37 @@ ok($art, 'Artist found by key in the resultset');
 
 # collapsing and non-collapsing are separate codepaths, thus the separate tests
 
+
 $artist_rs = $schema->resultset("Artist");
+
 warnings_exist {
   $artist_rs->find({})
 } qr/\QDBIx::Class::ResultSet::find(): Query returned more than one row.  SQL that returns multiple rows is DEPRECATED for ->find and ->single/
     =>  "Non-unique find generated a cursor inexhaustion warning";
+
 throws_ok {
   $artist_rs->find({}, { key => 'primary' })
 } qr/Unable to satisfy requested constraint 'primary'/;
 
+for (1, 0) {
+  warnings_like
+    sub {
+      $artist_rs->find({ artistid => undef }, { key => 'primary' })
+    },
+    $_ ? [
+      qr/undef values supplied for requested unique constraint.+almost certainly not what you wanted/,
+    ] : [],
+    'One warning on NULL conditions for constraint'
+  ;
+}
+
+
 $artist_rs = $schema->resultset("Artist")->search({}, { prefetch => 'cds' });
+
 warnings_exist {
   $artist_rs->find({})
 } qr/\QDBIx::Class::ResultSet::find(): Query returned more than one row/, "Non-unique find generated a cursor inexhaustion warning";
+
 throws_ok {
   $artist_rs->find({}, { key => 'primary' })
 } qr/Unable to satisfy requested constraint 'primary'/;