Index: modules/search/search.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.module,v
retrieving revision 1.263
diff -u -u -p -r1.263 search.module
--- modules/search/search.module	21 Aug 2008 19:36:38 -0000	1.263
+++ modules/search/search.module	28 Aug 2008 07:45:41 -0000
@@ -278,21 +278,23 @@ function search_cron() {
  * up to date (even if cron times out or otherwise fails).
  */
 function search_update_totals() {
-  // Update word IDF (Inverse Document Frequency) counts for new/changed words
-  foreach (search_dirty() as $word => $dummy) {
-    // Get total count
-    $total = db_result(db_query("SELECT SUM(score) FROM {search_index} WHERE word = '%s'", $word));
-    // Apply Zipf's law to equalize the probability distribution
-    $total = log10(1 + 1/(max(1, $total)));
-    db_merge('search_total')->key(array('word' => $word))->fields(array('count' => $total))->execute();
+  // Update the search totals in chunks of 500 words at a time,
+  // This prevents using too big of a SQL clause.
+  $dirty = array_keys(search_dirty());
+  while (count($dirty) > 0) {
+    $dirty500 = array_splice($dirty, 0, 500);
+    $placeholders = db_placeholders($dirty500, 'varchar');
+    db_query("DELETE FROM {search_total} WHERE word IN (". $placeholders .")", $dirty500);
+    // Update word IDF (Inverse Document Frequency) counts for new/changed words,
+    // Applying Zipf's law to equalize the probability distribution
+    db_query("INSERT INTO {search_total} SELECT word, LOG(10, 1+1/GREATEST(1, SUM(score))) FROM {search_index} WHERE WORD IN (". $placeholders .") GROUP BY word", $dirty500);
   }
+  
   // Find words that were deleted from search_index, but are still in
   // search_total. We use a LEFT JOIN between the two tables and keep only the
-  // rows which fail to join.
-  $result = db_query("SELECT t.word AS realword, i.word FROM {search_total} t LEFT JOIN {search_index} i ON t.word = i.word WHERE i.word IS NULL");
-  while ($word = db_fetch_object($result)) {
-    db_query("DELETE FROM {search_total} WHERE word = '%s'", $word->realword);
-  }
+  // rows which fail to join. We use the two embedded subqueries to avoid
+  // the database 'update in FROM clause' error.
+  db_query("DELETE FROM {search_total} WHERE word IN (SELECT word FROM (SELECT t.word AS realword FROM {search_total} t LEFT JOIN {search_index} i ON t.word = i.word WHERE i.word IS NULL) t1)");
 }
 
 /**
