// Copyright (c) 1998-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 <hal.h>
static RTest TheTest(_L("t_dbtrans: Test DBMS transactions"));
static RDbTable TheTable;
static RFs TheFs;
static RDbs TheDbs;
static RDbNamedDatabase TheDatabase;
static TFileName TheTestDbFileName;
const TPtrC KTableName(_S("table"));
const TPtrC KIndexInt=_S("int");
const TPtrC KIndexText=_S("text");
const TPtrC KColumnInt=_S("int");
const TPtrC KColumnText=_S("text");
const TPtrC KColumnComment=_S("comment");
const TPtrC KCommentValue=_S("abcdefghijklmnopqrstuvwxyz");
const TInt KRecords=2000;
///////////////////////////////////////////////////////////////////////////////////////
static void CloseAll()
{
TheTable.Close();
TheDatabase.Close();
TheDbs.Close();
}
///////////////////////////////////////////////////////////////////////////////////////
//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 DestroyTestEnv()
{
CloseAll();
DeleteFile(TheTestDbFileName);
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)
{
TheTest.Printf(_L("*** Boolean expression evaluated to false!\r\n"));
DestroyTestEnv();
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);
DestroyTestEnv();
TheTest(EFalse, aLine);
}
}
//Use these to test conditions.
#define TEST(arg) ::Check((arg), __LINE__)
#define TEST2(aValue, aExpected) ::Check(aValue, aExpected, __LINE__)
//////////////////////////////////////////////////////
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)
{
if(TheCounterFreq <= 0)
{
TEST2(HAL::Get(HAL::EFastCounterFrequency, TheCounterFreq), KErrNone);
TheTest.Printf(_L("Counter frequency=%d Hz\r\n"), TheCounterFreq);
}
double v = ((double)aFastCount * KMicroSecIn1Sec) / (double)TheCounterFreq;
TInt v2 = (TInt)v;
TheTest.Printf(aFormatStr, v2);
}
///////////////////////////////////////////////////////////////////////////////////////
//
// Prepare the test directory.
//
void CreateTestEnv()
{
TInt err = TheFs.Connect();
TheTest(err == KErrNone);
err = TheFs.MkDirAll(TheTestDbFileName);
TEST(err == KErrNone || err == KErrAlreadyExists);
}
///////////////////////////////////////////////////////////////////////////////////////
class Progress
{
enum {ETotal=32};
public:
Progress(TInt aCount);
void Next(TInt aStep);
private:
TInt iCount;
TInt iPos;
};
Progress::Progress(TInt aCount)
: iCount(aCount),iPos(0)
{}
void Progress::Next(TInt aStep)
{
TInt next=(ETotal*(iCount-aStep))/iCount;
if (next!=iPos)
{
iPos=next;
}
}
static void ProgressInc(RDbIncremental& inc,TInt aCount)
{
Progress progress(aCount);
while (aCount)
{
inc.Next(aCount);
progress.Next(aCount);
}
inc.Close();
}
//
// Create the database
//
static void CreateDatabase()
{
TInt err = TheDatabase.Replace(TheFs, TheTestDbFileName);
TEST2(err, KErrNone);
}
//
// Create the database
//
static void OpenDatabase()
{
TInt err = TheDatabase.Open(TheFs, TheTestDbFileName);
TEST2(err, KErrNone);
}
static void CloseDatabase()
{
TheDatabase.Close();
}
static void CreateTable()
{
TInt err = TheDatabase.Execute(_L("create table table (int integer,text varchar(8),comment varchar)"));
TEST2(err, KErrNone);
}
static void WriteRecordsL(TInt aCount)
{
Progress write(aCount);
TDbColNo cInt,cText,cComment;
CDbColSet* set=TheTable.ColSetL();
cInt=set->ColNo(KColumnInt);
cText=set->ColNo(KColumnText);
cComment=set->ColNo(KColumnComment);
delete set;
TBuf<10> text;
TInt jj=0;
for (TInt ii=0;ii<aCount;++ii)
{
TheTable.InsertL();
jj=(jj+23);
if (jj>=aCount)
jj-=aCount;
TheTable.SetColL(cInt,jj);
text.Num(jj);
TheTable.SetColL(cText,text);
TheTable.SetColL(cComment,KCommentValue);
TheTable.PutL();
write.Next(aCount-ii-1);
}
}
static TUint FileSize()
{
TEntry entry;
TEST2(TheFs.Entry(TheTestDbFileName, entry), KErrNone);
return entry.iSize;
}
static void BuildTableL(TInt aCount, TBool aTransactions, TUint32& aTicks, TUint& aSize)
{
TUint size = FileSize();
TUint fc = User::FastCounter();
CreateTable();
if(aTransactions)
{
TheDatabase.Begin();
}
TEST2(TheTable.Open(TheDatabase, KTableName), KErrNone);
WriteRecordsL(aCount);
if(aTransactions)
{
TEST2(TheDatabase.Commit(), KErrNone);
}
TheTable.Close();
aTicks = CalcTickDiff(fc, User::FastCounter());
aSize = FileSize() - size;
}
static void Execute(const TDesC& aSql)
{
RDbIncremental inc;
TInt step;
TEST2(inc.Execute(TheDatabase,aSql,step), KErrNone);
ProgressInc(inc,step);
}
static void BreakIndexL()
{
TheDatabase.Begin();
TEST2(TheTable.Open(TheDatabase,KTableName), KErrNone);
TheTable.InsertL();
TheTable.SetColL(1,-1);
TheTable.PutL();
TheTable.Close();
TheDatabase.Rollback();
TEST(TheDatabase.IsDamaged());
}
LOCAL_C void Recover()
{
RDbIncremental rec;
TInt step;
TEST2(rec.Recover(TheDatabase,step), KErrNone);
ProgressInc(rec,step);
TEST(!TheDatabase.IsDamaged());
}
/**
@SYMTestCaseID SYSLIB-DBMS-CT-0637
@SYMTestCaseDesc Streaming conversions test
@SYMTestPriority Medium
@SYMTestActions Test the database definition and enquiry functions
@SYMTestExpectedResults Test must not fail
@SYMREQ REQ0000
*/
static void TestL()
{
TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0637 Build without transactions "));
CreateDatabase();
TUint32 ticks1;
TUint size1;
BuildTableL(KRecords, EFalse, ticks1, size1);
CloseDatabase();
TheTest.Next(_L("Build with transactions"));
CreateDatabase();
TUint32 ticks2;
TUint size2;
BuildTableL(KRecords, ETrue, ticks2, size2);
PrintFcDiffAsUs(_L("#### Without transactions, time=%d us\n"), ticks1);
PrintFcDiffAsUs(_L("#### With transactions, time=%d us\n"), ticks2);
TheTest.Printf(_L("Transaction performance ratio (without trn:with trn): time %4.2f, size %4.2f\n"), TReal(ticks1) / TReal(ticks2), TReal(size1) / TReal(size2));
TheTest.Next(_L("Build Int index"));
Execute(_L("create unique index int on table (int)"));
TheTest.Next(_L("Break index"));
BreakIndexL();
TheTest.Next(_L("Build Text index"));
Execute(_L("create unique index text on table (text)"));
TheTest.Next(_L("Recover"));
TEST(TheDatabase.IsDamaged());
CloseDatabase();
OpenDatabase();
TEST(TheDatabase.IsDamaged());
Recover();
TheTest.Next(_L("Drop table"));
Execute(_L("drop table table"));
CloseDatabase();
}
//Usage: "t_trans [<drive letter>:]]"
TInt E32Main()
{
TheTest.Title();
CTrapCleanup* tc = CTrapCleanup::New();
TheTest(tc != NULL);
TBuf<256> cmdline;
User::CommandLine(cmdline);
TParse parse;
_LIT(KTestDatabase, "C:\\DBMS-TST\\T_TRANS.DB");
parse.Set(cmdline, &KTestDatabase, 0);
TheTestDbFileName.Copy(parse.FullName());
__UHEAP_MARK;
CreateTestEnv();
TRAPD(err, TestL());
TEST2(err, KErrNone);
DestroyTestEnv();
delete tc;
__UHEAP_MARKEND;
TheTest.End();
TheTest.Close();
return 0;
}