persistentstorage/dbms/utable/UT_DBS.CPP
changeset 0 08ec8eefde2f
child 55 44f437012c90
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/dbms/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"
+
+// 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()
+	{
+    }