persistentstorage/dbms/tdbms/t_dbperf3.cpp
changeset 0 08ec8eefde2f
child 55 44f437012c90
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/dbms/tdbms/t_dbperf3.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,659 @@
+// 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 <d32dbms.h>
+#include <s32file.h>
+#include <e32test.h>
+#include <e32math.h>
+#include <s32mem.h>
+#include <hal.h>
+
+static RTest TheTest(_L("t_dbperf3"));
+static CTrapCleanup* 	TheTrapCleanup;
+static RFs				TheFs;
+static RDbs 			TheDbs;
+static RDbNamedDatabase TheDatabase;
+static RDbRowSet 		TheRowSet, TheRowSet2;
+static RFile 			TheTestFile;
+static TFileName 		TheDatabaseFileName;
+
+#define COUNT_OF(array) (sizeof(array)/sizeof(array[0]))
+
+const TInt KTrackRecordCount = 200;
+const TInt KCategoryRecordCount = 50;
+const TInt KStatsRecordCount = 50;
+const TInt KTestBlobSize = 4096;
+
+//_LIT(KCreateTrackTable, "CREATE TABLE TRACKS (id INTEGER, marked_2_play INTEGER, category_id INTEGER, artist_last_name CHAR(15) NOT NULL,artist_first_name CHAR(15) NOT NULL, title CHAR(16) NOT NULL,download_site CHAR(30) NOT NULL,band_name CHAR(20) NOT NULL,origin CHAR(16),autostart INTEGER, init_volume INTEGER, music_file LONG VARCHAR)");
+_LIT(KCreateTrackIndex, "CREATE INDEX IDX1 ON TRACKS(id,marked_2_play,category_id)");
+_LIT(KCreateTrackTable, "CREATE TABLE TRACKS (id INTEGER, marked_2_play INTEGER, category_id INTEGER, artist_last_name CHAR(15) NOT NULL,artist_first_name CHAR(15) NOT NULL, title CHAR(16) NOT NULL,download_site CHAR(30) NOT NULL,band_name CHAR(20) NOT NULL,origin CHAR(16),autostart INTEGER, init_volume INTEGER)");
+_LIT(KCreateTrackTable2, "CREATE TABLE TRACKS2 (id INTEGER, music_file LONG VARCHAR)");
+//_LIT(KCreateTrackIndex2, "CREATE INDEX IDX4 ON TRACKS2(id)");
+
+//_LIT(KTrackTable,"TRACKS");
+
+_LIT(KId,"id");
+_LIT(KLastName,"artist_last_name");
+_LIT(KFirstName,"artist_first_name");
+_LIT(KTitle,"title");
+_LIT(KDownloadSite,"download_site");
+_LIT(KBandName,"band_name");
+_LIT(KOrigin,"origin");
+_LIT(KAutoStart,"autostart");
+_LIT(KInitVolume,"init_volume");
+_LIT(KMarked2Play,"marked_2_play");
+_LIT(KCategoryId,"category_id");
+_LIT(KMusicFile,"music_file");
+
+
+//category Table LITS
+_LIT(KCreateCategoryTable, "CREATE TABLE CATEGORY (category_id INTEGER,category_name CHAR(20),genre INTEGER)");
+_LIT(KCreateCategoryIndex, "CREATE INDEX IDX2 ON CATEGORY(category_id)");
+
+//_LIT(KCategoryTable,"CATEGORY");
+
+//KCategoryId defined for category table	
+_LIT(KCategoryName,"category_name");
+_LIT(KGenre,"genre");
+
+
+//STATS Table LITS
+_LIT(KCreatestatsTable, "CREATE TABLE STATS (category_id INTEGER, no_of_tracks INTEGER, no_autostart INTEGER,no_manualstart INTEGER,no_marked_2_play INTEGER, no_unmarked_2_play INTEGER, size_of_musicfiles INTEGER)");
+_LIT(KCreatestatsIndex, "CREATE UNIQUE INDEX IDX3 ON STATS(category_id)");
+
+//_LIT(KStatsTable,"STATS");
+
+//KCategoryId defined for category table
+_LIT(KNoOfTracks,"no_of_tracks");
+_LIT(KNoMarked2Play,"no_marked_2_play");
+_LIT(KNoUnmarked2Play,"no_unmarked_2_play");
+_LIT(KNoAutostart,"no_autostart");
+_LIT(KNoManualStart,"no_manualstart");
+_LIT(KSizeOfMusicFiles,"size_of_musicfiles");
+
+//////////////////////////////////////////////////////
+
+static TInt TheCounterFreq = -10000000;
+const TInt KMicroSecIn1Sec = 1000000;
+
+TUint32 CalcTickDiff(TUint32 aStartTicks, TUint32 aEndTicks)
+	{
+	TInt64 diffTicks = (TInt64)aEndTicks - (TInt64)aStartTicks;
+	if(diffTicks < 0)
+		{
+		diffTicks = KMaxTUint32 + diffTicks + 1;
+		}
+	return (TUint32)diffTicks;
+	}
+
+//Prints aFastCount parameter (converted to us)
+void PrintFcDiffAsUs(const TDesC& aFormatStr, TUint32 aFastCount)
+	{
+	double v = ((double)aFastCount * KMicroSecIn1Sec) / (double)TheCounterFreq;
+	TInt v2 = (TInt)v;
+	TheTest.Printf(aFormatStr, v2);
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+//Delete "aFullName" file.
+static void DeleteFile(const TDesC& aFullName)
+	{
+	RFs fsSession;
+	TInt err = fsSession.Connect();
+	if(err == KErrNone)
+		{
+		TEntry entry;
+		if(fsSession.Entry(aFullName, entry) == KErrNone)
+			{
+			err = fsSession.SetAtt(aFullName, 0, KEntryAttReadOnly);
+			if(err != KErrNone) 
+				{
+				TheTest.Printf(_L("Error %d changing \"%S\" file attributes.\n"), err, &aFullName);
+				}
+			err = fsSession.Delete(aFullName);
+			if(err != KErrNone) 
+				{
+				TheTest.Printf(_L("Error %d deleting \"%S\" file.\n"), err, &aFullName);
+				}
+			}
+		fsSession.Close();
+		}
+	else
+		{
+		TheTest.Printf(_L("Error %d connecting file session. File: %S.\n"), err, &aFullName);
+		}
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+static void CloseAll()
+	{
+	TheRowSet2.Close();
+	TheRowSet.Close();
+	TheDatabase.Close();
+	TheDbs.Close();
+	TheFs.Close();
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+//Tests macros and functions.
+//If (!aValue) then the test will be panicked, the test data files will be deleted.
+static void Check(TInt aValue, TInt aLine)
+	{
+	if(!aValue)
+		{
+		CloseAll();
+		DeleteFile(TheDatabaseFileName);
+		TheTest(EFalse, aLine);
+		}
+	}
+//If (aValue != aExpected) then the test will be panicked, the test data files will be deleted.
+static void Check(TInt aValue, TInt aExpected, TInt aLine)
+	{
+	if(aValue != aExpected)
+		{
+		TheTest.Printf(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue);
+		CloseAll();
+		DeleteFile(TheDatabaseFileName);
+		TheTest(EFalse, aLine);
+		}
+	}
+//Use these to test conditions.
+#define TEST(arg) ::Check((arg), __LINE__)
+#define TEST2(aValue, aExpected) ::Check(aValue, aExpected, __LINE__)
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+void PrintFileSize()
+	{
+	RDbDatabase::TSize s = TheDatabase.Size();
+	TheTest.Printf(_L("####FileSize: %d\r\n"), s.iSize);
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+void FillRandomData(TDes& aData, TInt64 aSeed)
+	{
+	aData.Zero();
+	for (TInt i=0; i<aData.MaxLength(); ++i)
+		{
+		// add next character (we stick to lowercase alphabet for now)
+		aData.Append(TChar(Math::FRand(aSeed)*25 + 'a'));	
+		}
+	}
+
+void FillRandomData(TDes& aData)
+	{
+	// get random seed
+	TTime time;
+	time.UniversalTime();
+	TInt64 seed = time.Int64();
+	// do the filling
+	FillRandomData(aData, seed);
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+void CreateDatabase()
+	{
+	TInt err = TheDatabase.Replace(TheFs, TheDatabaseFileName);
+	TEST2(err, KErrNone);
+	TheDatabase.Close();
+	err = TheDbs.Connect();
+	TEST2(err, KErrNone);
+	err = TheDatabase.Open(TheDbs, TheDatabaseFileName);
+	TEST2(err, KErrNone);
+	err = TheDatabase.Execute(KCreateTrackTable);
+	TEST2(err, KErrNone);
+	err = TheDatabase.Execute(KCreateTrackIndex);
+	TEST2(err, KErrNone);
+	err = TheDatabase.Execute(KCreateTrackTable2);
+	TEST2(err, KErrNone);
+	//err = TheDatabase.Execute(KCreateTrackIndex2);
+	//TEST2(err, KErrNone);
+	err = TheDatabase.Execute(KCreateCategoryTable);
+	TEST2(err, KErrNone);
+	err = TheDatabase.Execute(KCreateCategoryIndex);
+	TEST2(err, KErrNone);
+	err = TheDatabase.Execute(KCreatestatsTable);
+	TEST2(err, KErrNone);
+	err = TheDatabase.Execute(KCreatestatsIndex);
+	TEST2(err, KErrNone);
+	//err = TheDatabase.Compact();
+	//TEST2(err, KErrNone);
+	}
+
+void InsertTrackTableL()
+	{	
+	HBufC* randomDataBuf = HBufC::NewLC(KTestBlobSize);
+	TPtr randomData(randomDataBuf->Des());
+	FillRandomData(randomData);
+	
+	RDbView view;
+	TInt err = view.Prepare(TheDatabase, _L("select * from TRACKS"), view.EInsertOnly);
+	TEST2(err, KErrNone);
+	TheRowSet = view;	
+	
+	CDbColSet* colSet = TheRowSet.ColSetL();
+	const TInt KIdIdx = colSet->ColNo(KId);
+	const TInt KLastNameIdx = colSet->ColNo(KLastName);
+	const TInt KFirstNameIdx = colSet->ColNo(KFirstName);
+	const TInt KTitleIdx = colSet->ColNo(KTitle);
+	const TInt KDownloadSiteIdx = colSet->ColNo(KDownloadSite);
+	const TInt KBandNameIdx = colSet->ColNo(KBandName);
+	const TInt KOriginIdx = colSet->ColNo(KOrigin);
+	const TInt KAutoStartIdx = colSet->ColNo(KAutoStart);
+	const TInt KInitVolumeIdx = colSet->ColNo(KInitVolume);
+	const TInt KMarkedToPlayIdx = colSet->ColNo(KMarked2Play);
+	const TInt KCategoryIdIdx = colSet->ColNo(KCategoryId);
+	//const TInt KMusicFileIdx = colSet->ColNo(KMusicFile);
+	delete colSet;
+	colSet = NULL;
+
+	err = TheDatabase.Begin();
+	TEST2(err, KErrNone);
+	
+	for (TInt ii=1;ii<=KTrackRecordCount;++ii)
+		{
+		TheRowSet.InsertL();
+		TheRowSet.SetColL(KIdIdx, ii);
+		TheRowSet.SetColL(KLastNameIdx, _L("Dummy"));
+		TheRowSet.SetColL(KFirstNameIdx,_L("Dummy"));
+		TheRowSet.SetColL(KTitleIdx,_L("Dummy"));
+		TheRowSet.SetColL(KDownloadSiteIdx,_L("Dummy"));
+		TheRowSet.SetColL(KBandNameIdx,_L("Dummy"));
+		TheRowSet.SetColL(KOriginIdx,_L("Dummy"));
+		TheRowSet.SetColL(KAutoStartIdx,(ii%2));
+		TheRowSet.SetColL(KInitVolumeIdx,(ii%2));
+		TheRowSet.SetColL(KMarkedToPlayIdx,(ii%2));
+		TheRowSet.SetColL(KCategoryIdIdx,(ii%KCategoryRecordCount));
+
+		//RDbColWriteStream musicfile;
+		//musicfile.OpenLC(TheRowSet, KMusicFileIdx);
+		//musicfile.WriteL(randomData,KTestBlobSize);
+		//musicfile.CommitL();
+		//CleanupStack::PopAndDestroy(&musicfile);
+
+		TheRowSet.PutL();
+		}
+
+	err = TheDatabase.Commit();
+	TEST2(err, KErrNone);
+
+	//err = TheDatabase.Compact();
+	//TEST2(err, KErrNone);
+
+	TheRowSet.Close();	
+
+	////////////////////////////////////////////////////////////////////////////////////////////////
+
+	err = view.Prepare(TheDatabase, _L("select * from TRACKS2"), view.EInsertOnly);
+	TEST2(err, KErrNone);
+	TheRowSet = view;	
+	
+	colSet = TheRowSet.ColSetL();
+	const TInt KIdIdx2 = colSet->ColNo(KId);
+	const TInt KMusicFileIdx2 = colSet->ColNo(KMusicFile);
+	delete colSet;
+
+	err = TheDatabase.Begin();
+	TEST2(err, KErrNone);
+
+	for (TInt ii=1;ii<=KTrackRecordCount;++ii)
+		{
+		TheRowSet.InsertL();
+		TheRowSet.SetColL(KIdIdx2, ii);
+		
+		RDbColWriteStream musicfile;
+		musicfile.OpenLC(TheRowSet, KMusicFileIdx2);
+		musicfile.WriteL(randomData,KTestBlobSize);
+		musicfile.CommitL();
+		CleanupStack::PopAndDestroy(&musicfile);
+		
+		TheRowSet.PutL();
+		}
+
+	err = TheDatabase.Commit();
+	TEST2(err, KErrNone);
+
+	//err = TheDatabase.Compact();
+	//TEST2(err, KErrNone);
+
+	TheRowSet.Close();	
+
+	CleanupStack::PopAndDestroy(randomDataBuf);
+	}
+	
+void InsertCategoryTableL()
+	{
+	RDbView view;
+	TInt err = view.Prepare(TheDatabase, _L("select * from CATEGORY"), view.EInsertOnly);
+	TEST2(err, KErrNone);
+	TheRowSet = view;	
+
+	CDbColSet* colSet = TheRowSet.ColSetL();
+	const TInt KCategoryIdIdx = colSet->ColNo(KCategoryId);
+	const TInt KCategoryNameIdx = colSet->ColNo(KCategoryName);
+	const TInt KGenreIdx = colSet->ColNo(KGenre);
+	delete colSet;
+
+	err = TheDatabase.Begin();
+	TEST2(err, KErrNone);
+
+	for (TInt ii=1;ii<=KCategoryRecordCount;++ii)
+		{
+		TheRowSet.InsertL();
+		TheRowSet.SetColL(KCategoryIdIdx, ii);
+		TheRowSet.SetColL(KCategoryNameIdx, _L("History"));
+		TheRowSet.SetColL(KGenreIdx,(ii*500));
+		TheRowSet.PutL();
+		}
+
+	err = TheDatabase.Commit();
+	TEST2(err, KErrNone);
+	
+	//err = TheDatabase.Compact();
+	//TEST2(err, KErrNone);
+
+	TheRowSet.Close();	
+	}
+	
+void InsertStatsTableL()
+	{
+	RDbView view;
+	TInt err = view.Prepare(TheDatabase, _L("select * from STATS"), view.EInsertOnly);
+	TEST2(err, KErrNone);
+	TheRowSet = view;	
+
+	CDbColSet* colSet = TheRowSet.ColSetL();
+	const TInt KCategoryIdIdx = colSet->ColNo(KCategoryId);
+	const TInt KTrackCntIdx = colSet->ColNo(KNoOfTracks);
+	const TInt KMarkedToPlayCntIdx = colSet->ColNo(KNoMarked2Play);
+	const TInt KUnmarkedToPlayCntIdx = colSet->ColNo(KNoUnmarked2Play);
+	const TInt KAutoStartCntIdx = colSet->ColNo(KNoAutostart);
+	const TInt KManualStartCntIdx = colSet->ColNo(KNoManualStart);
+	const TInt KSizeMusicFilesIdx = colSet->ColNo(KSizeOfMusicFiles);
+	delete colSet;
+
+	TInt default_Stat = 0;
+
+	err = TheDatabase.Begin();
+	TEST2(err, KErrNone);
+	
+	for (TInt ii=0;ii<KStatsRecordCount;++ii)
+		{
+		TheRowSet.InsertL();
+		TheRowSet.SetColL(KCategoryIdIdx, ii);
+		TheRowSet.SetColL(KTrackCntIdx,default_Stat);
+		TheRowSet.SetColL(KMarkedToPlayCntIdx,default_Stat);
+		TheRowSet.SetColL(KUnmarkedToPlayCntIdx,default_Stat);
+		TheRowSet.SetColL(KAutoStartCntIdx,default_Stat);
+		TheRowSet.SetColL(KManualStartCntIdx,default_Stat);
+		TheRowSet.SetColL(KSizeMusicFilesIdx,default_Stat);
+		TheRowSet.PutL();
+		}
+
+	err = TheDatabase.Commit();
+	TEST2(err, KErrNone);
+	
+	//err = TheDatabase.Compact();
+	//TEST2(err, KErrNone);
+
+	TheRowSet.Close();	
+	}
+	
+void FillDatabaseL()
+	{
+	InsertTrackTableL();
+	InsertCategoryTableL();	
+	InsertStatsTableL();
+	}
+
+void DestroyDatabase()
+	{
+	TheRowSet.Close();
+	TheDatabase.Close();
+	TheDbs.Close();
+	TInt err = TheFs.Delete(TheDatabaseFileName);
+	TEST2(err, KErrNone);
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+void GetFastCounterFrequency()
+	{
+	TEST2(HAL::Get(HAL::EFastCounterFrequency, TheCounterFreq), KErrNone);
+	TheTest.Printf(_L("Counter frequency=%d\r\n"), TheCounterFreq);
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+void SelectTracksL(TInt aCount, RArray<TInt>& aTracks)
+	{
+	TUint32 fc = User::FastCounter();
+	RDbView view;
+	TUint32 fc2 = User::FastCounter();
+	TInt err = view.Prepare(TheDatabase, _L("select id from TRACKS"), view.EReadOnly);
+	TEST2(err, KErrNone);
+	PrintFcDiffAsUs(_L("###\"Prepare()\",time=%d us\r\n"), CalcTickDiff(fc2, User::FastCounter()));
+	fc2 = User::FastCounter();
+	err = view.EvaluateAll();
+	TEST2(err, KErrNone);
+	PrintFcDiffAsUs(_L("###\"EvaluateAll()\",time=%d us\r\n"), CalcTickDiff(fc2, User::FastCounter()));
+	TheRowSet = view;
+
+	TUint32 diff1 = 0, diff2 = 0;
+	TInt count = 0;	
+	while(count < aCount)
+		{
+		fc2 = User::FastCounter();
+		if(!TheRowSet.NextL())
+			{
+			break;	
+			}
+		diff1 += CalcTickDiff(fc2, User::FastCounter());	
+		fc2 = User::FastCounter();
+		TheRowSet.GetL();
+		diff2 += CalcTickDiff(fc2, User::FastCounter());	
+		aTracks.Append(TheRowSet.ColInt(1));
+		++count;
+		}
+	TEST2(count, aCount);
+	PrintFcDiffAsUs(_L("###\"Total NextL()\",time=%d us\r\n"), diff1);
+	PrintFcDiffAsUs(_L("###\"Total GetL()\",time=%d us\r\n"), diff2);
+	
+	fc2 = User::FastCounter();
+	TheRowSet.Close();	
+	PrintFcDiffAsUs(_L("###\"Close()\",time=%d us\r\n"), CalcTickDiff(fc2, User::FastCounter()));
+	PrintFcDiffAsUs(_L("###\"SELECT FROM TRACKS\",time=%d us\r\n"), CalcTickDiff(fc, User::FastCounter()));
+	}
+
+/** 
+@SYMTestCaseID          PDS-DBMS-UT-4009
+@SYMTestCaseDesc        DBMS performance tests.
+@SYMTestPriority        High
+@SYMTestActions        	The test opens the test database and:
+						- selects the ids of the tracks to be deleted and collects them into an array;
+						- deletes the recods with matching track ids from TRACK table;
+						- deletes the recods with matching track ids from TRACK2 table;
+						The execution times are printed out.
+@SYMTestExpectedResults Test must not fail
+@SYMREQ                 REQ7141
+*/
+void DeleteTracksL()
+	{
+	TheTest.Printf(_L("Record count: %d\r\n"), KTrackRecordCount);
+	
+	RArray<TInt> tracks;
+	tracks.ReserveL(KTrackRecordCount);
+	CleanupClosePushL(tracks);
+	SelectTracksL(KTrackRecordCount, tracks);
+	//
+	_LIT(KDeleteSql, "DELETE FROM tracks  WHERE id>=%d AND id<=%d");
+
+	TBuf<100> sql;
+	sql.Format(KDeleteSql, tracks[0], tracks[tracks.Count() - 1]);
+
+	TUint32 fc2 = User::FastCounter();
+
+	TInt err = TheDatabase.Begin();
+	TEST2(err, KErrNone);
+	
+	TUint32 fc = User::FastCounter();
+	TInt rc = TheDatabase.Execute(sql);
+	PrintFcDiffAsUs(_L("###\"DELETE FROM TRACKS\",time=%d us\r\n"), CalcTickDiff(fc, User::FastCounter()));
+	TEST2(rc, KTrackRecordCount);
+	TheTest.Printf(_L("Deleted record count: %d\r\n"), rc);
+
+	sql.Replace(12, 6, _L("TRACKS2"));
+	fc = User::FastCounter();
+	rc = TheDatabase.Execute(sql);
+	PrintFcDiffAsUs(_L("###\"DELETE FROM TRACKS2\",time=%d us\r\n"), CalcTickDiff(fc, User::FastCounter()));
+	TEST2(rc, KTrackRecordCount);
+	TheTest.Printf(_L("Deleted record count: %d\r\n"), rc);
+
+	err = TheDatabase.Commit();
+	TEST2(err, KErrNone);
+
+	PrintFcDiffAsUs(_L("###Total \"DELETE FROM TRACKS\",time=%d us\r\n"), CalcTickDiff(fc2, User::FastCounter()));
+	
+	CleanupStack::PopAndDestroy(&tracks);
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+//This test checks how RDbDatabase::Commit() works if there are some active RDbRowSet objects - 
+//read-only and updatable. The expectation is that the Commit() call won't fail, the RDbRowSet objects
+//retain their pre-commit positions.
+void CommitTestL()
+	{
+	//Create 2 test tables, insert some records in the first table
+	TheDatabase.Close();
+	TInt err = TheDatabase.Replace(TheFs, TheDatabaseFileName);
+	TEST2(err, KErrNone);
+	err = TheDatabase.Execute(_L("CREATE TABLE AA1(Id INTEGER)"));
+	TEST2(err, KErrNone);
+	err = TheDatabase.Execute(_L("CREATE TABLE AA2(Id INTEGER)"));
+	TEST2(err, KErrNone);
+	err = TheDatabase.Execute(_L("INSERT INTO AA1(Id) VALUES(1)"));
+	TEST2(err, 1);
+	err = TheDatabase.Execute(_L("INSERT INTO AA1(Id) VALUES(2)"));
+	TEST2(err, 1);
+	err = TheDatabase.Execute(_L("INSERT INTO AA1(Id) VALUES(3)"));
+	TEST2(err, 1);
+	//Begin transaction
+	err = TheDatabase.Begin();
+	TEST2(err, KErrNone);
+	//Prepare read-only view and call FirstL() (TheRowSet object)
+	RDbView view;
+	err = view.Prepare(TheDatabase, _L("select * from AA1"), RDbRowSet::EReadOnly);
+	TEST2(err, KErrNone);
+	TheRowSet = view;
+	err = view.EvaluateAll();	//DBMS can use FirstL() without the EvaluateAll() call in this case
+	TEST2(err, KErrNone);
+	TBool rc = TheRowSet.FirstL();
+	TEST(rc);
+	//Prepare updatable view and call NextL() (TheRowSet2 object)
+	err = view.Prepare(TheDatabase, _L("select * from AA1"), RDbRowSet::EUpdatable);
+	TEST2(err, KErrNone);
+	TheRowSet2 = view;
+	err = view.EvaluateAll();	//DBMS can use NextL() without the EvaluateAll() call in this case
+	TEST2(err, KErrNone);
+	rc = TheRowSet2.FirstL();
+	TEST(rc);
+	rc = TheRowSet2.NextL();
+	TEST(rc);
+	//Execute one INSERT statement
+	err = TheDatabase.Execute(_L("INSERT INTO AA2(Id) VALUES(1)"));
+	TEST2(err, 1);
+	//Commit transaction
+	err = TheDatabase.Commit();
+	TEST2(err, KErrNone);
+	//Check the retrieved by TheRowSet record 
+	TheRowSet.GetL();
+	TEST2(TheRowSet.ColInt(1), 1);
+	//Check the retrieved by TheRowSet2 record 
+	TheRowSet2.GetL();
+	TEST2(TheRowSet2.ColInt(1), 2);
+	//Cleanup
+	TheRowSet2.Close();
+	TheRowSet.Close();
+	TheDatabase.Close();
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////
+	
+void DoTestL()
+	{
+	TheTest.Start(_L("Get fast counter frequency"));
+	GetFastCounterFrequency();
+	
+	TheTest.Next(_L("Create&Fill test database"));
+	CreateDatabase();
+	FillDatabaseL();
+
+	TheTest.Next(_L(" @SYMTestCaseID:PDS-DBMS-UT-4009 Delete tracks"));
+	DeleteTracksL();
+
+	TheTest.Next(_L("Commit() test (not a performance test)"));
+	CommitTestL();
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+//Usage: "t_dbperf3 [<drive letter>:]"
+TInt E32Main()
+    {
+	TheTest.Title();
+	
+	TheTrapCleanup = CTrapCleanup::New();
+	TEST(TheTrapCleanup != NULL);
+	
+	//Construct test database file name
+	_LIT(KTestDatabase, "c:\\dbms-tst\\t_dbperf3.db");
+	TFileName fname;
+	User::CommandLine(fname);
+	TParse parse;
+	parse.Set(fname, &KTestDatabase, 0);
+	const TDesC& dbFilePath = parse.FullName();
+	TheDatabaseFileName.Copy(dbFilePath);
+	TheTest.Printf(_L("Test database: %S\r\n"), &TheDatabaseFileName);
+
+	__UHEAP_MARK;
+
+	TInt err = TheFs.Connect();
+	TEST2(err, KErrNone);
+	err = TheFs.MkDir(TheDatabaseFileName);
+	TheTest.Printf(_L("MkDir(): err=%d\r\n"), err);
+	TEST(err == KErrNone || err == KErrAlreadyExists);
+
+	DeleteFile(TheDatabaseFileName);
+
+	TRAP(err, DoTestL());
+	TEST2(err, KErrNone);
+
+	CloseAll();
+	DeleteFile(TheDatabaseFileName);
+
+	__UHEAP_MARKEND;
+
+	TheTest.End();
+	TheTest.Close();
+	
+	delete TheTrapCleanup;
+	return KErrNone;
+    }