--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgsrvnstore/server/src/msvdbadapter.cpp Mon Jan 18 20:36:02 2010 +0200
@@ -0,0 +1,4756 @@
+// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// HEADER FILES
+//
+//
+
+
+/**
+ * HEADER FILES
+ */
+#include <barsc.h>
+#include <bautils.h>
+
+#include "msvdbadapter.h"
+#include "msventryfreepool.h"
+#include "msvsearchsortdbwrapper.h"
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include "msvsearchsortconstants.h"
+#endif
+
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+ #include "cmessageconvertermanager.h"
+#endif
+
+/**
+ * CONSTANT DEFINITION
+ */
+#define SERVER_UID 0x1000484B
+#define KMsvNumStdFolder 7
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ #include "msvindexadapter.h"
+
+ //Main (dummy) DB name.
+ #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+ _LIT(KMainDummyDBName, "\\messaging_master.db");
+ _LIT(KMessagingDBName, "\\messaging.db");
+ #else
+ _LIT(KMainDummyDBName, "[1000484b]messaging_master.db");
+ _LIT(KMessagingDBName, "[1000484b]messaging.db");
+ #endif
+
+ _LIT(KLogicalName, "DB");
+ _LIT(KComma, ", ");
+ _LIT(KDelimiter, " ;");
+#endif // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+
+/**
+ * LITERAL DEFINITION
+ */
+//Data definition queries
+_LIT8(KEncodingText, "encoding=UTF-8");
+_LIT8(KCreateIndexEntryTableQuery, "CREATE TABLE IF NOT EXISTS IndexEntry ("
+ "id INTEGER PRIMARY KEY,"
+ "parentId INT,"
+ "serviceId INT,"
+ "mtmId INT,"
+ "type INT,"
+ "date INT64,"
+ "data INT,"
+ "size INT,"
+ "error INT,"
+ "mtmData1 INT,"
+ "mtmData2 INT,"
+ "mtmData3 INT,"
+ "relatedId INT,"
+ "bioType INT,"
+ "pcSyncCount INT,"
+ "reserved INT,"
+ "visibleParent INT,"
+ "description TEXT,"
+ "details TEXT" ");"
+ );
+
+_LIT8(KCreateIndexQuery, "CREATE INDEX IF NOT EXISTS INDEX_PARENT ON IndexEntry(parentId);");
+_LIT8(KCreateVersionTableQuery, "CREATE TABLE IF NOT EXISTS VersionTable ( "
+ "version INTEGER PRIMARY KEY );"
+ );
+
+//Common database queries
+_LIT8(KGetEntryExistsQuery, "SELECT parentId FROM IndexEntry WHERE id = :id;"); //
+_LIT8(KGetVisibleIdQuery, "SELECT data, visibleParent FROM IndexEntry WHERE id = :id;"); //
+_LIT8(KGetEntryQuery, "SELECT parentId, serviceId, mtmId, type, date, data, size, error, "
+ "mtmData1, mtmData2, mtmData3, relatedId, bioType, pcSyncCount, "
+ "reserved, visibleParent, description, details FROM IndexEntry WHERE id = :id;"); //
+_LIT8(KGetChildEntriesQuery, "SELECT id, serviceId, mtmId, type, date, data, size, error, "
+ "mtmData1, mtmData2, mtmData3, relatedId, bioType, pcSyncCount, "
+ "reserved, visibleParent, description, details FROM IndexEntry "
+ "WHERE parentId = :parentId order by id ASC;"); //
+
+//Data manipulation queries
+_LIT8(KCreateEntryQuery, "INSERT INTO IndexEntry VALUES ("
+ ":id, :parentId, :serviceId, :mtmId, :type, :date, :data, :size, :error,"
+ ":mtmData1, :mtmData2, :mtmData3, :relatedId, :bioType, :pcSyncCount,"
+ ":reserved, :visibleParent, :description, :details);"
+ ); //
+_LIT8(KUpdateEntryQuery, "UPDATE IndexEntry SET "
+ "parentId = :parentId, serviceId = :serviceId, mtmId = :mtmId, type = :type, date = :date,"
+ "data = :data, size = :size, error = :error, mtmData1 = :mtmData1, mtmData2 = :mtmData2,"
+ "mtmData3 = :mtmData3, relatedId = :relatedId, bioType = :bioType, pcSyncCount = :pcSyncCount,"
+ "reserved = :reserved, visibleParent = :visibleParent, description = :description,"
+ "details = :details WHERE id = :id;"
+ ); //
+_LIT8(KUpdateEntryNoParentQuery, "UPDATE IndexEntry SET "
+ "serviceId = :serviceId, mtmId = :mtmId, type = :type, date = :date,"
+ "data = :data, size = :size, error = :error, mtmData1 = :mtmData1, mtmData2 = :mtmData2,"
+ "mtmData3 = :mtmData3, relatedId = :relatedId, bioType = :bioType, pcSyncCount = :pcSyncCount,"
+ "reserved = :reserved, visibleParent = :visibleParent, description = :description,"
+ "details = :details WHERE id = :id;"
+ ); //
+
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+_LIT8(KCreateConversionStatusTableQuery, "CREATE TABLE IF NOT EXISTS ConversionStatus ("
+ "lastId INT,"
+ "serviceId INTEGER PRIMARY KEY,"
+ "sourceVersion INT,"
+ "targetVersion INT,"
+ "mtmId INT,"
+ "remainingCount INT );"
+ );
+
+_LIT8(KRemoveConversionStatusTable, "DROP TABLE IF EXISTS ConversionStatus;");
+
+
+
+#endif
+
+
+//Literals for parameter indexes
+_LIT(KMsgParamId, ":id");
+_LIT(KMsgParamParentId, ":parentId");
+_LIT(KMsgParamServiceId, ":serviceId");
+_LIT(KMsgParamMtmId, ":mtmId");
+_LIT(KMsgParamType, ":type");
+_LIT(KMsgParamDate, ":date");
+_LIT(KMsgParamData, ":data");
+_LIT(KMsgParamSize, ":size");
+_LIT(KMsgParamError, ":error");
+_LIT(KMsgParamMtmData1, ":mtmData1");
+_LIT(KMsgParamMtmData2, ":mtmData2");
+_LIT(KMsgParamMtmData3, ":mtmData3");
+_LIT(KMsgParamRelatedId, ":relatedId");
+_LIT(KMsgParamBiotype, ":bioType");
+_LIT(KMsgParamPcSyncCount, ":pcSyncCount");
+_LIT(KMsgParamReserved, ":reserved");
+_LIT(KMsgParamVisibleParent, ":visibleParent");
+_LIT(KMsgParamDescriptionTxt, ":description");
+_LIT(KMsgParamDetailsTxt, ":details");
+
+//Literals for column indexes
+_LIT(KMsgColumnId, "id");
+_LIT(KMsgColumnParentId, "parentId");
+_LIT(KMsgColumnServiceId, "serviceId");
+_LIT(KMsgColumnMtmId, "mtmId");
+_LIT(KMsgColumnType, "type");
+_LIT(KMsgColumnDate, "date");
+_LIT(KMsgColumnData, "data");
+_LIT(KMsgColumnSize, "size");
+_LIT(KMsgColumnError, "error");
+_LIT(KMsgColumnMtmData1, "mtmData1");
+_LIT(KMsgColumnMtmData2, "mtmData2");
+_LIT(KMsgColumnMtmData3, "mtmData3");
+_LIT(KMsgColumnRelatedId, "relatedId");
+_LIT(KMsgColumnBiotype, "bioType");
+_LIT(KMsgColumnPcSyncCount, "pcSyncCount");
+_LIT(KMsgColumnReserved, "reserved");
+_LIT(KMsgColumnVisibleParent, "visibleParent");
+_LIT(KMsgColumnDescriptionTxt, "description");
+_LIT(KMsgColumnDetailsTxt, "details");
+
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ _LIT8(KGetChildIdsQuery, "SELECT id, type, data FROM IndexEntry WHERE parentId = :parentId order by id ASC;"); //
+ _LIT8(KClearTableContents, "DELETE FROM SearchSortEntry;");
+#else
+ _LIT8(KDeleteTable, "DROP TABLE IF EXISTS SearchSortEntry;");
+ _LIT8(KGetChildIdsQuery, "SELECT id FROM IndexEntry WHERE parentId = :parentId order by id ASC;"); //
+ _LIT8(KGetInPreparationIdQuery, "SELECT id, data FROM IndexEntry;");
+#endif
+
+
+
+// Changes for PREQ 1667.
+//Data definition queries for SearchSort-Table
+_LIT8(KCreateSearchSortEntryTableQuery, "CREATE TABLE IF NOT EXISTS SearchSortEntry ("
+ "Qid INT,"
+ "id INT,"
+ "sortfield TEXT" ");"
+);
+
+_LIT8(KCreateSearchSortQuery, "CREATE UNIQUE INDEX IF NOT EXISTS SearchSortEntry_UNIQUE ON SearchSortEntry (Qid, id,sortfield);");
+
+//Common database queries
+_LIT8(KGetEntryAsc, "SELECT DISTINCT id FROM SearchSortEntry WHERE Qid = :Qid ORDER by sortfield ASC;");
+_LIT8(KGetEntryDesc, "SELECT DISTINCT id FROM SearchSortEntry WHERE Qid = :Qid ORDER by sortfield DESC;");
+_LIT8(KGetEntryNumAsc, "SELECT DISTINCT id FROM SearchSortEntry WHERE Qid = :Qid ORDER by CAST(sortfield AS INT) ASC;");
+_LIT8(KGetEntryNumDesc, "SELECT DISTINCT id FROM SearchSortEntry WHERE Qid = :Qid ORDER by CAST(sortfield AS INT) DESC;");
+
+_LIT8(KGetLastNIdsAsc, "SELECT DISTINCT id FROM SearchSortEntry WHERE ROWID > (LAST_INSERT_ROWID() - :RowId) AND Qid = :Qid ORDER by sortfield ASC;");
+_LIT8(KGetLastNIdsDesc, "SELECT DISTINCT id FROM SearchSortEntry WHERE ROWID > (LAST_INSERT_ROWID() - :RowId) AND Qid = :Qid ORDER by sortfield DESC;");
+_LIT8(KGetLastNIdsNumAsc, "SELECT DISTINCT id FROM SearchSortEntry WHERE ROWID > (LAST_INSERT_ROWID() - :RowId) AND Qid = :Qid ORDER by CAST(sortfield AS INT) ASC;");
+_LIT8(KGetLastNIdsNumDesc, "SELECT DISTINCT id FROM SearchSortEntry WHERE ROWID > (LAST_INSERT_ROWID() - :RowId) AND Qid = :Qid ORDER by CAST(sortfield AS INT) DESC;");
+
+_LIT8(KGetQueryCount, "SELECT COUNT(DISTINCT id) FROM SearchSortEntry WHERE Qid = :Qid");
+
+_LIT8(KGetFolderIds, "SELECT id FROM IndexEntry WHERE parentId = :parentId AND type LIKE :type");
+
+_LIT8(KGetIterResultCastAsc, "SELECT id FROM SearchSortEntry WHERE Qid = :qid ORDER by CAST(sortfield AS INT) ASC LIMIT :lim OFFSET :off ");
+_LIT8(KGetIterResultCastDesc, "SELECT id FROM SearchSortEntry WHERE Qid = :qid ORDER by CAST(sortfield AS INT) DESC LIMIT :lim OFFSET :off ");
+_LIT8(KGetIterResultAsc, "SELECT id FROM SearchSortEntry WHERE Qid = :qid ORDER by sortfield ASC LIMIT :lim OFFSET :off ");
+_LIT8(KGetIterResultDesc, "SELECT id FROM SearchSortEntry WHERE Qid = :qid ORDER by sortfield ASC LIMIT :lim OFFSET :off ");
+
+//Data manipulation queries
+_LIT8(KDeleteId, "DELETE FROM SearchSortEntry WHERE id = ");
+_LIT8(KCreateQueryEntry, "INSERT OR IGNORE INTO SearchSortEntry VALUES ("
+ ":Qid, :id, :sortfield);");
+
+_LIT8(KDeleteQueryId, "DELETE FROM SearchSortEntry WHERE Qid = ");
+_LIT8(KAndId, " AND id = ");
+_LIT8(KSemiColon, ";");
+
+//Literals for parameter indexes
+_LIT(KQueryQId, ":Qid");
+_LIT(KQueryTMsvId, ":id");
+_LIT(KQuerySortfield, ":sortfield");
+_LIT(KQueryRowId, ":RowId");
+_LIT(KOffset, ":off");
+_LIT(KLimit, ":lim");
+
+//Literals for column indexes
+_LIT(KQueryColumnTMsvId, "id");
+
+
+
+/**
+ * MEMBER FUNCTIONS OF CMsvDBAdapter
+ */
+
+
+
+/**
+ * CMsvDBAdapter()
+ * The default Constructor.
+ */
+CMsvDBAdapter::CMsvDBAdapter():isTransactionOpen(EFalse)
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ ,iDbPtrInitialized(EFalse)
+#endif
+ {
+ }
+
+
+
+
+/**
+ * ~CMsvDBAdapter()
+ * The default Destructor.
+ */
+CMsvDBAdapter::~CMsvDBAdapter()
+ {
+ //Close all RSqlStatement object.
+ for(TInt index = ECreateEntry; index < EIndexSentinel; index++)
+ {
+ iStatement[index].Close();
+ }
+
+ for(TInt index = EQueryCreateEntry; index < EQuerySentinel; index++)
+ {
+ iQueryStatement[index].Close();
+ }
+
+ iDatabase.Close();
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ if(iDatabasePresent)
+ {
+ iDatabasePresent->Close();
+ delete iDatabasePresent;
+ }
+#endif
+ }
+
+
+
+
+// Code added in PREQ 557.
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+/**
+ * NewL()
+ * @param None.
+ * @return None.
+ *
+ * Allocates and constructs a new DBAdapter object, calls ConstructL
+ * to create the dummy database and returns a handle to the DBAdapter.
+ */
+CMsvDBAdapter* CMsvDBAdapter::NewL()
+ {
+ //Create the DBAdapter object.
+ CMsvDBAdapter* self = new(ELeave) CMsvDBAdapter();
+ CleanupStack::PushL(self);
+
+ // Create the database.
+ self->ConstructL();
+
+ CleanupStack::Pop(self);
+ return self;
+
+ }
+
+
+
+
+/**
+ * ConstructL()
+ * @param None.
+ * @return None.
+ *
+ * Checks if there is the main (dummy) DB in the system drive
+ * and creates one if it is not present. Other databases will
+ * be attached to this DB which will not get deleted during
+ * the operation of the message server.
+ */
+void CMsvDBAdapter::ConstructL()
+ {
+ //Get the system drive.
+ TInt systemDrive = (TInt)RFs::GetSystemDrive();
+
+ RBuf dbFile;
+ CleanupClosePushL(dbFile);
+ dbFile.CreateL(50);
+ dbFile.Append(TDriveUnit(systemDrive).Name());
+ dbFile.Append(KMainDummyDBName);
+
+ //Check if the main DB exists. If not, then create it.
+ // > KErrNotFound, KErrPathNotFound - DB doesn't exist.
+ // > KErrNone, KErrInUse - DB exists.
+ TRAPD(err, iDatabase.OpenL(dbFile));
+ if(KErrNone != err)
+ {
+
+ // Leave in unfavorable condition.
+ if(KErrNoMemory == err ||
+ KErrNotReady == err ||
+ KErrInUse == err
+ )
+ {
+ User::Leave(err);
+ }
+
+ HBufC8* heapBuf = KEncodingText().AllocLC();
+
+ if(KSqlErrCorrupt == err || KSqlErrNotDb == err)
+ {
+ RSqlDatabase::Delete(dbFile);
+ }
+
+ //Create the dummy DB.
+#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+ // Create the non-secure database.
+ User::LeaveIfError(iDatabase.Create(dbFile, heapBuf));
+#else
+ // Using SID based security policy.
+ TSecureId sid(SERVER_UID);
+ const TSecurityPolicy KDefaultPolicy(sid);
+
+ //Create security policy
+ RSqlSecurityPolicy securityPolicy;
+ CleanupClosePushL(securityPolicy);
+
+ User::LeaveIfError(securityPolicy.Create(KDefaultPolicy));
+ User::LeaveIfError(iDatabase.Create(dbFile, securityPolicy, heapBuf));
+ CleanupStack::PopAndDestroy(); //securityPolicy
+#endif // #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+
+ CleanupStack::PopAndDestroy(); //heapBuf
+ }
+ CleanupStack::PopAndDestroy(); //dbFile
+
+ //Construct the data structure to store maximum TMsvIds in
+ //a given driveId.
+ iDatabasePresent = new(ELeave)RArray<TBool>(KMaxNumberOfDrives);
+ //Initialisation.
+ for(TInt index = 0; index < KMaxNumberOfDrives; ++index)
+ {
+ iDatabasePresent->Append(EFalse);
+ }
+
+ }
+
+
+
+
+/**
+ * AttachDBL()
+ * @param TDriveUnit The drive information of the drive to be checked.
+ * @param TUint The driveId of the drive (0-7).
+ * @param TMsvId& An output parameter that gives the maximum TMsvId of an
+ * entry in the messaging database of that drive.
+ *
+ * Attaches a database on the specified drive to the main (dummy)
+ * database on the system drive so that appropriate queries
+ * access entries in that database too. The function calls MaxTMsvIdL()
+ * to query the particular database to get the maximum TMsvId of an entry
+ * stored in it. This TMsvId is maintained in a data structure which has
+ * the driveId as the index.
+ *
+ * The database is detached by using its logical name which can
+ * be obtained from the driveId.
+ * (E.g.: logical name of a database on driveId 3 is 'DB3'. A query on the
+ * IndexEntry in this database should address the table as DB3.IndexEntry.)
+ */
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+void CMsvDBAdapter::AttachDBL(TDriveUnit aDriveUnit, TUint aDriveId, TMsvId& aMaxId, CMsvMessageDBAdapter* iMessageDBAdapter/*default= NULL*/)
+#else
+void CMsvDBAdapter::AttachDBL(TDriveUnit aDriveUnit, TUint aDriveId, TMsvId& aMaxId)
+#endif
+ {
+ //Construct the logical name of the database to be attached from
+ //the driveId.
+ RBuf logicalName;
+ CleanupClosePushL(logicalName);
+ logicalName.CreateL(5);
+ logicalName.Append(KLogicalName);
+ logicalName.AppendNum(aDriveId);
+
+ //Construct the DB filename appending messaging DB name to the drive name.
+ RBuf dbFile;
+ CleanupClosePushL(dbFile);
+ dbFile.CreateL(50);
+ dbFile.Append(aDriveUnit.Name());
+ dbFile.Append(KMessagingDBName);
+
+ //Attach the database to the connection.
+ User::LeaveIfError(iDatabase.Attach(dbFile, logicalName));
+
+ //Find the parameter and column indexes just once.
+ if((KErrNotFound == iDatabasePresent->Find(ETrue)) && (!iDbPtrInitialized))
+ {
+ InitializeL();
+ iDbPtrInitialized = ETrue;
+ }
+
+ //Find the maximum TMsvId in the database and store it.
+ aMaxId = MaxTMsvIdL(aDriveId);
+ (*iDatabasePresent)[aDriveId] = ETrue;
+
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+ if(iMessageDBAdapter)
+ {
+ iMessageDBAdapter->UpdateMetadataStructureL(aDriveId);
+ }
+#endif
+
+ CleanupStack::PopAndDestroy(2); //logicalName, dbFile
+ }
+
+
+
+
+/**
+ * DetachDBL()
+ * @param TUint The driveId (0-7) of the drive from which the database
+ * is to be detached.
+ * @return None.
+ *
+ * Detaches a database on the drive specified by the driveId from
+ * the main database connection. This is done when:
+ * a. The disk is removed from the drive.
+ * b. The drive is removed from the preferred drive list.
+ *
+ * The database is detached by using its logical name which can
+ * be obtained from the driveId.
+ * (E.g.: logical name of a database on driveId 3 is 'DB3'.)
+ */
+void CMsvDBAdapter::DetachDBL(TUint aDriveId)
+ {
+ //Construct the logical name.
+ RBuf logicalName;
+ CleanupClosePushL(logicalName);
+ logicalName.CreateL(5);
+ logicalName.Append(KLogicalName);
+ logicalName.AppendNum(aDriveId);
+
+ User::LeaveIfError(iDatabase.Detach(logicalName));
+
+ CleanupStack::PopAndDestroy(); //logicalName
+
+ (*iDatabasePresent)[aDriveId] = EFalse;
+
+ }
+
+
+
+
+/**
+ * CreateDBL()
+ * @param TDriveNumber The drive number of the drive on which a
+ * a new messaging database is to be created.
+ * @return None.
+ *
+ * Creates the messaging database on the drive specified by the TDriveNumber
+ * using a temporary local database connection.
+ * Also creates the IndexEntry table and an index on the parentId field in it,
+ * and then the Root entry in the database.
+ * Also creates a version table, which is a database with just one column
+ * and row which stores the current database version for message store
+ * versioning.
+ */
+#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+void CMsvDBAdapter::CreateDBL(TDriveNumber aDriveNumber, TBool aCreateVersionTable /*Default=ETrue*/, TBool aInvalid /*Default=EFalse*/)
+#else
+void CMsvDBAdapter::CreateDBL(TDriveNumber aDriveNumber)
+#endif
+ {
+ //Construct the database filename.
+ TParse parse;
+ TPtrC drive = TDriveUnit(aDriveNumber).Name();
+ parse.Set(KMessagingDBName, &drive, NULL);
+ TFileName dbFileName = parse.FullName();
+
+ RSqlDatabase tempDB; //A temporary local database connection.
+ CleanupClosePushL(tempDB);
+
+ HBufC8* heapBuf = KEncodingText().AllocLC();
+
+ //Create the database.
+#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+ User::LeaveIfError(tempDB.Create(dbFileName, heapBuf));
+#else
+ // Using SID based security policy.
+ TSecureId sid(SERVER_UID);
+ const TSecurityPolicy KDefaultPolicy(sid);
+
+ //Create security policy
+ RSqlSecurityPolicy securityPolicy;
+ CleanupClosePushL(securityPolicy);
+
+ User::LeaveIfError(securityPolicy.Create(KDefaultPolicy));
+ User::LeaveIfError(tempDB.Create(dbFileName, securityPolicy, heapBuf));
+
+ CleanupStack::PopAndDestroy(); //securityPolicy
+#endif // #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+
+ CleanupStack::PopAndDestroy(); //heapBuf
+
+ //Create tables for the database
+ TInt err = tempDB.Exec(KCreateIndexEntryTableQuery);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ User::Leave(KErrGeneral);
+ }
+
+ //Create index on indexEnty table.
+ //Index is created on parentId.
+ err = tempDB.Exec(KCreateIndexQuery);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ User::Leave(KErrGeneral);
+ }
+
+ // Create root entry in DB.
+ CreateRootEntryL(tempDB);
+
+#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+ if(aCreateVersionTable)
+ {
+#endif
+ //Create the version table to store the message store version.
+ err = tempDB.Exec(KCreateVersionTableQuery);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ User::Leave(KErrGeneral);
+ }
+ //Insert the version number into the above table.
+ _LIT(KInsertVersionNumberQuery, " INSERT INTO VersionTable Values ( " );
+ RBuf8 versionQuery;
+ CleanupClosePushL(versionQuery);
+ versionQuery.CreateL(50);
+ versionQuery.Append(KInsertVersionNumberQuery);
+
+#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+ if(aInvalid) //create an invalid database wrt version for testing
+ versionQuery.AppendNum(999);
+ else
+ versionQuery.AppendNum(KCurrentDatabaseVersion);
+#else
+ versionQuery.AppendNum(KCurrentDatabaseVersion);
+#endif
+
+ versionQuery.Append(_L(");"));
+ err = tempDB.Exec(versionQuery);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ User::Leave(KErrGeneral);
+ }
+
+ CleanupStack::PopAndDestroy(); //versionQuery
+
+#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+ }
+#endif
+
+ CleanupStack::PopAndDestroy(); // tempDB
+ }
+
+
+
+/**
+ * CreateRootEntryL()
+ *
+ * Creates root entry in the DB.
+ */
+void CMsvDBAdapter::CreateRootEntryL(RSqlDatabase& tempDB)
+ {
+ _LIT(KCreateRootEntryQuery, "INSERT INTO IndexEntry VALUES (");
+ _LIT(KComma, ", ");
+ _LIT(KDelimiter, " );");
+
+ TMsvEntry rootEntry;
+ rootEntry.iType = KUidMsvRootEntry;
+ rootEntry.iMtm = KUidMsvRootEntry;
+ rootEntry.iDate.UniversalTime();
+ rootEntry.SetId(KMsvRootIndexEntryId);
+ rootEntry.SetParent(KErrNotFound);
+ rootEntry.SetOwner(ETrue);
+ rootEntry.iSize = 0;
+
+ RBuf queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(300);
+ queryBuf.Append(KCreateRootEntryQuery);
+ queryBuf.AppendNum(rootEntry.iId);
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.Parent());
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.iServiceId);
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.iMtm.iUid);
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.iType.iUid);
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.iDate.Int64());
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.iData);
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.iSize);
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.iError);
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.iMtmData1);
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.iMtmData2);
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.iMtmData3);
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.iRelatedId);
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.iBioType);
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.iPcSyncCount);
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(rootEntry.iReserved);
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(KMsvRootIndexEntryId);
+ queryBuf.Append(KComma);
+ queryBuf.Append(_L("\"\""));
+ queryBuf.Append(KComma);
+ queryBuf.Append(_L("\"\""));
+ queryBuf.Append(KDelimiter);
+
+ TInt err = tempDB.Exec(queryBuf);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ User::Leave(KErrGeneral);
+ }
+ CleanupStack::PopAndDestroy(); //queryBuf
+ }
+
+
+
+
+/**
+ * MaxTMsvIdL()
+ * @param TDriveNumber The drive number of the drive to be queried.
+ * @return None.
+ *
+ * Queries the specified drive's database for the maximum TMsvId
+ * of an entry stored in it.
+ */
+TMsvId CMsvDBAdapter::MaxTMsvIdL(TUint aDriveId)
+ {
+ _LIT(KMaxTMsvIdQuery1, "SELECT MAX(id) FROM DB");
+ _LIT(KMaxTMsvIdQuery2, ".IndexEntry;");
+
+ RBuf queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(50);
+
+ queryBuf.Append(KMaxTMsvIdQuery1);
+ queryBuf.AppendNum(aDriveId);
+ queryBuf.Append(KMaxTMsvIdQuery2);
+
+ //Create a select query
+ TSqlScalarFullSelectQuery query(iDatabase);
+
+ //Get the column data
+ TMsvId maxTMsvId = query.SelectIntL(queryBuf);
+
+ CleanupStack::PopAndDestroy(); //queryBuf
+
+ if(KMsvRootIndexEntryId != maxTMsvId)
+ maxTMsvId = MaskTMsvId(aDriveId, maxTMsvId);
+ return maxTMsvId;
+ }
+
+
+
+
+/**
+ * ValidateDatabaseL()
+ * @param TDriveNumber The drive number of the drive to be checked.
+ * @return None.
+ *
+ * Validates a database by checking if:
+ * a. The database file is in the appropriate location.
+ * b. The database is readable and not corrupt.
+ * c. The database is of latest supported version.
+ * d. All standard folders (as specified in the messaging resource file)
+ * exist in the database.
+ */
+void CMsvDBAdapter::ValidateDatabaseL(TDriveNumber aDriveNumber)
+ {
+ //Check (a) and (b).
+ TParse parse;
+ TPtrC drive(TDriveUnit(aDriveNumber).Name());
+ parse.Set(KMessagingDBName, &drive, NULL);
+ TFileName dbFile = parse.FullName();
+
+ RSqlDatabase tempDB;
+ CleanupClosePushL(tempDB);
+ tempDB.OpenL(dbFile);
+
+ //Check (d) with the connection still open.
+ //Entries to be checked are Root, Local, Inbox, Outbox, Drafts,
+ //Sent and Deleted.
+ _LIT(KStandardEntryExistsQuery1, "SELECT count(*) FROM IndexEntry WHERE id <= ");
+ RBuf queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(150);
+ queryBuf.Append(KStandardEntryExistsQuery1);
+ queryBuf.AppendNum(KMsvDeletedEntryFolderEntryId);
+ queryBuf.Append(KDelimiter);
+
+ TSqlScalarFullSelectQuery query(tempDB);
+ TInt folders = 0;
+ folders = query.SelectIntL(queryBuf);
+
+ //The database is invalid if the number of folders returned
+ //from the above query is not 7.
+ if(folders != KMsvNumStdFolder) //Number of standard folders + root. To be put in a macro or const
+ {
+ User::Leave(KSqlErrCorrupt);
+ }
+ CleanupStack::PopAndDestroy(); //queryBuf
+
+ //(a), (b) and (d) are fine. Check (c).
+ //Check the version number against the expected version number.
+ //PREQ557 version - 1; Post-557 version - 2.
+ _LIT(KSelectVersionQuery, "SELECT version FROM VersionTable;");
+ TInt version = 0;
+
+ version = query.SelectIntL(KSelectVersionQuery);
+ if(version != KCurrentDatabaseVersion)
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ CleanupStack::PopAndDestroy(); // tempDB
+ }
+
+
+
+
+/**
+ * GetVisibleFolderIdL()
+ * @param TMsvId: Parent Id.
+ * @param TMsvId&: Out parameter for most immediate visible folder id of
+ * any child entry present under passed parent id.
+ * @return None.
+ *
+ * This functions returns the most immediate parent visible folder id.
+ * There are two types of folders. A visible folder is one which is
+ * visible to the external user, but there are internal non-visible folders
+ * created under each email message to organize the content of the email.
+ * Parent entry of an entry is either root or a folder. A folder can be
+ * service folder (like LocalServices), user-defined folder/standard folder
+ * like Inbox or a non-visible folder (created under an email message).
+ *
+ * For a given parent Id, the function returns the most immediate visible
+ * parent folder. The rules are as follows:
+ * 1. If the parent entry is root or children of root, then the visibleFolder
+ * will be root itself. This is because service folders are considered
+ * invisible, since they are not seen by user.
+ * 2. If the parent entry itself is a visible folder then child's visibleFolder
+ * id should be its parent id.
+ * 3. If the parent entry is a non-visible folder then child's visibleFolder
+ * id is same as its parent's visibleFolder id.
+ */
+void CMsvDBAdapter::GetVisibleFolderIdL(TMsvId aParentId, TMsvId& aVisibleFolderId)
+ {
+ // If the entry is either a root entry (parent=KErrNotFound) or
+ // child of root entry its visibleFolderId will be root entry itself.
+ if(KErrNotFound == aParentId)
+ {
+ aVisibleFolderId = KMsvRootIndexEntryId;
+ return;
+ }
+
+ //Get the driveId and unmask the TMsvId supplied.
+ TInt driveId = GetDriveId(aParentId);
+ aParentId = UnmaskTMsvId(aParentId);
+
+ if(KMsvRootIndexEntryId == aParentId)
+ {
+ aVisibleFolderId = KMsvRootIndexEntryId;
+ }
+ else
+ {
+ //Construct a query for the particular drive.
+ _LIT8(KGetVisibleIdQuery1, "SELECT data, visibleParent FROM DB");
+ _LIT8(KGetVisibleIdQuery2, ".IndexEntry WHERE id = ");
+
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(70);
+ queryBuf.Append(KGetVisibleIdQuery1);
+ queryBuf.AppendNum(driveId);
+ queryBuf.Append(KGetVisibleIdQuery2);
+ queryBuf.AppendNum(aParentId);
+ queryBuf.Append(KDelimiter);
+
+ RSqlStatement visQuery;
+ CleanupClosePushL(visQuery);
+ User::LeaveIfError(visQuery.Prepare(iDatabase, queryBuf));
+ TInt dataParam = GetColumnIndexL(visQuery, KMsgColumnData());
+ TInt visParam = GetColumnIndexL(visQuery, KMsgColumnVisibleParent());
+
+ if (KSqlAtRow != visQuery.Next())
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ TInt32 data = ColumnInt(visQuery, dataParam);
+ if( data & TMsvEntry::KMsvVisibleFolderNodeFlag)
+ {
+ // If visible folder flag is not set for parent entry.
+ aVisibleFolderId = ColumnInt(visQuery, visParam);
+ if(!IsStandardId(aVisibleFolderId))
+ {
+ aVisibleFolderId = MaskTMsvId(driveId, aVisibleFolderId);
+ }
+ }
+ else
+ {
+ // If parent entry is visible
+ if(IsStandardId(aParentId))
+ {
+ aVisibleFolderId = aParentId;
+ }
+ else
+ {
+ aVisibleFolderId = MaskTMsvId(driveId, aParentId);
+ }
+ }
+ CleanupStack::PopAndDestroy(2); //visQuery, queryBuf
+ }
+ }
+
+
+
+
+/**
+ * CreateEntryL()
+ * @param const TMsvEntry&: The entry to be created.
+ * @param const TMsvId: Immediate visible parent folder of the entry
+ * @return None.
+ *
+ * The function creates a new entry in the database.
+ * No consisitency check is performed on the passed entry. The function may
+ * leave if query execution fails.
+ */
+void CMsvDBAdapter::CreateEntryL(const TMsvEntry& aNewEntry, const TMsvId aImmediateVisibleFolder)
+ {
+ _LIT8(KCreateEntryQuery1, "INSERT INTO DB");
+ _LIT8(KCreateEntryQuery2, ".IndexEntry VALUES ("
+ ":id, :parentId, :serviceId, :mtmId, :type, :date, :data, :size, :error,"
+ ":mtmData1, :mtmData2, :mtmData3, :relatedId, :bioType, :pcSyncCount,"
+ ":reserved, :visibleParent, :description, :details);"
+ );
+
+ //Get the driveId and unmask the TMsvId supplied.
+ TInt driveId = GetDriveId(aNewEntry.iId);
+ TMsvId id = UnmaskTMsvId(aNewEntry.iId);
+ TMsvId parentId = UnmaskTMsvId(aNewEntry.iParentId);
+ TMsvId visFolder = UnmaskTMsvId(aImmediateVisibleFolder);
+ TMsvId serviceId = UnmaskTMsvId(aNewEntry.iServiceId);
+ TMsvId relatedId = UnmaskTMsvId(aNewEntry.iRelatedId);
+
+ //Construct a query for the particular drive.
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(350);
+ queryBuf.Append(KCreateEntryQuery1);
+ queryBuf.AppendNum(driveId);
+ queryBuf.Append(KCreateEntryQuery2);
+ iStatement[ECreateEntry].Close(); //closing any statement prepared previously
+ User::LeaveIfError(iStatement[ECreateEntry].Prepare(iDatabase, queryBuf));
+
+ //Bind the entry data
+ BindIntL(iStatement[ECreateEntry], iIdIndex[ECreateEntry], id);
+ BindIntL(iStatement[ECreateEntry], iParentIdIndex[ECreateEntry], parentId);
+ BindIntL(iStatement[ECreateEntry], iDataIndex[ECreateEntry], aNewEntry.iData);
+ BindIntL(iStatement[ECreateEntry], iPcSyncCountIndex[ECreateEntry], aNewEntry.iPcSyncCount);
+ BindIntL(iStatement[ECreateEntry], iReservedIndex[ECreateEntry], aNewEntry.iReserved);
+ BindIntL(iStatement[ECreateEntry], iRelatedIdIndex[ECreateEntry], relatedId);
+ BindIntL(iStatement[ECreateEntry], iTypeIndex[ECreateEntry], aNewEntry.iType.iUid);
+ BindInt64L(iStatement[ECreateEntry], iDateIndex[ECreateEntry], aNewEntry.iDate.Int64());
+ BindIntL(iStatement[ECreateEntry], iSizeIndex[ECreateEntry], aNewEntry.iSize);
+ BindIntL(iStatement[ECreateEntry], iErrorIndex[ECreateEntry], aNewEntry.iError);
+ BindIntL(iStatement[ECreateEntry], iBiotypeIndex[ECreateEntry], aNewEntry.iBioType);
+ BindIntL(iStatement[ECreateEntry], iMtmData1Index[ECreateEntry], aNewEntry.iMtmData1);
+ BindIntL(iStatement[ECreateEntry], iMtmData2Index[ECreateEntry], aNewEntry.iMtmData2);
+ BindIntL(iStatement[ECreateEntry], iMtmData3Index[ECreateEntry], aNewEntry.iMtmData3);
+ BindIntL(iStatement[ECreateEntry], iServiceIdIndex[ECreateEntry], serviceId);
+ BindIntL(iStatement[ECreateEntry], iMtmIdIndex[ECreateEntry], aNewEntry.iMtm.iUid);
+ BindIntL(iStatement[ECreateEntry], iVisibleParent[ECreateEntry], visFolder);
+ BindTextL(iStatement[ECreateEntry],iDescriptionIndex[ECreateEntry],aNewEntry.iDescription);
+ BindTextL(iStatement[ECreateEntry],iDetailsIndex[ECreateEntry],aNewEntry.iDetails);
+
+ TInt err = iStatement[ECreateEntry].Exec();
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ User::Leave(KErrGeneral);
+ }
+ iStatement[ECreateEntry].Close();
+ CleanupStack::PopAndDestroy();
+ }
+
+
+
+
+/**
+ * UpdateEntryL()
+ * @param const TMsvEntry&: Entry to be updated.
+ * @param const TMsvId: the visible folder Id of the updated entry.
+ * @param TBool: ETrue if the parent of the entry has been changed,
+ * EFalse if otherwise.
+ * @return None.
+ *
+ * The function updates an entry in the database.
+ * No consisitency check is performed on the passed entry. The function may
+ * leave if query execution fails.
+ */
+void CMsvDBAdapter::UpdateEntryL(const TMsvEntry& aEntry, const TMsvId aImmediateVisibleFolder, TBool aIsParentIdUpdated/*DEFAULT=ETrue*/)
+ {
+ _LIT8(KUpdateEntryQuery1, "UPDATE DB");
+ _LIT8(KUpdateEntryQuery2, ".IndexEntry SET ");
+ _LIT8(KUpdateEntryQueryWithParent, "parentId = :parentId, ");
+ _LIT8(KUpdateEntryQueryWithoutParent, "serviceId = :serviceId, mtmId = :mtmId, type = :type, date = :date,"
+ "data = :data, size = :size, error = :error, mtmData1 = :mtmData1, mtmData2 = :mtmData2,"
+ "mtmData3 = :mtmData3, relatedId = :relatedId, bioType = :bioType, pcSyncCount = :pcSyncCount,"
+ "reserved = :reserved, visibleParent = :visibleParent, description = :description,"
+ "details = :details WHERE id = :id;"
+ );
+
+ //Get the driveId and unmask the TMsvId supplied.
+ TInt driveId = GetDriveId(aEntry.iId);
+ TMsvId id = UnmaskTMsvId(aEntry.iId);
+ TMsvId parentId = UnmaskTMsvId(aEntry.iParentId);
+ TMsvId serviceId = UnmaskTMsvId(aEntry.iServiceId);
+ TMsvId relatedId = UnmaskTMsvId(aEntry.iRelatedId);
+ TMsvId visFolder = UnmaskTMsvId(aImmediateVisibleFolder);
+
+ //Form the query for the particular drive.
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(500);
+ queryBuf.Append(KUpdateEntryQuery1);
+ queryBuf.AppendNum(driveId);
+ queryBuf.Append(KUpdateEntryQuery2);
+
+ iStatementType updateStmt;
+ TInt err = KErrNone;
+ //Bind the entry data
+ if(aIsParentIdUpdated)
+ {
+ updateStmt = EUpdateEntry;
+ queryBuf.Append(KUpdateEntryQueryWithParent);
+ queryBuf.Append(KUpdateEntryQueryWithoutParent);
+ iStatement[updateStmt].Close(); //closing any statement prepared previously
+ User::LeaveIfError(iStatement[updateStmt].Prepare(iDatabase, queryBuf));
+ BindIntL(iStatement[updateStmt], iParentIdIndex[updateStmt], parentId);
+ }
+ else
+ {
+ updateStmt = EUpdateEntryNoParent;
+ iStatement[updateStmt].Close(); //closing any statement prepared previously
+ queryBuf.Append(KUpdateEntryQueryWithoutParent);
+ User::LeaveIfError(iStatement[updateStmt].Prepare(iDatabase, queryBuf));
+ }
+ BindIntL(iStatement[updateStmt], iVisibleParent[updateStmt], visFolder);
+ BindIntL(iStatement[updateStmt], iIdIndex[updateStmt], id);
+ BindIntL(iStatement[updateStmt], iDataIndex[updateStmt], aEntry.iData);
+ BindIntL(iStatement[updateStmt], iPcSyncCountIndex[updateStmt], aEntry.iPcSyncCount);
+ BindIntL(iStatement[updateStmt], iReservedIndex[updateStmt], aEntry.iReserved);
+ BindIntL(iStatement[updateStmt], iRelatedIdIndex[updateStmt], relatedId);
+ BindIntL(iStatement[updateStmt], iTypeIndex[updateStmt], aEntry.iType.iUid);
+ BindInt64L(iStatement[updateStmt], iDateIndex[updateStmt], aEntry.iDate.Int64());
+ BindIntL(iStatement[updateStmt], iSizeIndex[updateStmt], aEntry.iSize);
+ BindIntL(iStatement[updateStmt], iErrorIndex[updateStmt], aEntry.iError);
+ BindIntL(iStatement[updateStmt], iBiotypeIndex[updateStmt], aEntry.iBioType);
+ BindIntL(iStatement[updateStmt], iMtmData1Index[updateStmt], aEntry.iMtmData1);
+ BindIntL(iStatement[updateStmt], iMtmData2Index[updateStmt], aEntry.iMtmData2);
+ BindIntL(iStatement[updateStmt], iMtmData3Index[updateStmt], aEntry.iMtmData3);
+ BindIntL(iStatement[updateStmt], iServiceIdIndex[updateStmt], serviceId);
+ BindIntL(iStatement[updateStmt], iMtmIdIndex[updateStmt], aEntry.iMtm.iUid);
+ BindTextL(iStatement[updateStmt], iDescriptionIndex[updateStmt],aEntry.iDescription);
+ BindTextL(iStatement[updateStmt], iDetailsIndex[updateStmt],aEntry.iDetails);
+
+ //Execute the prepared SQL statement.
+ err = iStatement[updateStmt].Exec();
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ iStatement[updateStmt].Close();
+ CleanupStack::PopAndDestroy(); //queryBuf
+ }
+
+
+
+
+/**
+ * DeleteEntryL()
+ * @param TMsvId: Entry Id to be deleted.
+ *
+ * The function deletes an entry with the passed Id. The function
+ * may leave due to database error while execution. The function
+ * does not leave if the entry does not exist.
+ *
+ * **WARNING** The function does NOT ensure that if a parent entry
+ * is deleted all its child entries are also deleted.
+ */
+void CMsvDBAdapter::DeleteEntryL(TMsvId aEntryId)
+ {
+ _LIT8(KDeleteEntryQuery1, "DELETE FROM DB");
+ _LIT8(KDeleteEntryQuery2, ".IndexEntry WHERE id = ");
+
+ //Get the driveId and unmask the TMsvId supplied.
+ TInt driveId = GetDriveId(aEntryId);
+ aEntryId = UnmaskTMsvId(aEntryId);
+
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(100);
+ queryBuf.Append(KDeleteEntryQuery1);
+ queryBuf.AppendNum(driveId);
+ queryBuf.Append(KDeleteEntryQuery2);
+ queryBuf.AppendNum(aEntryId);
+ queryBuf.Append(KDelimiter);
+
+ TInt err = iDatabase.Exec(queryBuf);
+ CleanupStack::PopAndDestroy();
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ User::Leave(KErrNotFound);
+ }
+ }
+
+
+
+
+/**
+ * DeleteEntryL()
+ * @param const CMsvEntrySelection&: Entry Id list to be deleted.
+ * @return None.
+ *
+ * The function deletes all entries mentioned in the passed Id list.
+ * The function may leave due to database error while execution or
+ * if an entry does not exist.
+ *
+ * **WARNING** The function does NOT ensure that if a parent entry
+ * is deleted all its child entries are also deleted.
+ */
+void CMsvDBAdapter::DeleteEntryL(const CMsvEntrySelection& aEntryIdList)
+ {
+ TInt count;
+ if( 0 == (count = aEntryIdList.Count()) )
+ {
+ return;
+ }
+
+ _LIT(KQuery1, "DELETE FROM DB");
+ _LIT(KQuery2, ".IndexEntry WHERE id IN (");
+ _LIT(KEndDelimiter, ");");
+
+ //Delete maximum 100 entries at a time so as to not overflow IPC buffer
+#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+ TInt maxEntries = 50; //for testing
+#else
+ TInt maxEntries = 100;
+#endif
+
+ CMsvEntrySelection* entryList = aEntryIdList.CopyL(); //separate copy of the list to work on
+ CleanupStack::PushL(entryList);
+
+ for(TInt index1 = 0; index1<count; ++index1)
+ {
+ TInt driveId = GetDriveId(entryList->At(index1));
+ TInt numDeleted = 1;
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(70 + ((10+2)*maxEntries));
+ queryBuf.Append(KQuery1);
+ queryBuf.AppendNum(driveId);
+ queryBuf.Append(KQuery2);
+ queryBuf.AppendNum(UnmaskTMsvId(entryList->At(index1)));
+ for(TInt index2 = index1 + 1; index2<count && numDeleted<maxEntries; ++index2)
+ {
+ if(driveId == GetDriveId(entryList->At(index2)))
+ {
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(UnmaskTMsvId(entryList->At(index2)));
+ ++numDeleted;
+ entryList->Delete(index2);
+ --index2;
+ --count;
+ }
+ }
+ entryList->Delete(index1);
+ --index1;
+ --count;
+ queryBuf.Append(KEndDelimiter);
+ TInt err = iDatabase.Exec(queryBuf);
+ CleanupStack::PopAndDestroy(); //queryBuf
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ }
+ CleanupStack::PopAndDestroy(); //entryList
+ }
+
+
+
+
+/**
+ * GetEntryL()
+ * @param TMsvId: Id of the entry to be fetched.
+ * @param CMsvCacheEntry*&: The newly fetched entry.
+ * @param TMsvId&: Out parameter for value of VisibleParent column.
+ * @return None.
+ *
+ * Fetch an entry from the database. Memory to aEntry
+ * should not already be assigned.
+ */
+void CMsvDBAdapter::GetEntryL(TMsvId aId, CMsvCacheEntry*& aEntry, TMsvId& aVisibleParentEntryId)
+ {
+ _LIT8(KGetEntryQuery1, "SELECT parentId, serviceId, mtmId, type, date, data, size, error, "
+ "mtmData1, mtmData2, mtmData3, relatedId, bioType, pcSyncCount, "
+ "reserved, visibleParent, description, details FROM DB");
+ _LIT8(KGetEntryQuery2, ".IndexEntry WHERE id = ");
+
+ //Get the driveId and unmask the TMsvId supplied.
+ TInt driveId = GetDriveId(aId);
+
+ //Construct a query for the particular drive.
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ TInt len = KGetEntryQuery1().Length() + KGetEntryQuery2().Length() + 15;
+ queryBuf.CreateL(len);
+ queryBuf.Append(KGetEntryQuery1);
+ queryBuf.AppendNum(driveId);
+ queryBuf.Append(KGetEntryQuery2);
+ queryBuf.AppendNum(UnmaskTMsvId(aId));
+ queryBuf.Append(KDelimiter);
+
+ //Prepare a statement for the query.
+ RSqlStatement getStmt;
+ CleanupClosePushL(getStmt);
+ User::LeaveIfError(getStmt.Prepare(iDatabase, queryBuf));
+
+ if(KSqlAtRow != getStmt.Next())
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ //Get the entry from the statement
+ aEntry = CMsvEntryFreePool::Instance()->EntryL();
+ aEntry->Entry().iId = aId;
+
+ LoadEntryFromStatementL(getStmt, EGetEntry, aVisibleParentEntryId, *aEntry);
+
+ //We do not return non-standard visible folders from a non-current drive's database.
+ if(driveId != KCurrentDriveId &&
+ aEntry->Entry().Visible() &&
+ !IsStandardId(aEntry->GetId()) &&
+ KUidMsvFolderEntryValue == aEntry->Entry().iType.iUid
+ )
+ {
+ CMsvEntryFreePool::Instance()->ReleaseEntry(aEntry);
+ User::Leave(KErrNotFound);
+ }
+
+ // Unmask iId's of standard Ids.
+ if(IsStandardId(aEntry->GetId()))
+ {
+ aEntry->Entry().SetId(UnmaskTMsvId(aEntry->GetId()));
+ }
+
+ // Mask iParentId if it is a non-standard id.
+ if(!IsStandardId(aEntry->Entry().iParentId))
+ {
+ aEntry->Entry().iParentId = MaskTMsvId(driveId, aEntry->Entry().iParentId);
+ }
+
+ // Mask visible folder if it is a non-standard id.
+ if(!IsStandardId(aVisibleParentEntryId))
+ {
+ aVisibleParentEntryId = MaskTMsvId(driveId, aVisibleParentEntryId);
+ }
+
+ // Mask iServiceId if it is a non-standard id.
+ if(!IsStandardId(aEntry->Entry().iServiceId))
+ {
+ aEntry->Entry().iServiceId = MaskTMsvId(driveId, aEntry->Entry().iServiceId);
+ }
+
+ // Mask iRelatedId if it is a non-standard id.
+ if(!IsStandardId(aEntry->Entry().iRelatedId))
+ {
+ aEntry->Entry().iRelatedId = MaskTMsvId(driveId, aEntry->Entry().iRelatedId);
+ }
+
+ CleanupStack::PopAndDestroy(2); //getStmt, queryBuf
+ }
+
+
+
+
+/**
+ * GetChildrenL()
+ * @param TMsvId: Parent Id of the child entries to be fetched.
+ * @param RPointerArray<TMsvEntry>&: List of child entries to be filled.
+ * @return None.
+ *
+ * Fetch child entries from the database for a given parent Id.
+ * This does not check if the parent entry already exist. The
+ * entries will be added in ascending order of their TMsvId.
+ */
+void CMsvDBAdapter::GetChildrenL(TMsvId aParentId, RPointerArray<CMsvCacheEntry>& aChildArray)
+ {
+ _LIT8(KGetChildEntriesQuery1, "SELECT id, serviceId, mtmId, type, date, data, size, error, "
+ "mtmData1, mtmData2, mtmData3, relatedId, bioType, pcSyncCount, "
+ "reserved, visibleParent, description, details FROM DB");
+ _LIT8(KGetChildEntriesQuery2, ".IndexEntry WHERE parentId = ");
+ _LIT8(KGetChildEntriesQuery3, " order by id ASC;");
+
+ //Get the driveId and unmask the TMsvId supplied.
+ TInt driveId = GetDriveId(aParentId);
+ aParentId = UnmaskTMsvId(aParentId);
+
+ //Construct the query for the particular drive.
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(350);
+ queryBuf.Append(KGetChildEntriesQuery1);
+ queryBuf.AppendNum(driveId);
+ queryBuf.Append(KGetChildEntriesQuery2);
+ queryBuf.AppendNum(aParentId);
+ queryBuf.Append(KGetChildEntriesQuery3);
+
+ //Prepare a statement for the query.
+ RSqlStatement getStmt;
+ CleanupClosePushL(getStmt);
+ User::LeaveIfError(getStmt.Prepare(iDatabase, queryBuf));
+
+ while(KSqlAtRow == getStmt.Next())
+ {
+ // Do not return non-standard visible folders from non-current drive.
+ // If it is a non-current drive...
+ if( (driveId != KCurrentDriveId) &&
+ // If it is a folder entry.
+ (KUidMsvFolderEntryValue == ColumnInt(getStmt, iTypeIndex[EGetChildEntries])) &&
+ // If it is a visible folder.
+ (IsVisibleFolder(ColumnInt(getStmt, iDataIndex[EGetChildEntries]))) &&
+ // If it is a non-standard folder.
+ (!IsStandardId(ColumnInt(getStmt, iIdIndex[EGetChildEntries])))
+ )
+ {
+ continue;
+ }
+
+ TMsvId aVisibleParentEntryId;
+ CMsvCacheEntry *cacheEntry = CMsvEntryFreePool::Instance()->EntryL();
+ if(!IsStandardId(aParentId))
+ {
+ aParentId = MaskTMsvId(driveId, aParentId);
+ }
+ cacheEntry->Entry().iParentId = aParentId;
+ LoadEntryFromStatementL(getStmt, EGetChildEntries, aVisibleParentEntryId, *cacheEntry);
+
+ //Add the drive mask to the TMsvId.
+ if(!IsStandardId(cacheEntry->GetId()))
+ {
+ cacheEntry->Entry().iId = MaskTMsvId(driveId, cacheEntry->Entry().iId);
+ }
+
+ // Mask iServiceId if it is a non-standard id.
+ if(!IsStandardId(cacheEntry->Entry().iServiceId))
+ {
+ cacheEntry->Entry().iServiceId = MaskTMsvId(driveId, cacheEntry->Entry().iServiceId);
+ }
+
+ // Mask iRelatedId if it is a non-standard id.
+ if(!IsStandardId(cacheEntry->Entry().iRelatedId))
+ {
+ cacheEntry->Entry().iRelatedId = MaskTMsvId(driveId, cacheEntry->Entry().iRelatedId);
+ }
+
+ //Add the child entry to the array given
+ aChildArray.AppendL(cacheEntry);
+ }
+
+ CleanupStack::PopAndDestroy(2); //getStmt, queryBuf
+ }
+
+
+
+
+/**
+ * GetChildrenIdL()
+ * @param TMsvId: Parent Id of the child entries to be fetched.
+ * @param CMsvEntrySelection&: List of child entry Id's.
+ * @return None.
+ *
+ * Fetch child entry Id's from the database for a given parent Id.
+ * This does not check if the parent entry already exist. The
+ * entries will be added in ascending order of their TMsvId.
+ */
+void CMsvDBAdapter::GetChildrenIdL(TMsvId aParentId, CMsvEntrySelection& aChildArray)
+ {
+ _LIT8(KGetChildIdsQuery1, "SELECT id, type, data FROM DB");
+ _LIT8(KGetChildIdsQuery2, ".IndexEntry WHERE parentId = ");
+ _LIT8(KGetChildIdsQuery3, " order by id ASC;");
+
+ //Get the driveId and unmask the TMsvId supplied.
+ TInt driveId = GetDriveId(aParentId);
+ aParentId = UnmaskTMsvId(aParentId);
+
+ //Construct the query for the particular drive.
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(100);
+ queryBuf.Append(KGetChildIdsQuery1);
+ queryBuf.AppendNum(driveId);
+ queryBuf.Append(KGetChildIdsQuery2);
+ queryBuf.AppendNum(aParentId);
+ queryBuf.Append(KGetChildIdsQuery3);
+
+ //Prepare a statement for the query.
+ RSqlStatement getStmt;
+ CleanupClosePushL(getStmt);
+ User::LeaveIfError(getStmt.Prepare(iDatabase, queryBuf));
+
+ while(KSqlAtRow == getStmt.Next())
+ {
+ // Do not return non-standard visible folders from non-current drive.
+ // If it is a non-current drive...
+ if( (driveId != KCurrentDriveId) &&
+ // If it is a folder entry.
+ (KUidMsvFolderEntryValue == ColumnInt(getStmt, iTypeIndex[EGetChildIds])) &&
+ // If it is a visible folder.
+ (IsVisibleFolder(ColumnInt(getStmt, iDataIndex[EGetChildIds]))) &&
+ // If it is a non-standard folder.
+ (!IsStandardId(ColumnInt(getStmt, iIdIndex[EGetChildIds])))
+ )
+ {
+ continue;
+ }
+
+ TMsvId id = ColumnInt(getStmt, iIdIndex[EGetChildIds]);
+ if(!IsStandardId(id))
+ {
+ id = MaskTMsvId(driveId, id);
+ }
+ //Add the child Id to the array given
+ aChildArray.AppendL(id);
+ }
+
+ CleanupStack::PopAndDestroy(2); //getStmt, queryBuf
+ }
+
+
+
+
+/**
+ * GetChildrenL()
+* @param const TDesC&: Partial query string. (Where clause condition).
+ * The query string should start with 'AND' and should
+ * end with a semicolon. Examples are:
+ * "AND ID BETWEEN 100 and 200 ORDER BY ID ASC;"
+ * @param TMsvId: Parent Id of the child entries to be fetched.
+ * @param RPointerArray<TMsvEntry>&: List of child entries to be filled.
+ * @return None.
+ *
+ * Fetch child entries from the database for a given parent Id.
+ * This does not check if the parent entry already exist. The
+ * entries will be added in ascending order of their TMsvId.
+ */
+void CMsvDBAdapter::GetChildrenL(const TDesC8& aQueryStr, TMsvId aParentId, RPointerArray<CMsvCacheEntry>& aChildArray)
+ {
+ _LIT8(KQueryString1, "SELECT id, serviceId, mtmId, type, date, data, size, error, "
+ "mtmData1, mtmData2, mtmData3, relatedId, bioType, pcSyncCount, "
+ "reserved, visibleParent, description, details FROM DB");
+ _LIT8(KQueryString2, ".IndexEntry WHERE parentId = ");
+
+ //Get the driveId and unmask the TMsvId supplied.
+ TInt driveId = GetDriveId(aParentId);
+ aParentId = UnmaskTMsvId(aParentId);
+
+ //Construct a query for the particular drive.
+ TInt len = KQueryString1().Length() + KQueryString2().Length() + aQueryStr.Length();
+ len += 30;
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(len);
+ queryBuf.Append(KQueryString1);
+ queryBuf.AppendNum(driveId);
+ queryBuf.Append(KQueryString2);
+ queryBuf.AppendNum(aParentId);
+ queryBuf.Append(aQueryStr);
+
+ //Prepare a statement for the query.
+ RSqlStatement condGetChildrenStmnt;
+ CleanupClosePushL(condGetChildrenStmnt);
+
+ User::LeaveIfError(condGetChildrenStmnt.Prepare(iDatabase, queryBuf));
+ TInt index = 0;
+
+ while(KSqlAtRow == condGetChildrenStmnt.Next())
+ {
+ TInt type = ColumnInt(condGetChildrenStmnt, 3);
+ TInt32 data = ColumnInt(condGetChildrenStmnt, 5);
+
+ // Do not return non-standard visible folders from non-current drive.
+ // If it is a non-current drive...
+ if( (driveId != KCurrentDriveId) &&
+ // If it is a folder entry.
+ (KUidMsvFolderEntryValue == type) &&
+ // If it is a visible folder.
+ (IsVisibleFolder(data)) &&
+ // If it is a non-standard folder.
+ (!IsStandardId(ColumnInt(condGetChildrenStmnt, 0)))
+ )
+ {
+ continue;
+ }
+
+ CMsvCacheEntry* cacheEntry = CMsvEntryFreePool::Instance()->EntryL();
+ if(!IsStandardId(aParentId))
+ {
+ aParentId = MaskTMsvId(driveId, aParentId);
+ }
+ cacheEntry->Entry().iParentId = aParentId;
+
+ index = 0;
+ TMsvId id = ColumnInt(condGetChildrenStmnt, index);
+ if(IsStandardId(id))
+ {
+ cacheEntry->Entry().iId = id;
+ }
+ else
+ {
+ cacheEntry->Entry().iId = MaskTMsvId(driveId, id);
+ }
+ cacheEntry->Entry().iServiceId = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iMtm.iUid = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iType.iUid = type;
+ cacheEntry->Entry().iDate = ColumnInt64(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iData = data;
+ cacheEntry->Entry().iSize = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iError = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iMtmData1 = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iMtmData2 = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iMtmData3 = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iRelatedId = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iBioType = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iPcSyncCount = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iReserved = ColumnInt(condGetChildrenStmnt, ++index);
+ TMsvId aVisibleParentEntryId = ColumnInt(condGetChildrenStmnt, ++index);
+
+ cacheEntry->iDescriptionBuffer = ColumnTextL(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iDescription.Set(*cacheEntry->iDescriptionBuffer);
+
+ cacheEntry->iDetailsBuffer = ColumnTextL(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iDetails.Set(*cacheEntry->iDetailsBuffer);
+
+
+ // Mask iServiceId if it is a non-standard id.
+ if(!IsStandardId(cacheEntry->Entry().iServiceId))
+ {
+ cacheEntry->Entry().iServiceId = MaskTMsvId(driveId, cacheEntry->Entry().iServiceId);
+ }
+
+ // Mask iRelatedId if it is a non-standard id.
+ if(!IsStandardId(cacheEntry->Entry().iRelatedId))
+ {
+ cacheEntry->Entry().iRelatedId = MaskTMsvId(driveId, cacheEntry->Entry().iRelatedId);
+ }
+
+ //Add the child entry to the array given
+ aChildArray.AppendL(cacheEntry);
+ }
+ CleanupStack::PopAndDestroy(2); // condGetChildrenStmnt,queryBuf
+ }
+
+
+
+
+/**
+ * EntryExistsL()
+ * @param TMsvId: Entry Id to check.
+ * @return TBool: ETrue if the entry exists, otherwise EFalse.
+ *
+ * Checks if an entry with the specified TMsvId exists in the database.
+ */
+TBool CMsvDBAdapter::EntryExistsL(TMsvId aId)
+ {
+ _LIT8(KEntryExistsQuery1, "SELECT id FROM DB");
+ _LIT8(KEntryExistsQuery2, ".IndexEntry WHERE id = ");
+
+ //Get the driveId and unmask the TMsvId supplied.
+ TInt driveId = GetDriveId(aId);
+ aId = UnmaskTMsvId(aId);
+
+ //Construct a query for the particular drive.
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ TInt len = KEntryExistsQuery1().Length() + 10 + KEntryExistsQuery2().Length(); //10 = space for TMsvId
+ queryBuf.CreateL(len);
+ queryBuf.Append(KEntryExistsQuery1);
+ queryBuf.AppendNum(driveId);
+ queryBuf.Append(KEntryExistsQuery2);
+ queryBuf.AppendNum(aId);
+ queryBuf.Append(KDelimiter);
+
+ TSqlScalarFullSelectQuery query(iDatabase);
+ TMsvId id = NULL;
+ TRAPD(err, id = query.SelectIntL(queryBuf));
+
+ CleanupStack::PopAndDestroy(); //queryBuf
+ if(err!= KErrNone && err!= KErrNotFound)
+ {
+ User::Leave(err);
+ }
+ if(id)
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+
+
+
+
+/**
+ * GetInPreparationIdL()
+ * @param CMsvEntrySelection&: List of the TMsvEntries
+ * whose KMsvEntryInPreparationFlag is set.
+ * @return None.
+ *
+ * Gets the TMsvId's of all the entries whose KMsvEntryInPreparationFlag
+ * is set in the database.
+ */
+void CMsvDBAdapter::GetInPreparationIdL(CMsvEntrySelection& aSelection, TUint aDriveId /* DEFAULT = 0 */)
+ {
+ if(aDriveId)
+ {
+ DoGetInPreparationIdL(aSelection, aDriveId);
+ }
+ else
+ {
+ //Iterate through all the dives that might have a database.
+ for(TInt driveId = 1; driveId < KMaxNumberOfDrives; ++driveId)
+ {
+ DoGetInPreparationIdL(aSelection, driveId);
+ }
+ }
+ }
+
+
+
+
+void CMsvDBAdapter::DoGetInPreparationIdL(CMsvEntrySelection& aSelection, TUint aDriveId)
+ {
+ _LIT8(KGetInPreparationIdQuery1, "SELECT id, data FROM DB");
+ _LIT8(KGetInPreparationIdQuery2, ".IndexEntry;");
+
+ TInt paramIdColumn = 0;
+ TInt paramDataColumn = 1;
+
+ //Check if the drive has the database present.
+ //The iDatabasePresent array will have a value for only those driveIds which
+ //have been added through AttachDBL().
+ if((*iDatabasePresent)[aDriveId])
+ {
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(40);
+ queryBuf.Append(KGetInPreparationIdQuery1);
+ queryBuf.AppendNum(aDriveId);
+ queryBuf.Append(KGetInPreparationIdQuery2);
+
+ RSqlStatement statement;
+ CleanupClosePushL(statement);
+ User::LeaveIfError(statement.Prepare(iDatabase, queryBuf));
+
+ TMsvId id;
+ TInt32 data;
+ while (KSqlAtRow == statement.Next())
+ {
+ data = ColumnInt(statement, paramDataColumn);
+ if( data & TMsvEntry::KMsvEntryInPreparationFlag )
+ {
+ id = ColumnInt(statement, paramIdColumn);
+ if(!IsStandardId(id))
+ {
+ id = MaskTMsvId(aDriveId, id);
+ }
+ aSelection.AppendL(id);
+ }
+ }
+ CleanupStack::PopAndDestroy(2); //statement, queryBuf
+ }
+ }
+
+
+
+
+/**
+ * GetVisibleFlagL()
+ * @param TMsvId: the Id of the entry whose flag is to be checked.
+ * @return TBool: ETrue if the entry is visible, EFalse otherwise.
+ *
+ * Returns the status of the visible flag of an entry in the DB.
+ */
+TBool CMsvDBAdapter::GetVisibleFlagL(TMsvId aEntryId)
+ {
+ _LIT8(KGetVisibleFlagQuery1, "SELECT data FROM DB");
+ _LIT8(KGetVisibleFlagQuery2, ".IndexEntry WHERE id = ");
+
+ //Get the driveId and unmask the TMsvId supplied.
+ TInt driveId = GetDriveId(aEntryId);
+ aEntryId = UnmaskTMsvId(aEntryId);
+
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(60);
+ queryBuf.Append(KGetVisibleFlagQuery1);
+ queryBuf.AppendNum(driveId);
+ queryBuf.Append(KGetVisibleFlagQuery2);
+ queryBuf.AppendNum(aEntryId);
+ queryBuf.Append(KDelimiter);
+
+ TSqlScalarFullSelectQuery query(iDatabase);
+ TInt32 data = query.SelectIntL(queryBuf);
+ CleanupStack::PopAndDestroy(); // queryBuf
+ if(data & TMsvEntry::KMsvEntryInvisibleFlag )
+ {
+ return EFalse;
+ }
+ else
+ {
+ return ETrue;
+ }
+ }
+
+
+
+
+/**
+ * UpdateVisibleFolderL()
+ * @param CMsvEntrySelection*: List of entries whose visible parent is
+ * to be updated.
+ * @param TMsvId: The new visible folder Id.
+ * @return None.
+ *
+ * Updates the visible parent of the entries passed through the selection.
+ */
+ void CMsvDBAdapter::UpdateVisibleFolderL(CMsvEntrySelection* aEntryList, TMsvId aNewVisibleFolderId)
+ {
+ _LIT8(KUpdateVisibleFolderQuery1, "UPDATE DB");
+ _LIT8(KUpdateVisibleFolderQuery2, ".IndexEntry SET visibleParent = ");
+ _LIT8(KUpdateVisibleFolderQuery3, " WHERE id IN ( ");
+ _LIT8(KEndDelimiter, ");");
+
+ TInt count = aEntryList->Count();
+ if(0 == count)
+ {
+ return;
+ }
+
+ //Get the driveId and unmask the TMsvId supplied.
+ aNewVisibleFolderId = UnmaskTMsvId(aNewVisibleFolderId);
+ CMsvEntrySelection* list = aEntryList->CopyL();
+ CleanupStack::PushL(list);
+
+#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+ TInt maxEntries = 50; //for testing
+#else
+ TInt maxEntries = 100;
+#endif
+
+ BeginTransactionL();
+ for(TInt index1 = 0; index1<count; ++index1)
+ {
+ TInt driveId = GetDriveId(list->At(index1));
+
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(50 + ((10+2)*maxEntries));
+ queryBuf.Append(KUpdateVisibleFolderQuery1);
+ queryBuf.AppendNum(driveId);
+ queryBuf.Append(KUpdateVisibleFolderQuery2);
+ queryBuf.AppendNum(aNewVisibleFolderId);
+ queryBuf.Append(KUpdateVisibleFolderQuery3);
+ queryBuf.AppendNum(UnmaskTMsvId(list->At(index1)));
+ TInt num = 1;
+ for(TInt index2 = index1 + 1; index2<count && num<maxEntries; ++index2)
+ {
+ if(driveId == GetDriveId(list->At(index2)))
+ {
+ queryBuf.Append(KComma);
+ queryBuf.AppendNum(UnmaskTMsvId(list->At(index2)));
+ ++num;
+ list->Delete(index2);
+ --index2;
+ --count;
+ }
+ }
+ list->Delete(index1);
+ --index1;
+ --count;
+ queryBuf.Append(KEndDelimiter);
+ TInt err = iDatabase.Exec(queryBuf);
+ CleanupStack::PopAndDestroy(); //queryBuf
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ }
+
+ CommitTransactionL();
+ CleanupStack::PopAndDestroy(); //list
+ }
+
+
+
+
+/**
+ * UpdateOwnerStatusL()
+ *
+ * @param TMsvId: the Id of an entry which has had a child added
+ * under it and needs its owner flag updated.
+ * @param const TMsvEntry&: the parent entry.
+ * @param TBool: ETrue if the owner flag should be set, EFalse if otherwise.
+ * @return None.
+ *
+ * The function updates the owner flag of an entry which has had a
+ * child added or deleted under it.
+ */
+void CMsvDBAdapter::UpdateOwnerStatusL(TMsvId aId, const TMsvEntry& aParent, TBool aSet)
+ {
+ _LIT8(KUpdateOwnershipQuery1, "UPDATE DB");
+ _LIT8(KUpdateOwnershipQuery2, ".IndexEntry SET data = ");
+ _LIT8(KUpdateOwnershipQuery3, " WHERE id = ");
+
+ // Owner flag has already been set. Return to caller.
+ if(aParent.Owner() && aSet)
+ {
+ return;
+ }
+ // Otherwise update the owner flag for the entry in the DB.
+ else
+ {
+ //Get the driveId and unmask the TMsvId supplied.
+ TInt driveId = GetDriveId(aId);
+ TMsvId parentId = UnmaskTMsvId(aId);
+
+ TInt32 data;
+ if(aSet)
+ {
+ data = aParent.iData | TMsvEntry::KMsvEntryOwnerFlag;
+ }
+ else
+ {
+ data = aParent.iData & ~(TMsvEntry::KMsvEntryOwnerFlag);
+ }
+ TInt len = KUpdateOwnershipQuery1().Length() + KUpdateOwnershipQuery2().Length();
+ len += KUpdateOwnershipQuery3().Length() + 100; //data and TMsvId.
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(len);
+ queryBuf.Append(KUpdateOwnershipQuery1);
+ queryBuf.AppendNum(driveId);
+ queryBuf.Append(KUpdateOwnershipQuery2);
+ queryBuf.AppendNum(data);
+ queryBuf.Append(KUpdateOwnershipQuery3);
+ queryBuf.AppendNum(parentId);
+ queryBuf.Append(KDelimiter);
+ TInt err = iDatabase.Exec(queryBuf);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ CleanupStack::PopAndDestroy(); //queryBuf
+ }
+ }
+
+
+
+
+#else // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+
+
+
+/**
+ * NewL()
+ * @param TFileName: DB File Name.
+ * @return The newly created database adapter object.
+ *
+ * The function creates a new secure database in syslib private folder.
+ * It takes database name as input arg and returns instance of
+ * DB adpater class.
+ */
+CMsvDBAdapter* CMsvDBAdapter::NewL(const TFileName& aDbFileName)
+ {
+ //Create an messaging DB adaptor object.
+ CMsvDBAdapter* self = new(ELeave) CMsvDBAdapter();
+ CleanupStack::PushL(self);
+
+ // Create the database.
+ TBool isDBCreated = EFalse;
+ TRAPD(err, self->ConstructNewL(aDbFileName, isDBCreated));
+ if( KErrNone != err )
+ {
+ if( isDBCreated )
+ {
+ DeleteDB(aDbFileName);
+ }
+ User::Leave(err);
+ }
+
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+
+
+/**
+ * OpenL()
+ * @param TFileName: DB File Name.
+ * @return The newly created database adapter object.
+ *
+ * The function opens an already existing database. The database file
+ * is searched in syslib private folder. It takes database name as
+ * input arg and returns instance of DB adpater class. The function
+ * leaves if the DB file is not found or if the file is corrupted.
+ */
+CMsvDBAdapter* CMsvDBAdapter::OpenL(const TFileName& aDbFileName)
+ {
+ //Create an messaging DB adaptor object
+ CMsvDBAdapter* self = new(ELeave) CMsvDBAdapter();
+ CleanupStack::PushL(self);
+
+ // Open the database.
+ self->ConstructOpenL(aDbFileName);
+
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+
+
+/**
+ * DeleteDB()
+ * @param TFileName: DB File Name.
+ * @return error.
+ *
+ * This is a static function, hence can be called without creating
+ * an instance of this class. The function deletes the database
+ * file as mentioned in the input argument. The database file is
+ * searched in syslib private folder.
+ */
+TInt CMsvDBAdapter::DeleteDB(const TFileName& aDbFileName)
+ {
+ return RSqlDatabase::Delete(aDbFileName);
+ }
+
+
+
+
+/**
+ * ConstructOpenL()
+ * @param TFileName: DB File Name.
+ *
+ * This functions is called by OpenL() to open an existing database.
+ * The function leaves if there is an error while opening the DB with
+ * the leave code same as error code. It takes DB filename as input
+ * argument. The database file is searched in syslib private folder.
+ */
+void CMsvDBAdapter::ConstructOpenL(const TFileName& aDbFileName)
+ {
+ // >>> Pass configuration parameter, while opening the DB.
+ User::LeaveIfError(iDatabase.Open(aDbFileName));
+ ClearDBContentsL();
+ ConstructSortTableL();
+
+ //Initialize the database adapter class
+ InitializeL();
+
+ //Initialize the Search Sort database adapter class
+ InitializeSortTableL();
+ }
+
+
+
+
+/**
+ * ConstructNewL()
+ * @param TFileName: DB File Name.
+ *
+ * This functions is called by NewL() to create a new database.
+ * The function leaves if there is an error while creating the DB with
+ * the leave code same as error code. It takes DB filename as input
+ * argument. The database file is created in syslib private folder.
+ * It then create standard tables as well as indexes in the database.
+ */
+void CMsvDBAdapter::ConstructNewL(const TFileName& aDbFileName, TBool& aIsDBCreated)
+ {
+ HBufC8* heapBuf = KEncodingText().AllocLC();
+
+ //Create the database.
+#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+ User::LeaveIfError(iDatabase.Create(aDbFileName, heapBuf));
+#else
+ // Using SID based security policy.
+ TSecureId sid(SERVER_UID);
+ const TSecurityPolicy KDefaultPolicy(sid);
+
+ //Create security policy
+ RSqlSecurityPolicy securityPolicy;
+ CleanupClosePushL(securityPolicy);
+
+ User::LeaveIfError(securityPolicy.Create(KDefaultPolicy));
+ User::LeaveIfError(iDatabase.Create(aDbFileName, securityPolicy, heapBuf));
+
+ // Destroy securityPolicy.
+ CleanupStack::PopAndDestroy();
+#endif // #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+
+ // Destroy heapBuf
+ CleanupStack::PopAndDestroy();
+ aIsDBCreated = ETrue;
+
+ //Create tables for the database
+ TInt err = iDatabase.Exec(KCreateIndexEntryTableQuery);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ User::Leave(KErrGeneral);
+ }
+
+ //Create index on indexEnty table.
+ //Index is created on parentId.
+ err = iDatabase.Exec(KCreateIndexQuery);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ User::Leave(KErrGeneral);
+ }
+
+ //Create the version table to store the message store version.
+ err = iDatabase.Exec(KCreateVersionTableQuery);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ User::Leave(KErrGeneral);
+ }
+ //Insert the version number into the above table.
+ _LIT8(KInsertVersionNumberQuery, " INSERT INTO VersionTable Values ( " );
+ _LIT8(KDelimiter, " );");
+ RBuf8 versionQuery;
+ CleanupClosePushL(versionQuery);
+ versionQuery.CreateL(50); //a small value is more than enough for the above query.
+ versionQuery.Append(KInsertVersionNumberQuery);
+ versionQuery.AppendNum(KCurrentDatabaseVersion);
+ versionQuery.Append(KDelimiter);
+ err = iDatabase.Exec(versionQuery);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ User::Leave(KErrGeneral);
+ }
+ CleanupStack::PopAndDestroy(); //versionQuery
+
+ ConstructSortTableL();
+
+ //Initialize the database adapter class
+ InitializeL();
+
+ //Initialize the Search Sort database adapter class
+ InitializeSortTableL();
+ }
+
+
+
+
+/**
+ * GetVisibleFolderIdL()
+ * @param TMsvId: Parent Id.
+ * @return Most immediate visible folder id of any child entry
+ * present under passed parent id.
+ *
+ * This functions returns the most immediate parent visible folder id.
+ * There are two types of folders. A visible folder is one which is
+ * visible to the external user, but there are internal non-visible folders
+ * created under each email message to organize the content of the email.
+ * Parent entry of an entry is either root or a folder. A folder can be
+ * service folder (like LocalServices), userdefined folder/standard folder
+ * like Inbox or a non-visible folder (created under an email message).
+ *
+ * For a given parent Id, the function returns the most immediate visible
+ * parent folder. The rules are as follows:
+ * 1. If the parent entry is root or children of root, then the visibleFolder
+ * will be root itself. This is because service folders are considered
+ * invisible, since they are not seen by user.
+ * 2. If the parent entry itself is a visible folder then child's visibleFolder
+ * id should be its parent id.
+ * 3. If the parent entry is a non-visible folder then child's visibleFolder
+ * id is same as its parent's visibleFolder id.
+ */
+void CMsvDBAdapter::GetVisibleFolderIdL(TMsvId aParentId, TMsvId& aVisibleFolderId)
+ {
+ // If the entry is either a root entry (parent=KErrNotFound) or
+ // child of root entry its visibleFolderId will be root entry itself.
+ if((KErrNotFound == aParentId) || (KMsvRootIndexEntryId == aParentId))
+ {
+ aVisibleFolderId = KMsvRootIndexEntryId;
+ }
+ else
+ {
+ // Get the visible flag of parent entry.
+
+ // If parent entry is visible, then immediateVisibleFolder of child
+ // should be parent Id. And if it is invisible then child's immediateVisibleFolder
+ // should be same as parent's immediateVisibleFolder.
+
+ //Bind the msv id
+ BindIntL(iStatement[EGetVisibleId], iIdIndex[EGetVisibleId], aParentId);
+
+ // If parent entry does not exists leave with KErrNotFound.
+ if (KSqlAtRow != iStatement[EGetVisibleId].Next())
+ {
+ iStatement[EGetVisibleId].Reset();
+ User::Leave(KErrNotFound);
+ }
+
+ TInt32 data = ColumnInt(iStatement[EGetVisibleId], iDataIndex[EGetVisibleId]);
+ if( data & TMsvEntry::KMsvVisibleFolderNodeFlag)
+ {
+ // If visible folder flag is not set for parent entry.
+ aVisibleFolderId = ColumnInt(iStatement[EGetVisibleId], iVisibleParent[EGetVisibleId]);
+ }
+ else
+ {
+ // If parent entry is visible
+ aVisibleFolderId = aParentId;
+ }
+ //Reset the RSqlStatement
+ User::LeaveIfError(iStatement[EGetVisibleId].Reset());
+ }
+ }
+
+
+
+
+/**
+ * CreateEntryL()
+ * @param const TMsvEntry&: DB File Name.
+ * @return TMsvId: Immediate visible parent folder of the entry
+ *
+ * The function creates a new entry in the database. It gets the immediate
+ * visible folder id of the entry before inserting them into the database.
+ * No consisitency check is performed on the passed entry. The function may
+ * leave if query execution fails.
+ */
+void CMsvDBAdapter::CreateEntryL(const TMsvEntry& aNewEntry, const TMsvId aImmediateVisibleFolder)
+ {
+ //Bind the entry data
+ BindIntL(iStatement[ECreateEntry], iIdIndex[ECreateEntry], aNewEntry.iId);
+ BindIntL(iStatement[ECreateEntry], iParentIdIndex[ECreateEntry], aNewEntry.iParentId);
+ BindIntL(iStatement[ECreateEntry], iDataIndex[ECreateEntry], aNewEntry.iData);
+ BindIntL(iStatement[ECreateEntry], iPcSyncCountIndex[ECreateEntry], aNewEntry.iPcSyncCount);
+ BindIntL(iStatement[ECreateEntry], iReservedIndex[ECreateEntry], aNewEntry.iReserved);
+ BindIntL(iStatement[ECreateEntry], iRelatedIdIndex[ECreateEntry], aNewEntry.iRelatedId);
+ BindIntL(iStatement[ECreateEntry], iTypeIndex[ECreateEntry], aNewEntry.iType.iUid);
+ BindInt64L(iStatement[ECreateEntry], iDateIndex[ECreateEntry], aNewEntry.iDate.Int64());
+ BindIntL(iStatement[ECreateEntry], iSizeIndex[ECreateEntry], aNewEntry.iSize);
+ BindIntL(iStatement[ECreateEntry], iErrorIndex[ECreateEntry], aNewEntry.iError);
+ BindIntL(iStatement[ECreateEntry], iBiotypeIndex[ECreateEntry], aNewEntry.iBioType);
+ BindIntL(iStatement[ECreateEntry], iMtmData1Index[ECreateEntry], aNewEntry.iMtmData1);
+ BindIntL(iStatement[ECreateEntry], iMtmData2Index[ECreateEntry], aNewEntry.iMtmData2);
+ BindIntL(iStatement[ECreateEntry], iMtmData3Index[ECreateEntry], aNewEntry.iMtmData3);
+ BindIntL(iStatement[ECreateEntry], iServiceIdIndex[ECreateEntry], aNewEntry.iServiceId);
+ BindIntL(iStatement[ECreateEntry], iMtmIdIndex[ECreateEntry], aNewEntry.iMtm.iUid);
+ BindIntL(iStatement[ECreateEntry], iVisibleParent[ECreateEntry], aImmediateVisibleFolder);
+ BindTextL(iStatement[ECreateEntry],iDescriptionIndex[ECreateEntry],aNewEntry.iDescription);
+ BindTextL(iStatement[ECreateEntry],iDetailsIndex[ECreateEntry],aNewEntry.iDetails);
+ //Execute the prepared SQL statement.
+
+ TInt err = iStatement[ECreateEntry].Exec();
+ if(err < 0)
+ {
+ iStatement[ECreateEntry].Reset();
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ iStatement[ECreateEntry].Reset();
+ User::Leave(KErrGeneral);
+ }
+
+ //Reset the RSqlStatement
+ User::LeaveIfError(iStatement[ECreateEntry].Reset());
+ }
+
+
+
+
+/**
+ * UpdateEntryL()
+ * @param const TMsvEntry&: Entry to be updated.
+ * @param TBool: ETrue if the parent of the entry has been changed,
+ * EFalse if otherwise.
+ * @param TMsvId&: the visible folder Id of the updated entry.
+ * If aParentChanged is ETrue then aImmediateVisibleFolder
+ * is an output parameter, and input parameter if otherwise.
+ * @return None.
+ *
+ * The function updates an entry in the database. It gets the immediate
+ * visible folder id of the entry before inserting them into the database.
+ * No consisitency check is performed on the passed entry. The function may
+ * leave if query execution fails.
+ */
+void CMsvDBAdapter::UpdateEntryL(const TMsvEntry& aEntry, const TMsvId aImmediateVisibleFolder, const TBool aIsParentIdUpdated/*DEFAULT=ETrue*/)
+ {
+ iStatementType updateStmt;
+ //Bind the entry data
+ if(aIsParentIdUpdated)
+ {
+ updateStmt = EUpdateEntry;
+ BindIntL(iStatement[updateStmt], iParentIdIndex[updateStmt], aEntry.iParentId);
+ BindIntL(iStatement[updateStmt], iVisibleParent[updateStmt], aImmediateVisibleFolder);
+ }
+ else
+ {
+ updateStmt = EUpdateEntryNoParent;
+ }
+ BindIntL(iStatement[updateStmt], iIdIndex[updateStmt], aEntry.iId);
+ BindIntL(iStatement[updateStmt], iDataIndex[updateStmt], aEntry.iData);
+ BindIntL(iStatement[updateStmt], iPcSyncCountIndex[updateStmt], aEntry.iPcSyncCount);
+ BindIntL(iStatement[updateStmt], iReservedIndex[updateStmt], aEntry.iReserved);
+ BindIntL(iStatement[updateStmt], iRelatedIdIndex[updateStmt], aEntry.iRelatedId);
+ BindIntL(iStatement[updateStmt], iTypeIndex[updateStmt], aEntry.iType.iUid);
+ BindInt64L(iStatement[updateStmt], iDateIndex[updateStmt], aEntry.iDate.Int64());
+ BindIntL(iStatement[updateStmt], iSizeIndex[updateStmt], aEntry.iSize);
+ BindIntL(iStatement[updateStmt], iErrorIndex[updateStmt], aEntry.iError);
+ BindIntL(iStatement[updateStmt], iBiotypeIndex[updateStmt], aEntry.iBioType);
+ BindIntL(iStatement[updateStmt], iMtmData1Index[updateStmt], aEntry.iMtmData1);
+ BindIntL(iStatement[updateStmt], iMtmData2Index[updateStmt], aEntry.iMtmData2);
+ BindIntL(iStatement[updateStmt], iMtmData3Index[updateStmt], aEntry.iMtmData3);
+ BindIntL(iStatement[updateStmt], iServiceIdIndex[updateStmt], aEntry.iServiceId);
+ BindIntL(iStatement[updateStmt], iMtmIdIndex[updateStmt], aEntry.iMtm.iUid);
+ BindTextL(iStatement[updateStmt], iDescriptionIndex[updateStmt],aEntry.iDescription);
+ BindTextL(iStatement[updateStmt], iDetailsIndex[updateStmt],aEntry.iDetails);
+
+ //Execute the prepared SQL statement.
+ TInt err = iStatement[updateStmt].Exec();
+ if(err < 0)
+ {
+ iStatement[updateStmt].Reset();
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ iStatement[updateStmt].Reset();
+ User::Leave(KErrNotFound);
+ }
+
+ //Reset the RSqlStatement
+ User::LeaveIfError(iStatement[updateStmt].Reset());
+ }
+
+
+
+
+/**
+ * DeleteEntryL()
+ * @param TMsvId: Entry Id to be deleted.
+ *
+ * The function deletes an entry with the passed Id. The function
+ * may leave due to database error while execution. The function
+ * does not leave if the entry does not exist.
+ *
+ * **WARNING** The function does NOT ensure that if a parent entry
+ * is deleted all its child entries are also deleted.
+ */
+void CMsvDBAdapter::DeleteEntryL(TMsvId aEntryId)
+ {
+ _LIT8(KDeleteEntryQuery, "DELETE FROM IndexEntry WHERE id = ");
+ _LIT8(KSemiColon, ";");
+
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(KDeleteEntryQuery().Length() + 20);
+ queryBuf.Append(KDeleteEntryQuery);
+ queryBuf.AppendNum(aEntryId);
+ queryBuf.Append(KSemiColon);
+
+ TInt err = iDatabase.Exec(queryBuf);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ User::Leave(KErrNotFound);
+ }
+ CleanupStack::PopAndDestroy(); // queryBuf
+ }
+
+
+
+
+/**
+ * DeleteEntryL()
+ * @param CMsvEntrySelection: Entry Id list to be deleted.
+ *
+ * The function deletes all entries mentioned in the passed Id list.
+ * The function may leave due to database error while execution or
+ * if an entry does not exist.
+ *
+ * **WARNING** The function does NOT ensure that if a parent entry
+ * is deleted all its child entries are also deleted.
+ */
+void CMsvDBAdapter::DeleteEntryL(const CMsvEntrySelection& aEntryIdList)
+ {
+ TInt count;
+ if( 0 == (count = aEntryIdList.Count()) )
+ {
+ return;
+ }
+
+ _LIT(KQuery, "DELETE FROM IndexEntry WHERE id IN (");
+ _LIT(KComma, ", ");
+ _LIT(KEndDelimeter, ");");
+
+ RBuf8 buf;
+ CleanupClosePushL(buf);
+ TInt index = 0;
+ //Delete maximum 100 entries at a time so as to not overflow IPC buffer
+ TInt maxEntries = 100;
+ TInt iterRequired = count/maxEntries;
+ if(count%maxEntries)
+ {
+ iterRequired++;
+ }
+ if(iterRequired)
+ {
+ maxEntries = count/iterRequired;
+ }
+ for(TInt iter = 0; iter < iterRequired; ++iter)
+ {
+ if(iter && iter+1 == iterRequired)
+ {
+ maxEntries = count - index;
+ }
+ buf.CreateL( 40 + ((7 + 2) * maxEntries) + 2); //KQuery + (TMsvId+KComma)*100 + KEndDelimiter
+ buf.Append(KQuery);
+ TBool firstId = ETrue;
+ TInt num = 0;
+ while(num < maxEntries)
+ {
+ if(!firstId)
+ {
+ buf.Append(KComma);
+ }
+ firstId = EFalse;
+ buf.AppendNum(aEntryIdList.At(index));
+ ++index;
+ ++num;
+ }
+ buf.Append(KEndDelimeter);
+ User::LeaveIfError(iDatabase.Exec(buf));
+ buf.Close();
+ }
+ CleanupStack::PopAndDestroy(); //buf
+ }
+
+
+
+
+/**
+ * GetEntryL()
+ * @param TMsvId: Id of the entry to be fetched.
+ * @return TMsvId: Value of VisibleParent column.
+ * @return TMsvEntry*: The newly fetched entry.
+ *
+ * Fetch an entry from the database. Memory to aEntry
+ * should not already be assigned.
+ */
+void CMsvDBAdapter::GetEntryL(TMsvId aId, CMsvCacheEntry*& aEntry, TMsvId& aVisibleParentEntryId)
+ {
+ //Bind the msv id of the entry to be retrieved
+ BindIntL(iStatement[EGetEntry], iIdIndex[EGetEntry], aId);
+
+ if (KSqlAtRow != iStatement[EGetEntry].Next())
+ {
+ iStatement[EGetEntry].Reset();
+ User::Leave(KErrNotFound);
+ }
+
+ //Get the entry from the statement
+ aEntry = CMsvEntryFreePool::Instance()->EntryL();
+ aEntry->Entry().iId = aId;
+ LoadEntryFromStatementL(iStatement[EGetEntry], EGetEntry, aVisibleParentEntryId, *aEntry);
+
+ //Reset the RSqlStatement
+ User::LeaveIfError(iStatement[EGetEntry].Reset());
+ }
+
+
+
+
+/**
+ * GetChildrenL()
+ * @param TMsvId: Parent Id of the child entries to be fetched.
+ * @return RPointerArray<TMsvEntry>&: List of child entries.
+ *
+ * Fetch child entries from the database for a given parent Id.
+ * This does not check if the parent entry already exist. The
+ * entries will be added in ascending order of their TMsvId.
+ */
+void CMsvDBAdapter::GetChildrenL(TMsvId aParentId, RPointerArray<CMsvCacheEntry>& aChildArray)
+ {
+ //Bind the msv id of the entry whose children have to be retrieved
+ BindIntL(iStatement[EGetChildEntries], iParentIdIndex[EGetChildEntries], aParentId);
+
+ while(KSqlAtRow == iStatement[EGetChildEntries].Next())
+ {
+ TMsvId aVisibleParentEntryId;
+ CMsvCacheEntry *cacheEntry = CMsvEntryFreePool::Instance()->EntryL();
+ cacheEntry->Entry().iParentId = aParentId;
+ LoadEntryFromStatementL(iStatement[EGetChildEntries], EGetChildEntries, aVisibleParentEntryId, *cacheEntry);
+ //Add the child entry to the array given
+ aChildArray.AppendL(cacheEntry);
+ }
+
+ //Reset the RSqlStatement
+ User::LeaveIfError(iStatement[EGetChildEntries].Reset());
+ }
+
+
+
+
+/**
+ * GetChildrenIdL()
+ * @param TMsvId: Parent Id of the child entries to be fetched.
+ * @return RPointerArray<TMsvEntry>&: List of child entries.
+ *
+ * Fetch child entries from the database for a given parent Id.
+ * This does not check if the parent entry already exist. The
+ * entries will be added in ascending order of their TMsvId.
+ */
+void CMsvDBAdapter::GetChildrenIdL(TMsvId aParentId, CMsvEntrySelection& aChildArray)
+ {
+ //Bind the msv id of the entry whose children have to be retrieved
+ BindIntL(iStatement[EGetChildIds], iParentIdIndex[EGetChildIds], aParentId);
+
+ while(KSqlAtRow == iStatement[EGetChildIds].Next())
+ {
+ TMsvId id = ColumnInt(iStatement[EGetChildIds], iIdIndex[EGetChildIds]);
+ //Add the child Id to the array given
+ aChildArray.AppendL(id);
+ }
+
+ //Reset the RSqlStatement
+ User::LeaveIfError(iStatement[EGetChildIds].Reset());
+ }
+
+
+
+
+/**
+ * GetChildrenL()
+ * @param TDesc: Partial query string. (Where clause condition).
+ * The query string should start with 'AND' and should
+ * end with a semicolon. Examples are:
+ * "AND ID BETWEEN 100 and 200 ORDER BY ID ASC;"
+ * @param TMsvId: Parent Id of the child entries to be fetched.
+ * @return RPointerArray<TMsvEntry>&: List of child entries.
+ *
+ * Fetch child entries from the database for a given parent Id.
+ * This does not check if the parent entry already exist. The
+ * entries will be added in ascending order of their TMsvId.
+ */
+void CMsvDBAdapter::GetChildrenL(const TDesC8& aQueryStr, TMsvId aParentId, RPointerArray<CMsvCacheEntry>& aChildArray)
+ {
+ _LIT8(KQueryString, "SELECT id, serviceId, mtmId, type, date, data, size, error, "
+ "mtmData1, mtmData2, mtmData3, relatedId, bioType, pcSyncCount, "
+ "reserved, visibleParent, description, details FROM IndexEntry "
+ "WHERE parentId = :parentId ");
+
+ RSqlStatement condGetChildrenStmnt;
+ CleanupClosePushL(condGetChildrenStmnt);
+ TInt len = KQueryString().Length() + aQueryStr.Length();
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(len);
+ queryBuf.Append(KQueryString);
+ queryBuf.Append(aQueryStr);
+
+ User::LeaveIfError(condGetChildrenStmnt.Prepare(iDatabase, queryBuf));
+ TInt index = 0;
+
+ //Bind the msv id of the entry whose children have to be retrieved
+ BindIntL(condGetChildrenStmnt, index, aParentId);
+
+ while(KSqlAtRow == condGetChildrenStmnt.Next())
+ {
+ CMsvCacheEntry* cacheEntry = CMsvEntryFreePool::Instance()->EntryL();
+ cacheEntry->Entry().iParentId = aParentId;
+
+ index = 0;
+ cacheEntry->Entry().iId = ColumnInt(condGetChildrenStmnt, index);
+ cacheEntry->Entry().iServiceId = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iMtm.iUid = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iType.iUid = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iDate = ColumnInt64(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iData = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iSize = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iError = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iMtmData1 = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iMtmData2 = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iMtmData3 = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iRelatedId = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iBioType = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iPcSyncCount = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iReserved = ColumnInt(condGetChildrenStmnt, ++index);
+ TMsvId aVisibleParentEntryId = ColumnInt(condGetChildrenStmnt, ++index);
+ cacheEntry->iDescriptionBuffer = ColumnTextL(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iDescription.Set(*cacheEntry->iDescriptionBuffer);
+
+ cacheEntry->iDetailsBuffer = ColumnTextL(condGetChildrenStmnt, ++index);
+ cacheEntry->Entry().iDetails.Set(*cacheEntry->iDetailsBuffer);
+
+ //Add the child entry to the array given
+ aChildArray.AppendL(cacheEntry);
+ }
+ CleanupStack::PopAndDestroy(2); // condGetChildrenStmnt,queryBuf
+ }
+
+
+
+
+/**
+ * EntryExistsL()
+ * @param TMsvId: Entry Id to check.
+ * @return TBool: ETrue if the entry exists, otherwise EFalse.
+ */
+TBool CMsvDBAdapter::EntryExistsL(TMsvId aId)
+ {
+ _LIT8(KEntryExistsQuery, "SELECT id FROM IndexEntry WHERE id = ");
+ _LIT8(KEndDelimeter, ";");
+
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ TInt len = KEntryExistsQuery().Length() + 10 + KEndDelimeter().Length(); //10 = space for TMsvId
+ queryBuf.CreateL(len);
+ queryBuf.Append(KEntryExistsQuery);
+ queryBuf.AppendNum(aId);
+ queryBuf.Append(KEndDelimeter);
+ TSqlScalarFullSelectQuery query(iDatabase);
+ TMsvId id = NULL;
+ TRAPD(err, id = query.SelectIntL(queryBuf));
+ CleanupStack::PopAndDestroy(); // queryBuf
+ if(err!= KErrNone && err!= KErrNotFound)
+ {
+ User::Leave(err);
+ }
+ if(id)
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+
+
+
+
+/**
+ * GetMaxTMsvIdL()
+ * @param TMsvId&: Out parameter for maximum TMsvId in the database.
+ * @return None.
+ *
+ * If there are no entries in the database (DB is empty),
+ * the aMaxTMsvId is set to NULL.
+ */
+void CMsvDBAdapter::GetMaxTMsvIdL(TMsvId& aMaxTMsvId)
+ {
+ _LIT8(KQuery, "SELECT MAX(id) FROM IndexEntry;");
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(35);
+ queryBuf.Append(KQuery);
+
+ //Create a select query
+ TSqlScalarFullSelectQuery query(iDatabase);
+
+ //Get the column data
+ aMaxTMsvId = query.SelectIntL(queryBuf);
+ CleanupStack::PopAndDestroy();
+ }
+
+
+
+
+/**
+ * GetInPreparationIdL()
+ * @param aSelection CMsvEntrySelection of the TMsvEntries
+ * whose KMsvEntryInPreparationFlag is set
+ * @return void
+ */
+void CMsvDBAdapter::GetInPreparationIdL(CMsvEntrySelection& aSelection)
+ {
+ RSqlStatement statement;
+ User::LeaveIfError(statement.Prepare(iDatabase, KGetInPreparationIdQuery));
+
+ TInt paramIdColumn = GetColumnIndexL(statement, KMsgColumnId());
+ TInt paramDataColumn = GetColumnIndexL(statement, KMsgColumnData());
+
+ TMsvId Id;
+ TInt32 data;
+ while (KSqlAtRow == statement.Next())
+ {
+ data = ColumnInt(statement, paramDataColumn);
+ if( data & TMsvEntry::KMsvEntryInPreparationFlag )
+ {
+ Id = ColumnInt(statement, paramIdColumn);
+ aSelection.AppendL(Id);
+ }
+ }
+ statement.Close();
+ }
+
+
+
+
+/**
+ * GetVisibleFlagL()
+ *@param TMsvId : the Id of the entry whose flag is to be checked.
+ *@return TBool : ETrue if the entry is visible, EFalse otherwise.
+ *
+ * Returns the status of the visible flag of an entry in the DB.
+ */
+TBool CMsvDBAdapter::GetVisibleFlagL(TMsvId entryId)
+ {
+ _LIT8(KGetVisibleFlagQuery, "SELECT data FROM IndexEntry "
+ "WHERE id = ");
+ _LIT8(KEndDelimeter, ";");
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(60);
+ queryBuf.Append(KGetVisibleFlagQuery);
+ queryBuf.AppendNum(entryId);
+ queryBuf.Append(KEndDelimeter);
+ TSqlScalarFullSelectQuery query(iDatabase);
+ TInt32 data = 0;
+ TRAPD(err, data = query.SelectIntL(queryBuf));
+ CleanupStack::PopAndDestroy(); //queryBuf
+ if(err!= KErrNone && err!= KErrNotFound)
+ {
+ User::Leave(err);
+ }
+ if(data & TMsvEntry::KMsvEntryInvisibleFlag )
+ {
+ return EFalse;
+ }
+ else
+ {
+ return ETrue;
+ }
+ }
+
+
+
+
+/**
+ * UpdateVisibleFolderL()
+ * @param RBuf8 : the ID's of the entries of whose visible parent is to
+ * be updated.
+ * @return None.
+ *
+ * Updates the visible parent of the entries passed through the RBuf* idList.
+ */
+ void CMsvDBAdapter::UpdateVisibleFolderL(CMsvEntrySelection* entryList, TMsvId newVisibleFolderId)
+ {
+ _LIT8(KUpdateVisibleFolderQuery1, "UPDATE IndexEntry SET "
+ "visibleParent = ");
+ _LIT8(KUpdateVisibleFolderQuery2, " WHERE id IN ( ");
+ _LIT8(KComma, ", ");
+ _LIT8(KDelimiter, ");");
+
+ BeginTransactionL();
+
+ TInt count = entryList->Count();
+ TInt arrIndex = 0;
+ while(arrIndex < count)
+ {
+ TInt len = KUpdateVisibleFolderQuery1().Length() + KUpdateVisibleFolderQuery2().Length();
+ TInt temp;
+ //Update 50 entries or lesser at a time.
+
+ TInt totalEntries = count - arrIndex;
+
+ if(totalEntries < 50)
+ {
+ len += totalEntries*12 + 15; //number of entries*length of a TMsvId + length of visibleParent id
+ temp = totalEntries;
+ }
+ else
+ {
+ len += 50*12 + 15; //number of entries*length of a TMsvId + length of visibleParent id
+ temp = 50;
+ }
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(len);
+ queryBuf.Append(KUpdateVisibleFolderQuery1);
+ queryBuf.AppendNum(newVisibleFolderId);
+ queryBuf.Append(KUpdateVisibleFolderQuery2);
+ TInt index = arrIndex;
+ for(; index < arrIndex + temp; ++index)
+ {
+ queryBuf.AppendNum(entryList->At(index));
+ if(index != arrIndex + temp - 1)
+ {
+ queryBuf.Append(KComma);
+ }
+ }
+ queryBuf.Append(KDelimiter);
+ arrIndex += temp;
+ TInt err = iDatabase.Exec(queryBuf);
+ CleanupStack::PopAndDestroy(); // queryBuf
+ if(err < 0)
+ {
+ RollbackTransactionL();
+ User::Leave(err);
+ }
+ else if(!err) //no entries updated
+ {
+ RollbackTransactionL();
+ User::Leave(KErrNotFound);
+ }
+ }
+ CommitTransactionL();
+ }
+
+
+
+
+/**
+ * UpdateOwnerStatusL()
+ *
+ * @param TMsvId : the Id of an entry which has had a child added
+ * under it and needs its owner flag updated.
+ * @return None.
+ *
+ * The function updates the owner flag of an entry which has had a
+ * child added under it.
+ */
+void CMsvDBAdapter::UpdateOwnerStatusL(TMsvId aId, const TMsvEntry& aParent, TBool aSet)
+ {
+ _LIT8(KUpdateOwnershipQuery1, "UPDATE IndexEntry SET "
+ " data = ");
+ _LIT8(KUpdateOwnershipQuery2, " WHERE id = ");
+ _LIT8(KDelimiter, ";");
+
+ // Owner flag has already been set. Return to caller.
+ if(aParent.Owner() && aSet)
+ {
+ return;
+ }
+ // Otherwise update the owner flag for the entry in the DB.
+ else
+ {
+ TInt32 data;
+ if(aSet)
+ {
+ data = aParent.iData | TMsvEntry::KMsvEntryOwnerFlag;
+ }
+ else
+ {
+ data = aParent.iData & ~(TMsvEntry::KMsvEntryOwnerFlag);
+ }
+ TInt len = KUpdateOwnershipQuery1().Length() + KUpdateOwnershipQuery2().Length();
+ len += 100; //data and TMsvId.
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(len);
+ queryBuf.Append(KUpdateOwnershipQuery1);
+ queryBuf.AppendNum(data);
+ queryBuf.Append(KUpdateOwnershipQuery2);
+ queryBuf.AppendNum(aId);
+ queryBuf.Append(KDelimiter);
+ TInt err = iDatabase.Exec(queryBuf);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ CleanupStack::PopAndDestroy(); //queryBuf
+ }
+ }
+
+
+
+#endif // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+
+
+
+/**
+ * InitializeL()
+ *
+ * This functions prepares (compiles) frequetly used SQL queries,
+ * and create indexes on the variable arguments. When the query
+ * needs to be executed, we just have to bind the variables with
+ * the values and execute them. This increases the performance of
+ * query execution.
+ */
+void CMsvDBAdapter::InitializeL()
+ {
+ //Prepare the frequently used SQL statements
+ User::LeaveIfError(iStatement[ECreateEntry].Prepare(iDatabase, KCreateEntryQuery));
+ User::LeaveIfError(iStatement[EUpdateEntry].Prepare(iDatabase, KUpdateEntryQuery));
+ User::LeaveIfError(iStatement[EUpdateEntryNoParent].Prepare(iDatabase, KUpdateEntryNoParentQuery));
+ User::LeaveIfError(iStatement[EGetEntry].Prepare(iDatabase, KGetEntryQuery));
+ User::LeaveIfError(iStatement[EGetChildEntries].Prepare(iDatabase, KGetChildEntriesQuery));
+ User::LeaveIfError(iStatement[EGetVisibleId].Prepare(iDatabase, KGetVisibleIdQuery));
+ User::LeaveIfError(iStatement[EEntryExists].Prepare(iDatabase, KGetEntryExistsQuery));
+ User::LeaveIfError(iStatement[EGetChildIds].Prepare(iDatabase, KGetChildIdsQuery));
+
+ //Get the indices - This maps the parameter name to its offset
+ //in the SQL statement templates.
+ for(TInt index = ECreateEntry; index < EIndexSentinel; ++index)
+ {
+ switch(index)
+ {
+ case ECreateEntry: // KCreateEntryQuery
+ case EUpdateEntry: // KUpdateEntryQuery
+ //For creating and updating entries
+ iParentIdIndex[index] = GetParamIndexL(iStatement[index], KMsgParamParentId());
+ iVisibleParent[index] = GetParamIndexL(iStatement[index], KMsgParamVisibleParent());
+ iIdIndex[index] = GetParamIndexL(iStatement[index], KMsgParamId());
+ iServiceIdIndex[index] = GetParamIndexL(iStatement[index], KMsgParamServiceId());
+ iMtmIdIndex[index] = GetParamIndexL(iStatement[index], KMsgParamMtmId());
+ iTypeIndex[index] = GetParamIndexL(iStatement[index], KMsgParamType());
+ iDateIndex[index] = GetParamIndexL(iStatement[index], KMsgParamDate());
+ iDataIndex[index] = GetParamIndexL(iStatement[index], KMsgParamData());
+ iSizeIndex[index] = GetParamIndexL(iStatement[index], KMsgParamSize());
+ iErrorIndex[index] = GetParamIndexL(iStatement[index], KMsgParamError());
+ iMtmData1Index[index] = GetParamIndexL(iStatement[index], KMsgParamMtmData1());
+ iMtmData2Index[index] = GetParamIndexL(iStatement[index], KMsgParamMtmData2());
+ iMtmData3Index[index] = GetParamIndexL(iStatement[index], KMsgParamMtmData3());
+ iRelatedIdIndex[index] = GetParamIndexL(iStatement[index], KMsgParamRelatedId());
+ iBiotypeIndex[index] = GetParamIndexL(iStatement[index], KMsgParamBiotype());
+ iPcSyncCountIndex[index] = GetParamIndexL(iStatement[index], KMsgParamPcSyncCount());
+ iReservedIndex[index] = GetParamIndexL(iStatement[index], KMsgParamReserved());
+ iDescriptionIndex[index] = GetParamIndexL(iStatement[index], KMsgParamDescriptionTxt());
+ iDetailsIndex[index] = GetParamIndexL(iStatement[index], KMsgParamDetailsTxt());
+ break;
+ case EUpdateEntryNoParent:
+ iVisibleParent[index] = GetParamIndexL(iStatement[index], KMsgParamVisibleParent());
+ iIdIndex[index] = GetParamIndexL(iStatement[index], KMsgParamId());
+ iServiceIdIndex[index] = GetParamIndexL(iStatement[index], KMsgParamServiceId());
+ iMtmIdIndex[index] = GetParamIndexL(iStatement[index], KMsgParamMtmId());
+ iTypeIndex[index] = GetParamIndexL(iStatement[index], KMsgParamType());
+ iDateIndex[index] = GetParamIndexL(iStatement[index], KMsgParamDate());
+ iDataIndex[index] = GetParamIndexL(iStatement[index], KMsgParamData());
+ iSizeIndex[index] = GetParamIndexL(iStatement[index], KMsgParamSize());
+ iErrorIndex[index] = GetParamIndexL(iStatement[index], KMsgParamError());
+ iMtmData1Index[index] = GetParamIndexL(iStatement[index], KMsgParamMtmData1());
+ iMtmData2Index[index] = GetParamIndexL(iStatement[index], KMsgParamMtmData2());
+ iMtmData3Index[index] = GetParamIndexL(iStatement[index], KMsgParamMtmData3());
+ iRelatedIdIndex[index] = GetParamIndexL(iStatement[index], KMsgParamRelatedId());
+ iBiotypeIndex[index] = GetParamIndexL(iStatement[index], KMsgParamBiotype());
+ iPcSyncCountIndex[index] = GetParamIndexL(iStatement[index], KMsgParamPcSyncCount());
+ iReservedIndex[index] = GetParamIndexL(iStatement[index], KMsgParamReserved());
+ iDescriptionIndex[index] = GetParamIndexL(iStatement[index], KMsgParamDescriptionTxt());
+ iDetailsIndex[index] = GetParamIndexL(iStatement[index], KMsgParamDetailsTxt());
+ break;
+ case EGetEntry: // KGetEntryQuery
+ //Read an entry from DB
+ iIdIndex[index] = GetParamIndexL(iStatement[index], KMsgParamId());
+ iParentIdIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnParentId());
+ iServiceIdIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnServiceId());
+ iMtmIdIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnMtmId());
+ iTypeIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnType());
+ iDateIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnDate());
+ iDataIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnData());
+ iSizeIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnSize());
+ iErrorIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnError());
+ iMtmData1Index[index] = GetColumnIndexL(iStatement[index], KMsgColumnMtmData1());
+ iMtmData2Index[index] = GetColumnIndexL(iStatement[index], KMsgColumnMtmData2());
+ iMtmData3Index[index] = GetColumnIndexL(iStatement[index], KMsgColumnMtmData3());
+ iRelatedIdIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnRelatedId());
+ iBiotypeIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnBiotype());
+ iPcSyncCountIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnPcSyncCount());
+ iReservedIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnReserved());
+ iVisibleParent[index] = GetColumnIndexL(iStatement[index], KMsgColumnVisibleParent());
+ iDescriptionIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnDescriptionTxt());
+ iDetailsIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnDetailsTxt());
+ break;
+ case EGetChildEntries: // KGetChildEntriesQuery
+ //Read child entries for a given parent Id.
+ iParentIdIndex[index] = GetParamIndexL(iStatement[index], KMsgParamParentId());
+ iIdIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnId());
+ iServiceIdIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnServiceId());
+ iMtmIdIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnMtmId());
+ iTypeIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnType());
+ iDateIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnDate());
+ iDataIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnData());
+ iSizeIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnSize());
+ iErrorIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnError());
+ iMtmData1Index[index] = GetColumnIndexL(iStatement[index], KMsgColumnMtmData1());
+ iMtmData2Index[index] = GetColumnIndexL(iStatement[index], KMsgColumnMtmData2());
+ iMtmData3Index[index] = GetColumnIndexL(iStatement[index], KMsgColumnMtmData3());
+ iRelatedIdIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnRelatedId());
+ iBiotypeIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnBiotype());
+ iPcSyncCountIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnPcSyncCount());
+ iReservedIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnReserved());
+ iVisibleParent[index] = GetColumnIndexL(iStatement[index], KMsgColumnVisibleParent());
+ iDescriptionIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnDescriptionTxt());
+ iDetailsIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnDetailsTxt());
+ break;
+ case EGetVisibleId: // KGetVisibleIdQuery
+ //For getting visible Id related information
+ iIdIndex[index] = GetParamIndexL(iStatement[index], KMsgParamId());
+ iDataIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnData());
+ iVisibleParent[index] = GetColumnIndexL(iStatement[index], KMsgColumnVisibleParent());
+ break;
+ case EEntryExists: // KGetEntryExistsQuery
+ //To check if an entry exists in DB.
+ iIdIndex[index] = GetParamIndexL(iStatement[index], KMsgParamId());
+ iParentIdIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnParentId());
+ break;
+ case EGetChildIds: // KGetChildIdsQuery
+ //To check if an entry exists in DB.
+ iParentIdIndex[index] = GetParamIndexL(iStatement[index], KMsgParamParentId());
+ iIdIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnId());
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ iTypeIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnType());
+ iDataIndex[index] = GetColumnIndexL(iStatement[index], KMsgColumnData());
+#endif
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+
+
+
+/**
+ * BeginTransactionL()
+ *
+ * Starts a new DB transaction.
+ */
+void CMsvDBAdapter::BeginTransactionL()
+ {
+ if(!isTransactionOpen)
+ {
+ _LIT8(KBeginTransaction, "BEGIN;");
+ User::LeaveIfError(iDatabase.Exec(KBeginTransaction));
+ isTransactionOpen = ETrue;
+ }
+ }
+
+
+
+
+/**
+ * CommitTransactionL()
+ *
+ * Commits an already opened transaction.
+ */
+void CMsvDBAdapter::CommitTransactionL()
+ {
+ if(isTransactionOpen)
+ {
+ _LIT8(KCommitTransaction, "COMMIT;");
+ isTransactionOpen = EFalse;
+ User::LeaveIfError(iDatabase.Exec(KCommitTransaction));
+ }
+ }
+
+
+/**
+ * RollbackTransactionL()
+ *
+ * Rollback an already opened transaction.
+ */
+void CMsvDBAdapter::RollbackTransactionL()
+ {
+ if(isTransactionOpen)
+ {
+ _LIT8(KRollbackTransaction, "ROLLBACK;");
+ isTransactionOpen = EFalse;
+ User::LeaveIfError(iDatabase.Exec(KRollbackTransaction));
+ }
+ }
+
+
+
+
+
+/**
+ * LoadEntryFromStatementL()
+ * @param RSqlStatement&: a reference to the RSqlStatement to work against.
+ * @param TInt: Index of the SQL statement.
+ * @param TMsvId&: Out parameter for value of VisibleParent column.
+ * @param CMsvCacheEntry&: The newly fetched entry to be filled.
+ * @return None.
+ *
+ * Creates a CMsvCacheEntry from the executed RSqlStatement.
+ */
+void CMsvDBAdapter::LoadEntryFromStatementL(RSqlStatement& aStmt, TInt aIndex, TMsvId& aVisibleParentEntryId, CMsvCacheEntry& aEntry)
+ {
+ if(EGetEntry != aIndex)
+ {
+ aEntry.Entry().iId = ColumnInt(aStmt, iIdIndex[aIndex]);
+ }
+ if(EGetChildEntries != aIndex)
+ {
+ aEntry.Entry().iParentId = ColumnInt(aStmt, iParentIdIndex[aIndex]);
+ }
+
+ aEntry.Entry().iData = ColumnInt(aStmt, iDataIndex[aIndex]);
+ aEntry.Entry().iPcSyncCount = ColumnInt(aStmt, iPcSyncCountIndex[aIndex]);
+ aEntry.Entry().iReserved = ColumnInt(aStmt, iReservedIndex[aIndex]);
+ aEntry.Entry().iRelatedId = ColumnInt(aStmt, iRelatedIdIndex[aIndex]);
+ aEntry.Entry().iType.iUid = ColumnInt(aStmt, iTypeIndex[aIndex]);
+ aEntry.Entry().iDate = ColumnInt64(aStmt, iDateIndex[aIndex]);
+ aEntry.Entry().iSize = ColumnInt(aStmt, iSizeIndex[aIndex]);
+ aEntry.Entry().iError = ColumnInt(aStmt, iErrorIndex[aIndex]);
+ aEntry.Entry().iBioType = ColumnInt(aStmt, iBiotypeIndex[aIndex]);
+ aEntry.Entry().iMtmData1 = ColumnInt(aStmt, iMtmData1Index[aIndex]);
+ aEntry.Entry().iMtmData2 = ColumnInt(aStmt, iMtmData2Index[aIndex]);
+ aEntry.Entry().iMtmData3 = ColumnInt(aStmt, iMtmData3Index[aIndex]);
+ aEntry.Entry().iServiceId = ColumnInt(aStmt, iServiceIdIndex[aIndex]);
+ aEntry.Entry().iMtm.iUid = ColumnInt(aStmt, iMtmIdIndex[aIndex]);
+ aEntry.iDescriptionBuffer = ColumnTextL(aStmt, iDescriptionIndex[aIndex]);
+ aEntry.Entry().iDescription.Set(*aEntry.iDescriptionBuffer);
+ aEntry.iDetailsBuffer = ColumnTextL(aStmt, iDetailsIndex[aIndex]);
+ aEntry.Entry().iDetails.Set(*aEntry.iDetailsBuffer);
+
+ //Get the visible parent id
+ aVisibleParentEntryId = ColumnInt(aStmt, iVisibleParent[aIndex]);
+ }
+
+
+
+
+/**
+ * GetNextSiblingL()
+ *
+ * @param TMsvId: TMsvId of the entry whose sibling id is to be found.
+ * @param TMsvId: TMsvId of the parent entry of aId.
+ * @param TMsvId&: TMsvId of the sibling of aId, this is an o/p parameter.
+ * @return TBool
+ *
+ * Gets the id of the sibling of aId.
+ */
+TBool CMsvDBAdapter::GetNextSiblingL(TMsvId aId,TMsvId aParentId,TMsvId& aNextSiblingId)
+ {
+ TBool foundSibling=EFalse;
+ //get all the children for this parent
+ CMsvEntrySelection* children=new(ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(children);
+ GetChildrenIdL(aParentId,*children);
+ TInt childCount=children->Count();
+
+ for(TInt i=0;i<childCount;++i)
+ {
+ if(children->At(i)==aId && i<childCount-1)
+ {
+ aNextSiblingId=children->At(i+1);
+ foundSibling=ETrue;
+ break;
+ }
+ }
+ CleanupStack::PopAndDestroy(children);
+ return foundSibling;
+ }
+
+
+
+/**
+ * GetFirstChildIdL()
+ *
+ * @param TMsvId: TMsvId of the parent entry of aId.
+ * @param TMsvId: TMsvId of the child of aParentId, this is an o/p parameter.
+ * @return TBool.
+ *
+ * Gets the id of first child of aParentId.
+ */
+TBool CMsvDBAdapter::GetFirstChildIdL(TMsvId aParentId,TMsvId& aFirstChild)
+ {
+ TBool foundChild=EFalse;
+ //get all the children for this parent
+ CMsvEntrySelection* children=new(ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(children);
+ GetChildrenIdL(aParentId,*children);
+ TInt childCount=children->Count();
+
+ if(childCount>0)
+ {
+ aFirstChild=children->At(0);
+ foundChild=ETrue;
+ }
+ CleanupStack::PopAndDestroy(children);
+ return foundChild;
+ }
+
+
+/**
+ * ConstructSortTableL()
+ * @param none.
+ * #return none.
+ *
+ * This functions is called to create a new table,
+ * which stores the information for the search/sort
+ * operations performed.
+ */
+void CMsvDBAdapter::ConstructSortTableL()
+ {
+
+ //Create Search Sort Cache table. This stores the results of
+ // search sort result
+ TInt err = iDatabase.Exec(KCreateSearchSortEntryTableQuery);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+#if(defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ if(err == 0)
+ {
+ ClearDBContentsL();
+ }
+#endif
+
+ //Create Unique index's on indexEnty table.
+ //Unique Index is created on all columns to defer duplicates.
+ err = iDatabase.Exec(KCreateSearchSortQuery);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ }
+
+
+
+
+/**
+ * InitializeSortTableL()
+ * @param none.
+ * #return none.
+ *
+ * This functions prepares (compiles) frequetly used SQL queries,
+ * and create indexes on the variable arguments. When the query
+ * needs to be executed, we just have to bind the variables with
+ * the values and execute them. This increases the performance of
+ * query execution.
+ */
+void CMsvDBAdapter::InitializeSortTableL()
+ {
+ //Prepare the frequently used SQL statements
+ User::LeaveIfError(iQueryStatement[EQueryCreateEntry].Prepare(iDatabase, KCreateQueryEntry));
+ User::LeaveIfError(iQueryStatement[EQueryGetEntryAsc].Prepare(iDatabase, KGetEntryAsc));
+ User::LeaveIfError(iQueryStatement[EQueryGetEntryDesc].Prepare(iDatabase, KGetEntryDesc));
+ User::LeaveIfError(iQueryStatement[EQueryGetEntryNumAsc].Prepare(iDatabase, KGetEntryNumAsc));
+ User::LeaveIfError(iQueryStatement[EQueryGetEntryNumDesc].Prepare(iDatabase, KGetEntryNumDesc));
+ User::LeaveIfError(iQueryStatement[EQueryGetLastNIdsAsc].Prepare(iDatabase, KGetLastNIdsAsc));
+ User::LeaveIfError(iQueryStatement[EQueryGetLastNIdsDesc].Prepare(iDatabase, KGetLastNIdsDesc));
+ User::LeaveIfError(iQueryStatement[EQueryGetLastNIdsNumAsc].Prepare(iDatabase, KGetLastNIdsNumAsc));
+ User::LeaveIfError(iQueryStatement[EQueryGetLastNIdsNumDesc].Prepare(iDatabase, KGetLastNIdsNumDesc));
+ User::LeaveIfError(iQueryStatement[EGetFolderIds].Prepare(iDatabase, KGetFolderIds));
+ User::LeaveIfError(iQueryStatement[EQueryCount].Prepare(iDatabase, KGetQueryCount));
+ User::LeaveIfError(iQueryStatement[EQueryIteratorNumAsc].Prepare(iDatabase, KGetIterResultCastAsc));
+ User::LeaveIfError(iQueryStatement[EQueryIteratorNumDesc].Prepare(iDatabase, KGetIterResultCastDesc));
+ User::LeaveIfError(iQueryStatement[EQueryIteratorAsc].Prepare(iDatabase, KGetIterResultAsc));
+ User::LeaveIfError(iQueryStatement[EQueryIteratorDesc].Prepare(iDatabase, KGetIterResultDesc));
+
+ //Get the indices - This maps the parameter name to its offset
+ //in the SQL statement templates.
+ for(TInt index = EQueryCreateEntry; index < EQuerySentinel; ++index)
+ {
+ switch(index)
+ {
+ case EQueryCreateEntry:
+ {
+ iQIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryQId());
+ iIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryTMsvId());
+ iSortfieldQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQuerySortfield());
+ break;
+ }
+
+ case EQueryGetEntryAsc:
+ {
+ iQIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryQId());
+ iIdQueryIndex[index] = GetColumnIndexL(iQueryStatement[index], KQueryColumnTMsvId());
+ break;
+ }
+
+ case EQueryGetEntryDesc:
+ {
+ iQIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryQId());
+ iIdQueryIndex[index] = GetColumnIndexL(iQueryStatement[index], KQueryColumnTMsvId());
+ break;
+ }
+
+ case EQueryGetEntryNumAsc:
+ {
+ iQIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryQId());
+ iIdQueryIndex[index] = GetColumnIndexL(iQueryStatement[index], KQueryColumnTMsvId());
+ break;
+ }
+
+ case EQueryGetEntryNumDesc:
+ {
+ iQIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryQId());
+ iIdQueryIndex[index] = GetColumnIndexL(iQueryStatement[index], KQueryColumnTMsvId());
+ break;
+ }
+
+ case EQueryGetLastNIdsAsc:
+ {
+ iRowIdIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryRowId());
+ iQIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryQId());
+ iIdQueryIndex[index] = GetColumnIndexL(iQueryStatement[index], KQueryColumnTMsvId());
+ break;
+ }
+
+ case EQueryGetLastNIdsDesc:
+ {
+ iRowIdIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryRowId());
+ iQIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryQId());
+ iIdQueryIndex[index] = GetColumnIndexL(iQueryStatement[index], KQueryColumnTMsvId());
+ break;
+ }
+
+ case EQueryGetLastNIdsNumAsc:
+ {
+ iRowIdIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryRowId());
+ iQIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryQId());
+ iIdQueryIndex[index] = GetColumnIndexL(iQueryStatement[index], KQueryColumnTMsvId());
+ break;
+ }
+
+ case EQueryGetLastNIdsNumDesc:
+ {
+ iRowIdIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryRowId());
+ iQIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryQId());
+ iIdQueryIndex[index] = GetColumnIndexL(iQueryStatement[index], KQueryColumnTMsvId());
+ break;
+ }
+
+ case EGetFolderIds:
+ {
+ iParentIdfield = GetParamIndexL(iQueryStatement[index], KMsgParamParentId());
+ iTMsvidfield = GetParamIndexL(iQueryStatement[index], KMsgParamType());
+ break;
+ }
+
+ case EQueryCount:
+ {
+ iQIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryQId());
+ break;
+ }
+
+ case EQueryIteratorNumAsc:
+ {
+ iQIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryQId());
+ iIterOffset[index] =GetParamIndexL(iQueryStatement[index], KOffset());
+ iIterLimit[index] =GetParamIndexL(iQueryStatement[index], KLimit());
+ break;
+ }
+
+ case EQueryIteratorNumDesc:
+ {
+ iQIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryQId());
+ iIterOffset[index] =GetParamIndexL(iQueryStatement[index], KOffset());
+ iIterLimit[index] =GetParamIndexL(iQueryStatement[index], KLimit());
+ break;
+ }
+
+ case EQueryIteratorAsc:
+ {
+ iQIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryQId());
+ iIterOffset[index] =GetParamIndexL(iQueryStatement[index], KOffset());
+ iIterLimit[index] =GetParamIndexL(iQueryStatement[index], KLimit());
+ break;
+ }
+
+ case EQueryIteratorDesc:
+ {
+ iQIdQueryIndex[index] = GetParamIndexL(iQueryStatement[index], KQueryQId());
+ iIterOffset[index] =GetParamIndexL(iQueryStatement[index], KOffset());
+ iIterLimit[index] =GetParamIndexL(iQueryStatement[index], KLimit());
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+ }
+
+
+
+
+/**
+ * CreateQueryEntryL()
+ * @param TInt&: The Id of the Search/Sort Query
+ * @param TMsvIdWithSortField&: Fields to be added under the query id specified
+ * @return none.
+ *
+ * This Function adds the Entries into the DB under the Queryid specified
+ */
+void CMsvDBAdapter::CreateQueryEntryL(const TInt& aQueryId,const TMsvIdWithSortField& aEntry)
+ {
+ //Bind the entry data
+ BindIntL(iQueryStatement[EQueryCreateEntry], iQIdQueryIndex[EQueryCreateEntry], aQueryId);
+
+ #if(defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ BindIntL(iQueryStatement[EQueryCreateEntry], iIdQueryIndex[EQueryCreateEntry], UnmaskTMsvId(aEntry.iMessageId));
+ #else
+ BindIntL(iQueryStatement[EQueryCreateEntry], iIdQueryIndex[EQueryCreateEntry], aEntry.iMessageId);
+ #endif
+
+
+ BindTextL(iQueryStatement[EQueryCreateEntry], iSortfieldQueryIndex[EQueryCreateEntry], aEntry.iContentMessagePart);
+
+ TInt err = iQueryStatement[EQueryCreateEntry].Exec();
+ if(err < 0)
+ {
+ iQueryStatement[EQueryCreateEntry].Reset();
+ User::Leave(err);
+ }
+
+ //Reset the RSqlStatement
+ User::LeaveIfError(iQueryStatement[EQueryCreateEntry].Reset());
+ }
+
+
+
+
+/**
+ * GetSortedEntriesL()
+ * @param TInt&: The Id of the Search/Sort Query
+ * @param RArray<TMsvIdWithSortField>&: this array will be filled with the resultant ids
+ * #param TBool: Order of the Sort operation, default value is EFalse which performs sort in Ascending order
+ * @return none.
+ *
+ * This Function retrieves all the ids under the specified Query Id
+ */
+void CMsvDBAdapter::GetSearchSortEntriesL(const TInt& aQueryId, RArray<TMsvId>& aEntrySelection, const TBool aOrder/*Default = EFalse*/,const TBool aSortAsInt/*Default = EFalse*/)
+ {
+ TInt sortOrder;
+ TMsvId entryId;
+
+ if(aSortAsInt)
+ {
+ if(aOrder)
+ {
+ sortOrder = EQueryGetEntryNumAsc;
+ }
+ else
+ {
+ sortOrder = EQueryGetEntryNumDesc;
+ }
+ }
+ else
+ {
+ if(aOrder)
+ {
+ sortOrder = EQueryGetEntryAsc;
+ }
+ else
+ {
+ sortOrder = EQueryGetEntryDesc;
+ }
+ }
+
+ //Bind the msv id of the entry to be retrieved
+ BindIntL(iQueryStatement[sortOrder], iQIdQueryIndex[sortOrder], aQueryId);
+
+ while(KSqlAtRow == iQueryStatement[sortOrder].Next())
+ {
+ entryId = ColumnInt(iQueryStatement[sortOrder], iIdQueryIndex[sortOrder]);
+
+ #if(defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ entryId = MaskTMsvId(KCurrentDriveId,entryId);
+ #endif
+
+ aEntrySelection.AppendL(entryId);
+ }
+
+ //Reset the RSqlStatement
+ User::LeaveIfError(iQueryStatement[sortOrder].Reset());
+ }
+
+
+
+
+/**
+ * GetLastNTMsvIdsfromTableL()
+ * @param TInt&: The Id of the Search/Sort Query
+ * @param RArray<TMsvIdWithSortField>&: this array will be filled with the resultant ids
+ * @param TInt aLastCount: The Number of entries from the last rowid to be fetched from
+ * @param TBool: Order of the Sort operation, default value is EFalse which performs sort in Ascending order
+ * @return none.
+ *
+ * This Function retrieves the last N ids under the specified Query Id
+ */
+void CMsvDBAdapter::GetLastNTMsvIdsfromTableL(const TInt& aQueryId, RArray<TMsvId>& aEntrySelection, TInt aLastCount, const TBool aOrder/*Default = ETrue*/,const TBool aSortAsInt/*Default = EFalse*/)
+ {
+ TInt sortOrder;
+ TMsvId entryId;
+
+ if(aSortAsInt)
+ {
+ if(aOrder)
+ {
+ sortOrder = EQueryGetLastNIdsAsc;
+ }
+ else
+ {
+ sortOrder = EQueryGetLastNIdsDesc;
+ }
+ }
+ else
+ {
+ if(aOrder)
+ {
+ sortOrder = EQueryGetLastNIdsNumAsc;
+ }
+ else
+ {
+ sortOrder = EQueryGetLastNIdsNumDesc;
+ }
+ }
+
+ //Bind the count value
+ BindIntL(iQueryStatement[sortOrder], iRowIdIndex[sortOrder], aLastCount);
+
+ //Bind the msv id of the entry to be retrieved
+ BindIntL(iQueryStatement[sortOrder], iQIdQueryIndex[sortOrder], aQueryId);
+
+ while(KSqlAtRow == iQueryStatement[sortOrder].Next())
+ {
+ entryId = ColumnInt(iQueryStatement[sortOrder], iIdQueryIndex[sortOrder]);
+
+ #if(defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ entryId = MaskTMsvId(KCurrentDriveId, entryId);
+ #endif
+
+ aEntrySelection.AppendL(entryId);
+ }
+
+ //Reset the RSqlStatement
+ User::LeaveIfError(iQueryStatement[sortOrder].Reset());
+ }
+
+
+
+
+/**
+ * DeleteTMsvIdFromAllQueriesL()
+ * @param TMsvId&: The id to be deleted
+ * @return none.
+ *
+ * This Function delete a id under all Queryid's
+ */
+void CMsvDBAdapter::DeleteTMsvIdFromAllQueriesL(const TMsvId& aId)
+ {
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(KDeleteId().Length() + 20);
+ queryBuf.Append(KDeleteId);
+ queryBuf.AppendNum(aId);
+ queryBuf.Append(KSemiColon);
+
+ TInt err = iDatabase.Exec(queryBuf);
+ CleanupStack::PopAndDestroy(); // queryBuf
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ }
+
+
+
+
+/**
+ * DeleteQueryFromTableL()
+ * @param TInt&: The Id of the Search/Sort Query
+ * @return none.
+ *
+ * This Function deletes a particular Query from DB
+ */
+void CMsvDBAdapter::DeleteQueryFromTableL(const TInt& aQueryId)
+ {
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(KDeleteQueryId().Length() + 20);
+ queryBuf.Append(KDeleteQueryId);
+ queryBuf.AppendNum(aQueryId);
+ queryBuf.Append(KSemiColon);
+
+ TInt err = iDatabase.Exec(queryBuf);
+ CleanupStack::PopAndDestroy(); // queryBuf
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ }
+
+
+
+
+/**
+ * DeleteTMsvIdFromQueryL()
+ * @param TInt&: The Id of the Search/Sort Query
+ * @param TMsvId&: The TMsvId of the entry to be deleted
+ * @return none.
+ *
+ * This Function deletes a particular id under the specified QueryId
+ */
+void CMsvDBAdapter::DeleteTMsvIdFromQueryL(const TInt& aQueryId,const TMsvId& aId)
+ {
+ RBuf8 queryBuf;
+ CleanupClosePushL(queryBuf);
+ queryBuf.CreateL(KDeleteQueryId().Length()+KAndId().Length() + 20);
+ queryBuf.Append(KDeleteQueryId);
+ queryBuf.AppendNum(aQueryId);
+ queryBuf.Append(KAndId);
+ queryBuf.AppendNum(aId);
+ queryBuf.Append(KSemiColon);
+
+ TInt err = iDatabase.Exec(queryBuf);
+ CleanupStack::PopAndDestroy(); // queryBuf
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ }
+
+
+
+
+/**
+ * AddEntriesfromIndexTableL()
+ * @param TDesC8&: The Query to fill the SearchSortTable with the IndexEntry
+ * @return number of entries successfully added.
+ *
+ * This Function fills the SearchSortTable with the query specified on the IndexEntryTable
+ */
+TInt CMsvDBAdapter::AddEntriesfromIndexTableL(const TDesC8& aQuery)
+ {
+ TInt err = iDatabase.Exec(aQuery);
+
+ TPtrC errMsg = iDatabase.LastErrorMessage();
+
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+
+ return err;
+ }
+
+
+
+
+/**
+ * ReturnIdCountInDBL()
+ * @param TInt&: The Id of the Search/Sort Query
+ * @return TInt: The number of entries stored under the QueryId specified
+ *
+ * This Function returns the number of id's stored under the specified QueryId
+ */
+TInt CMsvDBAdapter::ReturnIdCountInDBL(const TInt& aQueryId)
+ {
+ TInt count=0;
+ //Bind the msv id of the entry to be retrieved
+ BindIntL(iQueryStatement[EQueryCount], iQIdQueryIndex[EQueryCount], aQueryId);
+
+ while(KSqlAtRow == iQueryStatement[EQueryCount].Next())
+ {
+ count = ColumnInt(iQueryStatement[EQueryCount], iIdQueryIndex[EQueryCount]);
+ }
+
+ //Reset the RSqlStatement
+ User::LeaveIfError(iQueryStatement[EQueryCount].Reset());
+ return count;
+ }
+
+
+
+
+/**
+ * SearchTMsvIdL()
+ * @param aQuery An object representing the the search sort query.
+ * @param aIdSelection RArray holding the resultant TMsvId list.
+ *
+ * This function should be used to retrieve TMsvId list of result set.
+ * Queries the table holding TMsvEntry and retrieves id list of matched results.
+ */
+void CMsvDBAdapter::SearchTMsvIdL(const TDesC8& aQuery, RArray<TMsvId>& aIdSelection)
+ {
+ RSqlStatement queryStmt;
+ CleanupClosePushL(queryStmt);
+ User::LeaveIfError(queryStmt.Prepare(iDatabase, aQuery));
+
+ TInt idColumnIndex = GetColumnIndexL(queryStmt, KMsgColumnId());
+ while(KSqlAtRow == queryStmt.Next())
+ {
+
+ TMsvId id = ColumnInt(queryStmt, idColumnIndex);
+
+ #if(defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ id = MaskTMsvId(KCurrentDriveId, id);
+ #endif
+
+ aIdSelection.AppendL(id);
+ }
+
+ CleanupStack::PopAndDestroy();
+ }
+
+
+
+
+/**
+ * GetFolderIdsL()
+ * @param aParentId Parent Id of the folder.
+ * @param aFolderIdList RArray holding the resultant TMsvId list.
+ *
+ * This function returns the id's of all the KUidMsvMessageEntry type under the parent.
+ */
+void CMsvDBAdapter::GetFolderIdsL(const TMsvId aParentId, RArray<TMsvId>& aFolderIdList)
+ {
+ TMsvId entryId;
+ TUid folderType = KUidMsvFolderEntry;
+
+ #if(defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ {
+ _LIT8(KGetFolderIds, "SELECT id FROM DB");
+ _LIT8(KGetFolderQuery,".IndexEntry WHERE parentId = ");
+
+ _LIT8(KTypeLike," AND type = ");
+
+ RBuf8 folderIdQuery;
+ CleanupClosePushL(folderIdQuery);
+ folderIdQuery.CreateL(500);
+ folderIdQuery.Append(KGetFolderIds);
+ folderIdQuery.AppendNum(KCurrentDriveId);
+ folderIdQuery.Append(KGetFolderQuery);
+ folderIdQuery.AppendNum(aParentId);
+ folderIdQuery.Append(KTypeLike);
+ folderIdQuery.AppendNum(folderType.iUid);
+ folderIdQuery.Append(KSemiColon);
+
+ RSqlStatement folderquerystatement;
+
+ User::LeaveIfError(folderquerystatement.Prepare(iDatabase, folderIdQuery));
+
+ while(KSqlAtRow == folderquerystatement.Next())
+ {
+ entryId = ColumnInt(folderquerystatement, 0);
+ aFolderIdList.AppendL(entryId);
+ }
+ folderquerystatement.Close();
+ CleanupStack::PopAndDestroy(); //folderIdQuery
+ }
+ #else
+ {
+ //Bind the msv id of the entry to be retrieved
+ BindIntL(iQueryStatement[EGetFolderIds], iParentIdfield, aParentId);
+ BindIntL(iQueryStatement[EGetFolderIds], iTMsvidfield, folderType.iUid);
+
+ while(KSqlAtRow == iQueryStatement[EGetFolderIds].Next())
+ {
+ entryId = ColumnInt(iQueryStatement[EGetFolderIds], iParentIdfield);
+ aFolderIdList.AppendL(entryId);
+ }
+ //Reset the RSqlStatement
+ User::LeaveIfError(iQueryStatement[EGetFolderIds].Reset());
+ }
+ #endif
+ }
+
+
+
+
+/**
+ * ClearDBContentsL()
+ * @param none.
+ * @param none.
+ *
+ * This function clears the DB contents.
+ */
+void CMsvDBAdapter::ClearDBContentsL()
+ {
+#if(defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ RSqlDatabase temp;
+ CleanupClosePushL(temp);
+ //Get the system drive.
+ TInt systemDrive = (TInt)RFs::GetSystemDrive();
+
+ RBuf dbFile;
+ CleanupClosePushL(dbFile);
+ dbFile.CreateL(50);
+ dbFile.Append(TDriveUnit(systemDrive).Name());
+ dbFile.Append(KMainDummyDBName);
+
+ TRAPD(err, temp.OpenL(dbFile));
+ if(err == KErrNone)
+ {
+ err = temp.Exec(KClearTableContents);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ }
+ temp.Close();
+ CleanupStack::PopAndDestroy(2); //temp, dbFile
+#else
+ TInt err = iDatabase.Exec(KDeleteTable);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+#endif
+
+ }
+
+
+
+
+/**
+ * ReturnIdsInIteratorL()
+ * @param aQueryId Query ID of the query to be executed.
+ * @param prevCount The previous value returned to the caller.
+ * @param aId If successfull, than this contains the result.
+
+ * This function returns the TMsvId's for each unique Query ID.
+ Upon called for the first time, it binds the query id to the statement and returns
+ next result in each subsequent execution. If the statement fails for some reason, than it returns the
+ error code.
+ */
+void CMsvDBAdapter::ReturnIdsInIteratorL(const TInt& aQueryId, const TBool aOrder/*Default = ETrue*/,const TBool aSortAsInt/*Default = EFalse*/,const TInt aLimit/*Default = 1*/)
+ {
+ if(aSortAsInt)
+ {
+ if(aOrder)
+ {
+ iIterQuery = EQueryIteratorNumAsc;
+ }
+ else
+ {
+ iIterQuery = EQueryIteratorNumDesc;
+ }
+ }
+ else
+ {
+ if(aOrder)
+ {
+ iIterQuery = EQueryIteratorAsc;
+ }
+ else
+ {
+ iIterQuery = EQueryIteratorDesc;
+ }
+ }
+
+ iOffsetValue = 0;
+ iQueryId = aQueryId;
+ iLimit = aLimit;
+
+ iIdColumnIndex = GetColumnIndexL(iQueryStatement[iIterQuery], KMsgColumnId());
+ }
+
+/**
+ * GetNextL()
+ * @param aId If successfull, than this contains the result.
+
+ * This function returns the next TMsvId's from the Iterator
+ */
+TInt CMsvDBAdapter::GetNextL(TMsvId& aId)
+ {
+ BindIntL(iQueryStatement[iIterQuery], iQIdQueryIndex[iIterQuery], iQueryId);
+ BindIntL(iQueryStatement[iIterQuery], iIterLimit[iIterQuery], iLimit);
+ BindIntL(iQueryStatement[iIterQuery], iIterOffset[iIterQuery], iOffsetValue);
+
+ while(iQueryStatement[iIterQuery].Next() == KSqlAtRow)
+ {
+ aId = ColumnInt(iQueryStatement[iIterQuery],iIdColumnIndex);
+
+ #if(defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ aId = MaskTMsvId(KCurrentDriveId, aId);
+ #endif
+
+ ++iOffsetValue;
+ }
+
+ User::LeaveIfError(iQueryStatement[iIterQuery].Reset());
+ return iOffsetValue;
+ }
+
+
+/**
+ * GetPrevL()
+ * @param aId If successfull, than this contains the result.
+
+ * This function returns the previous TMsvId's from the Iterator
+ */
+TInt CMsvDBAdapter::GetPrevL(TMsvId& aId)
+ {
+ BindIntL(iQueryStatement[iIterQuery], iQIdQueryIndex[iIterQuery], iQueryId);
+ BindIntL(iQueryStatement[iIterQuery], iIterLimit[iIterQuery], iLimit);
+ BindIntL(iQueryStatement[iIterQuery], iIterOffset[iIterQuery], iOffsetValue);
+
+ while(iQueryStatement[iIterQuery].Next() == KSqlAtRow)
+ {
+ aId = ColumnInt(iQueryStatement[iIterQuery],iIdColumnIndex);
+ #if(defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ aId = MaskTMsvId(KCurrentDriveId, aId);
+ #endif
+
+ --iOffsetValue;
+ }
+
+ User::LeaveIfError(iQueryStatement[iIterQuery].Reset());
+ return iOffsetValue;
+ }
+
+
+
+
+
+#if (!defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+/**
+ * ValidateDatabaseL()
+ *
+ * @param TFileName& The database filename to be checked.
+ * @return None.
+ *
+ * Checks the database version to see if it is supported.
+ * Supported version is KCurrentDatabaseVersion (1) only.
+ */
+void CMsvDBAdapter::ValidateDatabaseL(const TFileName& aDbFile)
+ {
+ _LIT8(KSelectVersionQuery, "SELECT version FROM VersionTable;");
+
+ //Use a temporary local database connection to open the file for now.
+ RSqlDatabase temp;
+ CleanupClosePushL(temp);
+ temp.OpenL(aDbFile);
+ TSqlScalarFullSelectQuery query(temp);
+
+ TInt version = 0;
+ version = query.SelectIntL(KSelectVersionQuery);
+ if(KCurrentDatabaseVersion != version)
+ {
+ User::Leave(KErrNotSupported);
+ }
+ CleanupStack::PopAndDestroy(); // temp
+ }
+#endif
+
+
+
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+/**
+* GetMtmIdsL()
+*
+* @param aMtmIdTable: aMtmIdTable will be updated with MtmIds
+* @param aQuery: QueryString which is prepared depending on SearchSort Query
+* return NONE
+*
+* Function to get MtmId/s for given parent id.
+*/
+void CMsvDBAdapter::GetMtmIdsL(const TDesC8& aQuery, RArray<TUid>& aMtmIdArray)
+ {
+ RSqlStatement queryStmt;
+ CleanupClosePushL(queryStmt);
+ User::LeaveIfError(queryStmt.Prepare(iDatabase, aQuery));
+
+ TInt mtmIdColumnIndex = GetColumnIndexL(queryStmt, KMsgColumnMtmId());
+
+ TUid tempMtmId ;
+ TInt32 mtmId = KErrNotFound;
+
+ while(KSqlAtRow == queryStmt.Next())
+ {
+ mtmId = ColumnInt(queryStmt, mtmIdColumnIndex);
+
+ tempMtmId.iUid = mtmId;
+ aMtmIdArray.AppendL(tempMtmId);
+ }
+
+ CleanupStack::PopAndDestroy();
+ }
+
+
+
+/***************************** Converter************************/
+
+/**
+OpenL()
+Opens a database and returns a handle to it.
+
+@param aDbFileName: DB name.
+@retun :CMsvDBAdapter object.
+*/
+CMsvDBAdapter* CMsvDBAdapter::OpenL(const TFileName& aDbFileName)
+ {
+ //Create an messaging DB adaptor object
+ CMsvDBAdapter* self = new(ELeave) CMsvDBAdapter();
+ CleanupStack::PushL(self);
+
+ // Open the database.
+ self->ConstructOpenDBL(aDbFileName);
+
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+ConstructOpenDBL()
+
+@param aDbFileName: DB name.
+@retun None
+*/
+void CMsvDBAdapter::ConstructOpenDBL(const TFileName& aDbFileName)
+ {
+ User::LeaveIfError(iDatabase.Open(aDbFileName));
+ iDatabasePresent = new(ELeave)RArray<TBool>(KMaxNumberOfDrives);
+ for(TInt index = 0; index < KMaxNumberOfDrives; ++index)
+ {
+ iDatabasePresent->Append(EFalse);
+ }
+ }
+
+
+/**
+ * InitializeL()
+ *
+ * This functions prepares (compiles) frequetly used SQL queries,
+ * and create indexes on the variable arguments. When the query
+ * needs to be executed, we just have to bind the variables with
+ * the values and execute them. This increases the performance of
+ * query execution.
+ */
+void CMsvDBAdapter::InitializeLConverterStatementL()
+ {
+ //Prepare the frequently used SQL statements
+ User::LeaveIfError(iStatement[ECreateEntry].Prepare(iDatabase, KCreateEntryQuery));
+
+ //For creating and updating entries
+ iParentIdIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamParentId());
+ iVisibleParent[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamVisibleParent());
+ iIdIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamId());
+ iServiceIdIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamServiceId());
+ iMtmIdIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamMtmId());
+ iTypeIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamType());
+ iDateIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamDate());
+ iDataIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamData());
+ iSizeIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamSize());
+ iErrorIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamError());
+ iMtmData1Index[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamMtmData1());
+ iMtmData2Index[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamMtmData2());
+ iMtmData3Index[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamMtmData3());
+ iRelatedIdIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamRelatedId());
+ iBiotypeIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamBiotype());
+ iPcSyncCountIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamPcSyncCount());
+ iReservedIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamReserved());
+ iDescriptionIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamDescriptionTxt());
+ iDetailsIndex[ECreateEntry] = GetParamIndexL(iStatement[ECreateEntry], KMsgParamDetailsTxt());
+ }
+
+
+/**
+CreateIndexEntryL()
+Inserts an entry in IndexEntry table.
+
+@param aNewEntry: TMsvEntry.
+@param aImmediateVisibleFolder: Visible Parent.
+@retun None
+*/
+void CMsvDBAdapter::CreateIndexEntryL(const TMsvEntry& aNewEntry, const TMsvId aImmediateVisibleFolder)
+ {
+ //Bind the entry data
+ BindIntL(iStatement[ECreateEntry], iIdIndex[ECreateEntry], aNewEntry.iId);
+ BindIntL(iStatement[ECreateEntry], iParentIdIndex[ECreateEntry], aNewEntry.iParentId);
+ BindIntL(iStatement[ECreateEntry], iDataIndex[ECreateEntry], aNewEntry.iData);
+ BindIntL(iStatement[ECreateEntry], iPcSyncCountIndex[ECreateEntry], aNewEntry.iPcSyncCount);
+ BindIntL(iStatement[ECreateEntry], iReservedIndex[ECreateEntry], aNewEntry.iReserved);
+ BindIntL(iStatement[ECreateEntry], iRelatedIdIndex[ECreateEntry], aNewEntry.iRelatedId);
+ BindIntL(iStatement[ECreateEntry], iTypeIndex[ECreateEntry], aNewEntry.iType.iUid);
+ BindInt64L(iStatement[ECreateEntry], iDateIndex[ECreateEntry], aNewEntry.iDate.Int64());
+ BindIntL(iStatement[ECreateEntry], iSizeIndex[ECreateEntry], aNewEntry.iSize);
+ BindIntL(iStatement[ECreateEntry], iErrorIndex[ECreateEntry], aNewEntry.iError);
+ BindIntL(iStatement[ECreateEntry], iBiotypeIndex[ECreateEntry], aNewEntry.iBioType);
+ BindIntL(iStatement[ECreateEntry], iMtmData1Index[ECreateEntry], aNewEntry.iMtmData1);
+ BindIntL(iStatement[ECreateEntry], iMtmData2Index[ECreateEntry], aNewEntry.iMtmData2);
+ BindIntL(iStatement[ECreateEntry], iMtmData3Index[ECreateEntry], aNewEntry.iMtmData3);
+ BindIntL(iStatement[ECreateEntry], iServiceIdIndex[ECreateEntry], aNewEntry.iServiceId);
+ BindIntL(iStatement[ECreateEntry], iMtmIdIndex[ECreateEntry], aNewEntry.iMtm.iUid);
+ BindIntL(iStatement[ECreateEntry], iVisibleParent[ECreateEntry], aImmediateVisibleFolder);
+ BindTextL(iStatement[ECreateEntry],iDescriptionIndex[ECreateEntry],aNewEntry.iDescription);
+ BindTextL(iStatement[ECreateEntry],iDetailsIndex[ECreateEntry],aNewEntry.iDetails);
+ //Execute the prepared SQL statement.
+
+ TInt err = iStatement[ECreateEntry].Exec();
+ if(err < 0)
+ {
+ iStatement[ECreateEntry].Reset();
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ iStatement[ECreateEntry].Reset();
+ User::Leave(KErrGeneral);
+ }
+
+ //Reset the RSqlStatement
+ User::LeaveIfError(iStatement[ECreateEntry].Reset());
+ }
+
+
+/**
+ChangeVersionL()
+Changes message store version of messaging database.
+
+@param aVersion: version
+@retun None
+*/
+void CMsvDBAdapter::ChangeVersionL(TInt aVersion)
+ {
+ _LIT(KUpdateVersionQuery, "UPDATE VersionTable SET version = ");
+
+ RBuf buf;
+ CleanupClosePushL(buf);
+ buf.CreateL(100);
+ buf.Append(KUpdateVersionQuery);
+ buf.AppendNum(aVersion);
+ buf.Append(KDelimiter);
+
+ TInt err = iDatabase.Exec(buf);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ CleanupStack::PopAndDestroy(); //buf
+ }
+
+
+/**************************** Conversion Status Table API's **************************/
+/**
+CreateConversionStatusTableL()
+Creates conversion status table.
+
+@param None:
+@retun None
+*/
+void CMsvDBAdapter::CreateConversionStatusTableL()
+ {
+ TInt err = iDatabase.Exec(KCreateConversionStatusTableQuery);
+ if(err < 0)
+ {
+ User::Leave(KErrGeneral);
+ }
+ }
+
+/**
+RemoveConversionStatusTableL()
+Removes conversion status table.
+
+@param None:
+@retun None
+*/
+void CMsvDBAdapter::RemoveConversionStatusTableL()
+ {
+ TInt err = iDatabase.Exec(KRemoveConversionStatusTable);
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ }
+
+/**
+GetConversionStatusL()
+Fetches conversion resume state from the conversion status table.
+
+@param aConversionResumeStatus: Conversion sresume status entry.
+@retun None
+*/
+void CMsvDBAdapter::GetConversionStatusL(TConversionResumeStatus& aConversionResumeStatus)
+ {
+ // We shld not get more than one mtm results for this query
+ _LIT16(KGetConversionStatusQuery, "SELECT * FROM ConversionStatus WHERE remainingCount != 0;");
+
+ RSqlStatement statement;
+ CleanupClosePushL(statement);
+ TInt index =0;
+
+ User::LeaveIfError(statement.Prepare(iDatabase, KGetConversionStatusQuery));
+
+ while(KSqlAtRow == statement.Next())
+ {
+ aConversionResumeStatus.lastId = ColumnInt(statement, index);
+ aConversionResumeStatus.serviceId = ColumnInt(statement, ++index);
+ aConversionResumeStatus.sourceVersion = ColumnInt(statement, ++index);
+ aConversionResumeStatus.targetVersion = ColumnInt(statement, ++index);
+ aConversionResumeStatus.mtmId.iUid = ColumnInt(statement, ++index);
+ aConversionResumeStatus.remainingCount = ColumnInt(statement, ++index);
+ index =0;
+ }
+ CleanupStack::PopAndDestroy(); //statement
+ }
+
+/**
+AddConversionStatusEntryL()
+Inserts a conversion status entry in the conversion status table.
+
+@param aConversionResumeStatus: Conversion sresume status entry.
+@retun None
+*/
+void CMsvDBAdapter::AddConversionStatusEntryL(TConversionResumeStatus& aConversionResumeStatus)
+ {
+ _LIT8(KAddConversionStatusEntryQuery, "INSERT INTO ConversionStatus VALUES ("
+ ":lastId, :serviceId, :sourceVersion, :targetVersion, :mtmId, :remainingCount);"
+ ); //
+
+ RSqlStatement statement;
+ CleanupClosePushL(statement);
+ TInt index =0;
+
+ User::LeaveIfError(statement.Prepare(iDatabase,KAddConversionStatusEntryQuery));
+ BindIntL(statement, index++, aConversionResumeStatus.lastId);
+ BindIntL(statement, index++, aConversionResumeStatus.serviceId);
+ BindIntL(statement, index++, aConversionResumeStatus.sourceVersion);
+ BindIntL(statement, index++, aConversionResumeStatus.targetVersion);
+ BindIntL(statement, index++, aConversionResumeStatus.mtmId.iUid);
+ BindIntL(statement, index++, aConversionResumeStatus.remainingCount);
+
+ TInt err = statement.Exec();
+
+ CleanupStack::PopAndDestroy(); //statement
+
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err )
+ {
+ User::Leave(KErrGeneral);
+ }
+ }
+
+/**
+UpdateConversionStatusEntryL()
+Updates a conversion status entry in the conversion status table.
+
+@param aConversionResumeStatus:Conversion sresume status entry.
+@retun None
+*/
+void CMsvDBAdapter::UpdateConversionStatusEntryL(TConversionResumeStatus& aConversionResumeStatus)
+ {
+ _LIT(KUpdateConversionStatusQuery1, "UPDATE ConversionStatus SET remainingCount = "); //
+ _LIT(KUpdateConversionStatusQuery2, " WHERE mtmId = "); //
+ _LIT(KUpdateConversionStatusQuery3, " AND serviceId = "); //
+
+ RBuf buf;
+ CleanupClosePushL(buf);
+ buf.CreateL(100);
+ buf.Append(KUpdateConversionStatusQuery1);
+ buf.AppendNum(aConversionResumeStatus.remainingCount);
+ buf.Append(KUpdateConversionStatusQuery2);
+ buf.AppendNum(aConversionResumeStatus.mtmId.iUid);
+ buf.Append(KUpdateConversionStatusQuery3);
+ buf.AppendNum(aConversionResumeStatus.serviceId);
+ buf.Append(KDelimiter);
+
+ TInt err = iDatabase.Exec(buf);
+ CleanupStack::PopAndDestroy(); //buf
+
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err )
+ {
+ User::Leave(KErrGeneral);
+ }
+ }
+
+/**
+RemoveConversionStatusEntriesL()
+Removes all conversion status entries in the conversion status table.
+
+@param None:
+@retun None
+*/
+void CMsvDBAdapter::RemoveConversionStatusEntriesL()
+ {
+ _LIT(KRemoveConversionStatusEntry, "DELETE FROM ConversionStatus;");
+
+ RSqlStatement statement;
+ CleanupClosePushL(statement);
+ User::LeaveIfError(statement.Prepare(iDatabase, KRemoveConversionStatusEntry));
+ TInt err = statement.Exec();
+
+ CleanupStack::PopAndDestroy(); // statement
+
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(err != KErrNone)
+ {
+ User::Leave(KErrGeneral);
+ }
+ }
+
+/**
+GetRemainingServiceIdsL()
+Fetches all service ids for which the conversion is not complete from the conversion status table.
+
+@param aIdArray:Array of TMsvId.
+@retun None
+*/
+void CMsvDBAdapter::GetRemainingServiceIdsL(RArray<TMsvId>& aIdArray)
+ {
+ _LIT(KGetToResumeServiceIds, "SELECT serviceId FROM ConversionStatus WHERE remainingCount != 0;");
+
+ RSqlStatement queryStmt;
+ CleanupClosePushL(queryStmt);
+ User::LeaveIfError(queryStmt.Prepare(iDatabase, KGetToResumeServiceIds));
+
+ TInt serviceColumnIndex = GetColumnIndexL(queryStmt, KMsgColumnServiceId());
+
+ while(KSqlAtRow == queryStmt.Next())
+ {
+ TMsvId serviceId = ColumnInt(queryStmt, serviceColumnIndex);
+ aIdArray.AppendL(serviceId);
+ }
+ CleanupStack::PopAndDestroy(); // stmt
+ }
+
+/**
+GetAllMessageIdsL()
+Gets all message ids for a service id. If the conversion is resumed than retrives the message ids
+after the last id that was converted.
+
+@param aServiceId: service id.
+@param aIdArray: Array of TMsvId.
+@param lastId: last id that was converted and commited in the database.
+@retun None
+*/
+void CMsvDBAdapter::GetAllMessageIdsL(TMsvId aServiceId, RArray<TMsvId>& aIdArray,TInt32 aMtm,TMsvId lastId)
+ {
+ _LIT16(KSelectMessageId, "Select id FROM IndexEntry WHERE type = ");
+ _LIT16(KMessageMtmId," AND mtmId = ");
+ _LIT16(KSelectServiceId," AND serviceId = ");
+ _LIT16(KMessageId, " AND id > ");
+ _LIT16(KOrderByString, " order by id ASC");
+
+ RBuf buf;
+ CleanupClosePushL(buf);
+ buf.CreateL(200);
+ buf.Append(KSelectMessageId);
+ buf.AppendNum(KUidMsvMessageEntryValue);
+ buf.Append(KMessageMtmId);
+ buf.AppendNum(aMtm);
+ buf.Append(KSelectServiceId);
+ buf.AppendNum(aServiceId);
+ buf.Append(KMessageId);
+ buf.AppendNum(lastId);
+ buf.Append(KOrderByString);
+ buf.Append(KDelimiter);
+
+ RSqlStatement Idquerystatement;
+ CleanupClosePushL(Idquerystatement);
+ User::LeaveIfError(Idquerystatement.Prepare(iDatabase, buf));
+
+ TInt Idindex = GetColumnIndexL(Idquerystatement, KMsgColumnId());
+
+ while(KSqlAtRow == Idquerystatement.Next())
+ {
+ aIdArray.Append(ColumnInt(Idquerystatement, Idindex));
+ }
+
+ CleanupStack::PopAndDestroy(2); //buf,Idquerystatement
+ }
+
+/**
+GetAllMimeIdsL()
+Gets all attachment ids for a message.
+
+@param aId: id
+@param aIdArray: Array of TMsvId.
+@retun None
+*/
+void CMsvDBAdapter::GetAllMimeIdsL(TMsvId aId, RArray<TMsvId>& aIdArray)
+ {
+ _LIT(KGetChild, "Select id, type FROM IndexEntry WHERE parentId = ");
+
+ const TInt32 KUidMsvEmailTextEntryValue = 0x100038F1;
+ const TInt32 KUidMsvEmailHtmlEntryValue = 0x100057C0; // 268457920
+ const TInt32 KUidMsvEmailRtfEntryValue = 0x1028368F; // 271070863
+
+ RBuf buf;
+ CleanupClosePushL(buf);
+ buf.CreateL(100);
+ buf.Append(KGetChild);
+ buf.AppendNum(aId);
+ buf.Append(KDelimiter);
+
+ RSqlStatement stmt;
+ CleanupClosePushL(stmt);
+ User::LeaveIfError(stmt.Prepare(iDatabase, buf));
+
+ TInt idIndex = 0;
+ TInt typeIndex = 1;
+
+ // For every child..
+ while(KSqlAtRow == stmt.Next())
+ {
+ // Get the type
+ TMsvId childId = ColumnInt(stmt, idIndex);
+ TInt32 type = ColumnInt(stmt, typeIndex);
+
+ // Append TMsvId's which may have MIME header
+ if( type == KUidMsvAttachmentEntryValue ||
+ type == KUidMsvEmailTextEntryValue ||
+ type == KUidMsvEmailHtmlEntryValue ||
+ type == KUidMsvEmailRtfEntryValue
+ )
+ {
+ aIdArray.Append(childId);
+ }
+ // Recursion for alternate folders
+ else if(type == KUidMsvFolderEntryValue)
+ {
+ aIdArray.Append(childId);
+ // also get the childs for these messages
+ GetAllMimeIdsL(childId, aIdArray);
+ }
+ }
+
+ CleanupStack::PopAndDestroy(2); // stmt, buf
+ }
+
+/**
+GetMessageCountL()
+Gets the count of messages under a service id.
+
+@param aServiceId: service id
+*/
+TInt CMsvDBAdapter::GetMessageCountL(TMsvId aServiceId)
+ {
+ _LIT(KSelectMessageId, "Select count(*) FROM IndexEntry WHERE type = ");
+ _LIT(KServiceId," AND serviceId = ");
+ RBuf buf;
+ CleanupClosePushL(buf);
+ buf.CreateL(100);
+ buf.Append(KSelectMessageId);
+ buf.AppendNum(KUidMsvMessageEntryValue);
+ buf.Append(KServiceId);
+ buf.AppendNum(aServiceId);
+ buf.Append(KDelimiter);
+
+ TSqlScalarFullSelectQuery query(iDatabase);
+ TInt msgcount = 0;
+ msgcount = query.SelectIntL(buf);
+
+ CleanupStack::PopAndDestroy(); //buf
+ return msgcount;
+ }
+
+/**
+GetOwningServiceL()
+Gets the ids owning service.
+
+@param aId: id
+@param aOwningId: owning service id reference variable.
+@retun None
+*/
+void CMsvDBAdapter::GetOwningServiceL(TMsvId aId, TMsvId& aOwningId)
+ {
+ _LIT(KSelectServiceId, "Select parentId,type FROM IndexEntry WHERE id = ");
+
+ TBool found = EFalse;
+ TMsvId entryid = aId;
+ TMsvId parentId = 0;
+ TMsvId typeId = 0;
+
+ while (!found)
+ {
+ RBuf buf;
+ CleanupClosePushL(buf);
+ buf.CreateL(100);
+ buf.Append(KSelectServiceId);
+ buf.AppendNum(entryid);
+ buf.Append(KDelimiter);
+
+ RSqlStatement parentIdquerystatement;
+ CleanupClosePushL(parentIdquerystatement);
+ User::LeaveIfError(parentIdquerystatement.Prepare(iDatabase, buf));
+
+ TInt parentIdindex = GetColumnIndexL(parentIdquerystatement, KMsgColumnParentId());
+ TInt typeIdindex = GetColumnIndexL(parentIdquerystatement, KMsgColumnType());
+
+ while(KSqlAtRow == parentIdquerystatement.Next())
+ {
+ parentId = ColumnInt(parentIdquerystatement, parentIdindex);
+ typeId = ColumnInt(parentIdquerystatement, typeIdindex);
+ }
+
+ CleanupStack::PopAndDestroy(2); //buf,parentIdquerystatement
+
+ if (typeId == KUidMsvServiceEntryValue)
+ {
+ found = ETrue;
+ }
+ else
+ {
+ entryid = parentId;
+ }
+ }
+ aOwningId = entryid;
+ }
+
+/**
+GetAllServiceIDsForMtmL()
+Gets all service ids for the specified mtm.
+
+@param aMtm: mtm id.
+@param aIdArray&: Array of TMsvId.
+@retun None
+*/
+void CMsvDBAdapter::GetAllServiceIDsForMtmL(TInt32 aMtm, RArray<TMsvId>& aIdArray)
+ {
+ // if sms, than dont get smtp id else, get the smtp id also
+ _LIT16(KSelectServiceIds, "Select distinct serviceId FROM IndexEntry where type = ");
+ _LIT16(KMtmIdQuery," AND mtmId = ");
+
+ RBuf buf;
+ CleanupClosePushL(buf);
+ buf.CreateL(200);
+ buf.Append(KSelectServiceIds);
+ buf.AppendNum(KUidMsvServiceEntryValue);
+ buf.Append(KMtmIdQuery);
+ buf.AppendNum(aMtm);
+ buf.Append(KDelimiter);
+
+ RSqlStatement queryStmt;
+ CleanupClosePushL(queryStmt);
+ User::LeaveIfError(queryStmt.Prepare(iDatabase, buf));
+ TInt serviceColumnIndex = GetColumnIndexL(queryStmt, KMsgColumnServiceId());
+
+ while(KSqlAtRow == queryStmt.Next())
+ {
+ TMsvId serviceId = ColumnInt(queryStmt, serviceColumnIndex);
+ aIdArray.AppendL(serviceId);
+ }
+ CleanupStack::PopAndDestroy(2); //buf, stmt
+
+ // lets also get all messages in the root with this service id
+ if(aMtm == 268439592 ) //0x1000102C sms
+ {
+ aIdArray.AppendL(KMsvGlobalOutBoxIndexEntryIdValue);
+ aIdArray.AppendL(KMsvDraftEntryIdValue);
+ aIdArray.AppendL(KMsvSentEntryIdValue);
+ }
+ }
+
+/**
+GetAllIndexEntryTableIdsL()
+Gets all ids present in index entry table.
+
+@param aIdArray: Array of TMsvId.
+@retun None
+*/
+void CMsvDBAdapter::GetAllIndexEntryTableIdsL(RArray<TMsvId>& aIdArray)
+ {
+ _LIT(KSelectAllIds, "Select * FROM IndexEntry;");
+
+ RSqlStatement queryStmt;
+ CleanupClosePushL(queryStmt);
+ User::LeaveIfError(queryStmt.Prepare(iDatabase, KSelectAllIds));
+
+ TInt serviceColumnIndex = GetColumnIndexL(queryStmt, KMsgColumnId());
+
+ while(KSqlAtRow == queryStmt.Next())
+ {
+ TMsvId Id = ColumnInt(queryStmt, serviceColumnIndex);
+ aIdArray.AppendL(Id);
+ }
+ CleanupStack::PopAndDestroy(); //queryStmt
+ }
+
+/**
+GetVisibleParentL()
+Gets the visible parent of the specified id.
+
+@param aId: id
+@param aVisibleParentId: visible parent id.
+@retun None
+*/
+
+void CMsvDBAdapter::GetVisibleParentL(TMsvId aId, TMsvId& aVisibleParentId)
+ {
+ _LIT(KSelectServiceId, "Select parentId,type FROM IndexEntry WHERE id = ");
+
+ TMsvId entryid = aId;
+ TMsvId parentId = 0;
+
+ RBuf buf;
+ CleanupClosePushL(buf);
+ buf.CreateL(100);
+ buf.Append(KSelectServiceId);
+ buf.AppendNum(entryid);
+ buf.Append(KDelimiter);
+
+ RSqlStatement parentIdquerystatement;
+ CleanupClosePushL(parentIdquerystatement);
+
+ User::LeaveIfError(parentIdquerystatement.Prepare(iDatabase, buf));
+
+ TInt parentIdindex = GetColumnIndexL(parentIdquerystatement, KMsgColumnParentId());
+
+ while(KSqlAtRow == parentIdquerystatement.Next())
+ {
+ parentId = ColumnInt(parentIdquerystatement, parentIdindex);
+ }
+
+ CleanupStack::PopAndDestroy(2); //buf,parentIdquerystatement
+
+ GetVisibleParentIdL(parentId,aVisibleParentId);
+ }
+
+/**
+GetVisibleParentIdL()
+This functions returns the most immediate parent visible folder id.
+There are two types of folders. A visible folder is one which is
+visible to the external user, but there are internal non-visible folders
+created under each email message to organize the content of the email.
+Parent entry of an entry is either root or a folder. A folder can be
+service folder (like LocalServices), userdefined folder/standard folder
+like Inbox or a non-visible folder (created under an email message).
+
+For a given parent Id, the function returns the most immediate visible
+parent folder. The rules are as follows:
+1. If the parent entry is root or children of root, then the visibleFolder
+will be root itself. This is because service folders are considered
+invisible, since they are not seen by user.
+2. If the parent entry itself is a visible folder then child's visibleFolder
+id should be its parent id.
+3. If the parent entry is a non-visible folder then child's visibleFolder
+id is same as its parent's visibleFolder id.
+
+@param TMsvId: Parent Id.
+@return Most immediate visible folder id of any child entry present under passed parent id.
+*/
+void CMsvDBAdapter::GetVisibleParentIdL(TMsvId aParentId, TMsvId& aVisibleFolderId)
+ {
+ // If the entry is either a root entry (parent=KErrNotFound) or
+ // child of root entry its visibleFolderId will be root entry itself.
+ if((KErrNotFound == aParentId) || (KMsvRootIndexEntryId == aParentId))
+ {
+ aVisibleFolderId = KMsvRootIndexEntryId;
+ }
+ else
+ {
+ // Get the visible flag of parent entry.
+
+ // If parent entry is visible, then immediateVisibleFolder of child
+ // should be parent Id. And if it is invisible then child's immediateVisibleFolder
+ // should be same as parent's immediateVisibleFolder.
+
+ //Bind the msv id
+ BindIntL(iStatement[EGetVisibleId], iIdIndex[EGetVisibleId], aParentId);
+
+ // If parent entry does not exists leave with KErrNotFound.
+ if (KSqlAtRow != iStatement[EGetVisibleId].Next())
+ {
+ iStatement[EGetVisibleId].Reset();
+ User::Leave(KErrNotFound);
+ }
+
+ TInt32 data = ColumnInt(iStatement[EGetVisibleId], iDataIndex[EGetVisibleId]);
+ if( data & TMsvEntry::KMsvVisibleFolderNodeFlag)
+ {
+ // If visible folder flag is not set for parent entry.
+ aVisibleFolderId = ColumnInt(iStatement[EGetVisibleId], iVisibleParent[EGetVisibleId]);
+ }
+ else
+ {
+ // If parent entry is visible
+ aVisibleFolderId = aParentId;
+ }
+ //Reset the RSqlStatement
+ User::LeaveIfError(iStatement[EGetVisibleId].Reset());
+ }
+ }
+
+/**
+UpdateVisibleFolderIdL()
+Updates visible parent and any other new changes in TMsvEntry structure post PREQ 1189.
+
+@param aId: id.
+@param visibleId: visible parent id.
+@retun None
+*/
+void CMsvDBAdapter::UpdateVisibleFolderIdL(TMsvId aId,TMsvId visibleId)
+ {
+ _LIT(KUpdateVisibleParentQuery,"UPDATE IndexEntry SET visibleParent = ");
+ _LIT(KWhere, " WHERE ");
+ _LIT(KUpdateVisibleParentQuery1, "id = ");
+
+ RBuf buf;
+ CleanupClosePushL(buf);
+ buf.CreateL(100);
+ buf.Append(KUpdateVisibleParentQuery);
+ buf.AppendNum(visibleId);
+ buf.Append(KWhere);
+ buf.Append(KUpdateVisibleParentQuery1);
+ buf.AppendNum(aId);
+ buf.Append(KDelimiter);
+
+ RSqlStatement queryStmt;
+ CleanupClosePushL(queryStmt);
+ User::LeaveIfError(queryStmt.Prepare(iDatabase, buf));
+
+ TInt err = queryStmt.Exec();
+
+ CleanupStack::PopAndDestroy(2); //stmt
+
+ if(err < 0)
+ {
+ User::Leave(err);
+ }
+ else if(!err)
+ {
+ User::Leave(KErrGeneral);
+ }
+ }
+
+TBool CMsvDBAdapter::GetParentVisibleFlagL(TMsvId parentId)
+ {
+ _LIT(KSelectServiceId, "Select data FROM IndexEntry WHERE id = ");
+
+ TInt data = KErrNotFound;
+ RBuf buf;
+ CleanupClosePushL(buf);
+ buf.CreateL(100);
+ buf.Append(KSelectServiceId);
+ buf.AppendNum(parentId);
+ buf.Append(KDelimiter);
+
+ RSqlStatement parentDataQuerystatement;
+ CleanupClosePushL(parentDataQuerystatement);
+
+ User::LeaveIfError(parentDataQuerystatement.Prepare(iDatabase, buf));
+
+ TInt parentIdindex = GetColumnIndexL(parentDataQuerystatement, KMsgColumnData());
+
+ while(KSqlAtRow == parentDataQuerystatement.Next())
+ {
+ data = ColumnInt(parentDataQuerystatement, parentIdindex);
+ }
+ CleanupStack::PopAndDestroy(2); //buf,parentIdquerystatement
+
+ return !(data & TMsvEntry::KMsvVisibleFolderNodeFlag);
+
+ }
+
+/**
+GetAllIndexEntryTableIdsL()
+Gets all ids present in index entry table.
+
+@param aIdArray: Array of TMsvId.
+@retun None
+*/
+void CMsvDBAdapter::GetRemainingIdsL(RArray<TMsvId>& aIdArray)
+ {
+ _LIT(KSelectAllIds, "Select id FROM IndexEntry where visibleParent = -99;");
+
+ RSqlStatement queryStmt;
+ CleanupClosePushL(queryStmt);
+ User::LeaveIfError(queryStmt.Prepare(iDatabase, KSelectAllIds));
+
+ TInt serviceColumnIndex = GetColumnIndexL(queryStmt, KMsgColumnId());
+
+ while(KSqlAtRow == queryStmt.Next())
+ {
+ TMsvId Id = ColumnInt(queryStmt, serviceColumnIndex);
+ aIdArray.AppendL(Id);
+ }
+ CleanupStack::PopAndDestroy(); //queryStmt
+ }
+
+/**
+DeleteTable()
+Deletes the header table identified by the UID
+
+@param aMtmId: MTM id.
+@retun None
+*/
+void CMsvDBAdapter::DeleteTableL(TUid aMtmId)
+ {
+ _LIT16(KDropTableQuery, "DROP table if exists Header_");
+
+ RBuf16 buf;
+ CleanupClosePushL(buf);
+ buf.CreateL(100);
+ buf.Append(KDropTableQuery);
+ buf.AppendNum(aMtmId.iUid);
+ buf.Append(KDelimiter);
+
+ TInt err = iDatabase.Exec(buf);
+
+ CleanupStack::PopAndDestroy(); //buf
+ }
+
+ /**
+DeleteTable()
+Deletes the header table identified by the UID
+
+@param None
+@retun None
+*/
+void CMsvDBAdapter::DeleteSearchSortTable()
+ {
+ _LIT16(KDropSearchSortTableQuery, "DROP table if exists SearchSortEntry;");
+
+ TInt err = iDatabase.Exec(KDropSearchSortTableQuery);
+ }
+
+
+#endif //#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+
+
+