diff -r 000000000000 -r 4e1aa6a622a0 sysstatemgmt/systemstarter/dscstoresrc/dscdatabase_sql.cpp --- /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 +#include +#include +#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 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 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 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 (aStmt.ColumnInt(4))); + aItem.SetFailureParams(aStmt.ColumnInt(6), aStmt.ColumnInt(5)); + aItem.SetMonitored(aStmt.ColumnInt(7)); + aItem.SetStartupType(static_cast (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 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 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 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 (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 (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; + }