loggingservices/eventlogger/LogServ/src/LogServDatabaseMarshall.cpp
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loggingservices/eventlogger/LogServ/src/LogServDatabaseMarshall.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,622 @@
+// Copyright (c) 2002-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 <logclientchangeobserver.h>
+#include "LogServDatabaseMarshall.h"
+#include "logservpanic.h"
+#include "LogServCacheConfig.h"
+#include "LogServCacheStrings.h"
+#include "LogServCacheTypes.h"
+#include "LogServBackupInterface.h"
+#include "LogServResourceInterpreter.h"
+#include "LogServDatabaseChangeInterface.h"
+#include <logserv.rsg>
+#include "LogServSqlStrings.h"
+#include "LOGREPDEFS.H"
+
+
+// Constants
+const TInt KExpectedNumberOfTables = 4; // Should match the code in CreateTablesL
+
+// Literal constants
+_LIT(KLogDatabaseName,"Logdbu.dat");
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// -----> CLogServDatabaseMarshall (source)
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CLogServDatabaseMarshall::CLogServDatabaseMarshall(RFs& aFsSession, 
+												   CLogServResourceInterpreter& aResourceInterface, 
+												   MLogServBackupInterface& aBackupInterface)
+:	iFsSession(aFsSession), iResourceInterface(aResourceInterface), iBackupInterface(aBackupInterface)
+	{
+	}
+
+CLogServDatabaseMarshall::~CLogServDatabaseMarshall()
+	{
+	iBackupInterface.BIObserverRemove(*this);
+	//
+	delete iDatabaseName;
+	delete iCacheStrings;
+	delete iCacheTypes;
+	delete iCacheConfig;
+	delete iSecurity;
+	delete iEventType;
+	//
+	iDatabase.Close();
+	iStandardTypeUids.Close();
+	}
+
+void CLogServDatabaseMarshall::ConstructL()
+	{
+	iBackupInterface.BIObserverAddL(*this, MLogServBackupInterface::EObjectDatabaseMarshall);
+	//
+	iSecurity = CLogServSecurity::NewL(iResourceInterface);
+	//
+	iEventType = CLogEventType::NewL();
+	
+	DatabaseLocateL();
+	DatabaseOpenL();
+	RestoreStandardTypesL();
+	
+	iCacheTypes->CopyStandardTypeUidsL(iStandardTypeUids);
+	}
+
+CLogServDatabaseMarshall* CLogServDatabaseMarshall::NewL(RFs& aFsSession, 
+														 CLogServResourceInterpreter& aResourceInterface, 
+														 MLogServBackupInterface& aBackupInterface)
+	{
+	CLogServDatabaseMarshall* self = new(ELeave) CLogServDatabaseMarshall(aFsSession, aResourceInterface, aBackupInterface);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
+TInt CLogServDatabaseMarshall::DTIBegin()
+	{
+	const TInt backupError = iBackupInterface.BIErrorValueForCurrentState();
+	if	(backupError != KErrNone)
+		return backupError;
+
+	__ASSERT_DEBUG(!iDatabase.InTransaction(), Panic(ELogBeginInTransaction));
+	return iDatabase.Begin();
+	}
+
+TInt CLogServDatabaseMarshall::DTICommitAndEnd()
+	{
+	__ASSERT_DEBUG(iDatabase.InTransaction(), Panic(ELogCommitNotInTransaction));
+	TInt err = iDatabase.Commit();
+	if (err == KErrNone && iCacheStrings != NULL)
+		{
+		iCacheStrings->Commit();
+		}
+	return err;
+	}
+
+void CLogServDatabaseMarshall::DTIRollBack()
+	{
+	__ASSERT_DEBUG(iDatabase.InTransaction(), Panic(ELogRollbackNotInTransaction));
+	iDatabase.Rollback();
+	if (iCacheStrings != NULL)
+		{
+		iCacheStrings->Rollback();
+		}
+	}
+
+TInt CLogServDatabaseMarshall::DTIExecuteSql(const TDesC& aStatement, TDbTextComparison aComparison)
+	{
+	return iDatabase.Execute(aStatement, aComparison);
+	}
+
+TBool CLogServDatabaseMarshall::DTIInTransaction() const
+	{
+	return iDatabase.InTransaction();
+	}
+
+TBool CLogServDatabaseMarshall::DTIDatabaseIsDamaged() const
+	{
+	return iDatabase.IsDamaged();
+	}
+
+CLogServResourceInterpreter& CLogServDatabaseMarshall::DTIResourceInterface() const
+	{
+	return iResourceInterface;
+	}
+
+MLogServDatabaseChangeInterface& CLogServDatabaseMarshall::DTIChangeInterface() const
+	{
+	__ASSERT_ALWAYS(iChangeInterface, Panic(ELogNoChangeInterfacePointer));
+	return *iChangeInterface;
+	}
+
+CLogServCacheStrings& CLogServDatabaseMarshall::DTICacheStrings() const
+	{
+	__ASSERT_ALWAYS(iCacheStrings, Panic(ELogCacheAccessDuringBackupStrings));
+	return *iCacheStrings;
+	}
+
+CLogServCacheTypes& CLogServDatabaseMarshall::DTICacheTypes() const
+	{
+	__ASSERT_ALWAYS(iCacheTypes, Panic(ELogCacheAccessDuringBackupTypes));
+	return *iCacheTypes;
+	}
+
+CLogServCacheConfig& CLogServDatabaseMarshall::DTICacheConfig() const
+	{
+	__ASSERT_ALWAYS(iCacheConfig, Panic(ELogCacheAccessDuringBackupConfig));
+	return *iCacheConfig;
+	}
+
+RDbDatabase& CLogServDatabaseMarshall::DTIDatabase()
+	{
+	return iDatabase;
+	}
+
+TBool CLogServDatabaseMarshall::DTIIsAllowed(TEventOp aEventOp, const RMessage2& aMessage, TUid aEventType, const char* aDiagnostic) const
+	{
+	return iSecurity->IsAllowed(aMessage, aEventType, aEventOp, aDiagnostic);
+	}
+	
+const RArray<TUid>& CLogServDatabaseMarshall::DTIUidsOfStandardTypes()
+	{
+	return iStandardTypeUids;
+	}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CLogServDatabaseMarshall::BOHandleEventL(TLogServBackupEvent aEvent)
+	{
+	switch(aEvent)
+		{
+		case EBackupStarting:
+			{
+			//Destroy config, types and strings caches
+			delete iCacheConfig;
+			iCacheConfig = NULL;
+			delete iCacheStrings;
+			iCacheStrings = NULL;
+			delete iCacheTypes;
+			iCacheTypes = NULL;
+			//Close the database
+			iDatabase.Close();
+			}
+			break;
+			
+		case EBackupEnded:
+			{
+			// Re-open the database and create config, types and strings caches 
+			DatabaseOpenL();
+			// reset views as a different database is being restored
+			DTIChangeInterface().DCISubmitGlobalChangeContextL(KLogClientChangeEventRefreshView);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CLogServDatabaseMarshall::DatabaseLocateL()
+	{
+	// Get drive for database
+	TDriveUnit driveUnit(static_cast<TInt>(RFs::GetSystemDrive()));
+	TDriveName name(driveUnit.Name());
+	
+	TFileName path;
+	iFsSession.PrivatePath(path);
+	
+	// Ensure database path exists
+	TParse parse;
+	User::LeaveIfError(parse.Set(path, &name, NULL));
+	path = parse.FullName();
+	
+	TInt error = iFsSession.MkDirAll(path);
+	if	(error != KErrAlreadyExists)
+		User::LeaveIfError(error);
+	
+	path += KLogDatabaseName;
+	iDatabaseName = path.AllocL();
+	}
+
+/**
+Opens the LogEng database.
+@return KErrNone,    If the "database open" operation completes successfully.
+                     If the "database open" operation fails the function returns the repported error code. 
+        KErrCorrupt, If the database is opened successfully but is damaged, then the function returns KErrCorrupt.
+*/
+TInt CLogServDatabaseMarshall::DoDbOpen()
+    {
+    LOGTEXT2("CLogServDatabaseMarshall::DatabaseOpenL() - attempting to open db: %S", iDatabaseName);
+#ifdef LOGGING_ENABLED
+    TEntry entry;
+    if  (iFsSession.Entry(*iDatabaseName, entry) == KErrNone)
+        {
+        LOGTEXT2("CLogServDatabaseMarshall::DatabaseOpenL() - Database file: %S DOES exist", iDatabaseName);        
+        }
+    else
+        {
+        LOGTEXT2("CLogServDatabaseMarshall::DatabaseOpenL() - Database file: %S NOT FOUND", iDatabaseName);     
+        }
+#endif
+    // Open database
+    TInt err = iDatabase.Open(iFsSession, DatabaseName());
+    LOGTEXT2("CLogServDatabaseMarshall::DatabaseOpenL() - attempting to open DMBS database resulted in error: %d", error);
+    // Check if the database is damaged. If it is set the error to KErrCorrupt so that it 
+    // will be deleted.
+    if ((err == KErrNone) && iDatabase.IsDamaged()) 
+        {
+        err =  KErrCorrupt;
+        }
+    return err;
+    }
+
+/**
+Check if the database table count is the expected one -  KExpectedNumberOfTables.
+@return True,   The database tables count is KExpectedNumberOfTables,
+        False,  The database tables count is not KExpectedNumberOfTables;
+@leave  KErrNoMemory, an out of memory condition has occurred;
+                      Note that the function may leave with database specific errors or 
+                      other system-wide error codes.
+*/
+TBool CLogServDatabaseMarshall::DbTableCntCheckL()
+    {
+    CDbTableNames* tables = iDatabase.TableNamesL();
+    TInt numberOfTables = tables->Count();
+    delete tables;
+    LOGTEXT2("CLogServDatabaseMarshall::DatabaseOpenL() - Number of tables: %d", numberOfTables);
+    return numberOfTables == KExpectedNumberOfTables;
+    }
+
+/**
+Alters the "Event" table if the number column length is not KLogMaxNumberLength.
+@return KErrNone, The "alter" operation has completed successfully, system wide or database specific error code otherwise.  
+*/
+TInt CLogServDatabaseMarshall::AlterEventTblIfOldFmt(CDbColSet& aEventTblColSet)
+    {
+    const TDbCol* numberCol = aEventTblColSet.Col(KLogFieldEventNumberString);
+    __ASSERT_DEBUG(numberCol != NULL, User::Invariant());
+    TInt err = KErrNone;
+    // check the column width is correct
+    if(numberCol->iMaxLength != KLogMaxNumberLength)
+        {
+        //The column width is not correct, so this is an old format database.
+        //Modify the database so the number length is KLogMaxNumberLength.
+        (const_cast <TDbCol*> (numberCol))->iMaxLength = KLogMaxNumberLength;
+        err = iDatabase.AlterTable(KLogNameEventString, aEventTblColSet);
+        }
+    return err;
+    }
+
+#ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
+
+/**
+Alters the "Event" table if the the table does not have "SimId" column.
+@return KErrNone, The "alter" operation has completed successfully, system wide or database specific error code otherwise.  
+@leave  KErrNoMemory, an out of memory condition has occurred;
+                      Some other failure codes, not related to the "alter" opertaion.
+*/
+TInt CLogServDatabaseMarshall::AlterEventTblIfNoSimIdL(CDbColSet& aEventTblColSet)
+    {//Compiled only when SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM macro is defined
+    const TDbCol* simIdCol = aEventTblColSet.Col(KLogFieldEventSimId);
+    TInt err = KErrNone;
+    if(!simIdCol)
+        {
+        TDbCol col(KLogFieldEventSimId, EDbColUint32);
+        aEventTblColSet.AddL(col);
+        err = iDatabase.AlterTable(KLogNameEventString, aEventTblColSet);
+        }
+    return err;
+    }
+
+#endif
+
+/**
+Checks the database structure and alters the tables if that's an old format database.
+@return KErrNone, The "alter" operation has completed successfully, system wide or database specific error code otherwise.
+@leave  KErrNoMemory, an out of memory condition has occurred;
+                      Some other failure codes, not related to the "alter" opertaion.
+*/
+TInt CLogServDatabaseMarshall::AlterDbIfOldFmtL()
+    {
+    CDbColSet* tableEventCol = iDatabase.ColSetL(KLogNameEventString);
+    CleanupStack::PushL(tableEventCol);
+    //Check for old format database which had MaxNumberLength =32
+    TInt err = AlterEventTblIfOldFmt(*tableEventCol);
+#ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
+    //Check if the "SimId" column is present
+    if(err == KErrNone)
+        {
+        err = AlterEventTblIfNoSimIdL(*tableEventCol);
+        }
+#endif    
+    CleanupStack::PopAndDestroy(tableEventCol);
+    return err;
+    }
+
+/**
+Closes and deletes the LogEng database. In _DEBUG builds the "delete file" error will be printed out. 
+*/
+void CLogServDatabaseMarshall::DbDelete()
+    {
+    iDatabase.Close();
+#ifdef _DEBUG       
+	//Do not remove the statement bellow. In _DEBUG builds it forms a single "TInt err2 = iFsSession.Delete(DatabaseName());" statement.
+    TInt err2 =
+#endif      
+    iFsSession.Delete(DatabaseName());
+#ifdef _DEBUG
+    if((err2 != KErrNone) && (err2 != KErrNotFound))
+        {
+        RDebug::Print(_L("CLogServDatabaseMarshall::DatabaseOpenL() - Failed to delete file. Error = %d"), err2);
+        }
+#endif
+    }
+
+/**
+Attempts to create the LogEng database and tables.
+@return   KErrNoNone, The database was created successfully, system wide or database specific error otherwise.
+*/
+TInt CLogServDatabaseMarshall::DbCreate()
+    {
+    // Try and create the database
+    LOGTEXT("CLogServDatabaseMarshall::DatabaseOpenL() - trying to create database");
+    TRAPD(err, DatabaseCreateL(DatabaseName()));
+    LOGTEXT2("CLogServDatabaseMarshall::DatabaseOpenL() - creation error was: %d", error);
+    return err;
+    }
+
+/**
+Creates config and string LogEng caches. Finishes the initialization of the event types cache. 
+@leave  KErrNoMemory, an out of memory condition has occurred;
+                      Note that the function may leave with database specific errors or 
+                      other system-wide error codes.
+*/
+void CLogServDatabaseMarshall::CreateCachesL()
+    {
+    // Create other cache objects (these require the database to be already opened)
+    LOGTEXT("CLogServDatabaseMarshall::DatabaseOpenL() - creating config cache");
+    iCacheConfig = CLogServCacheConfig::NewL(*this);
+    LOGTEXT("CLogServDatabaseMarshall::DatabaseOpenL() - creating string cache");
+    iCacheStrings = CLogServCacheStrings::NewL(*this);
+    // Finish the type cache initialization
+    LOGTEXT("CLogServDatabaseMarshall::DatabaseOpenL() - initializing type cache");
+    iCacheTypes->InitializeL();
+    }
+
+void CLogServDatabaseMarshall::DatabaseOpenL()
+	{
+	// Create the cache objects - objects need to be put into the cache as
+	// soon as the database is open.
+	LOGTEXT("CLogServDatabaseMarshall::DatabaseOpenL() - creating type cache");
+	iCacheTypes = CLogServCacheTypes::NewL(*this);
+	TInt err = DoDbOpen();
+	// Check we have the expected number of tables
+	if(err == KErrNone && !DbTableCntCheckL())
+		{
+	    err = KErrCorrupt;
+		}
+    // Check a compaction can be performed. If it can't it indicates a serious problem?
+    if(err == KErrNone && (err = iDatabase.Compact()) != KErrNone)
+       {
+       err = KErrCorrupt;
+       }
+	if(err == KErrNone)
+		{
+		err = CLogServDatabaseMarshall::AlterDbIfOldFmtL();
+		}
+	// If the database failed to open, delete and recreate.
+	if(err == KErrNotFound || err == KErrCorrupt || err == KErrArgument || err == KErrEof)
+		{
+		DbDelete();
+		// Try and create the database
+		err = DbCreate();
+	    if(err != KErrNone)
+	        {
+	        DbDelete();
+	        }
+		}
+	User::LeaveIfError(err);
+	CreateCachesL();
+    // At this point, its safe to tell the backup interface what file it has to watch
+    LOGTEXT("CLogServDatabaseMarshall::DatabaseOpenL() - registering database filename with backup interface");
+    iBackupInterface.BISetDatabaseNameL(DatabaseName());
+	LOGTEXT("CLogServDatabaseMarshall::DatabaseOpenL() - end");
+	}
+
+void CLogServDatabaseMarshall::DatabaseCreateL(const TDesC& aName)
+	{
+	User::LeaveIfError(iDatabase.Replace(iFsSession, aName));
+	CreateTablesL();
+	}
+
+// Note: Number of tables HAS to match KExpectedNumberOfTables
+void CLogServDatabaseMarshall::CreateTablesL()
+	{
+	DTIBeginWithRollBackProtectionLC();
+
+	// Create event table
+	TheSql.Format(KLogTableEventString, KLogMaxRemotePartyLength, KLogMaxSubjectLength, KLogMaxNumberLength);
+	User::LeaveIfError(iDatabase.Execute(TheSql));
+	MakeColumnAutoIncremetingL(KLogNameEventString, KLogFieldIdString);
+
+	// Create event type table
+	TheSql.Format(KLogTableTypeString, KLogMaxDescriptionLength);
+	User::LeaveIfError(iDatabase.Execute(TheSql));
+	MakeColumnAutoIncremetingL(KLogNameTypeString, KLogFieldIdString);
+
+	// Create string list table
+	TheSql.Format(KLogTableStringString, KLogMaxSharedStringLength);
+	User::LeaveIfError(iDatabase.Execute(TheSql));
+	MakeColumnAutoIncremetingL(KLogNameStringString, KLogFieldIdString);
+
+	// Create configuration table
+	TheSql.Copy(KLogTableConfigString);
+	User::LeaveIfError(iDatabase.Execute(TheSql));
+
+	// Create the index
+	CreateIndiciesL();
+
+	// Set the initial configuration
+	CreateConfigurationL();
+
+	// Load standard event types
+	CreateTypesL();
+
+	DTICommitAndCancelRollbackProtectionL();
+	}
+
+void CLogServDatabaseMarshall::CreateTypesL(TBool aReadOnly)
+	{
+	// Get the array size
+	TResourceReader reader;
+	iResourceInterface.CreateResourceReaderLC(reader, R_LOG_INITIAL_EVENTS, CLogServResourceInterpreter::ELogWrap);
+
+	// Create them
+	DTICacheTypes().CreateStandardTypesL(reader, aReadOnly);
+
+	CleanupStack::PopAndDestroy(); // reader
+	}
+
+void CLogServDatabaseMarshall::CreateIndiciesL()
+	{
+	// Get the array size
+	TResourceReader reader;
+	iResourceInterface.CreateResourceReaderLC(reader, R_LOG_INDEXES, CLogServResourceInterpreter::ELogWrap);
+
+	const TInt indexes = reader.ReadInt16();
+
+	// Read in the array
+	for(TInt c1 = 0; c1 < indexes; c1++)
+		{
+		const TPtrC name(reader.ReadTPtrC());
+		const TPtrC table(reader.ReadTPtrC());
+
+		// Get the number of keys
+		const TInt keys = reader.ReadInt16();
+
+		CDbKey* key = CDbKey::NewLC();
+
+		for(TInt c2 = 0; c2 < keys; c2++)
+			{
+			TPtrC col = reader.ReadTPtrC();
+			TUint order = reader.ReadUint16();
+			TInt len = reader.ReadInt16();
+
+			// Add the key
+			key->AddL(TDbKeyCol(col, len, (TDbKeyCol::TOrder)order));
+			}
+
+		// Make key unique if required
+		if (reader.ReadInt8())
+			key->MakeUnique();
+
+		// Set comparison
+		const TDbTextComparison comparison = static_cast<TDbTextComparison>(reader.ReadInt8());
+		key->SetComparison(comparison);
+
+		// Create the index
+		User::LeaveIfError(iDatabase.CreateIndex(name, table, *key));
+
+		CleanupStack::PopAndDestroy(key);
+		}
+
+	CleanupStack::PopAndDestroy(); // reader
+	}
+
+void CLogServDatabaseMarshall::CreateConfigurationL()
+	{
+	// Load the resource/repository file default configuration
+	// The precedence is given to the reading from the repository file.
+   	TLogConfig config;
+	
+	CRepository* repository = NULL;
+	TRAPD(res, repository = CRepository::NewL(KUidLogengRepository));		
+	if (res == KErrNone)
+		{
+		CleanupStack::PushL(repository);
+		ReadRepositoryFileConfigurationL(config, *repository);
+		CleanupStack::PopAndDestroy(repository);
+		}
+	else if (res == KErrCorrupt)
+		{
+		User::Leave(res);
+		}
+	else
+		{
+		ReadResourceFileConfigurationL(config);
+		}	
+   	// Insert the column
+   	TheSql.Format(KLogSqlInsertConfigString, config.iMaxLogSize, config.iMaxRecentLogSize, config.iMaxEventAge);
+	User::LeaveIfError(iDatabase.Execute(TheSql));
+	}
+
+void CLogServDatabaseMarshall::ReadRepositoryFileConfigurationL(TLogConfig& aConfig, CRepository& repository) const
+	{
+	TInt maxLogSize;
+	TInt maxRecentLogSize;
+	TInt maxEventAge;
+	//	
+	User::LeaveIfError(repository.Get(KMaxLogSizeRepKey, maxLogSize));
+	aConfig.iMaxLogSize = static_cast<TLogSize> (maxLogSize);
+	User::LeaveIfError(repository.Get(KMaxRecentLogSizeRepKey, maxRecentLogSize));
+	aConfig.iMaxRecentLogSize = static_cast<TLogRecentSize> (maxRecentLogSize);
+	User::LeaveIfError(repository.Get(KMaxEventAgeRepKey, maxEventAge));
+	aConfig.iMaxEventAge = static_cast<TLogAge> (maxEventAge);	
+	}
+
+void CLogServDatabaseMarshall::ReadResourceFileConfigurationL(TLogConfig& aConfig) const
+	{	
+	TResourceReader reader;
+	iResourceInterface.CreateResourceReaderLC(reader, R_LOG_INITIAL_CONFIG, CLogServResourceInterpreter::ELogWrap);
+	//
+	aConfig.iMaxLogSize = static_cast<TLogSize>(reader.ReadUint16());
+	aConfig.iMaxRecentLogSize = static_cast<TLogRecentSize>(reader.ReadUint8());
+	aConfig.iMaxEventAge = static_cast<TLogAge>(reader.ReadUint32());
+	//
+	CleanupStack::PopAndDestroy(); // reader	
+	}
+
+void CLogServDatabaseMarshall::MakeColumnAutoIncremetingL(const TDesC& aTable, const TDesC& aColumn)
+	{
+	CDbColSet* newTable = iDatabase.ColSetL(aTable);
+	CleanupStack::PushL(newTable);
+
+	const TDbCol* oldCol = newTable->Col(aColumn);
+	__ASSERT_DEBUG(oldCol != NULL, Panic(ELogNoSuchColumn));
+
+	TDbCol newCol = *oldCol;
+	newCol.iAttributes |= TDbCol::EAutoIncrement;
+
+	newTable->Remove(aColumn);
+	newTable->AddL(newCol);
+
+	User::LeaveIfError(iDatabase.DropTable(aTable));
+	User::LeaveIfError(iDatabase.CreateTable(aTable, *newTable));
+		
+	CleanupStack::PopAndDestroy(newTable);
+	}
+