Index: update.php
===================================================================
RCS file: /cvs/drupal/drupal/update.php,v
retrieving revision 1.301
diff -u -r1.301 update.php
--- update.php	25 Aug 2009 21:53:47 -0000	1.301
+++ update.php	6 Sep 2009 14:44:57 -0000
@@ -140,23 +140,28 @@
   // Output a list of queries executed
   if (!empty($_SESSION['update_results'])) {
     $output .= '<div id="update-results">';
-    $output .= '<h2>The following queries were executed</h2>';
+    $output .= '<h2>The following updates returned messages</h2>';
     foreach ($_SESSION['update_results'] as $module => $updates) {
       $output .= '<h3>' . $module . ' module</h3>';
       foreach ($updates as $number => $queries) {
         if ($number != '#abort') {
-          $output .= '<h4>Update #' . $number . '</h4>';
-          $output .= '<ul>';
+          $messages = array();
           foreach ($queries as $query) {
+            // If there is no message for this update, don't show anything.
+            if (empty($query['query'])) {
+              continue;
+            }
             if ($query['success']) {
-              $output .= '<li class="success">' . $query['query'] . '</li>';
+              $messages[] = '<li class="success">' . $query['query'] . '</li>';
             }
             else {
-              $output .= '<li class="failure"><strong>Failed:</strong> ' . $query['query'] . '</li>';
+              $messages[] = '<li class="failure"><strong>Failed:</strong> ' . $query['query'] . '</li>';
             }
           }
-          if (!count($queries)) {
-            $output .= '<li class="none">No queries</li>';
+
+          if ($messages) {
+            $output .= '<h4>Update #' . $number . "</h4>\n";
+            $output .= '<ul>' . implode("\n", $messages) . "</ul>\n";
           }
         }
         $output .= '</ul>';
Index: includes/update.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/update.inc,v
retrieving revision 1.6
diff -u -r1.6 update.inc
--- includes/update.inc	1 Sep 2009 17:03:31 -0000	1.6
+++ includes/update.inc	6 Sep 2009 14:44:57 -0000
@@ -273,7 +273,7 @@
  *
  * Install profiles are now treated as modules by Drupal, and have an upgrade path
  * based on their schema version in the system table.
- * 
+ *
  * The install profile will be set to schema_version 0, as it has already been
  * installed. Any other hook_update_N functions provided by the install profile
  * will be run by update.php.
@@ -365,13 +365,31 @@
  * Perform one update and store the results which will later be displayed on
  * the finished page.
  *
- * An update function can force the current and all later updates for this
- * module to abort by returning a $ret array with an element like:
- * $ret['#abort'] = array('success' => FALSE, 'query' => 'What went wrong');
- * The schema version will not be updated in this case, and all the
- * aborted updates will continue to appear on update.php as updates that
+ * If an update function completes successfully, it should return a message
+ * as a string indicating success, for example:
+ * @code
+ * return t('New index added successfully.');
+ * @endcode
+ *
+ * Alternatively, it may return nothing. In that case, no message
+ * will be displayed at all.
+ *
+ * If it fails for whatever reason, it should throw an instance of
+ * DrupalUpdateException with an appropriate error message, for example:
+ * @code
+ * throw new DrupalUpdateException(t('Description of what went wrong'));
+ * @endcode
+ *
+ * If an exception is thrown, the current and all later updates for this module
+ * will be aborted. The schema version will not be updated in this case, and all
+ * the aborted updates will continue to appear on update.php as updates that
  * have not yet been run.
  *
+ * If an update function needs to be re-run as part of a batch process, it
+ * should accept the $sandbox array by reference as its first parameter
+ * and set the #finished property to the percentage completed that it is, as a
+ * fraction of 1.
+ *
  * @param $module
  *   The module whose update will be run.
  * @param $number
@@ -386,16 +404,49 @@
     return;
   }
 
+  if (!isset($context['log'])) {
+    $context['log'] = variable_get('update_log_queries', 0);
+  }
+
+  $ret = array();
   $function = $module . '_update_' . $number;
   if (function_exists($function)) {
-    $ret = $function($context['sandbox']);
+    try {
+      if ($context['log']) {
+        Database::startLog($function);
+      }
+      $ret['results']['query'] = $function($context['sandbox']);
+      $ret['results']['success'] = TRUE;
+
+      // @TODO Remove this block after all updates have been converted to
+      // return only strings.
+      if (is_array($ret['results']['query'])) {
+        $ret = $ret['results']['query'];
+      }
+    }
+    // @TODO We may want to do different error handling for different exception
+    // types, but for now we'll just print the message.
+    catch (Exception $e) {
+      $ret['#abort'] = array('success' => FALSE, 'query' => $e->getMessage());
+    }
+
+    if ($context['log']) {
+      $ret['queries'] = Database::getLog($function);
+    }
   }
 
+  // @TODO Remove this block after all updates have been converted to return
+  // only strings.
   if (isset($ret['#finished'])) {
     $context['finished'] = $ret['#finished'];
     unset($ret['#finished']);
   }
 
+  if (isset($context['sandbox']['#finished'])) {
+    $context['finished'] = $context['sandbox']['#finished'];
+    unset($context['sandbox']['#finished']);
+  }
+
   if (!isset($context['results'][$module])) {
     $context['results'][$module] = array();
   }
@@ -407,17 +458,21 @@
   if (!empty($ret['#abort'])) {
     $context['results'][$module]['#abort'] = TRUE;
   }
+
   // Record the schema update if it was completed successfully.
   if ($context['finished'] == 1 && empty($context['results'][$module]['#abort'])) {
     drupal_set_installed_schema_version($module, $number);
-    // Conserve memory and avoid errors by resetting all static variables.
-    drupal_static_reset();
   }
 
   $context['message'] = 'Updating ' . check_plain($module) . ' module';
 }
 
 /**
+ * @class Exception class used to throw error if a module update fails.
+ */
+class DrupalUpdateException extends Exception { }
+
+/**
  * Start the database update batch process.
  *
  * @param $start
@@ -518,7 +573,7 @@
 function update_get_update_list() {
   // Make sure that the system module is first in the list of updates.
   $ret = array('system' => array());
-  
+
   $modules = drupal_get_installed_schema_version(NULL, FALSE, TRUE);
   foreach ($modules as $module => $schema_version) {
     $pending = array();
@@ -532,7 +587,7 @@
         $ret[$module]['warning'] = '<em>' . $module . '</em> module can not be updated. Its schema version is ' . $schema_version . '. Updates up to and including ' . $last_removed . ' have been removed in this release. In order to update <em>' . $module . '</em> module, you will first <a href="http://drupal.org/upgrade">need to upgrade</a> to the last version in which these updates were available.';
         continue;
       }
-      
+
       $updates = drupal_map_assoc($updates);
       foreach (array_keys($updates) as $update) {
         if ($update > $schema_version) {
@@ -550,7 +605,7 @@
       }
     }
   }
-  
+
   if (empty($ret['system'])) {
     unset($ret['system']);
   }
