diff -r 000000000000 -r 08ec8eefde2f loggingservices/eventlogger/LogServ/src/LogServView.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loggingservices/eventlogger/LogServ/src/LogServView.cpp Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,861 @@ +// Copyright (c) 2002-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 "LogServView.h" +#include "logpackage.h" +#include "logservpanic.h" +#include "LogServBackupInterface.h" +#include "LogServViewChangeManager.h" +#include "LogServDatabaseChangeInterface.h" +#include "LogServCacheTypes.h" +#include "LogServSqlStrings.h" +#include "LOGFILTQ.H" + +// Constants +const TInt KLogViewContentsGranuality = 20; +const TInt KLogViewLockStatusEventGranularity = 3; + +TDbColNo CLogServViewBase::iIdColNo = 0; +TDbColNo CLogServViewBase::iTypeColNo = 0; +TDbColNo CLogServViewBase::iFlagColNo[] = {0, 0, 0, 0}; + +TDbColNo CLogServViewRecent::iIdColNo = 0; +TDbColNo CLogServViewRecent::iRecentColNo = 0; +TDbColNo CLogServViewRecent::iDuplicateColNo = 0; + +//diagnostic message for the platform security +const char* KIgnoreDiagnostic = "This diagnostic message does not indicate an error, please ignore it"; + +///////////////////////////////////////////////////////////////////////////////////////// +// -----> CLogServViewBase (source) +///////////////////////////////////////////////////////////////////////////////////////// +CLogServViewBase::CLogServViewBase(MLogServDatabaseTransactionInterface& aDatabase, + MLogServBackupInterface& aBackupInterface, + CLogPackage& aPackage, TLogViewType aType, TLogViewId aViewId, + const RMessage2& aMessage) : + iDatabase(aDatabase), + iPackage(aPackage), + iBackupInterface(aBackupInterface), + iType(aType), + iViewId(aViewId), + iMessage (aMessage) + { + } + +CLogServViewBase::~CLogServViewBase() + { + iDatabase.DTIChangeInterface().DCIRequestChangeNotificationsCancel(*this); + iBackupInterface.BIObserverRemove(*this); + // + iViewContents.Close(); + // + iStandardTypeSecurityCache.Close(); + // + delete iLockChangeObserver; + delete iSql; + delete iChangeManager; + } + + +void CLogServViewBase::ConstructL() + { + // Handles changes for this view + iChangeManager = CLogServViewChangeManager::NewL(iDatabase.DTIChangeInterface()); + + // Register for change events + iDatabase.DTIChangeInterface().DCIRequestChangeNotificationsL(*this); + + // Register for backup events + iBackupInterface.BIObserverAddL(*this, MLogServBackupInterface::EObjectView); + + // Observes when the view is locked/unlocked due to a backup + iLockChangeObserver = CLogServViewLockObserver::NewL(iBackupInterface); + + const RArray& arrTUids = iDatabase.DTIUidsOfStandardTypes(); + TInt count = arrTUids.Count(); + iStandardTypeSecurityCache.ReserveL(count); + for(TInt i=0; i < count; i++) + { + SStandardTypeSecurity securitySetting; + securitySetting.eventType = arrTUids[i]; + securitySetting.readAccess = iDatabase.DTIIsAllowed(EReadOp, iMessage, arrTUids[i], KIgnoreDiagnostic); + securitySetting.writeAccess = iDatabase.DTIIsAllowed(EWriteOp, iMessage, arrTUids[i], KIgnoreDiagnostic); + TInt err = iStandardTypeSecurityCache.Append(securitySetting); + __ASSERT_ALWAYS(err == KErrNone, Panic(ELogArrayReserved)); + } + } + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + +void CLogServViewBase::DCOHandleChangeEventsL(const CLogChangeDefinition& aChanges) + { + // Just return if the view isn't setup + if (!iSql) + return; + + TRAPD(error, DoHandleChangeEventsL(aChanges)); + if (error != KErrNone) + { + iViewContents.Close(); + iViewContentsReady = EFalse; + iRebuildViewContents = ETrue; + } + } + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + +void CLogServViewBase::BOHandleEventL(TLogServBackupEvent aEvent) + { + switch(aEvent) + { + case EBackupStarting: + iViewContents.Close(); + iViewContentsReady = EFalse; + break; + case EBackupEnded: + RebuildViewL(); + break; + } + } + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + +#pragma BullseyeCoverage off + +/** +Remove an entry from the view. +By default you can't remove an event from a view. +*/ +void CLogServViewBase::RemoveL(const RMessage2& /*aMessage*/) + { + User::Leave(KErrNotSupported); + } + +/** +By default you can't clear duplicates from a view +*/ +void CLogServViewBase::ClearDuplicatesL(const RMessage2& /*aMessage*/) + { + User::Leave(KErrNotSupported); + } + +#pragma BullseyeCoverage on + +/** +Set the flags of all the entries in the view. +*/ +void CLogServViewBase::SetFlagsL(const RMessage2& aMessage) + { + if (ViewIsReady()) + { + // Flags from client + const TLogFlags flags = static_cast(aMessage.Int2()); + RLogDbView view; + view.PrepareLC(iDatabase.DTIDatabase(), *iSql); + InitializeColumnsL(view); + if(view.FirstL()) + { + iDatabase.DTIBeginWithRollBackProtectionLC(); + // Iterate through the events + do + { + // Get current event id + view.GetL(); + const TLogId id = view.ColInt32(CLogServViewBase::iIdColNo); + TUint8 eventTypeIndex = view.ColUint8(CLogServViewBase::iTypeColNo); + if(IsAllowed(EWriteOp, eventTypeIndex)) + { + // Make the change + view.UpdateL(); + TInt bit = KLogFlagsCount; + while(bit--) + { + const TBool flagIsSet = flags & (0x1 << bit) ? 1 : 0; + view.SetColL(CLogServViewBase::iFlagColNo[bit], flagIsSet); + } + view.PutL(); + iDatabase.DTIChangeInterface().DCISubmitChangedEventContextL(ELogChangeTypeEventChanged, id); + } + } + while(view.NextL()); + iDatabase.DTICommitAndCancelRollbackProtectionL(); + } + CleanupStack::PopAndDestroy(&view); + } + else + ::PanicClientL(aMessage, ELogViewRecentViewNotYetReadyForFlagSetting); + } + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + +/** +The client has requested change notifications +*/ +void CLogServViewBase::RequestChangeNotifications(const RMessage2& aMessage) + { + iChangeManager->RequestChangeNotifications(aMessage); + } + +/** +The client has cancelled a previous change notification request +*/ +void CLogServViewBase::RequestChangeNotificationsCancel() + { + iChangeManager->RequestChangeNotificationsCancel(); + } + +/** +The client has requested lock status change notifications +*/ +void CLogServViewBase::RequestLockStatusChanges(const RMessage2& aMessage) + { + iLockChangeObserver->RequestLockStatusChanges(aMessage); + } + +/** +The client has cancelled a previous change notification request +*/ +void CLogServViewBase::RequestLockStatusChangesCancel() + { + iLockChangeObserver->RequestLockStatusChangesCancel(); + } + +/** +The client has requested the current list of changes +*/ +void CLogServViewBase::RequestChangesL(const RMessage2& aMessage) + { + if (!iSql) + ::PanicClientL(aMessage, ELogViewNotSetupForChangesFetch); + else + iChangeManager->DeliverChangesL(aMessage); + } + +/** +Set up the server-side view based upon the client-side filter. This +method essentially fetches a client-side filter and then dynamically +executes the associated SELECT statement on the database to build up +a view. This view is then cached in terms of the entry ids (iViewContents). +*/ +void CLogServViewBase::SetupL(const RMessage2& aMessage, TLogFilterConstructionType aFilterType) + { + // Get the query string + const TPtrC pSQL(GetQueryStringL(aMessage, aFilterType)); + HBufC* buf = pSQL.AllocLC(); + // Setup the contents + PrepareViewContentsL(pSQL); + // Tidy up + CleanupStack::Pop(buf); + delete iSql; + iSql = buf; + } + +/** +Returns the number of entries in this view +*/ +TInt CLogServViewBase::Count() const + { + return const_cast(this)->RebuildViewContentsIfNecessary() ? 0 : iViewContents.Count(); + } + +/** +Get the log id at the specified index +*/ +TLogId CLogServViewBase::At(TInt aIndex) const + { + return (TUint)aIndex < iViewContents.Count() ? iViewContents[aIndex] : KLogNullId; + } + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + +void CLogServViewBase::DestroyList(TAny *aPtr) + { + CLogFilterList* filter = reinterpret_cast(aPtr); + filter->ResetAndDestroy(); + delete filter; + } + +void CLogServViewBase::InitializeColumnsL(RDbRowSet& aRowSet) + { + if(CLogServViewBase::iIdColNo == 0) + { + CDbColSet* colset = aRowSet.ColSetL(); + CLogServViewBase::iIdColNo = colset->ColNo(KLogFieldIdString); + CLogServViewBase::iTypeColNo = colset->ColNo(KLogFieldEventTypeString); + for(TInt i=0;iColNo(colname); + __ASSERT_DEBUG(CLogServViewBase::iFlagColNo[i] > 0, User::Invariant()); + } + delete colset; + } + __ASSERT_DEBUG(CLogServViewBase::iIdColNo > 0 && CLogServViewBase::iTypeColNo > 0, User::Invariant()); + } + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + +void CLogServViewBase::ResetViewContentsL(RDbRowSet& aRowSet) + { + // Get the view contents + RArray viewContents(KLogViewContentsGranuality); + CleanupClosePushL(viewContents); + viewContents.ReserveL(aRowSet.CountL()); + if(aRowSet.FirstL()) + { + do + { + // Get the id at the current position + aRowSet.GetL(); + const TLogId id = aRowSet.ColInt32(CLogServViewBase::iIdColNo); + TUint8 eventTypeIndex = aRowSet.ColUint8(CLogServViewBase::iTypeColNo); + if(IsAllowed(EReadOp, eventTypeIndex)) + { + TInt err = viewContents.Append(id); + __ASSERT_ALWAYS(err == KErrNone, Panic(ELogArrayReserved)); + } + } + while(aRowSet.NextL()); + } + // Tidy up - don't leave from below here + CleanupStack::Pop(&viewContents); + iViewContents.Close(); + iViewContents = viewContents; + iViewContentsReady = ETrue; + } + +void CLogServViewBase::PrepareViewContentsL(const TDesC& aSQL) + { + // Generate the view + RLogDbView view; + view.PrepareLC(iDatabase.DTIDatabase(), aSQL); + InitializeColumnsL(view); + // Reset the view + ResetViewContentsL(view); + CleanupStack::PopAndDestroy(&view); + } + +void CLogServViewBase::RebuildViewL() + { + if (iSql && iSql->Length()) + PrepareViewContentsL(*iSql); + } + +// +// The last change notification indication was not handled correctly. +// Attempt to re-initialise the view +// +TInt CLogServViewBase::RebuildViewContentsIfNecessary() + { + TInt error = KErrNone; + // + if (iRebuildViewContents && iSql && iSql->Length()) + { + TRAP(error, + + RebuildViewL(); + + // The view is okay now + iRebuildViewContents = EFalse; + ); + } + return error; + } + +void CLogServViewBase::DoHandleChangeEventsL(const CLogChangeDefinition& aChanges) + { + if(!ViewIsReady()) + { + return; + } + + // Generate the view + RLogDbView view; + view.PrepareLC(iDatabase.DTIDatabase(), *iSql); + InitializeColumnsL(view); + _LIT(KLogIdQuery, "Id = %d"); + TBuf<15> find; + TInt changeIndex; + + // Prepare for a change transaction + iChangeManager->ChangeTransactionPrepare(); + + const TInt count = aChanges.Count(); + for(TInt i=0; i= 0) + { + view.GetL(); + TUint8 eventTypeIndex = view.ColUint8(CLogServViewBase::iTypeColNo); + if (IsAllowed(EReadOp, eventTypeIndex)) + User::LeaveIfError(iViewContents.Insert(logId, changeIndex)); + + iChangeManager->ChangeTransactionSubmitL(logId, ELogChangeTypeEventAdded, changeIndex); + } + } + } + break; + case ELogChangeTypeEventChanged: + case ELogChangeTypeEventChangedHidden: + { + // See if the event is in the view + if (view.FirstL() && (changeIndex = view.FindL(RDbRowSet::EForwards, TDbQuery(find))) >= KErrNone) + { + // If the event was already in the view then it has changed otherwise it's been added + const TInt findIndex = iViewContents.Find(logId); + if (findIndex >= KErrNone) + { + // If the item that changed also caused its position within the view to be altered + // then we need to simulate a delete, followed by an addition + if (findIndex != changeIndex) + { + iChangeManager->ChangeTransactionSubmitL(logId, ELogChangeTypeEventDeleted, findIndex); + iChangeManager->ChangeTransactionSubmitL(logId, ELogChangeTypeEventAdded, changeIndex); + } + // Only tell the view if the CLogEvent has changed + else if (type != ELogChangeTypeEventChangedHidden) + { + iChangeManager->ChangeTransactionSubmitL(logId, ELogChangeTypeEventChanged, changeIndex); + } + } + else + { + User::LeaveIfError(iViewContents.Insert(logId, changeIndex)); + iChangeManager->ChangeTransactionSubmitL(logId, ELogChangeTypeEventAdded, changeIndex); + + // Update the type to indicate that this change action + // really resulted in an addition + type = ELogChangeTypeEventAdded; + } + } + else + { + changeIndex = iViewContents.Find(logId); + + // If it used to be in the view then it's been removed because it's + // not in there anymore + if (changeIndex >= KErrNone) + { + iViewContents.Remove(changeIndex); + iChangeManager->ChangeTransactionSubmitL(logId, ELogChangeTypeEventDeleted, changeIndex); + + // Update the type to indicate that this change action + // really resulted in a deletion + type = ELogChangeTypeEventDeleted; + } + } + } + break; + case ELogChangeTypeEventDeleted: + { + changeIndex = iViewContents.Find(logId); + + // If it used to be in the view then tell it about the deletion + if (changeIndex >= KErrNone) + { + iViewContents.Remove(changeIndex); + iChangeManager->ChangeTransactionSubmitL(logId, ELogChangeTypeEventDeleted, changeIndex); + } + } + break; + case ELogChangeTypeLogCleared: + { + RebuildViewL(); + iChangeManager->ChangeTransactionSubmitL(logId, ELogChangeTypeLogCleared, 0); + } + break; + default: + __ASSERT_DEBUG(EFalse, Panic(ELogUnrecognizedChangeType)); + break; + } + } + + CleanupStack::PopAndDestroy(&view); + + // Commit the transaction. Will notify client if necessary + iChangeManager->ChangeTransactionCommitL(); + } + +TBool CLogServViewBase::IsAllowed(TEventOp aEventOp, TUint8 aEventTypeIndex) + { + TBool result = ETrue; + + const TLogServCacheTypeEntry& entry = iDatabase.DTICacheTypes().FindById(aEventTypeIndex); + TUid eventTypeUid = entry.iEventType->Uid(); + TInt count = iStandardTypeSecurityCache.Count(); + + for(TInt i=0;i CLogServViewLockObserver (source) +///////////////////////////////////////////////////////////////////////////////////////// + +CLogServViewLockObserver::CLogServViewLockObserver(MLogServBackupInterface& aBackupInterface) +: iBackupInterface(aBackupInterface), iLockEvents(KLogViewLockStatusEventGranularity) + { + } + +CLogServViewLockObserver::~CLogServViewLockObserver() + { + iBackupInterface.BIObserverRemove(*this); + iLockEvents.Close(); + } + +void CLogServViewLockObserver::ConstructL() + { + // Register for backup events + iBackupInterface.BIObserverAddL(*this, MLogServBackupInterface::EObjectViewLock); + } + +CLogServViewLockObserver* CLogServViewLockObserver::NewL(MLogServBackupInterface& aBackupInterface) + { + CLogServViewLockObserver* self = new(ELeave) CLogServViewLockObserver(aBackupInterface); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CLogServViewLockObserver::BOHandleEventL(TLogServBackupEvent aEvent) + { + // Map event + TLogViewLockStatus status = ELogViewWindowOpen; + if (aEvent == MLogServBackupObserver::EBackupStarting) + status = ELogViewWindowLocked; + + // Cache or complete immediately + if (!HaveLockStatusChangePointer()) + User::LeaveIfError(iLockEvents.Append(status)); + else + CompleteLockStatusChangeMessage(status); + } + +/** +The client has requested lock status change notifications +*/ +void CLogServViewLockObserver::RequestLockStatusChanges(const RMessage2& aMessage) + { + if (!HaveLockStatusChangePointer()) + { + iLockStatusChangeMessage = aMessage; + + // Already have one cached event + if (iLockEvents.Count()) + { + CompleteLockStatusChangeMessage(iLockEvents[0]); + iLockEvents.Remove(0); + } + } + else + PanicClient(aMessage, ELogViewLockStatusChangeRequestAlreadyIssued); + } + +/** +The client has cancelled a previous change notification request +*/ +void CLogServViewLockObserver::RequestLockStatusChangesCancel() + { + if (HaveLockStatusChangePointer()) + CompleteLockStatusChangeMessage(KErrCancel); + } + +void CLogServViewLockObserver::CompleteLockStatusChangeMessage(TInt aCompletionCode) + { + __ASSERT_ALWAYS(HaveLockStatusChangePointer(), Panic(ELogViewNoLockStatusChangeMessage)); + iLockStatusChangeMessage.Complete(aCompletionCode); + } + +///////////////////////////////////////////////////////////////////////////////////////// +// -----> CLogServViewEvent (source) +///////////////////////////////////////////////////////////////////////////////////////// +CLogServViewEvent::CLogServViewEvent(MLogServDatabaseTransactionInterface& aDatabase, MLogServBackupInterface& aBackupInterface, CLogPackage& aPackage, TLogViewId aViewId, const RMessage2& aMessage) +: CLogServViewBase(aDatabase, aBackupInterface, aPackage, ELogViewTypeEvent, aViewId, aMessage) + { + } + +CLogServViewEvent* CLogServViewEvent::NewL(MLogServDatabaseTransactionInterface& aDatabase, MLogServBackupInterface& aBackupInterface, CLogPackage& aPackage, TLogViewId aViewId, const RMessage2& aMessage) + { + CLogServViewEvent* self = new(ELeave) CLogServViewEvent(aDatabase, aBackupInterface, aPackage, aViewId, aMessage); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +/** +Setup the view +Fetch the client-side SQL query string which this view uses to obtain a data-set. +*/ +TPtrC CLogServViewEvent::GetQueryStringL(const RMessage2& aMessage, TLogFilterConstructionType aFilterType) + { + // Read stuff from the client + iPackage.ResizeL(aMessage.GetDesLengthL(2)); + aMessage.ReadL(2, iPackage.Ptr()); + + // Decode the parameters we've read from the client + CLogFilterList* filter = new(ELeave)CLogFilterList; + CleanupStack::PushL(TCleanupItem(DestroyList, filter)); + iPackage.GetLogFilterListL(*filter); + RLogDynBuf expr; + TLogFilterExprBuilder exprBuilder(iDatabase); + exprBuilder.BuildExprLC(expr, *filter, KLogWhere, aFilterType); + // Generate the query string that will be used + TheSql.Format(KLogSqlEventViewString, &KLogViewSelectColList, &expr.DesC()); + CleanupStack::PopAndDestroy(2, filter); + return TheSql; + } + +///////////////////////////////////////////////////////////////////////////////////////// +// -----> CLogServViewRecent (source) +///////////////////////////////////////////////////////////////////////////////////////// +CLogServViewRecent::CLogServViewRecent(MLogServDatabaseTransactionInterface& aDatabase, MLogServBackupInterface& aBackupInterface, CLogPackage& aPackage, TLogViewId aViewId, const RMessage2& aMessage) +: CLogServViewBase(aDatabase, aBackupInterface, aPackage, ELogViewTypeRecent, aViewId, aMessage) + { + } + +CLogServViewRecent* CLogServViewRecent::NewL(MLogServDatabaseTransactionInterface& aDatabase, MLogServBackupInterface& aBackupInterface, CLogPackage& aPackage, TLogViewId aViewId, const RMessage2& aMessage) + { + CLogServViewRecent* self = new(ELeave) CLogServViewRecent(aDatabase, aBackupInterface, aPackage, aViewId, aMessage); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +/** +Setup the view +Fetch the client-side SQL query string which this view uses to obtain a data-set. +*/ +TPtrC CLogServViewRecent::GetQueryStringL(const RMessage2& aMessage, TLogFilterConstructionType aFilterType) + { + // Read stuff from the client + iPackage.ResizeL(aMessage.GetDesLengthL(2)); + aMessage.ReadL(2, iPackage.Ptr()); + + // Decode the parameters we've read from the client + CLogFilterList* filter = new(ELeave)CLogFilterList; + CleanupStack::PushL(TCleanupItem(DestroyList, filter)); + iPackage.GetLogFilterListL(*filter); + RLogDynBuf expr; + TLogFilterExprBuilder exprBuilder(iDatabase); + exprBuilder.BuildExprLC(expr, *filter, KLogAnd, aFilterType); + iRecentList = static_cast(aMessage.Int3()); + // Generate the view that will be used + if (iRecentList == KLogNullRecentList) + { + TheSql.Format(KLogSqlAllRecentViewString, &KLogViewSelectColList, &expr.DesC()); + } + else + { + TheSql.Format(KLogSqlRecentViewString, &KLogViewSelectColList, iRecentList, &expr.DesC()); + } + CleanupStack::PopAndDestroy(2, filter); + return TheSql; + } + +/** +Remove an entry from the view. +Note the client can call this even if the view isn't valid. +*/ +void CLogServViewRecent::RemoveL(const RMessage2& aMessage) + { + if(! aMessage.HasCapability(ECapabilityWriteDeviceData)) + User::Leave(KErrPermissionDenied); + + const TLogId id = static_cast(aMessage.Int2()); + TBuf<20> num; + num.AppendNum(id); + + iDatabase.DTIBeginWithRollBackProtectionLC(); + + TheSql.Copy(KLogSqlRemoveDuplicateEvents); + TheSql.Append(KIdEqStr); + TheSql.Append(num); + TheSql.Append(KLogOr); + TheSql.Append(KDuplicateEqStr); + TheSql.Append(num); + User::LeaveIfError(iDatabase.DTIExecuteSql(TheSql)); + + // This is a "hidden" change. It may affect the contents of a view, but the actual event hasn't changed + iDatabase.DTIChangeInterface().DCISubmitChangedEventContextL(ELogChangeTypeEventChangedHidden, id); + iDatabase.DTICommitAndCancelRollbackProtectionL(); + } + +/** +Clear all duplicate events associated with this recent list. +*/ +void CLogServViewRecent::ClearDuplicatesL(const RMessage2& aMessage) + { + if(! aMessage.HasCapability(ECapabilityWriteDeviceData)) + User::Leave(KErrPermissionDenied); + + if (iRecentList > 0) + { + // Get list of duplicates + TheSql.Format(KLogSqlSelectAllDuplicatesString, iRecentList); + RLogDbView view; + view.PrepareLC(iDatabase.DTIDatabase(), TheSql); + InitializeColumns2L(view); + if(view.FirstL()) + { + iDatabase.DTIBeginWithRollBackProtectionLC(); + // Iterate through the events + do + { + // Get current event id + view.GetL(); + const TLogId id = view.ColInt32(CLogServViewRecent::iIdColNo); + // Make the change + view.UpdateL(); + view.SetColNullL(CLogServViewRecent::iRecentColNo); + view.SetColNullL(CLogServViewRecent::iDuplicateColNo); + view.PutL(); + // This is a "hidden" change. It may affect the contents of a view, but the actual event hasn't changed + iDatabase.DTIChangeInterface().DCISubmitChangedEventContextL(ELogChangeTypeEventChangedHidden, id); + } + while(view.NextL()); + iDatabase.DTICommitAndCancelRollbackProtectionL(); + } + CleanupStack::PopAndDestroy(&view); + } + else + ::PanicClientL(aMessage, ELogInvalidRecentView); + } + +void CLogServViewRecent::InitializeColumns2L(RDbRowSet& aRowSet) + { + if(CLogServViewRecent::iIdColNo == 0) + { + CDbColSet* colset = aRowSet.ColSetL(); + CLogServViewRecent::iIdColNo = colset->ColNo(KLogFieldIdString); + CLogServViewRecent::iRecentColNo = colset->ColNo(KLogFieldEventRecentString); + CLogServViewRecent::iDuplicateColNo = colset->ColNo(KLogFieldEventDuplicateString); + delete colset; + } + __ASSERT_DEBUG(CLogServViewRecent::iIdColNo > 0 && + CLogServViewRecent::iRecentColNo > 0 && + CLogServViewRecent::iDuplicateColNo > 0, User::Invariant()); + + } + +///////////////////////////////////////////////////////////////////////////////////////// +// -----> CLogServViewDuplicate (source) +///////////////////////////////////////////////////////////////////////////////////////// +CLogServViewDuplicate::CLogServViewDuplicate(MLogServDatabaseTransactionInterface& aDatabase, MLogServBackupInterface& aBackupInterface, CLogPackage& aPackage, TLogViewId aViewId, const RMessage2& aMessage) +: CLogServViewBase(aDatabase, aBackupInterface, aPackage, ELogViewTypeDuplicate, aViewId, aMessage) +// +// Duplicate view +// + { + } + +CLogServViewDuplicate* CLogServViewDuplicate::NewL(MLogServDatabaseTransactionInterface& aDatabase, MLogServBackupInterface& aBackupInterface, CLogPackage& aPackage, TLogViewId aViewId, const RMessage2& aMessage) + { + CLogServViewDuplicate* self = new(ELeave) CLogServViewDuplicate(aDatabase, aBackupInterface, aPackage, aViewId, aMessage); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +/** +Setup the view +Fetch the client-side SQL query string which this view uses to obtain a data-set. +*/ +TPtrC CLogServViewDuplicate::GetQueryStringL(const RMessage2& aMessage, TLogFilterConstructionType aFilterType) + { + // Read stuff from the client + iPackage.ResizeL(aMessage.GetDesLengthL(2)); + aMessage.ReadL(2, iPackage.Ptr()); + + // Decode the parameters we've read from the client + CLogFilterList* filter = new(ELeave)CLogFilterList; + CleanupStack::PushL(TCleanupItem(DestroyList, filter)); + iPackage.GetLogFilterListL(*filter); + RLogDynBuf expr; + TLogFilterExprBuilder exprBuilder(iDatabase); + exprBuilder.BuildExprLC(expr, *filter, KLogAnd, aFilterType); + iSourceId = (TInt)aMessage.Ptr3(); + // Generate the view that will be used + TheSql.Format(KLogSqlDuplicateViewString2, &KLogViewSelectColList, iSourceId, &expr.DesC()); + CleanupStack::PopAndDestroy(2, filter); + return TheSql; + } + +/** +Remove an entry from the view. +*/ +void CLogServViewDuplicate::RemoveL(const RMessage2& aMessage) + { + if(! aMessage.HasCapability(ECapabilityWriteDeviceData)) + User::Leave(KErrPermissionDenied); + + const TLogId id = static_cast(aMessage.Int2()); + + iDatabase.DTIBeginWithRollBackProtectionLC(); + + // Do the actual work + TheSql.Format(KLogSqlRemoveDuplicateString, id, iSourceId); + const TInt error = iDatabase.DTIExecuteSql(TheSql); + User::LeaveIfError(error); + // + // This is a "hidden" change. It may affect the contents of a view, but the actual event hasn't changed + iDatabase.DTIChangeInterface().DCISubmitChangedEventContextL(ELogChangeTypeEventChangedHidden, id); + iDatabase.DTICommitAndCancelRollbackProtectionL(); + }