Bug 295088: Filter/Search term evaluator is extremely sub-optimal; p=Howard Chu <hyc@symas.com>, r=bienvenu, sr=dmose

This commit is contained in:
mnyromyr%tprac.de 2005-10-20 19:37:58 +00:00
Родитель 10de8e659f
Коммит dbf07011fd
8 изменённых файлов: 141 добавлений и 140 удалений

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved. * the Initial Developer. All Rights Reserved.
* *
* Contributor(s): * Contributor(s):
* Howard Chu <hyc@symas.com>
* *
* Alternatively, the contents of this file may be used under the terms of * 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"), * 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 representing the search terms and their boolean operators as a binary
expression tree. Each node in the tree consists of either expression tree. Each node in the tree consists of either
(1) a boolean operator and two nsMsgSearchBoolExpressions or (1) a boolean operator and two nsMsgSearchBoolExpressions or
(2) if the node is a leaf node then it contains a search term. (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 With each search term that is part of the expression we may also keep
track of either an evaluation value (XP_BOOL) or a character string. a character string. The character
Evaluation values are used for offline searching. The character
string is used to store the IMAP/NNTP encoding of the search term. This string is used to store the IMAP/NNTP encoding of the search term. This
makes evaluating the expression (for offline) or generating a search makes generating a search encoding (for online) easier.
encoding (for online) easier.
For IMAP/NNTP: nsMsgSearchBoolExpression has/assumes knowledge about how For IMAP/NNTP: nsMsgSearchBoolExpression has/assumes knowledge about how
AND and OR search terms are combined according to IMAP4 and NNTP protocol. AND and OR search terms are combined according to IMAP4 and NNTP protocol.
@ -76,9 +75,7 @@ public:
// create a leaf node expression // create a leaf node expression
nsMsgSearchBoolExpression(nsIMsgSearchTerm * aNewTerm, nsMsgSearchBoolExpression(nsIMsgSearchTerm * aNewTerm,
PRBool aEvaluationValue = PR_TRUE,
char * aEncodingString = NULL); char * aEncodingString = NULL);
nsMsgSearchBoolExpression(nsIMsgSearchTerm * aNewTerm, char * aEncodingString);
// create a non-leaf node expression containing 2 expressions // create a non-leaf node expression containing 2 expressions
// and a boolean operator // and a boolean operator
@ -90,18 +87,19 @@ public:
~nsMsgSearchBoolExpression(); // recursively destroys all sub ~nsMsgSearchBoolExpression(); // recursively destroys all sub
// expressions as well // expressions as well
// accesors // accessors
// Offline // Offline
static nsMsgSearchBoolExpression * AddSearchTerm (nsMsgSearchBoolExpression * aOrigExpr, nsIMsgSearchTerm * aNewTerm, PRBool aEvaluationValue); static nsMsgSearchBoolExpression * AddSearchTerm (nsMsgSearchBoolExpression * aOrigExpr, nsIMsgSearchTerm * aNewTerm, char * aEncodingStr); // IMAP/NNTP
static nsMsgSearchBoolExpression * AddSearchTermWithEncoding (nsMsgSearchBoolExpression * aOrigExpr, nsIMsgSearchTerm * aNewTerm, char * aEncodingStr); // IMAP/NNTP
static nsMsgSearchBoolExpression * AddExpressionTree(nsMsgSearchBoolExpression * aOrigExpr, nsMsgSearchBoolExpression * aExpression, PRBool aBoolOp); static nsMsgSearchBoolExpression * AddExpressionTree(nsMsgSearchBoolExpression * aOrigExpr, nsMsgSearchBoolExpression * aExpression, PRBool aBoolOp);
// parses the expression tree and all // parses the expression tree and all
// expressions underneath this node using // expressions underneath this node to
// each EvaluationValue at each leaf to
// determine if the end result is PR_TRUE or PR_FALSE. // 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 // assuming the expression is for online
// searches, determine the length of the // searches, determine the length of the
@ -112,15 +110,6 @@ public:
// memory in buffer with // memory in buffer with
// the IMAP/NNTP encoding for the expression // the IMAP/NNTP encoding for the expression
void GenerateEncodeStr(nsCString * buffer); 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 // if we are not a leaf node, then we have two other expressions
// and a boolean operator // and a boolean operator
@ -128,6 +117,13 @@ protected:
nsMsgSearchBoolExpression * m_rightChild; nsMsgSearchBoolExpression * m_rightChild;
nsMsgSearchBooleanOperator m_boolOp; 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 // internal methods
@ -138,7 +134,6 @@ protected:
// that by calling leftToRightAddTerm. If future forms of evaluation // that by calling leftToRightAddTerm. If future forms of evaluation
// need to be supported, add new methods here for proper tree construction. // need to be supported, add new methods here for proper tree construction.
nsMsgSearchBoolExpression * leftToRightAddTerm(nsIMsgSearchTerm * newTerm, nsMsgSearchBoolExpression * leftToRightAddTerm(nsIMsgSearchTerm * newTerm,
PRBool EvaluationValue,
char * encodingStr); char * encodingStr);
}; };

Просмотреть файл

@ -22,6 +22,7 @@
* Contributor(s): * Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com> * Pierre Phaneuf <pp@ludusdesign.com>
* Seth Spitzer <sspitzer@netscape.com> * Seth Spitzer <sspitzer@netscape.com>
* Howard Chu <hyc@symas.com>
* *
* Alternatively, the contents of this file may be used under the terms of * 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"), * either of the GNU General Public License Version 2 or later (the "GPL"),
@ -170,7 +171,8 @@ nsMsgRuleAction::GetStrValue(char **aStrValue)
nsMsgFilter::nsMsgFilter(): nsMsgFilter::nsMsgFilter():
m_temporary(PR_FALSE), m_temporary(PR_FALSE),
m_unparseable(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_termList));
NS_NewISupportsArray(getter_AddRefs(m_actionList)); NS_NewISupportsArray(getter_AddRefs(m_actionList));
@ -180,6 +182,7 @@ nsMsgFilter::nsMsgFilter():
nsMsgFilter::~nsMsgFilter() nsMsgFilter::~nsMsgFilter()
{ {
delete m_expressionTree;
} }
NS_IMPL_ISUPPORTS1(nsMsgFilter, nsIMsgFilter) NS_IMPL_ISUPPORTS1(nsMsgFilter, nsIMsgFilter)
@ -243,7 +246,8 @@ NS_IMETHODIMP nsMsgFilter::AddTerm(
NS_IMETHODIMP nsMsgFilter::AppendTerm(nsIMsgSearchTerm * aTerm) NS_IMETHODIMP nsMsgFilter::AppendTerm(nsIMsgSearchTerm * aTerm)
{ {
NS_ENSURE_TRUE(aTerm, NS_ERROR_NULL_POINTER); 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)); 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) NS_IMETHODIMP nsMsgFilter::SetSearchTerms(nsISupportsArray *aSearchList)
{ {
delete m_expressionTree;
m_termList = aSearchList; m_termList = aSearchList;
return NS_OK; return NS_OK;
} }
@ -511,7 +516,7 @@ NS_IMETHODIMP nsMsgFilter::MatchHdr(nsIMsgDBHdr *msgHdr, nsIMsgFolder *folder, n
nsXPIDLCString folderCharset; nsXPIDLCString folderCharset;
folder->GetCharset(getter_Copies(folderCharset)); folder->GetCharset(getter_Copies(folderCharset));
nsresult rv = nsMsgSearchOfflineMail::MatchTermsForFilter(msgHdr, m_termList, 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; delete scope;
return rv; return rv;
} }

Просмотреть файл

@ -21,6 +21,7 @@
* *
* Contributor(s): * Contributor(s):
* David Bienvenu (bienvenu@nventure.com) * David Bienvenu (bienvenu@nventure.com)
* Howard Chu <hyc@symas.com>
* *
* Alternatively, the contents of this file may be used under the terms of * 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"), * either of the GNU General Public License Version 2 or later (the "GPL"),
@ -44,6 +45,7 @@
#include "nsIMsgFilter.h" #include "nsIMsgFilter.h"
#include "nsMsgSearchArray.h" #include "nsMsgSearchArray.h"
#include "nsIMsgSearchScopeTerm.h" #include "nsIMsgSearchScopeTerm.h"
#include "nsMsgSearchBoolExpression.h"
class nsMsgRuleAction : public nsIMsgRuleAction class nsMsgRuleAction : public nsIMsgRuleAction
{ {
@ -120,6 +122,7 @@ protected:
nsCOMPtr<nsIMsgSearchScopeTerm> m_scope; /* default for mail rules is inbox, but news rules could nsCOMPtr<nsIMsgSearchScopeTerm> m_scope; /* default for mail rules is inbox, but news rules could
have a newsgroup - LDAP would be invalid */ have a newsgroup - LDAP would be invalid */
nsCOMPtr<nsISupportsArray> m_actionList; nsCOMPtr<nsISupportsArray> m_actionList;
nsMsgSearchBoolExpression *m_expressionTree;
}; };
#endif #endif

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved. * the Initial Developer. All Rights Reserved.
* *
* Contributor(s): * Contributor(s):
* Howard Chu <hyc@symas.com>
* *
* Alternatively, the contents of this file may be used under the terms of * 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"), * 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 // 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. // new expression. The encodingStr is the IMAP/NNTP encoding string for newTerm.
{ {
return aOrigExpr->leftToRightAddTerm(aNewTerm, PR_FALSE, aEncodingStr); return aOrigExpr->leftToRightAddTerm(aNewTerm, 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.
} }
nsMsgSearchBoolExpression * nsMsgSearchBoolExpression::AddExpressionTree(nsMsgSearchBoolExpression * aOrigExpr, nsMsgSearchBoolExpression * aExpression, PRBool aBoolOp) nsMsgSearchBoolExpression * nsMsgSearchBoolExpression::AddExpressionTree(nsMsgSearchBoolExpression * aOrigExpr, nsMsgSearchBoolExpression * aExpression, PRBool aBoolOp)
@ -100,19 +93,17 @@ nsMsgSearchBoolExpression::nsMsgSearchBoolExpression()
{ {
m_term = nsnull; m_term = nsnull;
m_boolOp = nsMsgSearchBooleanOp::BooleanAND; m_boolOp = nsMsgSearchBooleanOp::BooleanAND;
m_evalValue = PR_FALSE;
m_leftChild = nsnull; m_leftChild = nsnull;
m_rightChild = 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) // 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 // 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. // a boolean evaluation value which is used for offline search expressions.
{ {
m_term = newTerm; m_term = newTerm;
m_encodingStr = encodingStr; m_encodingStr = encodingStr;
m_evalValue = evalValue;
m_boolOp = nsMsgSearchBooleanOp::BooleanAND; m_boolOp = nsMsgSearchBooleanOp::BooleanAND;
// this expression does not contain sub expressions // this expression does not contain sub expressions
@ -130,7 +121,6 @@ nsMsgSearchBoolExpression::nsMsgSearchBoolExpression (nsMsgSearchBoolExpression
m_boolOp = boolOp; m_boolOp = boolOp;
m_term = nsnull; m_term = nsnull;
m_evalValue = PR_FALSE;
} }
nsMsgSearchBoolExpression::~nsMsgSearchBoolExpression() nsMsgSearchBoolExpression::~nsMsgSearchBoolExpression()
@ -143,18 +133,17 @@ nsMsgSearchBoolExpression::~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: // we have a base case where this is the first term being added to the expression:
if (!m_term && !m_leftChild && !m_rightChild) if (!m_term && !m_leftChild && !m_rightChild)
{ {
m_term = newTerm; m_term = newTerm;
m_evalValue = evalValue;
m_encodingStr = encodingStr; m_encodingStr = encodingStr;
return this; return this;
} }
nsMsgSearchBoolExpression * tempExpr = new nsMsgSearchBoolExpression (newTerm,evalValue,encodingStr); nsMsgSearchBoolExpression * tempExpr = new nsMsgSearchBoolExpression (newTerm,encodingStr);
if (tempExpr) // make sure creation succeeded if (tempExpr) // make sure creation succeeded
{ {
PRBool booleanAnd; 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.
// returns PR_TRUE or PR_FALSE depending on what the current expression evaluates to. Since this is PRBool nsMsgSearchBoolExpression::OfflineEvaluate(nsIMsgDBHdr *msgToMatch, const char *defaultCharset,
// offline, when we created the expression we stored an evaluation value for each search term in nsIMsgSearchScopeTerm *scope, nsIMsgDatabase *db, const char *headers,
// the expression. These are the values we use to determine if the expression is PR_TRUE or PR_FALSE. 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? 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 // 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) if (m_leftChild)
{ {
result1 = m_leftChild->OfflineEvaluate(); result = m_leftChild->OfflineEvaluate(msgToMatch, defaultCharset,
if (m_boolOp == nsMsgSearchBooleanOp::BooleanOR && result1 || scope, db, headers, headerSize, Filtering);
(m_boolOp == nsMsgSearchBooleanOp::BooleanAND && !result1)) // If (TRUE and OR) or (FALSE and AND) return result
return result1; 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) if (m_rightChild)
result2 = m_rightChild->OfflineEvaluate(); result = m_rightChild->OfflineEvaluate(msgToMatch, defaultCharset,
scope, db, headers, headerSize, Filtering);
if (m_boolOp == nsMsgSearchBooleanOp::BooleanOR) return result;
return (result1 || result2) ? PR_TRUE : PR_FALSE;
if (m_boolOp == nsMsgSearchBooleanOp::BooleanAND && result1 && result2)
return PR_TRUE;
return PR_FALSE;
} }
// ### Maybe we can get rid of these because of our use of nsString??? // ### Maybe we can get rid of these because of our use of nsString???
@ -350,9 +345,10 @@ nsMsgSearchOfflineMail::MatchTermsForFilter(nsIMsgDBHdr *msgToMatch,
nsIMsgDatabase * db, nsIMsgDatabase * db,
const char * headers, const char * headers,
PRUint32 headerSize, PRUint32 headerSize,
nsMsgSearchBoolExpression ** aExpressionTree,
PRBool *pResult) 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. // static method which matches a header against a list of search terms.
@ -362,46 +358,28 @@ nsMsgSearchOfflineMail::MatchTermsForSearch(nsIMsgDBHdr *msgToMatch,
const char *defaultCharset, const char *defaultCharset,
nsIMsgSearchScopeTerm *scope, nsIMsgSearchScopeTerm *scope,
nsIMsgDatabase *db, nsIMsgDatabase *db,
nsMsgSearchBoolExpression ** aExpressionTree,
PRBool *pResult) 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, nsresult nsMsgSearchOfflineMail::ConstructExpressionTree(nsISupportsArray * termList,
nsISupportsArray * termList, PRUint32 termCount,
PRUint32 &aStartPosInList, PRUint32 &aStartPosInList,
const char *defaultCharset, nsMsgSearchBoolExpression ** aExpressionTree)
nsIMsgSearchScopeTerm * scope,
nsIMsgDatabase * db,
const char * headers,
PRUint32 headerSize,
PRBool Filtering,
nsMsgSearchBoolExpression ** aExpressionTree,
PRBool *pResult)
{ {
PRBool result; nsMsgSearchBoolExpression * finalExpression = *aExpressionTree;
NS_ENSURE_ARG_POINTER(pResult); if (!finalExpression)
finalExpression = new nsMsgSearchBoolExpression();
*pResult = PR_FALSE; while (aStartPosInList < termCount)
// 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)
{ {
nsCOMPtr<nsIMsgSearchTerm> pTerm; nsCOMPtr<nsIMsgSearchTerm> pTerm;
termList->QueryElementAt(aStartPosInList, NS_GET_IID(nsIMsgSearchTerm), (void **)getter_AddRefs(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 beginsGrouping;
PRBool endsGrouping; PRBool endsGrouping;
@ -412,12 +390,8 @@ nsresult nsMsgSearchOfflineMail::ConstructExpressionTree(nsIMsgDBHdr *msgToMatch
{ {
//temporarily turn off the grouping for our recursive call //temporarily turn off the grouping for our recursive call
pTerm->SetBeginsGrouping(PR_FALSE); pTerm->SetBeginsGrouping(PR_FALSE);
// recursively process this inner expression
nsMsgSearchBoolExpression * innerExpression = new nsMsgSearchBoolExpression(); 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 // 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. // should be joined with the expressions to it's left.
PRBool booleanAnd; PRBool booleanAnd;
@ -426,29 +400,25 @@ nsresult nsMsgSearchOfflineMail::ConstructExpressionTree(nsIMsgDBHdr *msgToMatch
// now add this expression tree to our overall expression tree... // now add this expression tree to our overall expression tree...
finalExpression = nsMsgSearchBoolExpression::AddExpressionTree(finalExpression, innerExpression, booleanAnd); finalExpression = nsMsgSearchBoolExpression::AddExpressionTree(finalExpression, innerExpression, booleanAnd);
// recursively process this inner expression
ConstructExpressionTree(termList, termCount, aStartPosInList,
&finalExpression->m_rightChild);
// undo our damage // undo our damage
pTerm->SetBeginsGrouping(PR_TRUE); pTerm->SetBeginsGrouping(PR_TRUE);
} }
else else
{ {
ProcessSearchTerm(msgToMatch, pTerm, defaultCharset, scope, db, headers, headerSize, Filtering, &result); finalExpression = nsMsgSearchBoolExpression::AddSearchTerm(finalExpression, pTerm, nsnull); // add the term to the expression tree
finalExpression = nsMsgSearchBoolExpression::AddSearchTerm(finalExpression, pTerm, result); // added the term and its value to the expression tree
if (endsGrouping) if (endsGrouping)
{ break;
// okay, this term marks the end of a grouping...kick out of this function.
*pResult = result;
*aExpressionTree = finalExpression;
return NS_OK;
}
} }
aStartPosInList++; aStartPosInList++;
} // while we still have terms to process in this group } // while we still have terms to process in this group
*pResult = PR_TRUE;
*aExpressionTree = finalExpression; *aExpressionTree = finalExpression;
return NS_OK; return NS_OK;
@ -619,17 +589,35 @@ nsresult nsMsgSearchOfflineMail::MatchTerms(nsIMsgDBHdr *msgToMatch,
const char * headers, const char * headers,
PRUint32 headerSize, PRUint32 headerSize,
PRBool Filtering, PRBool Filtering,
nsMsgSearchBoolExpression ** aExpressionTree,
PRBool *pResult) PRBool *pResult)
{ {
nsMsgSearchBoolExpression * expressionTree = nsnull; NS_ENSURE_ARG(aExpressionTree);
PRUint32 initialPos = 0; nsresult err;
nsresult err = ConstructExpressionTree(msgToMatch, termList, initialPos, defaultCharset, scope, db, headers, headerSize,
Filtering, &expressionTree, pResult); // 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 // evaluate the expression tree and return the result
if (NS_SUCCEEDED(err) && expressionTree) if (NS_SUCCEEDED(err) && *aExpressionTree)
*pResult = expressionTree->OfflineEvaluate(); *pResult = (*aExpressionTree)->OfflineEvaluate(msgToMatch,
delete expressionTree; defaultCharset, scope, db, headers, headerSize, Filtering);
return err; return err;
} }
@ -642,6 +630,7 @@ nsresult nsMsgSearchOfflineMail::Search (PRBool *aDone)
NS_ENSURE_ARG(aDone); NS_ENSURE_ARG(aDone);
nsresult dbErr = NS_OK; nsresult dbErr = NS_OK;
nsCOMPtr<nsIMsgDBHdr> msgDBHdr; nsCOMPtr<nsIMsgDBHdr> msgDBHdr;
nsMsgSearchBoolExpression *expressionTree = nsnull;
const PRUint32 kTimeSliceInMS = 200; const PRUint32 kTimeSliceInMS = 200;
@ -678,7 +667,7 @@ nsresult nsMsgSearchOfflineMail::Search (PRBool *aDone)
GetSearchCharsets(getter_Copies(nullCharset), getter_Copies(folderCharset)); GetSearchCharsets(getter_Copies(nullCharset), getter_Copies(folderCharset));
NS_ConvertUCS2toUTF8 charset(folderCharset); NS_ConvertUCS2toUTF8 charset(folderCharset);
// Is this message a hit? // 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 // Add search hits to the results list
if (NS_SUCCEEDED(err) && match) if (NS_SUCCEEDED(err) && match)
{ {
@ -696,6 +685,8 @@ nsresult nsMsgSearchOfflineMail::Search (PRBool *aDone)
else else
*aDone = PR_TRUE; // we couldn't open up the DB. This is an unrecoverable error so mark the scope as done. *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... // 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, // 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 // we did not finish so continue...what we really want is to treat this current scope as done

Просмотреть файл

@ -73,39 +73,19 @@ public:
nsIMsgDatabase * db, nsIMsgDatabase * db,
const char * headers, const char * headers,
PRUint32 headerSize, PRUint32 headerSize,
nsMsgSearchBoolExpression ** aExpressionTree,
PRBool *pResult); PRBool *pResult);
static nsresult MatchTermsForSearch(nsIMsgDBHdr * msgTomatch, static nsresult MatchTermsForSearch(nsIMsgDBHdr * msgTomatch,
nsISupportsArray * termList, nsISupportsArray * termList,
const char *defaultCharset, const char *defaultCharset,
nsIMsgSearchScopeTerm *scope, nsIMsgSearchScopeTerm *scope,
nsIMsgDatabase *db, PRBool *pResult); nsIMsgDatabase *db,
nsMsgSearchBoolExpression ** aExpressionTree,
PRBool *pResult);
virtual nsresult OpenSummaryFile (); 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, static nsresult ProcessSearchTerm(nsIMsgDBHdr *msgToMatch,
nsIMsgSearchTerm * aTerm, nsIMsgSearchTerm * aTerm,
const char *defaultCharset, const char *defaultCharset,
@ -115,6 +95,23 @@ protected:
PRUint32 headerSize, PRUint32 headerSize,
PRBool Filtering, PRBool Filtering,
PRBool *pResult); 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 <nsIMsgDatabase> m_db; nsCOMPtr <nsIMsgDatabase> m_db;
nsCOMPtr<nsISimpleEnumerator> m_listContext; nsCOMPtr<nsISimpleEnumerator> m_listContext;
void CleanUpScope(); void CleanUpScope();

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved. * the Initial Developer. All Rights Reserved.
* *
* Contributor(s): * Contributor(s):
* Howard Chu <hyc@symas.com>
* *
* Alternatively, the contents of this file may be used under the terms of * 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"), * 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); err = EncodeImapTerm (pTerm, reallyDredd, srcCharset, destCharset, &termEncoding);
if (NS_SUCCEEDED(err) && nsnull != termEncoding) if (NS_SUCCEEDED(err) && nsnull != termEncoding)
{ {
expression = nsMsgSearchBoolExpression::AddSearchTermWithEncoding(expression, pTerm, termEncoding); expression = nsMsgSearchBoolExpression::AddSearchTerm(expression, pTerm, termEncoding);
delete [] termEncoding; delete [] termEncoding;
} }
} }

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved. * the Initial Developer. All Rights Reserved.
* *
* Contributor(s): * Contributor(s):
* Howard Chu <hyc@symas.com>
* *
* Alternatively, the contents of this file may be used under the terms of * 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"), * either of the GNU General Public License Version 2 or later (the "GPL"),
@ -59,6 +60,7 @@ nsMsgSearchSession::nsMsgSearchSession()
m_idxRunningScope = 0; m_idxRunningScope = 0;
m_urlQueueIndex = 0; m_urlQueueIndex = 0;
m_handlingError = PR_FALSE; m_handlingError = PR_FALSE;
m_expressionTree = nsnull;
m_searchPaused = PR_FALSE; m_searchPaused = PR_FALSE;
NS_NewISupportsArray(getter_AddRefs(m_termList)); NS_NewISupportsArray(getter_AddRefs(m_termList));
} }
@ -66,6 +68,7 @@ nsMsgSearchSession::nsMsgSearchSession()
nsMsgSearchSession::~nsMsgSearchSession() nsMsgSearchSession::~nsMsgSearchSession()
{ {
InterruptSearch(); InterruptSearch();
delete m_expressionTree;
DestroyResultList (); DestroyResultList ();
DestroyScopeList (); DestroyScopeList ();
DestroyTermList (); DestroyTermList ();
@ -90,6 +93,8 @@ nsMsgSearchSession::AddSearchTerm(nsMsgSearchAttribValue attrib,
if (nsnull == pTerm) if (nsnull == pTerm)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
m_termList->AppendElement (pTerm); m_termList->AppendElement (pTerm);
// force the expression tree to rebuild whenever we change the terms
delete m_expressionTree;
return NS_OK; return NS_OK;
} }
@ -98,6 +103,7 @@ nsMsgSearchSession::AppendTerm(nsIMsgSearchTerm *aTerm)
{ {
NS_ENSURE_ARG_POINTER(aTerm); NS_ENSURE_ARG_POINTER(aTerm);
NS_ENSURE_TRUE(m_termList, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(m_termList, NS_ERROR_NOT_INITIALIZED);
delete m_expressionTree;
return m_termList->AppendElement(aTerm); return m_termList->AppendElement(aTerm);
} }
@ -641,6 +647,7 @@ void nsMsgSearchSession::DestroyScopeList()
void nsMsgSearchSession::DestroyTermList () void nsMsgSearchSession::DestroyTermList ()
{ {
delete m_expressionTree;
m_termList->Clear(); m_termList->Clear();
} }
@ -746,7 +753,7 @@ nsMsgSearchSession::MatchHdr(nsIMsgDBHdr *aMsgHdr, nsIMsgDatabase *aDatabase, PR
nsXPIDLString nullCharset, folderCharset; nsXPIDLString nullCharset, folderCharset;
scope->m_adapter->GetSearchCharsets(getter_Copies(nullCharset), getter_Copies(folderCharset)); scope->m_adapter->GetSearchCharsets(getter_Copies(nullCharset), getter_Copies(folderCharset));
NS_ConvertUCS2toUTF8 charset(folderCharset.get()); 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; return NS_OK;

Просмотреть файл

@ -50,6 +50,7 @@
#include "nsWeakReference.h" #include "nsWeakReference.h"
class nsMsgSearchAdapter; class nsMsgSearchAdapter;
class nsMsgSearchBoolExpression;
class nsMsgSearchSession : public nsIMsgSearchSession, public nsIUrlListener, public nsSupportsWeakReference class nsMsgSearchSession : public nsIMsgSearchSession, public nsIUrlListener, public nsSupportsWeakReference
{ {
@ -103,6 +104,7 @@ protected:
nsCStringArray m_urlQueue; nsCStringArray m_urlQueue;
nsCOMPtr <nsITimer> m_backgroundTimer; nsCOMPtr <nsITimer> m_backgroundTimer;
PRBool m_searchPaused; PRBool m_searchPaused;
nsMsgSearchBoolExpression *m_expressionTree;
}; };
#endif #endif