emailservices/emailstore/message_store/server/src/ContainerStoreSortingTable.cpp
changeset 0 8466d47a6819
child 8 e1b6206813b4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/emailservices/emailstore/message_store/server/src/ContainerStoreSortingTable.cpp	Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,1247 @@
+/*
+* Copyright (c) 2006 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:  Container store sorting table implementation.
+*
+*/
+
+
+
+#include "ContainerStoreSortingTable.h"
+#include "MsgStoreTypes.h"
+#include "MessageStoreClientServer.h"
+#include "ContainerStoreDefs.h"
+#include "MsgStoreSortResultRowSet.h"
+#include "MsgStoreStringSortResultRowSet.h"
+#include "ContainerStoreUtils.h"
+#include "ContainerStoreEncryption.h"
+#include "MsgStoreInMemorySortRowSet.h"
+	
+_LIT( KSelect,  "SELECT "   );
+_LIT( KDelete,  "DELETE "   );
+_LIT( KFrom,    " FROM "    );
+_LIT( KWhere,   " WHERE "   );
+_LIT( KEquals,  " = "       );
+_LIT( KOrderBy, " ORDER BY ");
+_LIT( KComma,   ", "        );
+_LIT( KAsc,     " ASC"      );
+_LIT( KDesc,    " DESC"     );
+_LIT( KStar,    "* "        );
+
+const TUint KQuerryBufSize = 200;
+const TUint KQuerrySizeSmall = 60;
+
+enum TMsgStorePriorityScore
+	{
+	EPriorityScoreLow    = -10,
+	EPriorityScoreNormal =   0,
+	EPriorityScoreHigh   =  10
+	};
+
+    enum TMsgStoreReadScore
+        {
+        EReadScoreUnread     = 0,
+        EReadScoreRead       = 1,
+        EReadScoreReadLocal  = 2,
+        EReadScoreReadBoth   = 3
+        };
+
+    enum TMsgStoreFlagStatusScore
+    	{
+    	EFlagStatusScoreNone             = 0,
+    	EFlagStatusScoreFollowUpComplete = 10,
+    	EFlagStatusScoreFollowUp         = 20 
+    	};
+
+    
+// ==================================
+// CLASS: CContainerStoreSortingTable
+// ==================================
+// ==========================================================================
+// FUNCTION: OpenL
+// ==========================================================================
+CContainerStoreSortingTable* CContainerStoreSortingTable::OpenL( CContainerStoreUtils&        aUtils,
+                                                                 CContainerStoreEncryption&   aEncryption,
+                                                                 MSortingTableObserver&       aObserver )
+	{
+	CContainerStoreSortingTable* self = new(ELeave) CContainerStoreSortingTable( aUtils, aEncryption, aObserver );
+	CleanupStack::PushL( self );
+	self->OpenTableL();
+	CleanupStack::Pop( self );
+	return self;
+	}
+		
+// ==========================================================================
+// FUNCTION: CreateL
+// ==========================================================================
+CContainerStoreSortingTable* CContainerStoreSortingTable::CreateL( CContainerStoreUtils&        aUtils,
+                                                                   CContainerStoreEncryption&   aEncryption,
+                                                                   MSortingTableObserver&       aObserver )
+	{
+	CContainerStoreSortingTable* self = new(ELeave) CContainerStoreSortingTable( aUtils, aEncryption, aObserver );
+	CleanupStack::PushL( self );
+	self->CreateTableL();
+	CleanupStack::Pop( self );
+	return self;
+	}
+
+// ==========================================================================
+// FUNCTION: Constructor
+// ==========================================================================
+CContainerStoreSortingTable::CContainerStoreSortingTable( CContainerStoreUtils&        aUtils,
+                                                          CContainerStoreEncryption&   aEncryption,
+                                                          MSortingTableObserver&       aObserver )
+: CContainerStoreTable( aUtils ), iEncryption( aEncryption ), iObserver( aObserver )
+	{
+	__LOG_CONSTRUCT( "msg", "CContainerStoreSortingTable" )
+	__LOG_CLOSE_BETWEEN_WRITES
+	} // end constructor
+		
+// ==========================================================================
+// FUNCTION: Destructor
+// ==========================================================================
+CContainerStoreSortingTable::~CContainerStoreSortingTable()
+	{
+	iUtils.CloseTable( iTable );
+    iEncryptedBuffer.Close();
+	__LOG_DESTRUCT	
+	} // end destructor
+
+// ==========================================================================
+// FUNCTION: OpenTableL
+// ==========================================================================
+void CContainerStoreSortingTable::OpenTableL()
+	{
+	__LOG_ENTER( "OpenTableL" )
+
+	iUtils.OpenTableL( iTable, KSortingTableName );
+	
+	// Get the column numbers for the containers table.
+	CDbColSet* colSet = iTable.ColSetL();
+	CleanupStack::PushL( colSet );
+
+    iMessageIdColNum      = colSet->ColNo( KSortingTableMessageIdCol );
+    iFolderIdColNum       = colSet->ColNo( KSortingTableFolderIdCol );
+    iMailBoxIdColNum      = colSet->ColNo( KSortingTableMailBoxIdCol );
+    iReceivedDateColNum   = colSet->ColNo( KSortingTableReceivedDateCol );
+    iReadUnreadColNum     = colSet->ColNo( KSortingTableReadUnreadCol );
+    iPriotiryColNum       = colSet->ColNo( KSortingTablePriorityCol );
+    iFlagStatusColNum     = colSet->ColNo( KSortingTableFlagStatusCol );
+    iSizeColNum           = colSet->ColNo( KSortingTableSizeCol );
+    iAttachmentFlagColNum = colSet->ColNo( KSortingTableAttachmentFlagCol );
+    iFromColNum           = colSet->ColNo( KSortingTableFromCol );
+    iToColNum             = colSet->ColNo( KSortingTableToCol );
+    iSubjectColNum        = colSet->ColNo( KSortingTableSubjectCol );
+    iIsEncryptedColNum    = colSet->ColNo( KSortingTableIsEncryptedCol );
+	
+	CleanupStack::PopAndDestroy( colSet );
+	
+	// Set the table's index to the ID index.
+	User::LeaveIfError( iTable.SetIndex( KSortingTableMessageIdIndex ) );
+
+	__LOG_EXIT	
+	}
+		
+// ==========================================================================
+// FUNCTION: CreateTableL
+// ==========================================================================
+void CContainerStoreSortingTable::CreateTableL()
+	{
+	__LOG_ENTER( "CreateTableL" )
+	
+	// Create table columns
+	CDbColSet* colSet = CDbColSet::NewLC();
+	
+	TDbCol msgIdCol( KSortingTableMessageIdCol, EDbColUint32 );
+	colSet->AddL( msgIdCol );	
+	
+	TDbCol folderIdCol( KSortingTableFolderIdCol, EDbColUint32 );
+	colSet->AddL( folderIdCol );	
+	
+	TDbCol mailboxIdCol( KSortingTableMailBoxIdCol, EDbColUint32 );
+	colSet->AddL( mailboxIdCol );	
+	
+	TDbCol receivedDateCol( KSortingTableReceivedDateCol, EDbColInt64 );
+	colSet->AddL( receivedDateCol );	
+		
+	TDbCol readUnreadCol( KSortingTableReadUnreadCol, EDbColInt8 );
+	colSet->AddL( readUnreadCol );	
+	
+	TDbCol priorityCol( KSortingTablePriorityCol, EDbColInt8 );
+	colSet->AddL( priorityCol );	
+	
+	TDbCol flagStatusCol( KSortingTableFlagStatusCol, EDbColInt8 );
+	colSet->AddL( flagStatusCol );	
+	
+	TDbCol sizeCol( KSortingTableSizeCol, EDbColUint32 );
+	colSet->AddL( sizeCol );	
+	
+	TDbCol attCol( KSortingTableAttachmentFlagCol, EDbColInt8 );
+	colSet->AddL( attCol );	
+    
+    TDbCol fromCol( KSortingTableFromCol, EDbColLongBinary );
+    colSet->AddL( fromCol );
+    
+    TDbCol toCol( KSortingTableToCol, EDbColLongBinary );
+    colSet->AddL( toCol );  
+	
+    TDbCol subjectCol( KSortingTableSubjectCol, EDbColLongBinary );
+    colSet->AddL( subjectCol );  
+    
+    TDbCol encryptedCol( KSortingTableIsEncryptedCol, EDbColUint8 );
+    colSet->AddL( encryptedCol );  
+    
+	// Create table.
+	iUtils.CreateTableL( KSortingTableName, *colSet );
+	
+	CleanupStack::PopAndDestroy( colSet );
+	
+	// Create index for every column except for mailBoxId
+	CreateIndexL( KSortingTableName, KSortingTableMessageIdIndex,      KSortingTableMessageIdCol    );
+	CreateIndexL( KSortingTableName, KSortingTableFolderIdIndex,       KSortingTableFolderIdCol     );
+    CreateIndexL( KSortingTableName, KSortingTableMailBoxIdIndex,      KSortingTableMailBoxIdCol    );
+	CreateIndexL( KSortingTableName, KSortingTableReceivedDateIndex,   KSortingTableReceivedDateCol );
+	CreateIndexL( KSortingTableName, KSortingTableReadUnreadIndex,     KSortingTableReadUnreadCol,     KSortingTableReceivedDateCol );
+	CreateIndexL( KSortingTableName, KSortingTablePriorityIndex,       KSortingTablePriorityCol,       KSortingTableReceivedDateCol );
+	CreateIndexL( KSortingTableName, KSortingTableFlagStatusIndex,     KSortingTableFlagStatusCol,     KSortingTableReceivedDateCol );
+	CreateIndexL( KSortingTableName, KSortingTableSizeIndex,           KSortingTableSizeCol,           KSortingTableReceivedDateCol );
+	CreateIndexL( KSortingTableName, KSortingTableAttachmentFlagIndex, KSortingTableAttachmentFlagCol, KSortingTableReceivedDateCol );
+	
+	OpenTableL();
+			
+	__LOG_EXIT
+	}
+
+// ==========================================================================
+// FUNCTION: AddMessageL
+// ==========================================================================
+void CContainerStoreSortingTable::AddMessageL( TContainerId             aMessageId, 
+											   TContainerId             aFolderId, 
+											   TContainerId             aMailboxId, 
+                                               RMsgStoreSortableFields& aSortableFields )
+	{
+	__LOG_ENTER_SUPPRESS( "AddMessageL" )
+	
+	__LOG_WRITE8_FORMAT3_DEBUG3( "msgId=%x, folderId=%x, mailBoxId=%x", aMessageId, aFolderId, aMailboxId )
+	
+	iTable.LastL();
+	
+	InsertRowLC();
+	 
+	iTable.SetColL( iMessageIdColNum,    aMessageId );
+	iTable.SetColL( iFolderIdColNum,     aFolderId );
+	iTable.SetColL( iMailBoxIdColNum,    aMailboxId );
+    iTable.SetColL( iIsEncryptedColNum, static_cast<TUint8>( iEncryption.IsEncryptionOn() ) );
+	
+	//write the rest of the fields
+	WriteFieldsL( aSortableFields );
+	
+	PutRowUpdatesL();
+    
+    //Notify the observer
+    iObserver.MessageUpdate( aMessageId, 
+    						 aFolderId, 
+    						 EMsgStoreAdd, 
+    						 iFieldsChanged, 
+                             aSortableFields.iFrom, 
+                             aSortableFields.iTo, 
+                             aSortableFields.iSubject, 
+                             aSortableFields.iReceivedDate );
+	}
+		
+// ==========================================================================
+// FUNCTION: DeleteMessageL
+// ==========================================================================
+void CContainerStoreSortingTable::DeleteMessageL( TContainerId aMessageId )
+	{
+	__LOG_ENTER_SUPPRESS( "DeleteMessageL" )
+	
+	__LOG_WRITE8_FORMAT1_DEBUG3( "msgId=%x", aMessageId )
+	
+    SeekL( aMessageId );
+    iTable.GetL();
+    TContainerId folderId = iTable.ColUint32( iFolderIdColNum );
+    
+    iTable.DeleteL();
+    
+    //Notify the observer
+    iObserver.MessageUpdate( aMessageId, folderId, EMsgStoreDelete );
+	}
+
+// ==========================================================================
+// FUNCTION: DeleteMessagesByFolderIdL
+// ==========================================================================
+void CContainerStoreSortingTable::DeleteMessagesByFolderIdL( TContainerId aFolderId )
+	{
+	__LOG_ENTER_SUPPRESS( "DeleteMessagesByFolderIdL" )
+	__LOG_WRITE8_FORMAT1_DEBUG3( "aFolderId=%x", aFolderId )
+	
+	TBuf<KQuerryBufSize> queryString;
+	queryString.Copy( KDelete );
+	queryString.Append( KFrom );
+	queryString.Append( KSortingTableName );
+	queryString.Append( KWhere );
+	queryString.Append( KSortingTableFolderIdCol );
+	queryString.Append( KEquals );
+	queryString.AppendNum( aFolderId );
+	
+	iUtils.Execute( queryString );
+    
+    //Notify the observer
+    iObserver.FolderDeleted( aFolderId );
+	}
+
+// ==========================================================================
+// FUNCTION: DeleteMessagesByMailBoxIdL
+// ==========================================================================
+void CContainerStoreSortingTable::DeleteMessagesByMailBoxIdL( TContainerId aMailBoxId )
+    {
+    __LOG_ENTER_SUPPRESS( "DeleteMessagesByMailBoxIdL" )
+    __LOG_WRITE8_FORMAT1_DEBUG3( "aMailBoxId=%x", aMailBoxId )
+    
+    TBuf<KQuerryBufSize> queryString;
+    queryString.Copy( KDelete );
+    queryString.Append( KFrom );
+    queryString.Append( KSortingTableName );
+    queryString.Append( KWhere );
+    queryString.Append( KSortingTableMailBoxIdCol );
+    queryString.Append( KEquals );
+    queryString.AppendNum( aMailBoxId );
+    
+    iUtils.Execute( queryString );
+    
+    //Notify the observer
+    iObserver.MailBoxDeleted( aMailBoxId );
+    }
+
+// ==========================================================================
+// FUNCTION: UpdateMessageL
+// ==========================================================================
+void CContainerStoreSortingTable::UpdateMessageL( TContainerId aMessageId, 
+                                                  RMsgStoreSortableFields& aSortableFields )
+	{
+	__LOG_ENTER_SUPPRESS( "UpdateMessageL" )
+	
+	__LOG_WRITE8_FORMAT4_DEBUG3( "msgId=%x, flags=%x, ssize=%d csize=%d", aMessageId, 
+                                                                aSortableFields.iFlags, 
+                                                                aSortableFields.iSizeOnServer,
+                                                                aSortableFields.iSizeOnClient )
+	
+	SeekL( aMessageId );
+    
+    iTable.GetL();
+    TContainerId folderId = iTable.ColUint32( iFolderIdColNum );
+	
+	PrepareRowForUpdateLC();
+	
+	WriteFieldsL( aSortableFields, EFalse );
+	
+	PutRowUpdatesL();
+    
+    if ( iFieldsChanged > 0 )
+        {
+        iObserver.MessageUpdate( aMessageId, 
+        						 folderId, 
+        						 EMsgStoreUpdateProperties, 
+        						 iFieldsChanged,
+                                 aSortableFields.iFrom, 
+                                 aSortableFields.iTo, 
+                                 aSortableFields.iSubject, 
+                                 aSortableFields.iReceivedDate );
+        }
+	}
+
+// ==========================================================================
+// FUNCTION: UpdateMessageFolderL
+// ==========================================================================
+void CContainerStoreSortingTable::UpdateMessageFolderL( TContainerId aMessageId, TContainerId aNewFolderId )
+	{
+	__LOG_ENTER_SUPPRESS( "UpdateMessageFolderL" )
+	
+	__LOG_WRITE8_FORMAT2_DEBUG3( "msgId=%x, aNewFolder=%x", aMessageId, aNewFolderId )
+    
+	SeekL( aMessageId );
+    iTable.GetL();
+    
+    TContainerId oldFolderId = iTable.ColUint32( iFolderIdColNum );
+    
+    if ( oldFolderId != aNewFolderId )
+        {
+    	
+    	PrepareRowForUpdateLC();
+    	
+    	iTable.SetColL( iFolderIdColNum, aNewFolderId );
+    	
+    	PutRowUpdatesL();
+        
+        //send a notification for delete from old folder 
+        iObserver.MessageUpdate( aMessageId, oldFolderId, EMsgStoreDelete );
+        
+        //send a notification for new message to the new folder
+        RBuf from;
+        CleanupClosePushL( from );
+        ReadStringFieldL( iTable, iFromColNum, from );
+        
+        RBuf to;
+        CleanupClosePushL( to );
+        ReadStringFieldL( iTable, iToColNum, to );
+        
+        RBuf subject;
+        CleanupClosePushL( subject );
+        ReadStringFieldL( iTable, iSubjectColNum, subject );
+        
+        TInt64 date = iTable.ColInt64( iReceivedDateColNum );
+        
+        iObserver.MessageUpdate( aMessageId, aNewFolderId, EMsgStoreAdd, 0, from, to, subject, date );
+        
+        CleanupStack::PopAndDestroy( &subject );
+        CleanupStack::PopAndDestroy( &to );
+        CleanupStack::PopAndDestroy( &from );
+        
+        }    
+	}
+		
+// ==========================================================================
+// FUNCTION: SortL
+// ==========================================================================
+CMsgStoreSortResultRowSet* CContainerStoreSortingTable::SortL( const TMsgStoreSortCriteria& aSortCriteria,  TBool aInMemorySort  )
+	{
+	__LOG_ENTER_SUPPRESS( "SortL" )
+    
+	CMsgStoreSortResultRowSet* result = NULL;
+    
+    if ( aSortCriteria.iSortBy == EMsgStoreSortBySender ||
+         aSortCriteria.iSortBy == EMsgStoreSortByRecipient     ||   
+         aSortCriteria.iSortBy == EMsgStoreSortBySubject )
+        {
+        result = SortByStringFieldL( aSortCriteria );
+        }
+    else if ( aInMemorySort )
+    	{
+    	result = InMemorySortL( aSortCriteria );
+    	}
+    else
+        {
+
+    	TBuf<KQuerryBufSize> queryString;
+    	queryString.Copy( KSelect );
+        queryString.Append( KStar );
+    	queryString.Append( KFrom );
+    	queryString.Append( KSortingTableName );
+    	queryString.Append( KWhere );
+    	queryString.Append( KSortingTableFolderIdCol );
+    	queryString.Append( KEquals );
+    	queryString.AppendNum( aSortCriteria.iFolderId );
+    	queryString.Append( KOrderBy );
+    	
+    	switch( aSortCriteria.iSortBy )
+    		{
+    		case EMsgStoreSortByReceivedDate:
+    			queryString.Append( KSortingTableReceivedDateCol );
+    			break;
+    		
+    		case EMsgStoreSortByPriority:
+    			queryString.Append( KSortingTablePriorityCol );
+    			break;
+    			
+    		case EMsgStoreSortByFlagStatus:
+    			queryString.Append( KSortingTableFlagStatusCol );
+    			break;
+    		
+    		case EMsgStoreSortByUnRead:
+    			queryString.Append( KSortingTableReadUnreadCol );
+    			break;
+    		
+    		case EMsgStoreSortBySize:
+    			queryString.Append( KSortingTableSizeCol );
+    			break;
+    		
+    		case EMsgStoreSortByAttachment:
+    			queryString.Append( KSortingTableAttachmentFlagCol );
+    			break;
+    		
+    		default:
+    			User::Leave( KErrNotSupported );
+    			break;
+    		}
+    	
+    	//add the sort order
+    	AppendSortOrder( queryString, aSortCriteria.iSortOrder );
+    	
+    	//add the secondary sort field if primary is not received date
+    	if ( aSortCriteria.iSortBy != EMsgStoreSortByReceivedDate )
+    		{
+    		queryString.Append( KComma );
+    		queryString.Append( KSortingTableReceivedDateCol );
+    		AppendSortOrder( queryString, aSortCriteria.iSecondarySortOrder );
+    		}
+    	
+    	__LOG_WRITE_FORMAT1_INFO( "query=%S", &queryString );
+    
+    	result = CMsgStoreSortResultRowSet::NewL( aSortCriteria, 
+    	                                          iMessageIdColNum,
+    	                                          iReceivedDateColNum,
+    	                                          iReadUnreadColNum,
+    	                                          iPriotiryColNum,
+    	                                          iFlagStatusColNum,
+    	                                          iSizeColNum,
+    	                                          iAttachmentFlagColNum );
+    	CleanupStack::PushL( result );
+    	
+        iUtils.PopulateViewL( result->DbView(), queryString );
+        
+        __LOG_WRITE_FORMAT1_INFO( "rowCounts=%d", result->DbView().CountL() );
+        
+        CleanupStack::Pop( result );
+        }
+    
+        return result;
+	}
+
+
+// ==========================================================================
+// FUNCTION: SortByStringFieldL
+// ==========================================================================
+CMsgStoreStringSortResultRowSet* CContainerStoreSortingTable::SortByStringFieldL( const TMsgStoreSortCriteria& aSortCriteria  )
+    {
+    __LOG_ENTER_SUPPRESS( "SortByStringFieldL" )
+    
+    CMsgStoreStringSortResultRowSet* result = CMsgStoreStringSortResultRowSet::NewL( aSortCriteria, *this );
+    CleanupStack::PushL( result );
+    TBuf<KQuerryBufSize> queryString;
+    queryString.Copy( KSelect );
+    queryString.Append( KStar );
+    queryString.Append( KFrom );
+    queryString.Append( KSortingTableName );
+    queryString.Append( KWhere );
+    queryString.Append( KSortingTableFolderIdCol );
+    queryString.Append( KEquals );
+    queryString.AppendNum( aSortCriteria.iFolderId );
+
+    iUtils.PopulateViewL( result->DbView(), queryString );
+    
+    ReEvaluateStringViewL( *result, aSortCriteria.iSortBy );
+
+    result->SortL();
+    
+    CleanupStack::Pop( result );
+    
+    return result;
+    }
+
+// ==========================================================================
+// FUNCTION: InMemorySortL
+// ==========================================================================
+CMsgStoreInMemorySortRowSet* CContainerStoreSortingTable::InMemorySortL( const TMsgStoreSortCriteria& aSortCriteria  )
+    {
+    __LOG_ENTER_SUPPRESS( "InMemorySortL" )
+    
+    CMsgStoreInMemorySortRowSet* result = CMsgStoreInMemorySortRowSet::NewL( aSortCriteria, *this );
+    CleanupStack::PushL( result );
+    
+    TBuf<KQuerryBufSize> queryString;
+    queryString.Copy( KSelect );
+    queryString.Append( KStar );
+    queryString.Append( KFrom );
+    queryString.Append( KSortingTableName );
+    queryString.Append( KWhere );
+    queryString.Append( KSortingTableFolderIdCol );
+    queryString.Append( KEquals );
+    queryString.AppendNum( aSortCriteria.iFolderId );
+
+    iUtils.PopulateViewL( result->DbView(), queryString );
+    
+    ReEvaluateInMemoryViewL( *result, aSortCriteria.iSortBy );
+
+    result->SortL();
+    
+    CleanupStack::Pop( result );
+    
+    return result;
+    }
+
+
+// ==========================================================================
+// FUNCTION: ReEvaluateStringViewL
+// ==========================================================================
+void CContainerStoreSortingTable::ReEvaluateStringViewL( CMsgStoreStringSortResultRowSet& aResult, TMsgStoreSortByField aSortBy )
+    {
+    __LOG_ENTER( "ReEvaluateStringViewL" )
+    
+    iUtils.SuspendCompactionLC();
+    
+    TInt stringColNum = GetColumnNumL( aSortBy );
+    
+    RDbView& view = aResult.DbView();
+    
+    TBool found = view.FirstL();
+    
+    CStringRow* reuseRow = NULL;
+    
+    RBuf stringVal;
+    CleanupClosePushL( stringVal );
+    
+    while( found )
+        {
+        view.GetL();
+        
+        //get the message id, received date, and the desired string
+        TContainerId msgId = view.ColUint32( iMessageIdColNum );  
+        TInt64 receivedDate = view.ColInt64( iReceivedDateColNum );
+        
+        ReadStringFieldL( view, stringColNum, stringVal );
+        
+        //To reduce memory fragmentation, we re-use the row object whenever possible
+        CStringRow* row;
+        if ( reuseRow  )
+            {
+            row = reuseRow;
+            row->ResetL( msgId, receivedDate, stringVal );
+            CleanupStack::Pop( reuseRow );
+            }
+        else
+            {
+            row = CStringRow::NewL( msgId, receivedDate, stringVal );
+            }
+        
+        reuseRow = aResult.AppendL( row );
+        
+        if ( reuseRow )
+            {
+            CleanupStack::PushL( reuseRow );
+            }
+        
+        found = view.NextL();
+        
+        if ( !found && reuseRow )
+            {
+            //no more rows, delete the reuseRow
+            CleanupStack::PopAndDestroy( reuseRow );
+            }
+            
+        } // end while
+    
+    CleanupStack::PopAndDestroy( &stringVal );
+    
+    iUtils.ResumeCompaction();
+    
+    __LOG_EXIT
+    }
+
+// ==========================================================================
+// FUNCTION: ReEvaluateInMemoryViewL
+// ==========================================================================
+void CContainerStoreSortingTable::ReEvaluateInMemoryViewL( CMsgStoreInMemorySortRowSet& aResult, TMsgStoreSortByField aSortBy )
+    {
+    __LOG_ENTER( "ReEvaluateInMemoryViewL" )
+    
+    iUtils.SuspendCompactionLC();
+    
+    RDbView& view = aResult.DbView();
+    TBool found = view.FirstL();
+    
+    while( found )
+        {
+        view.GetL();
+        
+        //get the message id, received date, and the desired string
+        TContainerId msgId = view.ColUint32( iMessageIdColNum );  
+        TInt64 receivedDate = view.ColInt64( iReceivedDateColNum );
+
+        TInt32 value = GetIntValue( view, aSortBy );
+        
+        CIntegerRow* row = new(ELeave) CIntegerRow( msgId, receivedDate, value );
+        CleanupStack::PushL( row );
+        
+        aResult.AppendL( row );
+        
+        CleanupStack::Pop( row );
+        
+        found = view.NextL();            
+        } // end while
+   
+    iUtils.ResumeCompaction();
+    
+    __LOG_EXIT
+    }
+
+
+// ==========================================================================
+// FUNCTION: GetStringRowL
+// ==========================================================================
+CStringRow* CContainerStoreSortingTable::GetStringRowL( RDbView& aView, TContainerId aMessageId, TMsgStoreSortByField aSortBy )
+    {
+
+    TBuf<KQuerrySizeSmall> queryString;
+    
+    queryString.Copy( KSortingTableMessageIdCol );
+    queryString.Append( KEquals );
+    queryString.AppendNum( aMessageId );
+    
+    User::LeaveIfError( aView.FindL( RDbRowSet::EForwards, queryString ) );
+    
+    TInt stringColNum = GetColumnNumL( aSortBy ) ;
+    
+    aView.GetL();
+    
+    //get the message id, received date, and the desired string
+    TContainerId msgId = aView.ColUint32( iMessageIdColNum );  
+    TInt64 receivedDate = aView.ColInt64( iReceivedDateColNum );
+    
+    RBuf stringVal;
+    CleanupClosePushL( stringVal );
+    
+    ReadStringFieldL( aView, stringColNum, stringVal );
+    
+    CStringRow* row = CStringRow::NewL( msgId, receivedDate, stringVal );
+    
+    CleanupStack::PopAndDestroy( &stringVal );
+    
+    return row;
+    }
+
+// ==========================================================================
+// FUNCTION: GetIntValue
+// ==========================================================================
+TInt32 CContainerStoreSortingTable::GetIntValue( RDbRowSet& aRowSet, TMsgStoreSortByField aSortBy )
+	{
+	TInt32 value = 0;
+	if ( aSortBy !=  EMsgStoreSortByReceivedDate )
+		{
+		switch( aSortBy )
+			{
+			case EMsgStoreSortByPriority:
+			    value = aRowSet.ColInt8( iPriotiryColNum );
+				break;
+				
+			case EMsgStoreSortByFlagStatus:
+			    value = aRowSet.ColInt8( iFlagStatusColNum );
+				break;
+			
+			case EMsgStoreSortByUnRead:
+				value = aRowSet.ColInt8( iReadUnreadColNum );
+				break;
+			
+			case EMsgStoreSortBySize:
+				value = static_cast<TInt32>(aRowSet.ColUint32 ( iSizeColNum ));
+				break;
+			
+			case EMsgStoreSortByAttachment:
+				value = aRowSet.ColInt8( iAttachmentFlagColNum );
+				break;
+			
+			default:
+				break;
+			}
+		}
+	return value;
+	}
+
+// ==========================================================================
+// FUNCTION: GetIntValueL
+// ==========================================================================
+TInt32 CContainerStoreSortingTable::GetIntValueL( TMsgStoreSortByField aSortBy, TContainerId aMessageId )
+	{
+    TBuf<KQuerrySizeSmall> queryString;
+    
+    queryString.Copy( KSortingTableMessageIdCol );
+    queryString.Append( KEquals );
+    queryString.AppendNum( aMessageId );
+    
+    User::LeaveIfError( iTable.FindL( RDbRowSet::EForwards, queryString ) );
+    
+    iTable.GetL();
+    
+    return GetIntValue( iTable, aSortBy );	
+	}
+
+// ==========================================================================
+// FUNCTION: SeekL
+// ==========================================================================
+void CContainerStoreSortingTable::SeekL( TContainerId aMessageId )
+    {
+    __LOG_ENTER_SUPPRESS("SeekL")
+    if ( !iTable.SeekL( aMessageId ) )
+        {
+        __LOG_WRITE8_FORMAT1_ERROR( "Message id %x not found", aMessageId )
+        User::Leave( KErrNotFound );
+        }
+    }
+
+// ==========================================================================
+// FUNCTION: WriteFieldsL
+// ==========================================================================
+void CContainerStoreSortingTable::WriteFieldsL( RMsgStoreSortableFields& aSortableFields, TBool aIsNew )
+	{
+    
+    iFieldsChanged = 0;
+    
+    SetFlagIfChangedInt64( aSortableFields.iReceivedDate, iReceivedDateColNum, aIsNew, EMaskReceivedDate );
+	iTable.SetColL( iReceivedDateColNum, aSortableFields.iReceivedDate );
+	
+    /******************************
+	* process the read/unread flag
+    *******************************/
+    TUint flags = aSortableFields.iFlags;
+    
+	TInt8 readFlag = EReadScoreUnread; 
+	if ( (flags & EMsgStoreFlag_Read) && (flags & EMsgStoreFlag_Read_Locally) ) 
+	    {
+	    readFlag = EReadScoreReadBoth;
+	    }
+	else if ( flags & EMsgStoreFlag_Read )
+	    {
+        readFlag = EReadScoreRead;
+	    }
+	else if ( flags & EMsgStoreFlag_Read_Locally )
+	    {
+        readFlag = EReadScoreReadLocal;
+	    }
+	
+    SetFlagIfChangedInt8( readFlag, iReadUnreadColNum, aIsNew, EMaskReadUnread );
+    
+    //set the new value
+	iTable.SetColL( iReadUnreadColNum, readFlag );
+    
+    /******************************
+    * process the priority flag
+    *******************************/
+	TInt8 priority = EPriorityScoreNormal;
+	if ( flags & EMsgStoreFlag_Important )
+		{
+		priority = EPriorityScoreHigh;
+		}
+	else if ( flags & EMsgStoreFlag_Low )
+		{
+		priority = EPriorityScoreLow;
+		}
+    SetFlagIfChangedInt8( priority, iPriotiryColNum, aIsNew, EMaskPriotiry );
+	iTable.SetColL( iPriotiryColNum, priority );
+	
+    /******************************
+     * process the follow up flag
+     *******************************/
+	TInt8 flagStatus = EFlagStatusScoreNone;
+	if ( flags & EMsgStoreFlag_FollowUp )
+		{
+		flagStatus = EFlagStatusScoreFollowUp;
+		}
+	else if ( flags &  EMsgStoreFlag_FollowUpComplete )
+		{
+		flagStatus = EFlagStatusScoreFollowUpComplete;
+		}
+    SetFlagIfChangedInt8( flagStatus, iFlagStatusColNum, aIsNew, EMaskFlagStatus );
+	iTable.SetColL( iFlagStatusColNum, flagStatus );
+    
+    //process the attachment flag
+    TInt8 attachmentFalg = static_cast<TInt8>(flags & EMsgStoreFlag_Attachments);
+    SetFlagIfChangedInt8( attachmentFalg, iAttachmentFlagColNum, aIsNew, EMaskAttachmentFlag );
+	iTable.SetColL( iAttachmentFlagColNum, attachmentFalg );
+	
+    //if size on server is available, use it, otherwise, use the size on client
+    TUint size = aSortableFields.iSizeOnServer > 0 ? aSortableFields.iSizeOnServer : aSortableFields.iSizeOnClient;
+    SetFlagIfChangedUint( size, iSizeColNum, aIsNew, EMaskSize );
+	iTable.SetColL( iSizeColNum, size );
+    
+    //write the subject
+    WriteStringFieldL( iSubjectColNum, aSortableFields.iSubject, aIsNew, EMaskSubject );
+    
+    //write the from
+    WriteStringFieldL( iFromColNum, aSortableFields.iFrom, aIsNew, EMaskFrom );
+    
+    //write the to field
+    WriteStringFieldL( iToColNum, aSortableFields.iTo, aIsNew, EMaskTo );
+	}
+
+// ==========================================================================
+// FUNCTION: AppendSortOrder
+// ==========================================================================
+void CContainerStoreSortingTable::AppendSortOrder( TDes& aQuery, TMsgStoreSortOrder aOrder )
+	{
+	if ( aOrder == EMsgStoreSortDescending )
+		{
+		aQuery.Append( KDesc );
+		}
+	else
+		{
+		aQuery.Append( KAsc );
+		}
+	}
+
+// ==========================================================================
+// FUNCTION: WriteStringFieldL
+// ==========================================================================
+void CContainerStoreSortingTable::WriteStringFieldL( TInt                 aColumnNum, 
+                                                     const TDesC&         aString, 
+                                                     TBool                aIsNew, 
+                                                     TSortableFieldsMasks aMask )
+    {
+    __LOG_ENTER_SUPPRESS( "WriteStringFieldL" )
+    __LOG_WRITE_FORMAT2_DEBUG3( "col=%d, string=%S", aColumnNum, &aString )
+    
+    TBool changed = ETrue;
+    
+    if ( !aIsNew )
+        {
+        RBuf curVal;
+        CleanupClosePushL( curVal );
+        ReadStringFieldL( iTable, aColumnNum, curVal );
+        if ( curVal == aString )
+            {
+            changed = EFalse;
+            }
+        CleanupStack::PopAndDestroy( &curVal );
+        }
+        
+    if ( changed )
+        {
+        iFieldsChanged |= aMask;
+        }
+    
+    if ( aString.Length() == 0 )
+        {
+        iTable.SetColNullL( aColumnNum );
+        }
+    else if ( changed )
+        {
+        WriteStringL( aColumnNum, aString, IsEncrypted( iTable ) );
+        }  //end if
+    }
+
+// ==========================================================================
+// FUNCTION: WriteStringL
+// ==========================================================================
+void CContainerStoreSortingTable::WriteStringL( TInt         aColumnNum, 
+                                                const TDesC& aString, 
+                                                TBool        aIsRowEncrypted )
+    {
+    
+    const TUint8* valuePtr8 = reinterpret_cast<const TUint8*>( aString.Ptr() );
+    TPtrC8 string8;
+    string8.Set( valuePtr8, aString.Length() * 2 );
+    
+    if ( aIsRowEncrypted && string8.Length() > 0 )
+        {
+        RBuf8 encryptedBuffer;
+        encryptedBuffer.CreateL( string8.Length() + iEncryption.BlockSizeL() );
+        CleanupClosePushL( encryptedBuffer );
+        
+        RBuf8 paddedBuffer;
+        paddedBuffer.CreateL( string8.Length() + iEncryption.BlockSizeL() );       
+        CleanupClosePushL( paddedBuffer );
+        
+        paddedBuffer.Copy( string8 );
+        iEncryption.AddPaddingL( paddedBuffer, iEncryption.BlockSizeL() );
+        
+        iEncryption.EncryptL( paddedBuffer, encryptedBuffer );
+        
+        CleanupStack::PopAndDestroy( &paddedBuffer );
+        
+        iUtils.WriteLongColumnL( iTable, aColumnNum, encryptedBuffer );
+        
+        CleanupStack::PopAndDestroy( &encryptedBuffer );
+        }
+    else
+        {
+        iUtils.WriteLongColumnL( iTable, aColumnNum, string8 );
+        }
+    
+    }
+
+
+// ==========================================================================
+// FUNCTION: ReadStringFieldL
+// ==========================================================================
+void CContainerStoreSortingTable::ReadStringFieldL( RDbRowSet& aView, TInt aColumnNum, RBuf& aString )
+    {
+    __LOG_ENTER_SUPPRESS( "ReadStringFieldL" )
+    
+    aString.SetLength( 0 );
+    
+    iUtils.ReadLongColumnL( aView, aColumnNum, iEncryptedBuffer );
+    
+    RBuf8 string8;
+    CleanupClosePushL( string8 );
+    string8.Create( iEncryptedBuffer.Length() );
+    
+    if( aString.Size() < iEncryptedBuffer.Length() )
+        {        
+        aString.ReAllocL( iEncryptedBuffer.Length() );
+        } // end if
+    
+    if ( IsEncrypted( aView ) )
+        {
+        if( iEncryptedBuffer.Length() > 0 )
+            {        
+            iEncryption.DecryptL( iEncryptedBuffer, string8 );        
+            iEncryption.RemovePaddingL( string8 );
+            } // end if
+        }
+    else
+        {
+        string8.Copy( iEncryptedBuffer );
+        }
+    
+    const TUint16* valuePtr16 = reinterpret_cast<const TUint16*>( string8.Ptr() );
+    TPtrC16 string16;
+    string16.Set( valuePtr16, string8.Length() / 2 );
+    aString.Copy( string16 );
+    
+    CleanupStack::PopAndDestroy( &string8 );
+    
+    __LOG_WRITE_FORMAT2_DEBUG3( "col=%d, string=%S", aColumnNum, &aString )
+    }
+
+
+// ==========================================================================
+// FUNCTION: EncryptFirstL
+// ==========================================================================
+TBool CContainerStoreSortingTable::EncryptFirstL( TDbBookmark& aNextRow )
+    {
+    __LOG_ENTER( "EncryptFirstL" )
+    
+    TBool found = iUtils.FindFirstEncryptedOrUnencryptedL( iTable, KSortingTableIsEncryptedCol, EFalse, aNextRow );
+    
+    __LOG_EXIT
+    
+    return found;
+    }
+
+// ==========================================================================
+// FUNCTION: EncryptNextL
+// ==========================================================================
+TBool CContainerStoreSortingTable::EncryptNextL( TDbBookmark& aNextRow )
+    {
+    __LOG_ENTER( "EncryptNextL" )
+    
+    TBool hasMore = EFalse;
+    
+    TRAPD( err, iTable.GotoL( aNextRow ) );
+    if ( err == KErrNotFound )
+        {
+        hasMore = EncryptFirstL( aNextRow );
+        }
+    else if ( err != KErrNone )
+        {
+        User::Leave( err );        
+        }
+    else
+        {
+        iTable.GetL();
+        if ( !IsEncrypted( iTable ) )
+            {
+            RBuf string;
+            CleanupClosePushL( string );
+            
+            PrepareRowForUpdateLC();
+            
+            //process the from field
+            ReadStringFieldL( iTable, iFromColNum, string );
+            WriteStringL( iFromColNum, string, ETrue );  //encrypt before write
+            
+            //process the to field
+            ReadStringFieldL( iTable, iToColNum, string );
+            WriteStringL( iToColNum, string, ETrue );    //encrypt before write
+            
+            //process the subject field
+            ReadStringFieldL( iTable, iSubjectColNum, string );
+            WriteStringL( iSubjectColNum, string, ETrue );  //encrypt before write
+            
+            //update the isEncrypted column
+            SetEncryptedL( ETrue );
+            
+            PutRowUpdatesL();
+            
+            CleanupStack::PopAndDestroy( &string );
+            }
+        
+        hasMore = iTable.NextL();
+        if ( hasMore )
+            {
+            __LOG_WRITE_INFO("hasMore is TRUE")
+            aNextRow = iTable.Bookmark();
+            }
+        }
+
+    __LOG_EXIT
+    
+    return hasMore;
+    }
+
+// ==========================================================================
+// FUNCTION: DecryptFirstL
+// ==========================================================================
+TBool CContainerStoreSortingTable::DecryptFirstL( TDbBookmark& aNextRow )
+    {
+    __LOG_ENTER( "DecryptFirstL" )
+    
+    TBool found = iUtils.FindFirstEncryptedOrUnencryptedL( iTable, KSortingTableIsEncryptedCol, ETrue, aNextRow );
+    
+    __LOG_EXIT
+    
+    return found;
+    }
+
+// ==========================================================================
+// FUNCTION: DecryptNextL
+// ==========================================================================
+TBool CContainerStoreSortingTable::DecryptNextL( TDbBookmark& aNextRow )
+    {
+    __LOG_ENTER( "DecryptNextL" )
+    
+    TBool hasMore = EFalse;
+    
+    TRAPD( err, iTable.GotoL( aNextRow ) );
+    if ( err == KErrNotFound )
+        {
+        hasMore = DecryptFirstL( aNextRow );
+        }
+    else if ( err != KErrNone )
+        {
+        User::Leave( err );        
+        }
+    else
+        {
+        iTable.GetL();
+        if ( IsEncrypted( iTable ) )
+            {
+            RBuf string;
+            CleanupClosePushL( string );
+            
+            PrepareRowForUpdateLC();
+            
+            //process the from field
+            ReadStringFieldL( iTable, iFromColNum, string );
+            WriteStringL( iFromColNum, string, EFalse );  //do not encrypt
+            
+            //process the to field
+            ReadStringFieldL( iTable, iToColNum, string );
+            WriteStringL( iToColNum, string, EFalse );  //do not encrypt
+            
+            //process the subject field
+            ReadStringFieldL( iTable, iSubjectColNum, string );
+            WriteStringL( iSubjectColNum, string, EFalse );  //do not encrypt
+            
+            //update the isEncrypted column
+            SetEncryptedL( EFalse );
+            
+            PutRowUpdatesL();
+            
+            CleanupStack::PopAndDestroy( &string );
+            }
+        
+        hasMore = iTable.NextL();
+        if ( hasMore )
+            {
+            __LOG_WRITE_INFO("hasMore is TRUE")
+            aNextRow = iTable.Bookmark();
+            }
+        }
+
+    __LOG_EXIT
+    
+    return hasMore;
+    }
+
+// ==========================================================================
+// FUNCTION: SetFlagIfChangedInt8
+// ==========================================================================
+void CContainerStoreSortingTable::SetFlagIfChangedInt8( TInt8 newVal, TInt aColNum, TBool aIsNew, TSortableFieldsMasks aMask )
+    {
+    TInt8 curVal = newVal;
+    if ( !aIsNew )
+        {
+        curVal = iTable.ColInt8( aColNum );
+        }
+    
+    if ( aIsNew || curVal != newVal )
+        {
+        iFieldsChanged |= aMask;
+        }
+    }
+
+// ==========================================================================
+// FUNCTION: SetFlagIfChangedUint
+// ==========================================================================
+void CContainerStoreSortingTable::SetFlagIfChangedUint( TUint newVal, TInt aColNum, TBool aIsNew, TSortableFieldsMasks aMask )
+    {
+    TInt8 curVal = newVal;
+    if ( !aIsNew )
+        {
+        curVal = iTable.ColUint32( aColNum );
+        }
+    
+    if ( aIsNew || curVal != newVal )
+        {
+        iFieldsChanged |= aMask;
+        }
+    }
+
+// ==========================================================================
+// FUNCTION: SetFlagIfChangedInt64
+// ==========================================================================
+void CContainerStoreSortingTable::SetFlagIfChangedInt64( TInt64 newVal, TInt aColNum, TBool aIsNew, TSortableFieldsMasks aMask )
+    {
+    TInt64 curVal = newVal;
+    if ( !aIsNew )
+        {
+        curVal = iTable.ColInt64( aColNum );
+        }
+    
+    if ( aIsNew || curVal != newVal )
+        {
+        iFieldsChanged |= aMask;
+        }
+    }
+
+// ==========================================================================
+// FUNCTION: GetColumnNumL
+// ==========================================================================
+TInt CContainerStoreSortingTable::GetColumnNumL( TMsgStoreSortByField aSortBy )
+    {
+    TInt stringColNum = 0;
+    if ( aSortBy == EMsgStoreSortBySender )
+        {
+        stringColNum = iFromColNum;
+        }
+    else if ( aSortBy == EMsgStoreSortByRecipient )
+        {
+        stringColNum = iToColNum;
+        }
+    else if ( aSortBy == EMsgStoreSortBySubject )
+        {
+        stringColNum = iSubjectColNum;
+        }
+    else
+        {
+        User::Leave(KErrArgument);
+        }
+    return stringColNum;
+    }
+
+// ==========================================================================
+// FUNCTION: IsEncrypted
+// ==========================================================================
+TBool CContainerStoreSortingTable::IsEncrypted( RDbRowSet& aRowSet )
+    {
+    return static_cast<TBool>( aRowSet.ColUint8( iIsEncryptedColNum ) );
+    }
+
+// ==========================================================================
+// FUNCTION: SetEncryptedL
+// ==========================================================================
+void CContainerStoreSortingTable::SetEncryptedL( TBool aIsEncrypted )
+    {
+    iTable.SetColL( iIsEncryptedColNum, static_cast<TUint8>(aIsEncrypted) );
+    }
+