sl@0: // Copyright (c) 1998-2009 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: #ifndef __TOOLS2__
sl@0: #include <../include/d32dbms.h>
sl@0: #else
sl@0: #include <d32dbms.h>
sl@0: #endif
sl@0: #include <s32file.h>
sl@0: #include <e32test.h>
sl@0: #include <e32math.h>
sl@0: 
sl@0: #include "D32TABLE.H"
sl@0: 
sl@0: #include "crccheck.h"
sl@0: 
sl@0: #undef __UHEAP_MARK
sl@0: #define __UHEAP_MARK
sl@0: #undef __UHEAP_MARKEND
sl@0: #define __UHEAP_MARKEND
sl@0: 
sl@0: LOCAL_D TDBMS_CRCChecks TheCrcChecker;
sl@0: 
sl@0: #ifndef __linux__ //No CRC test on LINUX
sl@0: #ifdef __TOOLS2__
sl@0: const TPtrC	KCrcRecord=_L("\\epoc32\\winscw\\c\\dbms-tst\\T_INDEX.CRC");
sl@0: #else
sl@0: const TPtrC	KCrcRecord=_L("C:\\dbms-tst\\T_INDEX.CRC");
sl@0: #endif
sl@0: #endif
sl@0: 
sl@0: 
sl@0: // MSVC++ up to 5.0 has problems with expanding inline functions
sl@0: // This disables the mad warnings for the whole project
sl@0: #if defined(NDEBUG) && defined(__VC32__) && _MSC_VER<=1100
sl@0: #pragma warning(disable : 4710)			// function not expanded. MSVC 5.0 is stupid
sl@0: #endif
sl@0: 
sl@0: LOCAL_D RTest test(_L("T_INDEX - Test DBMS indexing and ordering"));
sl@0: LOCAL_D CTrapCleanup* TheTrapCleanup;
sl@0: LOCAL_D RDbs TheDbs;
sl@0: LOCAL_D RDbNamedDatabase TheDatabase;
sl@0: LOCAL_D RDbTable TheTable;
sl@0: LOCAL_D RDbView TheView;
sl@0: LOCAL_D RFs TheFs;
sl@0: LOCAL_D TBuf<0x200> TheBuf;
sl@0: 
sl@0: const TInt KTestCleanupStack=0x20;
sl@0: 
sl@0: #ifdef __TOOLS2__
sl@0: const TPtrC KTestDatabase=_L(".\\dbms-tst\\T_INDEX.DB");
sl@0: #else
sl@0: const TPtrC KTestDatabase=_L("C:\\dbms-tst\\T_INDEX.DB");
sl@0: #endif
sl@0: 
sl@0: const TPtrC KTableName(_S("Table"));
sl@0: const TPtrC KIndexName(_S("index"));
sl@0: const TPtrC KIndexTwo(_S("index_two"));
sl@0: const TPtrC KColumnName(_S("column"));
sl@0: const TPtrC KColumnTwo(_S("column2"));
sl@0: 
sl@0: const TPtrC KSelectOrdered(_L("select column from table order by column"));
sl@0: 
sl@0: #define elementsof(array) (sizeof(array)/sizeof(array[0]))
sl@0: 
sl@0: 
sl@0: //
sl@0: // Open the database (shared access) (SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version)
sl@0: //
sl@0: LOCAL_C void OpenDatabaseL()
sl@0: 	{
sl@0: 	TInt r=TheDatabase.Open(TheDbs,KTestDatabase);
sl@0: 	test (r==KErrNone);
sl@0: 	}
sl@0: 
sl@0: //
sl@0: // Create the database (SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version)
sl@0: //
sl@0: LOCAL_C void CreateDatabaseL()
sl@0: 	{
sl@0: 	TInt r=TheDatabase.Replace(TheFs,KTestDatabase);
sl@0: 	test (r==KErrNone);
sl@0: 	TheDatabase.Close();
sl@0: 	TheCrcChecker.GenerateCrcL(KTestDatabase);
sl@0: 	OpenDatabaseL();
sl@0: 	}
sl@0: 
sl@0: 
sl@0: LOCAL_C void CloseDatabaseL()
sl@0: 	{
sl@0: 	TheDatabase.Close();
sl@0: 	TheCrcChecker.GenerateCrcL(KTestDatabase);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-0618
sl@0: @SYMTestCaseDesc        Tests for RDbNamedDatabase functionality 
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Tests for RDbNamedDatabase::CreateIndex()
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: LOCAL_C void TestIndexBuild()
sl@0: 	{
sl@0: 	test.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0618 Create table "));
sl@0: 	TheDatabase.Begin();
sl@0: 	CDbColSet *cs=CDbColSet::NewLC();
sl@0: 	cs->AddL(TDbCol(KColumnName,EDbColInt32));
sl@0: 	cs->AddL(TDbCol(KColumnTwo,EDbColInt32));
sl@0: 	test(TheDatabase.CreateTable(KTableName,*cs)==KErrNone);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: 	test.Next(_L("create indices"));
sl@0: 	CDbKey *key=CDbKey::NewLC();
sl@0: 	key->AddL(TDbKeyCol(KColumnName));
sl@0: 	key->MakeUnique();
sl@0: 	test(TheDatabase.CreateIndex(KIndexName,KTableName,*key)==KErrNone);
sl@0: 	key->Clear();
sl@0: 	key->AddL(TDbKeyCol(KColumnTwo));
sl@0: 	key->MakeUnique();
sl@0: 	test(TheDatabase.CreateIndex(KIndexTwo,KTableName,*key)==KErrNone);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: 	test.Next(_L("Populate table"));
sl@0: 	test(TheTable.Open(TheDatabase,KTableName)==KErrNone);
sl@0: 	TheTable.InsertL();
sl@0: 	TheTable.SetColL(1,1);
sl@0: 	TheTable.SetColL(2,-1);
sl@0: 	TheTable.PutL();
sl@0: 	TheTable.InsertL();
sl@0: 	TheTable.SetColL(1,2);
sl@0: 	TheTable.SetColL(2,-2);
sl@0: 	TheTable.PutL();
sl@0: 	test(TheDatabase.Commit()==KErrNone);
sl@0: 	test.Next(_L("Check order"));
sl@0: 	test(TheTable.SetNoIndex()==KErrNone);
sl@0: 	test(TheTable.SetIndex(KIndexName)==KErrNone);
sl@0: 	test(TheTable.CountL()==2);
sl@0: 	test(TheTable.NextL());
sl@0: 	TheTable.GetL();
sl@0: 	test(TheTable.ColInt(1)==1);
sl@0: 	test(TheTable.NextL());
sl@0: 	TheTable.GetL();
sl@0: 	test(TheTable.ColInt(1)==2);
sl@0: 	test(!TheTable.NextL());
sl@0: 	test(TheTable.SetIndex(KIndexTwo)==KErrNone);
sl@0: 	test(TheTable.CountL()==2);
sl@0: 	test(TheTable.NextL());
sl@0: 	TheTable.GetL();
sl@0: 	test(TheTable.ColInt(1)==2);
sl@0: 	test(TheTable.NextL());
sl@0: 	TheTable.GetL();
sl@0: 	test(TheTable.ColInt(1)==1);
sl@0: 	test(!TheTable.NextL());
sl@0:  	test(TheTable.SetNoIndex()==KErrNone);
sl@0: 	test(TheTable.CountL()==2);
sl@0: 	test(TheTable.NextL());
sl@0: 	test(TheTable.NextL());
sl@0: 	test(!TheTable.NextL());
sl@0: 	TheTable.Close();
sl@0: 	test.Next(_L("Drop indices"));
sl@0: 	test(TheDatabase.DropIndex(KIndexTwo,KTableName)==KErrNone);
sl@0: 	test(TheTable.Open(TheDatabase,KTableName)==KErrNone);
sl@0: 	test(TheTable.SetIndex(KIndexName)==KErrNone);
sl@0: 	test(TheTable.SetIndex(KIndexTwo)!=KErrNone);
sl@0: 	TheTable.Close();
sl@0: 	test(TheDatabase.DropIndex(KIndexName,KTableName)==KErrNone);
sl@0: 	test(TheTable.Open(TheDatabase,KTableName)==KErrNone);
sl@0: 	test(TheTable.SetIndex(KIndexName)!=KErrNone);
sl@0: 	test(TheTable.SetIndex(KIndexTwo)!=KErrNone);
sl@0: 	TheTable.Close();
sl@0: 	test(TheDatabase.DropTable(KTableName)==KErrNone);
sl@0: 	test.End();
sl@0: 	}
sl@0: 
sl@0: LOCAL_C TInt CountRowsL()
sl@0: 	{
sl@0: 	TInt count=0;
sl@0: 	while (TheTable.NextL())
sl@0: 		++count;
sl@0: 	return count;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-0619
sl@0: @SYMTestCaseDesc        RDbNamedDatabase::Execute() function test
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Tests for CREATE TABLE,CREATE INDEX and CREATE UNIQUE INDEX query
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: LOCAL_C void TestPersistence()
sl@0: 	{
sl@0: 	test.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0619 Create table "));
sl@0: 	TheDatabase.Begin();
sl@0: 	test(TheDatabase.Execute(_L("CREATE TABLE Table (column CHAR(120) NOT NULL)"))==KErrNone);
sl@0: 	test(TheTable.Open(TheDatabase,KTableName)==KErrNone);
sl@0: 	TheTable.InsertL();
sl@0: 	TheTable.SetColL(1,_L("a"));
sl@0: 	TheTable.PutL();
sl@0: 	TheTable.InsertL();
sl@0: 	TheTable.SetColL(1,_L("b"));
sl@0: 	TheTable.PutL();
sl@0: 	TheTable.InsertL();
sl@0: 	TheTable.SetColL(1,_L("c"));
sl@0: 	TheTable.PutL();
sl@0: 	TheTable.InsertL();
sl@0: 	TheTable.SetColL(1,_L("d"));
sl@0: 	TheTable.PutL();
sl@0: 	TheTable.InsertL();
sl@0: 	TheTable.SetColL(1,_L("e"));
sl@0: 	TheTable.PutL();
sl@0: 	TheTable.Close();
sl@0: 	test(TheDatabase.Commit()==KErrNone);
sl@0: 	test.Next(_L("Build indices"));
sl@0: 	test (TheDatabase.Execute(_L("CREATE INDEX index ON table (column ASC)"))==KErrNone);
sl@0: 	test (TheDatabase.Execute(_L("CREATE UNIQUE INDEX index_two ON table (column DESC)"))==KErrNone);
sl@0: 	test.Next(_L("Close and re-open database"));
sl@0: 	CloseDatabaseL();
sl@0: 	OpenDatabaseL();
sl@0: 	test.Next(_L("Check indices"));
sl@0: 	CDbKey* key=TheDatabase.KeyL(KIndexName,KTableName);
sl@0: 	test (key->Count()==1);
sl@0: 	test (key->Comparison()==EDbCompareNormal);
sl@0: 	test (!key->IsUnique());
sl@0: 	test ((*key)[0].iName.CompareF(KColumnName)==0);
sl@0: 	test ((*key)[0].iOrder==TDbKeyCol::EAsc);
sl@0: 	delete key;
sl@0: 	key=TheDatabase.KeyL(KIndexTwo,KTableName);
sl@0: 	test (key->Count()==1);
sl@0: 	test (key->Comparison()==EDbCompareNormal);
sl@0: 	test (key->IsUnique());
sl@0: 	test ((*key)[0].iName.CompareF(KColumnName)==0);
sl@0: 	test ((*key)[0].iOrder==TDbKeyCol::EDesc);
sl@0: 	delete key;
sl@0: 	test(TheTable.Open(TheDatabase,KTableName)==KErrNone);
sl@0: 	test(TheTable.SetNoIndex()==KErrNone);
sl@0: 	test(CountRowsL()==5);
sl@0: 	test(TheTable.CountL()==5);
sl@0: 	test(TheTable.SetIndex(KIndexName)==KErrNone);
sl@0: 	test(TheTable.CountL()==5);
sl@0: 	test(CountRowsL()==5);
sl@0: 	test(TheTable.SetIndex(KIndexTwo)==KErrNone);
sl@0: 	test(TheTable.CountL()==5);
sl@0: 	test(CountRowsL()==5);
sl@0: 	TheTable.Close();
sl@0: 	test.Next(_L("Drop indices"));
sl@0: 	TheDatabase.Begin();
sl@0: 	test (TheDatabase.Execute(_L("DROP INDEX index_two FROM table"))==KErrNone);
sl@0: 	test (TheDatabase.Execute(_L("DROP INDEX index FROM table"))==KErrNone);
sl@0: 	test (TheDatabase.Execute(_L("DROP TABLE table"))==KErrNone);
sl@0: 	test(TheDatabase.Commit()==KErrNone);
sl@0: 	test.End();
sl@0: 	}
sl@0: 
sl@0: LOCAL_C void BuildTableProlog(TDbColType aType,TInt aAttribs=0)
sl@0: 	{
sl@0: 	TheDatabase.Begin();
sl@0: 	CDbColSet *cs=CDbColSet::NewLC();
sl@0: 	TDbCol col(KColumnName,aType);
sl@0: 	col.iAttributes=aAttribs;
sl@0: 	cs->AddL(col);
sl@0: 	test(TheDatabase.CreateTable(KTableName,*cs)==KErrNone);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: 	test(TheTable.Open(TheDatabase,KTableName)==KErrNone);
sl@0: 	}
sl@0: 
sl@0: inline void SetColL(RDbRowSet& aSet,TDbColNo col,const TInt& aValue)
sl@0: 	{aSet.SetColL(col,aValue);}
sl@0: inline void SetColL(RDbRowSet& aSet,TDbColNo col,const TUint& aValue)
sl@0: 	{aSet.SetColL(col,aValue);}
sl@0: inline void SetColL(RDbRowSet& aSet,TDbColNo col,const TInt64& aValue)
sl@0: 	{aSet.SetColL(col,aValue);}
sl@0: inline void SetColL(RDbRowSet& aSet,TDbColNo col,const TReal32& aValue)
sl@0: 	{aSet.SetColL(col,aValue);}
sl@0: inline void SetColL(RDbRowSet& aSet,TDbColNo col,const TReal64& aValue)
sl@0: 	{aSet.SetColL(col,aValue);}
sl@0: inline void SetColL(RDbRowSet& aSet,TDbColNo col,const TTime& aValue)
sl@0: 	{aSet.SetColL(col,aValue);}
sl@0: inline void SetColL(RDbRowSet& aSet,TDbColNo col,const TPtrC& aValue)
sl@0: 	{aSet.SetColL(col,aValue);}
sl@0: 
sl@0: template <class T>
sl@0: void BuildTable(TDbColType aType,TInt aAttribs,T aValues[],TInt aCount)
sl@0: 	{
sl@0: 	BuildTableProlog(aType,aAttribs);
sl@0: 	for (TInt ii=0;ii<aCount;++ii)
sl@0: 		{
sl@0: 		TheTable.InsertL();
sl@0: 		SetColL(TheTable,1,aValues[ii]);
sl@0: 		TheTable.PutL();
sl@0: 		}
sl@0: 	test(TheDatabase.Commit()==KErrNone);
sl@0: 	test (TheTable.CountL()==aCount);
sl@0: 	TheTable.Close();
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-0620
sl@0: @SYMTestCaseDesc        Setting the specified index as the active index for a table test 
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Create an index and set as active index for the table.
sl@0:                         Tests for RDbNamedDatabase::CreateIndex(),RDbNamedDatabase::Commit()
sl@0: 						RDbTable::Open(),RDbTable::SetIndex() functions. 
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: LOCAL_C void BuildIndex(TDbTextComparison aComparison=EDbCompareNormal,TInt aLength=KDbUndefinedLength)
sl@0: 	{
sl@0: 	test.Next(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0620 Test index order "));
sl@0: 	TheDatabase.Begin();
sl@0: 	CDbKey *key=CDbKey::NewLC();
sl@0: 	key->AddL(TDbKeyCol(KColumnName,aLength));
sl@0: 	key->MakeUnique();
sl@0: 	key->SetComparison(aComparison);
sl@0: 	test(TheDatabase.CreateIndex(KIndexName,KTableName,*key)==KErrNone);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: 	test (TheDatabase.Commit()==KErrNone);
sl@0: 	test(TheTable.Open(TheDatabase,KTableName)==KErrNone);
sl@0: 	test(TheTable.SetIndex(KIndexName)==KErrNone);
sl@0: 	}
sl@0: 
sl@0: inline void GetCol(RDbRowSet& aSet,TDbColNo col,TInt& aValue)
sl@0: 	{aValue=aSet.ColInt(col);}
sl@0: inline void GetCol(RDbRowSet& aSet,TDbColNo col,TUint& aValue)
sl@0: 	{aValue=aSet.ColUint(col);}
sl@0: inline void GetCol(RDbRowSet& aSet,TDbColNo col,TInt64& aValue)
sl@0: 	{aValue=aSet.ColInt64(col);}
sl@0: inline void GetCol(RDbRowSet& aSet,TDbColNo col,TReal32& aValue)
sl@0: 	{aValue=aSet.ColReal32(col);}
sl@0: inline void GetCol(RDbRowSet& aSet,TDbColNo col,TReal64& aValue)
sl@0: 	{aValue=aSet.ColReal64(col);}
sl@0: inline void GetCol(RDbRowSet& aSet,TDbColNo col,TTime& aValue)
sl@0: 	{aValue=aSet.ColTime(col);}
sl@0: 
sl@0: /**
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-0621
sl@0: @SYMTestCaseDesc        RDbRowSet ordering test
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Reorder the row set data with RDbRowSet::GetL(),SetL() functions.
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: template <class T>
sl@0: void TestOrdering(RDbRowSet& aSet,T,TInt aCount)
sl@0: 	{
sl@0: 	test.Next( _L( " @SYMTestCaseID:SYSLIB-DBMS-CT-0621 " ) );
sl@0: 	test(aSet.CountL()==aCount);
sl@0: 	TInt count=0;
sl@0: 	if (aSet.FirstL())
sl@0: 		{
sl@0: 		++count;
sl@0: 		aSet.GetL();
sl@0: 		T last;
sl@0: 		GetCol(aSet,1,last);
sl@0: 		while (aSet.NextL())	
sl@0: 			{
sl@0: 			++count;
sl@0: 			aSet.GetL();
sl@0: 			T current;
sl@0: 			GetCol(aSet,1,current);
sl@0: 			test(last<current);
sl@0: 			last=current;
sl@0: 			}
sl@0: 		}
sl@0: 	test(count==aCount);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-0622
sl@0: @SYMTestCaseDesc        RDbTable::SeekL() function test
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Tests for the retrieved column value
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: template <class T>
sl@0: void TestSeek(RDbTable& aTable,T,const T aValues[],TInt aCount)
sl@0: 	{
sl@0: 	test.Next( _L( " @SYMTestCaseID:SYSLIB-DBMS-CT-0622 Test index seeking " ) );
sl@0: 	for (TInt ii=0;ii<aCount;++ii)
sl@0: 		{
sl@0: 		test(aTable.SeekL(aValues[ii]));
sl@0: 		aTable.GetL();
sl@0: 		T val;
sl@0: 		GetCol(aTable,1,val);
sl@0: 		test(aValues[ii]==val);
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: aVal argument is used in the test functions (TestType & TestOrdering) and has no meaning outside them.
sl@0: It is used only to avoid some compiler varnings and to determine the correct template type
sl@0: 
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-0623
sl@0: @SYMTestCaseDesc        Tests for RDbTable,RDbRowSet classes
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Call up Test for table ordering and index seeking functions
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: template <class T>
sl@0: void TestType( TDbColType aType, TInt aAttribs, const T aValues[], TInt aCount )
sl@0: 	{
sl@0: 	test.Start( _L( " @SYMTestCaseID:SYSLIB-DBMS-CT-0623 Build table " ) );
sl@0: 	BuildTable( aType, aAttribs, aValues, aCount );
sl@0: 	T t(0);
sl@0: //
sl@0: 	test.Next( _L( "Test ORDER BY ordering" ) );
sl@0: 	test( TheView.Prepare( TheDatabase, KSelectOrdered ) == KErrNone );
sl@0: 	test( TheView.EvaluateAll() == KErrNone );
sl@0: 	TestOrdering( TheView, t, aCount );
sl@0: 	TheView.Close();
sl@0: //
sl@0: 	test.Next( _L( "Test index ordering" ) );
sl@0: 	BuildIndex();
sl@0: 	TestOrdering( TheTable, t, aCount );
sl@0: //
sl@0: 	test.Next( _L( "Test index seeking" ) );
sl@0: 	TestSeek( TheTable, t, aValues, aCount );
sl@0: 	TheTable.Close();
sl@0: //
sl@0: 	test( TheDatabase.DropTable( KTableName ) == KErrNone );
sl@0: 	test.End();
sl@0: 	}
sl@0: /**
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-1322
sl@0: @SYMTestCaseDesc        Text ordering test 
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Tests for RDbRowSet::Next(),RDbRowSet::GetL(),RDbRowSet::ColDes() functions
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: void TestTextOrdering(RDbRowSet& aSet,TInt aCount,const TTextOps& aComp)
sl@0: 	{
sl@0: 	test.Next(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-1322 "));
sl@0: 	test(aSet.CountL()==aCount);
sl@0: 	TInt count=0;
sl@0: 	while (aSet.NextL())
sl@0: 		{
sl@0: 		aSet.GetL();
sl@0: 		TPtrC current=aSet.ColDes(1);
sl@0: 		if (count++>0)
sl@0: 			test(aComp.Compare(TheBuf,current)<0);
sl@0: 		TheBuf=current;
sl@0: 		}
sl@0: 	test(count==aCount);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-1323
sl@0: @SYMTestCaseDesc        Tests for RDbView,RDbTable classes 
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Wrapper function to call up for text ordering and text indexing tests
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: void TestText(const TPtrC aValues[],TInt aCount,TDbTextComparison aComparison,TInt aLength=KDbUndefinedLength)
sl@0: 	{
sl@0: 	const TTextOps& comp=TTextOps::Ops(aComparison);
sl@0: 	test.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-1323 Build table "));
sl@0: 	BuildTable(EDbColText,0,aValues,aCount);
sl@0: //
sl@0: 	test.Next(_L("Test ORDER BY ordering"));
sl@0: 	test (TheView.Prepare(TheDatabase,TDbQuery(KSelectOrdered,aComparison))==KErrNone);
sl@0: 	test (TheView.EvaluateAll()==KErrNone);
sl@0: 	TestTextOrdering(TheView,aCount,comp);
sl@0: 	TheView.Close();
sl@0: //
sl@0: 	test.Next(_L("Test index order"));
sl@0: 	BuildIndex(aComparison,aLength);
sl@0: 	test(TheTable.SetIndex(KIndexName)==KErrNone);
sl@0: 	TestTextOrdering(TheTable,aCount,comp);
sl@0: //
sl@0: 	test.Next(_L("Test index seeking"));
sl@0: 	for (TInt ii=0;ii<aCount;++ii)
sl@0: 		{
sl@0: 		test(TheTable.SeekL(aValues[ii]));
sl@0: 		TheTable.GetL();
sl@0: 		test(comp.Compare(aValues[ii],TheTable.ColDes(1))==0);
sl@0: 		}
sl@0: //
sl@0: 	TheTable.Close();
sl@0: 	test(TheDatabase.DropTable(KTableName)==KErrNone);
sl@0: 	test.End();
sl@0: 	}
sl@0: 
sl@0: void TestLongTextOrdering(RDbRowSet& aSet,TInt aCount,const TTextOps& aComp)
sl@0: 	{
sl@0: 	test(aSet.CountL()==aCount);
sl@0: 	TInt count=0;
sl@0: 	HBufC* prev=0;
sl@0: 	while (aSet.NextL())
sl@0: 		{
sl@0: 		aSet.GetL();
sl@0: 		TInt len=aSet.ColLength(1);
sl@0: 		HBufC* buf=HBufC::NewL(len);
sl@0: 		RDbColReadStream s;
sl@0: 		s.OpenLC(aSet,1);
sl@0: 		TPtr des(buf->Des());
sl@0: 		s.ReadL(des,len);
sl@0: 		CleanupStack::PopAndDestroy();
sl@0: 		if (count++)
sl@0: 			test (aComp.Compare(*buf,*prev)>=0);
sl@0: 		delete prev;
sl@0: 		prev=buf;
sl@0: 		}
sl@0: 	delete prev;
sl@0: 	test(count==aCount);
sl@0: 	}
sl@0: 
sl@0: LOCAL_C void OrderByLongText(TInt aCount,TDbTextComparison aComparison)
sl@0: 	{
sl@0: 	test (TheView.Prepare(TheDatabase,TDbQuery(KSelectOrdered,aComparison))==KErrNone);
sl@0: 	test (TheView.EvaluateAll()==KErrNone);
sl@0: 	TestLongTextOrdering(TheView,aCount,TTextOps::Ops(aComparison));
sl@0: 	TheView.Close();
sl@0: 	}
sl@0: 
sl@0: LOCAL_C void TestLongText(const TPtrC aValues[],TInt aCount,TDbTextComparison aComparison,TInt aLength=KDbUndefinedLength)
sl@0: 	{
sl@0: 	const TTextOps& comp=TTextOps::Ops(aComparison);
sl@0: 	test.Start(_L("Build table"));
sl@0: 	BuildTable(EDbColLongText,0,aValues,aCount);
sl@0: //
sl@0: 	test.Next(_L("Test ORDER BY ordering"));
sl@0: 	OrderByLongText(aCount,aComparison);
sl@0: //
sl@0: 	test.Next(_L("Test index order"));
sl@0: 	BuildIndex(aComparison,aLength);
sl@0: 	test(TheTable.SetIndex(KIndexName)==KErrNone);
sl@0: 	TestLongTextOrdering(TheTable,aCount,comp);
sl@0: //
sl@0: 	test.Next(_L("Test index seeking"));
sl@0: 	for (TInt ii=0;ii<aCount;++ii)
sl@0: 		{
sl@0: 		test(TheTable.SeekL(aValues[ii]));
sl@0: 		TheTable.GetL();
sl@0: 		RDbColReadStream strm;
sl@0: 		strm.OpenLC(TheTable,1);
sl@0: 		strm.ReadL(TheBuf,TheTable.ColLength(1));
sl@0: 		CleanupStack::PopAndDestroy();
sl@0: 		test(comp.Compare(aValues[ii],TheBuf)==0);
sl@0: 		}
sl@0: 	TheTable.Close();
sl@0: //
sl@0: 	test(TheDatabase.DropTable(KTableName)==KErrNone);
sl@0: 	test.End();
sl@0: 	}
sl@0: 
sl@0: TUint const KBitValues[]={0,1};
sl@0: TInt const KInt8Values[]={0,KMinTInt8+1,1,KMaxTInt8,2,-3,-1,KMaxTInt8-1,KMinTInt8,-40};
sl@0: TInt const KInt16Values[]={0,KMinTInt16+1,1,KMaxTInt16,2,-3,-1,KMaxTInt16-1,KMinTInt16,-4000};
sl@0: TInt const KInt32Values[]={0,KMinTInt32+1,1,KMaxTInt32,2,-3,-1,KMaxTInt32-1,KMinTInt32,-40000000};
sl@0: TInt const KInt32Count=sizeof(KInt32Values)/sizeof(KInt32Values[0]);
sl@0: TUint const KUint8Values[]={0,1,KMaxTUint8,2,(KMaxTUint8+1)/2,(KMaxTUint8-1)/2,KMaxTUint8-1,40};
sl@0: TUint const KUint16Values[]={0,1,KMaxTUint16,2,(KMaxTUint16+1)/2,(KMaxTUint16-1)/2,KMaxTUint16-1,4000};
sl@0: TUint const KUint32Values[]={0,1,KMaxTUint32,2,KMaxTUint32/2+1,KMaxTUint32/2,KMaxTUint32-1,40000000};
sl@0: //TReal32 const KReal32Values[]={0.0f,1.0f,KMaxTReal32,KMinTReal32,-1.0f,-KMaxTReal32,-4e20f,-KMinTReal32};
sl@0: //TReal64 const KReal64Values[]={0.0,1.0,KMaxTReal64,KMinTReal64,-1.0,-KMaxTReal64,-4e200,-KMinTReal64};
sl@0: TReal32 const KReal32Values[]={0.0f,1.0f,1e37f,1e-37f,-1.0f,-1e37f,-4e20f,-1e-37f};
sl@0: TReal64 const KReal64Values[]={0.0,1.0,KMaxTReal64,KMinTReal64,-1.0,-KMaxTReal64,-4e200,-KMinTReal64};
sl@0: TInt64 const KInt64Values[]=
sl@0: 	{
sl@0: 	0,
sl@0: 	MAKE_TINT64(0x80000000u,0x1u),
sl@0: 	1,
sl@0: 	MAKE_TINT64(0x7fffffffu,0xffffffffu),
sl@0: 	2,
sl@0: 	-3,
sl@0: 	-1,
sl@0: 	MAKE_TINT64(0x7fffffffu,0xfffffffeu),
sl@0: 	MAKE_TINT64(0x80000000u,0x0u),
sl@0: 	-40
sl@0: 	};
sl@0: TTime const KTimeValues[]=
sl@0: 	{
sl@0: 	Time::MaxTTime(),
sl@0: 	TInt64(0),
sl@0: 	TDateTime(1970,EJanuary,0,0,0,0,0),
sl@0: 	Time::MinTTime(),
sl@0: 	TDateTime(2049,EDecember,30,23,59,59,999999),
sl@0: 	TDateTime(1996,EJuly,8,17,45,0,0)
sl@0: 	};
sl@0: TPtrC const KTextValues[]=
sl@0: 	{
sl@0: 	_S(""),
sl@0: 	_S("10"),
sl@0: 	_S("zyx"),
sl@0: 	_S("0"),
sl@0: 	_S("abcd"),
sl@0: 	_S("abcdefg"),
sl@0: 	_S("ABCDE"),
sl@0: 	_S("Z")
sl@0: 	};
sl@0: TPtrC const KLongTextValues[]=
sl@0: 	{
sl@0: 	_S("this blob will be inlined"),
sl@0: 	_S(""),
sl@0: 	_S("that blob was null"),
sl@0: 	_S("An example of an out-of-line blob in an index! LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8-LongText8")
sl@0: 	};
sl@0: const TInt KLongTextLimit=30;
sl@0: 
sl@0: /**
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-0624
sl@0: @SYMTestCaseDesc        Wrapper function testing for Indexing with different integer sizes and Text .
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Tests for indexing
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: LOCAL_C void TestTypes()
sl@0: 	{
sl@0: 	#define ARRAY_SIZE(a) TInt(sizeof(a)/sizeof(a[0]))
sl@0: 	test.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0624 Indexing Bit "));
sl@0: 	TestType(EDbColBit,TDbCol::ENotNull,KBitValues,ARRAY_SIZE(KBitValues));
sl@0: 	test.Next(_L("Indexing Int8"));
sl@0: 	TestType(EDbColInt8,TDbCol::ENotNull,KInt8Values,ARRAY_SIZE(KInt8Values));
sl@0: 	test.Next(_L("Indexing Int16"));
sl@0: 	TestType(EDbColInt16,TDbCol::ENotNull,KInt16Values,ARRAY_SIZE(KInt16Values));
sl@0: 	test.Next(_L("Indexing Int32"));
sl@0: 	TestType(EDbColInt32,TDbCol::ENotNull,KInt32Values,ARRAY_SIZE(KInt32Values));
sl@0: 	test.Next(_L("Indexing Uint8"));
sl@0: 	TestType(EDbColUint8,TDbCol::ENotNull,KUint8Values,ARRAY_SIZE(KUint8Values));
sl@0: 	test.Next(_L("Indexing Uint16"));
sl@0: 	TestType(EDbColUint16,TDbCol::ENotNull,KUint16Values,ARRAY_SIZE(KUint16Values));
sl@0: 	test.Next(_L("Indexing Uint32"));
sl@0: 	TestType(EDbColUint32,TDbCol::ENotNull,KUint32Values,ARRAY_SIZE(KUint32Values));
sl@0: 	test.Next(_L("Indexing Real32"));
sl@0: 	TestType(EDbColReal32,TDbCol::ENotNull,KReal32Values,ARRAY_SIZE(KReal32Values));
sl@0: 	test.Next(_L("Indexing Real64"));
sl@0: 	TestType(EDbColReal64,TDbCol::ENotNull,KReal64Values,ARRAY_SIZE(KReal64Values));
sl@0: 	test.Next(_L("Indexing Int64"));
sl@0: 	TestType(EDbColInt64,TDbCol::ENotNull,KInt64Values,ARRAY_SIZE(KInt64Values));
sl@0: 	test.Next(_L("Indexing Time"));
sl@0: 	TestType(EDbColDateTime,TDbCol::ENotNull,KTimeValues,ARRAY_SIZE(KTimeValues));
sl@0: 	test.Next(_L("Indexing Text (Normal)"));
sl@0: 	TestText(KTextValues,ARRAY_SIZE(KTextValues),EDbCompareNormal);
sl@0: 	test.Next(_L("Indexing Text (Folded)"));
sl@0: 	TestText(KTextValues,ARRAY_SIZE(KTextValues),EDbCompareFolded);
sl@0: 	test.Next(_L("Indexing Text (Collated)"));
sl@0: 	TestText(KTextValues,ARRAY_SIZE(KTextValues),EDbCompareCollated);
sl@0: 	test.Next(_L("Indexing Text (Normal, truncated)"));
sl@0: 	TestText(KTextValues,ARRAY_SIZE(KTextValues),EDbCompareNormal,5);
sl@0: 	test.Next(_L("Indexing LongText (Normal)"));
sl@0: 	TestLongText(KLongTextValues,ARRAY_SIZE(KLongTextValues),EDbCompareNormal,KLongTextLimit);
sl@0: 	test.Next(_L("Indexing LongText (Folded)"));
sl@0: 	TestLongText(KLongTextValues,ARRAY_SIZE(KLongTextValues),EDbCompareFolded,KLongTextLimit);
sl@0: 	test.Next(_L("Indexing LongText (Collated)"));
sl@0: 	TestLongText(KLongTextValues,ARRAY_SIZE(KLongTextValues),EDbCompareCollated,KLongTextLimit);
sl@0: 	test.End();
sl@0: 	}
sl@0: 
sl@0: const TInt KBlobKeyTruncated=32/sizeof(TText);
sl@0: const TInt KBlobKeyMaxInline=255/sizeof(TText);
sl@0: const TInt KBlobKeyCompare=512/sizeof(TText);
sl@0: 
sl@0: const TInt KMemoTestLengths[]=
sl@0: 	{
sl@0: 	0,
sl@0: 	1,
sl@0: 	KBlobKeyTruncated-1,
sl@0: 	KBlobKeyTruncated,
sl@0: 	KBlobKeyTruncated+1,
sl@0: 	KBlobKeyMaxInline,
sl@0: 	KBlobKeyMaxInline+1,
sl@0: 	KBlobKeyCompare-1,
sl@0: 	KBlobKeyCompare,
sl@0: 	KBlobKeyCompare+1,
sl@0: 	5000
sl@0: 	};
sl@0: 
sl@0: void TestMemoTable(CDbColSet& aBaseSet)
sl@0: 	{
sl@0: 	test.Start(_L("create the table"));
sl@0: 	aBaseSet.AddL(TDbCol(KColumnName,EDbColLongText));
sl@0: 	TheDatabase.Begin();
sl@0: 	TInt r=TheDatabase.CreateTable(KTableName,aBaseSet);
sl@0: 	test (r==KErrNone);
sl@0: //
sl@0: 	test.Next(_L("add the rows"));
sl@0: 	r=TheView.Prepare(TheDatabase,KSelectOrdered,RDbView::EInsertOnly);
sl@0: 	test (r==KErrNone);
sl@0: 	r=TheView.EvaluateAll();
sl@0: 	test (r==KErrNone);
sl@0: 	HBufC* prev=0;
sl@0: 	TInt count=0;
sl@0: 	for (TUint ii=0;ii<elementsof(KMemoTestLengths);++ii)
sl@0: 		{
sl@0: 		TInt size=KMemoTestLengths[ii];
sl@0: 		HBufC* buf=HBufC::NewL(size);
sl@0: 		if (size>0)
sl@0: 			{
sl@0: 			TPtr des(buf->Des());
sl@0: 			des.Copy(*prev);
sl@0: 			des.AppendFill('b',size-prev->Length());
sl@0: 			delete prev;
sl@0: 			TheView.InsertL();
sl@0: 			TheView.SetColL(1,*buf);
sl@0: 			TheView.PutL();
sl@0: 			++count;
sl@0: 			des[size-1]='a';
sl@0: 			}
sl@0: 		TheView.InsertL();
sl@0: 		TheView.SetColL(1,*buf);
sl@0: 		TheView.PutL();
sl@0: 		++count;
sl@0: 		prev=buf;
sl@0: 		}
sl@0: 	delete prev;
sl@0: 	TheView.Close();
sl@0: 	r=TheDatabase.Commit();
sl@0: 	test (r==KErrNone);
sl@0: //
sl@0: 	test.Next(_L("Normal order"));
sl@0: 	OrderByLongText(count,EDbCompareNormal);
sl@0: 	test.Next(_L("Folded order"));
sl@0: 	OrderByLongText(count,EDbCompareFolded);
sl@0: 	test.Next(_L("Collated order"));
sl@0: 	OrderByLongText(count,EDbCompareCollated);
sl@0: //
sl@0: 	r=TheDatabase.DropTable(KTableName);
sl@0: 	test (r==KErrNone);
sl@0: 	test.End();
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-0625
sl@0: @SYMTestCaseDesc        Tests for ordering by longtext 
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Tests for CDbColSet 
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: LOCAL_C void TestOrderByLongText()
sl@0: 	{
sl@0: 	test.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0625 Maximum Inline Limit "));
sl@0: 	CDbColSet* set=CDbColSet::NewLC();
sl@0: 	TestMemoTable(*set);
sl@0: //
sl@0: 	test.Next(_L("Reduced Inline limit [<32]"));
sl@0: 	set->Clear();
sl@0: 	TDbCol col;
sl@0: 	col.iType=EDbColText8;
sl@0: 	col.iMaxLength=255;
sl@0: 	col.iAttributes=0;
sl@0: 	TDbColName name;
sl@0: 	for (TInt ii=0;ii<32;++ii)
sl@0: 		{
sl@0: 		name.Format(_L("col%d"),ii);
sl@0: 		col.iName=name;
sl@0: 		if (ii==31)
sl@0: 			col.iMaxLength=255-20;
sl@0: 		set->AddL(col);
sl@0: 		}
sl@0: 	TestMemoTable(*set);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: 	test.End();
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-0626
sl@0: @SYMTestCaseDesc        Tests for reverse ordering in indexes
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Tests for reversing the indexes
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: LOCAL_C void TestReverse()
sl@0: 	{
sl@0: 	test.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0626 Create table and index "));
sl@0: 	TheDatabase.Begin();
sl@0: 	CDbColSet *cs=CDbColSet::NewLC();
sl@0: 	cs->AddL(TDbCol(KColumnName,EDbColInt32));
sl@0: 	test(TheDatabase.CreateTable(KTableName,*cs)==KErrNone);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: 	CDbKey *key=CDbKey::NewLC();
sl@0: 	key->AddL(TDbKeyCol(KColumnName,TDbKeyCol::EDesc));
sl@0: 	key->MakeUnique();
sl@0: 	test(TheDatabase.CreateIndex(KIndexName,KTableName,*key)==KErrNone);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: 	test(TheDatabase.Commit()==KErrNone);
sl@0: 	test.Next(_L("Add records"));
sl@0: 	TheDatabase.Begin();
sl@0: 	test(TheTable.Open(TheDatabase,KTableName)==KErrNone);
sl@0: 	for (TInt ii=0;ii<KInt32Count;++ii)
sl@0: 		{
sl@0: 		TheTable.InsertL();
sl@0: 		TheTable.SetColL(1,KInt32Values[ii]);
sl@0: 		TheTable.PutL();
sl@0: 		}
sl@0: 	test(TheDatabase.Commit()==KErrNone);
sl@0: 	test(TheTable.CountL()==KInt32Count);
sl@0: 	test.Next(_L("Check order"));
sl@0: 	test(TheTable.SetIndex(KIndexName)==KErrNone);
sl@0: 	test(TheTable.CountL()==KInt32Count);
sl@0: 	TInt count=0;
sl@0: 	if (TheTable.FirstL())
sl@0: 		{
sl@0: 		++count;
sl@0: 		TheTable.GetL();
sl@0: 		TInt32 last=TheTable.ColInt(1);
sl@0: 		while (TheTable.NextL())
sl@0: 			{
sl@0: 			++count;
sl@0: 			TheTable.GetL();
sl@0: 			TInt32 current=TheTable.ColInt(1);
sl@0: 			test(last>current);
sl@0: 			last=current;
sl@0: 			}
sl@0: 		}
sl@0: 	test(count==KInt32Count);
sl@0: 	TheTable.Close();
sl@0: 	test(TheDatabase.DropTable(KTableName)==KErrNone);
sl@0: 	test.End();
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-0627
sl@0: @SYMTestCaseDesc        Tests for multi-column keys
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Tests for mutliple column keys
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: LOCAL_C void TestMulti()
sl@0: 	{
sl@0: 	test.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0627 Create table and index "));
sl@0: 	TheDatabase.Begin();
sl@0: 	CDbColSet *cs=CDbColSet::NewLC();
sl@0: 	TDbCol col(KColumnName,EDbColInt32);
sl@0: 	col.iAttributes=TDbCol::ENotNull;
sl@0: 	cs->AddL(col);
sl@0: 	col.iName=KColumnTwo;
sl@0: 	cs->AddL(col);
sl@0: 	test(TheDatabase.CreateTable(KTableName,*cs)==KErrNone);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: 	CDbKey *key=CDbKey::NewLC();
sl@0: 	key->AddL(TDbKeyCol(KColumnTwo));
sl@0: 	key->AddL(TDbKeyCol(KColumnName,TDbKeyCol::EDesc));
sl@0: 	key->MakeUnique();
sl@0: 	test(TheDatabase.CreateIndex(KIndexName,KTableName,*key)==KErrNone);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: 	test(TheDatabase.Commit()==KErrNone);
sl@0: 	test.Next(_L("Add records"));
sl@0: 	TheDatabase.Begin();
sl@0: 	test(TheTable.Open(TheDatabase,KTableName)==KErrNone);
sl@0: 	for (TInt ii=0;ii<KInt32Count;++ii)
sl@0: 		{
sl@0: 		for (TInt jj=0;jj<KInt32Count;++jj)
sl@0: 			{
sl@0: 			TheTable.InsertL();
sl@0: 			TheTable.SetColL(1,KInt32Values[ii]);
sl@0: 			TheTable.SetColL(2,KInt32Values[jj]);
sl@0: 			TheTable.PutL();
sl@0: 			}
sl@0: 		}
sl@0: 	test(TheDatabase.Commit()==KErrNone);
sl@0: 	test.Next(_L("Check order"));
sl@0: 	test(TheTable.CountL()==KInt32Count*KInt32Count);
sl@0: 	test(TheTable.SetIndex(KIndexName)==KErrNone);
sl@0: 	test(TheTable.CountL()==KInt32Count*KInt32Count);
sl@0: 	TInt count=0;
sl@0: 	if (TheTable.FirstL())
sl@0: 		{
sl@0: 		++count;
sl@0: 		TheTable.GetL();
sl@0: 		TInt32 lastOne=TheTable.ColInt(1);
sl@0: 		TInt32 lastTwo=TheTable.ColInt(2);
sl@0: 		while (TheTable.NextL())
sl@0: 			{
sl@0: 			++count;
sl@0: 			TheTable.GetL();
sl@0: 			TInt32 currentOne=TheTable.ColInt(1);
sl@0: 			TInt32 currentTwo=TheTable.ColInt(2);
sl@0: 			test(lastTwo<currentTwo||(lastTwo==currentTwo&&lastOne>currentOne));
sl@0: 			lastOne=currentOne;
sl@0: 			lastTwo=currentTwo;
sl@0: 			}
sl@0: 		}
sl@0: 	test(count==KInt32Count*KInt32Count);
sl@0: 	TheTable.Close();
sl@0: 	test(TheDatabase.DropTable(KTableName)==KErrNone);
sl@0: 	test.End();
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-0628
sl@0: @SYMTestCaseDesc        Tests duplicates/unique constraints
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Tests for adding duplicate entries 
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: LOCAL_C void TestDuplicates()
sl@0: 	{
sl@0: 	test.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0628 Create table and indices "));
sl@0: 	BuildTable(EDbColInt32,TDbCol::ENotNull,KInt32Values,KInt32Count);
sl@0: 	BuildIndex();
sl@0: 	TheTable.Close();
sl@0: 	CDbKey* key=CDbKey::NewLC();
sl@0: 	key->AddL(KColumnName);
sl@0: 	test(TheDatabase.CreateIndex(KIndexTwo,KTableName,*key)==KErrNone);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: 	test.Next(_L("Attempt to add/update duplicate entry"));
sl@0: 	test(TheTable.Open(TheDatabase,KTableName)==KErrNone);
sl@0: 	TheTable.InsertL();
sl@0: 	TheTable.SetColL(1,0);
sl@0: 	TRAPD(r,TheTable.PutL());
sl@0: 	test(r!=KErrNone);
sl@0: 	TheTable.Cancel();
sl@0: 	TheTable.LastL();
sl@0: 	TheTable.UpdateL();
sl@0: 	TheTable.SetColL(1,0);
sl@0: 	TRAP(r,TheTable.PutL());
sl@0: 	test(r!=KErrNone);
sl@0: 	TheTable.Cancel();
sl@0: 	test.Next(_L("Remove unique index"));
sl@0: 	TheTable.Close();
sl@0: 	test(TheDatabase.DropIndex(KIndexName,KTableName)==KErrNone);
sl@0: 	test.Next(_L("Attempt to update/add duplicate entry"));
sl@0: 	test(TheTable.Open(TheDatabase,KTableName)==KErrNone);
sl@0: 	TheTable.LastL();
sl@0: 	TheTable.UpdateL();
sl@0: 	TheTable.SetColL(1,0);
sl@0: 	TRAP(r,TheTable.PutL());
sl@0: 	test(r==KErrNone);
sl@0: 	TheTable.InsertL();
sl@0: 	TheTable.SetColL(1,0);
sl@0: 	TRAP(r,TheTable.PutL());
sl@0: 	test(r==KErrNone);
sl@0: 	test.Next(_L("Check order"));
sl@0: 	test(TheTable.CountL()==KInt32Count+1);
sl@0: 	test(TheTable.SetIndex(KIndexTwo)==KErrNone);
sl@0: 	test(TheTable.CountL()==KInt32Count+1);
sl@0: 	TInt count=0;
sl@0: 	if (TheTable.FirstL())
sl@0: 		{
sl@0: 		++count;
sl@0: 		TheTable.GetL();
sl@0: 		TInt32 last=TheTable.ColInt(1);
sl@0: 		while (TheTable.NextL())
sl@0: 			{
sl@0: 			++count;
sl@0: 			TheTable.GetL();
sl@0: 			TInt32 current=TheTable.ColInt(1);
sl@0: 			test(last<=current);	// duplicates present
sl@0: 			last=current;
sl@0: 			}
sl@0: 		}
sl@0: 	test(count==KInt32Count+1);
sl@0: 	test.Next(_L("Try to create unique index"));
sl@0: 	TheTable.Close();
sl@0: 	key=CDbKey::NewLC();
sl@0: 	key->AddL(KColumnName);
sl@0: 	key->MakeUnique();
sl@0: 	test(TheDatabase.CreateIndex(KIndexName,KTableName,*key)!=KErrNone);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: 	test(TheDatabase.DropTable(KTableName)==KErrNone);
sl@0: 	test.End();
sl@0: 	}
sl@0: 
sl@0: struct Pair { TInt i1,i2; };
sl@0: struct TSeekingTest
sl@0: 	{
sl@0: 	Pair iSeek;
sl@0: 	Pair iResults[5];
sl@0: 	};
sl@0: 
sl@0: // seek pair: results for <,<=,=,>=,>
sl@0: static TSeekingTest const SeekingTests[]=
sl@0: 	{
sl@0: 	{{0,0},{{-1,-1},{-1,-1},{-1,-1},{100,10},{100,10}}},
sl@0: 	{{0,-1},{{-1,-1},{-1,-1},{-1,-1},{100,10},{100,10}}},
sl@0: 	{{100,0},{{-1,-1},{-1,-1},{-1,-1},{100,10},{100,10}}},
sl@0: 	{{100,10},{{-1,-1},{100,10},{100,10},{100,10},{100,20}}},
sl@0: 	{{100,55},{{100,50},{100,50},{-1,-1},{100,60},{100,60}}},
sl@0: 	{{100,60},{{100,50},{100,60},{100,60},{100,60},{100,70}}},
sl@0: 	{{100,100},{{100,90},{100,100},{100,100},{100,100},{200,10}}},
sl@0: 	{{100,110},{{100,100},{100,100},{-1,-1},{200,10},{200,10}}},
sl@0: 	{{100,-1},{{-1,-1},{100,100},{100,10},{100,10},{200,10}}},
sl@0: 	{{500,-1},{{400,100},{500,100},{500,10},{500,10},{600,10}}},
sl@0: 	{{550,50},{{500,100},{500,100},{-1,-1},{600,10},{600,10}}},
sl@0: 	{{550,-1},{{500,100},{500,100},{-1,-1},{600,10},{600,10}}},
sl@0: 	{{1000,0},{{900,100},{900,100},{-1,-1},{1000,10},{1000,10}}},
sl@0: 	{{1000,10},{{900,100},{1000,10},{1000,10},{1000,10},{1000,20}}},
sl@0: 	{{1000,100},{{1000,90},{1000,100},{1000,100},{1000,100},{-1,-1}}},
sl@0: 	{{1000,110},{{1000,100},{1000,100},{-1,-1},{-1,-1},{-1,-1}}},
sl@0: 	{{1000,-1},{{900,100},{1000,100},{1000,10},{1000,10},{-1,-1}}},
sl@0: 	{{1100,0},{{1000,100},{1000,100},{-1,-1},{-1,-1},{-1,-1}}},
sl@0: 	{{1100,-1},{{1000,100},{1000,100},{-1,-1},{-1,-1},{-1,-1}}}
sl@0: 	};
sl@0: 
sl@0: /**
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-0629
sl@0: @SYMTestCaseDesc        Tests for seeking on indexes
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Tests for SeekL and GetL functions 
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: LOCAL_C void TestSeeking()
sl@0: 	{
sl@0: 	test.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0629 Create table and index "));
sl@0: 	TheDatabase.Begin();
sl@0: 	CDbColSet *cs=CDbColSet::NewLC();
sl@0: 	TDbCol col(KColumnName,EDbColInt32);
sl@0: 	col.iAttributes=TDbCol::ENotNull;
sl@0: 	cs->AddL(col);
sl@0: 	col.iName=KColumnTwo;
sl@0: 	cs->AddL(col);
sl@0: 	test(TheDatabase.CreateTable(KTableName,*cs)==KErrNone);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: 	CDbKey *key=CDbKey::NewLC();
sl@0: 	key->AddL(KColumnName).AddL(KColumnTwo);
sl@0: 	key->MakeUnique();
sl@0: 	test(TheDatabase.CreateIndex(KIndexName,KTableName,*key)==KErrNone);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: 	test(TheDatabase.Commit()==KErrNone);
sl@0: 	test.Next(_L("Add records"));
sl@0: 	TheDatabase.Begin();
sl@0: 	test(TheTable.Open(TheDatabase,KTableName)==KErrNone);
sl@0: 	for (TInt ii=100;ii<=1000;ii+=100)
sl@0: 		{
sl@0: 		for (TInt jj=10;jj<=100;jj+=10)
sl@0: 			{
sl@0: 			TheTable.InsertL();
sl@0: 			TheTable.SetColL(1,ii);
sl@0: 			TheTable.SetColL(2,jj);
sl@0: 			TheTable.PutL();
sl@0: 			}
sl@0: 		}
sl@0: 	test(TheDatabase.Commit()==KErrNone);
sl@0: 	test(TheTable.CountL()==100);
sl@0: 	test(TheTable.SetIndex(KIndexName)==KErrNone);
sl@0: 	test(TheTable.CountL()==100);
sl@0: 	test.Next(_L("Seeking"));
sl@0: 	const TSeekingTest* stest=SeekingTests;
sl@0: 	const TSeekingTest* const end=stest+sizeof(SeekingTests)/sizeof(SeekingTests[0])-1;
sl@0: 	for (;stest<=end;++stest)
sl@0: 		{
sl@0: 		TDbSeekMultiKey<2> key;
sl@0: 		key.Add(stest->iSeek.i1);
sl@0: 		if (stest->iSeek.i2>=0)
sl@0: 			key.Add(stest->iSeek.i2);
sl@0: 		const Pair* results=stest->iResults;
sl@0: 		for (TInt ii=RDbTable::ELessThan;ii<=RDbTable::EGreaterThan;++results,++ii)
sl@0: 			{
sl@0: 			if (TheTable.SeekL(key,RDbTable::TComparison(ii)))
sl@0: 				{
sl@0: 				test(results->i1>=0);
sl@0: 				TRAPD(errCode, TheTable.GetL());
sl@0: 				test(errCode==KErrNone);
sl@0: 				test(TheTable.ColInt(1)==results->i1);
sl@0: 				test(TheTable.ColInt(2)==results->i2);
sl@0: 				}
sl@0: 			else
sl@0: 				test(results->i1<0);
sl@0: 			}
sl@0: 		}
sl@0: 	TheTable.Close();
sl@0: 	test(TheDatabase.DropTable(KTableName)==KErrNone);
sl@0: 	test.End();
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: @SYMTestCaseID          SYSLIB-DBMS-CT-0630
sl@0: @SYMTestCaseDesc        Tests for defect,index creation and set index operations 
sl@0: @SYMTestPriority        Medium
sl@0: @SYMTestActions         Tests for creating and setting index operations
sl@0: @SYMTestExpectedResults Test must not fail
sl@0: @SYMREQ                 REQ0000
sl@0: */
sl@0: LOCAL_C void TestInequalityError()
sl@0: 	{
sl@0: 	test.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0630 Create table "));
sl@0: 	TheDatabase.Begin();
sl@0: 	CDbColSet *cs=CDbColSet::NewLC();
sl@0: 	cs->AddL(TDbCol(KColumnName,EDbColInt32));
sl@0: 	test(TheDatabase.CreateTable(KTableName,*cs)==KErrNone);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: //
sl@0: 	test.Next(_L("create indices"));
sl@0: 	CDbKey *key=CDbKey::NewLC();
sl@0: 	key->AddL(TDbKeyCol(KColumnName));
sl@0: 	test(TheDatabase.CreateIndex(KIndexName,KTableName,*key)==KErrNone);
sl@0: 	CleanupStack::PopAndDestroy();
sl@0: //
sl@0: 	test.Next(_L("Populate table"));
sl@0: 	test(TheTable.Open(TheDatabase,KTableName)==KErrNone);
sl@0: 	for(TInt ii=0; ii<=130;++ii)
sl@0: 		{
sl@0: 		TheTable.InsertL();
sl@0: 		TheTable.SetColL(1,ii);
sl@0: 		TheTable.PutL();
sl@0: 		}
sl@0: //	
sl@0: 	test.Next(_L("Checks"));
sl@0: 	test(TheTable.SetIndex(KIndexName)==KErrNone);
sl@0: //
sl@0: // We need to delete a row in this node to get to the correct inequality condition
sl@0: 	test.Next(_L("Delete row 90"));
sl@0: 	test(TheTable.SeekL(TDbSeekKey(90)));
sl@0: 	TheTable.GetL();
sl@0: 	TheTable.DeleteL();
sl@0: // Now delete last row on node which should be 94
sl@0: 	test.Next(_L("Delete row 94"));
sl@0: 	test(TheTable.SeekL(TDbSeekKey(94)));
sl@0: 	TheTable.GetL();
sl@0: 	TheTable.DeleteL();
sl@0: 	TheTable.EndL();
sl@0: 	test(!TheTable.SeekL(TDbSeekKey(94)));
sl@0: //
sl@0: 	test.Next(_L("Insert row 94"));
sl@0: 	TheTable.InsertL();
sl@0: 	TheTable.SetColL(1,94);
sl@0: 	TheTable.PutL();
sl@0: //	
sl@0: 	test.Next(_L("now try and find it"));
sl@0: 	test(TheTable.SeekL(TDbSeekKey(94))); //prior to defect fix this line failed.
sl@0: //	
sl@0: 	TheTable.Close();
sl@0: 	test(TheDatabase.DropTable(KTableName)==KErrNone);
sl@0: 	test.End();
sl@0: 	}
sl@0: 
sl@0: //
sl@0: // Test the database definition and enquiry functions
sl@0: //
sl@0: LOCAL_C void TestIndexes()
sl@0: 	{
sl@0: 	test.Start(_L("Create Database"));
sl@0: 	CreateDatabaseL();
sl@0: 	test.Next(_L("Test index build and drop"));
sl@0: 	TestIndexBuild();
sl@0: 	test.Next(_L("Test index persistence"));
sl@0: 	TestPersistence();
sl@0: 	test.Next(_L("Testing index key types"));
sl@0: 	TestTypes();
sl@0: 	test.Next(_L("Testing LongText ORDER BY"));
sl@0: 	TestOrderByLongText();
sl@0: 	test.Next(_L("Testing reverse ordering"));
sl@0: 	TestReverse();
sl@0: 	test.Next(_L("Testing multi column keys"));
sl@0: 	TestMulti();
sl@0: 	test.Next(_L("Testing duplicate/unqiue"));
sl@0: 	TestDuplicates();
sl@0: 	test.Next(_L("Testing seeking"));
sl@0: 	TestSeeking();
sl@0: 	test.Next(_L("Testing incorrect inequaltiy condition in store btree"));
sl@0: 	TestInequalityError();
sl@0: 	CloseDatabaseL();
sl@0: 	test.End();
sl@0: 	}
sl@0: 
sl@0: //
sl@0: // Prepare the test directory.
sl@0: //
sl@0: LOCAL_C void setupTestDirectory()
sl@0:     {
sl@0: 	TInt r=TheFs.Connect();
sl@0: 	test(r==KErrNone);
sl@0: //
sl@0: 	r=TheFs.MkDir(KTestDatabase);
sl@0: 	test(r==KErrNone || r==KErrAlreadyExists);
sl@0: 	}
sl@0: 
sl@0: //
sl@0: // Initialise the cleanup stack.
sl@0: //
sl@0: LOCAL_C void setupCleanup()
sl@0:     {
sl@0: 	TheTrapCleanup=CTrapCleanup::New();
sl@0: 	test(TheTrapCleanup!=NULL);
sl@0: 	TRAPD(r,\
sl@0: 		{\
sl@0: 		for (TInt i=KTestCleanupStack;i>0;i--)\
sl@0: 			CleanupStack::PushL((TAny*)0);\
sl@0: 		CleanupStack::Pop(KTestCleanupStack);\
sl@0: 		});
sl@0: 	test(r==KErrNone);
sl@0: 	}
sl@0: 
sl@0: LOCAL_C void DeleteDataFile(const TDesC& aFullName)
sl@0: 	{
sl@0: 	RFs fsSession;
sl@0: 	TInt err = fsSession.Connect();
sl@0: 	if(err == KErrNone)
sl@0: 		{
sl@0: 		TEntry entry;
sl@0: 		if(fsSession.Entry(aFullName, entry) == KErrNone)
sl@0: 			{
sl@0: 			RDebug::Print(_L("Deleting \"%S\" file.\n"), &aFullName);
sl@0: 			err = fsSession.SetAtt(aFullName, 0, KEntryAttReadOnly);
sl@0: 			if(err != KErrNone) 
sl@0: 				{
sl@0: 				RDebug::Print(_L("Error %d changing \"%S\" file attributes.\n"), err, &aFullName);
sl@0: 				}
sl@0: 			err = fsSession.Delete(aFullName);
sl@0: 			if(err != KErrNone) 
sl@0: 				{
sl@0: 				RDebug::Print(_L("Error %d deleting \"%S\" file.\n"), err, &aFullName);
sl@0: 				}
sl@0: 			}
sl@0: 		fsSession.Close();
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		RDebug::Print(_L("Error %d connecting file session. File: %S.\n"), err, &aFullName);
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: //
sl@0: // Test streaming conversions.
sl@0: //
sl@0: GLDEF_C TInt E32Main()
sl@0:     {
sl@0: 	test.Title();
sl@0: 	setupTestDirectory();
sl@0: 	setupCleanup();
sl@0: 	__UHEAP_MARK;
sl@0: //
sl@0: #ifndef __TOOLS2__
sl@0: 	TInt r=TheDbs.Connect();
sl@0: 	test (r==KErrNone);
sl@0: 	TheDbs.ResourceMark();
sl@0: #else
sl@0: 	TInt r;
sl@0: #endif
sl@0: 	test.Start(_L("Standard database"));
sl@0: 	TRAP(r,TestIndexes();)
sl@0: 	test(r==KErrNone);
sl@0: 	test.Next(_L("Secure database"));
sl@0: 	TRAP(r,TestIndexes();)
sl@0: 	test(r==KErrNone);
sl@0: 	
sl@0: 	::DeleteDataFile(KTestDatabase);	//deletion of data files must be before call to end - DEF047652
sl@0: 	
sl@0: #ifndef __linux__
sl@0: 	TInt err;
sl@0: #ifndef __TOOLS2__
sl@0: 	TRAPD(lc, err = TheCrcChecker.DumpCrcRecordsL(KCrcRecord));
sl@0: 	test(err==KErrNone);
sl@0: 	test(lc==KErrNone);
sl@0: #else
sl@0: 	TRAPD(lc, err = TheCrcChecker.ValidateCrcRecordsL(KCrcRecord));
sl@0: 	TPtrC errmsg;
sl@0: 	TheCrcChecker.ErrorReportL(err, errmsg);
sl@0: 	RDebug::Print(errmsg);
sl@0: 	test(err==KErrNone || err==TDBMS_CRCChecks::ECrcCheckOk);
sl@0: #endif
sl@0: #endif
sl@0: 	
sl@0: 	test.End();
sl@0: #ifndef __TOOLS2__
sl@0: 	TheDbs.ResourceCheck();
sl@0: 	TheDbs.Close();
sl@0: #endif
sl@0: 
sl@0: 	test.Printf(_L("Waiting for server exit\n"));
sl@0: 	const TUint KExitDelay=6*0x100000;	// ~6 seconds
sl@0: 	User::After(KExitDelay);
sl@0: 
sl@0: 	__UHEAP_MARKEND;
sl@0: 	delete TheTrapCleanup;
sl@0: 
sl@0: 	TheFs.Close();
sl@0: 	test.Close();
sl@0: 	return 0;
sl@0:     }