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