loggingservices/eventlogger/LogServ/src/LOGQUERY.CPP
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 2002-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 "LOGQUERY.H"
       
    17 #include "logservpanic.h"
       
    18 #include "LogServDatabaseTransactionInterface.h"
       
    19 #include "LogServDatabaseChangeInterface.h"
       
    20 #include "LogServSqlStrings.h"
       
    21 #include "LogDynBuf.h"
       
    22 
       
    23 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    24 /////////////////////////         RLogDbTable             /////////////////////////////////////////////////////////
       
    25 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    26 
       
    27 /**
       
    28 RLogDbTable "resource acquisition" method.
       
    29 Opens the specified database table with the required access mode.
       
    30 If the database indexes are damaged, before the "table open" operation, an attempt will be made to recover the databasde.
       
    31 If the table is opened successfully, the current RLogDbTable object will be put on the cleanup stack. The caller is
       
    32 responsible for the destruction of the RLogDbTable object. 
       
    33 
       
    34 @param aDb RDbDatabase reference
       
    35 @param aTblName Table name
       
    36 @param aAccess Table access mode, one of RDbRowSet::TAccess enum item values
       
    37 
       
    38 @leave  KErrNoMemory, an out of memory condition has occurred;
       
    39                       Note that the function may leave with database specific errors and
       
    40                       other system-wide error codes.
       
    41 */
       
    42 void RLogDbTable::OpenLC(RDbDatabase& aDb, const TDesC& aTblName, RDbRowSet::TAccess aAccess)
       
    43     {
       
    44     if(aDb.IsDamaged())
       
    45         {
       
    46         User::LeaveIfError(aDb.Recover());
       
    47         }
       
    48     __ASSERT_DEBUG(!aDb.IsDamaged(), Panic(ELogDatabaseDamaged2));
       
    49     CleanupClosePushL(*this);
       
    50     User::LeaveIfError(RDbTable::Open(aDb, aTblName, aAccess));
       
    51     }
       
    52 
       
    53 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    54 /////////////////////////         RLogEventDbTable             ////////////////////////////////////////////////////
       
    55 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    56 
       
    57 TDbColNo RLogEventDbTable::iIdColNo = 0;
       
    58 TDbColNo RLogEventDbTable::iTypeColNo = 0;
       
    59 TDbColNo RLogEventDbTable::iRemotePartyColNo = 0;
       
    60 TDbColNo RLogEventDbTable::iDirectionColNo = 0;
       
    61 TDbColNo RLogEventDbTable::iTimeColNo = 0;
       
    62 TDbColNo RLogEventDbTable::iDurationTypeColNo = 0;
       
    63 TDbColNo RLogEventDbTable::iDurationColNo = 0;
       
    64 TDbColNo RLogEventDbTable::iStatusColNo = 0;
       
    65 TDbColNo RLogEventDbTable::iSubjectColNo = 0;
       
    66 TDbColNo RLogEventDbTable::iNumberColNo = 0;
       
    67 TDbColNo RLogEventDbTable::iContactColNo = 0;
       
    68 TDbColNo RLogEventDbTable::iLinkColNo = 0;
       
    69 TDbColNo RLogEventDbTable::iDataColNo = 0;
       
    70 TDbColNo RLogEventDbTable::iFlagColNo[] = {0, 0, 0, 0};
       
    71 TDbColNo RLogEventDbTable::iRecentColNo = 0;
       
    72 TDbColNo RLogEventDbTable::iDuplicateColNo = 0;
       
    73 #ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
       
    74 TDbColNo RLogEventDbTable::iSimIdColNo = 0;
       
    75 #endif
       
    76 
       
    77 /**
       
    78 RLogEventDbTable "resource acquisition" method.
       
    79 Opens the "Event" database table with the required access mode.
       
    80 If the database indexes are damaged, before the "table open" operation, an attempt will be made to recover the databasde.
       
    81 If the table is opened successfully, the current RLogEventDbTable object will be put on the cleanup stack. The caller is
       
    82 responsible for the destruction of the RLogEventDbTable object. 
       
    83 
       
    84 @param aDb RDbDatabase reference
       
    85 @param aAccess Table access mode, one of RDbRowSet::TAccess enum item values
       
    86 
       
    87 @leave  KErrNoMemory, an out of memory condition has occurred;
       
    88                       Note that the function may leave with database specific errors and
       
    89                       other system-wide error codes.
       
    90 */
       
    91 void RLogEventDbTable::OpenLC(RDbDatabase& aDb, RDbRowSet::TAccess aAccess)
       
    92     {
       
    93     RLogDbTable::OpenLC(aDb, KLogNameEventString, aAccess);
       
    94     InitializeColumnsL();
       
    95     }
       
    96 
       
    97 /**
       
    98 Initializes the static data members ("Event" table column numbers) of the RLogEventDbTable class.
       
    99 The initialization happens just once, during the construction of the first object of RLogEventDbTable type. 
       
   100 
       
   101 @leave  KErrNoMemory, an out of memory condition has occurred;
       
   102                       Note that the function may leave with database specific errors and
       
   103                       other system-wide error codes.
       
   104 */
       
   105 void RLogEventDbTable::InitializeColumnsL()
       
   106     {
       
   107     if(RLogEventDbTable::iIdColNo == 0)
       
   108         {
       
   109         CDbColSet* colset = ColSetL();
       
   110         RLogEventDbTable::iIdColNo = colset->ColNo(KLogFieldIdString);
       
   111         RLogEventDbTable::iTypeColNo = colset->ColNo(KLogFieldEventTypeString);
       
   112         RLogEventDbTable::iRemotePartyColNo = colset->ColNo(KLogFieldEventRemoteString);
       
   113         RLogEventDbTable::iDirectionColNo = colset->ColNo(KLogFieldEventDirectionString);
       
   114         RLogEventDbTable::iTimeColNo = colset->ColNo(KLogFieldEventTimeString);
       
   115         RLogEventDbTable::iDurationTypeColNo = colset->ColNo(KLogFieldEventDTypeString);
       
   116         RLogEventDbTable::iDurationColNo = colset->ColNo(KLogFieldEventDurationString);
       
   117         RLogEventDbTable::iStatusColNo = colset->ColNo(KLogFieldEventStatusString);
       
   118         RLogEventDbTable::iSubjectColNo = colset->ColNo(KLogFieldEventSubjectString);
       
   119         RLogEventDbTable::iNumberColNo = colset->ColNo(KLogFieldEventNumberString);
       
   120         RLogEventDbTable::iContactColNo = colset->ColNo(KLogFieldEventContactString);
       
   121         RLogEventDbTable::iLinkColNo = colset->ColNo(KLogFieldEventLinkString);
       
   122         RLogEventDbTable::iDataColNo = colset->ColNo(KLogFieldEventDataString);
       
   123         for(TInt i=0;i<KLogFlagsCount;++i)
       
   124             {
       
   125             TDbColName colname;
       
   126             colname.Format(KLogFieldEventFlagString, i + 1);
       
   127             RLogEventDbTable::iFlagColNo[i] = colset->ColNo(colname);
       
   128             __ASSERT_DEBUG(RLogEventDbTable::iFlagColNo[i] > 0, User::Invariant());
       
   129             }
       
   130         RLogEventDbTable::iRecentColNo = colset->ColNo(KLogFieldEventRecentString);
       
   131         RLogEventDbTable::iDuplicateColNo = colset->ColNo(KLogFieldEventDuplicateString);
       
   132 #ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
       
   133         RLogEventDbTable::iSimIdColNo = colset->ColNo(KLogFieldEventSimId);
       
   134 #endif        
       
   135         delete colset;
       
   136         }
       
   137 #ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
       
   138     __ASSERT_DEBUG(RLogEventDbTable::iIdColNo > 0 && 
       
   139             RLogEventDbTable::iTypeColNo > 0 &&
       
   140             RLogEventDbTable::iRemotePartyColNo > 0 &&
       
   141             RLogEventDbTable::iDirectionColNo > 0 &&
       
   142             RLogEventDbTable::iTimeColNo > 0 &&
       
   143             RLogEventDbTable::iDurationTypeColNo > 0 &&
       
   144             RLogEventDbTable::iDurationColNo > 0 &&
       
   145             RLogEventDbTable::iStatusColNo > 0 &&
       
   146             RLogEventDbTable::iSubjectColNo > 0 &&
       
   147             RLogEventDbTable::iNumberColNo > 0 &&
       
   148             RLogEventDbTable::iContactColNo > 0 &&
       
   149             RLogEventDbTable::iLinkColNo > 0 &&
       
   150             RLogEventDbTable::iDataColNo > 0 && 
       
   151             RLogEventDbTable::iRecentColNo > 0 &&
       
   152             RLogEventDbTable::iDuplicateColNo > 0 && 
       
   153             RLogEventDbTable::iSimIdColNo > 0, User::Invariant());
       
   154 #else
       
   155     __ASSERT_DEBUG(RLogEventDbTable::iIdColNo > 0 && 
       
   156             RLogEventDbTable::iTypeColNo > 0 &&
       
   157             RLogEventDbTable::iRemotePartyColNo > 0 &&
       
   158             RLogEventDbTable::iDirectionColNo > 0 &&
       
   159             RLogEventDbTable::iTimeColNo > 0 &&
       
   160             RLogEventDbTable::iDurationTypeColNo > 0 &&
       
   161             RLogEventDbTable::iDurationColNo > 0 &&
       
   162             RLogEventDbTable::iStatusColNo > 0 &&
       
   163             RLogEventDbTable::iSubjectColNo > 0 &&
       
   164             RLogEventDbTable::iNumberColNo > 0 &&
       
   165             RLogEventDbTable::iContactColNo > 0 &&
       
   166             RLogEventDbTable::iLinkColNo > 0 &&
       
   167             RLogEventDbTable::iDataColNo > 0 && 
       
   168             RLogEventDbTable::iRecentColNo > 0 &&
       
   169             RLogEventDbTable::iDuplicateColNo > 0, User::Invariant());
       
   170 #endif
       
   171     }
       
   172 
       
   173 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   174 /////////////////////////         RLogConfigDbTable             ///////////////////////////////////////////////////
       
   175 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   176 
       
   177 TDbColNo RLogConfigDbTable::iSizeColNo = 0;
       
   178 TDbColNo RLogConfigDbTable::iRecentColNo = 0;
       
   179 TDbColNo RLogConfigDbTable::iAgeColNo = 0;
       
   180 
       
   181 /**
       
   182 RLogConfigDbTable "resource acquisition" method.
       
   183 Opens the "Config" database table with the required access mode.
       
   184 If the database indexes are damaged, before the "table open" operation, an attempt will be made to recover the databasde.
       
   185 If the table is opened successfully, the current RLogConfigDbTable object will be put on the cleanup stack. The caller is
       
   186 responsible for the destruction of the RLogConfigDbTable object. 
       
   187 
       
   188 @param aDb RDbDatabase reference
       
   189 @param aAccess Table access mode, one of RDbRowSet::TAccess enum item values
       
   190 
       
   191 @leave  KErrNoMemory, an out of memory condition has occurred;
       
   192                       Note that the function may leave with database specific errors and
       
   193                       other system-wide error codes.
       
   194 */
       
   195 void RLogConfigDbTable::OpenLC(RDbDatabase& aDb, RDbRowSet::TAccess aAccess)
       
   196     {
       
   197     RLogDbTable::OpenLC(aDb, KLogNameConfigString, aAccess);
       
   198     InitializeColumnsL();
       
   199     }
       
   200 
       
   201 /**
       
   202 Initializes the static data members ("Config" table column numbers) of the RLogConfigDbTable class.
       
   203 The initialization happens just once, during the construction of the first object of RLogConfigDbTable type. 
       
   204 
       
   205 @leave  KErrNoMemory, an out of memory condition has occurred;
       
   206                       Note that the function may leave with database specific errors and
       
   207                       other system-wide error codes.
       
   208 */
       
   209 void RLogConfigDbTable::InitializeColumnsL()
       
   210     {
       
   211     if(RLogConfigDbTable::iSizeColNo == 0)
       
   212         {
       
   213         CDbColSet* colset = ColSetL();
       
   214         RLogConfigDbTable::iSizeColNo = colset->ColNo(KLogFieldConfigSizeString);
       
   215         RLogConfigDbTable::iRecentColNo = colset->ColNo(KLogFieldConfigRecentString);
       
   216         RLogConfigDbTable::iAgeColNo = colset->ColNo(KLogFieldConfigAgeString);
       
   217         delete colset;
       
   218         }
       
   219     __ASSERT_DEBUG(RLogConfigDbTable::iSizeColNo > 0 && 
       
   220             RLogConfigDbTable::iRecentColNo > 0 &&
       
   221             RLogConfigDbTable::iAgeColNo > 0, User::Invariant());
       
   222     }
       
   223 
       
   224 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   225 /////////////////////////         RLogDbView             //////////////////////////////////////////////////////////
       
   226 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   227 
       
   228 /**
       
   229 RLogDbView "resource acquisition" method.
       
   230 Prepares a database view with the passed as a parameter SQL and with the required access mode.
       
   231 If the database indexes are damaged, before the "prepare view" operation, an attempt will be made to recover the databasde.
       
   232 If the view is prepared successfully, the current RLogDbView object will be put on the cleanup stack and all records
       
   233 evaluated. The caller is responsible for the destruction of the RLogDbView object. 
       
   234 
       
   235 @param aDb RDbDatabase reference
       
   236 @param aQuery View SQL statement 
       
   237 @param aAccess View access mode, one of RDbRowSet::TAccess enum item values
       
   238 
       
   239 @leave  KErrNoMemory, an out of memory condition has occurred;
       
   240                       Note that the function may leave with database specific errors and
       
   241                       other system-wide error codes.
       
   242 */
       
   243 void RLogDbView::PrepareLC(RDbDatabase& aDb, const TDesC& aQuery, RDbRowSet::TAccess aAccess)
       
   244 	{
       
   245 	if(aDb.IsDamaged())
       
   246 		{
       
   247 		User::LeaveIfError(aDb.Recover());
       
   248 		}
       
   249 	__ASSERT_DEBUG(!aDb.IsDamaged(), Panic(ELogDatabaseDamaged2));
       
   250 	CleanupClosePushL(*this);
       
   251 	User::LeaveIfError(RDbView::Prepare(aDb, TDbQuery(aQuery, EDbCompareFolded), aAccess));
       
   252 	User::LeaveIfError(RDbView::EvaluateAll());
       
   253 	}
       
   254 
       
   255 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   256 /////////////////////////         Global functions             ////////////////////////////////////////////////////
       
   257 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   258 
       
   259 /**
       
   260 Runs the KLogSqlGetRecent SQL query and puts the IDs of the retrieved events into the aEventIds output array.
       
   261 This happens only if the retrieved events count is bigger than the aMaxRecentLogSize parameter. 
       
   262 
       
   263 @param aDb A MLogServDatabaseTransactionInterface reference
       
   264 @param aRecentListId Recent list Id
       
   265 @param aMaxRecentLogSize Max recent list size
       
   266 @param aEventIds Output parameter. The function will put it on the cleanup stack and fill it with
       
   267                  the events ids from the recent list. The caller is responsible for the destruction of
       
   268                  the aEventIds parameter.
       
   269 
       
   270 @leave  KErrNoMemory, an out of memory condition has occurred;
       
   271                Note that the function may leave with database specific errors and
       
   272                 other system-wide error codes.
       
   273 
       
   274 @internalComponent 
       
   275 */
       
   276 void LogGetRecentEventsLC(MLogServDatabaseTransactionInterface& aDb, TLogRecentList aRecentListId, 
       
   277                           TLogRecentSize aMaxRecentLogSize, RArray<TLogId>& aEventIds)
       
   278     {
       
   279     CleanupClosePushL(aEventIds);
       
   280     TheSql.Format(KLogSqlGetRecent, aRecentListId);
       
   281     RLogDbView view;                
       
   282     view.PrepareLC(aDb.DTIDatabase(), TheSql, RDbRowSet::EReadOnly);
       
   283     TInt count = view.CountL() - aMaxRecentLogSize;
       
   284     if(count > 0)
       
   285         {
       
   286         (void)view.LastL();//If "count > 0", then there is at least one record => LastL() cannot return EFalse. 
       
   287         static TDbColNo idColNo = 0;
       
   288         if(idColNo == 0)
       
   289             {
       
   290             CDbColSet* colset = view.ColSetL();
       
   291             idColNo = colset->ColNo(KLogFieldIdString);
       
   292             delete colset;
       
   293             }
       
   294         aEventIds.ReserveL(count);
       
   295         do
       
   296             {
       
   297             view.GetL();
       
   298             aEventIds.AppendL(view.ColInt32(idColNo));
       
   299             }
       
   300         while(--count && view.PreviousL());
       
   301         }
       
   302     CleanupStack::PopAndDestroy(&view);
       
   303     }
       
   304 
       
   305 /**
       
   306 The function accepts an array of event IDs as a parameter, prepares an UPDATE SQL query using those IDs and
       
   307 puts the constructed query into aSqlBuf output parameter.
       
   308  
       
   309 @param aEventIds Array with event Ids, used for the construction of the SQL statement
       
   310 @param aSqlBuf Output parameter. A reference to RLogDynBuf object where the SQL is constructed.
       
   311  
       
   312 @leave  KErrNoMemory, an out of memory condition has occurred;
       
   313  
       
   314 @internalComponent 
       
   315 */
       
   316 static void LogBuildPurgeRecentSqlL(const RArray<TLogId>& aEventIds, RLogDynBuf& aSqlBuf)
       
   317     {
       
   318     __ASSERT_DEBUG(aEventIds.Count() > 0, User::Invariant());
       
   319     aSqlBuf.SetLength(0);
       
   320     aSqlBuf.AppendL(KLogSqlRemoveDuplicateEvents);
       
   321     for(TInt i=0,count=aEventIds.Count();i<count;++i)
       
   322         {
       
   323         TBuf<20> num;//buf size of 20 is enough for a 32-bit number
       
   324         num.AppendNum(aEventIds[i]);
       
   325         aSqlBuf.AppendL(KIdEqStr);
       
   326         aSqlBuf.AppendL(num);
       
   327         aSqlBuf.AppendL(KLogOr);
       
   328         aSqlBuf.AppendL(KDuplicateEqStr);
       
   329         aSqlBuf.AppendL(num);
       
   330         aSqlBuf.AppendL(KLogOr);
       
   331         }
       
   332     aSqlBuf.SetLength(aSqlBuf.Length() - KLogOr().Length()); 
       
   333     }
       
   334 
       
   335 /**
       
   336 The function accepts an array of event IDs as a parameter, prepares an UPDATE SQL query and executes
       
   337 the query.
       
   338 The MLogServDatabaseChangeInterface interface will be used to collect the information about the IDs of the purged events.
       
   339 Later that information will be used if there are any outstanding notification requests waiting for completion.  
       
   340 If the count of the aEventIds elements is 0, then no query will be prepared and executed.
       
   341   
       
   342 @param aDb A reference to MLogServDatabaseTransactionInterface interface
       
   343 @param aEventIds Array with event Ids, used for the construction of the SQL statement
       
   344   
       
   345 @leave  KErrNoMemory, an out of memory condition has occurred;
       
   346                Note that the function may leave with database specific errors and
       
   347                 other system-wide error codes.
       
   348   
       
   349 @internalComponent 
       
   350 */
       
   351 void LogPurgeRecentEventsL(MLogServDatabaseTransactionInterface& aDb, const RArray<TLogId>& aEventIds)
       
   352     {
       
   353     TInt count = aEventIds.Count();
       
   354     if(count == 0)
       
   355         {
       
   356         return;
       
   357         }
       
   358     RLogDynBuf sqlBuf;
       
   359     sqlBuf.CreateLC(sizeof(KLogSqlRemoveDuplicateEvents) + count * 32);//32 - approx - length of "Duplicate=N OR Id=N"
       
   360     LogBuildPurgeRecentSqlL(aEventIds, sqlBuf);
       
   361     User::LeaveIfError(aDb.DTIExecuteSql(sqlBuf.DesC()));
       
   362     CleanupStack::PopAndDestroy(&sqlBuf);
       
   363     for(TInt i=0;i<count;++i)
       
   364         {
       
   365         // This is a "hidden" change. It may affect the contents of a view, but the actual event hasn't changed
       
   366         aDb.DTIChangeInterface().DCISubmitChangedEventContextL(ELogChangeTypeEventChangedHidden, aEventIds[i]);
       
   367         }
       
   368     }
       
   369 
       
   370 /**
       
   371 If the number of the events in the "Event" table is bigger than the aMaxLogSize parameter, 
       
   372 the oldest events will be deleted from the table.
       
   373 The MLogServDatabaseChangeInterface interface will be used to collect the information about the IDs of the deleted events.
       
   374 Later that information will be used if there are any outstanding notification requests waiting for completion.  
       
   375 If the number of the events in the "Event" table is less than the aMaxLogSize parameter, then the function does nothing. 
       
   376  
       
   377 @param aDb A reference to MLogServDatabaseTransactionInterface interface
       
   378 @param aTbl A reference to RLogEventDbTable object
       
   379 @param aMaxLogSize The max number of events allowed to exist in the "Event" table
       
   380 @param aCountPlus Integer, added to aMaxLogSize during the "max log size" calculations 
       
   381   
       
   382 @leave  KErrNoMemory, an out of memory condition has occurred;
       
   383                Note that the function may leave with database specific errors and
       
   384                 other system-wide error codes.
       
   385  
       
   386 @internalComponent 
       
   387 */
       
   388 void LogPurgeMainL(MLogServDatabaseTransactionInterface& aDb, RLogEventDbTable& aTbl, 
       
   389                    TLogSize aMaxLogSize, TInt aCountPlus)
       
   390     {
       
   391     User::LeaveIfError(aTbl.SetIndex(KLogNameEventIdx1));
       
   392     TInt count = aTbl.CountL() + aCountPlus - aMaxLogSize;
       
   393     if(count > 0)
       
   394         {
       
   395         (void)aTbl.FirstL();//If "count > 0", then there is at least one record => FirstL() cannot return EFalse. 
       
   396         TBool commit = !aDb.DTIInTransaction();
       
   397         if(commit)
       
   398             {
       
   399             aDb.DTIBeginWithRollBackProtectionLC();
       
   400             }
       
   401         do
       
   402             {
       
   403             aTbl.GetL(); 
       
   404             TLogId id = aTbl.ColInt32(RLogEventDbTable::iIdColNo);
       
   405             aTbl.DeleteL();
       
   406             aDb.DTIChangeInterface().DCISubmitChangedEventContextL(ELogChangeTypeEventDeleted, id);
       
   407             }
       
   408         while(--count && aTbl.NextL());
       
   409         if(commit)
       
   410             {
       
   411             aDb.DTICommitAndCancelRollbackProtectionL();
       
   412             }
       
   413         }
       
   414     }
       
   415 
       
   416 /**
       
   417 Updates the event records with "Duplicate" column value equal to aEventId. 
       
   418 The MLogServDatabaseChangeInterface interface will be used to collect the information about the IDs of the modified events.
       
   419 Later that information will be used if there are any outstanding notification requests waiting for completion.
       
   420 If no duplicates of the passed as a parameter event ID exist, then the function does nothing.  
       
   421  
       
   422 @param aDb A reference to MLogServDatabaseTransactionInterface interface
       
   423 @param aEventId Duplicated event id 
       
   424 
       
   425 @leave  KErrNoMemory, an out of memory condition has occurred;
       
   426                Note that the function may leave with database specific errors and
       
   427                 other system-wide error codes.
       
   428  
       
   429 @internalComponent 
       
   430 */
       
   431 void LogResetDuplicatesL(MLogServDatabaseTransactionInterface& aDb, TLogId aEventId)
       
   432     {
       
   433     TheSql.Format(KLogSqlDuplicateViewString, aEventId, &KNullDesC);
       
   434     RLogDbView view;
       
   435     view .PrepareLC(aDb.DTIDatabase(), TheSql);
       
   436     // Are there any duplicates?
       
   437     if(view.FirstL())
       
   438         {
       
   439         static TDbColNo idColNo = 0;
       
   440         static TDbColNo duplicateColNo = 0;
       
   441         if(idColNo == 0)
       
   442             {
       
   443             CDbColSet* colset = view.ColSetL();
       
   444             idColNo = colset->ColNo(KLogFieldIdString);
       
   445             duplicateColNo = colset->ColNo(KLogFieldEventDuplicateString);
       
   446             delete colset;
       
   447             }
       
   448         TBool commit = !aDb.DTIInTransaction();
       
   449         if(commit)
       
   450             {
       
   451             aDb.DTIBeginWithRollBackProtectionLC();
       
   452             }
       
   453         // Get the id of the latest event
       
   454         view.GetL();
       
   455         const TLogId idLatest = view.ColInt32(idColNo);
       
   456         // Mark the event as the latest duplicate
       
   457         view.UpdateL();
       
   458         view.SetColNullL(duplicateColNo);
       
   459         view.PutL();
       
   460         // This is a "hidden" change. It may affect the contents of a view, but the actual event hasn't changed
       
   461         aDb.DTIChangeInterface().DCISubmitChangedEventContextL(ELogChangeTypeEventChangedHidden, idLatest);
       
   462         // Reset the duplicate id's of the other duplicates
       
   463         while(view.NextL())
       
   464             {
       
   465             view.UpdateL();
       
   466             const TLogId id = view.ColInt32(idColNo);
       
   467             view.SetColL(duplicateColNo, idLatest);
       
   468             view.PutL();
       
   469             // This is a "hidden" change. It may affect the contents of a view, but the actual event hasn't changed
       
   470             aDb.DTIChangeInterface().DCISubmitChangedEventContextL(ELogChangeTypeEventChangedHidden, id);
       
   471             }
       
   472         if(commit)
       
   473             {
       
   474             aDb.DTICommitAndCancelRollbackProtectionL();
       
   475             }
       
   476         }
       
   477     CleanupStack::PopAndDestroy(&view);
       
   478     }