? d7search.kpf
? search.patch
? search_34.patch
? search_34.patch.1
? sites/default/files
? sites/default/settings.php
Index: modules/search/search.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.module,v
retrieving revision 1.259
diff -u -p -r1.259 search.module
--- modules/search/search.module	10 Jul 2008 02:13:02 -0000	1.259
+++ modules/search/search.module	11 Jul 2008 20:41:33 -0000
@@ -770,10 +770,10 @@ function search_parse_query($text) {
   }
 
   // Convert keywords into SQL statements.
-  $query = array();
-  $query2 = array();
-  $arguments = array();
-  $arguments2 = array();
+  $phrase_query = array();
+  $keyword_query = array();
+  $phrase_arguments = array();
+  $keyword_arguments = array();
   $matches = 0;
   $simple_and = FALSE;
   $simple_or = FALSE;
@@ -785,15 +785,15 @@ function search_parse_query($text) {
       $queryor = array();
       $any = FALSE;
       foreach ($key as $or) {
-        list($q, $num_new_scores) = _search_parse_query($or, $arguments2);
+        list($q, $num_new_scores) = _search_parse_query($or, $keyword_arguments);
         $any |= $num_new_scores;
         if ($q) {
           $queryor[] = $q;
-          $arguments[] = $or;
+          $phrase_arguments[] = $or;
         }
       }
       if (count($queryor)) {
-        $query[] = '(' . implode(' OR ', $queryor) . ')';
+        $phrase_query[] = '(' . implode(' OR ', $queryor) . ')';
         // A group of OR keywords only needs to match once
         $matches += ($any > 0);
       }
@@ -801,10 +801,10 @@ function search_parse_query($text) {
     // Single ANDed term
     else {
       $simple_and = TRUE;
-      list($q, $num_new_scores, $num_valid_words) = _search_parse_query($key, $arguments2);
+      list($q, $num_new_scores, $num_valid_words) = _search_parse_query($key, $keyword_arguments);
       if ($q) {
-        $query[] = $q;
-        $arguments[] = $key;
+        $phrase_query[] = $q;
+        $phrase_arguments[] = $key;
         if (!$num_valid_words) {
           $simple = FALSE;
         }
@@ -818,19 +818,19 @@ function search_parse_query($text) {
   }
   // Negative matches
   foreach ($keys['negative'] as $key) {
-    list($q) = _search_parse_query($key, $arguments2, TRUE);
+    list($q) = _search_parse_query($key, $keyword_arguments, TRUE);
     if ($q) {
-      $query[] = $q;
-      $arguments[] = $key;
+      $phrase_query[] = $q;
+      $phrase_arguments[] = $key;
       $simple = FALSE;
     }
   }
-  $query = implode(' AND ', $query);
+  $phrase_query = implode(' AND ', $phrase_query);
 
   // Build word-index conditions for the first pass
-  $query2 = substr(str_repeat("i.word = '%s' OR ", count($arguments2)), 0, -4);
+  $keyword_query = substr(str_repeat("i.word = '%s' OR ", count($keyword_arguments)), 0, -4);
 
-  return array($query, $arguments, $query2, $arguments2, $matches, $simple, $warning);
+  return compact('phrase_query', 'phrase_arguments', 'keyword_query', 'keyword_arguments', 'matches', 'simple', 'warning');
 }
 
 /**
@@ -915,44 +915,69 @@ function _search_parse_query(&$word, &$s
 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]) {
-    if ($query[6] == 'or') {
-      drupal_set_message(t('Search for either of the two terms with uppercase <strong>OR</strong>. For example, <strong>cats OR dogs</strong>.'));
-    }
+  // If nothing is being searched for, get out of here.
+  if ($query['phrase_query'] == '' || $query['keyword_query'] == '') {
+    return array();
   }
-  if ($query === NULL || $query[0] == '' || $query[2] == '') {
+  
+  // Calculate maximum keyword relevance, to normalize it.
+  // Start with a COUNT query.
+  $count_arguments = $arguments1;
+  $count_joins = array($join1);
+  $count_wheres = array($where1);
+
+  if ($query['keyword_query']) {
+    $count_wheres[] = "($query[keyword_query])";
+    $count_arguments = array_merge($count_arguments, $query['keyword_arguments']);
+  }
+  $count_wheres[] = "i.type = '%s'";
+  $count_arguments[] = $type;
+  if (!$query['simple']) {
+    // Complex queries have a JOIN and WHERE for phrases plus extra arguments.
+    $count_joins[] = 'INNER JOIN {search_dataset} d ON i.sid = d.sid AND i.type = d.type';
+    $count_arguments = array_merge($count_arguments, $query['phrase_arguments']);
+    $count_wheres[] = "({$query['phrase_query']})";
+  }
+
+  $count_join = implode(' ', $count_joins);
+  $count_where = implode(' AND ', $count_wheres);
+  
+  // Execute the count query before the main query.
+  $count = db_result(db_query("SELECT COUNT(*) FROM (SELECT 1 FROM {search_index} i $count_join WHERE $count_where GROUP BY i.type, i.sid HAVING COUNT(*) >= %d) n1", $count_arguments));
+  // If there aren't any results, return empty.
+  if ($count == 0) {
     return array();
   }
+  // Build the simplest of all queries for db_pager().
+  $count_select = "SELECT $count";
 
   // 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 keyword relevance, to normalize it.
-  $select = "SELECT SUM(i.score * t.count) AS score FROM {search_index} i $join WHERE $conditions GROUP BY i.type, i.sid HAVING COUNT(*) >= %d ORDER BY score DESC";
-  $arguments = array_merge($arguments1, array($query[4]));
-  $normalize = db_result(db_query_range($select, $arguments, 0, 1));
+  $query_arguments = array_merge($arguments1, $query['keyword_arguments'], array($type));
+  $query_joins = array("INNER JOIN {search_total} t ON i.word = t.word", $join1);
+  $query_wheres = array($where1, "($query[keyword_query])", "i.type = '%s'");
+
+  if (!$query['simple']) {
+    $query_wheres[] = "($query[phrase_query])";
+    $query_arguments = array_merge($query_arguments, $query['phrase_arguments']);
+    $query_joins[] = "INNER JOIN {search_dataset} d ON i.sid = d.sid AND i.type = d.type";
+  }
+
+  $query_arguments[] = $query['matches'];
+  $query_join = implode(' ', $query_joins);
+  $query_where = implode(' AND ', $query_wheres);
+  
+  $select = "SELECT SUM(i.score * t.count) AS score FROM {search_index} i $query_join WHERE $query_where GROUP BY i.type, i.sid HAVING COUNT(*) >= %d ORDER BY score DESC";
+  $normalize = db_result(db_query_range($select, $query_arguments, 0, 1));
   if (!$normalize) {
     return array();
   }
-  $columns2 = str_replace('i.relevance', '(' . (1.0 / $normalize) . ' * SUM(i.score * t.count))', $columns2);
 
   // 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]));
-
+  $columns2 = str_replace('i.relevance', '(' . (1.0 / $normalize) . ' * SUM(i.score * t.count))', $columns2);
+  $select = "SELECT i.type, i.sid, $columns2 FROM {search_index} i $query_join $join2 WHERE $query_where GROUP BY i.type, i.sid HAVING COUNT(*) >= %d";
+  
   // Do actual search query
-  $result = pager_query("$select $sort_parameters", 10, 0, $count_select, $arguments);
+  $result = pager_query("$select $sort_parameters", 10, 0, $count_select, array_merge($arguments2, $query_arguments));
   $results = array();
   while ($item = db_fetch_object($result)) {
     $results[] = $item;
@@ -1069,6 +1094,7 @@ function search_box(&$form_state, $form_
   );
   $form['submit'] = array('#type' => 'submit', '#value' => t('Search'));
   $form['#submit'][] = 'search_box_form_submit';
+  $form['#submit'][] = 'search_form_submit';
 
   return $form;
 }
@@ -1078,7 +1104,8 @@ function search_box(&$form_state, $form_
  */
 function search_box_form_submit($form, &$form_state) {
   $form_id = $form['form_id']['#value'];
-  $form_state['redirect'] = 'search/node/' . trim($form_state['values'][$form_id]);
+  $form_state['values']['processed_keys'] = trim($form_state['values'][$form_id]);
+  $form_state['values']['module'] = 'node';
 }
 
 /**
Index: modules/search/search.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.pages.inc,v
retrieving revision 1.5
diff -u -p -r1.5 search.pages.inc
--- modules/search/search.pages.inc	14 Apr 2008 17:48:41 -0000	1.5
+++ modules/search/search.pages.inc	11 Jul 2008 20:41:33 -0000
@@ -124,6 +124,17 @@ function search_form_submit($form, &$for
     // Fall through to the drupal_goto() call.
   }
 
+  $query = search_parse_query($keys);
+  if ($query['keyword_query'] == '') {
+    form_set_error('keys', t('You must include at least one keyword with @count characters or more.', array('@count' => variable_get('minimum_word_size', 3))));
+  }
+
+  // Warn users if they have the word 'or' in their query that only uppercase
+  // OR is recognized as a boolean modifier.
+  if ($query['warning'] == 'or') {
+    drupal_set_message(t('Search for either of the two terms with uppercase <strong>OR</strong>. For example, <strong>cats OR dogs</strong>.'));
+  }
+
   $type = $form_state['values']['module'] ? $form_state['values']['module'] : 'node';
   $form_state['redirect'] = 'search/' . $type . '/' . $keys;
   return;
Index: modules/search/search.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.test,v
retrieving revision 1.6
diff -u -p -r1.6 search.test
--- modules/search/search.test	5 Jun 2008 21:55:45 -0000	1.6
+++ modules/search/search.test	11 Jul 2008 20:41:33 -0000
@@ -196,6 +196,66 @@ class SearchBikeShed extends DrupalWebTe
   }
 }
 
+class SearchAdvancedSearchForm extends DrupalWebTestCase {
+  protected $settings;
+  
+  /**
+   * Implementation of getInfo().
+   */
+  function getInfo() {
+    return array(
+      'name' => t('Advanced search form'),
+      'description' => t('Indexes content and tests advanced search form searches.'),
+      'group' => t('Search'),
+    );
+  }
+
+  /**
+   * Implementation of setUp().
+   */
+  function setUp() {
+    parent::setUp('search');
+    // Create and login user.
+    $test_user = $this->drupalCreateUser(array('access content', 'search content', 'use advanced search', 'administer nodes'));
+    $this->drupalLogin($test_user);
+
+    // Create initial node.
+    $node = $this->drupalCreateNode();
+    $this->settings = get_object_vars($node);
+    
+    // First update the index. This does the initial processing
+    node_update_index();
+    
+    // Then, run the shutdown function. Testing is a unique case where indexing
+    // and searching has to happen in the same request, so running the shutdown
+    // function manually is needed to finsh the indexing process.
+    search_update_totals();
+  }
+  
+  function testNodeType() {
+    $this->assertTrue($this->settings, t('Node type is page.'));
+    
+    // Search for the title of the node with a GET query
+    $this->drupalGet('search/node/' . drupal_urlencode($this->settings['title']));
+    $this->assertText($this->settings['title'], t('Page node is found with GET query.'));
+    
+    // Search for the title of the node with a POST query
+    $edit['or'] = $this->settings['title'];
+    $this->drupalPost('search/node', $edit, t('Advanced search'));
+    $this->assertText($this->settings['title'], t('Page node is found with POST query.'));
+    
+    $edit['type[page]'] = 'page';
+    $this->drupalPost('search/node', $edit, t('Advanced search'));
+    $this->assertText($this->settings['title'], t('Page node is found with POST query and type:page.'));
+    
+    unset($edit['type[page]']);
+    $edit['type[article]'] = 'article';
+    $this->drupalPost('search/node', $edit, t('Advanced search'));
+    $this->assertText('bike shed', t('Page node is found with POST query and type:page.'));
+    
+  }
+}
+
 class SearchRankingTestCase extends DrupalWebTestCase {
   /**
    * Implementation of getInfo().
