Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.522
diff -u -r1.522 system.install
--- modules/system/system.install	5 Nov 2010 19:05:02 -0000	1.522
+++ modules/system/system.install	12 Nov 2010 18:54:35 -0000
@@ -2772,93 +2772,94 @@
     $sandbox['max'] = db_query("SELECT COUNT(*) FROM {system_update_7061}")->fetchField();
   }
 
-  $node_revisions = array();
-
   // Determine vids for this batch.
   // Process all files attached to a given revision during the same batch.
-  $limit = 100;
+  $limit = variable_get('upload_update_batch_size', 100);
   $vids = db_query_range('SELECT vid FROM {system_update_7061} WHERE vid > :lastvid ORDER BY vid', 0, $limit, array(':lastvid' => $sandbox['last_vid_processed']))
     ->fetchCol();
 
   // Retrieve information on all the files attached to these revisions.
-  $result = db_query('SELECT u.fid, u.vid, u.list, u.description, n.nid, n.type, u.weight FROM {upload} u INNER JOIN {node_revision} nr ON u.vid = nr.vid INNER JOIN {node} n ON n.nid = nr.nid WHERE u.vid IN (:vids) ORDER BY u.vid, u.weight, u.fid', array(':vids' => $vids));
-  foreach ($result as $record) {
-    // For each uploaded file, retrieve the corresponding data from the old
-    // files table (since upload doesn't know about the new entry in the
-    // file_managed table).
-    $file = db_select('files', 'f')
-      ->fields('f', array('fid', 'uid', 'filename', 'filepath', 'filemime', 'filesize', 'status', 'timestamp'))
-      ->condition('f.fid', $record->fid)
-      ->execute()
-      ->fetchAssoc();
-    if (!$file) {
-      continue;
+  if (!empty($vids)) {
+    $node_revisions = array();
+    $result = db_query('SELECT u.fid, u.vid, u.list, u.description, n.nid, n.type, u.weight FROM {upload} u INNER JOIN {node_revision} nr ON u.vid = nr.vid INNER JOIN {node} n ON n.nid = nr.nid WHERE u.vid IN (:vids) ORDER BY u.vid, u.weight, u.fid', array(':vids' => $vids));
+    foreach ($result as $record) {
+      // For each uploaded file, retrieve the corresponding data from the old
+      // files table (since upload doesn't know about the new entry in the
+      // file_managed table).
+      $file = db_select('files', 'f')
+        ->fields('f', array('fid', 'uid', 'filename', 'filepath', 'filemime', 'filesize', 'status', 'timestamp'))
+        ->condition('f.fid', $record->fid)
+        ->execute()
+        ->fetchAssoc();
+      if (!$file) {
+        continue;
+      }
+
+      // Add in the file information from the upload table.
+      $file['description'] = $record->description;
+      $file['display'] = $record->list;
+
+      // Create one record for each revision that contains all the uploaded
+      // files.
+      $node_revisions[$record->vid]['nid'] = $record->nid;
+      $node_revisions[$record->vid]['vid'] = $record->vid;
+      $node_revisions[$record->vid]['type'] = $record->type;
+      $node_revisions[$record->vid]['file'][LANGUAGE_NONE][] = $file;
     }
 
-    // Add in the file information from the upload table.
-    $file['description'] = $record->description;
-    $file['display'] = $record->list;
-
-    // Create one record for each revision that contains all the uploaded files.
-    $node_revisions[$record->vid]['nid'] = $record->nid;
-    $node_revisions[$record->vid]['vid'] = $record->vid;
-    $node_revisions[$record->vid]['type'] = $record->type;
-    $node_revisions[$record->vid]['file'][LANGUAGE_NONE][] = $file;
-  }
-
-  // Now that we know which files belong to which revisions, update the files'
-  // database entries, and save a reference to each file in the upload field on
-  // their node revisions.
-  $basename = variable_get('file_directory_path', conf_path() . '/files');
-  $scheme = file_default_scheme() . '://';
-  foreach ($node_revisions as $vid => $revision) {
-    foreach ($revision['file'][LANGUAGE_NONE] as $delta => $file) {
-      // We will convert filepaths to uri using the default scheme
-      // and stripping off the existing file directory path.
-      $file['uri'] = $scheme . str_replace($basename, '', $file['filepath']);
-      $file['uri'] = file_stream_wrapper_uri_normalize($file['uri']);
-      unset($file['filepath']);
-      // Insert into the file_managed table.
-      // Each fid should only be stored once in file_managed.
-      db_merge('file_managed')
-        ->key(array(
-          'fid' => $file['fid'],
-        ))
-        ->fields(array(
-          'uid' => $file['uid'],
-          'filename' => $file['filename'],
-          'uri' => $file['uri'],
-          'filemime' => $file['filemime'],
-          'filesize' => $file['filesize'],
-          'status' => $file['status'],
-          'timestamp' => $file['timestamp'],
-        ))
-        ->execute();
-
-      // Add the usage entry for the file.
-      $file = (object) $file;
-      file_usage_add($file, 'file', 'node', $revision['nid']);
-
-      // Update the node revision's upload file field with the file data.
-      $revision['file'][LANGUAGE_NONE][$delta] = array('fid' => $file->fid, 'display' => $file->display, 'description' => $file->description);
+    // Now that we know which files belong to which revisions, update the
+    // files'// database entries, and save a reference to each file in the
+    // upload field on their node revisions.
+    $basename = variable_get('file_directory_path', conf_path() . '/files');
+    $scheme = file_default_scheme() . '://';
+    foreach ($node_revisions as $vid => $revision) {
+      foreach ($revision['file'][LANGUAGE_NONE] as $delta => $file) {
+        // We will convert filepaths to uri using the default scheme
+        // and stripping off the existing file directory path.
+        $file['uri'] = $scheme . str_replace($basename, '', $file['filepath']);
+        $file['uri'] = file_stream_wrapper_uri_normalize($file['uri']);
+        unset($file['filepath']);
+        // Insert into the file_managed table.
+        // Each fid should only be stored once in file_managed.
+        db_merge('file_managed')
+          ->key(array(
+            'fid' => $file['fid'],
+          ))
+          ->fields(array(
+            'uid' => $file['uid'],
+            'filename' => $file['filename'],
+            'uri' => $file['uri'],
+            'filemime' => $file['filemime'],
+            'filesize' => $file['filesize'],
+            'status' => $file['status'],
+            'timestamp' => $file['timestamp'],
+          ))
+          ->execute();
+
+        // Add the usage entry for the file.
+        $file = (object) $file;
+        file_usage_add($file, 'file', 'node', $revision['nid']);
+
+        // Update the node revision's upload file field with the file data.
+        $revision['file'][LANGUAGE_NONE][$delta] = array('fid' => $file->fid, 'display' => $file->display, 'description' => $file->description);
+      }
+
+      // Write the revision's upload field data into the field_upload tables.
+      $node = (object) $revision;
+      _update_7000_field_sql_storage_write('node', $node->type, $node->nid, $node->vid, 'upload', $node->file);
+
+      // Update our progress information for the batch update.
+      $sandbox['progress']++;
+      $sandbox['last_vid_processed'] = $vid;
     }
-
-    // Write the revision's upload field data into the field_upload tables.
-    $node = (object) $revision;
-    _update_7000_field_sql_storage_write('node', $node->type, $node->nid, $node->vid, 'upload', $node->file);
-
-    // Update our progress information for the batch update.
-    $sandbox['progress']++;
-    $sandbox['last_vid_processed'] = $vid;
   }
 
   // If less than limit node revisions were processed, the update process is
   // finished.
-  if (count($node_revisions) < $limit) {
+  if (count($vids) < $limit) {
     $finished = TRUE;
   }
 
-
   // If there's no max value then there's nothing to update and we're finished.
   if (empty($sandbox['max']) || isset($finished)) {
     db_drop_table('upload');
Index: modules/simpletest/tests/upgrade/upgrade.upload.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/upgrade/upgrade.upload.test,v
retrieving revision 1.1
diff -u -r1.1 upgrade.upload.test
--- modules/simpletest/tests/upgrade/upgrade.upload.test	3 Oct 2010 23:19:52 -0000	1.1
+++ modules/simpletest/tests/upgrade/upgrade.upload.test	12 Nov 2010 18:54:34 -0000
@@ -20,6 +20,8 @@
       drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-6.upload.database.php',
     );
     parent::setUp();
+    // Set a small batch size to test multiple iterations of the batch.
+    $this->variable_set('upload_update_batch_size', 2);
 
     $this->uninstallModulesExcept(array('upload'));
   }
@@ -36,8 +38,11 @@
     $query->fieldCondition('upload');
     $entities = $query->execute();
     $revisions = $entities['node'];
-    // Node revisions 50-52 should have uploaded files.
-    $this->assertTrue((isset($revisions[50]) && isset($revisions[51]) && isset($revisions[52])), 'Nodes with uploaded files now contain filefield data.');
+    // Node revision 50 should not have uploaded files, as the entry in {files}
+    // is corrupted.
+    $this->assertFalse((isset($revisions[50])), 'Nodes with missing files do not contain filefield data.');
+    // Node revisions 51-53 should have uploaded files.
+    $this->assertTrue((isset($revisions[51]) && isset($revisions[52]) && isset($revisions[53])), 'Nodes with uploaded files now contain filefield data.');
     // The test database lists uploaded filenames in the body of each node with
     // uploaded files attached. Make sure all files are there in the same order.
     foreach ($revisions as $vid => $revision) {
@@ -58,9 +63,7 @@
       foreach ($files as $file) {
         $filenames[] = $file['filename'];
       }
-
-      $diff = array_diff($filenames, $recorded_filenames);
-      $this->assertTrue(empty($diff), 'The uploaded files are present in the same order after the upgrade.');
+      $this->assertIdentical($filenames, $recorded_filenames, 'The uploaded files are present in the same order after the upgrade.');
     }
   }
 }
Index: modules/simpletest/tests/upgrade/drupal-6.upload.database.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/upgrade/drupal-6.upload.database.php,v
retrieving revision 1.1
diff -u -r1.1 drupal-6.upload.database.php
--- modules/simpletest/tests/upgrade/drupal-6.upload.database.php	3 Oct 2010 23:19:52 -0000	1.1
+++ modules/simpletest/tests/upgrade/drupal-6.upload.database.php	12 Nov 2010 18:54:34 -0000
@@ -11,6 +11,10 @@
   'status',
   'timestamp',
 ))
+/*
+ * This entry is deliberately omitted to test the upgrade routine when facing
+ * possible data corruption.
+ *
 ->values(array(
   'fid' => '1',
   'uid' => '1',
@@ -20,7 +24,7 @@
   'filesize' => '1011',
   'status' => '1',
   'timestamp' => '1285700240',
-))
+)) */
 ->values(array(
   'fid' => '2',
   'uid' => '1',
@@ -132,14 +136,14 @@
 ))
 ->values(array(
   'nid' => '38',
-  'vid' => '51',
+  'vid' => '50',
   'type' => 'page',
   'language' => '',
-  'title' => 'node title 38 revision 51',
+  'title' => 'node title 38 revision 50',
   'uid' => '1',
   'status' => '1',
-  'created' => '1285700317',
-  'changed' => '1285700600',
+  'created' => '1285603317',
+  'changed' => '1285603317',
   'comment' => '0',
   'promote' => '0',
   'moderate' => '0',
@@ -152,7 +156,24 @@
   'vid' => '52',
   'type' => 'page',
   'language' => '',
-  'title' => 'node title 39 revision 53',
+  'title' => 'node title 39 revision 52',
+  'uid' => '1',
+  'status' => '1',
+  'created' => '1285700317',
+  'changed' => '1285700600',
+  'comment' => '0',
+  'promote' => '0',
+  'moderate' => '0',
+  'sticky' => '0',
+  'tnid' => '0',
+  'translate' => '0',
+))
+->values(array(
+  'nid' => '40',
+  'vid' => '53',
+  'type' => 'page',
+  'language' => '',
+  'title' => 'node title 40 revision 53',
   'uid' => '1',
   'status' => '1',
   'created' => '1285709012',
@@ -182,6 +203,17 @@
   'vid' => '50',
   'uid' => '1',
   'title' => 'node title 38 revision 50',
+  'body' => "Attachments:\r\npowered-blue-80x15.png",
+  'teaser' => "Attachments:\r\npowered-blue-80x15.png",
+  'log' => '',
+  'timestamp' => '1285603317',
+  'format' => '1',
+))
+->values(array(
+  'nid' => '39',
+  'vid' => '51',
+  'uid' => '1',
+  'title' => 'node title 39 revision 51',
   'body' => "Attachments:\r\npowered-blue-80x15.png\r\npowered-blue-88x31.png\r\npowered-blue-135x42.png",
   'teaser' => "Attachments:\r\npowered-blue-80x15.png\r\npowered-blue-88x31.png\r\npowered-blue-135x42.png",
   'log' => '',
@@ -189,10 +221,10 @@
   'format' => '1',
 ))
 ->values(array(
-  'nid' => '38',
-  'vid' => '51',
+  'nid' => '39',
+  'vid' => '52',
   'uid' => '1',
-  'title' => 'node title 38 revision 51',
+  'title' => 'node title 39 revision 52',
   'body' => "Attachments:\r\npowered-blue-88x31.png\r\npowered-black-80x15.png\r\npowered-black-135x42.png",
   'teaser' => "Attachments:\r\npowered-blue-88x31.png\r\npowered-black-80x15.png\r\npowered-black-135x42.png",
   'log' => '',
@@ -200,10 +232,10 @@
   'format' => '1',
 ))
 ->values(array(
-  'nid' => '39',
-  'vid' => '52',
+  'nid' => '40',
+  'vid' => '53',
   'uid' => '1',
-  'title' => 'node title 39 revision 53',
+  'title' => 'node title 40 revision 53',
   'body' => "Attachments:\r\nforum-hot-new.png\r\nforum-hot.png\r\nforum-sticky.png\r\nforum-new.png",
   'teaser' => "Attachments:\r\nforum-hot-new.png\r\nforum-hot.png\r\nforum-sticky.png\r\nforum-new.png",
   'log' => '',
@@ -276,7 +308,7 @@
   'weight',
 ))
 ->values(array(
-  'fid' => '2',
+  'fid' => '1',
   'nid' => '38',
   'vid' => '50',
   'description' => 'powered-blue-80x15.png',
@@ -284,73 +316,81 @@
   'weight' => '0',
 ))
 ->values(array(
+  'fid' => '2',
+  'nid' => '39',
+  'vid' => '51',
+  'description' => 'powered-blue-80x15.png',
+  'list' => '1',
+  'weight' => '0',
+))
+->values(array(
   'fid' => '3',
-  'nid' => '38',
-  'vid' => '50',
+  'nid' => '39',
+  'vid' => '51',
   'description' => 'powered-blue-88x31.png',
   'list' => '1',
   'weight' => '0',
 ))
 ->values(array(
   'fid' => '4',
-  'nid' => '38',
-  'vid' => '50',
+  'nid' => '39',
+  'vid' => '51',
   'description' => 'powered-blue-135x42.png',
   'list' => '1',
   'weight' => '0',
 ))
 ->values(array(
   'fid' => '3',
-  'nid' => '38',
-  'vid' => '51',
+  'nid' => '39',
+  'vid' => '52',
   'description' => 'powered-blue-88x31.png',
   'list' => '1',
   'weight' => '0',
 ))
 ->values(array(
   'fid' => '5',
-  'nid' => '38',
-  'vid' => '51',
+  'nid' => '39',
+  'vid' => '52',
   'description' => 'powered-black-80x15.png',
   'list' => '1',
   'weight' => '0',
 ))
 ->values(array(
   'fid' => '6',
-  'nid' => '38',
-  'vid' => '51',
+  'nid' => '39',
+  'vid' => '52',
   'description' => 'powered-black-135x42.png',
   'list' => '1',
   'weight' => '0',
 ))
 ->values(array(
   'fid' => '7',
-  'nid' => '39',
-  'vid' => '52',
+  'nid' => '40',
+  'vid' => '53',
   'description' => 'forum-hot-new.png',
   'list' => '1',
   'weight' => '-4',
 ))
 ->values(array(
   'fid' => '8',
-  'nid' => '39',
-  'vid' => '52',
+  'nid' => '40',
+  'vid' => '53',
   'description' => 'forum-hot.png',
   'list' => '1',
   'weight' => '-3',
 ))
 ->values(array(
   'fid' => '10',
-  'nid' => '39',
-  'vid' => '52',
+  'nid' => '40',
+  'vid' => '53',
   'description' => 'forum-sticky.png',
   'list' => '1',
   'weight' => '-2',
 ))
 ->values(array(
   'fid' => '9',
-  'nid' => '39',
-  'vid' => '52',
+  'nid' => '40',
+  'vid' => '53',
   'description' => 'forum-new.png',
   'list' => '1',
   'weight' => '-1',
