persistentstorage/dbms/tdbms/t_dbstrcmp.cpp
changeset 0 08ec8eefde2f
child 55 44f437012c90
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Testing DBMS ordering and searching functionality when the key field is unicode string.
       
    15 // The idea is to verify that collation level 0 is used when doing string based searching
       
    16 // and collation level > 0 is used when doing string based ordering.
       
    17 // 
       
    18 //
       
    19 
       
    20 #include <e32test.h>
       
    21 #include <f32file.h>
       
    22 #include <d32dbms.h>
       
    23 
       
    24 /////////////////////////////////////////////////////////////////
       
    25 //Globals
       
    26 
       
    27 _LIT(					KTestDatabase, "C:\\DBMS-TST\\T_DbmsStrComp.DB");
       
    28 
       
    29 static RTest			TheTest(_L("t_dbstrcmp"));
       
    30 static RFs				TheFs;
       
    31 static RDbNamedDatabase TheDb;
       
    32 static RDbs				TheDbSession;
       
    33 
       
    34 //Test table defs
       
    35 _LIT(KTestTableName1, "TABLE1");//EDbColText16 key field
       
    36 _LIT(KTestTableName2, "TABLE2");//EDbColLongText16 key field
       
    37 
       
    38 struct TColDef
       
    39 	{
       
    40 	const TText*	iName;
       
    41 	TDbColType		iType;
       
    42 	TInt			iAttributes;
       
    43 	};
       
    44 static TColDef const KColDefs1[]=
       
    45 	{
       
    46 		{_S("ID"), EDbColText16, 0},
       
    47 		{_S("DATA"), EDbColUint32, 0},
       
    48 		{0}
       
    49 	};
       
    50 static TColDef const KColDefs2[]=
       
    51 	{
       
    52 		{_S("ID"), EDbColLongText16, 0},
       
    53 		{_S("DATA"), EDbColUint32, 0},
       
    54 		{0}
       
    55 	};
       
    56 
       
    57 //Test strings
       
    58 const TInt KTestStrLen = 3; //The length of test strings
       
    59 typedef TBuf16<KTestStrLen> TNameBuf;
       
    60 //Test strings array - using upper and lower case - which will force the DBMS server to make
       
    61 //different decisions depending on what is the current case: ordering or searching.
       
    62 const TNameBuf KTestStr[] =
       
    63 	{
       
    64 	_L16("aaa"),
       
    65 	_L16("aAa"),
       
    66 	_L16("bbB"),
       
    67 	_L16("BbB")
       
    68 	};
       
    69 const TInt KTestStrCnt = sizeof(KTestStr) / sizeof(KTestStr[0]);
       
    70 
       
    71 ///////////////////////////////////////////////////////////////////////////////////////
       
    72 ///////////////////////////////////////////////////////////////////////////////////////
       
    73 //Destroy test environment - global functions
       
    74 
       
    75 //Deletes "aFullName" file.
       
    76 static TInt DeleteDataFile(const TDesC& aFullName)
       
    77 	{
       
    78 	RFs fsSession;
       
    79 	TInt err = fsSession.Connect();
       
    80 	if(err == KErrNone)
       
    81 		{
       
    82 		TEntry entry;
       
    83 		err = fsSession.Entry(aFullName, entry);
       
    84 		if(err == KErrNone)
       
    85 			{
       
    86 			RDebug::Print(_L("Deleting \"%S\" file.\n"), &aFullName);
       
    87 			err = fsSession.SetAtt(aFullName, 0, KEntryAttReadOnly);
       
    88 			if(err != KErrNone)
       
    89 				{
       
    90 				RDebug::Print(_L("Error %d changing \"%S\" file attributes.\n"), err, &aFullName);
       
    91 				}
       
    92 			err = fsSession.Delete(aFullName);
       
    93 			if(err != KErrNone)
       
    94 				{
       
    95 				RDebug::Print(_L("Error %d deleting \"%S\" file.\n"), err, &aFullName);
       
    96 				}
       
    97 			}
       
    98 		fsSession.Close();
       
    99 		}
       
   100 	else
       
   101 		{
       
   102 		RDebug::Print(_L("Error %d connecting file session. File: %S.\n"), err, &aFullName);
       
   103 		}
       
   104 	return err;
       
   105 	}
       
   106 
       
   107 ///////////////////////////////////////////////////////////////////////////////////////
       
   108 ///////////////////////////////////////////////////////////////////////////////////////
       
   109 //Tests macros and functions.
       
   110 //If (!aValue) then the test will be panicked, the test data files will be deleted.
       
   111 static void Check(TInt aValue, TInt aLine)
       
   112 	{
       
   113 	if(!aValue)
       
   114 		{
       
   115 		::DeleteDataFile(KTestDatabase);
       
   116 		TheTest(EFalse, aLine);
       
   117 		}
       
   118 	}
       
   119 //If (aValue != aExpected) then the test will be panicked, the test data files will be deleted.
       
   120 static void Check(TInt aValue, TInt aExpected, TInt aLine)
       
   121 	{
       
   122 	if(aValue != aExpected)
       
   123 		{
       
   124 		RDebug::Print(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue);
       
   125 		::DeleteDataFile(KTestDatabase);
       
   126 		TheTest(EFalse, aLine);
       
   127 		}
       
   128 	}
       
   129 //Use these to test conditions.
       
   130 #define TEST(arg) ::Check((arg), __LINE__)
       
   131 #define TEST2(aValue, aExpected) ::Check(aValue, aExpected, __LINE__)
       
   132 
       
   133 ///////////////////////////////////////////////////////////////////////////////////////
       
   134 ///////////////////////////////////////////////////////////////////////////////////////
       
   135 //Global functions
       
   136 
       
   137 //Prepares the test directory.
       
   138 //TheFs.Connect() has to be called already.
       
   139 static void SetupTestDirectory()
       
   140     {
       
   141 	TInt err = TheFs.MkDir(KTestDatabase);
       
   142 	TEST(err == KErrNone || err == KErrAlreadyExists);
       
   143 	}
       
   144 
       
   145 //Leaves with info message printed out
       
   146 static void LeaveL(TInt aError, TInt aLine)
       
   147 	{
       
   148 	RDebug::Print(_L("*** Leave. Error: %d, Line: %d\r\n"), aError, aLine);
       
   149 	User::Leave(aError);
       
   150 	}
       
   151 
       
   152 //Leaves if aError < 0 with info message printed out
       
   153 static void LeaveIfErrorL(TInt aError, TInt aLine)
       
   154 	{
       
   155 	if(aError < KErrNone)
       
   156 		{
       
   157 		LeaveL(aError, aLine);
       
   158 		}
       
   159 	}
       
   160 
       
   161 //Use LEAVE() macro instead of User::Leave() and LEAVE_IF_ERROR() macro instead of
       
   162 //User::LeaveIfError(). They will print the line number, where the "leave" was called.
       
   163 #define LEAVE(aError) ::LeaveL(aError, __LINE__)
       
   164 #define LEAVE_IF_ERROR(aError) ::LeaveIfErrorL(aError, __LINE__)
       
   165 
       
   166 //Creates the test DBMS session
       
   167 static void CreateTestDbSession()
       
   168 	{
       
   169 	RDebug::Print(_L("Create DBMS session\n"));
       
   170 	TInt err = TheDbSession.Connect();
       
   171 	TEST2(err, KErrNone);
       
   172 	}
       
   173 
       
   174 
       
   175 //Creates the test database
       
   176 //TheDbSession instance has to be connected already.
       
   177 //TheFs.Connect() has to be called already.
       
   178 static void CreateTestDatabase(RDbs& aDbs, RDbNamedDatabase& aDb)
       
   179 	{
       
   180 	RDebug::Print(_L("Create test database\n"));
       
   181 	TInt err = aDb.Replace(TheFs, KTestDatabase);
       
   182 	TEST2(err, KErrNone);
       
   183 	TheDb.Close();
       
   184 	err = aDb.Open(aDbs, KTestDatabase);
       
   185 	TEST2(err, KErrNone);
       
   186 	}
       
   187 
       
   188 //Creates test table
       
   189 static void DoCreateTestTableL(RDbNamedDatabase& aDb, const TDesC& aTblName, const TColDef aColDefs[])
       
   190 	{
       
   191 	CDbColSet* colSet = CDbColSet::NewLC();
       
   192 	for(const TColDef* colDef=aColDefs;colDef->iName;++colDef)
       
   193 		{
       
   194 		TDbCol col(TPtrC(colDef->iName), colDef->iType);
       
   195 		col.iAttributes = colDef->iAttributes;
       
   196 		colSet->AddL(col);
       
   197 		}
       
   198 	TEST2(aDb.CreateTable(aTblName, *colSet), KErrNone);
       
   199 	CleanupStack::PopAndDestroy(colSet);
       
   200 	}
       
   201 
       
   202 //Creates test tables
       
   203 static void CreateTestTablesL(RDbNamedDatabase& aDb)
       
   204 	{
       
   205 	RDebug::Print(_L("Create test tables\n"));
       
   206 	::DoCreateTestTableL(aDb, KTestTableName1, KColDefs1);
       
   207 	::DoCreateTestTableL(aDb, KTestTableName2, KColDefs2);
       
   208 	}
       
   209 
       
   210 //Gets the value of the string field, which type may be EDbColText16 or EDbColLongText16
       
   211 void GetStrFieldValueL(RDbRowSet& aTbl, const TDesC& aTblName, TDes& aStrFldVal)
       
   212 	{
       
   213 	if(aTblName.CompareF(KTestTableName1) == 0)
       
   214 		{
       
   215 		aStrFldVal = aTbl.ColDes16(1);
       
   216 		}
       
   217 	else
       
   218 		{
       
   219 		RDbColReadStream blob;
       
   220 		blob.OpenLC(aTbl, 1);
       
   221 		blob.ReadL(aStrFldVal, aTbl.ColLength(1));
       
   222 		CleanupStack::PopAndDestroy();
       
   223 		}
       
   224 	}
       
   225 
       
   226 //Prints all table records
       
   227 static TInt PrintRecordsL(RDbRowSet& aTbl, const TDesC& aTblName)
       
   228 	{
       
   229 	RDebug::Print(_L("Table: %S\n"), &aTblName);
       
   230     aTbl.FirstL();
       
   231 	TInt rec = 0;
       
   232     while(aTbl.AtRow())
       
   233         {
       
   234         aTbl.GetL();
       
   235 		TNameBuf strFldVal;
       
   236 		GetStrFieldValueL(aTbl, aTblName, strFldVal);
       
   237 		TUint32 v = aTbl.ColUint32(2);
       
   238 		RDebug::Print(_L("   Record %d, Str: %S, Val: %d\n"), ++rec, &strFldVal, v);
       
   239         aTbl.NextL();
       
   240         }
       
   241 	return rec;
       
   242 	}
       
   243 
       
   244 //Checks if the records order (based on a string key field comparison) matches the order of the
       
   245 //strings in aTestStrArray
       
   246 static void AssertRecordsOrderL(RDbRowSet& aTbl, const TDesC& aTblName, const RArray<TNameBuf>& aTestStrArray)
       
   247 	{
       
   248     aTbl.FirstL();
       
   249 	TInt rec = 0;
       
   250     while(aTbl.AtRow())
       
   251         {
       
   252         aTbl.GetL();
       
   253 		TNameBuf strFldVal;
       
   254 		GetStrFieldValueL(aTbl, aTblName, strFldVal);
       
   255 		TEST(aTestStrArray[rec] == strFldVal);
       
   256 		++rec;
       
   257         aTbl.NextL();
       
   258         }
       
   259 	}
       
   260 
       
   261 //Adds test data to the specified table. Make sure that the records are not in
       
   262 //order (assuming that the first field will be the key).
       
   263 static void AddTestDataL(RDbNamedDatabase& aDb, const TDesC& aTblName)
       
   264 	{
       
   265 	RDbTable tbl;
       
   266 	CleanupClosePushL(tbl);
       
   267 	TEST2(tbl.Open(aDb, aTblName, RDbRowSet::EUpdatable), KErrNone);
       
   268 	for(TInt i=0;i<KTestStrCnt;++i)
       
   269 		{
       
   270 		tbl.InsertL();
       
   271 		tbl.SetColL(1, KTestStr[KTestStrCnt - i - 1]);
       
   272 		tbl.SetColL(2, i + 1);
       
   273 		tbl.PutL();
       
   274 		}
       
   275 	TEST(tbl.CountL() == KTestStrCnt);
       
   276 	(void)::PrintRecordsL(tbl, aTblName);
       
   277 	CleanupStack::PopAndDestroy(&tbl);
       
   278 	}
       
   279 
       
   280 //Adds the test data to test tables
       
   281 static void AddTestDataL(RDbNamedDatabase& aDb)
       
   282 	{
       
   283 	RDebug::Print(_L("Add data to test tables\n"));
       
   284 	::AddTestDataL(aDb, KTestTableName1);
       
   285 	::AddTestDataL(aDb, KTestTableName2);
       
   286 	}
       
   287 
       
   288 //Init test environment
       
   289 static void InitEnvL()
       
   290 	{
       
   291 	::CreateTestDbSession();
       
   292     //Create test database and tables. Add some test data to them.
       
   293 	::CreateTestDatabase(TheDbSession, TheDb);
       
   294 	::CreateTestTablesL(TheDb);
       
   295 	::AddTestDataL(TheDb);
       
   296 	}
       
   297 
       
   298 //String comparison function, used in FillStrArraySorted() function.
       
   299 static TInt CompareC(const TNameBuf& aName1, const TNameBuf& aName2)
       
   300     {
       
   301     return aName1.CompareC(aName2);
       
   302     }
       
   303 
       
   304 //Inserts all test string into an ordered array - aTestStrArray
       
   305 static void FillStrArraySortedL(RArray<TNameBuf>& aTestStrArray)
       
   306 	{
       
   307 	for(TInt i=0;i<KTestStrCnt;++i)
       
   308 		{
       
   309     	User::LeaveIfError(aTestStrArray.InsertInOrder(KTestStr[i], TLinearOrder<TNameBuf>(CompareC)));
       
   310 		}
       
   311 	}
       
   312 
       
   313 static void CreateIndexL(RDbNamedDatabase& aDb, const TDesC& aTblName, const TDesC& aColumnName)
       
   314 	{
       
   315 	RDebug::Print(_L("Create index. Table: %S, column: %S\n"), &aTblName, &aColumnName);
       
   316 	CDbKey* key = CDbKey::NewLC();
       
   317 	key->AddL(aColumnName);
       
   318 	key->MakeUnique();
       
   319 	key->SetComparison(EDbCompareCollated);
       
   320 	LEAVE_IF_ERROR(aDb.CreateIndex(aColumnName, aTblName, *key));
       
   321 	CleanupStack::PopAndDestroy(key);
       
   322 	}
       
   323 
       
   324 ///////////////////////////////////////////////////////////////////////////////////////
       
   325 ///////////////////////////////////////////////////////////////////////////////////////
       
   326 //Test cases
       
   327 
       
   328 //Test case 1. Check SELECT statement with ORDER BY clause when the key field is a string.
       
   329 static void OrderByTestL(RDbNamedDatabase& aDb, const TDesC& aTblName, const RArray<TNameBuf>& aTestStrArray)
       
   330 	{
       
   331     RDbView view;
       
   332     CleanupClosePushL(view);
       
   333 
       
   334     TBuf<128> sqlStmt;
       
   335     sqlStmt.Append(_L("SELECT ID, DATA FROM "));
       
   336     sqlStmt.Append(aTblName);
       
   337     sqlStmt.Append(_L(" ORDER BY ID"));
       
   338     User::LeaveIfError(view.Prepare(aDb, TDbQuery(sqlStmt, EDbCompareCollated), TDbWindow::EUnlimited));
       
   339     User::LeaveIfError(view.EvaluateAll());
       
   340 
       
   341 	(void)::PrintRecordsL(view, aTblName);
       
   342 	AssertRecordsOrderL(view, aTblName, aTestStrArray);
       
   343 
       
   344     CleanupStack::PopAndDestroy(&view);
       
   345 	}
       
   346 
       
   347 //Test case 2. Check SELECT statement with LIKE keyword when the key field is a string.
       
   348 static void LikeTestL(RDbNamedDatabase& aDb, const TDesC& aTblName)
       
   349 	{
       
   350     RDbView view;
       
   351     CleanupClosePushL(view);
       
   352 
       
   353     TBuf<128> sqlStmt;
       
   354     sqlStmt.Append(_L("SELECT ID, DATA FROM "));
       
   355     sqlStmt.Append(aTblName);
       
   356     sqlStmt.Append(_L(" WHERE ID LIKE 'B*'"));
       
   357     User::LeaveIfError(view.Prepare(aDb, TDbQuery(sqlStmt, EDbCompareCollated), TDbWindow::EUnlimited));
       
   358     User::LeaveIfError(view.EvaluateAll());
       
   359 
       
   360 	TInt cnt = ::PrintRecordsL(view, aTblName);
       
   361 	TEST(cnt == 2);
       
   362 
       
   363     CleanupStack::PopAndDestroy(&view);
       
   364 	}
       
   365 
       
   366 //Test case 3. Check SELECT statement with LIKE & ORDER BY keywords when the key field is a string.
       
   367 static void LikeOrderTestL(RDbNamedDatabase& aDb, const TDesC& aTblName, const RArray<TNameBuf>& aTestStrArray)
       
   368 	{
       
   369     RDbView view;
       
   370     CleanupClosePushL(view);
       
   371 
       
   372     TBuf<128> sqlStmt;
       
   373     sqlStmt.Append(_L("SELECT ID, DATA FROM "));
       
   374     sqlStmt.Append(aTblName);
       
   375     sqlStmt.Append(_L(" WHERE ID LIKE 'B*' ORDER BY ID"));
       
   376     User::LeaveIfError(view.Prepare(aDb, TDbQuery(sqlStmt, EDbCompareCollated), TDbWindow::EUnlimited));
       
   377     User::LeaveIfError(view.EvaluateAll());
       
   378 
       
   379 	TInt cnt = ::PrintRecordsL(view, aTblName);
       
   380 	TEST(cnt == 2);
       
   381 	AssertRecordsOrderL(view, aTblName, aTestStrArray);
       
   382 
       
   383     CleanupStack::PopAndDestroy(&view);
       
   384 	}
       
   385 
       
   386 //Test case 4. Indexed table. The index is a string field.
       
   387 static void IndexTestL(RDbNamedDatabase& aDb, const TDesC& aTblName, const RArray<TNameBuf>& aTestStrArray)
       
   388 	{
       
   389 	_LIT(KIdxName, "ID");
       
   390 	::CreateIndexL(aDb, aTblName, KIdxName);
       
   391 
       
   392 	RDbTable tbl;
       
   393 	CleanupClosePushL(tbl);
       
   394 	TEST2(tbl.Open(aDb, aTblName, RDbRowSet::EReadOnly), KErrNone);
       
   395 	TEST2(tbl.SetIndex(KIdxName), KErrNone);
       
   396 
       
   397 	(void)::PrintRecordsL(tbl, aTblName);
       
   398 	AssertRecordsOrderL(tbl, aTblName, aTestStrArray);
       
   399 
       
   400     CleanupStack::PopAndDestroy(&tbl);
       
   401 	}
       
   402 
       
   403 ///////////////////////////////////////////////////////////////////////////////////////
       
   404 ///////////////////////////////////////////////////////////////////////////////////////
       
   405 //The main test function.
       
   406 //Call your new test functions from here
       
   407 static void RunTestsL()
       
   408 	{
       
   409 	TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-LEGACY-DBMSSTRCOMP-0001 Init test environment "));
       
   410 	::InitEnvL();
       
   411 
       
   412     RArray<TNameBuf> testStrArray;
       
   413     CleanupClosePushL(testStrArray);
       
   414 	::FillStrArraySortedL(testStrArray);
       
   415 
       
   416 	TheTest.Next(_L("SELECT, ORDER BY, EDbColText16"));
       
   417 	::OrderByTestL(TheDb, KTestTableName1, testStrArray);
       
   418 
       
   419 	TheTest.Next(_L("SELECT, ORDER BY, EDbColLongText16"));
       
   420 	::OrderByTestL(TheDb, KTestTableName2, testStrArray);
       
   421 
       
   422 	TheTest.Next(_L("SELECT, LIKE, EDbColText16"));
       
   423 	::LikeTestL(TheDb, KTestTableName1);
       
   424 
       
   425 	TheTest.Next(_L("SELECT, LIKE, EDbColLongText16"));
       
   426 	::LikeTestL(TheDb, KTestTableName2);
       
   427 
       
   428     RArray<TNameBuf> testStrArray2;
       
   429     CleanupClosePushL(testStrArray2);
       
   430     testStrArray2.AppendL(testStrArray[2]);//"bbB"
       
   431     testStrArray2.AppendL(testStrArray[3]);//"BbB"
       
   432 
       
   433 	TheTest.Next(_L("SELECT, LIKE, ORDER BY, EDbColText16"));
       
   434 	::LikeOrderTestL(TheDb, KTestTableName1, testStrArray2);
       
   435 
       
   436 	TheTest.Next(_L("SELECT, LIKE, ORDER BY, EDbColLongText16"));
       
   437 	::LikeOrderTestL(TheDb, KTestTableName2, testStrArray2);
       
   438 
       
   439 	TheTest.Next(_L("Index, EDbColText16"));
       
   440 	::IndexTestL(TheDb, KTestTableName1, testStrArray);
       
   441 
       
   442 // Not possible to create a key with EDbColLongText16
       
   443 //	TheTest.Next(_L("Index, EDbColLongText16"));
       
   444 //	::IndexTestL(TheDb, KTestTableName2, testStrArray);
       
   445 
       
   446 	//Add tests here!
       
   447 
       
   448     CleanupStack::PopAndDestroy(&testStrArray2);
       
   449     CleanupStack::PopAndDestroy(&testStrArray);
       
   450 	}
       
   451 
       
   452 TInt E32Main()
       
   453 	{
       
   454 	TheTest.Title();
       
   455 
       
   456 	__UHEAP_MARK;
       
   457 
       
   458 	CTrapCleanup* trapCleanup = CTrapCleanup::New();
       
   459 	TEST(trapCleanup != NULL);
       
   460 
       
   461 	TInt err = TheFs.Connect();
       
   462 	TEST2(err, KErrNone);
       
   463 	::SetupTestDirectory();
       
   464 
       
   465 	::DeleteDataFile(KTestDatabase);
       
   466 
       
   467 	TRAP(err, ::RunTestsL());
       
   468 	TheDb.Close();
       
   469 	TheDbSession.Close();
       
   470 	TheFs.Close();
       
   471 	TEST2(err, KErrNone);
       
   472 
       
   473 	::DeleteDataFile(KTestDatabase);
       
   474 
       
   475 	TheTest.End();
       
   476 	TheTest.Close();
       
   477 
       
   478 	delete trapCleanup;
       
   479 
       
   480 	__UHEAP_MARKEND;
       
   481 
       
   482 	return 0;
       
   483 	}
       
   484 
       
   485