Fix oversight in subqueried MySQL update/delete
Peter Rabbitson [Tue, 9 Apr 2013 13:15:12 +0000 (15:15 +0200)]
Changes
lib/DBIx/Class/Storage/DBI/mysql.pm
t/71mysql.t
t/sqlmaker/mysql.t

diff --git a/Changes b/Changes
index 9a3ce19..416776c 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,10 @@
 Revision history for DBIx::Class
 
+    * Fixes
+        - Fix update/delete operations on resultsets *joining* the updated
+          table failing on MySQL. Resolves oversights in the fixes for
+          RT#81378 and RT#81897
+
 0.08210 2013-04-04 15:30 (UTC)
     * New Features / Changes
         - Officially deprecate the 'cols' and 'include_columns' resultset
index 3ace8e2..a2aa2fc 100644 (file)
@@ -78,7 +78,7 @@ sub _prep_for_execute {
   }
 
   local $sm->{_modification_target_referenced_re} =
-      qr/ (?<!DELETE) [\s\)] FROM \s (?: \` \Q$target_name\E \` | \Q$target_name\E ) [\s\(] /xi
+      qr/ (?<!DELETE) [\s\)] (?: FROM | JOIN ) \s (?: \` \Q$target_name\E \` | \Q$target_name\E ) [\s\(] /xi
     if $target_name;
 
   $self->next::method(@_);
index de1e2fd..e492417 100644 (file)
@@ -319,20 +319,34 @@ NULLINSEARCH: {
     );
   }
 
-  my $ac = $schema->resultset('Artist')->count_rs;
-  my $old_count = $ac->next;
-  $ac->reset;
+  is ($rs->count, 10, '10 artists present');
 
   my $orig_debug = $schema->storage->debug;
   $schema->storage->debug(1);
-  my $query_count = 0;
+  my $query_count;
   $schema->storage->debugcb(sub { $query_count++ });
+
+  $query_count = 0;
   $complex_rs->delete;
-  $schema->storage->debugcb(undef);
-  $schema->storage->debug($orig_debug);
 
   is ($query_count, 1, 'One delete query fired');
-  is ($old_count - $ac->next, 10, '10 Artists correctly deleted');
+  is ($rs->count, 0, '10 Artists correctly deleted');
+
+  $rs->create({
+    name => 'baby_with_cd',
+    cds => [ { title => 'babeeeeee', year => 2013 } ],
+  });
+  is ($rs->count, 1, 'Artist with cd created');
+
+  $query_count = 0;
+  $schema->resultset('CD')->search_related('artist',
+    { 'artist.name' => { -like => 'baby_with_%' } }
+  )->delete;
+  is ($query_count, 1, 'And one more delete query fired');
+  is ($rs->count, 0, 'Artist with cd deleted');
+
+  $schema->storage->debugcb(undef);
+  $schema->storage->debug($orig_debug);
 }
 
 ZEROINSEARCH: {
index 9de4c7f..b00691f 100644 (file)
@@ -49,7 +49,7 @@ bless ( $schema->storage, 'DBIx::Class::Storage::DBI::mysql' );
     'Correct delete-SQL with double-wrapped subquery',
   );
 
-  # and a really contrived example (we test it live in t/71mysql.t)
+  # and a couple of really contrived examples (we test them live in t/71mysql.t)
   my $rs = $schema->resultset('Artist')->search({ name => { -like => 'baby_%' } });
   my ($count_sql, @count_bind) = @${$rs->count_rs->as_query};
   eval {
@@ -86,6 +86,31 @@ bless ( $schema->storage, 'DBIx::Class::Storage::DBI::mysql' );
     [ ("'baby_%'") x 2 ],
   );
 
+  eval {
+    $schema->resultset('CD')->search_related('artist',
+      { 'artist.name' => { -like => 'baby_with_%' } }
+    )->delete
+  };
+
+  is_same_sql_bind (
+    $sql,
+    \@bind,
+    q(
+      DELETE FROM `artist`
+      WHERE `artistid` IN (
+        SELECT *
+          FROM (
+            SELECT `artist`.`artistid`
+              FROM cd `me`
+              INNER JOIN `artist` `artist`
+                ON `artist`.`artistid` = `me`.`artist`
+            WHERE `artist`.`name` LIKE ?
+          ) `_forced_double_subquery`
+      )
+    ),
+    [ "'baby_with_%'" ],
+  );
+
   $schema->storage->debugobj ($orig_debugobj);
   $schema->storage->debug ($orig_debug);
 }