loggingservices/eventlogger/LogServ/src/LOGFILTQ.CPP
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loggingservices/eventlogger/LogServ/src/LOGFILTQ.CPP	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,755 @@
+// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "LOGFILTQ.H"
+#include <logcli.h>
+#include <logcntdef.h>
+#include "logservpanic.h"
+#include "LogServDatabaseTransactionInterface.h"
+#include <logfilterandeventconstants.hrh>
+#include "LogServCacheStrings.h"
+#include "LogServCacheTypes.h"
+#include "LogServSqlStrings.h"
+
+#ifdef _DEBUG
+#  define __LOGFILTQ_INVARIANT()  Invariant()
+#else
+#  define __LOGFILTQ_INVARIANT()  void(0)
+#endif
+
+/**
+KFilterFields array contains all fields that can participate in a filter.
+The term "field" refers a constant, which value is power of two.
+Every "field" uniquely identifies one of the event properties.
+The field values are used in the implementation of the TLogFilterExprBuilder class for initializing the 
+iField data member, used to identify the currently processed event property value.  
+@internalComponent 
+*/
+const TUint16 KFilterFields[] = 
+	{
+	ELogContactField,
+	ELogDirectionField,
+	ELogDurationTypeField,
+	ELogEventTypeField,
+	ELogNumberField,
+	ELogRemotePartyField,
+	ELogStatusField,
+	ELogStartTimeField,
+	ELogEndTimeField,
+#ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
+	ELogSimIdField,		//The new ELogSimIdField must be before the flags: see 
+						//DoNextProcessFieldByFieldFilterByFilterL() implementation and the assert.
+#endif	
+	ELogFlagsField
+	};
+
+/**
+The size of the KFilterFields array.
+@internalComponent 
+*/
+const TInt KFilterFieldsSize = sizeof(KFilterFields) / sizeof(KFilterFields[0]);
+
+// Constants
+const TInt KLogBlockSize = 128;
+const TInt KLogPredicateListGranuality = 10;
+const TInt KLogMaxPredicateLength = 128;
+const TInt KLogNumberCharsToMatch = 9;
+
+/**
+Sets the iDatabase data member.
+The rest of the data member is left uninitialized. They will be initialized later by the BuildExprLC() call.
+@param aDatabase A reference to MLogServDatabaseTransactionInterface interface.  
+*/
+TLogFilterExprBuilder::TLogFilterExprBuilder(MLogServDatabaseTransactionInterface& aDatabase) :
+    iDatabase(aDatabase)
+	{
+	}
+
+/**
+Builds the WHERE expresssion of an SQL statement used later to filter events from the Event table.
+How the builder works? - BuildExprLC() gets as a parameter list of filters: CLogFilterList.
+Each filter is an object of CLogFilter type. The CLogFilter class contains the same set of properties as the CLogEvent
+class: phone number, SIM id, call type, etc. Some of the filter property values are set, defining the desired set
+of events that can pass the filter.
+
+For example, the filter list has two filters:
+ - Filter 1: number is "1011", SimId is 200;
+ - Filter 2: duration type is 2;
+ 
+BuildExprLC() takes the filter list and depending on passed TLogFilterConstructionType type:
+ - ELogFilterConstructFilterByFilterFieldByField
+   Organises two loops: the outer loop iterates over all field types, the inner loop iterates over the filters;
+ - ELogFilterConstructFieldByFieldFilterByFilter  
+   Organises two loops: the outer loop iterates over the filters, the inner loop iterates over all field types;
+
+On each inner loop iteration the current field value of the filter will be checked and if it is not null then a predicate 
+will be created of form "<column name> = <field value>" and added to the list of predicates.
+If the field value is null but it is allowed to include that field in the expression (the related bit of 
+CLogFilter::iNullFields is set. This is tested by using CLogFilter::NullFields()), then the predicate format will be
+"<column name> IS NULL".
+So using the example filters above, the predicates lists will be:
+ - "Number = '1011'", "SimId - 200";
+ - "DType = 2";
+
+At the end of each outer loop iteration the predicates will be "linked" using either "AND" if the field type is "flags"
+or "OR" for the rest of the fields types.
+So, after the first outer loop iteration, the constructed part of the WHERE expression will be:
+ "Number = '1011' OR SimId = 200". 
+After the second outer loop iteration the expression will be: "DType = 2".
+Also, depending on the TLogFilterConstructionType type these expressions will be "linked" either by "AND" or "OR":
+ "(Number = '1011' OR SimId = 200) AND (DType = 2)".
+ 
+On the first outer loop iteration, the predicates expression will be prefixed by the string refered by the aInitial
+parameter (that could be "WHERE " or " AND " or " OR ").
+
+When the processing of the filters finishes, the ready for use expression will be in the aExpr out parameter.
+
+@param aExpr Out parameter. If BuildExprLC() completes successfully, aExpr contrains the generated expression.
+             The caller is responsible for the destruction of aExpr. BuildExprLC() will create aExpr and put it on
+             the cleanup stack; 
+       aFilterList Filters list;
+       aInitial String that has to be added in front of the generated expresssion;
+       aType Defines the order of the processing of the filters and the fields;
+@leave KErrNoMemory Out of memory condition has occured.             
+*/
+void TLogFilterExprBuilder::BuildExprLC(RLogDynBuf& aExpr, const CLogFilterList& aFilterList, const TDesC& aInitial, 
+                                        TLogFilterConstructionType aType)
+	{
+	aExpr.CreateLC(KLogBlockSize);
+    iPredicateList = new (ELeave) CDesCArrayFlat(KLogPredicateListGranuality);
+    CleanupStack::PushL(iPredicateList);
+
+    iFilterList = &aFilterList;
+    iInitial = &aInitial;
+    iConstructionType = aType;
+    iFilterIndex = 0;
+    iField = KFilterFields[0];
+    iFlagIndex = 0;
+    
+    __LOGFILTQ_INVARIANT();
+    
+    switch(iConstructionType)
+        {
+        case ELogFilterConstructFilterByFilterFieldByField:
+            DoNextProcessFilterByFilterFieldByFieldL(aExpr);
+            break;
+        case ELogFilterConstructFieldByFieldFilterByFilter:
+            DoNextProcessFieldByFieldFilterByFilterL(aExpr);
+            break;
+        default:
+            __ASSERT_DEBUG(EFalse, Panic(ELogInvalidConstructionType));
+            break;
+        }
+
+#ifdef _DEBUG
+    iFilterList = NULL;
+    iInitial = NULL;
+    iFilterIndex = -1;
+    iField = 0;
+    iFlagIndex = -1;
+#endif    
+    CleanupStack::PopAndDestroy(iPredicateList);
+	}
+
+/**
+Processes the filters and the fields.
+Organises two loops:
+ - the outer loop is on the fields;
+ - the inner loop is on the filters; 
+
+@param aExpr Out parameter. The place where the expression is generated. 
+@leave KErrNoMemory Out of memory condition has occured.             
+
+@see BuildExprLC() 
+*/
+void TLogFilterExprBuilder::DoNextProcessFilterByFilterFieldByFieldL(RLogDynBuf& aExpr)
+	{
+    __LOGFILTQ_INVARIANT();
+	const TInt KCount = iFilterList->Count();
+	for(TInt i=0;i<KFilterFieldsSize;++i)
+	    {
+	    iField = KFilterFields[i];
+	    for(iFilterIndex=0; iFilterIndex<KCount; ++iFilterIndex)
+	        {
+	        iField != ELogFlagsField ? MakePredicatesL() : MakeFlagPredicatesL();  
+	        }
+        MakeConditionL(aExpr);
+        iPredicateList->Reset();
+	    }
+	}
+
+/**
+Processes the filters and the fields.
+Organises two loops:
+ - the outer loop is on the filters; 
+ - the inner loop is on the fields;
+ 
+@param aExpr Out parameter. The place where the expression is generated. 
+@leave KErrNoMemory Out of memory condition has occured.             
+
+@see BuildExprLC() 
+*/
+void TLogFilterExprBuilder::DoNextProcessFieldByFieldFilterByFilterL(RLogDynBuf& aExpr)
+	{
+    __LOGFILTQ_INVARIANT();
+    const TInt KCount = iFilterList->Count();
+    for(iFilterIndex=0; iFilterIndex<KCount; ++iFilterIndex)
+        {
+        //Process all filter fields except flags.
+    	for(TInt i=0;i<(KFilterFieldsSize-1);++i)
+            {
+    	    iField = KFilterFields[i];
+            MakePredicatesL();
+            }
+    	//Process the flag fields last
+	    iField = KFilterFields[KFilterFieldsSize - 1];
+        __ASSERT_DEBUG(iField == ELogFlagsField, User::Invariant());
+        MakeFlagPredicatesL();
+        MakeConditionL(aExpr);
+        iPredicateList->Reset();
+        }
+	}
+
+/**
+Called on each inner iteration from DoNextProcessFieldByFieldFilterByFilterL() and 
+DoNextProcessFilterByFilterFieldByFieldL().
+Generates a predicate in one of the following formats:
+ - "<column name> = <field value>"
+ - "<column name> IS NULL"
+The generated predicate will be added to the predicates list (iPredicateList data member).
+
+@leave KErrNoMemory Out of memory condition has occured.              
+
+@see DoNextProcessFilterByFilterFieldByFieldL()
+@see DoNextProcessFieldByFieldFilterByFilterL()
+*/
+void TLogFilterExprBuilder::MakePredicatesL()
+	{
+    __LOGFILTQ_INVARIANT();
+	
+	const CLogFilter* filter = iFilterList->At(iFilterIndex);
+	__ASSERT_DEBUG(filter, Panic(ELogNullFilterInList1));
+
+	// Check for null field in filter and if the field has already been used
+	TBuf<KLogMaxPredicateLength> predicate;
+	if (!IsFieldEmpty(*filter) && !IsDuplicateField(*filter))
+		{
+		MakePredicateL(predicate, *filter);
+		if (predicate.Length() > 0)
+			iPredicateList->AppendL(predicate);
+		}
+
+	// Add Null predicate if required and not already specified
+	if (filter->NullFields() & iField && !IsDuplicateNullField())
+		{
+		predicate.Zero();
+		MakeNullPredicate(predicate);
+		if (predicate.Length() > 0)
+			iPredicateList->AppendL(predicate);
+		}
+
+    __LOGFILTQ_INVARIANT();
+	}
+
+/**
+Called on each outer loop iteration.
+At this time, all generated predicates are in the predicates list (iPredicateList data member).
+The predicates will be "linked" into the expression using "AND" for the "flags" and "OR" for the rest of the fields.
+Depending on the TLogFilterConstructionType type (iConstructionType data member) either "AND" or "OR" will be used 
+to "link" pedicates from two different predicates lists.  
+
+@param aExpr Out parameter. The place where the expression is generated. 
+@leave KErrNoMemory Out of memory condition has occured.
+
+@see DoNextProcessFilterByFilterFieldByFieldL()
+@see DoNextProcessFieldByFieldFilterByFilterL()
+@see MakePredicatesL()
+*/
+void TLogFilterExprBuilder::MakeConditionL(RLogDynBuf& aExpr)
+	{
+    __ASSERT_DEBUG(iFilterList != NULL, User::Invariant());
+    __ASSERT_DEBUG(iInitial != NULL, User::Invariant());
+    __ASSERT_DEBUG(iConstructionType == ELogFilterConstructFilterByFilterFieldByField || iConstructionType == ELogFilterConstructFieldByFieldFilterByFilter, User::Invariant());
+    __ASSERT_DEBUG(iPredicateList != NULL, User::Invariant());
+	
+	// Are there any predicates to add?
+	TInt total = iPredicateList->MdcaCount();
+	if (total == 0)
+		return;
+
+	// Add separator between conditions
+	if(aExpr.Length() == 0)
+	    {
+	    aExpr.AppendL(*iInitial);
+	    }
+	else
+		{
+		switch(iConstructionType)
+			{
+		case ELogFilterConstructFilterByFilterFieldByField:
+			aExpr.AppendL(KLogAnd);
+			break;
+		case ELogFilterConstructFieldByFieldFilterByFilter:
+			aExpr.AppendL(KLogOr);
+			break;
+		default:
+            __ASSERT_DEBUG(EFalse, Panic(ELogInvalidConstructionType));
+		    break;
+			}
+		}
+
+	aExpr.AppendL(KLogOpenBracket);
+
+	// Add Predicates
+	TInt count = 0;
+	while(count < total)
+		{
+		// Add separator between predicates
+		if (count > 0)
+			{
+			if (iField != ELogFlagsField)
+				aExpr.AppendL(KLogOr);
+			else
+				aExpr.AppendL(KLogAnd);
+			}
+
+		aExpr.AppendL((*iPredicateList)[count]);
+		count++;
+		}
+
+	// Close the brackets
+	aExpr.AppendL(KLogCloseBracket);
+	}
+
+/**
+Called on each inner loop iteration.
+Processes the "flags" filter fields and generates predicates.
+
+@leave KErrNoMemory Out of memory condition has occured.
+
+@see DoNextProcessFilterByFilterFieldByFieldL()
+@see DoNextProcessFieldByFieldFilterByFilterL()
+*/
+void TLogFilterExprBuilder::MakeFlagPredicatesL()
+    {
+    __LOGFILTQ_INVARIANT();
+    
+    const CLogFilter* filter = iFilterList->At(iFilterIndex);
+    __ASSERT_DEBUG(filter, Panic(ELogNullFilterInList2));
+
+    // Return if no flags are set
+    if (filter->Flags() == KLogNullFlags)
+        return;
+
+    TBuf<KLogMaxPredicateLength> predicate;
+
+    // Go through each bit in turn
+    iFlagIndex = KLogFlagsCount;
+    while(iFlagIndex--)
+        {
+        // See if the current flag is set in filter and bit wasn't set in any previous filters
+        if (filter->Flags() & 0x1 << iFlagIndex && !IsDuplicateField(*filter))
+            {
+            // Generate predicate - if null field flag set we don't want the flag to be set
+            predicate.Format(KLogFlagPredicate, &KLogFlagString, iFlagIndex + 1, (filter->NullFields() & iField) ? 0 : 1);
+            iPredicateList->AppendL(predicate);
+            }
+        }
+    iFlagIndex = 0;
+    
+    __LOGFILTQ_INVARIANT();
+    }
+
+/**
+Depending on the currently processed field (iField data member) the function returns the column name that
+has to be used in the predicate being generated.
+
+@return A const reference to the column name.
+
+@see MakeNullPredicate()
+@see MakePredicateL()   
+*/
+const TDesC& TLogFilterExprBuilder::ColumnName() const
+	{
+    __LOGFILTQ_INVARIANT();
+	switch (iField)
+		{
+		case ELogContactField:
+			return KLogFieldEventContactString();
+		case ELogDirectionField:
+			return KLogFieldEventDirectionString();
+		case ELogDurationTypeField:
+			return KLogFieldEventDTypeString();
+		case ELogEventTypeField:
+			return KLogFieldEventTypeString();
+		case ELogNumberField:
+			return KLogFieldEventNumberString();
+		case ELogRemotePartyField:
+			return KLogFieldEventRemoteString();
+		case ELogStatusField:
+			return KLogFieldEventStatusString();
+		case ELogSubjectField:
+			return KLogFieldEventSubjectString();
+		case ELogLinkField:
+			return KLogFieldEventLinkString();
+		case ELogDataField:
+			return KLogFieldEventDataString();
+		case ELogStartTimeField:
+		case ELogEndTimeField:
+			return KLogFieldEventTimeString();
+#ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
+		case ELogSimIdField:
+			return KLogFieldEventSimId();
+#endif			
+		default:
+			__ASSERT_DEBUG(EFalse, Panic(ELogNoSuchState3));
+			break;
+		}
+	return KLogUnknownString();
+	}
+
+/**
+Generates a predicate of form "<column name> IS NULL" in the passed descriptor.
+
+@param aDes Out parameter. The place where the predicate will be generated.
+
+@see MakePredicatesL() 
+*/
+void TLogFilterExprBuilder::MakeNullPredicate(TDes& aDes)
+    {
+    __LOGFILTQ_INVARIANT();
+    aDes.Format(KLogNullPredicate, &ColumnName());
+    __LOGFILTQ_INVARIANT();
+    }
+
+/**
+Generates a predicate of form "<column name> = <field value>" in the passed descriptor.
+
+@param aDes Out parameter. The place where the predicate will be generated.
+@param aFilter The filter where the field values will be picked from.
+               The current field is identified by the value of the iField data member.
+
+@leave The leaving codes from TTime::FormatL().
+
+@see MakePredicatesL() 
+*/
+void TLogFilterExprBuilder::MakePredicateL(TDes& aDes, const CLogFilter& aFilter)
+	{
+    __LOGFILTQ_INVARIANT();
+	const TDesC& columnName = ColumnName();
+	switch (iField)
+		{
+		case ELogContactField:
+			aDes.Format(KLogNumberPredicate, &columnName, aFilter.Contact());
+			break;
+
+		case ELogDirectionField:
+			{
+			TLogStringId id = iDatabase.DTICacheStrings().FindId(aFilter.Direction());
+			aDes.Format(KLogNumberPredicate, &columnName, id);
+			}
+			break;
+
+		case ELogDurationTypeField:
+			aDes.Format(KLogNumberPredicate, &columnName, aFilter.DurationType());
+			break;
+
+		case ELogEventTypeField:
+			{
+			const TLogServCacheTypeEntry& entry = iDatabase.DTICacheTypes().FindByUid(aFilter.EventType());
+			aDes.Format(KLogNumberPredicate, &columnName, entry.iEventTypeId);
+			break;
+			}
+
+		// If the phone number in the filter is at least KLogNumberCharsToMatch long
+		// then it does a wild card search for numbers that match the last KLogNumberCharsToMatch chars
+		case ELogNumberField:
+			{
+			if (aFilter.Number().Length() < KLogNumberCharsToMatch)
+				aDes.Format(KLogStringPredicate, &columnName, &aFilter.Number());
+			else
+				{
+				TPtrC number(aFilter.Number().Right(KLogNumberCharsToMatch));
+				aDes.Format(KLogLikePredicate, &columnName, &number);
+				}
+			break;
+			}
+
+		case ELogRemotePartyField:
+			//We need to check RemoteParty string for any single quotes and 
+			//add a second single quote to properly handle strings such as 
+			//"Sam's Wife"	
+		    {
+			//If single quotes are found we need to modify the string
+			TInt quoteIndex =  aFilter.RemoteParty().Locate('\'');			
+			if( quoteIndex >= 0)
+				{	
+				//Allocate a buffer twice the length of the string to cater for 
+				//the worst case when every character is a single quote
+				TPtrC temp = aFilter.RemoteParty();
+				TBuf<KLogMaxRemotePartyLength * 2> buf;
+
+				//loop through and replace all single quotes
+				//with two quote characters
+				while(quoteIndex >= 0)
+					{	
+					_LIT(KQuoteStr, "''");
+					//Append the characters before the single quote followed
+					//by two quote characters
+					buf.Append(temp.Left(quoteIndex));	
+					buf.Append(KQuoteStr);
+
+					//Set the substring to the remaining characters after the
+					//single quote and look for the next single quote character
+					temp.Set(temp.Mid(quoteIndex + 1));
+					quoteIndex = temp.Locate('\'');
+					}		
+
+				//No quotes left so append the remaining data
+				buf.Append(temp);
+				aDes.Format(KLogStringPredicate, &columnName, &buf);
+				}
+			else
+				{
+				aDes.Format(KLogStringPredicate, &columnName, &aFilter.RemoteParty());
+				}
+		    }
+			break;
+
+		case ELogStatusField:
+			{
+			TLogStringId id = iDatabase.DTICacheStrings().FindId(aFilter.Status());
+			aDes.Format(KLogNumberPredicate, &columnName, id);
+			}
+			break;
+			
+		case ELogStartTimeField:
+		    {
+			TTime time = aFilter.StartTime();
+		    TBuf<KLogMaxDateLength> buf;
+			time.FormatL(buf, LogUtils::DateFormatForLocale());
+			aDes.Format(KLogDateAfterPredicate, &columnName, &buf);
+		    }
+			break;  
+
+		case ELogEndTimeField:
+		    {
+			TTime time = aFilter.EndTime();
+		    TBuf<KLogMaxDateLength> buf;
+			time.FormatL(buf, LogUtils::DateFormatForLocale());
+			aDes.Format(KLogDateBeforePredicate, &columnName, &buf);
+		    }
+			break;
+			
+#ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
+		case ELogSimIdField:
+			aDes.Format(KLogUNumberPredicate, &columnName, aFilter.SimId());
+			break;
+#endif	
+			
+		default:
+			__ASSERT_DEBUG(EFalse, Panic(ELogNoSuchState4));
+			break;
+		};
+    __LOGFILTQ_INVARIANT();
+	}
+
+/**
+Determines whether the current field identified by the value of the iField data member, is a duplicate, used/defined
+by the previously processed filters. For example, if there are two filters and both define the "number" field value, then
+only the "number" value from the first filter will be used.
+
+@param aFilter The current filter being processed;
+@return True the current field value has been already used in some of the previously processed filters, false otherwise.
+
+@see IsDuplicateNullField()
+@see MakePredicatesL() 
+*/
+TBool TLogFilterExprBuilder::IsDuplicateField(const CLogFilter& aFilter) const
+    {
+    __LOGFILTQ_INVARIANT();
+    TInt count = iFilterIndex;
+    while(count--)
+        {
+        const CLogFilter* testFilter = iFilterList->At(count);
+        __ASSERT_DEBUG(testFilter, Panic(ELogNullFilterInList3));
+        if (IsDuplicate(aFilter, *testFilter))
+            return ETrue;
+        }
+    return EFalse;
+    }
+
+/**
+Determines whether the current "null" field identified by the value of the iField data member, is a duplicate, used/defined
+by the previously processed filters.
+
+@param aFilter The current filter being processed;
+@return True the current "null" field value has been already used in some of the previously processed filters, false otherwise.
+
+@see IsDuplicateField()
+@see MakePredicatesL() 
+*/
+TBool TLogFilterExprBuilder::IsDuplicateNullField() const
+    {
+    __LOGFILTQ_INVARIANT();
+    TInt count = iFilterIndex;
+    while(count--)
+        {
+        const CLogFilter* testFilter = iFilterList->At(count);
+        __ASSERT_DEBUG(testFilter, Panic(ELogNullFilterInList4));
+        if (testFilter->NullFields() & iField)
+            return ETrue;
+        }
+    return EFalse;  
+    }
+
+/**
+Determines whether the current field value, identified by the value of the iField data member, is a null value.
+
+@param aFilter The current filter being processed;
+@return True The current field value is null, false otherwise.
+
+@see MakePredicatesL()  
+*/
+TBool TLogFilterExprBuilder::IsFieldEmpty(const CLogFilter& aFilter) const
+	{
+    __LOGFILTQ_INVARIANT();
+	switch (iField)
+		{
+		case ELogContactField:
+			return aFilter.Contact() == KLogNullContactId;
+
+		case ELogDirectionField:
+			return aFilter.Direction().Length() == 0;
+
+		case ELogDurationTypeField:
+			return aFilter.DurationType() == KLogNullDurationType;
+
+		case ELogEventTypeField:
+			return aFilter.EventType() == KNullUid;
+
+		case ELogNumberField:
+			return aFilter.Number().Length() == 0;
+
+		case ELogRemotePartyField:
+			return aFilter.RemoteParty().Length() == 0;
+
+		case ELogStatusField:
+			return aFilter.Status().Length() == 0;
+
+		case ELogStartTimeField:
+			return (aFilter.StartTime() == TTime(0));
+
+		case ELogEndTimeField:
+			return (aFilter.EndTime() == TTime(0));
+
+		// These fields are not part of the filter
+		case ELogSubjectField:
+		case ELogLinkField:
+		case ELogDataField:
+			return ETrue;
+
+#ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
+		case ELogSimIdField:
+			return (aFilter.SimId() == KLogNullSimId);
+#endif
+			
+		default:
+			__ASSERT_DEBUG(EFalse, Panic(ELogNoSuchState5));
+			break;
+		};
+	return ETrue;
+	}
+
+/**
+The function checks whether the field identified by the value of the iField data member has the same value in the
+passed two filter objects. 
+
+@param  aFilter1 Filter 1
+@param  aFilter1 Filter 2
+@return True The values of the current field are identical in both filters, false otherwise. 
+ 
+@see IsDuplicateField() 
+*/
+TBool TLogFilterExprBuilder::IsDuplicate(const CLogFilter& aFilter1, const CLogFilter& aFilter2) const
+	{
+	__LOGFILTQ_INVARIANT();
+	switch (iField)
+		{
+		case ELogContactField:
+			return aFilter1.Contact() == aFilter2.Contact();
+
+		case ELogDirectionField:
+			return aFilter1.Direction().CompareF(aFilter2.Direction()) == 0;
+
+		case ELogDurationTypeField:
+			return aFilter1.DurationType() == aFilter2.DurationType();
+
+		case ELogEventTypeField:
+			return aFilter1.EventType() == aFilter2.EventType();
+
+		// The number fields in filters are considered to be duplicates if the last KLogNumberCharsToMatch chars match
+		case ELogNumberField:
+			{
+			TPtrC number1(aFilter1.Number().Right(KLogNumberCharsToMatch));
+			TPtrC number2(aFilter2.Number().Right(KLogNumberCharsToMatch));
+			return number1.CompareF(number2) == 0;
+			}
+
+		case ELogRemotePartyField:
+			return aFilter1.RemoteParty().CompareF(aFilter2.RemoteParty()) == 0;
+
+		case ELogStatusField:
+			return aFilter1.Status().CompareF(aFilter2.Status()) == 0;
+
+		case ELogStartTimeField:
+			return aFilter1.StartTime() == aFilter2.StartTime();
+
+		case ELogEndTimeField:
+			return aFilter1.EndTime() == aFilter2.EndTime();
+
+		case ELogFlagsField:
+			return aFilter2.Flags() & iFlagIndex;
+
+#ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
+		case ELogSimIdField:
+			return aFilter1.SimId() == aFilter2.SimId();
+#endif			
+			
+		default:
+			__ASSERT_DEBUG(EFalse, Panic(ELogNoSuchState6));
+			break;
+		};
+	return EFalse;
+	}
+
+#ifdef _DEBUG
+void TLogFilterExprBuilder::Invariant() const
+    {
+    __ASSERT_DEBUG(KFilterFields[KFilterFieldsSize - 1] == ELogFlagsField, User::Invariant());
+    __ASSERT_DEBUG(iFilterList != NULL, User::Invariant());
+    __ASSERT_DEBUG(iInitial != NULL, User::Invariant());
+    __ASSERT_DEBUG(iConstructionType == ELogFilterConstructFilterByFilterFieldByField || iConstructionType == ELogFilterConstructFieldByFieldFilterByFilter, User::Invariant());
+    __ASSERT_DEBUG((TUint)iFilterIndex < iFilterList->Count(), User::Invariant());
+    TInt idx = KMaxTInt;
+    for(idx=0;idx<KFilterFieldsSize && iField!=KFilterFields[idx];++idx)
+    	{
+    	}
+    __ASSERT_DEBUG(idx < KFilterFieldsSize, User::Invariant());
+    __ASSERT_DEBUG((iField & (iField - 1)) == 0, User::Invariant());
+    __ASSERT_DEBUG((TUint)iFlagIndex < KLogFlagsCount, User::Invariant());
+    __ASSERT_DEBUG(iPredicateList != NULL, User::Invariant());
+    }
+#endif