diff -r 000000000000 -r 08ec8eefde2f persistentstorage/dbms/tdbms/t_dbalter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/dbms/tdbms/t_dbalter.cpp Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,697 @@ +// 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 +#include +#include + +LOCAL_D RTest test(_L("t_dbalter : Test AlterTable")); +LOCAL_D CTrapCleanup* TheTrapCleanup; +LOCAL_D CFileStore* TheStore; +LOCAL_D RDbStoreDatabase TheDatabase; +LOCAL_D RDbTable TheTable; +LOCAL_D RFs TheFs; + +const TInt KTestCleanupStack=0x20; +const TPtrC KTestDir=_L("C:\\DBMS-TST\\"); +const TPtrC KTestFile=_L("T_ALTER.DB"); +const TPtrC KTableName(_S("Table")); +const TPtrC KTableName2(_S("Table2")); +const TPtrC KIndexName(_S("Index")); + +TInt KRecords=100; + +const TUint KCol1Data=0; +const TInt KCol2Data=2; +const TPtrC KCol3Data=_L("three"); +const TUint8 _Col4Data[80]={4,4,4,4,0,0xff,2,2,1}; +const TPtrC8 KCol4Data(_Col4Data,sizeof(_Col4Data)); +const TUint KCol5Data=1; +const TInt KCol6Data=5; +const TPtrC KCol7Data=_L("six"); +const TPtrC KCol8Data=_L("column number eight = #8"); +const TUint8 _Col9Data[400]={1,2,3,4,5,6,7,8,9,10}; +const TPtrC8 KCol9Data(_Col9Data,sizeof(_Col9Data)); + +const TText* const KColumn1=_S("c1"); +const TText* const KColumn2=_S("c2"); +const TText* const KColumn3=_S("c3"); +const TText* const KColumn4=_S("c4"); +const TText* const KColumn5=_S("c5"); +const TText* const KColumn6=_S("c6"); +const TText* const KColumn7=_S("c7"); +const TText* const KColumn8=_S("c8"); +const TText* const KColumn9=_S("c9"); +const TText* const KColumn10=_S("c10"); +const TText* const KColumn11=_S("c11"); +const TPtrC KColumns[]= + { + KColumn1, + KColumn2, + KColumn3, + KColumn4, + KColumn5, + KColumn6, + KColumn7, + KColumn8, + KColumn9 + }; + +class Set + { +public: + struct SColDef + { + const TText* iName; + TDbColType iType; + TInt iAttributes; + TInt iMaxLength; + }; + static SColDef const Basic[]; + static SColDef const Bad[]; + static SColDef const Incompatible1[]; + static SColDef const Incompatible2[]; + static SColDef const Incompatible3[]; + static SColDef const Different[]; + static SColDef const Extended[]; + static SColDef const LongerText[]; + static SColDef const TextToLongText[]; + static SColDef const Column3[]; + static SColDef const DropSome[]; + static SColDef const DropAndAdd[]; +public: + static CDbColSet* CreateL(const SColDef* aDef); + }; +// the basic column definition +enum TCol {EBit,EInt,EText,ELong,EBitNull,EIntNull,ETextNull,ELongNull,EExtra}; +Set::SColDef const Set::Basic[]= + { + {KColumn1,EDbColBit,TDbCol::ENotNull,-1}, + {KColumn2,EDbColInt32,TDbCol::ENotNull,-1}, + {KColumn3,EDbColText,TDbCol::ENotNull,-1}, + {KColumn4,EDbColLongBinary,TDbCol::ENotNull,-1}, + {KColumn5,EDbColBit,0,-1}, + {KColumn6,EDbColInt32,0,-1}, + {KColumn7,EDbColText,0,-1}, + {KColumn8,EDbColText,0,50}, + {0} + }; +// a basically invalid set +Set::SColDef const Set::Bad[]= + { + {KColumn9,EDbColInt32,0,-1}, + {KColumn9,EDbColInt32,0,-1}, + {0} + }; +// an incompatible set with Basic +Set::SColDef const Set::Incompatible1[]= + { + {KColumn1,EDbColInt32,TDbCol::ENotNull,-1}, // retype a column + {0} + }; +Set::SColDef const Set::Incompatible2[]= + { + {KColumn5,EDbColBit,TDbCol::ENotNull,-1}, // change attributes + {0} + }; +Set::SColDef const Set::Incompatible3[]= + { + {KColumn8,EDbColText,0,49}, // shrink a text column + {0} + }; +// a wildly different set +Set::SColDef const Set::Different[]= + { + {KColumn11,EDbColInt32,0,-1}, + {KColumn4,EDbColLongBinary,TDbCol::ENotNull,-1}, + {KColumn10,EDbColBit,TDbCol::ENotNull,-1}, + {KColumn3,EDbColText,TDbCol::ENotNull,-1}, + {0} + }; +// basic + 1 column +Set::SColDef const Set::Extended[]= + { + {KColumn1,EDbColBit,TDbCol::ENotNull,-1}, + {KColumn2,EDbColInt32,TDbCol::ENotNull,-1}, + {KColumn3,EDbColText,TDbCol::ENotNull,-1}, + {KColumn4,EDbColLongBinary,TDbCol::ENotNull,-1}, + {KColumn5,EDbColBit,0,-1}, + {KColumn6,EDbColInt32,0,-1}, + {KColumn7,EDbColText,0,-1}, + {KColumn8,EDbColText,0,50}, + {KColumn9,EDbColLongBinary,0,-1}, // add this column + {0} + }; +// Extended with a longer text column +Set::SColDef const Set::LongerText[]= + { + {KColumn1,EDbColBit,TDbCol::ENotNull,-1}, + {KColumn2,EDbColInt32,TDbCol::ENotNull,-1}, + {KColumn3,EDbColText,TDbCol::ENotNull,-1}, + {KColumn4,EDbColLongBinary,TDbCol::ENotNull,-1}, + {KColumn5,EDbColBit,0,-1}, + {KColumn6,EDbColInt32,0,-1}, + {KColumn7,EDbColText,0,-1}, + {KColumn8,EDbColText,0,51}, // longer definition + {KColumn9,EDbColLongBinary,0,-1}, + {0} + }; +// Extended with a text->LongText column +Set::SColDef const Set::TextToLongText[]= + { + {KColumn1,EDbColBit,TDbCol::ENotNull,-1}, + {KColumn2,EDbColInt32,TDbCol::ENotNull,-1}, + {KColumn3,EDbColText,TDbCol::ENotNull,-1}, + {KColumn4,EDbColLongBinary,TDbCol::ENotNull,-1}, + {KColumn5,EDbColBit,0,-1}, + {KColumn6,EDbColInt32,0,-1}, + {KColumn7,EDbColText,0,-1}, + {KColumn8,EDbColLongText,0,-1}, // longer still + {KColumn9,EDbColLongBinary,0,-1}, + {0} + }; +Set::SColDef const Set::Column3[]= + { + {KColumn3,EDbColText,TDbCol::ENotNull,-1}, + {0} + }; +Set::SColDef const Set::DropSome[]= + { + {KColumn1,EDbColBit,TDbCol::ENotNull,-1}, + {KColumn2,EDbColInt32,TDbCol::ENotNull,-1}, + {KColumn6,EDbColInt32,0,-1}, + {KColumn7,EDbColText,0,-1}, + {0} + }; +Set::SColDef const Set::DropAndAdd[]= + { + {KColumn2,EDbColInt32,TDbCol::ENotNull,-1}, + {KColumn7,EDbColText,0,-1}, + {KColumn10,EDbColBinary,0,-1}, + {0} + }; + +CDbColSet* Set::CreateL(const SColDef* aDef) + { + CDbColSet *set=CDbColSet::NewLC(); + for (;aDef->iName;++aDef) + { + TDbCol col(TPtrC(aDef->iName),aDef->iType); + col.iAttributes=aDef->iAttributes; + if (aDef->iMaxLength>=0) + col.iMaxLength=aDef->iMaxLength; + set->AddL(col); + } + CleanupStack::Pop(); + return set; + } + +// +// Create the database-in-a-store +// +LOCAL_C void CreateDatabaseL() + { + CFileStore* store=CPermanentFileStore::ReplaceLC(TheFs,KTestFile,EFileRead|EFileWrite); + store->SetTypeL(KPermanentFileStoreLayoutUid); + TStreamId id; + id=TheDatabase.CreateL(store); + store->SetRootL(id); + store->CommitL(); + CleanupStack::Pop(); + TheStore=store; + } + +// +// Open the database-in-a-store +// +LOCAL_C void OpenDatabaseL() + { + CFileStore* store=CFileStore::OpenLC(TheFs,KTestFile,EFileRead|EFileWrite); + TStreamId id=store->Root(); + TheDatabase.OpenL(store,id); + CleanupStack::Pop(); + TheStore=store; + } + +LOCAL_C void CloseDatabaseL() + { + TheDatabase.Close(); + delete TheStore; + } + +LOCAL_C void DestroyDatabaseL() + { + TheDatabase.Destroy(); + TheStore->CommitL(); + delete TheStore; + } + +LOCAL_C CDbColSet* TableDefinitionL(const TDesC& aTable) + { + RDbTable table; + test(table.Open(TheDatabase,aTable,table.EReadOnly)==KErrNone); + CDbColSet* cs=table.ColSetL(); + table.Close(); + return cs; + } + +// +// Compare two column sets +// +LOCAL_C void Compare(const CDbColSet& aLeft,const CDbColSet& aRight) + { + test(aLeft.Count()==aRight.Count()); + for (TDbColSetIter iter(aLeft);iter;++iter) + { + const TDbCol* pRight=aRight.Col(iter->iName); + test(pRight!=NULL); + test(iter->iType==pRight->iType); + test(iter->iMaxLength==KDbUndefinedLength || pRight->iMaxLength==KDbUndefinedLength || iter->iMaxLength==pRight->iMaxLength); + test((iter->iAttributes&pRight->iAttributes)==iter->iAttributes); + } + } + +/** +@SYMTestCaseID SYSLIB-DBMS-CT-0575 +@SYMTestCaseDesc Store database test + Test for altering the table with different column definitions +@SYMTestPriority Medium +@SYMTestActions Test for RDbStoreDatabase::AlterTable(),RDbStoreDatabase::DropIndex() +@SYMTestExpectedResults Test must not fail +@SYMREQ REQ0000 +*/ +LOCAL_C void TestEmptyTableL() + { + test.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0575 Create table ")); + CreateDatabaseL(); + CDbColSet* set=Set::CreateL(Set::Basic); + test(TheDatabase.CreateTable(KTableName,*set)==KErrNone); + test.Next(_L("Alter non existant table")); + test(TheDatabase.AlterTable(KTableName2,*set)==KErrNotFound); + delete set; +// + test.Next(_L("Alter to bad definitions")); + set=Set::CreateL(Set::Bad); + test(TheDatabase.AlterTable(KTableName,*set)!=KErrNone); + delete set; + set=Set::CreateL(Set::Incompatible1); + test(TheDatabase.AlterTable(KTableName,*set)!=KErrNone); + delete set; + set=Set::CreateL(Set::Incompatible2); + test(TheDatabase.AlterTable(KTableName,*set)!=KErrNone); + delete set; + set=Set::CreateL(Set::Incompatible3); + test(TheDatabase.AlterTable(KTableName,*set)!=KErrNone); + delete set; +// + test.Next(_L("Drop an indexed column")); + CDbKey* key=CDbKey::NewLC(); + key->AddL(TPtrC(KColumn2)); + key->MakeUnique(); + test(TheDatabase.CreateIndex(KIndexName,KTableName,*key)==KErrNone); + CleanupStack::PopAndDestroy(); + set=TableDefinitionL(KTableName); + set->Remove(TPtrC(KColumn2)); + test(TheDatabase.AlterTable(KTableName,*set)!=KErrNone); + test(TheDatabase.DropIndex(KIndexName,KTableName)==KErrNone); + delete set; +// + test.Next(_L("Extend an indexed text column")); + set=Set::CreateL(Set::Extended); + test(TheDatabase.AlterTable(KTableName,*set)==KErrNone); + delete set; + key=CDbKey::NewLC(); + key->AddL(TPtrC(KColumn8)); + key->MakeUnique(); + test(TheDatabase.CreateIndex(KIndexName,KTableName,*key)==KErrNone); + CleanupStack::PopAndDestroy(); + set=Set::CreateL(Set::LongerText); + test(TheDatabase.AlterTable(KTableName,*set)!=KErrNone); + test(TheDatabase.DropIndex(KIndexName,KTableName)==KErrNone); +// + test.Next(_L("Extend a text column")); + test(TheDatabase.AlterTable(KTableName,*set)==KErrNone); + delete set; +// + test.Next(_L("Extend a text column to a LongText column")); + set=Set::CreateL(Set::TextToLongText); + test(TheDatabase.AlterTable(KTableName,*set)==KErrNone); + delete set; +// + test.Next(_L("Alter to a very different set")); + set=Set::CreateL(Set::Different); + test(TheDatabase.AlterTable(KTableName,*set)==KErrNone); + CloseDatabaseL(); + OpenDatabaseL(); + CDbColSet* def=TableDefinitionL(KTableName); + Compare(*set,*def); + delete def; + delete set; + test.End(); + test(TheDatabase.DropTable(KTableName)==KErrNone); + DestroyDatabaseL(); + } + +class Map + { +public: + Map(); + void Init(RDbRowSet& aSet); + inline TDbColNo operator[](TInt aCol) const + {return iMap[aCol];} +private: + TDbColNo iMap[EExtra+1]; + }; + +Map::Map() + { + } + +void Map::Init(RDbRowSet& aSet) + { + CDbColSet* set=NULL; + TRAPD(errCode, set=aSet.ColSetL()); + if(errCode != KErrNone) + { + return; + } + for (TInt ii=EBit;ii<=EExtra;++ii) + iMap[ii]=set->ColNo(KColumns[ii]); + if(set) + delete set; + } + +// +// Build the table for Altering +// +LOCAL_C void BuildTableL(const Set::SColDef* aDef=Set::Basic) + { + CDbColSet* set=Set::CreateL(aDef); + test(TheDatabase.CreateTable(KTableName,*set)==KErrNone); + delete set; + TheDatabase.Begin(); + test(TheTable.Open(TheDatabase,KTableName,TheTable.EInsertOnly)==KErrNone); + Map map; + map.Init(TheTable); + for (TInt ii=0;ii buf; + __ASSERT_DEBUG(buf.MaxLength()>=aData.Length(),User::Invariant()); + RDbColReadStream str; + str.OpenLC(TheTable,aCol); + str.ReadL(buf,aData.Length()); + CleanupStack::PopAndDestroy(); + test(buf==aData); + } + +#if defined(UNICODE) +LOCAL_C void CheckBlobL(TDbColNo aCol,const TDesC16& aData) + { + test(TheTable.ColSize(aCol)==aData.Size()); + TBuf16<500> buf; + __ASSERT_DEBUG(buf.MaxLength()>=aData.Length(),User::Invariant()); + RDbColReadStream str; + str.OpenLC(TheTable,aCol); + str.ReadL(buf,aData.Length()); + CleanupStack::PopAndDestroy(); + test(buf==aData); + } +#endif + +// +// Check that the columns which still exist, still contain the same stuff +// New columns should be Null +// +LOCAL_C void CheckTableL() + { + test(TheTable.Open(TheDatabase,KTableName,TheTable.EReadOnly)==KErrNone); + Map map; + map.Init(TheTable); + + for (TInt ii=0;iiAddL(col10); + test(TheDatabase.AlterTable(KTableName,*set)!=KErrNone); +// + test.Next(_L("Add nullable column")); + set->Remove(col10.iName); + col10.iAttributes=0; + set->AddL(col10); + test(TheDatabase.AlterTable(KTableName,*set)==KErrNone); + CheckTableL(); +// + test.Next(_L("Drop columns one by one")); + while (set->Count()>1) + { + set->Remove((*set)[1].iName); + test(TheDatabase.AlterTable(KTableName,*set)==KErrNone); + CheckTableL(); + } + delete set; + test(TheDatabase.DropTable(KTableName)==KErrNone); +// + test.Next(_L("Extend a text column")); + BuildTableL(Set::Extended); + set=Set::CreateL(Set::LongerText); + test(TheDatabase.AlterTable(KTableName,*set)==KErrNone); + delete set; + CheckTableL(); +// + test.Next(_L("Extend it to a LongText column")); + set=Set::CreateL(Set::TextToLongText); + test(TheDatabase.AlterTable(KTableName,*set)==KErrNone); + delete set; + CheckTableL(); +// + test.Next(_L("Drop all except one")); + set=Set::CreateL(Set::Column3); + test(TheDatabase.AlterTable(KTableName,*set)==KErrNone); + delete set; + CheckTableL(); + test(TheDatabase.DropTable(KTableName)==KErrNone); + test.Next(_L("Drop single column")); + for (TInt ii=EBit;ii<=EExtra;++ii) + { + BuildTableL(Set::Extended); + CDbColSet* set=TableDefinitionL(KTableName); + set->Remove(KColumns[ii]); + test(TheDatabase.AlterTable(KTableName,*set)==KErrNone); + delete set; + CheckTableL(); + test(TheDatabase.DropTable(KTableName)==KErrNone); + } + test.Next(_L("Drop multiple columns")); + BuildTableL(); + set=Set::CreateL(Set::DropSome); + test(TheDatabase.AlterTable(KTableName,*set)==KErrNone); + delete set; + CheckTableL(); + test.Next(_L("Drop and add together")); + set=Set::CreateL(Set::DropAndAdd); + test(TheDatabase.AlterTable(KTableName,*set)==KErrNone); + delete set; + CheckTableL(); + test(TheDatabase.DropTable(KTableName)==KErrNone); + test.End(); + DestroyDatabaseL(); + } + +LOCAL_C void Test() + { + __UHEAP_MARK; +// + test.Start(_L("Alter empty table")); + TRAPD(r,TestEmptyTableL();) + test(r==KErrNone); + __UHEAP_CHECK(0); + test.Next(_L("Alter full table")); + TRAP(r,TestFullTableL();) + test(r==KErrNone); + test.End(); +// + __UHEAP_MARKEND; + } + +// +// Prepare the test directory. +// +LOCAL_C void setupTestDirectory() + { + TInt r=TheFs.Connect(); + test(r==KErrNone); +// + r=TheFs.MkDir(KTestDir); + test(r==KErrNone || r==KErrAlreadyExists); + r=TheFs.SetSessionPath(KTestDir); + test(r==KErrNone); + } + +// +// Initialise the cleanup stack. +// +LOCAL_C void setupCleanup() + { + TheTrapCleanup=CTrapCleanup::New(); + test(TheTrapCleanup!=NULL); + TRAPD(r,\ + {\ + for (TInt i=KTestCleanupStack;i>0;i--)\ + CleanupStack::PushL((TAny*)0);\ + CleanupStack::Pop(KTestCleanupStack);\ + }); + test(r==KErrNone); + } + +LOCAL_C void DeleteDataFile(const TDesC& aFullName) + { + RFs fsSession; + TInt err = fsSession.Connect(); + if(err == KErrNone) + { + TEntry entry; + if(fsSession.Entry(aFullName, entry) == KErrNone) + { + RDebug::Print(_L("Deleting \"%S\" file.\n"), &aFullName); + err = fsSession.SetAtt(aFullName, 0, KEntryAttReadOnly); + if(err != KErrNone) + { + RDebug::Print(_L("Error %d changing \"%S\" file attributes.\n"), err, &aFullName); + } + err = fsSession.Delete(aFullName); + if(err != KErrNone) + { + RDebug::Print(_L("Error %d deleting \"%S\" file.\n"), err, &aFullName); + } + } + fsSession.Close(); + } + else + { + RDebug::Print(_L("Error %d connecting file session. File: %S.\n"), err, &aFullName); + } + } + +// +// Test streaming conversions. +// +GLDEF_C TInt E32Main() + { + test.Title(); + setupTestDirectory(); + setupCleanup(); + __UHEAP_MARK; +// + test.Start(_L("Standard database")); + Test(); + test.Next(_L("Secure database")); + Test(); + + // clean up data files used by this test - must be done before call to End() - DEF047652 + _LIT(KTestDbName, "C:\\DBMS-TST\\T_ALTER.DB"); + ::DeleteDataFile(KTestDbName); + + test.End(); +// + __UHEAP_MARKEND; + delete TheTrapCleanup; + + TheFs.Close(); + test.Close(); + return 0; + }