Index: modules/search/search.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.install,v
retrieving revision 1.6
diff -u -u -p -r1.6 search.install
--- modules/search/search.install	1 Sep 2006 07:40:08 -0000	1.6
+++ modules/search/search.install	21 May 2007 02:26:00 -0000
@@ -8,13 +8,6 @@ function search_install() {
   switch ($GLOBALS['db_type']) {
     case 'mysql':
     case 'mysqli':
-      db_query("CREATE TABLE {search_dataset} (
-        sid int unsigned NOT NULL default '0',
-        type varchar(16) default NULL,
-        data longtext NOT NULL,
-        KEY sid_type (sid, type)
-      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
-
       db_query("CREATE TABLE {search_index} (
         word varchar(50) NOT NULL default '',
         sid int unsigned NOT NULL default '0',
@@ -25,7 +18,7 @@ function search_install() {
         KEY sid_type (sid, type),
         KEY from_sid_type (fromsid, fromtype),
         KEY word (word)
-      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
+      ) ENGINE=MyISAM /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
 
       db_query("CREATE TABLE {search_total} (
         word varchar(50) NOT NULL default '',
@@ -34,13 +27,6 @@ function search_install() {
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
       break;
     case 'pgsql':
-      db_query("CREATE TABLE {search_dataset} (
-        sid int_unsigned NOT NULL default '0',
-        type varchar(16) default NULL,
-        data text NOT NULL
-      )");
-      db_query("CREATE INDEX {search_dataset}_sid_type_idx ON {search_dataset} (sid, type)");
-
       db_query("CREATE TABLE {search_index} (
         word varchar(50) NOT NULL default '',
         sid int_unsigned NOT NULL default '0',
@@ -66,7 +52,6 @@ function search_install() {
  * Implementation of hook_uninstall().
  */
 function search_uninstall() {
-  db_query('DROP TABLE {search_dataset}');
   db_query('DROP TABLE {search_index}');
   db_query('DROP TABLE {search_total}');
   variable_del('minimum_word_size');
Index: modules/search/search.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.module,v
retrieving revision 1.222
diff -u -u -p -r1.222 search.module
--- modules/search/search.module	15 May 2007 05:43:16 -0000	1.222
+++ modules/search/search.module	21 May 2007 02:26:01 -0000
@@ -291,7 +291,6 @@ function search_wipe($sid = NULL, $type 
     module_invoke_all('search', 'reset');
   }
   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);
@@ -620,9 +619,6 @@ 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);
-
   // Insert results into search index
   foreach ($results[0] as $word => $score) {
     db_query("INSERT INTO {search_index} (word, sid, type, score) VALUES ('%s', %d, '%s', %f)", $word, $sid, $type, $score);
@@ -679,6 +675,7 @@ function search_parse_query($text) {
 
   // Classify tokens
   $or = FALSE;
+  $match_or = array('OR' => 1, 'or' => 1, 'Or' => 1, 'oR' => 1);
   foreach ($matches as $match) {
     $phrase = FALSE;
     // Strip off phrase quotes
@@ -696,7 +693,7 @@ function search_parse_query($text) {
     }
     // OR operator: instead of a single keyword, we store an array of all
     // OR'd keywords.
-    elseif ($match[2] == 'OR' && count($keys['positive'])) {
+    elseif (isset($match_or[$match[2]]) && count($keys['positive'])) {
       $last = array_pop($keys['positive']);
       // Starting a new OR?
       if (!is_array($last)) {
@@ -722,54 +719,36 @@ function search_parse_query($text) {
   // Convert keywords into SQL statements.
   $query = array();
   $query2 = array();
-  $arguments = array();
   $arguments2 = array();
   $matches = 0;
   // Positive matches
   foreach ($keys['positive'] as $key) {
     // Group of ORed terms
     if (is_array($key) && count($key)) {
-      $queryor = array();
-      $any = FALSE;
       foreach ($key as $or) {
-        list($q, $count) = _search_parse_query($or, $arguments2);
-        $any |= $count;
-        if ($q) {
-          $queryor[] = $q;
-          $arguments[] = $or;
-        }
-      }
-      if (count($queryor)) {
-        $query[] = '('. implode(' OR ', $queryor) .')';
-        // A group of OR keywords only needs to match once
-        $matches += ($any > 0);
+        _search_parse_query($or, $arguments2);
       }
     }
     // Single ANDed term
     else {
-      list($q, $count) = _search_parse_query($key, $arguments2);
-      if ($q) {
-        $query[] = $q;
-        $arguments[] = $key;
-        // Each AND keyword needs to match at least once
-        $matches += $count;
-      }
+      $count = _search_parse_query($key, $arguments2);
+      // Each AND keyword needs to match at least once
+      $matches += $count;
     }
   }
   // Negative matches
+  $arguments1 = array();
+  $negcount = 0;
   foreach ($keys['negative'] as $key) {
-    list($q) = _search_parse_query($key, $arguments2, TRUE);
-    if ($q) {
-      $query[] = $q;
-      $arguments[] = $key;
-    }
+    _search_parse_query($key, $arguments2, TRUE);
+    $arguments1[] = $key;
   }
-  $query = implode(' AND ', $query);
 
   // Build word-index conditions for the first pass
-  $query2 = substr(str_repeat("i.word = '%s' OR ", count($arguments2)), 0, -4);
+  $query2 = 'i.fromsid=0 AND i.word IN ('. implode(',', array_fill(0, count($arguments2), "'%s'")) .')';
 
-  return array($query, $arguments, $query2, $arguments2, $matches);
+  // return [0]=1 for legacy reasons so array indexes don't need to change
+  return array(1, $arguments1, $query2, $arguments2, $matches);
 }
 
 /**
@@ -791,8 +770,8 @@ function _search_parse_query(&$word, &$s
       }
     }
   }
-  // Return matching snippet and number of added words
-  return array("d.data ". ($not ? 'NOT ' : '') ."LIKE '%% %s %%'", $count);
+  // Return number of added words
+  return $count;
 }
 
 /**
@@ -801,28 +780,7 @@ 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.
- *
- * 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
+ * TODO: This comment needs to be corrected
  *
  * @param $keywords
  *   A search string as entered by the user.
@@ -868,34 +826,38 @@ function do_search($keywords, $type, $jo
   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 === NULL || $query[0] == '' || $query[2] == '') {
+  if ($query === NULL || $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');
-
-  // Calculate maximum relevance, to normalize it
-  $normalize = db_result(db_query('SELECT MAX(relevance) FROM temp_search_sids'));
-  if (!$normalize) {
-    return array();
+  $conditions1 = $where1 .' AND ('. $query[2] .") AND i.type = '%s'";
+  $arguments1 = array_merge($arguments1, $query[3], (array) $type);
+  $sql1 = "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 $conditions1 GROUP BY i.sid";
+  if ($query[4] > 1) {
+    $sql1 .= " HAVING COUNT(*) = %d";
+    $arguments1[] = $query[4];
   }
-  $select2 = str_replace('i.relevance', '('. (1.0 / $normalize) .' * i.relevance)', $select2);
 
-  // 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();
+  // add exclusionary terms
+  if (count($query[1])) {
+    $conditions2 = implode(',', array_fill(0, count($query[1]), '"%s"'));
+    $join2 .= " LEFT JOIN (SELECT x.sid FROM search_index x WHERE x.fromsid=0 AND x.word IN (". $conditions2 .") GROUP BY x.sid) e ON e.sid=i.sid WHERE e.sid IS NULL";
+    $arguments1 = array_merge($arguments1, $query[1]);
   }
-  $count_query = "SELECT $count";
+
+  // Second pass: only keep items that match the complicated keywords conditions (phrase search, negative keywords, ...)
+  $sql2 = "SELECT i.type, i.sid, $select2 FROM ($sql1) i $join2 $sort_parameters";
+
+  // combine the search terms
+  // modify the SQL here and pass no arguments so that the COUNT(*) query works
+  $arguments = array_merge($arguments2, $arguments1);
+  _db_query_callback($arguments, TRUE);
+  $sql = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $sql2);
 
   // Do actual search query
-  $result = pager_query("SELECT * FROM temp_search_results", 10, 0, $count_query);
+  $result = pager_query($sql, 10, 0, NULL);
   $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.113
diff -u -u -p -r1.113 system.install
--- modules/system/system.install	20 May 2007 12:34:47 -0000	1.113
+++ modules/system/system.install	21 May 2007 02:26:01 -0000
@@ -4062,6 +4062,24 @@ function system_update_6017() {
   return $ret;
 }
 
+function system_update_6018() {
+  // NOTE: this will frequently exceed the 240 timeout, as long as an hour
+  // HELP: what needs to be done to insure it actually completes
+  $ret = array();
+  switch ($GLOBALS['db_type']) {
+    case 'pgsql':
+      // TODO: what goes here?
+      break;
+    case 'mysql':
+    case 'mysqli':
+      $ret[] = update_sql("ALTER TABLE {search_index} ENGINE=MyISAM");
+      $ret[] = update_sql("ALTER IGNORE TABLE {search_index} ADD UNIQUE INDEX (sid, word, type, fromsid)");
+      $ret[] = update_sql("DROP TABLE {search_dataset}");
+      break;
+  }
+  return $ret[];
+}
+
 /**
  * @} End of "defgroup updates-5.x-to-6.x"
  * The next series of updates should start at 7000.
