diff -r 000000000000 -r 08ec8eefde2f persistentstorage/dbms/pcdbms/utable/UT_DBS.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/dbms/pcdbms/utable/UT_DBS.CPP Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,568 @@ +// 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" +#include "U32STD_DBMS.H" +// Class CDbTableDatabase::CInterface + +// +// ctor. Add the initial reference to the database engine +// +CDbTableDatabase::CInterface::CInterface(CDbTableDatabase& aDatabase) + :iDatabase(aDatabase) + { + aDatabase.Open(); + } + +// +// dtor. remove our reference from the database engine +// +CDbTableDatabase::CInterface::~CInterface() + { + if (Database().Transaction().InTransaction(*this)) + Rollback(); // release the lock if we have it + Database().Close(); + } + +void CDbTableDatabase::CInterface::PrepareDDLL() + { + Database().Transaction().DDLPrepareL(*this); + } + +// +// destroy the database (database must be empty) +// +TInt CDbTableDatabase::CInterface::Destroy() + { + __ASSERT(Database().Schema().IsEmpty()); + TRAPD(r,Database().DestroyL()); + return r; + } + +// +// Initiate a transaction on the database +// +TInt CDbTableDatabase::CInterface::Begin() + { + TRAPD(r,Database().Transaction().BeginL(*this)); + return r; + } + +// +// Commit a transaction on the database +// +TInt CDbTableDatabase::CInterface::Commit() + { + TRAPD(r,Database().Transaction().CommitL(*this)); + return r; + } + +// +// Rollback a failed transaction on the database +// +void CDbTableDatabase::CInterface::Rollback() + { + Database().Transaction().Rollback(*this); + } + +// +// Report a requested property +// +TInt CDbTableDatabase::CInterface::Property(CDbDatabase::TProperty aProperty) + { + if (aProperty==EInTransaction) + return Database().Transaction().InTransaction(*this) ? 1 : 0; +// + return Database().Property(aProperty); + } + +void CDbTableDatabase::CInterface::CreateTableL(const TDesC& aName,const CDbColSet& aColSet,const CDbKey* aPrimaryKey) + { + PrepareDDLL(); + Database().DoCreateTableL(aName,aColSet,aPrimaryKey); + } + +CDbCursor* CDbTableDatabase::CInterface::PrepareViewL(const TDbQuery& aQuery,const TDbWindow& aWindow,RDbRowSet::TAccess anAccess) + { + return Database().PrepareViewL(aQuery,aWindow,anAccess); + } + +CDbCursor* CDbTableDatabase::CInterface::OpenTableL(const TDesC& aName,RDbRowSet::TAccess anAccess) + { + return Database().PrepareTableL(aName,anAccess); + } + +CDbIncremental* CDbTableDatabase::CInterface::OpenDropTableL(const TDesC& aTable,TInt& aStep) + { + PrepareDDLL(); + return Database().OpenDropTableL(aTable,aStep); + } + +CDbIncremental* CDbTableDatabase::CInterface::OpenAlterTableL(const TDesC& aTable,const CDbColSet& aNewDef,TInt& aStep) + { + PrepareDDLL(); + return Database().OpenAlterTableL(aTable,aNewDef,aStep); + } + +CDbIncremental* CDbTableDatabase::CInterface::OpenCreateIndexL(const TDesC& aName,const TDesC& aTable,const CDbKey& aKey,TInt& aStep) + { + PrepareDDLL(); + return Database().OpenCreateIndexL(aName,aTable,aKey,aStep); + } + +CDbIncremental* CDbTableDatabase::CInterface::OpenDropIndexL(const TDesC& aName,const TDesC& aTable,TInt& aStep) + { + PrepareDDLL(); + return Database().OpenDropIndexL(aName,aTable,aStep); + } + +// +// Create a database utility. Check the corresponding property to see if it is viable +// +CDbIncremental* CDbTableDatabase::CInterface::OpenUtilityL(CDbDatabase::TUtility aType,TInt& aStep) + { + if (!Property(TProperty(-aType))) + { // nothing to do, or not capable + aStep=0; + return 0; + } + RDbTransaction& t=Database().Transaction(); + t.UtilityPrepareL(*this); + if (aType==ERecover) + Database().Release(); // must not have any tables open during recovery + return CUtility::NewL(t,aType,aStep); + } + +CDbIncremental* CDbTableDatabase::CInterface::OpenExecuteL(const TDesC& aSql,TDbTextComparison aComparison,TInt& aInit) + { + switch (Sql::Type(aSql)) + { + default: + __ASSERT(0); + case Sql::ENone: + __LEAVE(KErrArgument); + case Sql::EDDL: + { + CDbIncremental* inc=Sql::ParseDDLStatementLC(aSql)->ExecuteL(*this,aComparison,aInit); + CleanupStack::PopAndDestroy(); // statement + return inc; + } + case Sql::EDML: + { + CSqlDMLStatement* statement=Sql::ParseDMLStatementLC(aSql); + RDbTransaction& t=Database().Transaction(); + t.DMLCheckL(); // ensure we can open a cursor + t.DMLPrepareL(*this); + CDbIncremental* inc=statement->ExecuteL(Database(),aComparison,aInit); + CleanupStack::PopAndDestroy(); // statement + return inc; + } + } + } + +// +// Open a client-side notifier object +// +CDbNotifier* CDbTableDatabase::CInterface::OpenNotifierL() + { + return Database().Transaction().NotifierL(); + } + +// +// list the tables on the database +// +void CDbTableDatabase::CInterface::TablesL(CDbTableNames& aNames) + { + TSglQueIterC iter(Database().SchemaL()); + for (const CDbTableDef* def;(def=iter++)!=0;) + aNames.AddL(def->Name()); + } + +// +// build a column set for the table +// +void CDbTableDatabase::CInterface::ColumnsL(CDbColSet& aColSet,const TDesC& aName) + { + TDbCol col; + const HDbColumnSet& set=Database().SchemaL().FindL(aName).Columns(); + HDbColumnSet::TIteratorC iter=set.Begin(); + const HDbColumnSet::TIteratorC end=set.End(); + do + { + iter->AsTDbCol(col); + aColSet.AddL(col); + } while (++iter iter(Database().SchemaL().FindL(aTable).Indexes().AsQue()); + for (const CDbTableIndexDef* def;(def=iter++)!=0;) + aNames.AddL(def->Name()); + } + +// +// build a key for the index +// +void CDbTableDatabase::CInterface::KeysL(CDbKey& aKey,const TDesC& aName,const TDesC& aTable) + { + const CDbKey& key=Database().SchemaL().FindL(aTable).Indexes().FindL(aName).Key(); + TInt max=key.Count(); + for (TInt ii=0;ii0); + if (--iRef==0) + delete this; + } + +// +// Construct the implementation interface for the database framework +// On success, the interface takes an owning reference to this +// +EXPORT_C CDbDatabase* CDbTableDatabase::InterfaceL() + { + return new(ELeave) CInterface(*this); + } + +// +// Construct the implementation interface for the database framework +// On success, the interface takes an owning reference to this +// +EXPORT_C CDbSource* CDbTableDatabase::SourceL() + { + return new(ELeave) CSource(*this); + } + +// +// Load the schema if required +// +EXPORT_C RDbTableSchema& CDbTableDatabase::SchemaL() + { + RDbTableSchema& schema=Schema(); + if (!schema.IsLoaded()) + { + schema.Discard(); + LoadSchemaL(); + schema.Loaded(); + } + return schema; + } + +// +// Find any tables which are now idle, and cache them +// Caching such a table can result in *any* table being deleted +// and so the iteration must restart every time an idle table is cached +// +void CDbTableDatabase::CheckIdle() + { + while (!iTables.IsEmpty()) + { + for (TSglQueIter iter(iTables);;) + { + CDbTable* table=iter++; + if (table==0) // no more idle tables + return; + if (table->IsIdle()) + { // idle->cache transition can modify the collection + table->Idle(); + break; + } + } + } + // If there are no tables left open, then the database can go idle + Idle(); + } + +// +// Does nothing by default +// +EXPORT_C void CDbTableDatabase::Idle() + { + } + +// +// default implementation +// +EXPORT_C TInt CDbTableDatabase::Property(CDbDatabase::TProperty aProperty) + { + if (aProperty<0) + return 0; // utilities are not available with table database + __ASSERT(aProperty!=CDbDatabase::EInTransaction); + return KErrNotSupported; + } + +// +// default implementation, should never be invoked +// +EXPORT_C CDbTableDatabase::CStepper* CDbTableDatabase::UtilityL(CDbDatabase::TUtility,TInt&) + { + __ASSERT(0); + return 0; + } + +void CDbTableDatabase::FlushL(TDbLockType aLock) + { + if (aLock>=EDbWriteLock) + { + TSglQueIter iter(iTables); + for (CDbTable* table;(table=iter++)!=0;) + table->FlushL(); + } + } + +void CDbTableDatabase::Abandon(TDbLockType aLock) + { + if (aLock>=EDbWriteLock) + { + TSglQueIter iter(iTables); + for (CDbTable* table;(table=iter++)!=0;) + table->Abandon(); + } + if (aLock==EDbSchemaLock) + { + Release(); // ensure no-one is using the old schema + Schema().Discard(); + } + } + +// +// Discard a table if it is using this definition +// +void CDbTableDatabase::Release(const CDbTableDef& aDef) + { + TSglQueIter iter(iTables); + for (CDbTable* table;(table=iter++)!=0;) + { + if (&table->Def()==&aDef) + { + table->Release(); + break; + } + } + } + +// +// Discard all open tables as the schema has been modified or discarded +// +void CDbTableDatabase::Release() + { + TSglQueIter iter(iTables); + for (CDbTable* table;(table=iter++)!=0;) + table->Release(); + } + +// +// Remove a table from the open set +// +void CDbTableDatabase::RemoveTable(CDbTable& aTable) + { + iTables.Remove(aTable); + if (!Transaction().IsLocked() && iTables.IsEmpty()) + Idle(); + } + +CDbTableSource* CDbTableDatabase::TableSourceL(const TDesC& aTableName) + { + CDbTableSource* rec=new(ELeave) CDbTableSource; + CDbTable* table=iTables.Find(aTableName); + if (table) + table->Open(); // a new reference to it + else + { + CleanupStack::PushL(rec); + table=TableL(SchemaL().FindL(aTableName)); + CleanupStack::Pop(); // table source + } + rec->Construct(table); + iCache.Flush(); // check-point for object cache membership + return rec; + } + +// +// Prepare the data pipeline +// +CDbCursor* CDbTableDatabase::PrepareViewL(const TDbQuery& aQuery,const TDbWindow& aWindow,RDbRowSet::TAccess aAccess) + { + Transaction().DMLCheckL(); // ensure we can open a cursor + CSqlQuery *query=Sql::ParseQueryLC(aQuery.Query()); + RDbAccessPlan plan(query,aQuery.Comparison()); + plan.BuildLC(*this,aAccess,aWindow); + CDbTableCursor* cursor=CDbTableCursor::NewL(plan,aAccess); + CleanupStack::Pop(); // the plan + CleanupStack::PopAndDestroy(); // the query + return cursor; + } + +// +// Prepare the data pipeline +// +CDbCursor* CDbTableDatabase::PrepareTableL(const TDesC& aTable,RDbRowSet::TAccess aAccess) + { + Transaction().DMLCheckL(); // ensure we can open a cursor + RDbAccessPlan plan; + plan.BuildLC(*this,aTable,aAccess); + CDbTableCursor* cursor=CDbTableCursor::NewL(plan,aAccess); + CleanupStack::Pop(); // the plan + return cursor; + } + +void CDbTableDatabase::DoCreateTableL(const TDesC& aName,const CDbColSet& aColSet,const CDbKey* aPrimaryKey) + { + if (SchemaL().Find(aName)) + __LEAVE(KErrAlreadyExists); +// validate the colset set passed in + Validate::NameL(aName); + Validate::ColSetL(aColSet); + Transaction().DDLBeginLC(); + iSchema.Add(CreateTableL(aName,aColSet,aPrimaryKey)); + Transaction().DDLCommitL(); + CleanupStack::Pop(); // rollback not required + } + +// +// Create index definition and prepare to build it +// +CDbTableDatabase::CIncremental* CDbTableDatabase::OpenCreateIndexL(const TDesC& aName,const TDesC& aTable,const CDbKey& aKey,TInt& aStep) + { + CDbTableDef& tDef=SchemaL().FindL(aTable); + RDbIndexes& indexes=tDef.Indexes(); + if (indexes.Find(aName)!=NULL) + __LEAVE(KErrAlreadyExists); + if (indexes.Count()==KDbTableMaxIndexes) + __LEAVE(KErrNotSupported); + Validate::NameL(aName); + Validate::KeyL(aKey,tDef.Columns()); + if (aKey.IsPrimary()) + __LEAVE(KErrArgument); // cannot create a primary index + + CCreateIndex* builder=CCreateIndex::NewLC(Transaction()); + CDbTableIndexDef* xDef=CreateIndexL(tDef,aName,aKey); + tDef.Indexes().Add(xDef); + Release(tDef); // release any table using the old schema + aStep=builder->ConstructL(tDef,*xDef); + CleanupStack::Pop(); // builder + return builder; + } + +// +// Remove index from schema first, then remove index data +// +CDbTableDatabase::CIncremental* CDbTableDatabase::OpenDropIndexL(const TDesC& aName,const TDesC& aTable,TInt& aStep) + { + CDbTableDef& tDef=SchemaL().FindL(aTable); + CDbTableIndexDef& xDef=tDef.Indexes().FindL(aName); +// + Release(tDef); // release any table using the old schema + CDropIndex* drop=CDropIndex::NewL(Transaction(),tDef,&xDef,aStep); + tDef.Indexes().Remove(&xDef); + return drop; + } + +CDbTableDatabase::CIncremental* CDbTableDatabase::OpenDropTableL(const TDesC& aTable,TInt& aStep) + { + CDbTableDef& tDef=SchemaL().FindL(aTable); +// + Release(tDef); // release the tables using the old schema + CDropTable* drop=CDropTable::NewL(Transaction(),&tDef,aStep); + iSchema.Remove(&tDef); + return drop; + } + +// +// Create an incremental table altering object +// +CDbTableDatabase::CIncremental* CDbTableDatabase::OpenAlterTableL(const TDesC& aTable,const CDbColSet& aNewDef,TInt& aStep) + { + CDbTableDef& tDef=SchemaL().FindL(aTable); + Validate::ColSetL(aNewDef); + Release(tDef); // release the tables using the old schema + return CAlterTable::NewL(Transaction(),tDef,aNewDef,aStep); + } + +// +// Reserved for future development +// +EXPORT_C void CDbTableDatabase::Reserved_1() + { + } + +// +// Reserved for future development +// +EXPORT_C void CDbTableDatabase::Reserved_2() + { + }