sl@0: // Copyright (c) 2002-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 "LOGQUERY.H" sl@0: #include "logservpanic.h" sl@0: #include "LogServDatabaseTransactionInterface.h" sl@0: #include "LogServDatabaseChangeInterface.h" sl@0: #include "LogServSqlStrings.h" sl@0: #include "LogDynBuf.h" sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////// RLogDbTable ///////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: RLogDbTable "resource acquisition" method. sl@0: Opens the specified database table with the required access mode. sl@0: If the database indexes are damaged, before the "table open" operation, an attempt will be made to recover the databasde. sl@0: If the table is opened successfully, the current RLogDbTable object will be put on the cleanup stack. The caller is sl@0: responsible for the destruction of the RLogDbTable object. sl@0: sl@0: @param aDb RDbDatabase reference sl@0: @param aTblName Table name sl@0: @param aAccess Table access mode, one of RDbRowSet::TAccess enum item values sl@0: sl@0: @leave KErrNoMemory, an out of memory condition has occurred; sl@0: Note that the function may leave with database specific errors and sl@0: other system-wide error codes. sl@0: */ sl@0: void RLogDbTable::OpenLC(RDbDatabase& aDb, const TDesC& aTblName, RDbRowSet::TAccess aAccess) sl@0: { sl@0: if(aDb.IsDamaged()) sl@0: { sl@0: User::LeaveIfError(aDb.Recover()); sl@0: } sl@0: __ASSERT_DEBUG(!aDb.IsDamaged(), Panic(ELogDatabaseDamaged2)); sl@0: CleanupClosePushL(*this); sl@0: User::LeaveIfError(RDbTable::Open(aDb, aTblName, aAccess)); sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////// RLogEventDbTable //////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: TDbColNo RLogEventDbTable::iIdColNo = 0; sl@0: TDbColNo RLogEventDbTable::iTypeColNo = 0; sl@0: TDbColNo RLogEventDbTable::iRemotePartyColNo = 0; sl@0: TDbColNo RLogEventDbTable::iDirectionColNo = 0; sl@0: TDbColNo RLogEventDbTable::iTimeColNo = 0; sl@0: TDbColNo RLogEventDbTable::iDurationTypeColNo = 0; sl@0: TDbColNo RLogEventDbTable::iDurationColNo = 0; sl@0: TDbColNo RLogEventDbTable::iStatusColNo = 0; sl@0: TDbColNo RLogEventDbTable::iSubjectColNo = 0; sl@0: TDbColNo RLogEventDbTable::iNumberColNo = 0; sl@0: TDbColNo RLogEventDbTable::iContactColNo = 0; sl@0: TDbColNo RLogEventDbTable::iLinkColNo = 0; sl@0: TDbColNo RLogEventDbTable::iDataColNo = 0; sl@0: TDbColNo RLogEventDbTable::iFlagColNo[] = {0, 0, 0, 0}; sl@0: TDbColNo RLogEventDbTable::iRecentColNo = 0; sl@0: TDbColNo RLogEventDbTable::iDuplicateColNo = 0; sl@0: #ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM sl@0: TDbColNo RLogEventDbTable::iSimIdColNo = 0; sl@0: #endif sl@0: sl@0: /** sl@0: RLogEventDbTable "resource acquisition" method. sl@0: Opens the "Event" database table with the required access mode. sl@0: If the database indexes are damaged, before the "table open" operation, an attempt will be made to recover the databasde. sl@0: If the table is opened successfully, the current RLogEventDbTable object will be put on the cleanup stack. The caller is sl@0: responsible for the destruction of the RLogEventDbTable object. sl@0: sl@0: @param aDb RDbDatabase reference sl@0: @param aAccess Table access mode, one of RDbRowSet::TAccess enum item values sl@0: sl@0: @leave KErrNoMemory, an out of memory condition has occurred; sl@0: Note that the function may leave with database specific errors and sl@0: other system-wide error codes. sl@0: */ sl@0: void RLogEventDbTable::OpenLC(RDbDatabase& aDb, RDbRowSet::TAccess aAccess) sl@0: { sl@0: RLogDbTable::OpenLC(aDb, KLogNameEventString, aAccess); sl@0: InitializeColumnsL(); sl@0: } sl@0: sl@0: /** sl@0: Initializes the static data members ("Event" table column numbers) of the RLogEventDbTable class. sl@0: The initialization happens just once, during the construction of the first object of RLogEventDbTable type. sl@0: sl@0: @leave KErrNoMemory, an out of memory condition has occurred; sl@0: Note that the function may leave with database specific errors and sl@0: other system-wide error codes. sl@0: */ sl@0: void RLogEventDbTable::InitializeColumnsL() sl@0: { sl@0: if(RLogEventDbTable::iIdColNo == 0) sl@0: { sl@0: CDbColSet* colset = ColSetL(); sl@0: RLogEventDbTable::iIdColNo = colset->ColNo(KLogFieldIdString); sl@0: RLogEventDbTable::iTypeColNo = colset->ColNo(KLogFieldEventTypeString); sl@0: RLogEventDbTable::iRemotePartyColNo = colset->ColNo(KLogFieldEventRemoteString); sl@0: RLogEventDbTable::iDirectionColNo = colset->ColNo(KLogFieldEventDirectionString); sl@0: RLogEventDbTable::iTimeColNo = colset->ColNo(KLogFieldEventTimeString); sl@0: RLogEventDbTable::iDurationTypeColNo = colset->ColNo(KLogFieldEventDTypeString); sl@0: RLogEventDbTable::iDurationColNo = colset->ColNo(KLogFieldEventDurationString); sl@0: RLogEventDbTable::iStatusColNo = colset->ColNo(KLogFieldEventStatusString); sl@0: RLogEventDbTable::iSubjectColNo = colset->ColNo(KLogFieldEventSubjectString); sl@0: RLogEventDbTable::iNumberColNo = colset->ColNo(KLogFieldEventNumberString); sl@0: RLogEventDbTable::iContactColNo = colset->ColNo(KLogFieldEventContactString); sl@0: RLogEventDbTable::iLinkColNo = colset->ColNo(KLogFieldEventLinkString); sl@0: RLogEventDbTable::iDataColNo = colset->ColNo(KLogFieldEventDataString); sl@0: for(TInt i=0;iColNo(colname); sl@0: __ASSERT_DEBUG(RLogEventDbTable::iFlagColNo[i] > 0, User::Invariant()); sl@0: } sl@0: RLogEventDbTable::iRecentColNo = colset->ColNo(KLogFieldEventRecentString); sl@0: RLogEventDbTable::iDuplicateColNo = colset->ColNo(KLogFieldEventDuplicateString); sl@0: #ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM sl@0: RLogEventDbTable::iSimIdColNo = colset->ColNo(KLogFieldEventSimId); sl@0: #endif sl@0: delete colset; sl@0: } sl@0: #ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM sl@0: __ASSERT_DEBUG(RLogEventDbTable::iIdColNo > 0 && sl@0: RLogEventDbTable::iTypeColNo > 0 && sl@0: RLogEventDbTable::iRemotePartyColNo > 0 && sl@0: RLogEventDbTable::iDirectionColNo > 0 && sl@0: RLogEventDbTable::iTimeColNo > 0 && sl@0: RLogEventDbTable::iDurationTypeColNo > 0 && sl@0: RLogEventDbTable::iDurationColNo > 0 && sl@0: RLogEventDbTable::iStatusColNo > 0 && sl@0: RLogEventDbTable::iSubjectColNo > 0 && sl@0: RLogEventDbTable::iNumberColNo > 0 && sl@0: RLogEventDbTable::iContactColNo > 0 && sl@0: RLogEventDbTable::iLinkColNo > 0 && sl@0: RLogEventDbTable::iDataColNo > 0 && sl@0: RLogEventDbTable::iRecentColNo > 0 && sl@0: RLogEventDbTable::iDuplicateColNo > 0 && sl@0: RLogEventDbTable::iSimIdColNo > 0, User::Invariant()); sl@0: #else sl@0: __ASSERT_DEBUG(RLogEventDbTable::iIdColNo > 0 && sl@0: RLogEventDbTable::iTypeColNo > 0 && sl@0: RLogEventDbTable::iRemotePartyColNo > 0 && sl@0: RLogEventDbTable::iDirectionColNo > 0 && sl@0: RLogEventDbTable::iTimeColNo > 0 && sl@0: RLogEventDbTable::iDurationTypeColNo > 0 && sl@0: RLogEventDbTable::iDurationColNo > 0 && sl@0: RLogEventDbTable::iStatusColNo > 0 && sl@0: RLogEventDbTable::iSubjectColNo > 0 && sl@0: RLogEventDbTable::iNumberColNo > 0 && sl@0: RLogEventDbTable::iContactColNo > 0 && sl@0: RLogEventDbTable::iLinkColNo > 0 && sl@0: RLogEventDbTable::iDataColNo > 0 && sl@0: RLogEventDbTable::iRecentColNo > 0 && sl@0: RLogEventDbTable::iDuplicateColNo > 0, User::Invariant()); sl@0: #endif sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////// RLogConfigDbTable /////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: TDbColNo RLogConfigDbTable::iSizeColNo = 0; sl@0: TDbColNo RLogConfigDbTable::iRecentColNo = 0; sl@0: TDbColNo RLogConfigDbTable::iAgeColNo = 0; sl@0: sl@0: /** sl@0: RLogConfigDbTable "resource acquisition" method. sl@0: Opens the "Config" database table with the required access mode. sl@0: If the database indexes are damaged, before the "table open" operation, an attempt will be made to recover the databasde. sl@0: If the table is opened successfully, the current RLogConfigDbTable object will be put on the cleanup stack. The caller is sl@0: responsible for the destruction of the RLogConfigDbTable object. sl@0: sl@0: @param aDb RDbDatabase reference sl@0: @param aAccess Table access mode, one of RDbRowSet::TAccess enum item values sl@0: sl@0: @leave KErrNoMemory, an out of memory condition has occurred; sl@0: Note that the function may leave with database specific errors and sl@0: other system-wide error codes. sl@0: */ sl@0: void RLogConfigDbTable::OpenLC(RDbDatabase& aDb, RDbRowSet::TAccess aAccess) sl@0: { sl@0: RLogDbTable::OpenLC(aDb, KLogNameConfigString, aAccess); sl@0: InitializeColumnsL(); sl@0: } sl@0: sl@0: /** sl@0: Initializes the static data members ("Config" table column numbers) of the RLogConfigDbTable class. sl@0: The initialization happens just once, during the construction of the first object of RLogConfigDbTable type. sl@0: sl@0: @leave KErrNoMemory, an out of memory condition has occurred; sl@0: Note that the function may leave with database specific errors and sl@0: other system-wide error codes. sl@0: */ sl@0: void RLogConfigDbTable::InitializeColumnsL() sl@0: { sl@0: if(RLogConfigDbTable::iSizeColNo == 0) sl@0: { sl@0: CDbColSet* colset = ColSetL(); sl@0: RLogConfigDbTable::iSizeColNo = colset->ColNo(KLogFieldConfigSizeString); sl@0: RLogConfigDbTable::iRecentColNo = colset->ColNo(KLogFieldConfigRecentString); sl@0: RLogConfigDbTable::iAgeColNo = colset->ColNo(KLogFieldConfigAgeString); sl@0: delete colset; sl@0: } sl@0: __ASSERT_DEBUG(RLogConfigDbTable::iSizeColNo > 0 && sl@0: RLogConfigDbTable::iRecentColNo > 0 && sl@0: RLogConfigDbTable::iAgeColNo > 0, User::Invariant()); sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////// RLogDbView ////////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: RLogDbView "resource acquisition" method. sl@0: Prepares a database view with the passed as a parameter SQL and with the required access mode. sl@0: If the database indexes are damaged, before the "prepare view" operation, an attempt will be made to recover the databasde. sl@0: If the view is prepared successfully, the current RLogDbView object will be put on the cleanup stack and all records sl@0: evaluated. The caller is responsible for the destruction of the RLogDbView object. sl@0: sl@0: @param aDb RDbDatabase reference sl@0: @param aQuery View SQL statement sl@0: @param aAccess View access mode, one of RDbRowSet::TAccess enum item values sl@0: sl@0: @leave KErrNoMemory, an out of memory condition has occurred; sl@0: Note that the function may leave with database specific errors and sl@0: other system-wide error codes. sl@0: */ sl@0: void RLogDbView::PrepareLC(RDbDatabase& aDb, const TDesC& aQuery, RDbRowSet::TAccess aAccess) sl@0: { sl@0: if(aDb.IsDamaged()) sl@0: { sl@0: User::LeaveIfError(aDb.Recover()); sl@0: } sl@0: __ASSERT_DEBUG(!aDb.IsDamaged(), Panic(ELogDatabaseDamaged2)); sl@0: CleanupClosePushL(*this); sl@0: User::LeaveIfError(RDbView::Prepare(aDb, TDbQuery(aQuery, EDbCompareFolded), aAccess)); sl@0: User::LeaveIfError(RDbView::EvaluateAll()); sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////// Global functions //////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: Runs the KLogSqlGetRecent SQL query and puts the IDs of the retrieved events into the aEventIds output array. sl@0: This happens only if the retrieved events count is bigger than the aMaxRecentLogSize parameter. sl@0: sl@0: @param aDb A MLogServDatabaseTransactionInterface reference sl@0: @param aRecentListId Recent list Id sl@0: @param aMaxRecentLogSize Max recent list size sl@0: @param aEventIds Output parameter. The function will put it on the cleanup stack and fill it with sl@0: the events ids from the recent list. The caller is responsible for the destruction of sl@0: the aEventIds parameter. sl@0: sl@0: @leave KErrNoMemory, an out of memory condition has occurred; sl@0: Note that the function may leave with database specific errors and sl@0: other system-wide error codes. sl@0: sl@0: @internalComponent sl@0: */ sl@0: void LogGetRecentEventsLC(MLogServDatabaseTransactionInterface& aDb, TLogRecentList aRecentListId, sl@0: TLogRecentSize aMaxRecentLogSize, RArray& aEventIds) sl@0: { sl@0: CleanupClosePushL(aEventIds); sl@0: TheSql.Format(KLogSqlGetRecent, aRecentListId); sl@0: RLogDbView view; sl@0: view.PrepareLC(aDb.DTIDatabase(), TheSql, RDbRowSet::EReadOnly); sl@0: TInt count = view.CountL() - aMaxRecentLogSize; sl@0: if(count > 0) sl@0: { sl@0: (void)view.LastL();//If "count > 0", then there is at least one record => LastL() cannot return EFalse. sl@0: static TDbColNo idColNo = 0; sl@0: if(idColNo == 0) sl@0: { sl@0: CDbColSet* colset = view.ColSetL(); sl@0: idColNo = colset->ColNo(KLogFieldIdString); sl@0: delete colset; sl@0: } sl@0: aEventIds.ReserveL(count); sl@0: do sl@0: { sl@0: view.GetL(); sl@0: aEventIds.AppendL(view.ColInt32(idColNo)); sl@0: } sl@0: while(--count && view.PreviousL()); sl@0: } sl@0: CleanupStack::PopAndDestroy(&view); sl@0: } sl@0: sl@0: /** sl@0: The function accepts an array of event IDs as a parameter, prepares an UPDATE SQL query using those IDs and sl@0: puts the constructed query into aSqlBuf output parameter. sl@0: sl@0: @param aEventIds Array with event Ids, used for the construction of the SQL statement sl@0: @param aSqlBuf Output parameter. A reference to RLogDynBuf object where the SQL is constructed. sl@0: sl@0: @leave KErrNoMemory, an out of memory condition has occurred; sl@0: sl@0: @internalComponent sl@0: */ sl@0: static void LogBuildPurgeRecentSqlL(const RArray& aEventIds, RLogDynBuf& aSqlBuf) sl@0: { sl@0: __ASSERT_DEBUG(aEventIds.Count() > 0, User::Invariant()); sl@0: aSqlBuf.SetLength(0); sl@0: aSqlBuf.AppendL(KLogSqlRemoveDuplicateEvents); sl@0: for(TInt i=0,count=aEventIds.Count();i num;//buf size of 20 is enough for a 32-bit number sl@0: num.AppendNum(aEventIds[i]); sl@0: aSqlBuf.AppendL(KIdEqStr); sl@0: aSqlBuf.AppendL(num); sl@0: aSqlBuf.AppendL(KLogOr); sl@0: aSqlBuf.AppendL(KDuplicateEqStr); sl@0: aSqlBuf.AppendL(num); sl@0: aSqlBuf.AppendL(KLogOr); sl@0: } sl@0: aSqlBuf.SetLength(aSqlBuf.Length() - KLogOr().Length()); sl@0: } sl@0: sl@0: /** sl@0: The function accepts an array of event IDs as a parameter, prepares an UPDATE SQL query and executes sl@0: the query. sl@0: The MLogServDatabaseChangeInterface interface will be used to collect the information about the IDs of the purged events. sl@0: Later that information will be used if there are any outstanding notification requests waiting for completion. sl@0: If the count of the aEventIds elements is 0, then no query will be prepared and executed. sl@0: sl@0: @param aDb A reference to MLogServDatabaseTransactionInterface interface sl@0: @param aEventIds Array with event Ids, used for the construction of the SQL statement sl@0: sl@0: @leave KErrNoMemory, an out of memory condition has occurred; sl@0: Note that the function may leave with database specific errors and sl@0: other system-wide error codes. sl@0: sl@0: @internalComponent sl@0: */ sl@0: void LogPurgeRecentEventsL(MLogServDatabaseTransactionInterface& aDb, const RArray& aEventIds) sl@0: { sl@0: TInt count = aEventIds.Count(); sl@0: if(count == 0) sl@0: { sl@0: return; sl@0: } sl@0: RLogDynBuf sqlBuf; sl@0: sqlBuf.CreateLC(sizeof(KLogSqlRemoveDuplicateEvents) + count * 32);//32 - approx - length of "Duplicate=N OR Id=N" sl@0: LogBuildPurgeRecentSqlL(aEventIds, sqlBuf); sl@0: User::LeaveIfError(aDb.DTIExecuteSql(sqlBuf.DesC())); sl@0: CleanupStack::PopAndDestroy(&sqlBuf); sl@0: for(TInt i=0;i 0) sl@0: { sl@0: (void)aTbl.FirstL();//If "count > 0", then there is at least one record => FirstL() cannot return EFalse. sl@0: TBool commit = !aDb.DTIInTransaction(); sl@0: if(commit) sl@0: { sl@0: aDb.DTIBeginWithRollBackProtectionLC(); sl@0: } sl@0: do sl@0: { sl@0: aTbl.GetL(); sl@0: TLogId id = aTbl.ColInt32(RLogEventDbTable::iIdColNo); sl@0: aTbl.DeleteL(); sl@0: aDb.DTIChangeInterface().DCISubmitChangedEventContextL(ELogChangeTypeEventDeleted, id); sl@0: } sl@0: while(--count && aTbl.NextL()); sl@0: if(commit) sl@0: { sl@0: aDb.DTICommitAndCancelRollbackProtectionL(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Updates the event records with "Duplicate" column value equal to aEventId. sl@0: The MLogServDatabaseChangeInterface interface will be used to collect the information about the IDs of the modified events. sl@0: Later that information will be used if there are any outstanding notification requests waiting for completion. sl@0: If no duplicates of the passed as a parameter event ID exist, then the function does nothing. sl@0: sl@0: @param aDb A reference to MLogServDatabaseTransactionInterface interface sl@0: @param aEventId Duplicated event id sl@0: sl@0: @leave KErrNoMemory, an out of memory condition has occurred; sl@0: Note that the function may leave with database specific errors and sl@0: other system-wide error codes. sl@0: sl@0: @internalComponent sl@0: */ sl@0: void LogResetDuplicatesL(MLogServDatabaseTransactionInterface& aDb, TLogId aEventId) sl@0: { sl@0: TheSql.Format(KLogSqlDuplicateViewString, aEventId, &KNullDesC); sl@0: RLogDbView view; sl@0: view .PrepareLC(aDb.DTIDatabase(), TheSql); sl@0: // Are there any duplicates? sl@0: if(view.FirstL()) sl@0: { sl@0: static TDbColNo idColNo = 0; sl@0: static TDbColNo duplicateColNo = 0; sl@0: if(idColNo == 0) sl@0: { sl@0: CDbColSet* colset = view.ColSetL(); sl@0: idColNo = colset->ColNo(KLogFieldIdString); sl@0: duplicateColNo = colset->ColNo(KLogFieldEventDuplicateString); sl@0: delete colset; sl@0: } sl@0: TBool commit = !aDb.DTIInTransaction(); sl@0: if(commit) sl@0: { sl@0: aDb.DTIBeginWithRollBackProtectionLC(); sl@0: } sl@0: // Get the id of the latest event sl@0: view.GetL(); sl@0: const TLogId idLatest = view.ColInt32(idColNo); sl@0: // Mark the event as the latest duplicate sl@0: view.UpdateL(); sl@0: view.SetColNullL(duplicateColNo); sl@0: view.PutL(); sl@0: // This is a "hidden" change. It may affect the contents of a view, but the actual event hasn't changed sl@0: aDb.DTIChangeInterface().DCISubmitChangedEventContextL(ELogChangeTypeEventChangedHidden, idLatest); sl@0: // Reset the duplicate id's of the other duplicates sl@0: while(view.NextL()) sl@0: { sl@0: view.UpdateL(); sl@0: const TLogId id = view.ColInt32(idColNo); sl@0: view.SetColL(duplicateColNo, idLatest); sl@0: view.PutL(); sl@0: // This is a "hidden" change. It may affect the contents of a view, but the actual event hasn't changed sl@0: aDb.DTIChangeInterface().DCISubmitChangedEventContextL(ELogChangeTypeEventChangedHidden, id); sl@0: } sl@0: if(commit) sl@0: { sl@0: aDb.DTICommitAndCancelRollbackProtectionL(); sl@0: } sl@0: } sl@0: CleanupStack::PopAndDestroy(&view); sl@0: }