diff -r 000000000000 -r 08ec8eefde2f persistentstorage/sql/TEST/t_sqlfserr.cpp --- /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 +#include +#include +#include +#include +#include +#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=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=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=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=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= 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 0, User::Invariant()); + TDriveUnit drvUnit(aDriveNo); + _LIT(KDbName, "\\flashmedia.db"); + TParse parse; + parse.Set(drvUnit.Name(), &KDbName, 0); + TheRmvMediaDbFileName.Copy(parse.FullName()); + TBuf8 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 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 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= 0); + //Insert records + err = TheDb.Exec(_L8("BEGIN")); + TEST(err >= 0); + const TInt KRecLen = 1000; + TBuf8 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 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 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 data; + data.SetLength(KBlobSize / KWriteCnt); + data.Fill(0xA5); + + for(TInt i=0;i 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 data; + aDes.SetLength(0); + + for(TInt i=0;i 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