From dbf07011fdf5458170ccd271c185de605c0edc52 Mon Sep 17 00:00:00 2001 From: "mnyromyr%tprac.de" Date: Thu, 20 Oct 2005 19:37:58 +0000 Subject: [PATCH] Bug 295088: Filter/Search term evaluator is extremely sub-optimal; p=Howard Chu , r=bienvenu, sr=dmose --- .../search/public/nsMsgSearchBoolExpression.h | 43 ++--- mailnews/base/search/src/nsMsgFilter.cpp | 11 +- mailnews/base/search/src/nsMsgFilter.h | 3 + mailnews/base/search/src/nsMsgLocalSearch.cpp | 165 +++++++++--------- mailnews/base/search/src/nsMsgLocalSearch.h | 45 +++-- .../base/search/src/nsMsgSearchAdapter.cpp | 3 +- .../base/search/src/nsMsgSearchSession.cpp | 9 +- mailnews/base/search/src/nsMsgSearchSession.h | 2 + 8 files changed, 141 insertions(+), 140 deletions(-) diff --git a/mailnews/base/search/public/nsMsgSearchBoolExpression.h b/mailnews/base/search/public/nsMsgSearchBoolExpression.h index 115dca3e5b2e..34335bd4e024 100644 --- a/mailnews/base/search/public/nsMsgSearchBoolExpression.h +++ b/mailnews/base/search/public/nsMsgSearchBoolExpression.h @@ -20,6 +20,7 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Howard Chu * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -51,13 +52,11 @@ representing the search terms and their boolean operators as a binary expression tree. Each node in the tree consists of either (1) a boolean operator and two nsMsgSearchBoolExpressions or - (2) if the node is a leaf node then it contains a search term. - With each search term that is part of the expression we also keep - track of either an evaluation value (XP_BOOL) or a character string. - Evaluation values are used for offline searching. The character + (2) if the node is a leaf node then it contains a search term. + With each search term that is part of the expression we may also keep + a character string. The character string is used to store the IMAP/NNTP encoding of the search term. This - makes evaluating the expression (for offline) or generating a search - encoding (for online) easier. + makes generating a search encoding (for online) easier. For IMAP/NNTP: nsMsgSearchBoolExpression has/assumes knowledge about how AND and OR search terms are combined according to IMAP4 and NNTP protocol. @@ -76,9 +75,7 @@ public: // create a leaf node expression nsMsgSearchBoolExpression(nsIMsgSearchTerm * aNewTerm, - PRBool aEvaluationValue = PR_TRUE, char * aEncodingString = NULL); - nsMsgSearchBoolExpression(nsIMsgSearchTerm * aNewTerm, char * aEncodingString); // create a non-leaf node expression containing 2 expressions // and a boolean operator @@ -90,18 +87,19 @@ public: ~nsMsgSearchBoolExpression(); // recursively destroys all sub // expressions as well - // accesors + // accessors // Offline - static nsMsgSearchBoolExpression * AddSearchTerm (nsMsgSearchBoolExpression * aOrigExpr, nsIMsgSearchTerm * aNewTerm, PRBool aEvaluationValue); - static nsMsgSearchBoolExpression * AddSearchTermWithEncoding (nsMsgSearchBoolExpression * aOrigExpr, nsIMsgSearchTerm * aNewTerm, char * aEncodingStr); // IMAP/NNTP + static nsMsgSearchBoolExpression * AddSearchTerm (nsMsgSearchBoolExpression * aOrigExpr, nsIMsgSearchTerm * aNewTerm, char * aEncodingStr); // IMAP/NNTP static nsMsgSearchBoolExpression * AddExpressionTree(nsMsgSearchBoolExpression * aOrigExpr, nsMsgSearchBoolExpression * aExpression, PRBool aBoolOp); // parses the expression tree and all - // expressions underneath this node using - // each EvaluationValue at each leaf to + // expressions underneath this node to // determine if the end result is PR_TRUE or PR_FALSE. - PRBool OfflineEvaluate(); + PRBool OfflineEvaluate(nsIMsgDBHdr *msgToMatch, + const char *defaultCharset, nsIMsgSearchScopeTerm *scope, + nsIMsgDatabase *db, const char *headers, PRUint32 headerSize, + PRBool Filtering); // assuming the expression is for online // searches, determine the length of the @@ -112,15 +110,6 @@ public: // memory in buffer with // the IMAP/NNTP encoding for the expression void GenerateEncodeStr(nsCString * buffer); -protected: - // if we are a leaf node, all we have is a search term - // and a Evaluation value for that search term - - nsIMsgSearchTerm * m_term; - PRBool m_evalValue; - - // store IMAP/NNTP encoding for the search term if applicable - nsCString m_encodingStr; // if we are not a leaf node, then we have two other expressions // and a boolean operator @@ -128,6 +117,13 @@ protected: nsMsgSearchBoolExpression * m_rightChild; nsMsgSearchBooleanOperator m_boolOp; +protected: + // if we are a leaf node, all we have is a search term + + nsIMsgSearchTerm * m_term; + + // store IMAP/NNTP encoding for the search term if applicable + nsCString m_encodingStr; // internal methods @@ -138,7 +134,6 @@ protected: // that by calling leftToRightAddTerm. If future forms of evaluation // need to be supported, add new methods here for proper tree construction. nsMsgSearchBoolExpression * leftToRightAddTerm(nsIMsgSearchTerm * newTerm, - PRBool EvaluationValue, char * encodingStr); }; diff --git a/mailnews/base/search/src/nsMsgFilter.cpp b/mailnews/base/search/src/nsMsgFilter.cpp index df686fd13735..344d5cabb115 100644 --- a/mailnews/base/search/src/nsMsgFilter.cpp +++ b/mailnews/base/search/src/nsMsgFilter.cpp @@ -22,6 +22,7 @@ * Contributor(s): * Pierre Phaneuf * Seth Spitzer + * Howard Chu * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -170,7 +171,8 @@ nsMsgRuleAction::GetStrValue(char **aStrValue) nsMsgFilter::nsMsgFilter(): m_temporary(PR_FALSE), m_unparseable(PR_FALSE), - m_filterList(nsnull) + m_filterList(nsnull), + m_expressionTree(nsnull) { NS_NewISupportsArray(getter_AddRefs(m_termList)); NS_NewISupportsArray(getter_AddRefs(m_actionList)); @@ -180,6 +182,7 @@ nsMsgFilter::nsMsgFilter(): nsMsgFilter::~nsMsgFilter() { + delete m_expressionTree; } NS_IMPL_ISUPPORTS1(nsMsgFilter, nsIMsgFilter) @@ -243,7 +246,8 @@ NS_IMETHODIMP nsMsgFilter::AddTerm( NS_IMETHODIMP nsMsgFilter::AppendTerm(nsIMsgSearchTerm * aTerm) { NS_ENSURE_TRUE(aTerm, NS_ERROR_NULL_POINTER); - + // invalidate expression tree if we're changing the terms + delete m_expressionTree; return m_termList->AppendElement(NS_STATIC_CAST(nsISupports*,aTerm)); } @@ -391,6 +395,7 @@ NS_IMETHODIMP nsMsgFilter::GetSearchTerms(nsISupportsArray **aResult) NS_IMETHODIMP nsMsgFilter::SetSearchTerms(nsISupportsArray *aSearchList) { + delete m_expressionTree; m_termList = aSearchList; return NS_OK; } @@ -511,7 +516,7 @@ NS_IMETHODIMP nsMsgFilter::MatchHdr(nsIMsgDBHdr *msgHdr, nsIMsgFolder *folder, n nsXPIDLCString folderCharset; folder->GetCharset(getter_Copies(folderCharset)); nsresult rv = nsMsgSearchOfflineMail::MatchTermsForFilter(msgHdr, m_termList, - folderCharset.get(), scope, db, headers, headersSize, pResult); + folderCharset.get(), scope, db, headers, headersSize, &m_expressionTree, pResult); delete scope; return rv; } diff --git a/mailnews/base/search/src/nsMsgFilter.h b/mailnews/base/search/src/nsMsgFilter.h index 87417ad28cc2..d455ed714f79 100644 --- a/mailnews/base/search/src/nsMsgFilter.h +++ b/mailnews/base/search/src/nsMsgFilter.h @@ -21,6 +21,7 @@ * * Contributor(s): * David Bienvenu (bienvenu@nventure.com) + * Howard Chu * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -44,6 +45,7 @@ #include "nsIMsgFilter.h" #include "nsMsgSearchArray.h" #include "nsIMsgSearchScopeTerm.h" +#include "nsMsgSearchBoolExpression.h" class nsMsgRuleAction : public nsIMsgRuleAction { @@ -120,6 +122,7 @@ protected: nsCOMPtr m_scope; /* default for mail rules is inbox, but news rules could have a newsgroup - LDAP would be invalid */ nsCOMPtr m_actionList; + nsMsgSearchBoolExpression *m_expressionTree; }; #endif diff --git a/mailnews/base/search/src/nsMsgLocalSearch.cpp b/mailnews/base/search/src/nsMsgLocalSearch.cpp index 2f3a42e92d35..41d95130ea5c 100644 --- a/mailnews/base/search/src/nsMsgLocalSearch.cpp +++ b/mailnews/base/search/src/nsMsgLocalSearch.cpp @@ -20,6 +20,7 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Howard Chu * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -67,19 +68,11 @@ extern "C" //---------------------------------------------------------------------------- -nsMsgSearchBoolExpression * nsMsgSearchBoolExpression::AddSearchTermWithEncoding(nsMsgSearchBoolExpression * aOrigExpr, nsIMsgSearchTerm * aNewTerm, char * aEncodingStr) +nsMsgSearchBoolExpression * nsMsgSearchBoolExpression::AddSearchTerm(nsMsgSearchBoolExpression * aOrigExpr, nsIMsgSearchTerm * aNewTerm, char * aEncodingStr) // appropriately add the search term to the current expression and return a pointer to the // new expression. The encodingStr is the IMAP/NNTP encoding string for newTerm. { - return aOrigExpr->leftToRightAddTerm(aNewTerm, PR_FALSE, aEncodingStr); -} - -nsMsgSearchBoolExpression * nsMsgSearchBoolExpression::AddSearchTerm(nsMsgSearchBoolExpression * aOrigExpr, nsIMsgSearchTerm * aNewTerm, PRBool aEvalValue) -// appropriately add the search term to the current expression -// Returns: a pointer to the new expression which includes this new search term -{ - return aOrigExpr->leftToRightAddTerm(aNewTerm, aEvalValue, nsnull); // currently we build our expressions to - // evaluate left to right. + return aOrigExpr->leftToRightAddTerm(aNewTerm, aEncodingStr); } nsMsgSearchBoolExpression * nsMsgSearchBoolExpression::AddExpressionTree(nsMsgSearchBoolExpression * aOrigExpr, nsMsgSearchBoolExpression * aExpression, PRBool aBoolOp) @@ -100,19 +93,17 @@ nsMsgSearchBoolExpression::nsMsgSearchBoolExpression() { m_term = nsnull; m_boolOp = nsMsgSearchBooleanOp::BooleanAND; - m_evalValue = PR_FALSE; m_leftChild = nsnull; m_rightChild = nsnull; } -nsMsgSearchBoolExpression::nsMsgSearchBoolExpression (nsIMsgSearchTerm * newTerm, PRBool evalValue, char * encodingStr) +nsMsgSearchBoolExpression::nsMsgSearchBoolExpression (nsIMsgSearchTerm * newTerm, char * encodingStr) // we are creating an expression which contains a single search term (newTerm) // and the search term's IMAP or NNTP encoding value for online search expressions AND // a boolean evaluation value which is used for offline search expressions. { m_term = newTerm; m_encodingStr = encodingStr; - m_evalValue = evalValue; m_boolOp = nsMsgSearchBooleanOp::BooleanAND; // this expression does not contain sub expressions @@ -130,7 +121,6 @@ nsMsgSearchBoolExpression::nsMsgSearchBoolExpression (nsMsgSearchBoolExpression m_boolOp = boolOp; m_term = nsnull; - m_evalValue = PR_FALSE; } nsMsgSearchBoolExpression::~nsMsgSearchBoolExpression() @@ -143,18 +133,17 @@ nsMsgSearchBoolExpression::~nsMsgSearchBoolExpression() } nsMsgSearchBoolExpression * -nsMsgSearchBoolExpression::leftToRightAddTerm(nsIMsgSearchTerm * newTerm, PRBool evalValue, char * encodingStr) +nsMsgSearchBoolExpression::leftToRightAddTerm(nsIMsgSearchTerm * newTerm, char * encodingStr) { // we have a base case where this is the first term being added to the expression: if (!m_term && !m_leftChild && !m_rightChild) { m_term = newTerm; - m_evalValue = evalValue; m_encodingStr = encodingStr; return this; } - nsMsgSearchBoolExpression * tempExpr = new nsMsgSearchBoolExpression (newTerm,evalValue,encodingStr); + nsMsgSearchBoolExpression * tempExpr = new nsMsgSearchBoolExpression (newTerm,encodingStr); if (tempExpr) // make sure creation succeeded { PRBool booleanAnd; @@ -169,36 +158,42 @@ nsMsgSearchBoolExpression::leftToRightAddTerm(nsIMsgSearchTerm * newTerm, PRBool } -PRBool nsMsgSearchBoolExpression::OfflineEvaluate() -// returns PR_TRUE or PR_FALSE depending on what the current expression evaluates to. Since this is -// offline, when we created the expression we stored an evaluation value for each search term in -// the expression. These are the values we use to determine if the expression is PR_TRUE or PR_FALSE. +// returns PR_TRUE or PR_FALSE depending on what the current expression evaluates to. +PRBool nsMsgSearchBoolExpression::OfflineEvaluate(nsIMsgDBHdr *msgToMatch, const char *defaultCharset, + nsIMsgSearchScopeTerm *scope, nsIMsgDatabase *db, const char *headers, + PRUint32 headerSize, PRBool Filtering) { + PRBool result = PR_TRUE; // always default to false positives + PRBool isAnd; + if (m_term) // do we contain just a search term? - return m_evalValue; + { + nsMsgSearchOfflineMail::ProcessSearchTerm(msgToMatch, m_term, + defaultCharset, scope, db, headers, headerSize, Filtering, &result); + return result; + } // otherwise we must recursively determine the value of our sub expressions - PRBool result1 = PR_TRUE; // always default to false positives - PRBool result2 = PR_TRUE; + + isAnd = (m_boolOp == nsMsgSearchBooleanOp::BooleanAND); if (m_leftChild) { - result1 = m_leftChild->OfflineEvaluate(); - if (m_boolOp == nsMsgSearchBooleanOp::BooleanOR && result1 || - (m_boolOp == nsMsgSearchBooleanOp::BooleanAND && !result1)) - return result1; + result = m_leftChild->OfflineEvaluate(msgToMatch, defaultCharset, + scope, db, headers, headerSize, Filtering); + // If (TRUE and OR) or (FALSE and AND) return result + if (result ^ isAnd) + return result; } + // If we got this far, either there was no leftChild (which is impossible) + // or we got (FALSE and OR) or (TRUE and AND) from the first result. That + // means the outcome depends entirely on the rightChild. if (m_rightChild) - result2 = m_rightChild->OfflineEvaluate(); + result = m_rightChild->OfflineEvaluate(msgToMatch, defaultCharset, + scope, db, headers, headerSize, Filtering); - if (m_boolOp == nsMsgSearchBooleanOp::BooleanOR) - return (result1 || result2) ? PR_TRUE : PR_FALSE; - - if (m_boolOp == nsMsgSearchBooleanOp::BooleanAND && result1 && result2) - return PR_TRUE; - - return PR_FALSE; + return result; } // ### Maybe we can get rid of these because of our use of nsString??? @@ -350,9 +345,10 @@ nsMsgSearchOfflineMail::MatchTermsForFilter(nsIMsgDBHdr *msgToMatch, nsIMsgDatabase * db, const char * headers, PRUint32 headerSize, + nsMsgSearchBoolExpression ** aExpressionTree, PRBool *pResult) { - return MatchTerms(msgToMatch, termList, defaultCharset, scope, db, headers, headerSize, PR_TRUE, pResult); + return MatchTerms(msgToMatch, termList, defaultCharset, scope, db, headers, headerSize, PR_TRUE, aExpressionTree, pResult); } // static method which matches a header against a list of search terms. @@ -362,46 +358,28 @@ nsMsgSearchOfflineMail::MatchTermsForSearch(nsIMsgDBHdr *msgToMatch, const char *defaultCharset, nsIMsgSearchScopeTerm *scope, nsIMsgDatabase *db, + nsMsgSearchBoolExpression ** aExpressionTree, PRBool *pResult) { - return MatchTerms(msgToMatch, termList, defaultCharset, scope, db, nsnull, 0, PR_FALSE, pResult); + return MatchTerms(msgToMatch, termList, defaultCharset, scope, db, nsnull, 0, PR_FALSE, aExpressionTree, pResult); } -nsresult nsMsgSearchOfflineMail::ConstructExpressionTree(nsIMsgDBHdr *msgToMatch, - nsISupportsArray * termList, +nsresult nsMsgSearchOfflineMail::ConstructExpressionTree(nsISupportsArray * termList, + PRUint32 termCount, PRUint32 &aStartPosInList, - const char *defaultCharset, - nsIMsgSearchScopeTerm * scope, - nsIMsgDatabase * db, - const char * headers, - PRUint32 headerSize, - PRBool Filtering, - nsMsgSearchBoolExpression ** aExpressionTree, - PRBool *pResult) + nsMsgSearchBoolExpression ** aExpressionTree) { - PRBool result; + nsMsgSearchBoolExpression * finalExpression = *aExpressionTree; - NS_ENSURE_ARG_POINTER(pResult); + if (!finalExpression) + finalExpression = new nsMsgSearchBoolExpression(); - *pResult = PR_FALSE; - - // Don't even bother to look at expunged messages awaiting compression - PRUint32 msgFlags; - msgToMatch->GetFlags(&msgFlags); - if (msgFlags & MSG_FLAG_EXPUNGED) - result = PR_FALSE; - - PRUint32 count; - termList->Count(&count); - - nsMsgSearchBoolExpression * finalExpression = new nsMsgSearchBoolExpression(); - - while (aStartPosInList < count) + while (aStartPosInList < termCount) { nsCOMPtr pTerm; termList->QueryElementAt(aStartPosInList, NS_GET_IID(nsIMsgSearchTerm), (void **)getter_AddRefs(pTerm)); - NS_ASSERTION (msgToMatch, "couldn't get term to match"); + NS_ASSERTION (pTerm, "couldn't get term to match"); PRBool beginsGrouping; PRBool endsGrouping; @@ -412,12 +390,8 @@ nsresult nsMsgSearchOfflineMail::ConstructExpressionTree(nsIMsgDBHdr *msgToMatch { //temporarily turn off the grouping for our recursive call pTerm->SetBeginsGrouping(PR_FALSE); - // recursively process this inner expression nsMsgSearchBoolExpression * innerExpression = new nsMsgSearchBoolExpression(); - ConstructExpressionTree(msgToMatch, termList, aStartPosInList, defaultCharset, scope, db, headers, - headerSize, Filtering, &innerExpression, &result); - // the first search term in the grouping is the one that holds the operator for how this search term // should be joined with the expressions to it's left. PRBool booleanAnd; @@ -426,29 +400,25 @@ nsresult nsMsgSearchOfflineMail::ConstructExpressionTree(nsIMsgDBHdr *msgToMatch // now add this expression tree to our overall expression tree... finalExpression = nsMsgSearchBoolExpression::AddExpressionTree(finalExpression, innerExpression, booleanAnd); + // recursively process this inner expression + ConstructExpressionTree(termList, termCount, aStartPosInList, + &finalExpression->m_rightChild); + // undo our damage pTerm->SetBeginsGrouping(PR_TRUE); } else { - ProcessSearchTerm(msgToMatch, pTerm, defaultCharset, scope, db, headers, headerSize, Filtering, &result); - finalExpression = nsMsgSearchBoolExpression::AddSearchTerm(finalExpression, pTerm, result); // added the term and its value to the expression tree + finalExpression = nsMsgSearchBoolExpression::AddSearchTerm(finalExpression, pTerm, nsnull); // add the term to the expression tree if (endsGrouping) - { - // okay, this term marks the end of a grouping...kick out of this function. - *pResult = result; - *aExpressionTree = finalExpression; - return NS_OK; - - } + break; } aStartPosInList++; } // while we still have terms to process in this group - *pResult = PR_TRUE; *aExpressionTree = finalExpression; return NS_OK; @@ -619,17 +589,35 @@ nsresult nsMsgSearchOfflineMail::MatchTerms(nsIMsgDBHdr *msgToMatch, const char * headers, PRUint32 headerSize, PRBool Filtering, + nsMsgSearchBoolExpression ** aExpressionTree, PRBool *pResult) { - nsMsgSearchBoolExpression * expressionTree = nsnull; - PRUint32 initialPos = 0; - nsresult err = ConstructExpressionTree(msgToMatch, termList, initialPos, defaultCharset, scope, db, headers, headerSize, - Filtering, &expressionTree, pResult); + NS_ENSURE_ARG(aExpressionTree); + nsresult err; + + // Don't even bother to look at expunged messages awaiting compression + PRUint32 msgFlags; + msgToMatch->GetFlags(&msgFlags); + if (msgFlags & MSG_FLAG_EXPUNGED) + { + *pResult = PR_FALSE; + return NS_OK; + } + + if (!*aExpressionTree) + { + PRUint32 initialPos = 0; + PRUint32 count; + termList->Count(&count); + err = ConstructExpressionTree(termList, count, initialPos, aExpressionTree); + if (NS_FAILED(err)) + return err; + } // evaluate the expression tree and return the result - if (NS_SUCCEEDED(err) && expressionTree) - *pResult = expressionTree->OfflineEvaluate(); - delete expressionTree; + if (NS_SUCCEEDED(err) && *aExpressionTree) + *pResult = (*aExpressionTree)->OfflineEvaluate(msgToMatch, + defaultCharset, scope, db, headers, headerSize, Filtering); return err; } @@ -642,6 +630,7 @@ nsresult nsMsgSearchOfflineMail::Search (PRBool *aDone) NS_ENSURE_ARG(aDone); nsresult dbErr = NS_OK; nsCOMPtr msgDBHdr; + nsMsgSearchBoolExpression *expressionTree = nsnull; const PRUint32 kTimeSliceInMS = 200; @@ -678,7 +667,7 @@ nsresult nsMsgSearchOfflineMail::Search (PRBool *aDone) GetSearchCharsets(getter_Copies(nullCharset), getter_Copies(folderCharset)); NS_ConvertUCS2toUTF8 charset(folderCharset); // Is this message a hit? - err = MatchTermsForSearch (msgDBHdr, m_searchTerms, charset.get(), m_scope, m_db, &match); + err = MatchTermsForSearch (msgDBHdr, m_searchTerms, charset.get(), m_scope, m_db, &expressionTree, &match); // Add search hits to the results list if (NS_SUCCEEDED(err) && match) { @@ -696,6 +685,8 @@ nsresult nsMsgSearchOfflineMail::Search (PRBool *aDone) else *aDone = PR_TRUE; // we couldn't open up the DB. This is an unrecoverable error so mark the scope as done. + delete expressionTree; + // in the past an error here would cause an "infinite" search because the url would continue to run... // i.e. if we couldn't open the database, it returns an error code but the caller of this function says, oh, // we did not finish so continue...what we really want is to treat this current scope as done diff --git a/mailnews/base/search/src/nsMsgLocalSearch.h b/mailnews/base/search/src/nsMsgLocalSearch.h index 066be65dfbb4..fb81d10c1438 100644 --- a/mailnews/base/search/src/nsMsgLocalSearch.h +++ b/mailnews/base/search/src/nsMsgLocalSearch.h @@ -73,39 +73,19 @@ public: nsIMsgDatabase * db, const char * headers, PRUint32 headerSize, + nsMsgSearchBoolExpression ** aExpressionTree, PRBool *pResult); static nsresult MatchTermsForSearch(nsIMsgDBHdr * msgTomatch, nsISupportsArray * termList, const char *defaultCharset, nsIMsgSearchScopeTerm *scope, - nsIMsgDatabase *db, PRBool *pResult); + nsIMsgDatabase *db, + nsMsgSearchBoolExpression ** aExpressionTree, + PRBool *pResult); virtual nsresult OpenSummaryFile (); -protected: - static nsresult MatchTerms(nsIMsgDBHdr *msgToMatch, - nsISupportsArray *termList, - const char *defaultCharset, - nsIMsgSearchScopeTerm *scope, - nsIMsgDatabase * db, - const char * headers, - PRUint32 headerSize, - PRBool ForFilters, - PRBool *pResult); - - static nsresult ConstructExpressionTree(nsIMsgDBHdr *msgToMatch, - nsISupportsArray * termList, - PRUint32 &aStartPosInList, - const char *defaultCharset, - nsIMsgSearchScopeTerm * scope, - nsIMsgDatabase * db, - const char * headers, - PRUint32 headerSize, - PRBool Filtering, - nsMsgSearchBoolExpression ** aExpressionTree, - PRBool *pResult); - static nsresult ProcessSearchTerm(nsIMsgDBHdr *msgToMatch, nsIMsgSearchTerm * aTerm, const char *defaultCharset, @@ -115,6 +95,23 @@ protected: PRUint32 headerSize, PRBool Filtering, PRBool *pResult); +protected: + static nsresult MatchTerms(nsIMsgDBHdr *msgToMatch, + nsISupportsArray *termList, + const char *defaultCharset, + nsIMsgSearchScopeTerm *scope, + nsIMsgDatabase * db, + const char * headers, + PRUint32 headerSize, + PRBool ForFilters, + nsMsgSearchBoolExpression ** aExpressionTree, + PRBool *pResult); + + static nsresult ConstructExpressionTree(nsISupportsArray * termList, + PRUint32 termCount, + PRUint32 &aStartPosInList, + nsMsgSearchBoolExpression ** aExpressionTree); + nsCOMPtr m_db; nsCOMPtr m_listContext; void CleanUpScope(); diff --git a/mailnews/base/search/src/nsMsgSearchAdapter.cpp b/mailnews/base/search/src/nsMsgSearchAdapter.cpp index c78bb3e6783e..a1f544f5cd62 100644 --- a/mailnews/base/search/src/nsMsgSearchAdapter.cpp +++ b/mailnews/base/search/src/nsMsgSearchAdapter.cpp @@ -20,6 +20,7 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Howard Chu * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -786,7 +787,7 @@ nsresult nsMsgSearchAdapter::EncodeImap (char **ppOutEncoding, nsISupportsArray err = EncodeImapTerm (pTerm, reallyDredd, srcCharset, destCharset, &termEncoding); if (NS_SUCCEEDED(err) && nsnull != termEncoding) { - expression = nsMsgSearchBoolExpression::AddSearchTermWithEncoding(expression, pTerm, termEncoding); + expression = nsMsgSearchBoolExpression::AddSearchTerm(expression, pTerm, termEncoding); delete [] termEncoding; } } diff --git a/mailnews/base/search/src/nsMsgSearchSession.cpp b/mailnews/base/search/src/nsMsgSearchSession.cpp index ddf5a15aeade..dbe1ed8bb89b 100644 --- a/mailnews/base/search/src/nsMsgSearchSession.cpp +++ b/mailnews/base/search/src/nsMsgSearchSession.cpp @@ -20,6 +20,7 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Howard Chu * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -59,6 +60,7 @@ nsMsgSearchSession::nsMsgSearchSession() m_idxRunningScope = 0; m_urlQueueIndex = 0; m_handlingError = PR_FALSE; + m_expressionTree = nsnull; m_searchPaused = PR_FALSE; NS_NewISupportsArray(getter_AddRefs(m_termList)); } @@ -66,6 +68,7 @@ nsMsgSearchSession::nsMsgSearchSession() nsMsgSearchSession::~nsMsgSearchSession() { InterruptSearch(); + delete m_expressionTree; DestroyResultList (); DestroyScopeList (); DestroyTermList (); @@ -90,6 +93,8 @@ nsMsgSearchSession::AddSearchTerm(nsMsgSearchAttribValue attrib, if (nsnull == pTerm) return NS_ERROR_OUT_OF_MEMORY; m_termList->AppendElement (pTerm); + // force the expression tree to rebuild whenever we change the terms + delete m_expressionTree; return NS_OK; } @@ -98,6 +103,7 @@ nsMsgSearchSession::AppendTerm(nsIMsgSearchTerm *aTerm) { NS_ENSURE_ARG_POINTER(aTerm); NS_ENSURE_TRUE(m_termList, NS_ERROR_NOT_INITIALIZED); + delete m_expressionTree; return m_termList->AppendElement(aTerm); } @@ -641,6 +647,7 @@ void nsMsgSearchSession::DestroyScopeList() void nsMsgSearchSession::DestroyTermList () { + delete m_expressionTree; m_termList->Clear(); } @@ -746,7 +753,7 @@ nsMsgSearchSession::MatchHdr(nsIMsgDBHdr *aMsgHdr, nsIMsgDatabase *aDatabase, PR nsXPIDLString nullCharset, folderCharset; scope->m_adapter->GetSearchCharsets(getter_Copies(nullCharset), getter_Copies(folderCharset)); NS_ConvertUCS2toUTF8 charset(folderCharset.get()); - nsMsgSearchOfflineMail::MatchTermsForSearch(aMsgHdr, m_termList, charset.get(), scope, aDatabase, aResult); + nsMsgSearchOfflineMail::MatchTermsForSearch(aMsgHdr, m_termList, charset.get(), scope, aDatabase, &m_expressionTree, aResult); } } return NS_OK; diff --git a/mailnews/base/search/src/nsMsgSearchSession.h b/mailnews/base/search/src/nsMsgSearchSession.h index f1b6dc86df22..0c4291555cf7 100644 --- a/mailnews/base/search/src/nsMsgSearchSession.h +++ b/mailnews/base/search/src/nsMsgSearchSession.h @@ -50,6 +50,7 @@ #include "nsWeakReference.h" class nsMsgSearchAdapter; +class nsMsgSearchBoolExpression; class nsMsgSearchSession : public nsIMsgSearchSession, public nsIUrlListener, public nsSupportsWeakReference { @@ -103,6 +104,7 @@ protected: nsCStringArray m_urlQueue; nsCOMPtr m_backgroundTimer; PRBool m_searchPaused; + nsMsgSearchBoolExpression *m_expressionTree; }; #endif