persistentstorage/sql/TEST/t_sqlfserr.cpp
changeset 0 08ec8eefde2f
child 8 fa9941cf3867
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/sql/TEST/t_sqlfserr.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,1128 @@
+// 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:
+//
+
+#include <e32test.h>
+#include <bautils.h>
+#include <sqldb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> 
+#include "sqlite3.h"
+#include "SqliteSymbian.h"
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+RTest TheTest(_L("t_sqlfserr test"));
+_LIT(KTestDir, "c:\\test\\");
+_LIT(KTestDbName, "c:\\test\\t_fserr.db");
+TFileName TheRmvMediaDbFileName;//The name of the file used for tests on a removable media
+RFs TheFs;
+RSqlDatabase TheDb;
+
+//The next constants are used in the "blob write" test
+const TInt KWriteCnt = 9;
+const TInt KBlobSize = 397 * KWriteCnt;
+_LIT(KAttachDb, "AttachDb");
+
+//In order to be able to compile the test, the following variables are defined (used inside the OS porting layer, when _SQLPROFILER macro is defined)
+#ifdef _SQLPROFILER
+TInt TheSqlSrvProfilerFileRead = 0;
+TInt TheSqlSrvProfilerFileWrite = 0;
+TInt TheSqlSrvProfilerFileSync = 0;
+TInt TheSqlSrvProfilerFileSetSize = 0;
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+TBool FileExists(const TDesC& aFileName)
+	{
+	TEntry entry;
+	return TheFs.Entry(aFileName, entry) == KErrNone;
+	}
+
+void DestroyTestEnv()
+	{
+	TheDb.Close();
+	(void)RSqlDatabase::Delete(KTestDbName);
+	(void)RSqlDatabase::Delete(TheRmvMediaDbFileName);
+	TheFs.Close();
+	sqlite3SymbianLibFinalize();
+	CloseSTDLIB();
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+//Test macros and functions
+void Check(TInt aValue, TInt aLine)
+	{
+	if(!aValue)
+		{
+		DestroyTestEnv();
+		TheTest(EFalse, aLine);
+		}
+	}
+void Check(TInt aValue, TInt aExpected, TInt aLine)
+	{
+	if(aValue != aExpected)
+		{
+		DestroyTestEnv();
+		RDebug::Print(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue);
+		TheTest(EFalse, aLine);
+		}
+	}
+#define TEST(arg) ::Check((arg), __LINE__)
+#define TEST2(aValue, aExpected) ::Check(aValue, aExpected, __LINE__)
+
+void SqliteCheck(sqlite3* aDbHandle, TInt aValue, TInt aExpected, TInt aLine)
+	{
+	if(aValue != aExpected)
+		{
+		RDebug::Print(_L("*** SQLITE: Expected error: %d, got: %d\r\n"), aExpected, aValue);
+		if(aDbHandle)
+			{
+			const char* errMsg = sqlite3_errmsg(aDbHandle);
+			TPtrC8 ptr8((const TUint8*)errMsg, strlen(errMsg));
+			TBuf<200> buf;
+			buf.Copy(ptr8);
+			RDebug::Print(_L("*** SQLITE error message: \"%S\"\r\n"), &buf);
+			}
+		DestroyTestEnv();
+		TheTest(EFalse, aLine);
+		}
+	}
+#define SQLITE_TEST(aDbHandle, aValue, aExpected) ::SqliteCheck(aDbHandle, aValue, aExpected, __LINE__)
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+void SetupTestEnv()
+    {
+	TInt err = TheFs.Connect();
+	TEST2(err, KErrNone);
+
+	err = TheFs.MkDir(KTestDir);
+	TEST(err == KErrNone || err == KErrAlreadyExists);
+
+	sqlite3SymbianLibInit();
+	}
+
+TBool CheckRecord(TInt aId, const TDesC& aExpectedName, TBool aOpenDb = ETrue)
+	{
+	if(aOpenDb)
+		{
+		TEST2(TheDb.Open(KTestDbName), KErrNone);
+		}
+	TBuf<64> sql;
+	sql.Copy(_L("SELECT Name FROM A WHERE Id="));
+	sql.AppendNum(aId);
+	TSqlScalarFullSelectQuery q(TheDb);
+	TBuf<20> name;
+	TRAPD(err, (void)q.SelectTextL(sql, name));
+	TEST2(err, KErrNone);
+	if(aOpenDb)
+		{
+		TheDb.Close();
+		}
+	return name == aExpectedName;
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-3419
+@SYMTestCaseDesc		Test for DEF103859 "SQLITE panic, _DEBUG mode, persistent file I/O error simulation".
+						The test creates a test database with one table, inserts one record.
+						Then the test attempts to update the existing record while simulating file I/O failures.
+						After each test iteration the database content is tested and is expected to be the same
+						as it was before the test. RSqlDatabase::Exec() is used for the update operation.
+@SYMTestPriority		High
+@SYMTestActions			Test for DEF103859 "SQLITE panic, _DEBUG mode, persistent file I/O error simulation".
+@SYMTestExpectedResults The test must not fail
+@SYMDEF					DEF103859
+*/
+void AlterDatabaseTest()
+	{
+	(void)RSqlDatabase::Delete(KTestDbName);
+	TInt err = TheDb.Create(KTestDbName);
+	TEST2(err, KErrNone);
+	err = TheDb.Exec(_L("CREATE TABLE A(Id INTEGER,Name TEXT)"));
+	TEST(err >= 0);
+	TheDb.Close();
+	err = KErrNotFound;
+	for(TInt cnt=1;err<KErrNone;++cnt)
+		{
+		TheTest.Printf(_L("%d \r"), cnt);		
+		for (TInt fsError=KErrNotFound;fsError>=KErrDied;--fsError)
+			{
+			//Preprocessing
+			TEST2(TheDb.Open(KTestDbName), KErrNone);
+			(void)TheDb.Exec(_L("DELETE FROM A WHERE Id=1"));
+			err = TheDb.Exec(_L("INSERT INTO A(Id,Name) VALUES(1,'Name')"));
+			TEST2(err, 1);
+			//The test
+			(void)TheFs.SetErrorCondition(fsError, cnt);
+			err = TheDb.Exec(_L("UPDATE A SET Name='Name2' WHERE Id=1"));
+			(void)TheFs.SetErrorCondition(KErrNone);
+			if(err < 1)
+				{
+				TheDb.Close();//close the database to recover from the last error
+				//check the database content - all bets are off in a case of an I/O error. 
+				//The existing record might have been updated.
+				TEST(CheckRecord(1, _L("Name")) || CheckRecord(1, _L("Name2")));
+				}
+			else
+				{
+				TEST2(err, 1);
+				//check the database content has been modified by the operation. 
+				TEST(CheckRecord(1, _L("Name2"), EFalse));
+				TheDb.Close();
+				}
+			}
+		}
+	(void)TheFs.SetErrorCondition(KErrNone);
+	TEST2(err, 1);
+	//check the database content (transaction durability). 
+	TEST(CheckRecord(1, _L("Name2")));
+	err = RSqlDatabase::Delete(KTestDbName);
+	TEST2(err, KErrNone);
+	TheTest.Printf(_L("\r\n"));
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-3420
+@SYMTestCaseDesc		Test for DEF103859 "SQLITE panic, _DEBUG mode, persistent file I/O error simulation".
+						The test creates a test database with one table, inserts one record.
+						Then the test attempts to update the existing record while simulating file I/O failures.
+						After each test iteration the database content is tested and is expected to be the same
+						as it was before the test. RSqlStatement::Exec() is used for the update operation.
+@SYMTestPriority		High
+@SYMTestActions			Test for DEF103859 "SQLITE panic, _DEBUG mode, persistent file I/O error simulation".
+@SYMTestExpectedResults The test must not fail
+@SYMDEF					DEF103859
+*/
+void AlterDatabaseTest2()
+	{
+	(void)RSqlDatabase::Delete(KTestDbName);
+	TInt err = TheDb.Create(KTestDbName);
+	TEST2(err, KErrNone);
+	err = TheDb.Exec(_L("CREATE TABLE A(Id INTEGER,Name TEXT)"));
+	TEST(err >= 0);
+	TheDb.Close();
+	err = KErrNotFound;
+	for(TInt cnt=1;err<KErrNone;++cnt)
+		{
+		TheTest.Printf(_L("%d \r"), cnt);		
+		for (TInt fsError=KErrNotFound;fsError>=KErrDied;--fsError)
+			{
+			//Preprocessing
+			TEST2(TheDb.Open(KTestDbName), KErrNone);
+			(void)TheDb.Exec(_L("DELETE FROM A WHERE Id=1"));
+			err = TheDb.Exec(_L("INSERT INTO A(Id,Name) VALUES(1,'Name')"));
+			TEST2(err, 1);
+			//The test
+			(void)TheFs.SetErrorCondition(fsError, cnt);
+			RSqlStatement stmt;
+			err = stmt.Prepare(TheDb, _L("UPDATE A SET Name='Name2' WHERE Id=1"));
+			if(err == KErrNone)
+				{
+				err = stmt.Exec();	
+				}
+			(void)TheFs.SetErrorCondition(KErrNone);
+			stmt.Close();
+			if(err < 1)
+				{
+				TheDb.Close();//close the database to recover from the last error
+				//check the database content - all bets are off in a case of an I/O error. 
+				//The existing record might have been updated.
+				TEST(CheckRecord(1, _L("Name")) || CheckRecord(1, _L("Name2")));
+				}
+			else
+				{
+				TEST2(err, 1);
+				//check the database content has been modified by the operation. 
+				TEST(CheckRecord(1, _L("Name2"), EFalse));
+				TheDb.Close();
+				}
+			}
+		}
+	(void)TheFs.SetErrorCondition(KErrNone);
+	TEST2(err, 1);
+	//check the database content has been modified by the operation. 
+	TEST(CheckRecord(1, _L("Name2")));
+	err = RSqlDatabase::Delete(KTestDbName);
+	TEST2(err, KErrNone);
+	TheTest.Printf(_L("\r\n"));
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-3421
+@SYMTestCaseDesc		Test for DEF103859 "SQLITE panic, _DEBUG mode, persistent file I/O error simulation".
+						The test creates a test database with one table, inserts one record.
+						Then the test attempts to open the database while simulating file I/O failures.
+						At the end of the test the database content is tested and is expected to be the same
+						as it was before the test. RSqlStatement::Open() is used in the test.
+@SYMTestPriority		High
+@SYMTestActions			Test for DEF103859 "SQLITE panic, _DEBUG mode, persistent file I/O error simulation".
+@SYMTestExpectedResults The test must not fail
+@SYMDEF					DEF103859
+*/
+void OpenDatabaseTest()
+	{
+	(void)RSqlDatabase::Delete(KTestDbName);
+	TInt err = TheDb.Create(KTestDbName);
+	TEST2(err, KErrNone);
+	err = TheDb.Exec(_L("CREATE TABLE A(Id INTEGER,Name TEXT)"));
+	TEST(err >= 0);
+	err = TheDb.Exec(_L("INSERT INTO A(Id,Name) VALUES(1,'Name')"));
+	TEST2(err, 1);
+	TheDb.Close();
+
+	err = KErrNotFound;
+	for(TInt cnt=1;err<KErrNone;++cnt)
+		{		
+		TheTest.Printf(_L("%d \r"), cnt);		
+		for (TInt fsError=KErrNotFound;fsError>=KErrDied;--fsError)
+			{
+			(void)TheFs.SetErrorCondition(fsError, cnt);
+			err = TheDb.Open(KTestDbName);
+			(void)TheFs.SetErrorCondition(KErrNone);
+			if(err != KErrNone)
+				{
+				TheDb.Close();//close the database to recover from the last error
+				//check the database content is still the same as before the "open" call
+				TEST(CheckRecord(1, _L("Name")));
+				}
+			else
+				{
+				TEST2(err, KErrNone);
+				//check the database content is still the same as before the operation, without closing the database
+				TEST(CheckRecord(1, _L("Name"), EFalse));
+				TheDb.Close();
+				}
+			}
+		}
+	(void)TheFs.SetErrorCondition(KErrNone);
+	TEST2(err, KErrNone);
+	//check the database content is the same as before the operation, after reopening the database.
+	TEST(CheckRecord(1, _L("Name")));
+	err = RSqlDatabase::Delete(KTestDbName);
+	TEST2(err, KErrNone);
+	TheTest.Printf(_L("\r\n"));
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-3434
+@SYMTestCaseDesc		Test for DEF104820 "SQL, RSqlDatabase::Create() does not delete the file if fails".
+						Test for DEF103859 "SQLITE panic, _DEBUG mode, persistent file I/O error simulation".
+						Then the test attempts to create a database while simulating file I/O failures.
+						When the test succeeds, the test verifies that the database file does exist.
+@SYMTestPriority		High
+@SYMTestActions			Test for DEF104820 "SQL, RSqlDatabase::Create() does not delete the file if fails".
+						Test for DEF103859 "SQLITE panic, _DEBUG mode, persistent file I/O error simulation".
+@SYMTestExpectedResults The test must not fail
+@SYMDEF					DEF103859
+*/
+void CreateDatabaseTest()
+	{
+	TInt err = -1;
+	for(TInt cnt=1;err<KErrNone;++cnt)
+		{		
+		TheTest.Printf(_L("%d \r"), cnt);		
+		for (TInt fsError=KErrNotFound;fsError>=KErrDied;--fsError)
+			{
+			//Ideally, the database should be deleted by the SQL server, if RSqlDatabase::Create() fails.
+			//But SetErrorCondition() makes the error persistent, so the SQL server will fail to delete the file.
+			//This is the reason, RSqlDatabase::Delete()to be used, before simulating file I/O error.
+			(void)RSqlDatabase::Delete(KTestDbName);
+			(void)TheFs.SetErrorCondition(fsError, cnt);
+			err = TheDb.Create(KTestDbName);
+			(void)TheFs.SetErrorCondition(KErrNone);
+			TheDb.Close();
+			//If err != KErrNone, the database file should have been already deleted by the server and here is 
+			//the place to check that. But since the file I/O failure simulation makes the file I/O error 
+			//persistent, the file cannot be deleted by the server, because the "file delete" operation also fails.
+			}
+		}
+	(void)TheFs.SetErrorCondition(KErrNone);
+	TheDb.Close();
+	TEST2(err, KErrNone);
+	TEST(FileExists(KTestDbName));
+	err = RSqlDatabase::Delete(KTestDbName);
+	TEST2(err, KErrNone);
+	TheTest.Printf(_L("\r\n"));
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-3462
+@SYMTestCaseDesc		Test for DEF105434 "SQL, persistent file I/O simulation, COMMIT problem".
+						The test creates a test database with one table, inserts one record.
+						Then the test attempts to retrieve the existing record while simulating file I/O failures.
+						After each iteration, the database content is tested, that it has not been modified by the operation.
+@SYMTestPriority		High
+@SYMTestActions			Test for DEF105434 "SQL, persistent file I/O simulation, COMMIT problem".
+@SYMTestExpectedResults The test must not fail
+@SYMDEF					DEF105434
+*/
+void SelectRecordTest()
+	{
+	(void)RSqlDatabase::Delete(KTestDbName);
+	TInt err = TheDb.Create(KTestDbName);
+	TEST2(err, KErrNone);
+	err = TheDb.Exec(_L("CREATE TABLE A(Id INTEGER, Name TEXT)"));
+	TEST(err >= 0);
+	err = TheDb.Exec(_L("INSERT INTO A(Id,Name) VALUES(1,'Name')"));
+	TEST2(err, 1);
+	TheDb.Close();
+	err = -1;
+	for(TInt cnt=1;err<KErrNone;++cnt)
+		{		
+		TheTest.Printf(_L("%d \r"), cnt);		
+		err = TheDb.Open(KTestDbName);
+		TEST2(err, KErrNone);
+		RSqlStatement stmt;
+		(void)TheFs.SetErrorCondition(KErrGeneral, cnt);
+		err = stmt.Prepare(TheDb, _L("SELECT * FROM A WHERE Id=?"));
+		if(err == KErrNone)
+			{
+			err = stmt.BindInt(0, 1);
+			if(err == KErrNone)
+				{
+				err = stmt.Next();
+				TEST(err == KSqlAtRow || err < 0);
+				if(err == KSqlAtRow)
+					{
+					TInt id = stmt.ColumnInt(0);
+					TEST2(id, 1);
+					TPtrC name;
+					err = stmt.ColumnText(1, name);
+					TEST2(err, KErrNone);
+					TEST(name == _L("Name"));
+					}
+				}
+			}
+		(void)TheFs.SetErrorCondition(KErrNone);
+		stmt.Close();
+		TheDb.Close();
+		//check the database content is the same as before the operation
+		TEST(CheckRecord(1, _L("Name")));
+		}
+	(void)TheFs.SetErrorCondition(KErrNone);
+	TEST(err >= 0);
+	TheDb.Close();
+	//check the database content is the same as before the operation, after reopening the database.
+	TEST(CheckRecord(1, _L("Name")));
+	err = RSqlDatabase::Delete(KTestDbName);
+	TEST2(err, KErrNone);
+	TheTest.Printf(_L("\r\n"));
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-3463
+@SYMTestCaseDesc		Test for DEF105434 "SQL, persistent file I/O simulation, COMMIT problem".
+						The test creates a test database with one table, inserts one record.
+						Then the test attempts to insert another while simulating file I/O failures.
+						After each iteration, the database content is tested, that it has not been modified by the operation.
+						If the operation succeeds, the database content is tested again to check that the inserted record is there.
+@SYMTestPriority		High
+@SYMTestActions			Test for DEF105434 "SQL, persistent file I/O simulation, COMMIT problem".
+@SYMTestExpectedResults The test must not fail
+@SYMDEF					DEF105434
+*/
+void InsertRecordTest()
+	{
+	(void)RSqlDatabase::Delete(KTestDbName);
+	TInt err = TheDb.Create(KTestDbName);
+	TEST2(err, KErrNone);
+	err = TheDb.Exec(_L("CREATE TABLE A(Id INTEGER,Name TEXT)"));
+	TEST(err >= 0);
+	err = TheDb.Exec(_L("INSERT INTO A(Id,Name) VALUES(1,'Name')"));
+	TEST2(err, 1);
+	TheDb.Close();
+	err = -1;
+	for(TInt cnt=1;err<KErrNone;++cnt)
+		{		
+		TheTest.Printf(_L("%d \r"), cnt);		
+		err = TheDb.Open(KTestDbName);
+		TEST2(err, KErrNone);
+		RSqlStatement stmt;
+		(void)TheFs.SetErrorCondition(KErrGeneral, cnt);
+		err = stmt.Prepare(TheDb, _L("INSERT INTO A(Id,Name) VALUES(2, 'Name2')"));
+		if(err == KErrNone)
+			{
+			err = TheDb.Exec(_L("BEGIN TRANSACTION"));
+			if(err == KErrNone)
+				{
+				err = stmt.Exec();
+				TEST(err == 1 || err < 0);
+				if(err == 1)
+					{
+					err = TheDb.Exec(_L("COMMIT TRANSACTION"));
+					}
+				}
+			}
+		(void)TheFs.SetErrorCondition(KErrNone);
+		stmt.Close();
+		if(err < 1)
+			{
+			TheDb.Close();//close the database to recover from the last error
+			//check that the database contains the "name" record that has been inserted before the file I/O failure test.
+			TEST(CheckRecord(1, _L("Name")));
+			}
+		else
+			{
+			TEST2(err, 1);
+			//check the database content has been modified by the operation, without closing the database.
+			TEST(CheckRecord(1, _L("Name"), EFalse));
+			TEST(CheckRecord(2, _L("Name2"), EFalse));
+			TheDb.Close();
+			}
+		}
+	(void)TheFs.SetErrorCondition(KErrNone);
+	TEST2(err, 1);
+	//check the database content (transaction durability).
+	TEST(CheckRecord(1, _L("Name")));
+	TEST(CheckRecord(2, _L("Name2")));
+	(void)RSqlDatabase::Delete(KTestDbName);
+	TheTest.Printf(_L("\r\n"));
+	}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////         Removable media robustness test      /////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+_LIT8(KNameColData, "A123456789012345678901234567890");
+_LIT8(KUpdatedNameColData, "1234");
+
+//TRemovableMediaTest class is used for testing the SQLITE behaviour when the database file is created on a removable media where
+//the cluster size is bigger than the page size and in case of a power failure is not guaranteed that the content
+//of the last updated cluster will be preserved.
+class TRemovableMediaTest
+	{
+	enum {KTestRecCnt = 200};
+	enum {KMinCachePageSize = 512};
+	
+public:	
+	void Run();
+	
+private:	
+	TInt GetRemovableMediaDriveNo();
+	TInt ClusterSize(TInt aDriveNo);
+	void CreateDatabase(TInt aDriveNo, TInt aCachePageSize);
+	void CheckRecord(sqlite3_stmt* aStmt, TInt aRecId);
+	void VerifyDatabase();
+	void DoTest();
+
+	};
+
+//Returns the number of the removable media drive, KErrNotFound otherwise.
+TInt TRemovableMediaTest::GetRemovableMediaDriveNo()
+	{
+	for(TInt driveNo=EDriveA;driveNo<=EDriveZ;++driveNo)
+		{
+		TDriveInfo driveInfo;
+		TInt err = TheFs.Drive(driveInfo, driveNo);
+		if(err == KErrNone)
+			{
+			_LIT(KType1, "Not present");
+			_LIT(KType2, "Unknown");
+			_LIT(KType3, "Floppy");
+			_LIT(KType4, "Hard disk");
+			_LIT(KType5, "CD ROM");
+			_LIT(KType6, "RAM disk");
+			_LIT(KType7, "Flash");
+			_LIT(KType8, "ROM drive");
+			_LIT(KType9, "Remote drive");
+			_LIT(KType10,"NAND flash");
+			_LIT(KType11,"Rotating media");
+			_LIT(KYes, "Yes");
+			_LIT(KNo,  "No ");
+			TPtrC KMediaTypeNames[] = {KType1(), KType2(), KType3(), KType4(), KType5(), KType6(), KType7(), KType8(), KType9(), KType10(), KType11()};
+			TheTest.Printf(_L("Drive: %C:, %S, Removable: %S\r\n"), 'A' + driveNo, &KMediaTypeNames[driveInfo.iType], 
+																	driveInfo.iDriveAtt & KDriveAttRemovable ? &KYes : &KNo);
+			if(driveInfo.iDriveAtt & KDriveAttRemovable)
+				{
+				TheTest.Printf(_L("Removable drive to test: %C:\r\n"), 'A' + driveNo);
+				return driveNo;	
+				}
+			}
+		}
+	return KErrNotFound;
+	}
+
+//Get the cluster size of aDriveNo drive	
+TInt TRemovableMediaTest::ClusterSize(TInt aDriveNo)
+	{
+	__ASSERT_DEBUG((TUint)aDriveNo <= EDriveZ, User::Invariant());
+	TVolumeIOParamInfo volIoParams;
+	TInt err = TheFs.VolumeIOParam(aDriveNo, volIoParams);
+	return (err == KErrNone) ? volIoParams.iClusterSize : err;
+	}
+
+//Create a test database on aDriveNo with aCachePageSize page size.
+//Insert KTestRecCnt records.
+void TRemovableMediaTest::CreateDatabase(TInt aDriveNo, TInt aCachePageSize)
+	{
+	__ASSERT_DEBUG((TUint)aDriveNo <= EDriveZ, User::Invariant());
+	__ASSERT_DEBUG(aCachePageSize > 0, User::Invariant());
+	TDriveUnit drvUnit(aDriveNo);
+	_LIT(KDbName, "\\flashmedia.db");
+	TParse parse;
+	parse.Set(drvUnit.Name(), &KDbName, 0);
+	TheRmvMediaDbFileName.Copy(parse.FullName());
+	TBuf8<KMaxFileName + 1> dbFileName8;
+	dbFileName8.Copy(TheRmvMediaDbFileName);
+	(void)TheFs.Delete(TheRmvMediaDbFileName);
+	
+	sqlite3* dbHandle = NULL;
+	TInt rc = sqlite3_open((const char*)dbFileName8.PtrZ(), &dbHandle);
+	SQLITE_TEST(dbHandle, rc, SQLITE_OK);
+	__ASSERT_DEBUG(dbHandle != NULL, User::Invariant());
+	
+	TBuf8<40> config;
+	config.Copy(_L8("PRAGMA PAGE_SIZE="));
+	config.AppendNum(aCachePageSize);
+	rc = sqlite3_exec(dbHandle, (const char*)config.PtrZ(), 0, 0, 0);
+	SQLITE_TEST(dbHandle, rc, SQLITE_OK);
+
+	rc = sqlite3_exec(dbHandle, "CREATE TABLE A(Id INTEGER,Name TEXT)", 0, 0, 0);
+	SQLITE_TEST(dbHandle, rc, SQLITE_OK);
+	rc = sqlite3_exec(dbHandle, "BEGIN", 0, 0, 0);
+	SQLITE_TEST(dbHandle, rc, SQLITE_OK);
+	for(TInt recid=1;recid<=KTestRecCnt;++recid)
+		{
+		
+		TBuf8<100> sql;
+		sql.Copy(_L8("INSERT INTO A VALUES("));
+		sql.AppendNum(recid);
+		sql.Append(_L8(",'"));
+		sql.Append(KNameColData);
+		sql.Append(_L8("')"));
+		rc = sqlite3_exec(dbHandle, (const char*)sql.PtrZ(), 0, 0, 0);
+		SQLITE_TEST(dbHandle, rc, SQLITE_OK);
+		}
+	rc = sqlite3_exec(dbHandle, "COMMIT", 0, 0, 0);
+	SQLITE_TEST(dbHandle, rc, SQLITE_OK);
+	sqlite3_close(dbHandle);
+	}
+
+//Checks the content of a single record
+void TRemovableMediaTest::CheckRecord(sqlite3_stmt* aStmt, TInt aRecId)
+	{
+	__ASSERT_DEBUG(aStmt != NULL, User::Invariant());
+	TInt id = sqlite3_column_int(aStmt, 0);
+	TEST2(id, aRecId);
+	const TUint8* text = (const TUint8*)sqlite3_column_text(aStmt, 1);
+	TPtrC8 name(text, User::StringLength(text));
+	TEST(KNameColData() == name || KUpdatedNameColData() == name);
+	}
+
+//Verifies that the database content is either the same as it was before the UPDATE operation or 
+//it has been updated with the new data.
+void TRemovableMediaTest::VerifyDatabase()
+	{
+	TBuf8<KMaxFileName + 1> dbFileName8;
+	dbFileName8.Copy(TheRmvMediaDbFileName);
+	
+	sqlite3* dbHandle = NULL;
+	TInt rc = sqlite3_open((const char*)dbFileName8.PtrZ(), &dbHandle);
+	SQLITE_TEST(dbHandle, rc, SQLITE_OK);
+	__ASSERT_DEBUG(dbHandle != NULL, User::Invariant());
+	
+	sqlite3_stmt* stmtHandle = NULL;
+	rc = sqlite3_prepare(dbHandle, "SELECT Id,Name FROM A", -1, &stmtHandle, 0);
+	SQLITE_TEST(dbHandle, rc, SQLITE_OK);
+	__ASSERT_DEBUG(stmtHandle != NULL, User::Invariant());
+	
+	for(TInt recid=1;recid<=KTestRecCnt;++recid)
+		{
+		rc = sqlite3_step(stmtHandle);
+		SQLITE_TEST(dbHandle, rc, SQLITE_ROW);
+		CheckRecord(stmtHandle, recid);
+		}
+	rc = sqlite3_step(stmtHandle);
+	SQLITE_TEST(dbHandle, rc, SQLITE_DONE);
+	
+	sqlite3_finalize(stmtHandle);
+	sqlite3_close(dbHandle);
+	}
+
+//Simulates a file system error in a loop.
+//Attempts to update single record in a transaction.
+//If the UPDATE operation fails - verifies the database content on each iteration.
+//Note: pages are stored at the moment, not clusters. The database operations are not more robust if
+//      clusters are stored in a case of a removable media.
+void TRemovableMediaTest::DoTest()
+	{
+	TheTest.Printf(_L("Update 1 record in a file I/o simulation loop\r\n"));		
+	TInt rc = -1;
+	TBuf8<KMaxFileName + 1> dbFileName8;
+	dbFileName8.Copy(TheRmvMediaDbFileName);
+	for(TInt cnt=1;rc!=SQLITE_OK;++cnt)
+		{		
+		TheTest.Printf(_L("%d \r"), cnt);		
+		sqlite3* dbHandle = NULL;
+		rc = sqlite3_open((const char*)dbFileName8.PtrZ(), &dbHandle);
+		SQLITE_TEST(dbHandle, rc, SQLITE_OK);
+		__ASSERT_DEBUG(dbHandle != NULL, User::Invariant());
+		(void)TheFs.SetErrorCondition(KErrCorrupt, cnt);
+		rc = sqlite3_exec(dbHandle, "BEGIN IMMEDIATE", 0, 0, 0);
+		if(rc == SQLITE_OK)
+			{
+			rc = sqlite3_exec(dbHandle, "UPDATE A SET Name='1234' WHERE Id=1", 0, 0, 0);
+			if(rc == SQLITE_OK)
+				{
+				TInt cnt = sqlite3_changes(dbHandle);
+				TEST2(cnt, 1);
+				rc = sqlite3_exec(dbHandle, "COMMIT", 0, 0, 0);
+				}
+			}
+		(void)TheFs.SetErrorCondition(KErrNone);
+		sqlite3_close(dbHandle);
+		if(rc != SQLITE_OK)
+			{
+			VerifyDatabase();
+			}
+		}
+	TEST2(rc, SQLITE_OK);
+	VerifyDatabase();
+	}
+	
+void TRemovableMediaTest::Run()
+	{
+	TInt driveNo = GetRemovableMediaDriveNo();
+	if(driveNo == KErrNotFound)
+		{
+		TheTest.Printf(_L("No removable media discovered. Test case not executed.\r\n"));	
+		return;
+		}
+	TInt clusterSize = ClusterSize(driveNo);
+	if(clusterSize < 0)
+		{
+		TheTest.Printf(_L("Error %d retrieving the cluster size of drive %C. Test case not executed.\r\n"), clusterSize, 'A' + driveNo);
+		return;
+		}
+	if(clusterSize <= KMinCachePageSize)
+		{
+		TheTest.Printf(_L("Cluster size: %d. No appropriate cache page size found. Test case not executed.\r\n"), clusterSize);	
+		return;
+		}
+		
+	TheTest.Printf(_L("Cluster size: %d. Cache page size %d.\r\nBegin test.\r\n"), clusterSize, KMinCachePageSize);	
+	CreateDatabase(driveNo, KMinCachePageSize);
+	DoTest();
+	(void)TheFs.Delete(TheRmvMediaDbFileName);
+	TheTest.Printf(_L("End test.\r\n"));
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-3516
+@SYMTestCaseDesc		Removable media robustness test
+						The test creates a test database with a table with some records. Then the test verifies
+						that the database content cannot be corrupted by file I/O failures during database updates, 
+						when the database file is on a removable media and the media cluster size is bigger than the 
+						database page size.
+@SYMTestPriority		High
+@SYMTestActions			Removable media robustness test
+@SYMTestExpectedResults The test must not fail
+@SYMREQ					REQ7913
+*/
+void RemovableMediaRobustnessTest()
+	{
+	TRemovableMediaTest removableMediaTest;
+	removableMediaTest.Run();
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-4044
+@SYMTestCaseDesc		RSqlDatabase::Size(TSize&), file I/O error simulation test.
+						The test creates a database and executes RSqldatabase::Size(TSize&)
+						during a file I/O error simulation. The database should not be corrupted 
+						by the call.
+@SYMTestPriority		High
+@SYMTestActions			RSqlDatabase::Size(TSize&), file I/O error simulation test.
+@SYMTestExpectedResults Test must not fail
+@SYMREQ					REQ10407
+*/
+void SizeTest()
+	{
+	(void)RSqlDatabase::Delete(KTestDbName);
+	TInt err = TheDb.Create(KTestDbName);
+	TEST2(err, KErrNone);
+	err = TheDb.Exec(_L("BEGIN;CREATE TABLE A(Id INTEGER,Data BLOB);INSERT INTO A VALUES(1, x'11223344');COMMIT;"));
+	TEST(err >= 0);
+	RSqlDatabase::TSize size1 = {-1, -1};
+	err = TheDb.Size(size1);
+	TEST2(err, KErrNone);
+	TEST(size1.iSize > 0);
+	TEST2(size1.iFree, 0);
+	TheDb.Close();
+	//"File I/O" error simulation loop
+	err = KErrCorrupt;
+	for(TInt cnt=1;err<KErrNone;++cnt)
+		{
+		TheTest.Printf(_L("%d \r"), cnt);		
+		TEST2(TheDb.Open(KTestDbName), KErrNone);
+		(void)TheFs.SetErrorCondition(KErrCorrupt, cnt);
+		RSqlDatabase::TSize size2 = {-1, -1};
+		err = TheDb.Size(size2);
+		(void)TheFs.SetErrorCondition(KErrNone);
+		TheDb.Close();
+		if(err == KErrNone)
+			{
+			TEST(size2.iSize == size1.iSize);
+			TEST(size2.iFree == size1.iFree);
+			break;
+			}
+		else
+			{
+			//check the database content - all bets are off in a case of an I/O error. 
+			TEST2(TheDb.Open(KTestDbName), KErrNone);
+			TSqlScalarFullSelectQuery q(TheDb);
+			TInt recCnt = 0;
+			TRAPD(err2, recCnt = q.SelectIntL(_L8("SELECT COUNT(*) FROM A")));
+			TheDb.Close();
+			TEST2(err2, KErrNone);
+			TEST2(recCnt, 1);
+			}
+		}
+	(void)RSqlDatabase::Delete(KTestDbName);
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-4045
+@SYMTestCaseDesc		RSqlDatabase::Compact(), file I/O error simulation test.
+						The test creates a database and executes RSqlDatabase::Compact()
+						during a file I/O error simulation. The database should not be corrupted 
+						by the call.
+@SYMTestPriority		High
+@SYMTestActions			RSqlDatabase::Compact(), file I/O error simulation test.
+@SYMTestExpectedResults Test must not fail
+@SYMREQ					REQ10405
+*/
+void CompactTest()
+	{
+	(void)RSqlDatabase::Delete(KTestDbName);
+	_LIT8(KConfig, "compaction=manual");
+	TInt err = TheDb.Create(KTestDbName, &KConfig);
+	TEST2(err, KErrNone);
+	err = TheDb.Exec(_L("CREATE TABLE A(Id INTEGER,Data BLOB)"));
+	TEST(err >= 0);
+	//Insert records
+	err = TheDb.Exec(_L8("BEGIN"));
+	TEST(err >= 0);
+	const TInt KRecLen = 1000;
+	TBuf8<KRecLen> sqlfmt;
+	sqlfmt.Copy(_L8("INSERT INTO A VALUES(%d,x'"));
+	for(TInt j=0;j<(KRecLen-50);++j)
+		{
+		sqlfmt.Append(_L8("A"));
+		}
+	sqlfmt.Append(_L8("')"));
+	const TInt KRecCount = 100;	
+	for(TInt i=0;i<KRecCount;++i)
+		{
+		TBuf8<KRecLen> sql;
+		sql.Format(sqlfmt, i + 1);
+		err = TheDb.Exec(sql);
+		TEST2(err, 1);
+		}
+	err = TheDb.Exec(_L8("COMMIT"));
+	TEST(err >= 0);
+	//Free some space
+	const TInt KDeletedRecCnt = KRecCount - 10;
+	err = TheDb.Exec(_L8("DELETE FROM A WHERE Id > 10"));
+	TEST(err >= 0);
+	//Get the database size
+	RSqlDatabase::TSize size;
+	err = TheDb.Size(size);
+	TEST2(err, KErrNone);
+	TheDb.Close();
+	TEST(size.iSize > 0);
+	TEST(size.iFree > 0);
+	//"File I/O" error simulation loop
+	err = KErrCorrupt;
+	for(TInt cnt=1;err<KErrNone;++cnt)
+		{
+		TheTest.Printf(_L("%d \r"), cnt);		
+		TEST2(TheDb.Open(KTestDbName), KErrNone);
+		(void)TheFs.SetErrorCondition(KErrCorrupt, cnt);
+		err = TheDb.Compact(RSqlDatabase::EMaxCompaction);
+		(void)TheFs.SetErrorCondition(KErrNone);
+		TheDb.Close();
+		if(err == KErrNone)
+			{
+			break;
+			}
+		else
+			{
+			//check the database content - all bets are off in a case of an I/O error. 
+			//The database maight have been compacted, so - no check for that.
+			TEST2(TheDb.Open(KTestDbName), KErrNone);
+			TSqlScalarFullSelectQuery q(TheDb);
+			TInt recCnt = 0;
+			TRAPD(err2, recCnt = q.SelectIntL(_L8("SELECT COUNT(*) FROM A")));
+			TheDb.Close();
+			TEST2(err2, KErrNone);
+			TEST2(recCnt, (KRecCount - KDeletedRecCnt));
+			}
+		}
+	TheTest.Printf(_L("\r\n"));
+	//Check that the database has been really compacted
+	TEST2(TheDb.Open(KTestDbName), KErrNone);
+	RSqlDatabase::TSize size2;
+	err = TheDb.Size(size2);
+	TEST2(err, KErrNone);
+	TheDb.Close();
+	(void)RSqlDatabase::Delete(KTestDbName);
+	TEST(size.iSize > size2.iSize);
+	TEST2(size2.iFree, 0);
+	}
+
+void DoBlobWriteStreamTestL(TBool aAttachDb)
+	{
+	RSqlBlobWriteStream strm;
+	CleanupClosePushL(strm);
+	if(aAttachDb)
+		{
+		strm.OpenL(TheDb, _L("A"), _L("Data"), 1, KAttachDb);
+		}
+	else
+		{
+		strm.OpenL(TheDb, _L("A"), _L("Data"), 1);
+		}
+
+	TBuf8<KBlobSize / KWriteCnt> data;
+	data.SetLength(KBlobSize / KWriteCnt);
+	data.Fill(0xA5);
+	
+	for(TInt i=0;i<KWriteCnt;++i)
+		{
+		strm.WriteL(data);
+		}
+	
+	strm.CommitL();
+	
+	CleanupStack::PopAndDestroy(&strm);
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-4089
+@SYMTestCaseDesc		RSqlBlobWriteStream::WriteL(), file I/O error simulation test.
+						The test creates a database and executes RSqlBlobWriteStream::WriteL()
+						during a file I/O error simulation. The database should not be corrupted 
+						by the call.
+@SYMTestPriority		High
+@SYMTestActions			RSqlBlobWriteStream::WriteL(), file I/O error simulation test.
+@SYMTestExpectedResults Test must not fail
+@SYMREQ					REQ5792
+                        REQ10418
+*/
+void BlobWriteStreamTest(TBool aAttachDb)
+	{
+	(void)RSqlDatabase::Delete(KTestDbName);
+	TInt err = TheDb.Create(KTestDbName);
+	TEST2(err, KErrNone);
+	err = TheDb.Exec(_L("CREATE TABLE A(Id INTEGER,Data BLOB)"));
+	TEST2(err, 1);
+	TBuf8<100> sql;
+	sql.Format(_L8("INSERT INTO A VALUES(1, zeroblob(%d))"), KBlobSize);
+	err = TheDb.Exec(sql);
+	TEST2(err, 1);
+	TheDb.Close();
+	
+	err = KErrCorrupt;
+	for(TInt cnt=1;err<KErrNone;++cnt)
+		{
+		TheTest.Printf(_L("%d \r"), cnt);		
+		TEST2(TheDb.Open(KTestDbName), KErrNone);
+		if(aAttachDb)
+			{
+			TEST2(TheDb.Attach(KTestDbName, KAttachDb), KErrNone);	
+			}
+		(void)TheFs.SetErrorCondition(KErrCorrupt, cnt);
+		TRAP(err, DoBlobWriteStreamTestL(aAttachDb));
+		(void)TheFs.SetErrorCondition(KErrNone);
+		if(aAttachDb)
+			{
+			TEST2(TheDb.Detach(KAttachDb), KErrNone);	
+			}
+		TheDb.Close();
+		}
+	TheTest.Printf(_L("\r\n"));
+
+	TEST2(TheDb.Open(KTestDbName), KErrNone);
+	
+	RSqlStatement stmt;
+	err = stmt.Prepare(TheDb, _L8("SELECT * FROM A"));
+	TEST2(err, KErrNone);
+	err = stmt.Next();
+	TEST2(err, KSqlAtRow);
+	TPtrC8 data;
+	err = stmt.ColumnBinary(1, data);
+	TEST2(err, KErrNone);
+	TEST2(data.Length(), KBlobSize);
+	for(TInt j=0;j<KBlobSize;++j)
+		{
+		TUint8 d = data[j];
+		TEST2(d, 0xA5);	
+		}
+	stmt.Close();
+	
+	TheDb.Close();
+	(void)RSqlDatabase::Delete(KTestDbName);
+	}
+
+void DoBlobReadStreamTestL(TBool aAttachDb, TDes8& aDes)
+	{
+	RSqlBlobReadStream strm;
+	CleanupClosePushL(strm);
+	if(aAttachDb)
+		{
+		strm.OpenL(TheDb, _L("A"), _L("Data"), 1, KAttachDb);
+		}
+	else
+		{
+		strm.OpenL(TheDb, _L("A"), _L("Data"), 1);
+		}
+
+	TBuf8<KBlobSize / KWriteCnt> data;
+	aDes.SetLength(0);
+	
+	for(TInt i=0;i<KWriteCnt;++i)
+		{
+		strm.ReadL(data);
+		aDes.Append(data);
+		}
+	
+	CleanupStack::PopAndDestroy(&strm);
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-4090
+@SYMTestCaseDesc		RSqlBlobReadStream::ReadL(), file I/O error simulation test.
+						The test creates a database and executes RSqlBlobReadStream::ReadL()
+						during a file I/O error simulation. The database should not be corrupted 
+						by the call.
+@SYMTestPriority		High
+@SYMTestActions			RSqlBlobReadStream::ReadL(), file I/O error simulation test.
+@SYMTestExpectedResults Test must not fail
+@SYMREQ					REQ5792
+                        REQ10410
+                        REQ10411
+*/
+void BlobReadStreamTest(TBool aAttachDb)
+	{
+	(void)RSqlDatabase::Delete(KTestDbName);
+	TInt err = TheDb.Create(KTestDbName);
+	TEST2(err, KErrNone);
+	err = TheDb.Exec(_L("CREATE TABLE A(Id INTEGER,Data BLOB)"));
+	TEST2(err, 1);
+	TBuf8<100> sql;
+	sql.Format(_L8("INSERT INTO A VALUES(1, zeroblob(%d))"), KBlobSize);
+	err = TheDb.Exec(sql);
+	TEST2(err, 1);
+	TRAP(err, DoBlobWriteStreamTestL(EFalse));
+	TEST2(err, KErrNone);
+	TheDb.Close();
+	
+	HBufC8* buf = HBufC8::New(KBlobSize);
+	TEST(buf != NULL);
+	TPtr8 bufptr = buf->Des();
+	
+	err = KErrCorrupt;
+	for(TInt cnt=1;err<KErrNone;++cnt)
+		{
+		TheTest.Printf(_L("%d \r"), cnt);		
+		TEST2(TheDb.Open(KTestDbName), KErrNone);
+		if(aAttachDb)
+			{
+			TEST2(TheDb.Attach(KTestDbName, KAttachDb), KErrNone);	
+			}
+		(void)TheFs.SetErrorCondition(KErrCorrupt, cnt);
+		TRAP(err, DoBlobReadStreamTestL(aAttachDb, bufptr));
+		(void)TheFs.SetErrorCondition(KErrNone);
+		if(aAttachDb)
+			{
+			TEST2(TheDb.Detach(KAttachDb), KErrNone);	
+			}
+		TheDb.Close();
+		}
+	TheTest.Printf(_L("\r\n"));
+
+	TEST2(bufptr.Length(), KBlobSize);
+	for(TInt j=0;j<KBlobSize;++j)
+		{
+		TUint8 d = bufptr[j];
+		TEST2(d, 0xA5);	
+		}
+		
+	delete buf;
+		
+	(void)RSqlDatabase::Delete(KTestDbName);
+	}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void DoTests()
+	{
+	TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-3419 Alter database during file I/O error "));
+	AlterDatabaseTest();
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-3420 Alter database during file I/O error (using statement object) "));
+	AlterDatabaseTest2();
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-3421 Open database during file I/O error "));
+	OpenDatabaseTest();
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-3434 Create database during file I/O error "));
+	CreateDatabaseTest();
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-3462 Select record test during file I/O error "));
+	SelectRecordTest();
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-3463 Insert record test during file I/O error "));
+	InsertRecordTest();
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-3516 Removable Media robustness test "));
+	RemovableMediaRobustnessTest();
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4044 Database size test during file I/O error"));	
+	SizeTest();
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4045 Compact database test during file I/O error"));	
+	CompactTest();
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4089 RSqlBlobWriteStream::WriteL() test during file I/O error"));	
+	BlobWriteStreamTest(EFalse);
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4089 RSqlBlobWriteStream::WriteL()+attached database test during file I/O error"));	
+	BlobWriteStreamTest(ETrue);
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4090 RSqlBlobReadStream::ReadL() test during file I/O error"));	
+	BlobReadStreamTest(EFalse);
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4090 RSqlBlobReadStream::ReadL()+attached database test during file I/O error"));	
+	BlobReadStreamTest(ETrue);
+	}
+
+TInt E32Main()
+	{
+	TheTest.Title();
+	
+	CTrapCleanup* tc = CTrapCleanup::New();
+	
+	__UHEAP_MARK;
+	
+	SetupTestEnv();
+	DoTests();
+	DestroyTestEnv();
+	
+	__UHEAP_MARKEND;
+	
+	TheTest.End();
+	TheTest.Close();
+	
+	delete tc;
+	
+	User::Heap().Check();
+	return KErrNone;
+	}