sl@0: // Copyright (c) 2006-2010 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: static RFs TheFs; sl@0: RTest TheTest(_L("t_sqlprivcage test")); sl@0: sl@0: _LIT(KTestDir, "c:\\test\\"); sl@0: _LIT(KTestDb1, "c:\\private\\21212124\\t_sqlprivcage_1.db"); sl@0: _LIT(KTestDb2, "c:\\private\\21212124\\t_sqlprivcage_2.db"); sl@0: _LIT(KTestDbZ, "z:\\private\\21212124\\t_sqldb1.db");//Created outside this test sl@0: _LIT(KTestDb, "\\private\\21212124\\t_sqlprivcage_3.db"); sl@0: TParse TheFileNameParse; sl@0: sl@0: static RCriticalSection ThreadCritSect; sl@0: static RCriticalSection MainCritSect; sl@0: sl@0: _LIT(KPanicCategory, "TransFail"); sl@0: const TInt KPanicCode = 1111; sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: //Deletes all created test files. sl@0: void DeleteTestFiles() sl@0: { sl@0: if(TheFileNameParse.FullName().Length() > 0) sl@0: { sl@0: (void)RSqlDatabase::Delete(TheFileNameParse.FullName()); sl@0: } sl@0: (void)RSqlDatabase::Delete(KTestDb2); sl@0: (void)RSqlDatabase::Delete(KTestDb1); sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: //Test macros and functions sl@0: void Check1(TInt aValue, TInt aLine, TBool aPrintThreadName = EFalse) sl@0: { sl@0: if(!aValue) sl@0: { sl@0: DeleteTestFiles(); sl@0: if(aPrintThreadName) sl@0: { sl@0: RThread th; sl@0: TName name = th.Name(); sl@0: RDebug::Print(_L("*** Thread %S, Line %d\r\n"), &name, aLine); sl@0: } sl@0: else sl@0: { sl@0: RDebug::Print(_L("*** Line %d\r\n"), aLine); sl@0: } sl@0: TheTest(EFalse, aLine); sl@0: } sl@0: } sl@0: void Check2(TInt aValue, TInt aExpected, TInt aLine, TBool aPrintThreadName = EFalse) sl@0: { sl@0: if(aValue != aExpected) sl@0: { sl@0: DeleteTestFiles(); sl@0: if(aPrintThreadName) sl@0: { sl@0: RThread th; sl@0: TName name = th.Name(); sl@0: RDebug::Print(_L("*** Thread %S, Line %d Expected error: %d, got: %d\r\n"), &name, aLine, aExpected, aValue); sl@0: } sl@0: else sl@0: { sl@0: RDebug::Print(_L("*** Line %d, Expected error: %d, got: %d\r\n"), aLine, aExpected, aValue); sl@0: } sl@0: TheTest(EFalse, aLine); sl@0: } sl@0: } sl@0: #define TEST(arg) ::Check1((arg), __LINE__) sl@0: #define TEST2(aValue, aExpected) ::Check2(aValue, aExpected, __LINE__) sl@0: #define TTEST(arg) ::Check1((arg), __LINE__, ETrue) sl@0: #define TTEST2(aValue, aExpected) ::Check2(aValue, aExpected, __LINE__, ETrue) sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: //Creates file session instance and the test directory sl@0: void CreateTestEnv() sl@0: { sl@0: TInt err = TheFs.Connect(); sl@0: TEST2(err, KErrNone); sl@0: sl@0: err = TheFs.CreatePrivatePath(EDriveC); sl@0: TEST(err == KErrNone || err == KErrAlreadyExists); sl@0: sl@0: err = TheFs.MkDir(KTestDir); sl@0: TEST(err == KErrNone || err == KErrAlreadyExists); sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: @SYMTestCaseID SYSLIB-SQL-CT-1764 sl@0: @SYMTestCaseDesc The test creates a database in the test application's private data cage. sl@0: Then the test does some operations with the created private database: sl@0: create table, insert records, select records, transactions, delete database. sl@0: The tests verifies that the SQL server can create a database in the application's sl@0: private data cage and can operate with the database. sl@0: @SYMTestPriority High sl@0: @SYMTestActions SQL, Private database test. sl@0: @SYMTestExpectedResults Test must not fail sl@0: @SYMREQ REQ5792 sl@0: REQ5793 sl@0: */ sl@0: void SimpleDbOpTest() sl@0: { sl@0: //Create private database sl@0: RSqlDatabase db; sl@0: TInt err = db.Create(KTestDb1); sl@0: TEST2(err, KErrNone); sl@0: sl@0: //Execute some operations with the private database sl@0: err = db.Exec(_L8("CREATE TABLE A(ID INTEGER)")); sl@0: TEST(err >= 0); sl@0: err = db.Exec(_L8("INSERT INTO A(ID) VALUES(1);INSERT INTO A(ID) VALUES(2);INSERT INTO A(ID) VALUES(3);")); sl@0: TEST(err >= 0); sl@0: sl@0: //Check written records sl@0: RSqlStatement stmt; sl@0: err = stmt.Prepare(db, _L8("SELECT * FROM A")); sl@0: TEST2(err, KErrNone); sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtRow); sl@0: TEST2(stmt.ColumnInt(0), 1); sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtRow); sl@0: TEST2(stmt.ColumnInt(0), 2); sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtRow); sl@0: TEST2(stmt.ColumnInt(0), 3); sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtEnd); sl@0: stmt.Close(); sl@0: sl@0: db.Close(); sl@0: //Open private database sl@0: err = db.Open(KTestDb1); sl@0: TEST2(err, KErrNone); sl@0: sl@0: //Execute a DELETE transaction sl@0: err = db.Exec(_L8("BEGIN IMMEDIATE TRANSACTION")); sl@0: TEST(err >= 0); sl@0: sl@0: err = db.Exec(_L8("DELETE FROM A WHERE ID > 1")); sl@0: TEST(err >= 0); sl@0: sl@0: err = db.Exec(_L8("COMMIT TRANSACTION")); sl@0: TEST(err >= 0); sl@0: sl@0: //Check records left sl@0: err = stmt.Prepare(db, _L8("SELECT * FROM A")); sl@0: TEST2(err, KErrNone); sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtRow); sl@0: TEST2(stmt.ColumnInt(0), 1); sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtEnd); sl@0: stmt.Close(); sl@0: sl@0: //Open private database which is on drive Z and with the same name sl@0: RSqlDatabase db2; sl@0: err = db2.Open(KTestDbZ); sl@0: TEST2(err, KErrNone); sl@0: //An attempt to write to a read-only database sl@0: err = db2.Exec(_L("INSERT INTO A VALUES(6)")); sl@0: TheTest.Printf(_L(" === Read-only private database. RSqlDatabase::Exec() returned err=%d\r\n"), err); sl@0: TEST(err != KErrNone); sl@0: //Check records sl@0: err = stmt.Prepare(db2, _L8("SELECT * FROM A")); sl@0: TEST2(err, KErrNone); sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtRow); sl@0: TEST2(stmt.ColumnInt(0), 1); sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtEnd); sl@0: stmt.Close(); sl@0: db2.Close(); sl@0: sl@0: db.Close(); sl@0: err = RSqlDatabase::Delete(KTestDb1); sl@0: TEST2(err, KErrNone); sl@0: sl@0: //Create private database on drive different than C: sl@0: for(TInt drvNum=EDriveD;drvNum<=EDriveZ;++drvNum) sl@0: { sl@0: TDriveUnit drvUnit(drvNum); sl@0: TPtrC drvName = drvUnit.Name(); sl@0: TheFileNameParse.Set(KTestDb, &drvName, 0); sl@0: //Check if it is possible to create application's private data cage on drvNum drive. sl@0: err = TheFs.CreatePrivatePath(drvNum); sl@0: if(err == KErrNone || err == KErrAlreadyExists) sl@0: { sl@0: (void)RSqlDatabase::Delete(TheFileNameParse.FullName()); sl@0: err = db.Create(TheFileNameParse.FullName()); sl@0: if(err == KErrNone) sl@0: { sl@0: //Execute some operations with the private database sl@0: err = db.Exec(_L8("BEGIN IMMEDIATE TRANSACTION")); sl@0: TEST(err >= 0); sl@0: err = db.Exec(_L8("CREATE TABLE A(ID INTEGER)")); sl@0: TEST(err >= 0); sl@0: err = db.Exec(_L8("INSERT INTO A(ID) VALUES(1);INSERT INTO A(ID) VALUES(2);INSERT INTO A(ID) VALUES(3);")); sl@0: TEST(err >= 0); sl@0: err = db.Exec(_L8("COMMIT TRANSACTION")); sl@0: TEST(err >= 0); sl@0: db.Close(); sl@0: err = RSqlDatabase::Delete(TheFileNameParse.FullName()); sl@0: TEST2(err, KErrNone); sl@0: break; sl@0: } sl@0: } sl@0: TheFileNameParse.Set(KNullDesC, 0, 0); sl@0: } sl@0: sl@0: //An attempt to create/open "C:[21212122]BBDb2.db" - this test has no enough rights to do that. sl@0: //...open as a non-secure database sl@0: err = db.Open(_L("C:[21212122]BBDb2.db")); sl@0: TEST2(err, KErrPermissionDenied); sl@0: //...create as a non-secure database sl@0: err = db.Create(_L("C:[21212122]BBDb2.db")); sl@0: TEST2(err, KErrArgument);//secure database name, no security policy sl@0: //Very long private database name sl@0: err = db.Create(_L("c:\\private\\21212124\\hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh.db")); sl@0: TEST2(err, KErrBadName); sl@0: //Private database name without drive letter sl@0: err = db.Create(_L("\\private\\21212124\\dbname_no_drive_letter.db")); sl@0: TEST2(err, KErrBadName); sl@0: //Zero length private database name sl@0: err = db.Create(_L("")); sl@0: TEST2(err, KErrBadName); sl@0: //Private database + very long config string sl@0: _LIT8(KVeryLongConfig, "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj"); sl@0: err = db.Create(KTestDb2, &KVeryLongConfig); sl@0: TEST2(err, KErrArgument); sl@0: //...create as a secure database sl@0: RSqlSecurityPolicy dbSecurity; sl@0: TSecurityPolicy policy(TSecurityPolicy::EAlwaysPass); sl@0: err = dbSecurity.Create(policy); sl@0: TEST2(err, KErrNone); sl@0: err = db.Create(_L("C:[21212122]BBDb2.db"), dbSecurity); sl@0: TEST2(err, KErrPermissionDenied); sl@0: dbSecurity.Close(); sl@0: sl@0: //An attempt to delete "C:[21212122]BBDb2.db" - this test has no enough rights to do that. sl@0: err = RSqlDatabase::Delete(_L("C:[21212122]BBDb2.db")); sl@0: TEST2(err, KErrPermissionDenied); sl@0: } sl@0: sl@0: /** sl@0: @SYMTestCaseID SYSLIB-SQL-CT-1765 sl@0: @SYMTestCaseDesc The test creates two databases in the test application's private data cage. sl@0: Then the test inserts some records in both databases using separate RSqlDatabase objects. sl@0: The test closes both databases, then reopens the first one and attaches th second one. sl@0: Again, the test inserts some records in both databases, using single RSqlDatabase object. sl@0: The test reads the inserted records and verifies their column values. sl@0: The tests verifies that the SQL server can create a database in the application's sl@0: private data cage, can operate with the database and can attach private databases. sl@0: @SYMTestPriority High sl@0: @SYMTestActions SQL, Attach private database test. sl@0: @SYMTestExpectedResults Test must not fail sl@0: @SYMREQ REQ5792 sl@0: REQ5793 sl@0: */ sl@0: void AttachDbOpTest() sl@0: { sl@0: //Create private database 1 sl@0: RSqlDatabase db1; sl@0: TInt err = db1.Create(KTestDb1); sl@0: TEST2(err, KErrNone); sl@0: //Execute some operations with private database 1 sl@0: err = db1.Exec(_L8("CREATE TABLE A(ID INTEGER)")); sl@0: TEST(err >= 0); sl@0: err = db1.Exec(_L8("INSERT INTO A(ID) VALUES(1)")); sl@0: TEST2(err, 1); sl@0: db1.Close(); sl@0: sl@0: //Create private database 2 sl@0: RSqlDatabase db2; sl@0: err = db2.Create(KTestDb2); sl@0: TEST2(err, KErrNone); sl@0: //Execute some operations with private database 2 sl@0: err = db2.Exec(_L8("CREATE TABLE A(ID INTEGER, T TEXT)")); sl@0: TEST(err >= 0); sl@0: err = db2.Exec(_L8("INSERT INTO A(ID, T) VALUES(1, 'NAME-NAME-NAME')")); sl@0: TEST2(err, 1); sl@0: db2.Close(); sl@0: sl@0: //Open database 1 sl@0: RSqlDatabase db; sl@0: err = db.Open(KTestDb1); sl@0: TEST2(err, KErrNone); sl@0: //An attempt to attach a database with zero length name sl@0: err = db.Attach(_L(""), _L("Db2")); sl@0: TEST2(err, KErrBadName); sl@0: //Attach database 2 sl@0: err = db.Attach(KTestDb2, _L("Db2")); sl@0: TEST2(err, KErrNone); sl@0: sl@0: //Insert some records sl@0: err = db.Exec(_L8("BEGIN IMMEDIATE TRANSACTION")); sl@0: TEST(err >= 0); sl@0: err = db.Exec(_L8("INSERT INTO Main.A(ID) VALUES(2);INSERT INTO Db2.A(ID, T) VALUES(2, 'AAA');")); sl@0: TEST(err >= 0); sl@0: err = db.Exec(_L8("COMMIT TRANSACTION")); sl@0: TEST(err >= 0); sl@0: sl@0: err = db.Detach(_L("Db2")); sl@0: TEST2(err, KErrNone); sl@0: db.Close(); sl@0: sl@0: //Verify inserted data in database 2 sl@0: err = db.Open(KTestDb2); sl@0: TEST2(err, KErrNone); sl@0: sl@0: RSqlStatement stmt; sl@0: err = stmt.Prepare(db, _L8("SELECT * FROM A")); sl@0: TEST2(err, KErrNone); sl@0: sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtRow); sl@0: TEST2(stmt.ColumnInt(0), 1); sl@0: TPtrC text; sl@0: err = stmt.ColumnText(1, text); sl@0: TEST2(err, KErrNone); sl@0: TEST(text == _L("NAME-NAME-NAME")); sl@0: sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtRow); sl@0: TEST2(stmt.ColumnInt(0), 2); sl@0: err = stmt.ColumnText(1, text); sl@0: TEST2(err, KErrNone); sl@0: TEST(text == _L("AAA")); sl@0: sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtEnd); sl@0: stmt.Close(); sl@0: db.Close(); sl@0: sl@0: //Open database 1, attach read-only database 2 sl@0: err = db.Open(KTestDb1); sl@0: TEST2(err, KErrNone); sl@0: //Make database 2 read-only. sl@0: err = TheFs.SetAtt(KTestDb2, KEntryAttReadOnly, 0); sl@0: TEST2(err, KErrNone); sl@0: //Attach database 2 sl@0: err = db.Attach(KTestDb2, _L("Db2")); sl@0: TEST2(err, KErrNone); sl@0: // sl@0: err = db.Exec(_L("INSERT INTO Db2.A(ID, T) VALUES(3, 'AAA')")); sl@0: TPtrC errmsg = db.LastErrorMessage(); sl@0: TheTest.Printf(_L(" === Read-only private attached database. Msg=%S, err=%d\r\n"), &errmsg, err); sl@0: TEST(err != KErrNone); sl@0: TSqlScalarFullSelectQuery q(db); sl@0: TBuf<20> text2; sl@0: TRAP(err, q.SelectTextL(_L("SELECT T FROM Db2.A WHERE ID=2"), text2)); sl@0: TEST2(err, KErrNone); sl@0: TEST(text2 == _L("AAA")); sl@0: // sl@0: err = db.Detach(_L("Db2")); sl@0: TEST2(err, KErrNone); sl@0: err = TheFs.SetAtt(KTestDb2, 0, KEntryAttReadOnly); sl@0: TEST2(err, KErrNone); sl@0: db.Close(); sl@0: sl@0: err = RSqlDatabase::Delete(KTestDb2); sl@0: TEST2(err, KErrNone); sl@0: err = RSqlDatabase::Delete(KTestDb1); sl@0: TEST2(err, KErrNone); sl@0: } sl@0: sl@0: /** sl@0: @SYMTestCaseID SYSLIB-SQL-CT-1766 sl@0: @SYMTestCaseDesc The test creates a database in the test application's private data cage. sl@0: Then the test creates two RSqlDatabase obejcts connecting them to the same sl@0: private database. The test inserts some records using both connections. sl@0: The test verifies that the inserted records are in the database file and sl@0: verifies the column values. sl@0: The test verifies that it is possible to make more than one connection to the sl@0: same private database and operate with the database using the database connections. sl@0: @SYMTestPriority High sl@0: @SYMTestActions SQL, Two database connections to the same private database test. sl@0: @SYMTestExpectedResults Test must not fail sl@0: @SYMREQ REQ5792 sl@0: REQ5793 sl@0: */ sl@0: void TwoDbOpTest() sl@0: { sl@0: //Create private database sl@0: RSqlDatabase db1; sl@0: TInt err = db1.Create(KTestDb1); sl@0: TEST2(err, KErrNone); sl@0: sl@0: //Make a second connection with the test database sl@0: RSqlDatabase db2; sl@0: err = db2.Open(KTestDb1); sl@0: TEST2(err, KErrNone); sl@0: sl@0: //Execute some operations with the private database sl@0: err = db1.Exec(_L8("CREATE TABLE A(ID INTEGER)")); sl@0: TEST(err >= 0); sl@0: err = db1.Exec(_L8("INSERT INTO A(ID) VALUES(1);")); sl@0: TEST2(err, 1); sl@0: err = db2.Exec(_L8("INSERT INTO A(ID) VALUES(2);")); sl@0: TEST2(err, 1); sl@0: sl@0: //Verify inserted data sl@0: RSqlStatement stmt; sl@0: err = stmt.Prepare(db2, _L8("SELECT * FROM A")); sl@0: TEST2(err, KErrNone); sl@0: sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtRow); sl@0: TEST2(stmt.ColumnInt(0), 1); sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtRow); sl@0: TEST2(stmt.ColumnInt(0), 2); sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtEnd); sl@0: stmt.Close(); sl@0: sl@0: db2.Close(); sl@0: db1.Close(); sl@0: err = RSqlDatabase::Delete(KTestDb1); sl@0: TEST2(err, KErrNone); sl@0: } sl@0: sl@0: //Test thread function. sl@0: //The test thread opens a database, begins a transaction and then simulates a crash within the transaction. sl@0: TInt ThreadFunc1(void*) sl@0: { sl@0: __UHEAP_MARK; sl@0: sl@0: CTrapCleanup* tc = CTrapCleanup::New(); sl@0: TTEST(tc != NULL); sl@0: sl@0: //Open test database sl@0: RSqlDatabase db; sl@0: TInt err = db.Open(KTestDb1); sl@0: TTEST2(err, KErrNone); sl@0: sl@0: RDebug::Print(_L("---:WorkThread: Begin transaction. Exec SQL...\r\n")); sl@0: sl@0: //Begin a transaction sl@0: err = db.Exec(_L8("BEGIN IMMEDIATE TRANSACTION")); sl@0: TTEST(err >= 0); sl@0: sl@0: //Execute INSERT sql statements sl@0: err = db.Exec(_L8("INSERT INTO A(ID) VALUES(2);INSERT INTO A(ID) VALUES(3);")); sl@0: TTEST(err >= 0); sl@0: sl@0: RDebug::Print(_L("---:WorkThread: Notify the main thread about the SQL statement execution\r\n")); sl@0: MainCritSect.Signal(); sl@0: sl@0: RDebug::Print(_L("---:WorkThread: Wait for permisson to continue...\r\n")); sl@0: ThreadCritSect.Wait(); sl@0: sl@0: User::SetJustInTime(EFalse); // disable debugger panic handling sl@0: sl@0: //Panic current thread without commiting the transaction (crash simulation) sl@0: RDebug::Print(_L("---:WorkThread: Panic!\r\n")); sl@0: User::Panic(KPanicCategory, KPanicCode); sl@0: sl@0: delete tc; sl@0: sl@0: __UHEAP_MARKEND; sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: @SYMTestCaseID SYSLIB-SQL-CT-1767 sl@0: @SYMTestCaseDesc The test creates a database in the test application's private data cage. sl@0: The test does some operations with the database leaving it in state A. sl@0: Then the test creates a test thread and runs the thread. The test thread sl@0: opens a connection to the database, begins a transaction, inserts some data sl@0: and then simulates a crash within the transaction (kills the thread). sl@0: When the main thread takes the execution control, it reopens the database connection sl@0: and verifies that the database is in the same state A as it was before. sl@0: @SYMTestPriority High sl@0: @SYMTestActions SQL, Private database - transaction recovery test. sl@0: @SYMTestExpectedResults Test must not fail sl@0: @SYMREQ REQ5792 sl@0: REQ5793 sl@0: */ sl@0: void TransDbOpTest() sl@0: { sl@0: //Create private database sl@0: RSqlDatabase db; sl@0: TInt err = db.Create(KTestDb1); sl@0: TEST2(err, KErrNone); sl@0: sl@0: //Execute some operations with the private database sl@0: err = db.Exec(_L8("CREATE TABLE A(ID INTEGER)")); sl@0: TEST(err >= 0); sl@0: err = db.Exec(_L8("INSERT INTO A(ID) VALUES(1)")); sl@0: TEST2(err, 1); sl@0: sl@0: //Check written records sl@0: RSqlStatement stmt; sl@0: err = stmt.Prepare(db, _L8("SELECT * FROM A")); sl@0: TEST2(err, KErrNone); sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtRow); sl@0: TEST2(stmt.ColumnInt(0), 1); sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtEnd); sl@0: stmt.Close(); sl@0: sl@0: db.Close(); sl@0: sl@0: //Run a test thread which will begin a transaction and then simulate a crash within the transaction sl@0: TEST2(ThreadCritSect.CreateLocal(), KErrNone); sl@0: ThreadCritSect.Wait(); sl@0: TEST2(MainCritSect.CreateLocal(), KErrNone); sl@0: MainCritSect.Wait(); sl@0: RDebug::Print(_L("+++:MainThread: Create the worker thread\r\n")); sl@0: _LIT(KThreadName, "WorkThrd"); sl@0: RThread thread; sl@0: TEST2(thread.Create(KThreadName, &ThreadFunc1, 0x2000, 0x1000, 0x10000, NULL, EOwnerProcess), KErrNone); sl@0: TRequestStatus status; sl@0: thread.Logon(status); sl@0: TEST2(status.Int(), KRequestPending); sl@0: thread.Resume(); sl@0: RDebug::Print(_L("+++:MainThread: Wait SQL statement(s) to be executed...\r\n")); sl@0: MainCritSect.Wait(); sl@0: RDebug::Print(_L("+++:MainThread: Notify the worker thread to simulate a crash...\r\n")); sl@0: ThreadCritSect.Signal(); sl@0: User::WaitForRequest(status); sl@0: User::SetJustInTime(ETrue); // enable debugger panic handling sl@0: TEST2(thread.ExitType(), EExitPanic); sl@0: TEST2(thread.ExitReason(), KPanicCode); sl@0: thread.Close(); sl@0: MainCritSect.Close(); sl@0: ThreadCritSect.Close(); sl@0: sl@0: //Reopen the test database. The failed transaction must be rolled back. sl@0: err = db.Open(KTestDb1); sl@0: TEST2(err, KErrNone); sl@0: //Verify that the database content is the same as before the failed transaction sl@0: err = stmt.Prepare(db, _L8("SELECT * FROM A")); sl@0: TEST2(err, KErrNone); sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtRow); sl@0: TEST2(stmt.ColumnInt(0), 1); sl@0: err = stmt.Next(); sl@0: TEST2(err, KSqlAtEnd); sl@0: stmt.Close(); sl@0: db.Close(); sl@0: sl@0: err = RSqlDatabase::Delete(KTestDb1); sl@0: TEST2(err, KErrNone); sl@0: } sl@0: sl@0: void DoTests() sl@0: { sl@0: TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1764 Simple private db operations ")); sl@0: SimpleDbOpTest(); sl@0: sl@0: TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1765 Private db operations - attach database ")); sl@0: AttachDbOpTest(); sl@0: sl@0: TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1766 Private db operations - 2 database connections ")); sl@0: TwoDbOpTest(); sl@0: sl@0: TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1767 Private db operations - transaction recovery ")); sl@0: TransDbOpTest(); sl@0: } sl@0: sl@0: TInt E32Main() sl@0: { sl@0: TheTest.Title(); sl@0: sl@0: CTrapCleanup* tc = CTrapCleanup::New(); sl@0: sl@0: __UHEAP_MARK; sl@0: sl@0: CreateTestEnv(); sl@0: DeleteTestFiles(); sl@0: DoTests(); sl@0: DeleteTestFiles(); sl@0: TheFs.Close(); sl@0: sl@0: __UHEAP_MARKEND; sl@0: sl@0: TheTest.End(); sl@0: TheTest.Close(); sl@0: sl@0: delete tc; sl@0: sl@0: User::Heap().Check(); sl@0: return KErrNone; sl@0: }