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