Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.611.2.20
diff -u -u -p -r1.611.2.20 common.inc
--- includes/common.inc	9 Jul 2008 19:34:30 -0000	1.611.2.20
+++ includes/common.inc	9 Sep 2008 12:28:56 -0000
@@ -293,6 +293,11 @@ function drupal_get_destination() {
  * @see drupal_get_destination()
  */
 function drupal_goto($path = '', $query = NULL, $fragment = NULL, $http_response_code = 302) {
+  // Ignore drupal_goto's within cron.php.
+  if (drupal_get_cron()) {
+    return;
+  }
+
   if (isset($_REQUEST['destination'])) {
     extract(parse_url(urldecode($_REQUEST['destination'])));
   }
@@ -1998,6 +2003,18 @@ function drupal_mail($mailkey, $to, $sub
 }
 
 /**
+ * Get/Set a status variable indicating that this is the cron page.
+ */
+function drupal_get_cron($set = NULL) {
+  static $cron = FALSE;
+
+  if (!is_null($set)) {
+    $cron = $set;
+  }
+  return $cron;
+}
+
+/**
  * Executes a cron run when called
  * @return
  * Returns TRUE if ran successfully
@@ -2029,6 +2046,9 @@ function drupal_cron_run() {
     // Register shutdown callback
     register_shutdown_function('drupal_cron_cleanup');
 
+    // Set a status variable indicating that this is the cron page.
+    drupal_get_cron(TRUE);
+
     // Lock cron semaphore
     variable_set('cron_semaphore', time());
 
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.776.2.30
diff -u -u -p -r1.776.2.30 node.module
--- modules/node/node.module	16 Jul 2008 19:04:21 -0000	1.776.2.30
+++ modules/node/node.module	9 Sep 2008 12:28:56 -0000
@@ -855,16 +855,14 @@ function node_search($op = 'search', $ke
       return t('Content');
 
     case 'reset':
-      variable_del('node_cron_last');
-      variable_del('node_cron_last_nid');
+      db_query("UPDATE {search_dataset} SET reindex = %d AND type = 'node'", time());
       return;
 
     case 'status':
-      $last = variable_get('node_cron_last', 0);
-      $last_nid = variable_get('node_cron_last_nid', 0);
       $total = db_result(db_query('SELECT COUNT(*) FROM {node} WHERE status = 1'));
-      $remaining = db_result(db_query('SELECT COUNT(*) FROM {node} n LEFT JOIN {node_comment_statistics} c ON n.nid = c.nid WHERE n.status = 1 AND ((GREATEST(n.created, n.changed, c.last_comment_timestamp) = %d AND n.nid > %d ) OR (n.created > %d OR n.changed > %d OR c.last_comment_timestamp > %d))', $last, $last_nid, $last, $last, $last));
-      return array('remaining' => $remaining, 'total' => $total);
+      $remaining = db_result(db_query("SELECT COUNT(*) FROM {node} n LEFT JOIN {search_dataset} d ON d.type = 'node' AND d.sid = n.nid WHERE n.status = 1 AND (d.sid IS NULL OR d.reindex > 0)"));
+      $pending = db_result(db_query("SELECT COUNT(*) FROM {node} n LEFT JOIN {search_dataset} d ON d.type = 'node' AND d.sid = n.nid WHERE n.status = 1 AND d.reindex < 0"));
+      return array('remaining' => $remaining, 'total' => $total, 'pending' => $pending);
 
     case 'admin':
       $form = array();
@@ -935,7 +933,7 @@ function node_search($op = 'search', $ke
         $ranking[] = '%d * POW(2, (GREATEST(n.created, n.changed, c.last_comment_timestamp) - %d) * 6.43e-8)';
         $arguments2[] = $weight;
         $arguments2[] = (int)variable_get('node_cron_last', 0);
-        $join2 .= ' INNER JOIN {node} n ON n.nid = i.sid LEFT JOIN {node_comment_statistics} c ON c.nid = i.sid';
+        $join2 .= ' LEFT JOIN {node_comment_statistics} c ON c.nid = i.sid';
         $stats_join = TRUE;
         $total += $weight;
       }
@@ -2532,40 +2530,25 @@ function node_page_edit($node) {
 }
 
 /**
- * shutdown function to make sure we always mark the last node processed.
- */
-function node_update_shutdown() {
-  global $last_change, $last_nid;
-
-  if ($last_change && $last_nid) {
-    variable_set('node_cron_last', $last_change);
-    variable_set('node_cron_last_nid', $last_nid);
-  }
-}
-
-/**
  * Implementation of hook_update_index().
  */
 function node_update_index() {
-  global $last_change, $last_nid;
-
-  register_shutdown_function('node_update_shutdown');
-
-  $last = variable_get('node_cron_last', 0);
-  $last_nid = variable_get('node_cron_last_nid', 0);
   $limit = (int)variable_get('search_cron_limit', 100);
 
   // Store the maximum possible comments per thread (used for ranking by reply count)
   variable_set('node_cron_comments_scale', 1.0 / max(1, db_result(db_query('SELECT MAX(comment_count) FROM {node_comment_statistics}'))));
   variable_set('node_cron_views_scale', 1.0 / max(1, db_result(db_query('SELECT MAX(totalcount) FROM {node_counter}'))));
 
-  $result = db_query_range('SELECT GREATEST(IF(c.last_comment_timestamp IS NULL, 0, c.last_comment_timestamp), n.changed) as last_change, n.nid FROM {node} n LEFT JOIN {node_comment_statistics} c ON n.nid = c.nid WHERE n.status = 1 AND ((GREATEST(n.changed, c.last_comment_timestamp) = %d AND n.nid > %d) OR (n.changed > %d OR c.last_comment_timestamp > %d)) ORDER BY GREATEST(n.changed, c.last_comment_timestamp) ASC, n.nid ASC', $last, $last_nid, $last, $last, $last, 0, $limit);
+  $result = db_query_range("SELECT n.nid FROM {node} n LEFT JOIN {search_dataset} d ON d.type = 'node' AND d.sid = n.nid WHERE d.sid IS NULL OR d.reindex > 0 ORDER BY d.reindex ASC, n.nid ASC", 0, $limit);
 
   while ($node = db_fetch_object($result)) {
     $last_change = $node->last_change;
     $last_nid = $node->nid;
     $node = node_load($node->nid);
 
+    // Mark the node with an index is in progress indicator.
+    search_touch_node($last_nid, TRUE);
+
     // Build the node body.
     $node = node_build_content($node, FALSE, FALSE);
     $node->body = drupal_render($node->content);
Index: modules/search/search.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.install,v
retrieving revision 1.6.2.1
diff -u -u -p -r1.6.2.1 search.install
--- modules/search/search.install	30 Sep 2007 01:13:23 -0000	1.6.2.1
+++ modules/search/search.install	9 Sep 2008 12:28:56 -0000
@@ -12,6 +12,7 @@ function search_install() {
         sid int unsigned NOT NULL default '0',
         type varchar(16) default NULL,
         data longtext NOT NULL,
+        reindex int NOT NULL default '0',
         KEY sid_type (sid, type)
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
 
@@ -19,11 +20,8 @@ function search_install() {
         word varchar(50) NOT NULL default '',
         sid int unsigned NOT NULL default '0',
         type varchar(16) default NULL,
-        fromsid int unsigned NOT NULL default '0',
-        fromtype varchar(16) default NULL,
         score float default NULL,
         KEY sid_type (sid, type),
-        KEY from_sid_type (fromsid, fromtype),
         KEY word (word)
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
 
@@ -32,8 +30,18 @@ function search_install() {
         count float default NULL,
         PRIMARY KEY (word)
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
+
+      db_query("CREATE TABLE {search_node_links} (
+        sid int unsigned NOT NULL default '0',
+        type varchar(16) default NULL,
+        nid int unsigned NOT NULL default '0',
+        caption TEXT NOT NULL,
+        PRIMARY KEY sid_type_nid (sid, type, nid),
+        KEY nid (nid)
+      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
       break;
     case 'pgsql':
+      // @TODO: update for #146466
       db_query("CREATE TABLE {search_dataset} (
         sid int_unsigned NOT NULL default '0',
         type varchar(16) default NULL,
Index: modules/search/search.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.module,v
retrieving revision 1.209.2.6
diff -u -u -p -r1.209.2.6 search.module
--- modules/search/search.module	14 May 2008 06:35:29 -0000	1.209.2.6
+++ modules/search/search.module	9 Sep 2008 12:28:57 -0000
@@ -268,9 +268,11 @@ function search_wipe($sid = NULL, $type 
   }
   else {
     db_query("DELETE FROM {search_dataset} WHERE sid = %d AND type = '%s'", $sid, $type);
-    db_query("DELETE FROM {search_index} WHERE fromsid = %d AND fromtype = '%s'", $sid, $type);
-    // When re-indexing, keep link references
-    db_query("DELETE FROM {search_index} WHERE sid = %d AND type = '%s'". ($reindex ? " AND fromsid = 0" : ''), $sid, $type);
+    db_query("DELETE FROM {search_index} WHERE sid = %d AND type = '%s'", $sid, $type);
+    // Don't remove links if re-indexing.
+    if (!$reindex) {
+      db_query("DELETE FROM {search_node_links} WHERE sid = %d AND type = '%s'", $sid, $type);
+    }
   }
 }
 
@@ -566,18 +568,24 @@ function search_index($sid, $type, $text
               $word = (int)ltrim($word, '-0');
             }
 
+            // Links score mainly for the target.
             if ($link) {
               if (!isset($results[$linknid])) {
                 $results[$linknid] = array();
               }
-              $results[$linknid][$word] += $score * $focus;
+              $results[$linknid][] = $word;
+              // Reduce score of the link caption in the source.
+              $focus *= 0.2;
             }
-            else {
-              $results[0][$word] += $score * $focus;
-              // Focus is a decaying value in terms of the amount of unique words up to this point.
-              // From 100 words and more, it decays, to e.g. 0.5 at 500 words and 0.3 at 1000 words.
-              $focus = min(1, .01 + 3.5 / (2 + count($results[0]) * .015));
+            // Fall-through
+            if (!isset($results[0][$word])) {
+              $results[0][$word] = 0;
             }
+            $results[0][$word] += $score * $focus;
+
+            // Focus is a decaying value in terms of the amount of unique words up to this point.
+            // From 100 words and more, it decays, to e.g. 0.5 at 500 words and 0.3 at 1000 words.
+            $focus = min(1, .01 + 3.5 / (2 + count($results[0]) * .015));
           }
           $tagwords++;
           // Too many words inside a single tag probably mean a tag was accidentally left open.
@@ -594,7 +602,7 @@ function search_index($sid, $type, $text
   search_wipe($sid, $type, TRUE);
 
   // Insert cleaned up data into dataset
-  db_query("INSERT INTO {search_dataset} (sid, type, data) VALUES (%d, '%s', '%s')", $sid, $type, $accum);
+  db_query("INSERT INTO {search_dataset} (sid, type, data, reindex) VALUES (%d, '%s', '%s', %d)", $sid, $type, $accum, 0);
 
   // Insert results into search index
   foreach ($results[0] as $word => $score) {
@@ -603,13 +611,86 @@ function search_index($sid, $type, $text
   }
   unset($results[0]);
 
-  // Now insert links to nodes
+  // Get all previous links from this item.
+  $result = db_query("SELECT nid, caption FROM {search_node_links} WHERE sid = %d AND type = '%s'", $sid, $type);
+  $links = array();
+  while ($link = db_fetch_object($result)) {
+    $links[$link->nid] = $link->caption;
+  }
+
+  // Now store links to nodes.
   foreach ($results as $nid => $words) {
-    foreach ($words as $word => $score) {
-      db_query("INSERT INTO {search_index} (word, sid, type, fromsid, fromtype, score) VALUES ('%s', %d, '%s', %d, '%s', %f)", $word, $nid, 'node', $sid, $type, $score);
-      search_dirty($word);
+    $caption = implode(' ', $words);
+    if (isset($links[$nid])) {
+      if ($links[$nid] != $caption) {
+        // Update the existing link and mark the node for reindexing.
+        db_query("UPDATE {search_node_links} SET caption = '%s' WHERE sid = %d AND type = '%s' AND nid = %d", $caption, $sid, $type, $nid);
+        search_touch_node($nid);
+      }
+      // Unset the link to mark it as processed.
+      unset($links[$nid]);
+    }
+    else {
+      // Insert the existing link and mark the node for reindexing.
+      db_query("INSERT INTO {search_node_links} (caption, sid, type, nid) VALUES ('%s', %d, '%s', %d)", $caption, $sid, $type, $nid);
+      search_touch_node($nid);
     }
   }
+  // Any left-over links in $links no longer exist. Delete them and mark the nodes for reindexing.
+  foreach ($links as $nid) {
+    db_query("DELETE FROM {search_node_links} WHERE sid = %d AND type = '%s' AND nid = %d", $sid, $type, $nid);
+    search_touch_node($nid);
+  }
+}
+
+/**
+ * Change a node's changed timestamp to 'now' to force reindexing.
+ *
+ * @param $nid
+ *   The nid of the node that needs reindexing.
+ * @param $pending
+ *   A bool, TRUE indicating to reindex the node,
+ *           FALSE indicating that the node is currently being reindexed.
+ */
+function search_touch_node($nid, $pending = FALSE) {
+  db_query("UPDATE {search_dataset} SET reindex = %d WHERE sid = %d AND type = 'node'", (($pending) ? -1 : 1) * time(), $nid);
+}
+
+/**
+ * Implementation of hook_nodeapi().
+ */
+function search_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
+  switch ($op) {
+    // Transplant links to a node into the target node.
+    case 'update index':
+      $result = db_query("SELECT caption FROM {search_node_links} WHERE nid = %d", $node->nid);
+      $output = array();
+      while ($link = db_fetch_object($result)) {
+        $output[] = $link->caption;
+      }
+      return '<a>('. implode(', ', $output) .')</a>';
+    // Reindex the node when it is updated.  The node is automatically indexed
+    // when it is added, simply by being added to the node table.
+    case 'update':
+      search_touch_node($node->nid);
+      break;
+  }
+}
+
+/**
+ * Implementation of hook_comment().
+ */
+function search_comment($a1, $op) {
+  switch ($op) {
+    // Reindex the node when comments are added or changed
+    case 'insert':
+    case 'update':
+    case 'delete':
+    case 'publish':
+    case 'unpublish':
+      search_touch_node(is_array($a1) ? $a1['nid'] : $a1->nid);
+      break;
+  }
 }
 
 /**
@@ -638,7 +719,22 @@ function search_query_insert($keys, $opt
 /**
  * Parse a search query into SQL conditions.
  *
- * We build a query that matches the dataset bodies.
+ * We build two queries that matches the dataset bodies. @See do_search for
+ * more about these.
+ *
+ * @param $text
+ *   The search keys.
+ * @return
+ *   A list of six elements.
+ *    * A series of statements AND'd together which will be used to provide all
+ *      possible matches.
+ *    * Arguments for this query part.
+ *    * A series of exact word matches OR'd together.
+ *    * Arguments for this query part.
+ *    * A bool indicating whether this is a simple query or not. Negative
+ *      terms, presence of both AND / OR make this FALSE.
+ *    * A bool indicating the presence of a lowercase or. Maybe the user
+ *      wanted to use OR.
  */
 function search_parse_query($text) {
   $keys = array('positive' => array(), 'negative' => array());
@@ -652,12 +748,15 @@ function search_parse_query($text) {
 
   // Classify tokens
   $or = FALSE;
+  $or_warning = FALSE;
+  $simple = TRUE;
   foreach ($matches as $match) {
     $phrase = FALSE;
     // Strip off phrase quotes
     if ($match[2]{0} == '"') {
       $match[2] = substr($match[2], 1, -1);
       $phrase = TRUE;
+      $simple = FALSE;
     }
     // Simplify keyword according to indexing rules and external preprocessors
     $words = search_simplify($match[2]);
@@ -681,6 +780,9 @@ function search_parse_query($text) {
     }
     // Plain keyword
     else {
+      if ($match[2] == 'or') {
+        $or_warning = TRUE;
+      }
       if ($or) {
         // Add to last element (which is an array)
         $keys['positive'][count($keys['positive']) - 1] = array_merge($keys['positive'][count($keys['positive']) - 1], $words);
@@ -698,10 +800,13 @@ function search_parse_query($text) {
   $arguments = array();
   $arguments2 = array();
   $matches = 0;
+  $simple_and = FALSE;
+  $simple_or = FALSE;
   // Positive matches
   foreach ($keys['positive'] as $key) {
     // Group of ORed terms
     if (is_array($key) && count($key)) {
+      $simple_or = TRUE;
       $queryor = array();
       $any = FALSE;
       foreach ($key as $or) {
@@ -720,6 +825,7 @@ function search_parse_query($text) {
     }
     // Single ANDed term
     else {
+      $simple_and = TRUE;
       list($q, $count) = _search_parse_query($key, $arguments2);
       if ($q) {
         $query[] = $q;
@@ -729,12 +835,16 @@ function search_parse_query($text) {
       }
     }
   }
+  if ($simple_and && $simple_or) {
+    $simple = FALSE;
+  }
   // Negative matches
   foreach ($keys['negative'] as $key) {
     list($q) = _search_parse_query($key, $arguments2, TRUE);
     if ($q) {
       $query[] = $q;
       $arguments[] = $key;
+      $simple = FALSE;
     }
   }
   $query = implode(' AND ', $query);
@@ -742,7 +852,7 @@ function search_parse_query($text) {
   // Build word-index conditions for the first pass
   $query2 = substr(str_repeat("i.word = '%s' OR ", count($arguments2)), 0, -4);
 
-  return array($query, $arguments, $query2, $arguments2, $matches);
+  return array($query, $arguments, $query2, $arguments2, $matches, $simple, $or_warning);
 }
 
 /**
@@ -774,28 +884,12 @@ function _search_parse_query(&$word, &$s
  * This function is normally only called by each module that support the
  * indexed search (and thus, implements hook_update_index()).
  *
- * Two queries are performed which can be extended by the caller.
- *
- * The first query selects a set of possible matches based on the search index
- * and any extra given restrictions. This is the classic "OR" search.
+ * Results are retrieved in two logical passes. However, the two passes are
+ * joined together into a single query.  And in the case of most simple
+ * queries the second pass is not even used.
  *
- * SELECT i.type, i.sid, SUM(i.score*t.count) AS relevance
- * FROM {search_index} i
- * INNER JOIN {search_total} t ON i.word = t.word
- * $join1
- * WHERE $where1 AND (...)
- * GROUP BY i.type, i.sid
- *
- * The second query further refines this set by verifying advanced text
- * conditions (such as AND, negative or phrase matches), and orders the results
- * on a the column or expression 'score':
- *
- * SELECT i.type, i.sid, $select2
- * FROM temp_search_sids i
- * INNER JOIN {search_dataset} d ON i.sid = d.sid AND i.type = d.type
- * $join2
- * WHERE (...)
- * ORDER BY score DESC
+ * The first pass selects a set of all possible matches, which has the benefit
+ * of also providing the exact result set for simple "AND" or "OR" searches.
  *
  * @param $keywords
  *   A search string as entered by the user.
@@ -814,7 +908,7 @@ function _search_parse_query(&$word, &$s
  * @param $arguments1
  *   (optional) Extra SQL arguments belonging to the first query.
  *
- * @param $select2
+ * @param $columns2
  *   (optional) Inserted into the SELECT pat of the second query. Must contain
  *   a column selected as 'score'.
  *   defaults to 'i.relevance AS score'
@@ -835,40 +929,45 @@ function _search_parse_query(&$word, &$s
  *
  * @ingroup search
  */
-function do_search($keywords, $type, $join1 = '', $where1 = '1', $arguments1 = array(), $select2 = 'i.relevance AS score', $join2 = '', $arguments2 = array(), $sort_parameters = 'ORDER BY score DESC') {
+function do_search($keywords, $type, $join1 = '', $where1 = '1', $arguments1 = array(), $columns2 = 'i.relevance AS score', $join2 = '', $arguments2 = array(), $sort_parameters = 'ORDER BY score DESC') {
   $query = search_parse_query($keywords);
 
   if ($query[2] == '') {
     form_set_error('keys', t('You must include at least one positive keyword with @count characters or more.', array('@count' => variable_get('minimum_word_size', 3))));
   }
+  if ($query[6]) {
+    form_set_error('keys', t('Try uppercase "OR" to search for either of two terms.'));
+  }
   if ($query === NULL || $query[0] == '' || $query[2] == '') {
     return array();
   }
 
-  // First pass: select all possible matching sids, doing a simple index-based OR matching on the keywords.
-  // 'matches' is used to reject those items that cannot possibly match the query.
-  $conditions = $where1 .' AND ('. $query[2] .") AND i.type = '%s'";
-  $arguments = array_merge($arguments1, $query[3], array($type, $query[4]));
-  $result = db_query_temporary("SELECT i.type, i.sid, SUM(i.score * t.count) AS relevance, COUNT(*) AS matches FROM {search_index} i INNER JOIN {search_total} t ON i.word = t.word $join1 WHERE $conditions GROUP BY i.type, i.sid HAVING COUNT(*) >= %d", $arguments, 'temp_search_sids');
+  // Build query for keyword normalization.
+  $conditions = "$where1 AND ($query[2]) AND i.type = '%s'";
+  $arguments1 = array_merge($arguments1, $query[3], array($type));
+  $join = "INNER JOIN {search_total} t ON i.word = t.word $join1";
+  if (!$query[5]) {
+    $conditions .= " AND ($query[0])";
+    $arguments1 = array_merge($arguments1, $query[1]);
+    $join .= " INNER JOIN {search_dataset} d ON i.sid = d.sid AND i.type = d.type";
+  }
 
-  // Calculate maximum relevance, to normalize it
-  $normalize = db_result(db_query('SELECT MAX(relevance) FROM temp_search_sids'));
+  // Calculate maximum keyword relevance, to normalize it.
+  $select = "SELECT MAX(i.score * t.count) FROM {search_index} i $join WHERE $conditions GROUP BY i.type, i.sid HAVING COUNT(*) >= %d";
+  $arguments = array_merge($arguments1, array($query[4]));
+  $normalize = db_result(db_query($select, $arguments));
   if (!$normalize) {
     return array();
   }
-  $select2 = str_replace('i.relevance', '('. (1.0 / $normalize) .' * i.relevance)', $select2);
+  $columns2 = str_replace('i.relevance', '('. (1.0 / $normalize) .' * (i.score * t.count))', $columns2);
 
-  // Second pass: only keep items that match the complicated keywords conditions (phrase search, negative keywords, ...)
-  $conditions = '('. $query[0] .')';
-  $arguments = array_merge($arguments2, $query[1]);
-  $result = db_query_temporary("SELECT i.type, i.sid, $select2 FROM temp_search_sids i INNER JOIN {search_dataset} d ON i.sid = d.sid AND i.type = d.type $join2 WHERE $conditions $sort_parameters", $arguments, 'temp_search_results');
-  if (($count = db_result(db_query('SELECT COUNT(*) FROM temp_search_results'))) == 0) {
-    return array();
-  }
-  $count_query = "SELECT $count";
+  // Build query to retrieve results.
+  $select = "SELECT i.type, i.sid, $columns2 FROM {search_index} i $join $join2 WHERE $conditions GROUP BY i.type, i.sid HAVING COUNT(*) >= %d";
+  $count_select =  "SELECT COUNT(*) FROM ($select) n1";
+  $arguments = array_merge($arguments2, $arguments1, array($query[4]));
 
   // Do actual search query
-  $result = pager_query("SELECT * FROM temp_search_results", 10, 0, $count_query);
+  $result = pager_query("$select $sort_parameters", 10, 0, $count_select, $arguments);
   $results = array();
   while ($item = db_fetch_object($result)) {
     $results[] = $item;
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.69.2.11
diff -u -u -p -r1.69.2.11 system.install
--- modules/system/system.install	25 Feb 2008 02:25:36 -0000	1.69.2.11
+++ modules/system/system.install	9 Sep 2008 12:28:57 -0000
@@ -3534,6 +3534,58 @@ function system_update_1022() {
 }
 
 /**
+ * Add Drupal 6.x search tables/updates.
+ */
+function system_update_1023() {
+  $ret = array();
+  if (db_table_exists('search_dataset')) {
+    switch ($GLOBALS['db_type']) {
+      case 'mysql':
+      case 'mysqli':
+        // Create the search_dataset.reindex column.
+        $ret[] = update_sql("ALTER TABLE {search_dataset} ADD reindex int NOT NULL default '0'");
+
+        // Drop the search_index.from fields which are no longer used.
+        $ret[] = update_sql("ALTER TABLE {search_index} DROP INDEX from_sid_type");
+        $ret[] = update_sql("ALTER TABLE {search_index} DROP fromsid");
+        $ret[] = update_sql("ALTER TABLE {search_index} DROP fromtype");
+
+        // Drop the search_dataset.sid_type index, so that it can be made unique.
+        $ret[] = update_sql("ALTER TABLE {search_dataset} DROP INDEX sid_type");
+
+        // Create the search_node_links Table.
+        $ret[] = update_sql("CREATE TABLE {search_node_links} (
+          sid int unsigned NOT NULL default '0',
+          type varchar(16) default NULL,
+          nid int unsigned NOT NULL default '0',
+          caption TEXT NOT NULL,
+          PRIMARY KEY sid_type_nid (sid, type, nid),
+          KEY nid (nid)
+        ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
+
+        // with the change to search_dataset.reindex, the search queue is handled differently,
+        // and this is no longer needed
+        variable_del('node_cron_last');
+
+        // Everything needs to be reindexed.
+        $ret[] = update_sql("UPDATE {search_dataset} SET reindex = 1");
+
+        // Add a unique index for the search_index.
+        // Since it's possible that some existing sites have duplicates,
+        // create the index using the IGNORE keyword, which ignores duplicate errors.
+        // However, pgsql doesn't support it
+        $ret[] = update_sql("ALTER IGNORE TABLE {search_index} ADD UNIQUE KEY sid_word_type (sid, word, type)");
+        $ret[] = update_sql("ALTER IGNORE TABLE {search_dataset} ADD UNIQUE KEY sid_type (sid, type)");
+        break;
+      case 'pgsql':
+        // @TODO:
+        break;
+    }
+  }
+  return $ret;
+}
+
+/**
  * @} End of "defgroup updates-5.x-extra"
  */
 

