os/persistentdata/loggingservices/eventlogger/LogServ/src/LOGFILTQ.CPP
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include "LOGFILTQ.H"
    17 #include <logcli.h>
    18 #include <logcntdef.h>
    19 #include "logservpanic.h"
    20 #include "LogServDatabaseTransactionInterface.h"
    21 #include <logfilterandeventconstants.hrh>
    22 #include "LogServCacheStrings.h"
    23 #include "LogServCacheTypes.h"
    24 #include "LogServSqlStrings.h"
    25 
    26 #ifdef _DEBUG
    27 #  define __LOGFILTQ_INVARIANT()  Invariant()
    28 #else
    29 #  define __LOGFILTQ_INVARIANT()  void(0)
    30 #endif
    31 
    32 /**
    33 KFilterFields array contains all fields that can participate in a filter.
    34 The term "field" refers a constant, which value is power of two.
    35 Every "field" uniquely identifies one of the event properties.
    36 The field values are used in the implementation of the TLogFilterExprBuilder class for initializing the 
    37 iField data member, used to identify the currently processed event property value.  
    38 @internalComponent 
    39 */
    40 const TUint16 KFilterFields[] = 
    41 	{
    42 	ELogContactField,
    43 	ELogDirectionField,
    44 	ELogDurationTypeField,
    45 	ELogEventTypeField,
    46 	ELogNumberField,
    47 	ELogRemotePartyField,
    48 	ELogStatusField,
    49 	ELogStartTimeField,
    50 	ELogEndTimeField,
    51 #ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
    52 	ELogSimIdField,		//The new ELogSimIdField must be before the flags: see 
    53 						//DoNextProcessFieldByFieldFilterByFilterL() implementation and the assert.
    54 #endif	
    55 	ELogFlagsField
    56 	};
    57 
    58 /**
    59 The size of the KFilterFields array.
    60 @internalComponent 
    61 */
    62 const TInt KFilterFieldsSize = sizeof(KFilterFields) / sizeof(KFilterFields[0]);
    63 
    64 // Constants
    65 const TInt KLogBlockSize = 128;
    66 const TInt KLogPredicateListGranuality = 10;
    67 const TInt KLogMaxPredicateLength = 128;
    68 const TInt KLogNumberCharsToMatch = 9;
    69 
    70 /**
    71 Sets the iDatabase data member.
    72 The rest of the data member is left uninitialized. They will be initialized later by the BuildExprLC() call.
    73 @param aDatabase A reference to MLogServDatabaseTransactionInterface interface.  
    74 */
    75 TLogFilterExprBuilder::TLogFilterExprBuilder(MLogServDatabaseTransactionInterface& aDatabase) :
    76     iDatabase(aDatabase)
    77 	{
    78 	}
    79 
    80 /**
    81 Builds the WHERE expresssion of an SQL statement used later to filter events from the Event table.
    82 How the builder works? - BuildExprLC() gets as a parameter list of filters: CLogFilterList.
    83 Each filter is an object of CLogFilter type. The CLogFilter class contains the same set of properties as the CLogEvent
    84 class: phone number, SIM id, call type, etc. Some of the filter property values are set, defining the desired set
    85 of events that can pass the filter.
    86 
    87 For example, the filter list has two filters:
    88  - Filter 1: number is "1011", SimId is 200;
    89  - Filter 2: duration type is 2;
    90  
    91 BuildExprLC() takes the filter list and depending on passed TLogFilterConstructionType type:
    92  - ELogFilterConstructFilterByFilterFieldByField
    93    Organises two loops: the outer loop iterates over all field types, the inner loop iterates over the filters;
    94  - ELogFilterConstructFieldByFieldFilterByFilter  
    95    Organises two loops: the outer loop iterates over the filters, the inner loop iterates over all field types;
    96 
    97 On each inner loop iteration the current field value of the filter will be checked and if it is not null then a predicate 
    98 will be created of form "<column name> = <field value>" and added to the list of predicates.
    99 If the field value is null but it is allowed to include that field in the expression (the related bit of 
   100 CLogFilter::iNullFields is set. This is tested by using CLogFilter::NullFields()), then the predicate format will be
   101 "<column name> IS NULL".
   102 So using the example filters above, the predicates lists will be:
   103  - "Number = '1011'", "SimId - 200";
   104  - "DType = 2";
   105 
   106 At the end of each outer loop iteration the predicates will be "linked" using either "AND" if the field type is "flags"
   107 or "OR" for the rest of the fields types.
   108 So, after the first outer loop iteration, the constructed part of the WHERE expression will be:
   109  "Number = '1011' OR SimId = 200". 
   110 After the second outer loop iteration the expression will be: "DType = 2".
   111 Also, depending on the TLogFilterConstructionType type these expressions will be "linked" either by "AND" or "OR":
   112  "(Number = '1011' OR SimId = 200) AND (DType = 2)".
   113  
   114 On the first outer loop iteration, the predicates expression will be prefixed by the string refered by the aInitial
   115 parameter (that could be "WHERE " or " AND " or " OR ").
   116 
   117 When the processing of the filters finishes, the ready for use expression will be in the aExpr out parameter.
   118 
   119 @param aExpr Out parameter. If BuildExprLC() completes successfully, aExpr contrains the generated expression.
   120              The caller is responsible for the destruction of aExpr. BuildExprLC() will create aExpr and put it on
   121              the cleanup stack; 
   122        aFilterList Filters list;
   123        aInitial String that has to be added in front of the generated expresssion;
   124        aType Defines the order of the processing of the filters and the fields;
   125 @leave KErrNoMemory Out of memory condition has occured.             
   126 */
   127 void TLogFilterExprBuilder::BuildExprLC(RLogDynBuf& aExpr, const CLogFilterList& aFilterList, const TDesC& aInitial, 
   128                                         TLogFilterConstructionType aType)
   129 	{
   130 	aExpr.CreateLC(KLogBlockSize);
   131     iPredicateList = new (ELeave) CDesCArrayFlat(KLogPredicateListGranuality);
   132     CleanupStack::PushL(iPredicateList);
   133 
   134     iFilterList = &aFilterList;
   135     iInitial = &aInitial;
   136     iConstructionType = aType;
   137     iFilterIndex = 0;
   138     iField = KFilterFields[0];
   139     iFlagIndex = 0;
   140     
   141     __LOGFILTQ_INVARIANT();
   142     
   143     switch(iConstructionType)
   144         {
   145         case ELogFilterConstructFilterByFilterFieldByField:
   146             DoNextProcessFilterByFilterFieldByFieldL(aExpr);
   147             break;
   148         case ELogFilterConstructFieldByFieldFilterByFilter:
   149             DoNextProcessFieldByFieldFilterByFilterL(aExpr);
   150             break;
   151         default:
   152             __ASSERT_DEBUG(EFalse, Panic(ELogInvalidConstructionType));
   153             break;
   154         }
   155 
   156 #ifdef _DEBUG
   157     iFilterList = NULL;
   158     iInitial = NULL;
   159     iFilterIndex = -1;
   160     iField = 0;
   161     iFlagIndex = -1;
   162 #endif    
   163     CleanupStack::PopAndDestroy(iPredicateList);
   164 	}
   165 
   166 /**
   167 Processes the filters and the fields.
   168 Organises two loops:
   169  - the outer loop is on the fields;
   170  - the inner loop is on the filters; 
   171 
   172 @param aExpr Out parameter. The place where the expression is generated. 
   173 @leave KErrNoMemory Out of memory condition has occured.             
   174 
   175 @see BuildExprLC() 
   176 */
   177 void TLogFilterExprBuilder::DoNextProcessFilterByFilterFieldByFieldL(RLogDynBuf& aExpr)
   178 	{
   179     __LOGFILTQ_INVARIANT();
   180 	const TInt KCount = iFilterList->Count();
   181 	for(TInt i=0;i<KFilterFieldsSize;++i)
   182 	    {
   183 	    iField = KFilterFields[i];
   184 	    for(iFilterIndex=0; iFilterIndex<KCount; ++iFilterIndex)
   185 	        {
   186 	        iField != ELogFlagsField ? MakePredicatesL() : MakeFlagPredicatesL();  
   187 	        }
   188         MakeConditionL(aExpr);
   189         iPredicateList->Reset();
   190 	    }
   191 	}
   192 
   193 /**
   194 Processes the filters and the fields.
   195 Organises two loops:
   196  - the outer loop is on the filters; 
   197  - the inner loop is on the fields;
   198  
   199 @param aExpr Out parameter. The place where the expression is generated. 
   200 @leave KErrNoMemory Out of memory condition has occured.             
   201 
   202 @see BuildExprLC() 
   203 */
   204 void TLogFilterExprBuilder::DoNextProcessFieldByFieldFilterByFilterL(RLogDynBuf& aExpr)
   205 	{
   206     __LOGFILTQ_INVARIANT();
   207     const TInt KCount = iFilterList->Count();
   208     for(iFilterIndex=0; iFilterIndex<KCount; ++iFilterIndex)
   209         {
   210         //Process all filter fields except flags.
   211     	for(TInt i=0;i<(KFilterFieldsSize-1);++i)
   212             {
   213     	    iField = KFilterFields[i];
   214             MakePredicatesL();
   215             }
   216     	//Process the flag fields last
   217 	    iField = KFilterFields[KFilterFieldsSize - 1];
   218         __ASSERT_DEBUG(iField == ELogFlagsField, User::Invariant());
   219         MakeFlagPredicatesL();
   220         MakeConditionL(aExpr);
   221         iPredicateList->Reset();
   222         }
   223 	}
   224 
   225 /**
   226 Called on each inner iteration from DoNextProcessFieldByFieldFilterByFilterL() and 
   227 DoNextProcessFilterByFilterFieldByFieldL().
   228 Generates a predicate in one of the following formats:
   229  - "<column name> = <field value>"
   230  - "<column name> IS NULL"
   231 The generated predicate will be added to the predicates list (iPredicateList data member).
   232 
   233 @leave KErrNoMemory Out of memory condition has occured.              
   234 
   235 @see DoNextProcessFilterByFilterFieldByFieldL()
   236 @see DoNextProcessFieldByFieldFilterByFilterL()
   237 */
   238 void TLogFilterExprBuilder::MakePredicatesL()
   239 	{
   240     __LOGFILTQ_INVARIANT();
   241 	
   242 	const CLogFilter* filter = iFilterList->At(iFilterIndex);
   243 	__ASSERT_DEBUG(filter, Panic(ELogNullFilterInList1));
   244 
   245 	// Check for null field in filter and if the field has already been used
   246 	TBuf<KLogMaxPredicateLength> predicate;
   247 	if (!IsFieldEmpty(*filter) && !IsDuplicateField(*filter))
   248 		{
   249 		MakePredicateL(predicate, *filter);
   250 		if (predicate.Length() > 0)
   251 			iPredicateList->AppendL(predicate);
   252 		}
   253 
   254 	// Add Null predicate if required and not already specified
   255 	if (filter->NullFields() & iField && !IsDuplicateNullField())
   256 		{
   257 		predicate.Zero();
   258 		MakeNullPredicate(predicate);
   259 		if (predicate.Length() > 0)
   260 			iPredicateList->AppendL(predicate);
   261 		}
   262 
   263     __LOGFILTQ_INVARIANT();
   264 	}
   265 
   266 /**
   267 Called on each outer loop iteration.
   268 At this time, all generated predicates are in the predicates list (iPredicateList data member).
   269 The predicates will be "linked" into the expression using "AND" for the "flags" and "OR" for the rest of the fields.
   270 Depending on the TLogFilterConstructionType type (iConstructionType data member) either "AND" or "OR" will be used 
   271 to "link" pedicates from two different predicates lists.  
   272 
   273 @param aExpr Out parameter. The place where the expression is generated. 
   274 @leave KErrNoMemory Out of memory condition has occured.
   275 
   276 @see DoNextProcessFilterByFilterFieldByFieldL()
   277 @see DoNextProcessFieldByFieldFilterByFilterL()
   278 @see MakePredicatesL()
   279 */
   280 void TLogFilterExprBuilder::MakeConditionL(RLogDynBuf& aExpr)
   281 	{
   282     __ASSERT_DEBUG(iFilterList != NULL, User::Invariant());
   283     __ASSERT_DEBUG(iInitial != NULL, User::Invariant());
   284     __ASSERT_DEBUG(iConstructionType == ELogFilterConstructFilterByFilterFieldByField || iConstructionType == ELogFilterConstructFieldByFieldFilterByFilter, User::Invariant());
   285     __ASSERT_DEBUG(iPredicateList != NULL, User::Invariant());
   286 	
   287 	// Are there any predicates to add?
   288 	TInt total = iPredicateList->MdcaCount();
   289 	if (total == 0)
   290 		return;
   291 
   292 	// Add separator between conditions
   293 	if(aExpr.Length() == 0)
   294 	    {
   295 	    aExpr.AppendL(*iInitial);
   296 	    }
   297 	else
   298 		{
   299 		switch(iConstructionType)
   300 			{
   301 		case ELogFilterConstructFilterByFilterFieldByField:
   302 			aExpr.AppendL(KLogAnd);
   303 			break;
   304 		case ELogFilterConstructFieldByFieldFilterByFilter:
   305 			aExpr.AppendL(KLogOr);
   306 			break;
   307 		default:
   308             __ASSERT_DEBUG(EFalse, Panic(ELogInvalidConstructionType));
   309 		    break;
   310 			}
   311 		}
   312 
   313 	aExpr.AppendL(KLogOpenBracket);
   314 
   315 	// Add Predicates
   316 	TInt count = 0;
   317 	while(count < total)
   318 		{
   319 		// Add separator between predicates
   320 		if (count > 0)
   321 			{
   322 			if (iField != ELogFlagsField)
   323 				aExpr.AppendL(KLogOr);
   324 			else
   325 				aExpr.AppendL(KLogAnd);
   326 			}
   327 
   328 		aExpr.AppendL((*iPredicateList)[count]);
   329 		count++;
   330 		}
   331 
   332 	// Close the brackets
   333 	aExpr.AppendL(KLogCloseBracket);
   334 	}
   335 
   336 /**
   337 Called on each inner loop iteration.
   338 Processes the "flags" filter fields and generates predicates.
   339 
   340 @leave KErrNoMemory Out of memory condition has occured.
   341 
   342 @see DoNextProcessFilterByFilterFieldByFieldL()
   343 @see DoNextProcessFieldByFieldFilterByFilterL()
   344 */
   345 void TLogFilterExprBuilder::MakeFlagPredicatesL()
   346     {
   347     __LOGFILTQ_INVARIANT();
   348     
   349     const CLogFilter* filter = iFilterList->At(iFilterIndex);
   350     __ASSERT_DEBUG(filter, Panic(ELogNullFilterInList2));
   351 
   352     // Return if no flags are set
   353     if (filter->Flags() == KLogNullFlags)
   354         return;
   355 
   356     TBuf<KLogMaxPredicateLength> predicate;
   357 
   358     // Go through each bit in turn
   359     iFlagIndex = KLogFlagsCount;
   360     while(iFlagIndex--)
   361         {
   362         // See if the current flag is set in filter and bit wasn't set in any previous filters
   363         if (filter->Flags() & 0x1 << iFlagIndex && !IsDuplicateField(*filter))
   364             {
   365             // Generate predicate - if null field flag set we don't want the flag to be set
   366             predicate.Format(KLogFlagPredicate, &KLogFlagString, iFlagIndex + 1, (filter->NullFields() & iField) ? 0 : 1);
   367             iPredicateList->AppendL(predicate);
   368             }
   369         }
   370     iFlagIndex = 0;
   371     
   372     __LOGFILTQ_INVARIANT();
   373     }
   374 
   375 /**
   376 Depending on the currently processed field (iField data member) the function returns the column name that
   377 has to be used in the predicate being generated.
   378 
   379 @return A const reference to the column name.
   380 
   381 @see MakeNullPredicate()
   382 @see MakePredicateL()   
   383 */
   384 const TDesC& TLogFilterExprBuilder::ColumnName() const
   385 	{
   386     __LOGFILTQ_INVARIANT();
   387 	switch (iField)
   388 		{
   389 		case ELogContactField:
   390 			return KLogFieldEventContactString();
   391 		case ELogDirectionField:
   392 			return KLogFieldEventDirectionString();
   393 		case ELogDurationTypeField:
   394 			return KLogFieldEventDTypeString();
   395 		case ELogEventTypeField:
   396 			return KLogFieldEventTypeString();
   397 		case ELogNumberField:
   398 			return KLogFieldEventNumberString();
   399 		case ELogRemotePartyField:
   400 			return KLogFieldEventRemoteString();
   401 		case ELogStatusField:
   402 			return KLogFieldEventStatusString();
   403 		case ELogSubjectField:
   404 			return KLogFieldEventSubjectString();
   405 		case ELogLinkField:
   406 			return KLogFieldEventLinkString();
   407 		case ELogDataField:
   408 			return KLogFieldEventDataString();
   409 		case ELogStartTimeField:
   410 		case ELogEndTimeField:
   411 			return KLogFieldEventTimeString();
   412 #ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
   413 		case ELogSimIdField:
   414 			return KLogFieldEventSimId();
   415 #endif			
   416 		default:
   417 			__ASSERT_DEBUG(EFalse, Panic(ELogNoSuchState3));
   418 			break;
   419 		}
   420 	return KLogUnknownString();
   421 	}
   422 
   423 /**
   424 Generates a predicate of form "<column name> IS NULL" in the passed descriptor.
   425 
   426 @param aDes Out parameter. The place where the predicate will be generated.
   427 
   428 @see MakePredicatesL() 
   429 */
   430 void TLogFilterExprBuilder::MakeNullPredicate(TDes& aDes)
   431     {
   432     __LOGFILTQ_INVARIANT();
   433     aDes.Format(KLogNullPredicate, &ColumnName());
   434     __LOGFILTQ_INVARIANT();
   435     }
   436 
   437 /**
   438 Generates a predicate of form "<column name> = <field value>" in the passed descriptor.
   439 
   440 @param aDes Out parameter. The place where the predicate will be generated.
   441 @param aFilter The filter where the field values will be picked from.
   442                The current field is identified by the value of the iField data member.
   443 
   444 @leave The leaving codes from TTime::FormatL().
   445 
   446 @see MakePredicatesL() 
   447 */
   448 void TLogFilterExprBuilder::MakePredicateL(TDes& aDes, const CLogFilter& aFilter)
   449 	{
   450     __LOGFILTQ_INVARIANT();
   451 	const TDesC& columnName = ColumnName();
   452 	switch (iField)
   453 		{
   454 		case ELogContactField:
   455 			aDes.Format(KLogNumberPredicate, &columnName, aFilter.Contact());
   456 			break;
   457 
   458 		case ELogDirectionField:
   459 			{
   460 			TLogStringId id = iDatabase.DTICacheStrings().FindId(aFilter.Direction());
   461 			aDes.Format(KLogNumberPredicate, &columnName, id);
   462 			}
   463 			break;
   464 
   465 		case ELogDurationTypeField:
   466 			aDes.Format(KLogNumberPredicate, &columnName, aFilter.DurationType());
   467 			break;
   468 
   469 		case ELogEventTypeField:
   470 			{
   471 			const TLogServCacheTypeEntry& entry = iDatabase.DTICacheTypes().FindByUid(aFilter.EventType());
   472 			aDes.Format(KLogNumberPredicate, &columnName, entry.iEventTypeId);
   473 			break;
   474 			}
   475 
   476 		// If the phone number in the filter is at least KLogNumberCharsToMatch long
   477 		// then it does a wild card search for numbers that match the last KLogNumberCharsToMatch chars
   478 		case ELogNumberField:
   479 			{
   480 			if (aFilter.Number().Length() < KLogNumberCharsToMatch)
   481 				aDes.Format(KLogStringPredicate, &columnName, &aFilter.Number());
   482 			else
   483 				{
   484 				TPtrC number(aFilter.Number().Right(KLogNumberCharsToMatch));
   485 				aDes.Format(KLogLikePredicate, &columnName, &number);
   486 				}
   487 			break;
   488 			}
   489 
   490 		case ELogRemotePartyField:
   491 			//We need to check RemoteParty string for any single quotes and 
   492 			//add a second single quote to properly handle strings such as 
   493 			//"Sam's Wife"	
   494 		    {
   495 			//If single quotes are found we need to modify the string
   496 			TInt quoteIndex =  aFilter.RemoteParty().Locate('\'');			
   497 			if( quoteIndex >= 0)
   498 				{	
   499 				//Allocate a buffer twice the length of the string to cater for 
   500 				//the worst case when every character is a single quote
   501 				TPtrC temp = aFilter.RemoteParty();
   502 				TBuf<KLogMaxRemotePartyLength * 2> buf;
   503 
   504 				//loop through and replace all single quotes
   505 				//with two quote characters
   506 				while(quoteIndex >= 0)
   507 					{	
   508 					_LIT(KQuoteStr, "''");
   509 					//Append the characters before the single quote followed
   510 					//by two quote characters
   511 					buf.Append(temp.Left(quoteIndex));	
   512 					buf.Append(KQuoteStr);
   513 
   514 					//Set the substring to the remaining characters after the
   515 					//single quote and look for the next single quote character
   516 					temp.Set(temp.Mid(quoteIndex + 1));
   517 					quoteIndex = temp.Locate('\'');
   518 					}		
   519 
   520 				//No quotes left so append the remaining data
   521 				buf.Append(temp);
   522 				aDes.Format(KLogStringPredicate, &columnName, &buf);
   523 				}
   524 			else
   525 				{
   526 				aDes.Format(KLogStringPredicate, &columnName, &aFilter.RemoteParty());
   527 				}
   528 		    }
   529 			break;
   530 
   531 		case ELogStatusField:
   532 			{
   533 			TLogStringId id = iDatabase.DTICacheStrings().FindId(aFilter.Status());
   534 			aDes.Format(KLogNumberPredicate, &columnName, id);
   535 			}
   536 			break;
   537 			
   538 		case ELogStartTimeField:
   539 		    {
   540 			TTime time = aFilter.StartTime();
   541 		    TBuf<KLogMaxDateLength> buf;
   542 			time.FormatL(buf, LogUtils::DateFormatForLocale());
   543 			aDes.Format(KLogDateAfterPredicate, &columnName, &buf);
   544 		    }
   545 			break;  
   546 
   547 		case ELogEndTimeField:
   548 		    {
   549 			TTime time = aFilter.EndTime();
   550 		    TBuf<KLogMaxDateLength> buf;
   551 			time.FormatL(buf, LogUtils::DateFormatForLocale());
   552 			aDes.Format(KLogDateBeforePredicate, &columnName, &buf);
   553 		    }
   554 			break;
   555 			
   556 #ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
   557 		case ELogSimIdField:
   558 			aDes.Format(KLogUNumberPredicate, &columnName, aFilter.SimId());
   559 			break;
   560 #endif	
   561 			
   562 		default:
   563 			__ASSERT_DEBUG(EFalse, Panic(ELogNoSuchState4));
   564 			break;
   565 		};
   566     __LOGFILTQ_INVARIANT();
   567 	}
   568 
   569 /**
   570 Determines whether the current field identified by the value of the iField data member, is a duplicate, used/defined
   571 by the previously processed filters. For example, if there are two filters and both define the "number" field value, then
   572 only the "number" value from the first filter will be used.
   573 
   574 @param aFilter The current filter being processed;
   575 @return True the current field value has been already used in some of the previously processed filters, false otherwise.
   576 
   577 @see IsDuplicateNullField()
   578 @see MakePredicatesL() 
   579 */
   580 TBool TLogFilterExprBuilder::IsDuplicateField(const CLogFilter& aFilter) const
   581     {
   582     __LOGFILTQ_INVARIANT();
   583     TInt count = iFilterIndex;
   584     while(count--)
   585         {
   586         const CLogFilter* testFilter = iFilterList->At(count);
   587         __ASSERT_DEBUG(testFilter, Panic(ELogNullFilterInList3));
   588         if (IsDuplicate(aFilter, *testFilter))
   589             return ETrue;
   590         }
   591     return EFalse;
   592     }
   593 
   594 /**
   595 Determines whether the current "null" field identified by the value of the iField data member, is a duplicate, used/defined
   596 by the previously processed filters.
   597 
   598 @param aFilter The current filter being processed;
   599 @return True the current "null" field value has been already used in some of the previously processed filters, false otherwise.
   600 
   601 @see IsDuplicateField()
   602 @see MakePredicatesL() 
   603 */
   604 TBool TLogFilterExprBuilder::IsDuplicateNullField() const
   605     {
   606     __LOGFILTQ_INVARIANT();
   607     TInt count = iFilterIndex;
   608     while(count--)
   609         {
   610         const CLogFilter* testFilter = iFilterList->At(count);
   611         __ASSERT_DEBUG(testFilter, Panic(ELogNullFilterInList4));
   612         if (testFilter->NullFields() & iField)
   613             return ETrue;
   614         }
   615     return EFalse;  
   616     }
   617 
   618 /**
   619 Determines whether the current field value, identified by the value of the iField data member, is a null value.
   620 
   621 @param aFilter The current filter being processed;
   622 @return True The current field value is null, false otherwise.
   623 
   624 @see MakePredicatesL()  
   625 */
   626 TBool TLogFilterExprBuilder::IsFieldEmpty(const CLogFilter& aFilter) const
   627 	{
   628     __LOGFILTQ_INVARIANT();
   629 	switch (iField)
   630 		{
   631 		case ELogContactField:
   632 			return aFilter.Contact() == KLogNullContactId;
   633 
   634 		case ELogDirectionField:
   635 			return aFilter.Direction().Length() == 0;
   636 
   637 		case ELogDurationTypeField:
   638 			return aFilter.DurationType() == KLogNullDurationType;
   639 
   640 		case ELogEventTypeField:
   641 			return aFilter.EventType() == KNullUid;
   642 
   643 		case ELogNumberField:
   644 			return aFilter.Number().Length() == 0;
   645 
   646 		case ELogRemotePartyField:
   647 			return aFilter.RemoteParty().Length() == 0;
   648 
   649 		case ELogStatusField:
   650 			return aFilter.Status().Length() == 0;
   651 
   652 		case ELogStartTimeField:
   653 			return (aFilter.StartTime() == TTime(0));
   654 
   655 		case ELogEndTimeField:
   656 			return (aFilter.EndTime() == TTime(0));
   657 
   658 		// These fields are not part of the filter
   659 		case ELogSubjectField:
   660 		case ELogLinkField:
   661 		case ELogDataField:
   662 			return ETrue;
   663 
   664 #ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
   665 		case ELogSimIdField:
   666 			return (aFilter.SimId() == KLogNullSimId);
   667 #endif
   668 			
   669 		default:
   670 			__ASSERT_DEBUG(EFalse, Panic(ELogNoSuchState5));
   671 			break;
   672 		};
   673 	return ETrue;
   674 	}
   675 
   676 /**
   677 The function checks whether the field identified by the value of the iField data member has the same value in the
   678 passed two filter objects. 
   679 
   680 @param  aFilter1 Filter 1
   681 @param  aFilter1 Filter 2
   682 @return True The values of the current field are identical in both filters, false otherwise. 
   683  
   684 @see IsDuplicateField() 
   685 */
   686 TBool TLogFilterExprBuilder::IsDuplicate(const CLogFilter& aFilter1, const CLogFilter& aFilter2) const
   687 	{
   688 	__LOGFILTQ_INVARIANT();
   689 	switch (iField)
   690 		{
   691 		case ELogContactField:
   692 			return aFilter1.Contact() == aFilter2.Contact();
   693 
   694 		case ELogDirectionField:
   695 			return aFilter1.Direction().CompareF(aFilter2.Direction()) == 0;
   696 
   697 		case ELogDurationTypeField:
   698 			return aFilter1.DurationType() == aFilter2.DurationType();
   699 
   700 		case ELogEventTypeField:
   701 			return aFilter1.EventType() == aFilter2.EventType();
   702 
   703 		// The number fields in filters are considered to be duplicates if the last KLogNumberCharsToMatch chars match
   704 		case ELogNumberField:
   705 			{
   706 			TPtrC number1(aFilter1.Number().Right(KLogNumberCharsToMatch));
   707 			TPtrC number2(aFilter2.Number().Right(KLogNumberCharsToMatch));
   708 			return number1.CompareF(number2) == 0;
   709 			}
   710 
   711 		case ELogRemotePartyField:
   712 			return aFilter1.RemoteParty().CompareF(aFilter2.RemoteParty()) == 0;
   713 
   714 		case ELogStatusField:
   715 			return aFilter1.Status().CompareF(aFilter2.Status()) == 0;
   716 
   717 		case ELogStartTimeField:
   718 			return aFilter1.StartTime() == aFilter2.StartTime();
   719 
   720 		case ELogEndTimeField:
   721 			return aFilter1.EndTime() == aFilter2.EndTime();
   722 
   723 		case ELogFlagsField:
   724 			return aFilter2.Flags() & iFlagIndex;
   725 
   726 #ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
   727 		case ELogSimIdField:
   728 			return aFilter1.SimId() == aFilter2.SimId();
   729 #endif			
   730 			
   731 		default:
   732 			__ASSERT_DEBUG(EFalse, Panic(ELogNoSuchState6));
   733 			break;
   734 		};
   735 	return EFalse;
   736 	}
   737 
   738 #ifdef _DEBUG
   739 void TLogFilterExprBuilder::Invariant() const
   740     {
   741     __ASSERT_DEBUG(KFilterFields[KFilterFieldsSize - 1] == ELogFlagsField, User::Invariant());
   742     __ASSERT_DEBUG(iFilterList != NULL, User::Invariant());
   743     __ASSERT_DEBUG(iInitial != NULL, User::Invariant());
   744     __ASSERT_DEBUG(iConstructionType == ELogFilterConstructFilterByFilterFieldByField || iConstructionType == ELogFilterConstructFieldByFieldFilterByFilter, User::Invariant());
   745     __ASSERT_DEBUG((TUint)iFilterIndex < iFilterList->Count(), User::Invariant());
   746     TInt idx = KMaxTInt;
   747     for(idx=0;idx<KFilterFieldsSize && iField!=KFilterFields[idx];++idx)
   748     	{
   749     	}
   750     __ASSERT_DEBUG(idx < KFilterFieldsSize, User::Invariant());
   751     __ASSERT_DEBUG((iField & (iField - 1)) == 0, User::Invariant());
   752     __ASSERT_DEBUG((TUint)iFlagIndex < KLogFlagsCount, User::Invariant());
   753     __ASSERT_DEBUG(iPredicateList != NULL, User::Invariant());
   754     }
   755 #endif