--- /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<CDbTableDef> 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<end);
+ }
+
+//
+// List the indexes on a table
+//
+void CDbTableDatabase::CInterface::IndexesL(CDbIndexNames& aNames,const TDesC& aTable)
+ {
+ TSglQueIterC<CDbTableIndexDef> 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;ii<max;++ii)
+ aKey.AddL(key[ii]);
+ if (key.IsUnique())
+ aKey.MakeUnique();
+ if (key.IsPrimary())
+ aKey.MakePrimary();
+ aKey.SetComparison(key.Comparison());
+ }
+
+// Class CDbTableDatabase::CSource
+
+//
+// ctor. Add a reference to the database engine
+//
+CDbTableDatabase::CSource::CSource(CDbTableDatabase& aDatabase)
+ :iDatabase(aDatabase)
+ {
+ aDatabase.Open();
+ }
+
+//
+// dtor. remove our reference from the database engine
+//
+CDbTableDatabase::CSource::~CSource()
+ {
+ Database().Close();
+ }
+
+
+//SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method
+CDbDatabase* CDbTableDatabase::CSource::AuthenticateL()
+ {
+ Database().AuthenticateL();
+ return Database().InterfaceL();
+ }
+
+
+CDbNotifier* CDbTableDatabase::CSource::OpenNotifierL()
+ {
+ return Database().Transaction().NotifierL();
+ }
+
+// Class CDbTableDatabase
+
+EXPORT_C CDbTableDatabase::CDbTableDatabase()
+ {
+ iCache.Open();
+ iTransaction.Open(*this);
+ }
+
+EXPORT_C CDbTableDatabase::~CDbTableDatabase()
+ {
+ __ASSERT(iRef==0);
+ iTransaction.Close();
+ iTables.Close();
+ iSchema.Close();
+ iCache.Close();
+ }
+
+void CDbTableDatabase::Close()
+ {
+ __ASSERT(iRef>0);
+ 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<CDbTable> 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<CDbTable> iter(iTables);
+ for (CDbTable* table;(table=iter++)!=0;)
+ table->FlushL();
+ }
+ }
+
+void CDbTableDatabase::Abandon(TDbLockType aLock)
+ {
+ if (aLock>=EDbWriteLock)
+ {
+ TSglQueIter<CDbTable> 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<CDbTable> 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<CDbTable> 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()
+ {
+ }