sysstatemgmt/systemstarter/dscstoresrc/dscdatabase.cpp
changeset 0 4e1aa6a622a0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sysstatemgmt/systemstarter/dscstoresrc/dscdatabase.cpp	Tue Feb 02 00:53:00 2010 +0200
@@ -0,0 +1,884 @@
+// 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 <dscitem.h>
+#include "dscdatabase.h"
+#include "sysstartpanic.h"
+
+/**
+The maximum length for a database name: 20 characters.
+@internalComponent 
+@released
+*/
+const TInt KMaxDatabaseName=20;
+
+_LIT(KDatabaseName, "%c:DBS_DSC.db");
+_LIT(KSecureFormat, "secure[2000836D]");
+
+//Table names
+_LIT(KDscTable, "DSC");
+_LIT(KItemTable, "DscItem");
+//Column names
+_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");
+//Index names
+_LIT(KIdIndex, "DscIndex");
+_LIT(KIndex, "Index");
+
+//Max length of respective number when represented as a string
+const TInt KMaxLengthOfEnum = 5;
+const TInt KMaxLengthOfTInt = 11;
+const TInt KMaxLengthOfBoolean = 1;
+
+//
+// SQL Select query definitions
+//
+_LIT(KSqlSelectDscItemOnId,"SELECT %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S FROM %S WHERE %S=%d AND %S=%d");
+const TInt KFormatCharCountDscItemOnId=32; //for the %S and %d in the format string
+const TInt KSqlSelectDscItemOnIdLength = KSqlSelectDscItemOnId().Length() + KDscIdCol().Length() + KItemIdCol().Length() + 
+			KFileNameCol().Length() + KArgListCol().Length() + KStartMethodCol().Length() + KTimeoutCol().Length() + 
+			KNoOfRetriesCol().Length() + KMonitorCol().Length() + KStartupTypeCol().Length() + KViewlessCol().Length() + 
+			KStartInBackgroundCol().Length() + KItemTable().Length() + KDscIdCol().Length() + KMaxLengthOfTInt + 
+			KItemIdCol().Length() + KMaxLengthOfTInt - KFormatCharCountDscItemOnId;
+
+_LIT(KSqlSelectDscItemOnName,"SELECT %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S FROM %S WHERE %S=%d AND %S='%S' AND %S ='%S'"); 
+const TInt KFormatCharCountDscItemOnName=36; //	the extra characters for the %S, %d in the format string
+const TInt KSqlSelectDscItemOnNameLength = KSqlSelectDscItemOnName().Length() + KDscIdCol().Length() + KItemIdCol().Length() + 
+			KFileNameCol().Length() + KArgListCol().Length() + KStartMethodCol().Length() + KTimeoutCol().Length() + 
+			KNoOfRetriesCol().Length() + KMonitorCol().Length() + KStartupTypeCol().Length() + KViewlessCol().Length() + 
+			KStartInBackgroundCol().Length() + KItemTable().Length() + KDscIdCol().Length() + KMaxLengthOfTInt + 
+			KFileNameCol().Length() + KArgListCol().Length() - KFormatCharCountDscItemOnName;
+
+_LIT(KSqlQueryAllItemIds,"SELECT %S FROM %S WHERE %S=%d ORDER BY %S");
+const TInt KFormatCharCountQueryAllItemIds = 10;
+const TInt KSqlQueryAllItemIdsLength = KSqlQueryAllItemIds().Length() + KItemIdCol().Length() + KItemTable().Length() + 
+			KDscIdCol().Length() + KMaxLengthOfTInt + KItemIdCol().Length() - KFormatCharCountQueryAllItemIds;
+
+_LIT(KSqlSelectDsc,"SELECT %S FROM %S WHERE %S=%d");
+const TInt KFormatCharCountSelectDsc = 8;
+const TInt KSqlSelectDscLength = KSqlSelectDsc().Length() + KDscIdCol().Length() + KDscTable().Length() + 
+			KDscIdCol().Length() + KMaxLengthOfTInt - KFormatCharCountSelectDsc; 
+
+_LIT(KSqlSelectDscDescription,"SELECT %S FROM %S WHERE %S=%d");
+const TInt KFormatCharCountSelectDscDescription = 8;
+const TInt KSqlSelectDscDescriptionLength = KSqlSelectDscDescription().Length() + KDescriptionCol().Length() + KDscTable().Length() + 
+			KDscIdCol().Length() + KMaxLengthOfTInt - KFormatCharCountSelectDscDescription;
+
+_LIT(KSqlSelectAllItemsInDsc,"SELECT %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S FROM %S WHERE %S=%d ORDER BY %S"); 
+const TInt KFormatCharCountSelectAllItemsInDsc = 30;
+const TInt KSqlSelectAllItemsInDscLength = KSqlSelectAllItemsInDsc().Length() + 
+					KDscIdCol().Length() + KItemIdCol().Length() + KFileNameCol().Length() + KArgListCol().Length() + 
+					KStartMethodCol().Length() + KTimeoutCol().Length() + KNoOfRetriesCol().Length() + KMonitorCol().Length() + 
+					KStartupTypeCol().Length() + KViewlessCol().Length() + KStartInBackgroundCol().Length() +
+					KItemTable().Length() +	KDscIdCol().Length() + KMaxLengthOfTInt + KItemIdCol().Length() - KFormatCharCountSelectAllItemsInDsc;
+
+//
+// SQL DML definitions
+//
+_LIT(KSqlUpdateUsingName,"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'");
+const TInt KFormatCharCountUpdateUsingName = 42;
+const TInt KSqlUpdateUsingNameLength = KSqlUpdateUsingName().Length() + KItemTable().Length() + 
+			KStartMethodCol().Length() + KMaxLengthOfEnum + KTimeoutCol().Length() + KMaxLengthOfTInt + 
+			KNoOfRetriesCol().Length() + KMaxLengthOfTInt + KMonitorCol().Length() + KMaxLengthOfBoolean + 
+			KStartupTypeCol().Length() + KMaxLengthOfEnum + KViewlessCol().Length() + KMaxLengthOfBoolean + 
+			KStartInBackgroundCol().Length() + KMaxLengthOfBoolean + KDscIdCol().Length() +  KMaxLengthOfTInt + 
+			KFileNameCol().Length() + KArgListCol().Length() - KFormatCharCountUpdateUsingName;
+
+_LIT(KSqlUpdateUsingId,"UPDATE %S SET %S=%d,%S=%d, %S=%d,%S=%b,%S=%d,%S=%b, %S=%b WHERE %S=%d AND %S=%d");
+const TInt KFormatCharCountUpdateUsingId = 38;
+const TInt KSqlUpdateUsingIdLength = KSqlUpdateUsingName().Length() + KItemTable().Length() + 
+			KStartMethodCol().Length() + KMaxLengthOfEnum + KTimeoutCol().Length() + KMaxLengthOfTInt + 
+			KNoOfRetriesCol().Length() + KMaxLengthOfTInt + KMonitorCol().Length() + KMaxLengthOfBoolean + 
+			KStartupTypeCol().Length() + KMaxLengthOfEnum + KViewlessCol().Length() + KMaxLengthOfBoolean + 
+			KStartInBackgroundCol().Length() + KMaxLengthOfBoolean + KDscIdCol().Length() +  KMaxLengthOfTInt + 
+			KItemIdCol().Length() + KMaxLengthOfTInt - KFormatCharCountUpdateUsingId;
+
+_LIT(KSqlDeleteItemUsingId,"DELETE FROM %S WHERE %S=%d AND %S=%d");
+const TInt KFormatCharCountDeleteItemUsingId = 8;
+const TInt KSqlDeleteItemUsingIdLength = KSqlDeleteItemUsingId().Length() + KItemTable().Length() + KDscIdCol().Length() + 
+			KMaxLengthOfTInt + KItemIdCol().Length() + KMaxLengthOfTInt - KFormatCharCountDeleteItemUsingId;
+
+_LIT(KSqlDeleteItemUsingName,"DELETE FROM %S WHERE %S=%d AND %S='%S' AND %S= '%S'");
+const TInt KFormatCharCountDeleteItemUsingName = 14;
+const TInt KSqlDeleteItemUsingNameLength = KSqlDeleteItemUsingName().Length() + KItemTable().Length() + KDscIdCol().Length() + 
+			KMaxLengthOfTInt + KFileNameCol().Length() + KArgListCol().Length() - KFormatCharCountDeleteItemUsingName;
+
+_LIT(KSqlInsertDscItem,"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)");
+const TInt KFormatCharCountInsertDscItem = 46;
+const TInt KSqlInsertDscItemLength = KSqlInsertDscItem().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*KMaxLengthOfTInt) + (2*KMaxLengthOfEnum) + (3*KMaxLengthOfBoolean) - KFormatCharCountInsertDscItem;
+
+_LIT(KSqlInsertDsc,"INSERT INTO %S (%S,%S) VALUES (%d,'%S')");
+const TInt KFormatCharCountInsertDsc = 10;
+const TInt KSqlInsertDscLength = KSqlInsertDsc().Length() + KDscTable().Length() + KDscIdCol().Length() + KDescriptionCol().Length() +
+			KMaxLengthOfTInt - KFormatCharCountInsertDsc;
+
+_LIT(KSqlDeleteUsingId,"DELETE FROM %S WHERE %S=%d ");
+const TInt KFormatCharCountDeleteUsingId = 6;
+const TInt KMaxTableNameLength = Max(KItemTable().Length(), KDscTable().Length());
+const TInt KSqlDeleteUsingIdLength = KSqlDeleteUsingId().Length() + KMaxTableNameLength + KDscIdCol().Length() + KMaxLengthOfTInt - 
+			KFormatCharCountDeleteUsingId;
+
+//
+//SQL DDL definitions
+//
+_LIT(KSqlCreateItemTable,"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)");
+const TInt KFormatCharCountCreateItemTable = 28;
+const TInt KSqlCreateItemTableLength = KSqlCreateItemTable().Length() + KItemTable().Length() + KDscIdCol().Length() + 
+				KItemIdCol().Length() + KFileNameCol().Length() + KMaxLengthOfTInt + KArgListCol().Length() + KMaxLengthOfTInt +
+				KStartMethodCol().Length() + KTimeoutCol().Length() + KNoOfRetriesCol().Length() + KMonitorCol().Length() +
+				KStartupTypeCol().Length() + KViewlessCol().Length() + KStartInBackgroundCol().Length()	- KFormatCharCountCreateItemTable;
+
+_LIT(KSqlCreateDscTable,"CREATE TABLE %S (%S INTEGER NOT NULL, %S VARCHAR(%d))");	
+const TInt KFormatCharCountCreateDscTable = 8;
+const TInt KSqlCreateDscTableLength = KSqlCreateDscTable().Length() + KDscTable().Length() + KDscIdCol().Length() + 
+			KDescriptionCol().Length() + KMaxLengthOfTInt - KFormatCharCountCreateDscTable;
+
+_LIT(KSqlCreateDscIndex,"CREATE UNIQUE INDEX %S ON %S (%S)");
+const TInt KFormatCharCountCreateDscIndex = 6;
+const TInt KSqlCreateDscIndexLength = KSqlCreateDscIndex().Length() + KIdIndex().Length() + KDscTable().Length() + KDscIdCol().Length() - 
+			KFormatCharCountCreateDscIndex;
+
+_LIT(KSqlCreateItemIndex,"CREATE UNIQUE INDEX %S ON %S (%S, %S)");
+const TInt KFormatCharCountCreateItemIndex = 8;
+const TInt KSqlCreateItemIndexLength = KSqlCreateItemIndex().Length() + KIndex().Length() + KItemTable().Length() + KDscIdCol().Length() +
+			KItemIdCol().Length() - KFormatCharCountCreateItemIndex;
+
+const TInt KMaxDdlLength = Max(Max(KSqlCreateDscTableLength,KSqlCreateItemTableLength), Max(KSqlCreateDscIndexLength,KSqlCreateItemIndexLength));
+// The maximum length for varchar
+const TInt KDscStoreMaxStringLength = KDbMaxStrLen;
+
+
+/** Help, print out SQL query */
+static void DebugPrint(const TDesC& aQuery)
+	{
+	(void)aQuery;
+#ifdef _DEBUG
+	RDebug::RawPrint(aQuery);
+#endif
+	}
+
+/**
+Verify aItem. Will leave for following reasons:
+- if filename is empty
+- if filename or argList is >KDbMaxStrLen
+*/
+static void LeaveIfFileParamsNotValidL(const CDscItem& aItem)
+	{
+	//filename and args in a CDscItem is guaranteed to be trimmed of unnecessary whitespace
+	if(	(aItem.FileName().Length() == 0) || 
+		(aItem.FileName().Length() > KDbMaxStrLen) ||
+		(aItem.Args().Length() > KDbMaxStrLen) )
+		{
+		User::Leave(KErrArgument);
+		}
+	}
+
+CDscDatabase* CDscDatabase::NewL()
+	{
+	CDscDatabase* self = new(ELeave) CDscDatabase();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+void CDscDatabase::ConstructL()
+	{
+	//Open database connection 
+	User::LeaveIfError(iDbsSession.Connect());
+	
+	TBuf<KMaxDatabaseName> databaseName;
+	GetDatabaseNameL(databaseName);
+	const TInt error = iDatabase.Open(iDbsSession, databaseName, KSecureFormat);
+	if(KErrNotFound == error)
+		{
+		CreateDatabaseL(databaseName);
+		}
+	else
+		{
+		User::LeaveIfError(error);
+		}
+	}	
+
+//Default constructor	
+CDscDatabase::CDscDatabase() : iIsEnumOpened(EFalse)
+	{
+	}
+	
+CDscDatabase::~CDscDatabase()
+	{
+	if(iIsEnumOpened)
+		{
+		Rollback();
+		}
+	iView.Close();
+	iDatabase.Close();
+	iDbsSession.Close();
+	}
+
+//Destroy DSC database
+TInt CDscDatabase::DeleteDb()
+	{
+	return iDatabase.Destroy();
+	}
+
+void CDscDatabase::CreateDatabaseL(const TDesC& aDatabaseName)
+	{
+	//create it and also open it
+	User::LeaveIfError(iDatabase.Create(iDbsSession, aDatabaseName, KSecureFormat));
+	
+	//Create tables for DSC database
+	TRAPD(error, CreateTablesL());
+	if (KErrNone != error)
+		{
+		//Create table fail,  destroy the DB, so next time can recreate it
+		DeleteDb();
+		}
+	
+	User::LeaveIfError(error);
+	}
+
+void CDscDatabase::CreateTablesL()
+	{
+	RBuf sqlCmd;
+	CleanupClosePushL(sqlCmd);
+	sqlCmd.CreateL(KMaxDdlLength);	
+		
+	//Start a new transaction		
+	DatabaseBeginLC();
+
+	//Create Table DSC
+	sqlCmd.Format(KSqlCreateDscTable, &KDscTable, &KDscIdCol, &KDescriptionCol, KDbUndefinedLength);
+	DebugPrint(sqlCmd);
+	User::LeaveIfError(iDatabase.Execute(sqlCmd));
+
+	//Create unique index for Table DSC
+	sqlCmd.Format(KSqlCreateDscIndex, &KIdIndex, &KDscTable, &KDscIdCol);
+	DebugPrint(sqlCmd);
+ 	User::LeaveIfError(iDatabase.Execute(sqlCmd));
+ 	
+	//Create Table DscItem	
+	sqlCmd.Format(KSqlCreateItemTable, &KItemTable, &KDscIdCol, &KItemIdCol, &KFileNameCol, KDbUndefinedLength, &KArgListCol,
+				KDbUndefinedLength, &KStartMethodCol, &KTimeoutCol, &KNoOfRetriesCol, &KMonitorCol, &KStartupTypeCol,
+				&KViewlessCol, &KStartInBackgroundCol);
+	DebugPrint(sqlCmd);
+	User::LeaveIfError(iDatabase.Execute(sqlCmd));
+	
+	//Create unique index for Table DscItem
+	sqlCmd.Format(KSqlCreateItemIndex, &KIndex, &KItemTable, &KDscIdCol, &KItemIdCol);
+	DebugPrint(sqlCmd);
+	User::LeaveIfError(iDatabase.Execute(sqlCmd));
+	
+	DatabaseCommitL(); //CommitL + CleanupStack::Pop()
+	
+ 	CleanupStack::PopAndDestroy(&sqlCmd);
+	}
+
+//Add a DSC with aDscId to DSC DB. if the aDscId exists, leave with KErrAlreadyExists
+void CDscDatabase::CreateDscL(const TUid& aDscId, const TDesC& aDescription)
+	{
+	//The maximum length of aDescription is KDbMaxStrLen
+	if(aDescription.Length() > KDbMaxStrLen)
+		{
+		User::Leave(KErrArgument);
+		}
+	
+	//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, will leave with KErrAlreadyExists	
+	RBuf sqlCmd;
+	CleanupClosePushL(sqlCmd);
+	sqlCmd.CreateL(KSqlInsertDscLength + aDescription.Length());
+	
+	sqlCmd.Format(KSqlInsertDsc, &KDscTable, &KDscIdCol, &KDescriptionCol, aDscId, &aDescription);
+	DebugPrint(sqlCmd);
+	User::LeaveIfError(iDatabase.Execute(sqlCmd));
+	
+	CleanupStack::PopAndDestroy(&sqlCmd);
+	
+	DatabaseCommitL(); //CommitL + CleanupStack::Pop()
+	}
+
+//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);
+		}
+		
+	RBuf sqlCmd;
+	CleanupClosePushL(sqlCmd);
+	sqlCmd.CreateL(KSqlDeleteUsingIdLength);
+	
+	//Delete all items related with aDscId first
+	sqlCmd.Format(KSqlDeleteUsingId, &KItemTable, &KDscIdCol, aDscId);
+	DebugPrint(sqlCmd);
+	User::LeaveIfError(iDatabase.Execute(sqlCmd));
+
+	//Then delete the row in Table DSC
+	sqlCmd.Format(KSqlDeleteUsingId, &KDscTable, &KDscIdCol, aDscId);	
+	DebugPrint(sqlCmd);
+	User::LeaveIfError(iDatabase.Execute(sqlCmd));
+	
+	CleanupStack::PopAndDestroy(&sqlCmd);
+	
+	DatabaseCommitL(); //CommitL + CleanupStack::Pop()
+	}
+
+//Check the existance of a DSC	
+TBool CDscDatabase::DscExistsL(const TUid& aDscId) const
+	{
+	RDbView view;
+	CleanupClosePushL(view);
+
+	RBuf sqlCmd;
+	CleanupClosePushL(sqlCmd);
+	sqlCmd.CreateL(KSqlSelectDscLength);
+
+	sqlCmd.Format(KSqlSelectDsc, &KDscIdCol, &KDscTable, &KDscIdCol, aDscId);
+	DebugPrint(sqlCmd);
+	User::LeaveIfError(view.Prepare(iDatabase, sqlCmd));
+	User::LeaveIfError(view.EvaluateAll());  
+	const TBool dscExists = !view.IsEmptyL(); 
+	
+	CleanupStack::PopAndDestroy(&sqlCmd);
+	CleanupStack::PopAndDestroy(&view);
+	
+	return (dscExists);
+	}
+
+void CDscDatabase::GetDscDescriptionL(const TUid &aDscId, TDes& aDescription) const
+	{	
+	RDbView view;
+	CleanupClosePushL(view);
+
+	RBuf sqlCmd;
+	CleanupClosePushL(sqlCmd);
+	sqlCmd.CreateL(KSqlSelectDscDescriptionLength);
+	
+	sqlCmd.Format(KSqlSelectDscDescription, &KDescriptionCol, &KDscTable, &KDscIdCol, aDscId);
+	DebugPrint(sqlCmd);
+	User::LeaveIfError(view.Prepare(iDatabase, sqlCmd));
+	User::LeaveIfError(view.EvaluateAll());  
+	CleanupStack::PopAndDestroy(&sqlCmd);
+	
+	if(view.IsEmptyL())
+		{
+		User::Leave(KErrNotFound);
+		}
+	
+ 	view.FirstL();
+	view.GetL();
+	
+	//Check the length of aDescription
+	TPtrC description(view.ColDes(1));
+	if (description.Length() > aDescription.MaxLength())
+		{
+		User::Leave(KErrOverflow);
+		}
+	
+	aDescription.Zero();	
+	aDescription=description;
+	
+	CleanupStack::PopAndDestroy(&view);
+	}
+
+//Check the existance of aItem
+TBool CDscDatabase::ItemExistsL( const CDscItem& aItem) const
+	{
+	RDbView view;
+	CleanupClosePushL(view);
+
+	QueryItemL(view, aItem);
+	const TBool itemExists = !view.IsEmptyL();
+
+	CleanupStack::PopAndDestroy(&view);  
+	return (itemExists);
+	}
+
+//Query the aItem from Table DscItem	
+void CDscDatabase::QueryItemL(RDbView& aView, const CDscItem& aItem) const
+	{
+	RBuf sqlCmd;
+	CleanupClosePushL(sqlCmd);
+	
+	if (aItem.ItemId())
+		{
+		sqlCmd.CreateL(KSqlSelectDscItemOnIdLength);
+		sqlCmd.Format(	KSqlSelectDscItemOnId, &KDscIdCol, &KItemIdCol, &KFileNameCol, 
+						&KArgListCol,&KStartMethodCol, &KTimeoutCol, &KNoOfRetriesCol, 
+						&KMonitorCol, &KStartupTypeCol, &KViewlessCol, &KStartInBackgroundCol, 
+						&KItemTable, &KDscIdCol, aItem.DscId(), &KItemIdCol, aItem.ItemId());
+		}
+	else 
+		{
+		const TPtrC filename = aItem.FileName();
+		const TPtrC argList = aItem.Args();	//whitespace already trimmed
+		
+		LeaveIfFileParamsNotValidL(aItem);
+			
+		const TInt length = KSqlSelectDscItemOnNameLength + filename.Length() + argList.Length();
+		sqlCmd.CreateL(length);
+		sqlCmd.Format(KSqlSelectDscItemOnName, &KDscIdCol, &KItemIdCol, &KFileNameCol,&KArgListCol, &KStartMethodCol, 
+					 &KTimeoutCol, &KNoOfRetriesCol, &KMonitorCol, &KStartupTypeCol, &KViewlessCol, &KStartInBackgroundCol, 
+					 &KItemTable, &KDscIdCol, aItem.DscId(), &KFileNameCol, &filename, &KArgListCol, &argList);
+		}
+
+	DebugPrint(sqlCmd);
+	
+	User::LeaveIfError(aView.Prepare(iDatabase, sqlCmd));
+	User::LeaveIfError(aView.EvaluateAll());  //no error for non existing item
+	CleanupStack::PopAndDestroy(&sqlCmd);	
+	}
+
+
+//Open a view of items with aDscID for enumeration, need to 
+//call EnumClose() to close the view after enumeration.	
+void CDscDatabase::EnumOpenLC(const TUid& aDscId)
+	{
+	//If the DSC is opened for enumeration, leave with KErrLocked
+	if (iIsEnumOpened)
+		{
+		User::Leave(KErrLocked);
+		}
+		
+	//Start a new transaction to add read-lock on DSC	
+	EnumBeginLC();
+		
+	//Leave with KErrNotFound if aDscId doesn't exist
+	if (!DscExistsL(aDscId))
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	iIsEnumOpened = ETrue;
+
+	//Open a view contains all items in aDscId
+	RBuf sqlCmd;
+	CleanupClosePushL(sqlCmd);
+	sqlCmd.CreateL(KSqlSelectAllItemsInDscLength);
+	
+	sqlCmd.Format(KSqlSelectAllItemsInDsc, &KDscIdCol, &KItemIdCol, &KFileNameCol, &KArgListCol,
+				&KStartMethodCol, &KTimeoutCol, &KNoOfRetriesCol, &KMonitorCol, &KStartupTypeCol,
+				&KViewlessCol, &KStartInBackgroundCol, &KItemTable, &KDscIdCol, aDscId, &KItemIdCol);
+	DebugPrint(sqlCmd);
+	User::LeaveIfError(iView.Prepare(iDatabase, sqlCmd));
+	User::LeaveIfError(iView.EvaluateAll());  //no error for non existing item
+	CleanupStack::PopAndDestroy(&sqlCmd);
+	}
+
+
+//Enumerating the view 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);
+		}
+		
+	if (!iView.NextL())
+		{
+		//reached to the end of the view
+		return NULL;
+		}
+	
+	//Read item from the view
+	CDscItem* item=CDscItem::NewL();
+	CleanupStack::PushL(item);
+	ReadDscItemL(iView, *item);
+
+	CleanupStack::Pop(item);
+	return item;
+	}	
+
+//Read aItem from the view.
+//Cannot use ReadItemL because we want the read-lock to remain
+void CDscDatabase::ReadDscItemL(RDbRowSet& rowSet, CDscItem& aItem) const
+	{	
+	rowSet.GetL();
+
+	aItem.SetDscId(TUid::Uid(rowSet.ColInt(1)));
+	if( 0 == aItem.ItemId() )
+		{
+		aItem.SetItemId(rowSet.ColInt(2));
+		}
+	else
+		{
+		__ASSERT_ALWAYS(aItem.ItemId() == rowSet.ColInt(2), PanicNow(KPanicDsc, EIdCannotChange));
+		}
+	aItem.SetFileParamsL(rowSet.ColDes(3), rowSet.ColDes(4));
+	aItem.SetStartMethodL(static_cast<TStartMethod> (rowSet.ColInt8(5)));
+	aItem.SetNoOfRetriesL(rowSet.ColInt(7));
+	aItem.SetTimeoutL(rowSet.ColInt32(6));
+	aItem.SetMonitored(rowSet.ColInt8(8));
+	aItem.SetStartupType(static_cast<TStartupType> (rowSet.ColInt8(9)));
+	aItem.SetViewless(rowSet.ColInt8(10));
+	aItem.SetStartInBackground( rowSet.ColInt8(11));
+	}
+
+//Close the view opened by EnumOpenLC() and rollback the transaction
+void CDscDatabase::EnumClose()
+	{
+	//To avoid double close
+	if (iIsEnumOpened)
+		{
+		iView.Close();
+		iIsEnumOpened=EFalse;
+		
+		//Roll back transaction
+		Rollback();
+		}
+	}
+
+//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,
+	LeaveIfFileParamsNotValidL(aItem);
+	if(aItem.ItemId() != 0)
+		{
+		User::Leave(KErrArgument);
+		}
+
+	//Start transaction
+	DatabaseBeginLC();
+
+	//Leave if aDscId doesn't exist
+	if (!DscExistsL(aItem.DscId()))
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	//Leave if aItem exists
+	if (ItemExistsL(aItem))
+		{
+		User::Leave(KErrAlreadyExists);
+		}
+
+	const TPtrC filename = aItem.FileName();
+	const TPtrC argList = aItem.Args();	//whitespace already trimmed
+	const TInt itemId = GetNextItemIdL(aPos, aItem.DscId());
+	
+	RBuf sqlCmd;
+	CleanupClosePushL(sqlCmd);
+	sqlCmd.CreateL(KSqlInsertDscItemLength + filename.Length() + argList.Length());
+	
+	//insert the item
+	sqlCmd.Format(KSqlInsertDscItem, &KItemTable, &KDscIdCol, &KItemIdCol, &KFileNameCol, &KArgListCol,
+				&KStartMethodCol, &KTimeoutCol, &KNoOfRetriesCol, &KMonitorCol, &KStartupTypeCol,
+				&KViewlessCol, &KStartInBackgroundCol, aItem.DscId(), itemId, &filename, &argList, aItem.StartMethod(),
+				aItem.Timeout(), aItem.NoOfRetries(), aItem.Monitored(),
+				aItem.StartupType(), aItem.Viewless(), aItem.StartInBackground());
+
+	DebugPrint(sqlCmd);
+	
+	User::LeaveIfError(iDatabase.Execute(sqlCmd));
+	CleanupStack::PopAndDestroy(&sqlCmd);
+	DatabaseCommitL(); //CommitL + CleanupStack::Pop()
+	
+	//Now aItem is persistent, set the ItemId so it can be read by the client
+	aItem.SetItemId(itemId);
+	}
+
+//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);
+	
+	if (aItem.ItemId())
+		{
+		sqlCmd.CreateL(KSqlDeleteItemUsingIdLength);
+		sqlCmd.Format(KSqlDeleteItemUsingId, &KItemTable, &KDscIdCol, aItem.DscId(), &KItemIdCol, aItem.ItemId());
+		}
+	else
+		{
+		const TPtrC filename = aItem.FileName();
+		const TPtrC argList = aItem.Args();	//whitespace already trimmed
+		
+		LeaveIfFileParamsNotValidL(aItem);
+	
+		const TInt length = KSqlDeleteItemUsingNameLength + filename.Length() + argList.Length();
+		sqlCmd.CreateL(length);
+		sqlCmd.Format(KSqlDeleteItemUsingName, &KItemTable, &KDscIdCol, aItem.DscId(), &KFileNameCol, &filename, &KArgListCol, &argList);
+		}
+
+	DebugPrint(sqlCmd);
+
+	User::LeaveIfError(iDatabase.Execute(sqlCmd));
+	CleanupStack::PopAndDestroy(&sqlCmd);
+	DatabaseCommitL(); //CommitL + CleanupStack::Pop()
+	}
+	
+//Update aItem. 
+void CDscDatabase::UpdateItemL(const CDscItem& aItem)
+	{
+	//Leave if DB is opened for enumeration
+	if (iIsEnumOpened)
+		{
+		User::Leave(KErrLocked);
+		}
+
+	if(aItem.ItemId() == 0)
+		{
+		LeaveIfFileParamsNotValidL(aItem);
+		}
+
+	DatabaseBeginLC();
+
+	//Leave if aItem does not exist
+	if (!ItemExistsL( aItem))
+		{
+		User::Leave(KErrNotFound);	
+		}
+	
+	RBuf sqlCmd;
+	CleanupClosePushL(sqlCmd);
+
+	if (aItem.ItemId())
+		{
+		sqlCmd.CreateL(KSqlUpdateUsingIdLength);
+		sqlCmd.Format(KSqlUpdateUsingId, &KItemTable, &KStartMethodCol, aItem.StartMethod(), &KTimeoutCol, aItem.Timeout(),
+				&KNoOfRetriesCol, aItem.NoOfRetries(), &KMonitorCol, aItem.Monitored(), &KStartupTypeCol, aItem.StartupType(),
+				&KViewlessCol, aItem.Viewless(), &KStartInBackgroundCol, aItem.StartInBackground(),
+				&KDscIdCol, aItem.DscId(), &KItemIdCol, aItem.ItemId());
+		}
+	else 
+		{
+		const TPtrC filename = aItem.FileName();
+		const TPtrC argList = aItem.Args();	//whitespace already trimmed
+		
+		const TInt length = KSqlUpdateUsingNameLength + filename.Length() + argList.Length();
+		sqlCmd.CreateL(length);		
+		sqlCmd.Format(KSqlUpdateUsingName, &KItemTable, &KStartMethodCol, aItem.StartMethod(), &KTimeoutCol, aItem.Timeout(),
+						&KNoOfRetriesCol, aItem.NoOfRetries(), &KMonitorCol, aItem.Monitored(), &KStartupTypeCol, aItem.StartupType(),
+						&KViewlessCol, aItem.Viewless(), &KStartInBackgroundCol, aItem.StartInBackground(),
+						&KDscIdCol, aItem.DscId(), &KFileNameCol, &filename, &KArgListCol, &argList);
+		}
+
+	DebugPrint(sqlCmd);
+		
+	User::LeaveIfError(iDatabase.Execute(sqlCmd));	
+	CleanupStack::PopAndDestroy(&sqlCmd);
+	DatabaseCommitL(); //CommitL + CleanupStack::Pop()
+	}
+
+//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();	
+
+	RDbView view;
+	CleanupClosePushL(view);
+	
+	QueryItemL(view,  aItem);
+	if(view.CountL()==0)
+		{
+		 //aItem does not exist
+		User::Leave(KErrNotFound);	
+		}
+	else
+		{
+		view.FirstL(); 
+		ReadDscItemL(view, aItem);
+		}
+	
+	CleanupStack::PopAndDestroy(2); //view and CleanupDatabaseRollback
+	}
+
+//Rollback transaction	
+void CDscDatabase::Rollback()
+	{
+	iDatabase.Rollback();
+	if(iDatabase.IsDamaged())
+		{
+		iDatabase.Recover();
+		}
+	}
+
+//Start a new transaction.Pushes cleanup rollback action to the cleanup stack. 
+void CDscDatabase::DatabaseBeginLC()
+	{
+	User::LeaveIfError(iDatabase.Begin());	
+	CleanupStack::PushL(TCleanupItem(CleanupDatabaseRollback, this));
+	}
+	
+//Commit transaction. Pops cleanup rollback action
+void CDscDatabase::DatabaseCommitL()
+	{
+	User::LeaveIfError(iDatabase.Commit());
+	// 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()
+	{
+	User::LeaveIfError(iDatabase.Begin());	
+	CleanupStack::PushL(TCleanupItem(CleanupEnumRollback, this));
+	}
+		
+//Cleanup rollback action for EnumOpenLC()
+void CDscDatabase::CleanupEnumRollback(TAny *aDatabase)
+	{
+	ASSERT(aDatabase);
+	if(aDatabase)
+		static_cast <CDscDatabase*>(aDatabase)->EnumClose();
+	}
+	
+//Get DSC database name
+void CDscDatabase::GetDatabaseNameL(TDes& aDatabaseName)
+	{
+	RFs fs;
+	CleanupClosePushL(fs);
+	User::LeaveIfError(fs.Connect());
+	
+	// retrieve system drive
+	TDriveNumber driveNumber = fs.GetSystemDrive();
+ 
+	// convert to char
+    TChar driveChar;
+    User::LeaveIfError(RFs::DriveToChar(driveNumber, driveChar));
+ 
+	aDatabaseName.Format(KDatabaseName, (TUint)driveChar);
+	CleanupStack::PopAndDestroy(&fs);
+	}
+
+	
+/**
+Helper function. Get the next available itemId for the item.
+Reads all existing ItemIds for the specified DscId, then calculates last+1
+or first-1 depending on aPos. Will never return 0 as its reserved to mean
+not yet persistent.
+*/
+TInt CDscDatabase::GetNextItemIdL(TDscPosition aPos, const TUid& aDscId) const
+	{	
+	RDbView view;
+	CleanupClosePushL(view);
+	RBuf sqlCmd;
+	CleanupClosePushL(sqlCmd);
+	
+	sqlCmd.CreateL(KSqlQueryAllItemIdsLength);
+	sqlCmd.Format(KSqlQueryAllItemIds, &KItemIdCol, &KItemTable,&KDscIdCol, aDscId, &KItemIdCol );
+
+	DebugPrint(sqlCmd);
+	
+	User::LeaveIfError(view.Prepare(iDatabase, sqlCmd));
+	User::LeaveIfError(view.EvaluateAll());  		
+	CleanupStack::PopAndDestroy(&sqlCmd);
+	
+	TInt nextId = 1; //add first item with id=1 and reserve 0 to mean "not yet persistent"
+	if (aPos==ELast && view.LastL())
+		{
+		//add at ELast: pos =max of itemId+1
+		view.GetL();
+		nextId = view.ColInt(1);
+		if(KMaxTInt == nextId)
+			{
+			User::Leave(KErrOverflow);
+			}
+		//increase, make sure to not use 0 as itemid in the database
+		nextId = (-1==nextId) ? (nextId+2) : (nextId+1);
+		}		
+	else if (aPos==EFirst && view.FirstL())
+		{
+		//add at EFirst: pos=min of itemId-1	
+		view.GetL();
+		nextId = view.ColInt(1);
+		if(KMinTInt == nextId)
+			{
+			User::Leave(KErrUnderflow);
+			}
+		//decrease, but reserve 0 to mean "not yet persistent"
+		nextId = (1==nextId) ? (nextId-2) : (nextId-1);
+		}
+	
+	CleanupStack::PopAndDestroy(&view);
+	return nextId;
+	}
+
+TInt CDscDatabase::MaxStringLength()
+	{
+	return KDbMaxStrLen; //defined in d32dbms.h
+	}
+