persistentstorage/dbms/utable/UT_INCR.CPP
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/dbms/utable/UT_INCR.CPP	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,374 @@
+// 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 "UT_STD.H"
+
+// Class CDbTableDatabase::CMultiStepper
+
+inline CDbTableDatabase::CMultiStepper::CMultiStepper( TInt aCount )
+ :	iStepper( iSteppers - 1 ), iEnd( iSteppers + aCount )
+	{}
+
+CDbTableDatabase::CMultiStepper::~CMultiStepper()
+	{
+	SStepper* const end = iEnd;
+	for ( SStepper* iter = iSteppers; iter < end; ++iter )
+		delete iter->iStepper;
+	}
+
+EXPORT_C CDbTableDatabase::CMultiStepper* CDbTableDatabase::CMultiStepper::NewL( TInt aStepperCount )
+	{
+	return new( ELeave, sizeof( SStepper ) * ( aStepperCount - 1 ) ) CMultiStepper( aStepperCount );	// get the extra size for the entries, leaves on error
+	}
+
+EXPORT_C void CDbTableDatabase::CMultiStepper::AddStepper( CStepper* aStepper, TInt aStep )
+	{
+	++iStepper;
+	__ASSERT( iStepper < iEnd );
+	iStepper->iStepper = aStepper;
+	iStepper->iStep = aStep;
+	}
+
+EXPORT_C TInt CDbTableDatabase::CMultiStepper::TotalSteps()
+//
+// Count the number of steps, and normalise the step counts
+//
+	{
+	TInt steps = 0;
+	SStepper* const end = iStepper;
+	for( SStepper* stepper = iSteppers; stepper <= end; ++stepper )
+		{
+		TInt step = stepper->iStep;
+		stepper->iStep = steps;
+		steps += step;
+		}
+	return steps;
+	}
+
+TInt CDbTableDatabase::CMultiStepper::StepL( TInt aStep )
+	{
+	SStepper* stepper = iStepper;
+	__ASSERT( stepper != 0 && stepper >= iSteppers );
+	TInt base;
+	for ( ; ; )
+		{
+		base = stepper->iStep;
+		if ( aStep > base )
+			break;
+		if ( --stepper < iSteppers )
+			return 0;
+		iStepper = stepper;
+		}
+	return stepper->iStepper->StepL( aStep - base ) + base;
+	}
+
+// Class CDbTableDatabase::CIncremental
+
+CDbTableDatabase::CIncremental::CIncremental(RDbTransaction& aTransaction)
+	: iTransaction(aTransaction)
+	{
+	Database().Open();		// we reference the database
+	__ASSERT(iState==ERunning);
+	}
+
+CDbTableDatabase::CIncremental::~CIncremental()
+	{
+	delete iStepper;
+	Database().Close();		// drop the database reference
+	}
+
+TBool CDbTableDatabase::CIncremental::NextL(TInt& aStep)
+//
+// if step is 1 then invopke the last step otherwise do
+//
+	{
+	__ASSERT(!IsCommitted());
+	if (iState==EFailed)
+		__LEAVE(KErrDied);
+	iState=EFailed;
+	if (aStep!=ELastStep)
+		{
+		aStep=DoNextL(aStep);
+		iState=ERunning;
+		}
+	else
+		{
+		DoLastL();
+		aStep=0;
+		iState=ECommitted;
+		}
+	return 0;	// return 0 for DDL incremental operations
+	}
+
+TInt CDbTableDatabase::CIncremental::DoNextL(TInt aStep)
+//
+// default use of stepper object (re-normalised the step count)
+//
+	{
+	return iStepper->StepL(aStep-ELastStep)+ELastStep;
+	}
+
+// Class CDbTableDatabase::CIncrementalDDL
+
+CDbTableDatabase::CIncrementalDDL::CIncrementalDDL(RDbTransaction& aTransaction)
+	: CIncremental(aTransaction)
+	{
+	Transaction().DDLBegin();
+	}
+
+CDbTableDatabase::CIncrementalDDL::~CIncrementalDDL()
+	{
+	if (!IsCommitted())
+		Transaction().DDLRollback();
+	}
+
+void CDbTableDatabase::CIncrementalDDL::DoLastL()
+	{
+	Transaction().DDLCommitL();
+	}
+
+// Class CDbTableDatabase::CBuildIndex
+
+EXPORT_C CDbTableDatabase::CBuildIndex* CDbTableDatabase::CBuildIndex::NewL(CDbTableDatabase& aDatabase,const CDbTableDef& aTable,const CDbTableIndexDef& anIndex)
+	{
+	CBuildIndex* self=new(ELeave) CBuildIndex();
+	CleanupStack::PushL(self);
+	CDbTableSource* source=self->iSource=aDatabase.TableSourceL(aTable.Name());
+	CDbTable& table=source->Table();
+	source->SetIterator(table.IteratorL());
+	self->iIndex=table.RecordIndexL(anIndex);
+	self->iIndex->OpenL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CDbTableDatabase::CBuildIndex::CBuildIndex()
+	: iNext(EDbFirst)
+	{}
+
+CDbTableDatabase::CBuildIndex::~CBuildIndex()
+	{
+	delete iIndex;
+	delete iSource;
+	}
+
+EXPORT_C TInt CDbTableDatabase::CBuildIndex::Steps(TInt aCardinality)
+	{
+	return aCardinality+1;
+	}
+
+EXPORT_C TInt CDbTableDatabase::CBuildIndex::StepsL()
+	{
+	return Steps(iSource->CountL());
+	}
+
+TInt CDbTableDatabase::CBuildIndex::StepL(TInt aStep)
+//
+// One step on an incremental index build
+//
+	{
+	for (TInt inc=1;;++inc)
+		{
+		TDbRecordId id;
+		if (iSource->CDbDataSource::GotoL(iNext,id)!=CDbDataSource::ESuccess)
+			break;	// run out of data
+		iSource->ReadRowL(id);
+		if (!iIndex->InsertL(id,iSource->Row()))
+			__LEAVE(KErrAlreadyExists);		// duplicate key - fail
+		iNext=EDbNext;
+		if (inc==ERecordsPerStep)
+			return Max(aStep-inc,1);
+		}
+	iIndex->FlushL();
+	return 0;
+	}
+
+// Class CDbTableDatabase::CCreateIndex
+
+CDbTableDatabase::CCreateIndex* CDbTableDatabase::CCreateIndex::NewLC(RDbTransaction& aTransaction)
+	{
+	CCreateIndex* self=new(ELeave) CCreateIndex(aTransaction);
+	CleanupStack::PushL(self);
+	return self;
+	}
+
+TInt CDbTableDatabase::CCreateIndex::ConstructL(const CDbTableDef& aTable,const CDbTableIndexDef& anIndex)
+	{
+	CBuildIndex* builder=CBuildIndex::NewL(Database(),aTable,anIndex);
+	Construct(builder);
+	return builder->StepsL();
+	}
+
+// Class CDbTableDatabase::CDropIndex
+
+CDbTableDatabase::CDropIndex::~CDropIndex()
+	{
+	delete iDef;
+	}
+
+CDbTableDatabase::CDropIndex* CDbTableDatabase::CDropIndex::NewL(RDbTransaction& aTransaction,const CDbTableDef& aTable,CDbTableIndexDef* anIndex,TInt& aStep)
+	{
+	CDropIndex* self=new(ELeave) CDropIndex(aTransaction);
+	CleanupStack::PushL(self);
+	self->Construct(aTransaction.Database().IndexDiscarderL(aTable,*anIndex,aStep));
+	self->iDef=anIndex;
+	aStep+=ELastStep;
+	CleanupStack::Pop();
+	return self;
+	}
+
+// Class CDbTableDatabase::CDropTable
+
+CDbTableDatabase::CDropTable::~CDropTable()
+	{
+	Database().Release(*iDef);		// discard the table using this definition
+	delete iDef;
+	}
+
+CDbTableDatabase::CDropTable* CDbTableDatabase::CDropTable::NewL(RDbTransaction& aTransaction,CDbTableDef* aTable,TInt& aStep)
+	{
+	CDropTable* self=new(ELeave) CDropTable(aTransaction);
+	CDbTableDatabase& database=aTransaction.Database();
+	CleanupStack::PushL(self);
+	CMultiStepper* mstepper=CMultiStepper::NewL(aTable->Indexes().Count()+1);
+	self->Construct(mstepper);
+	CStepper* stepper=database.RecordDiscarderL(*aTable,aStep);
+	mstepper->AddStepper(stepper,aStep);
+	TSglQueIterC<CDbTableIndexDef> iter(aTable->Indexes().AsQue());
+	for (const CDbTableIndexDef* xDef;(xDef=iter++)!=0;)
+		{
+		stepper=database.IndexDiscarderL(*aTable,*xDef,aStep);
+		mstepper->AddStepper(stepper,aStep);
+		}
+	aStep=mstepper->TotalSteps()+ELastStep;
+	self->iDef=aTable;
+	CleanupStack::Pop();
+	return self;
+	}
+
+// Class CDbTableDatabase::CAlterTable
+
+CDbTableDatabase::CAlterTable::~CAlterTable()
+	{
+	delete iNewSet;
+	}
+
+void CDbTableDatabase::CAlterTable::ConstructL(const CDbColSet& aNewDef,TInt& aStep)
+//
+// get all the deleted columns
+// check changes to columns still present
+// get all the new columns
+// construct a new columns set based on the changes
+//
+	{
+//
+// flag all columns as dropped initially
+	HDbColumnSet& columns=iDef.Columns();
+	HDbColumnSet::TIterator iter=columns.Begin();
+	HDbColumnSet::TIteratorC const end=columns.End();
+	do
+		{
+		iter->iFlags=TDbColumnDef::EDropped;
+		} while (++iter<end);
+//
+// look for additions and changes
+	CDbColSet* change=CDbColSet::NewLC();
+	CDbColSet* add=CDbColSet::NewLC();
+	for (TDbColSetIter iterNew(aNewDef);iterNew;++iterNew)
+		{
+		const TDbCol& col=*iterNew;
+		TDbColumnDef* def=columns.ColumnL(iterNew->iName);
+		if (!def)	// a new column
+			add->AddL(col);
+		else
+			{	// see if the definition has changed
+			if (def->iAttributes!=col.iAttributes)
+				__LEAVE(KErrArgument);		// can't change attributes
+			TUint8 flag=0;
+			if (def->iType!=col.iType)
+				flag=TDbColumnDef::EChangedType;
+			else if (def->iType>=EDbColText8 && col.iMaxLength!=KDbUndefinedLength && col.iMaxLength!=def->iMaxLength)
+				flag=TDbColumnDef::EChangedLen;
+			def->iFlags=flag;
+			if (flag)
+				change->AddL(col);	// column has changed
+			}
+		}
+//
+// check that all marked columns are not indexed
+//
+	iter=columns.Begin();
+	do
+		{
+		if (iter->iFlags && iDef.IsIndexed(*iter->iName))
+			__LEAVE(KErrArgument);		// can't remove indexed column
+		} while (++iter<end);
+//
+	iNewSet=HDbColumnSet::NewL(aNewDef.Count());
+	iDef.AlteredColumnSetL(*iNewSet,*change,*add);
+	CleanupStack::PopAndDestroy(2);	// add, change
+	Construct(Database().TableAlterL(iDef,*iNewSet,aStep));
+	}
+
+CDbTableDatabase::CAlterTable* CDbTableDatabase::CAlterTable::NewL(RDbTransaction& aTransaction,CDbTableDef& aTable,const CDbColSet& aNewDef,TInt& aStep)
+//
+// Check the validity of the new definition before asking the implentation to provide
+// the incremental class
+//
+	{
+	CAlterTable* self=new(ELeave) CAlterTable(aTransaction,aTable);
+	CleanupStack::PushL(self);
+	self->ConstructL(aNewDef,aStep);
+	aStep+=ELastStep;
+	CleanupStack::Pop();
+	return self;
+	}
+
+void CDbTableDatabase::CAlterTable::DoLastL()
+//
+// last step is to change the definition
+//
+	{
+	iDef.ExchangeColumnSet(iNewSet);
+	iNewSet=0;
+	CIncrementalDDL::DoLastL();
+	}
+
+// Class CDbTableDatabase::CUtility
+
+inline CDbTableDatabase::CUtility::CUtility(RDbTransaction& aTransaction,CDbDatabase::TUtility aType)
+	: CIncremental(aTransaction)
+	{Transaction().UtilityBegin(aType);}
+
+CDbTableDatabase::CUtility::~CUtility()
+	{
+	if (!IsCommitted())
+		Transaction().UtilityRollback();
+	}
+
+CDbTableDatabase::CUtility* CDbTableDatabase::CUtility::NewL(RDbTransaction& aTransaction,CDbDatabase::TUtility aType,TInt& aStep)
+	{
+	CUtility* self=new(ELeave) CUtility(aTransaction,aType);
+	CleanupStack::PushL(self);
+	self->Construct(aTransaction.Database().UtilityL(aType,aStep));
+	aStep+=ELastStep;
+	CleanupStack::Pop();
+	return self;
+	}
+
+void CDbTableDatabase::CUtility::DoLastL()
+	{
+	Transaction().UtilityCommitL();
+	}