--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sysstatemgmt/systemstarter/dscstoresrc/dscdatabase_sql.cpp Tue Feb 02 00:53:00 2010 +0200
@@ -0,0 +1,919 @@
+// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "dscdatabase_sql.h"
+#include "dscitem.h"
+#include <e32debug.h>
+#include <e32math.h>
+#include <f32file.h>
+#include "e32modes.h"
+
+
+//DSC Database name
+_LIT(KDatabaseName, "%s:[2000836D]DBS_DSC.db");
+//Table name
+_LIT(KDscTable, "DSC");
+_LIT(KItemTable, "DscItem");
+//Column name
+_LIT(KDscIdCol, "DscId");
+_LIT(KDescriptionCol, "Description");
+_LIT(KItemIdCol, "ItemId");
+_LIT(KFileNameCol, "FileName");
+_LIT(KArgListCol, "ArgList");
+_LIT(KStartMethodCol, "StartMethod");
+_LIT(KTimeoutCol, "Timeout");
+_LIT(KNoOfRetriesCol, "NoOfRetries");
+_LIT(KMonitorCol, "Monitored");
+_LIT(KStartupTypeCol, "StartupType");
+_LIT(KViewlessCol, "Viewless");
+_LIT(KStartInBackgroundCol, "StartInBackground");
+
+
+_LIT8(KBeginTrans, "BEGIN");
+_LIT8(KRollbackTrans, "ROLLBACK");
+_LIT8(KCommitTrans, "COMMIT");
+
+/**
+The maximum length for DBMS varchar: 255 characters.
+@internalTechnology
+@released
+*/
+const TInt KDscStoreMaxStringLength =255;
+
+//length of characters in TUint 32
+//This is used to calculate the length of sqlCmd in order to allocate adequate buffer.
+//characters in TUint32 and TInt32
+//This is used to calculate the length of sqlCmd in order to allocate adequate buffer.
+const TInt lengthOfTUint=10;
+const TInt lengthOfTInt=11;
+
+//The maximum characters in DSC database name
+const TInt KMaxDatabaseName=40;
+
+CDscDatabase* CDscDatabase::NewL()
+ {
+ CDscDatabase* db = new(ELeave) CDscDatabase();
+ CleanupStack::PushL(db);
+
+ db->ConstructL();
+
+ CleanupStack::Pop(db);
+ return db;
+ }
+
+//Second phase constructor, Open connection to Dscdatabase.
+//If DSC database doesn't exist, create it.
+void CDscDatabase::ConstructL()
+ {
+
+ TBuf<KMaxDatabaseName> databaseName;
+ GetDatabaseName(databaseName);
+
+ //Open DSC database
+ TInt error=iDatabase.Open(databaseName );
+
+ if (KErrNotFound!=error) //Dsc Database exists
+ {
+ //If open with error. Leave with error code return from SQLite
+ User::LeaveIfError(ConvertErrCode(error));
+ //Opened successfully
+ return;
+ }
+
+ //DscDatabase doesn't exist
+ //Create security policy: Read: ReadDeviceData, Write: WriteDeviceData,
+ //Schema: ReadDeviceData and WriteDeviceData
+ TSecurityPolicy defaultPolicy;
+ RSqlSecurityPolicy securityPolicy;
+ CleanupClosePushL(securityPolicy);
+ User::LeaveIfError(securityPolicy.Create(defaultPolicy));
+
+ const TSecurityPolicy KSchemePolicy(ECapabilityReadDeviceData, ECapabilityWriteDeviceData);
+ const TSecurityPolicy KReadPolicy(ECapabilityReadDeviceData);
+ const TSecurityPolicy KWritePolicy(ECapabilityWriteDeviceData);
+
+ User::LeaveIfError(securityPolicy.SetDbPolicy(RSqlSecurityPolicy::ESchemaPolicy,KSchemePolicy));
+ User::LeaveIfError(securityPolicy.SetDbPolicy(RSqlSecurityPolicy::EWritePolicy,KWritePolicy));
+ User::LeaveIfError(securityPolicy.SetDbPolicy(RSqlSecurityPolicy::EReadPolicy,KReadPolicy));
+
+ //Create DSC database according to security policy.
+ User::LeaveIfError(iDatabase.Create(databaseName, securityPolicy));
+
+ CleanupStack::PopAndDestroy(&securityPolicy);
+
+ //Create tables for DSC database
+ TRAP(error,CreateTablesL());
+
+ if (KErrNone > error)
+ {
+ //Fail to create tables, destroy the DB, so next time can recreate it
+ DeleteDb();
+ }
+ User::LeaveIfError(error);
+ }
+
+//Default constructor
+CDscDatabase::CDscDatabase():iIsEnumOpened(EFalse)
+ {
+ }
+
+CDscDatabase::~CDscDatabase()
+ {
+ iStmt.Close();
+ iDatabase.Close();
+ }
+
+//Destroy DSC database,
+TInt CDscDatabase::DeleteDb()
+ {
+ iDatabase.Close();
+
+ TBuf<KMaxDatabaseName> databaseName;
+ GetDatabaseName(databaseName);
+ return iDatabase.Delete(databaseName);
+ }
+
+void CDscDatabase::CreateTablesL()
+ {
+ RBuf sqlCmd;
+ CleanupClosePushL(sqlCmd);
+ //Allocate memory for create item table sql cmd which has the most characters.
+ _LIT(KCreateItemTable,"CREATE TABLE %S (%S INTEGER NOT NULL, %S INTEGER NOT NULL, %S VARCHAR (%d)NOT NULL,\
+ %S VARCHAR(%d), %S TINYINT, %S INTEGER, %S INTEGER, %S BIT, %S TINYINT, %S BIT, %S BIT, \
+ UNIQUE(%S, %S))");
+ //the extra characters for the %S, %d in the format string
+ const TInt extraLength=32;
+ //chars in KDscStoreMaxStringLength
+ const TInt lengthOfKDscStoreMaxStringLength=3;
+
+ // The maximum number of characters for create table DscItem sql command
+ const TInt length=KCreateItemTable().Length()+KItemTable().Length()+KDscIdCol().Length()+KItemIdCol().Length()+
+ KFileNameCol().Length()+KArgListCol().Length()+
+ KStartMethodCol().Length()+KTimeoutCol().Length()+KNoOfRetriesCol().Length()+KMonitorCol().Length()+
+ KStartupTypeCol().Length()+KViewlessCol().Length()+KStartInBackgroundCol().Length()+
+ KDscIdCol().Length()+KItemIdCol().Length()-extraLength+2* lengthOfKDscStoreMaxStringLength;
+
+ sqlCmd.CreateL(length);
+
+ //format a sql cmd for create table dsc
+ _LIT(KCreateDscTable,"CREATE TABLE %S (%S INTEGER NOT NULL, %S VARCHAR(%d), PRIMARY KEY(%S))");
+ sqlCmd.Format(KCreateDscTable,&KDscTable,&KDscIdCol,&KDescriptionCol, KDscStoreMaxStringLength, &KDscIdCol);
+
+
+ PrintSqlCmd(sqlCmd);
+
+ //Start a new transaction
+ DatabaseBeginLC();
+
+ //Create Table DSC
+ TInt error=iDatabase.Exec(sqlCmd);
+ User::LeaveIfError(ConvertErrCode(error));
+
+ //Create Table DscItem
+
+ sqlCmd.Format(KCreateItemTable,&KItemTable,&KDscIdCol, &KItemIdCol,&KFileNameCol,KDscStoreMaxStringLength,&KArgListCol,
+ KDscStoreMaxStringLength, &KStartMethodCol, &KTimeoutCol, &KNoOfRetriesCol, &KMonitorCol, &KStartupTypeCol,
+ &KViewlessCol, &KStartInBackgroundCol, &KDscIdCol, &KItemIdCol);
+
+ PrintSqlCmd(sqlCmd);
+
+ error=iDatabase.Exec(sqlCmd);
+ User::LeaveIfError(ConvertErrCode(error));
+ DatabaseCommitLP();
+ CleanupStack::PopAndDestroy(&sqlCmd);
+
+
+
+ }
+
+#ifdef _DEBUG
+//Help, print out SQL message
+void CDscDatabase::PrintSqlCmd(const TDesC& aMess) const
+ {
+ RDebug::RawPrint(aMess);
+ }
+#else
+void CDscDatabase::PrintSqlCmd(const TDesC& /*aMess*/) const
+ {
+
+ }
+#endif
+
+//Add a DSC with aDscId to DSC DB. if the aDscId exists, leave with KErrAlreadyExists
+void CDscDatabase::CreateDscL(const TUid& aDscId, const TDesC& aDescription)
+ {
+ //If the DSC is opened for enumeration, leave with KErrLocked
+ if (iIsEnumOpened)
+ {
+ User::Leave( KErrLocked);
+ }
+
+ //Start a new transaction
+ DatabaseBeginLC();
+
+ //Insert aDscId in Table DSC. If aDscId exists, leave with KErrAlreadyExists
+ RBuf sqlCmd;
+ CleanupClosePushL(sqlCmd);
+
+ _LIT(KSQLQuery,"INSERT INTO %S (%S,%S) VALUES (%d,'%S')");
+
+ //Allocate memory for insert sql cmd
+ const TInt length=KSQLQuery().Length()+ KDscTable().Length()+KDscIdCol().Length()+
+ KDescriptionCol().Length()+aDescription.Length();
+ sqlCmd.CreateL(length);
+
+
+ sqlCmd.Format(KSQLQuery,&KDscTable,&KDscIdCol,&KDescriptionCol, aDscId, &aDescription);
+
+ PrintSqlCmd(sqlCmd);
+
+ TInt error=iDatabase.Exec(sqlCmd);
+ CleanupStack::PopAndDestroy(&sqlCmd);
+ User::LeaveIfError(ConvertErrCode(error));
+
+ DatabaseCommitLP();
+ }
+
+//Delete the DSC with aDscId, all items related to aDscId are deleted too.
+void CDscDatabase::DeleteDscL(const TUid& aDscId)
+ {
+ //If the DSC is opened for enumeration, leave with KErrLocked
+ if (iIsEnumOpened)
+ {
+ User::Leave(KErrLocked);
+ }
+
+ //Start a new transaction
+ DatabaseBeginLC();
+ if (!DscExistsL(aDscId))
+ {
+ // aDscId doesn't exist, leave with KErrNotFound
+ User::Leave(KErrNotFound);
+ }
+
+ //Delete all items related with aDscId first
+ _LIT(KSQLQuery,"DELETE FROM %S WHERE %S=%d ");
+ RBuf sqlCmd;
+ CleanupClosePushL(sqlCmd);
+
+ // the extra characters for the %S, %d in the format string
+ const TInt extraLength=6;
+ //Allocate memory for delete sql cmd
+ const TInt length=KSQLQuery().Length()+ KItemTable().Length()+KDscIdCol().Length()+
+ lengthOfTUint-extraLength ;
+ sqlCmd.CreateL(length);
+ sqlCmd.Format(KSQLQuery,&KItemTable,&KDscIdCol,aDscId);
+ TInt error=iDatabase.Exec(sqlCmd);
+ User::LeaveIfError(ConvertErrCode(error));
+
+ //Delete aDscId from Table DSC
+ sqlCmd.Format(KSQLQuery,&KDscTable,&KDscIdCol,aDscId);
+ error=iDatabase.Exec(sqlCmd);
+ User::LeaveIfError(ConvertErrCode(error));
+ CleanupStack::PopAndDestroy(&sqlCmd);
+ DatabaseCommitLP();
+ }
+
+//Check the existance of the aDscId
+TBool CDscDatabase::DscExistsL(const TUid& aDscId) const
+ {
+
+ RSqlStatement stmt;
+ CleanupClosePushL(stmt);
+
+ _LIT(KSQLQuery,"SELECT %S FROM %S WHERE %S=%d ");
+
+ RBuf sqlCmd;
+ CleanupClosePushL(sqlCmd);
+
+ // the extra characters for the %S, %d in the format string
+ const TInt extraLength=8;
+ //Allocate memory for delete sql cmd
+ const TInt length=KSQLQuery().Length()+ KDscTable().Length()+2*KDscIdCol().Length()+
+ lengthOfTUint-extraLength ;
+ sqlCmd.CreateL(length);
+ sqlCmd.Format(KSQLQuery, &KDscIdCol, &KDscTable,&KDscIdCol,aDscId);
+
+ TInt error=stmt.Prepare(iDatabase, sqlCmd);
+ CleanupStack::PopAndDestroy(&sqlCmd);
+
+ User::LeaveIfError(ConvertErrCode(error));
+
+ error=stmt.Next();
+ User::LeaveIfError(ConvertErrCode(error));
+
+ CleanupStack::PopAndDestroy(&stmt);
+ return KSqlAtRow==error ? ETrue:EFalse;
+ }
+
+//Check the existance of aItem
+TBool CDscDatabase::ItemExistsL( const CDscItem& aItem) const
+ {
+
+ RSqlStatement stmt;
+ CleanupClosePushL(stmt);
+
+ TBool result=QueryItemL(stmt, aItem);
+
+
+
+ CleanupStack::PopAndDestroy(&stmt);
+
+ return result;
+ }
+
+//Query the aItem from Table DscItem
+TBool CDscDatabase::QueryItemL(RSqlStatement& aStmt, const CDscItem& aItem) const
+ {
+
+ RBuf sqlCmd;
+ CleanupClosePushL(sqlCmd);
+
+
+ TUid dscId=aItem.DscId();
+ TPtrC name=aItem.FileName();
+
+ //If fileName is NULL, query aItem by DSC ID and ItemId
+ if (name ==KNullDesC)
+ {
+ _LIT(KSQLQuery,"SELECT %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S FROM %S WHERE %S=%d AND %S=%d ");
+ // the extra characters for the %S, %d in the format string
+ const TInt extraLength=32;
+ //Allocate memory for search sql cmd
+ const TInt length=KSQLQuery().Length()+2*KDscIdCol().Length()+KItemIdCol().Length()+ KFileNameCol().Length()
+ +KArgListCol().Length()+KStartMethodCol().Length()+KTimeoutCol().Length()+KNoOfRetriesCol().Length()
+ +KMonitorCol().Length()+KStartupTypeCol().Length()+KViewlessCol().Length()+KStartInBackgroundCol().Length()
+ +KItemTable().Length()+lengthOfTInt+lengthOfTUint+KItemIdCol().Length()-extraLength;
+ sqlCmd.CreateL(length);
+ sqlCmd.Format(KSQLQuery,&KDscIdCol, &KItemIdCol,&KFileNameCol,&KArgListCol,
+ &KStartMethodCol, &KTimeoutCol, &KNoOfRetriesCol, &KMonitorCol, &KStartupTypeCol,
+ &KViewlessCol, &KStartInBackgroundCol, &KItemTable,&KDscIdCol, dscId, &KItemIdCol,aItem.ItemId());
+ }
+ //Otherwise query aItem by DSC ID, fileName and arguments
+ else
+ {
+ if(name.Length() >KDscStoreMaxStringLength || aItem.Args().Length() >KDscStoreMaxStringLength)
+ {
+ User::Leave(KErrArgument);
+ }
+
+ TBuf<KDscStoreMaxStringLength> argList=aItem.Args();
+ argList.TrimAll();
+
+ _LIT(KSQLQuery,"SELECT %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S FROM %S WHERE %S=%d AND %S= '%S' AND %S = '%S' ");
+ // the extra characters for the %S, %d in the format string
+ const TInt extraLength=36;
+ //Allocate memory for search sql cmd
+ const TInt length=KSQLQuery().Length()+2*KDscIdCol().Length()+KItemIdCol().Length()+ KFileNameCol().Length()
+ +KArgListCol().Length()+KStartMethodCol().Length()+KTimeoutCol().Length()+KNoOfRetriesCol().Length()
+ +KMonitorCol().Length()+KStartupTypeCol().Length()+KViewlessCol().Length()+KStartInBackgroundCol().Length()
+ +KItemTable().Length()+lengthOfTUint+KFileNameCol().Length()+aItem.FileName().Length()
+ +KArgListCol().Length()+argList.Length()-extraLength;
+ sqlCmd.CreateL(length);
+ sqlCmd.Format(KSQLQuery,&KDscIdCol, &KItemIdCol,&KFileNameCol,&KArgListCol, &KStartMethodCol, &KTimeoutCol,
+ &KNoOfRetriesCol, &KMonitorCol, &KStartupTypeCol,&KViewlessCol, &KStartInBackgroundCol,
+ &KItemTable,&KDscIdCol, dscId, &KFileNameCol,&name, &KArgListCol, &argList);
+ }
+
+
+ PrintSqlCmd(sqlCmd);
+
+
+ TInt error=aStmt.Prepare(iDatabase, sqlCmd);
+ CleanupStack::PopAndDestroy(&sqlCmd);
+ if(KErrNone <= error)
+ {
+ error=aStmt.Next(); //no error for non existing item
+ }
+
+ return KSqlAtRow==error? ETrue: EFalse;
+ }
+
+//Open a result set of items with aDscID for enumeration, need to
+//call EnumClose() to close the set after enumeration.
+void CDscDatabase::EnumOpenLC(const TUid& aDscId)
+ {
+ //If the DSC is opened for enumeration, leave with KErrLocked
+ if (iIsEnumOpened)
+ {
+ User::Leave(KErrLocked);
+ }
+ EnumBeginLC();
+ iIsEnumOpened=ETrue;
+
+ //Leave with KErrNotFound if aDscId doesn't exist
+ if (!DscExistsL(aDscId))
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ RBuf sqlCmd;
+ CleanupClosePushL(sqlCmd);
+ _LIT(KSQLQuery,"SELECT %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S FROM %S WHERE %S=%d ORDER BY %S");
+ // the extra characters for the %S, %d in the format string
+ const TInt extraLength=30;
+ //Allocate memory for delete sql cmd
+ const TInt length=KSQLQuery().Length()+ 2*KDscIdCol().Length()+2*KItemIdCol().Length()+ KFileNameCol().Length()
+ +KArgListCol().Length()+KStartMethodCol().Length()+KTimeoutCol().Length()+KNoOfRetriesCol().Length()
+ +KMonitorCol().Length()+KStartupTypeCol().Length()+KViewlessCol().Length()+KStartInBackgroundCol().Length()
+ +KItemTable().Length()+lengthOfTUint-extraLength;
+ sqlCmd.CreateL(length);
+ sqlCmd.Format(KSQLQuery, &KDscIdCol, &KItemIdCol,&KFileNameCol,&KArgListCol,
+ &KStartMethodCol, &KTimeoutCol, &KNoOfRetriesCol, &KMonitorCol, &KStartupTypeCol,
+ &KViewlessCol, &KStartInBackgroundCol,&KItemTable,&KDscIdCol,aDscId, &KItemIdCol);
+
+
+ //Open a result stmt contains all items in aDscId
+ TInt error=iStmt.Prepare(iDatabase, sqlCmd);
+ CleanupStack::PopAndDestroy(&sqlCmd);
+ User::LeaveIfError(ConvertErrCode(error));
+ }
+
+//Enumrating the result stmt opened by EnumOpenLC(), if there are no item in the DSC
+//or has reached the end of the list, return NULL
+CDscItem* CDscDatabase::EnumReadNextL()
+ {
+ if (!iIsEnumOpened)
+ {
+ //EnumOpenLC() has not been called.
+ User::Leave(KErrNotReady);
+ }
+ TInt err=iStmt.Next();
+ User::LeaveIfError(ConvertErrCode(err));
+
+ if (KSqlAtEnd==err)
+ {
+ //reached to the end of the result set
+ return NULL;
+ }
+
+ //Read item from the result stmt
+ CDscItem* item=CDscItem::NewL();
+ CleanupStack::PushL(item);
+ ReadDscItemL(iStmt, *item);
+ CleanupStack::Pop(item);
+ return item;
+ }
+
+//Read aItem from the stmt
+void CDscDatabase::ReadDscItemL(RSqlStatement& aStmt, CDscItem& aItem)
+ {
+ TPtrC name=aStmt.ColumnTextL(2);
+ TPtrC args=aStmt.ColumnTextL(3);
+ aItem.SetDscId(TUid::Uid(aStmt.ColumnInt(0)));
+ aItem.SetItemId(aStmt.ColumnInt(1));
+ aItem.SetFileParamsL(name, args);
+ aItem.SetStartMethodL(static_cast<TStartMethod> (aStmt.ColumnInt(4)));
+ aItem.SetFailureParams(aStmt.ColumnInt(6), aStmt.ColumnInt(5));
+ aItem.SetMonitored(aStmt.ColumnInt(7));
+ aItem.SetStartupType(static_cast<TStartupType> (aStmt.ColumnInt(8)));
+ aItem.SetViewless(aStmt.ColumnInt(9));
+ aItem.SetStartInBackground( aStmt.ColumnInt(10));
+ }
+
+
+//Close the view opened by EnumOpenLC() and rollback the transaction
+void CDscDatabase::EnumClose()
+ {
+ //To avoid double close
+ if (iIsEnumOpened)
+ {
+ iStmt.Close();
+ iIsEnumOpened=EFalse;
+
+ //Roll back transaction
+ Rollback();
+ CleanupStack::Pop();//Pop client CleanupEnumRollback
+ }
+ }
+
+//Add aItem to DSC at aPos
+void CDscDatabase::AddItemL(CDscItem& aItem, TDscPosition aPos)
+ {
+ //Leave if DB is opened for enumeration
+ if (iIsEnumOpened)
+ {
+ User::Leave(KErrLocked);
+ }
+
+ //verify data integrity
+ VerifyDataL(aItem);
+
+ DatabaseBeginLC();
+
+ TUid dscId=aItem.DscId();
+ //Leave if aDscId doesn't exist
+ if (!DscExistsL(dscId))
+ {
+ User::Leave(KErrNotFound);
+ }
+ //Leave if aItem exists
+ if (ItemExistsL( aItem))
+ {
+ User::Leave(KErrAlreadyExists);
+ }
+
+ RBuf sqlCmd;
+ CleanupClosePushL(sqlCmd);
+ //Allocate memory for insert item sql cmd which has the most characters.
+ _LIT(KSQLQuery1,"INSERT INTO %S (%S,%S,%S,%S,%S,%S,%S,%S,%S, %S, %S ) VALUES \
+ (%d,%d,'%S','%S',%d,%d, %d, %b, %d, %b, %b)");
+ // the extra characters for the %S, %d in the format string
+ const TInt extraLength=40;
+ const TInt length=KSQLQuery1().Length()+KItemTable().Length()+KDscIdCol().Length()+KItemIdCol().Length()
+ +KFileNameCol().Length()+KArgListCol().Length()+KStartMethodCol().Length()
+ +KTimeoutCol().Length()+KNoOfRetriesCol().Length()+KMonitorCol().Length()
+ +KStartupTypeCol().Length()+KViewlessCol().Length()+KStartInBackgroundCol().Length()
+ +4*lengthOfTUint+ aItem.FileName().Length()+aItem.Args().Length()-extraLength;
+ sqlCmd.CreateL(length);
+
+ RSqlStatement stmt;
+ CleanupClosePushL(stmt);
+
+
+ //calculate item id according to the position to be inserted
+ //add at ELast: pos =max of itemId+1
+ if (ELast==aPos )
+ {
+ _LIT(KSQLQuery,"SELECT MAX(%S) FROM %S WHERE %S=%d ");
+ sqlCmd.Format(KSQLQuery, &KItemIdCol, &KItemTable,&KDscIdCol, dscId );
+ }
+ //add at EFirst: pos=min of itemId-1
+ else
+ {
+ _LIT(KSQLQuery,"SELECT MIN(%S) FROM %S WHERE %S=%d ");
+ sqlCmd.Format(KSQLQuery, &KItemIdCol, &KItemTable,&KDscIdCol, dscId );
+ }
+
+
+ PrintSqlCmd(sqlCmd);
+
+
+ TInt err=stmt.Prepare(iDatabase, sqlCmd);
+ User::LeaveIfError(ConvertErrCode(err));
+ err=stmt.Next();
+ User::LeaveIfError(ConvertErrCode(err));
+
+ //for empty DSC, 0 will be returned from the stmt, so the initial value
+ //of itemId will be -1 or 1 depend on where to insert,
+ //this is slightly different from DBMS implementation, where
+ //initial value for itemId is always 0
+ //Since itemId is used as reference for relative orders, this should
+ //be acceptable
+
+
+ //Get the next available itemId for the item
+ TInt itemId=GetItemIdL(aPos, stmt);
+
+ CleanupStack::PopAndDestroy(&stmt);
+
+ //set the item id, it will be return to client
+ aItem.SetItemId(itemId);
+
+ //insert item into DSC
+ TPtrC name=aItem.FileName();
+
+ //Trim white space in argment list
+ TBuf<KDscStoreMaxStringLength> argList=aItem.Args();
+ argList.TrimAll();
+
+ sqlCmd.Format(KSQLQuery1,&KItemTable,&KDscIdCol,&KItemIdCol,&KFileNameCol,&KArgListCol,
+ &KStartMethodCol, &KTimeoutCol, &KNoOfRetriesCol, &KMonitorCol, &KStartupTypeCol,
+ &KViewlessCol, &KStartInBackgroundCol, dscId,itemId,&name, &argList, aItem.StartMethod(),
+ aItem.Timeout(), aItem.NoOfRetries(), aItem.Monitored(),
+ aItem.StartupType(), aItem.Viewless(), aItem.StartInBackground());
+
+
+ PrintSqlCmd(sqlCmd);
+
+ err=iDatabase.Exec(sqlCmd);
+ CleanupStack::PopAndDestroy(&sqlCmd);
+ User::LeaveIfError(ConvertErrCode(err));
+
+ DatabaseCommitLP();
+ }
+
+//Delete aItem from DSC
+void CDscDatabase::DeleteItemL( const CDscItem& aItem)
+ {
+ //Leave if DB is opened for enumeration
+ if (iIsEnumOpened)
+ {
+ User::Leave(KErrLocked);
+ }
+
+ DatabaseBeginLC();
+
+ //Leave if aItem does not exist
+ if (!ItemExistsL( aItem))
+ {
+ User::Leave(KErrNotFound);
+ }
+
+
+ RBuf sqlCmd;
+ CleanupClosePushL(sqlCmd);
+
+
+ TPtrC name=aItem.FileName();
+ TUid dscId=aItem.DscId();
+ //Delete the item by itemId
+ if (name==KNullDesC)
+ {
+ _LIT(KSQLQuery,"DELETE FROM %S WHERE %S=%d AND %S=%d ");
+ // the extra characters for the %S, %d in the format string
+ const TInt extraLength=10;
+ const TInt length=KSQLQuery().Length()+KItemTable().Length()+KDscIdCol().Length()+2*lengthOfTUint
+ +KItemIdCol().Length()-extraLength;
+ sqlCmd.CreateL(length);
+
+ sqlCmd.Format(KSQLQuery,&KItemTable,&KDscIdCol, dscId,&KItemIdCol,aItem.ItemId());
+ }
+ //Delete the item by fileName + arguments
+ else
+ {
+
+ TBuf<KDscStoreMaxStringLength> argList=aItem.Args();
+ argList.TrimAll();
+ _LIT(KSQLQuery,"DELETE FROM %S WHERE %S=%d AND %S='%S' AND %S= '%S' ");
+ // the extra characters for the %S, %d in the format string
+ const TInt extraLength=14;
+ const TInt length=KSQLQuery().Length()+KItemTable().Length()+KDscIdCol().Length()+lengthOfTUint
+ +KFileNameCol().Length()+aItem.FileName().Length()+KArgListCol().Length()
+ +aItem.Args().Length()-extraLength;
+ sqlCmd.CreateL(length);
+
+ sqlCmd.Format(KSQLQuery,&KItemTable,&KDscIdCol, dscId,&KFileNameCol,&name, &KArgListCol, &argList);
+ }
+
+ PrintSqlCmd(sqlCmd);
+
+
+ TInt err=iDatabase.Exec(sqlCmd);
+ CleanupStack::PopAndDestroy(&sqlCmd);
+
+ User::LeaveIfError(ConvertErrCode(err));
+ DatabaseCommitLP();
+
+ }
+
+//Update aItem. Unable to update an item only determined by itemId
+void CDscDatabase::UpdateItemL( const CDscItem& aItem)
+ {
+ //Leave if DB is opened for enumeration
+ if (iIsEnumOpened)
+ {
+ User::Leave(KErrLocked);
+ }
+
+ //verify data integrity,
+ VerifyDataL(aItem);
+
+ DatabaseBeginLC();
+ //Leave if aItem does not exist
+ if (!ItemExistsL( aItem))
+ {
+ User::Leave(KErrNotFound);
+ }
+
+
+ RBuf sqlCmd;
+ CleanupClosePushL(sqlCmd);
+
+ TPtrC name=aItem.FileName();
+
+ TBuf<KDscStoreMaxStringLength> argList=aItem.Args();
+ argList.TrimAll();
+ TUid dscId=aItem.DscId();
+
+ //update aItem determined by fileName, argList and dscId. These three fields can't be updated
+ _LIT(KSQLQuery,"UPDATE %S SET %S=%d,%S=%d, %S=%d,%S=%b,%S=%d,%S=%b, %S=%b WHERE %S=%d AND %S='%S' AND %S='%S'");
+ // the extra characters for the %S, %d in the format string
+ const TInt extraLength=38;
+ const TInt length=KSQLQuery().Length()+KItemTable().Length()+KStartMethodCol().Length()+ KTimeoutCol().Length()
+ +3* lengthOfTUint + KNoOfRetriesCol().Length() +KMonitorCol().Length()+ KStartupTypeCol().Length()
+ +KViewlessCol().Length()+ KStartInBackgroundCol().Length()+KDscIdCol().Length()+ KFileNameCol().Length()
+ +KArgListCol().Length()+aItem.FileName().Length()+aItem.Args().Length()-extraLength;
+ sqlCmd.CreateL(length);
+
+ sqlCmd.Format(KSQLQuery,&KItemTable, &KStartMethodCol, aItem.StartMethod(), &KTimeoutCol, aItem.Timeout(),
+ &KNoOfRetriesCol,aItem.NoOfRetries(), &KMonitorCol, aItem.Monitored(), &KStartupTypeCol,aItem.StartupType(),
+ &KViewlessCol, aItem.Viewless(), &KStartInBackgroundCol, aItem.StartInBackground(),
+ &KDscIdCol, dscId, &KFileNameCol, &name, &KArgListCol, &argList);
+
+
+ PrintSqlCmd(sqlCmd);
+
+
+ TInt err=iDatabase.Exec(sqlCmd);
+ CleanupStack::PopAndDestroy(&sqlCmd);
+ User::LeaveIfError(ConvertErrCode(err));
+ DatabaseCommitLP();
+ }
+
+//Read aItem from DSC DB either by fileName, argList and dscId, or by itemId and dscId
+void CDscDatabase::ReadItemL(CDscItem& aItem)
+ {
+ //Leave if DB is opened for enumeration
+ if (iIsEnumOpened)
+ {
+ User::Leave(KErrLocked);
+ }
+
+ DatabaseBeginLC();
+ RSqlStatement stmt;
+ CleanupClosePushL(stmt);
+
+
+ TBool itemExists=QueryItemL(stmt, aItem);
+
+ //aItem exists
+ if(itemExists)
+ {
+ ReadDscItemL(stmt, aItem);
+
+ //Reset all other values to default
+ aItem.SetRecoveryParams(EIgnoreOnFailure,EStartupModeUndefined);
+ aItem.SetLocalizationParamsL(KNullDesC,0);
+ }
+ //aItem does not exist
+ else
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ CleanupStack::PopAndDestroy(&stmt);
+ DatabaseCommitLP();
+ }
+
+
+//Rollback a transaction
+void CDscDatabase::Rollback()
+ {
+ iDatabase.Exec(KRollbackTrans);
+ }
+
+//Verify aItem
+void CDscDatabase::VerifyDataL(const CDscItem& aItem)
+ {
+ TInt noOfRetries=aItem.NoOfRetries();
+
+ //item with empty filename is not allowed to add to DB, or been updated
+ //fileName and argList of aItem is limited to KDscStoreMaxStringLength
+ //noOfRetries is restricted to 0 or 1
+ //StartMethod is retricted to EFireAndForget or EWaitForStart
+ //Recovery policy of DscItem is restricted to IgnoreprocessFailure.
+ if((aItem.FileName()==KNullDesC) ||(aItem.FileName().Length() > KDscStoreMaxStringLength) ||
+ (aItem.Args().Length() > KDscStoreMaxStringLength)||
+ (noOfRetries!=0 && noOfRetries!=1 ) ||(aItem.Timeout() <0) ||
+ (aItem.StartMethod() !=EFireAndForget && aItem.StartMethod() !=EWaitForStart )||
+ (aItem.RecoveryMethod() !=EIgnoreOnFailure ))
+ {
+ User::Leave(KErrArgument);
+ }
+ }
+
+//Start a new transaction.Pushes cleanup rollback action to the cleanup stack.
+void CDscDatabase::DatabaseBeginLC()
+ {
+ TInt err=iDatabase.Exec(KBeginTrans);
+ User::LeaveIfError(ConvertErrCode(err));
+ CleanupStack::PushL(TCleanupItem(CleanupDatabaseRollback,this));
+
+ }
+
+//Commit transaction. Pops cleanup rollback action
+void CDscDatabase::DatabaseCommitLP()
+ {
+ TInt err=iDatabase.Exec(KCommitTrans);
+ User::LeaveIfError(ConvertErrCode(err)); // force a rollback on error
+ // Pop CleanupDatabaseRollback
+ CleanupStack::Pop();
+ }
+
+//Cleanup rollback action for DatabaseBeginLC()
+void CDscDatabase::CleanupDatabaseRollback(TAny *aDatabase)
+ {
+ ASSERT(aDatabase);
+ CDscDatabase* database=static_cast <CDscDatabase *>(aDatabase);
+
+ database->Rollback();
+ }
+
+//Start a new transaction for enumeration.Pushes cleanup rollback action to the cleanup stack.
+void CDscDatabase::EnumBeginLC()
+ {
+
+ TInt err=iDatabase.Exec(KBeginTrans);
+ User::LeaveIfError(ConvertErrCode(err));
+
+ CleanupStack::PushL(TCleanupItem(CleanupEnumRollback,this));
+
+ }
+//Cleanup rollback action for EnumOpenLC()
+void CDscDatabase::CleanupEnumRollback(TAny *aDatabase)
+ {
+ ASSERT(aDatabase);
+ CDscDatabase* database=static_cast <CDscDatabase *>(aDatabase);
+ database->iStmt.Close();
+ database->iIsEnumOpened=EFalse;
+
+ //Roll back transaction
+ database->Rollback();
+ }
+
+//Covert SQLite specific error code to Symbian standard error code
+TInt CDscDatabase::ConvertErrCode(TInt aErr) const
+ {
+ if (-144<=aErr)
+ {
+ return aErr;
+ }
+ TInt err;
+ switch (aErr)
+ {
+ case KSqlErrPermission:
+ err=KErrPermissionDenied;
+ break;
+
+ case KSqlErrBusy:
+ case KSqlErrLocked:
+ err=KErrLocked;
+ break;
+
+ case KSqlErrCorrupt:
+ err=KErrCorrupt;
+ break;
+
+ case KSqlErrAbort:
+ err=KErrAbort;
+ break;
+ case KSqlErrNotFound:
+ err=KErrNotFound;
+ break;
+ case KSqlErrConstraint:
+ err=KErrAlreadyExists;
+ break;
+
+ case KSqlErrFull:
+ err=KErrOverflow;
+ break;
+
+ default:
+ err=KErrGeneral;
+
+ }
+ return err;
+ }
+
+//Get DSC database name
+void CDscDatabase::GetDatabaseNameL(TDes& aDatabaseName)
+ {
+ RFs fs;
+ CleanupClosePushL(fs);
+ User::LeaveIfError(fs.Connect());
+ //Retrieve system drive
+ TDriveNumber driveNumber=fs.GetSystemDrive();
+
+ TChar driveChar;
+ User::LeaveIfError(RFs::DriveToChar(driveNumber, driveChar));
+
+ aDatabaseName.Format(KDatabaseName,&driveChar);
+ CleanupStack::PopAndDestroy(&fs);
+ }
+//Helper function. Get the next available itemId for the item
+TInt CDscDatabase::GetItemIdL(TDscPosition aPos, RSqlStatement& aStmt)
+ {
+ TInt itemId=aStmt.ColumnInt(0);
+
+ if(ELast==aPos )
+ {
+ if(KMaxTInt32==itemId)
+ {
+ User::Leave(KErrOverflow);
+ }
+ ++itemId;
+
+ }
+ else if(EFirst==aPos )
+ {
+ if(KMinTInt32==itemId)
+ {
+ User::Leave(KErrOverflow);
+ }
+ --itemId;
+ }
+ return itemId;
+ }