persistentstorage/dbms/sdbms/SD_SESS.CPP
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/dbms/sdbms/SD_SESS.CPP	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,1056 @@
+// 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:
+// DBMS server-session and support classes
+// 
+//
+
+#include <s32file.h>
+#include "SD_STD.H"
+#include "Sd_DbList.h"
+
+using namespace DBSC;
+
+/*
+CDbsSession class is updated now to with a support for DBMS security policies.
+What idea sits behind the update:
+1) DBMS server has a set of server side CDbsSession objects.
+2) Each CDbsSession object has a list of CDbsSession::TEntry items.
+   Each CDbsSession::TEntry item holds a server side DBMS object, which is
+   used to perform client requests.
+3) CDbsSession::TEntry object could be:
+	- EDbsDatabase - database object. It operates at database level.
+		OpenDatabaseL is the method, which creates it.
+	- EDbsIncremental - incremental object. It operates either at database or table level.
+		NewIncrementalL is the method, which creates it.
+	- EDbsCursor - cursor object. It operates at table level.
+		NewCursorL is the method, which creates it.
+	- EDbsConstraint - constraint object. It is used at table level and needs the same
+		security policy as its table.
+	- EDbsStream - stream object. It operates either at database or table level.
+		NewStreamL are the methods, which create it.
+	- EDbsObserver - observer object. It operates at database level.
+4) When DBMS server is used in a security environment, database/table security policies 
+	describe allowed W/R operations for the database/tables.
+5) Each database/table has a security policy object assiciated with it. It may be accessed
+	using MPolicy interface.
+6) There is a MPolicySpace interface, which holds a collection of MPolicy interfaces
+	for the database/tables. MPolicy interfaces can be queried using MPolicySpace methods.
+7) All DBMS server side objects, described in (3), operate at database/table level. In a
+	security environment, the client's access rights has to be checked, before performing
+	particular database/table operation.
+	It is known at the moment of DBMS object creation, on which database/table it will operate.
+	The database/table cannot be changed during the DBMS object life time.
+	At the moment of DBMS object creation, the related database/table interface is queried and
+	stored in CDbsSession::TEntry::iPolicy data member. 
+	It is an error if CDbsSession::TEntry item exists without a security policy.
+8) Every time, when a client needs particular DBMS server functionality and CDbsSession::ServiceL
+	has been called, the session object will find which DBMS server object has to be used and
+	asserts client's access rights against its security policy.
+	If the client has not enough access rights to perform desired DBMS operation, the DBMS
+	session will leave with KErrPermissionDenied error code.
+	======================================================================================
+	In one sentence - every time, when an object from CDbsSession::TEntry list is about to 
+	perform particular operation at database/table level, the associated database/table 
+	security policy will be checked and the opration may be rejected.
+*/
+
+// Class CDbsSession::TEntry
+
+//
+// release the object
+//
+void CDbsSession::TEntry::Release()
+	{
+	TDbsType t=Type();
+	__ASSERT(t!=EDbsFree);
+	if (t==EDbsObserver)
+		delete STATIC_CAST(CDbsObserver::HObserver*,iObject);
+	else if (t==EDbsStream)
+		delete STATIC_CAST(HDbsStream*,iObject);
+	else
+		CDbObject::Destroy(STATIC_CAST(CDbObject*,iObject));
+	iType=TUint8(EDbsFree);
+	iPolicy = NULL;
+	}
+
+#ifdef __DBDUMP__
+//Using CDbsSession::TEntry::Dump() method you can dump the TEntry's content
+//into a stream. Note that the dump works only if you have __DBDUMP__ macro defined.
+void CDbsSession::TEntry::Dump(RFile& aFile) const
+	{
+	_LIT8(KClassName, "CDbsSession::TEntry. this=%X");
+	_LIT8(KType, "Type=%S");
+	_LIT8(KMagic, "Magic=%d");
+	_LIT8(KCrLf, "\r\n");
+	_LIT8(KEnd, "====");
+	TPtrC8 KDbsType[EDbsMaxType + 1] = {_L8("Free"), _L8("Database"), _L8("Incremental"), _L8("Cursor"), _L8("Constraint"), _L8("Stream"), _L8("Observer")};
+	TBuf8<40> buf;
+
+	buf.Format(KClassName, this);
+	(void)aFile.Write(buf);
+	(void)aFile.Write(KCrLf);
+	buf.Format(KType, &KDbsType[iType]);
+	(void)aFile.Write(buf);
+	(void)aFile.Write(KCrLf);
+	buf.Format(KMagic, iMagic);
+	(void)aFile.Write(buf);
+	(void)aFile.Write(KCrLf);
+	__ASSERT(iPolicy);
+	iPolicy->Dump(aFile);
+	(void)aFile.Write(KEnd);
+	(void)aFile.Write(KCrLf);
+	}
+#endif//__DBDUMP__
+
+// Class CDbsSession
+
+//
+// Release all this clients resources
+// Streams must be released before cursors, and everything before the connection
+//
+CDbsSession::~CDbsSession()
+	{
+	TEntry* const base=&iIx[0];
+	if (base)
+		{
+		TInt type=EDbsMaxType;
+		do	{
+			for (TEntry* e=base+iSize;--e>=base;)
+				{
+				if (e->iType==type)
+					e->Release();
+				}
+			} while (--type>EDbsFree);
+		User::Free(base);
+		}
+	iDbPolicyRqColl.Close();
+    delete iSessDriveSpace;
+	Server().RemoveSession();
+	}
+
+/**
+Overrides virtual CSession2::Create2().
+Creates iSessDriveSpace instance.
+*/
+void CDbsSession::CreateL()
+    {
+    iSessDriveSpace = CDbsSessDriveSpace::NewL(Server().DriveSpaceCol());
+    }
+
+//
+// provide for CSession
+// If this leaves, we complete message through ServiceError(...)
+//
+void CDbsSession::ServiceL(const RMessage2& aMessage)
+	{
+	//set received message in server so it can be used in cleanup when server panics.
+	CPolicyProxy& policyProxy = Server().PolicyProxy();
+	TDbsFunction f=DbsFunction(aMessage.Function());
+	if (f&KDbsObjectReturn)		// may return a derived object
+		AllocL();	// ensure index space
+	TInt r=0;//object handle
+	TInt h=DbsHandle(aMessage.Function());
+	if (h==KDbsSessionHandle)
+		{	// session based requests
+		switch (f&~KDbsObjectReturn)
+			{
+		case EDbsResourceMark:
+			ResourceCountMarkStart();
+			break;
+		case EDbsResourceCheck:
+			ResourceCountMarkEnd(aMessage);
+			break;
+		case EDbsResourceCount:
+			r=CountResources();
+			break;
+		case EDbsSetHeapFailure:
+			User::__DbgSetAllocFail(RHeap::EUser,RHeap::TAllocFail(aMessage.Int0()),aMessage.Int1());
+			break;
+		case EDbsOpenDatabase:
+			r=OpenDatabaseL(aMessage);
+			break;
+		case EDbsReserveDriveSpace:
+			ReserveDriveSpaceL(static_cast <TDriveNumber> (aMessage.Int0()));
+			break;
+        case EDbsFreeReservedSpace:
+	        FreeReservedSpace(static_cast <TDriveNumber> (aMessage.Int0()));
+			break;
+		case EDbsReserveGetAccess:
+			GetReserveAccessL(static_cast <TDriveNumber> (aMessage.Int0()));
+			break;
+		case EDbsReserveReleaseAccess:
+			ReleaseReserveAccess(static_cast <TDriveNumber> (aMessage.Int0()));
+			break;
+		default:
+			r=ExtServiceL(aMessage, static_cast <TDbsFunction> (f&~KDbsObjectReturn));
+			break;
+			}
+		}
+	else
+		{	// object based requests
+		TEntry& e=Object(h);
+		__ASSERT(e.iPolicy);
+		policyProxy.CheckL(aMessage, *e.iPolicy);
+		TDbsFunction dbmsFuncNo = static_cast <TDbsFunction> (f & ~KDbsObjectReturn);
+		switch (dbmsFuncNo)
+			{
+	// the common close function
+		case EDbsClose:
+			//If this is a database object, remove the related pair (handle, uid) from iDbPolicyRqColl collection.
+			if(e.Type() == EDbsDatabase)
+				{
+				iDbPolicyRqColl.Remove(h);
+				}
+			Free(e);
+			break;
+	// database functions
+		case EDbsDatabaseAuthenticate:
+			{
+            __LEAVE(KErrNotSupported);             
+			}
+			break;
+		case EDbsDatabaseDestroy:
+			r=e.Database().Destroy();
+			break;
+		case EDbsDatabaseBegin:
+			r=e.Database().Begin();
+			break;
+		case EDbsDatabaseCommit:
+			r=e.Database().Commit();
+			break;
+		case EDbsDatabaseRollback:
+			e.Database().Rollback();
+			break;
+		case EDbsDatabaseProperty:
+			r=e.Database().Property(CDbDatabase::TProperty(aMessage.Int0()));
+			break;
+		case EDbsDatabaseTables:
+			{//The new stream object will have the same security policy as the database
+			 //Read only stream
+			CDbTableNames* names=CDbTableNames::NewLC();
+			e.Database().TablesL(*names);
+			r=NewStreamL(names,Externalizer(names),aMessage,e.iPolicy);
+			}
+			break;
+		case EDbsDatabaseColumns:
+			{//The new stream object will have the same security policy as the database
+			 //Read only stream
+			CDbColSet* set=CDbColSet::NewLC();
+			e.Database().ColumnsL(*set,ReadName0L(0,aMessage));
+			r=NewStreamL(set,Externalizer(set),aMessage,e.iPolicy);
+			}
+			break;
+		case EDbsDatabaseIndexes:
+			{//The new stream object will have the same security policy as the database
+			 //Read only stream
+			CDbIndexNames* names=CDbIndexNames::NewLC();
+			e.Database().IndexesL(*names,ReadName0L(0,aMessage));
+			r=NewStreamL(names,Externalizer(names),aMessage,e.iPolicy);
+			}
+			break;
+		case EDbsDatabaseKeys:
+			{//The new stream object will have the same security policy as the database
+			 //Read only stream
+			CDbKey* key=CDbKey::NewLC();
+			e.Database().KeysL(*key,ReadName0L(0,aMessage),ReadName1L(1,aMessage));
+			r=NewStreamL(key,Externalizer(key),aMessage,e.iPolicy);
+			}
+			break;
+		case EDbsDatabaseCreateTable:
+			{
+			const TDesC& name=ReadName0L(0,aMessage);
+			CDbColSet* set=ColSetLC(1,aMessage);
+			CDbKey* primary=0;
+			if (aMessage.Ptr2())
+				primary=KeyLC(2,aMessage);
+
+			e.Database().CreateTableL(name,*set,primary);
+			if (primary)
+				CleanupStack::PopAndDestroy();	// primary
+			CleanupStack::PopAndDestroy();	// set
+			}
+			break;
+		case EDbsDatabaseOpenObserver:
+			//The new observer object will have the same security policy as the database
+			r=Add(CDbsConnection::Source(e.Database()).ObserverL(),e.iPolicy);
+			break;
+		case EDbsDatabaseOpenUtility:
+			{//The new incremental object will have the same security policy as the database
+			TInt step;
+			r=NewIncrementalL(e.Database().UtilityL(CDbDatabase::TUtility(aMessage.Int0()),step),step,aMessage,e.iPolicy);
+			}
+			break;
+		case EDbsDatabaseOpenDropTable:
+			{//The new incremental object will have the same security policy as the database
+			TInt step;
+			const TDesC& name=ReadName0L(0,aMessage);
+			r=NewIncrementalL(e.Database().DropTableL(name,step),step,aMessage,e.iPolicy);
+			}
+			break;
+		case EDbsDatabaseOpenAlterTable:
+			{//The new incremental object will have the same security policy as the database
+			TInt step;
+			const TDesC& name=ReadName0L(0,aMessage);
+			CDbColSet* set=ColSetLC(1,aMessage);
+			r=NewIncrementalL(e.Database().AlterTableL(name,*set,step),step,aMessage,e.iPolicy);
+			CleanupStack::PopAndDestroy();	// set
+			}
+			break;
+		case EDbsDatabaseOpenCreateIndex:
+			{//The new incremental object will have the same security policy as the database
+			TInt step;
+			const TDesC& name=ReadName0L(0,aMessage);
+			const TDesC& table=ReadName1L(1,aMessage);
+			CDbKey* key=KeyLC(2,aMessage);
+			r=NewIncrementalL(e.Database().CreateIndexL(name,table,*key,step),step,aMessage,e.iPolicy);
+			CleanupStack::PopAndDestroy();	// key
+			}
+			break;
+		case EDbsDatabaseOpenDropIndex:
+			{//The new incremental object will have the same security policy as the database
+			TInt step;
+			const TDesC& name=ReadName0L(0,aMessage);
+			const TDesC& table=ReadName1L(1,aMessage);
+			r=NewIncrementalL(e.Database().DropIndexL(name,table,step),step,aMessage,e.iPolicy);
+			}
+			break;
+		case EDbsDatabaseExecute:
+			{//The new incremental object will have the same security policy as the database or table - sql dependent.
+			//In order EDbsDatabaseExecute request to be performed, the DBMS session has already
+			//checked the client capabilities at the database level.
+			//Now, the sql string will be parsed and the client capabilities will be checked
+			//again at more specific database or table level.
+			TInt init;
+			HBufC* sql=ReadHBufLC(0,aMessage);
+			const TDbPolicyRequest& rq = iDbPolicyRqColl[h];
+			TPolicyType policyType = EPTNone;
+			const MPolicy* policy = policyProxy.SqlPolicyL(rq, *sql, policyType);
+			policyProxy.CheckL(policyType, aMessage, *policy);			
+			r=NewIncrementalL(e.Database().ExecuteL(*sql,TDbTextComparison(aMessage.Int1()),init),init,aMessage,policy);
+			CleanupStack::PopAndDestroy(sql);
+			}
+			break;
+		case EDbsDatabasePrepareView:
+			{//The new cursor object will have the same security policy as the table in the sql string.
+			//In order EDbsDatabasePrepareView request to be performed, the DBMS session has already
+			//checked the client capabilities at the database level.
+			//Now, the sql string will be parsed and the client capabilities will be checked
+			//again at table level.
+			HBufC* sql=ReadHBufLC(0,aMessage);
+			const TDbPolicyRequest& rq = iDbPolicyRqColl[h];
+			TPolicyType policyType = EPTNone;
+			const MPolicy* policy = policyProxy.SqlPolicyL(rq, *sql, policyType);
+			policyProxy.CheckL(policyType, aMessage, *policy);			
+			TPckgBuf<TDbWindow> window;
+			aMessage.ReadL(2,window);
+			TInt mode=aMessage.Int1();
+			CDbCursor* cursor=e.Database().ViewL(TDbQuery(*sql,TDbTextComparison(mode&0xff)),window(),RDbRowSet::TAccess(mode>>8));
+			r=NewCursorL(cursor,aMessage,policy);
+			CleanupStack::PopAndDestroy(sql);
+			}
+			break;
+		case EDbsDatabaseOpenTable:
+			{//The new cursor object will have the same security policy as the table
+			const TDesC& name=ReadName0L(0,aMessage);
+			const TDbPolicyRequest& rq = iDbPolicyRqColl[h];
+			const MPolicy* policy = policyProxy.TblPolicyL(rq, name);
+			//Check caller capabilities against the table policy
+			RDbRowSet::TAccess accessType = static_cast <RDbRowSet::TAccess> (aMessage.Int1());
+			TPolicyType policyType = accessType == RDbRowSet::EReadOnly ? EPTRead : EPTWrite;
+			policyProxy.CheckL(policyType, aMessage, *policy);
+			//Create cursor
+			r=NewCursorL(e.Database().TableL(name,accessType),aMessage,policy);
+			}
+			break;
+	// Incremental functions
+		case EDbsIncrementalNext:
+			{
+			TPckgBuf<TInt> step=aMessage.Int0();
+			r=e.Incremental().NextL(step());
+			aMessage.WriteL(1,step);
+			}
+			break;
+	// Observer functions
+		case EDbsObserverNotify:
+			e.Observer().Notify(aMessage);
+			return;		// deferred completion of the message!
+		case EDbsObserverCancel:
+			e.Observer().Cancel();
+			break;
+	// cursor functions
+		case EDbsCursorColumnTypes:
+			{
+			TInt count=e.Cursor().ColumnCount();
+			TUint8* types=(TUint8*)User::AllocLC(count);
+			for (TInt ii=count;--ii>=0;)
+				types[ii]=TUint8(e.Cursor().ColumnType(ii+1));
+			aMessage.WriteL(3,TPtrC8(types,count));
+			CleanupStack::PopAndDestroy();
+			}
+			break;
+		case EDbsCursorReset:
+			e.Cursor().Reset();
+			break;
+		case EDbsCursorEvaluate:
+			r=e.Cursor().EvaluateL()?1:0;
+			break;
+		case EDbsCursorUnevaluated:
+			r=e.Cursor().Unevaluated()?1:0;
+			break;
+		case EDbsCursorSetIndex:
+			{
+			const TDesC* name=0;
+			if (aMessage.Ptr0())
+				name=&ReadName0L(0,aMessage);
+			e.Cursor().SetIndexL(name);
+			}
+			break;
+		case EDbsCursorSeek:
+			{
+			TDbLookupKey* key=LookupKeyLC(0,aMessage.Int1(),aMessage);
+			r=e.Cursor().SeekL(*key,RDbTable::TComparison(aMessage.Int2()))?1:0;
+			CleanupStack::PopAndDestroy();		// key;
+			}
+			break;
+		case EDbsCursorAtBeginning:
+			r=e.Cursor().AtBeginning()?1:0;
+			break;
+		case EDbsCursorAtEnd:
+			r=e.Cursor().AtEnd()?1:0;
+			break;
+		case EDbsCursorAtRow:
+			r=e.Cursor().AtRow()?1:0;
+			break;
+		case EDbsCursorCount:
+			r=e.Cursor().CountL(RDbRowSet::TAccuracy(aMessage.Int0()))+1;
+			break;
+		case EDbsCursorGotoPos:
+			if (e.Cursor().GotoL(RDbRowSet::TPosition(aMessage.Int0())))
+				{
+				e.Cursor().GetL();
+				r=RetrieveRowL(e.Cursor(),aMessage);
+				}
+			break;
+		case EDbsCursorBookmark:
+			{
+			TPckgBuf<TDbBookmark::TMark> mark;
+			e.Cursor().Bookmark(mark());
+			aMessage.WriteL(3,mark);
+			}
+			break;
+		case EDbsCursorGotoBookmark:
+			{
+			TPckgBuf<TDbBookmark::TMark> mark;
+			aMessage.ReadL(0,mark);
+			e.Cursor().GotoL(mark());
+			}
+			break;
+		case EDbsCursorGet:
+			e.Cursor().GetL();
+			r=RetrieveRowL(e.Cursor(),aMessage);
+			break;
+		case EDbsCursorInsert:
+			e.Cursor().InsertL(CDbCursor::TInsert(aMessage.Int0()));
+			r=RetrieveRowL(e.Cursor(),aMessage);
+			break;
+		case EDbsCursorUpdate:
+			e.Cursor().UpdateL();
+			r=RetrieveRowL(e.Cursor(),aMessage);
+			break;
+		case EDbsCursorRetrieveRow:	// pass the row buffer back to the client
+			r=RetrieveRowL(e.Cursor(),aMessage);
+			break;
+		case EDbsCursorCancel:
+			e.Cursor().Cancel();
+			break;
+		case EDbsCursorPut:
+			PutRowL(e.Cursor(),aMessage);
+			e.Cursor().PutL();
+			break;
+		case EDbsCursorDelete:
+			e.Cursor().DeleteL();
+			break;
+		case EDbsCursorColumns:
+			{// reduce memory usage by extracting and stream columns individually
+			 //Read only stream
+			RWriteStream strm(HBufBuf::NewLC());
+			TInt count=e.Cursor().ColumnCount();
+			strm.WriteInt32L(count);
+			TDbCol col;
+			for (TInt ii=0;++ii<=count;)
+				{
+				e.Cursor().ColumnDef(col,ii);
+				strm<<col;
+				}
+			strm.CommitL();
+			TInt ext=strm.Sink()->SizeL();
+			CleanupStack::Pop();			// stream
+			r=NewStreamL(strm.Sink(),aMessage,e.iPolicy,ext);
+			}
+			break;
+		case EDbsCursorColumnDef:
+			{
+			TPckgBuf<TDbCol> col;
+			e.Cursor().ColumnDef(col(),aMessage.Int0());
+			aMessage.WriteL(3,col);
+			}
+			break;
+		case EDbsCursorSetNull:
+			__ASSERT(TDbCol::IsLong(e.Cursor().ColumnType(aMessage.Int0())));
+			e.Cursor().SetNullL(aMessage.Int0());
+			break;
+		case EDbsCursorColumnSize:
+			__ASSERT(TDbCol::IsLong(e.Cursor().ColumnType(aMessage.Int0())));
+			r=e.Cursor().ColumnSize(aMessage.Int0());
+			break;
+		case EDbsCursorColumnSource:
+			__ASSERT(TDbCol::IsLong(e.Cursor().ColumnType(aMessage.Int0())));
+			{//The new stream object will have the same security policy as the table
+			 //Read only stream, used for large BLOB fields.
+			TDbColNo col=aMessage.Int0();
+			CDbCursor& cursor=e.Cursor();
+			r=NewStreamL(cursor.ColumnSourceL(col),aMessage,e.iPolicy,cursor.ColumnSize(col));
+			}
+			break;
+		case EDbsCursorColumnSink:
+			//The new stream object will have the same security policy as the table
+			//Write stream, used for large BLOB fields.
+			r=NewStreamL(e.Cursor().ColumnSinkL(aMessage.Int0()),aMessage,e.iPolicy);
+			break;
+		case EDbsCursorOpenConstraint:
+			{//The new constraint object will have the same security policy as the table
+			HBufC* sql=ReadHBufLC(0,aMessage);
+			CDbRowConstraint* ct=e.Cursor().ConstraintL(TDbQuery(*sql,TDbTextComparison(aMessage.Int1())));
+			CleanupStack::PopAndDestroy();	//sql
+			r=Add(ct, e.iPolicy);
+			}
+			break;
+		case EDbsCursorMatch:
+			r=e.Cursor().MatchL(Object(aMessage.Int0()).Constraint())?1:0;
+			break;
+		case EDbsCursorFind:
+			{
+			HBufC* sql=ReadHBufLC(0,aMessage);
+			TDbQuery q(*sql,TDbTextComparison(aMessage.Int1()));
+			r=e.Cursor().FindL(RDbRowSet::TDirection(aMessage.Int2()),q)-KErrNotFound;
+			CleanupStack::PopAndDestroy();	//sql
+			}
+			break;
+			// stream functions
+		case EDbsStreamRead:
+			{
+			r=e.Stream().ReadL(aMessage);
+			}
+			break;
+		case EDbsStreamWrite:
+			{
+			e.Stream().WriteL(aMessage);
+			}
+			break;
+		case EDbsStreamSize:
+			{
+			r=e.Stream().SizeL();
+			}
+			break;
+		case EDbsStreamSynch:
+			{
+			e.Stream().SynchL();
+			}
+			break;
+	// we don't know about any other functions
+		default:
+			r=KErrNotSupported;
+			break;
+			}
+		}
+
+	// don't complete message if we have paniced client, just reset variable;
+	if (!aMessage.IsNull())
+		aMessage.Complete(r);
+	}
+
+
+// Handle an error from CDbsSession::ServiceL()
+// A bad descriptor error implies a badly programmed client, so panic it;
+// otherwise use the default handling (report the error to the client)
+void CDbsSession::ServiceError(const RMessage2& aMessage,TInt aError)
+ 	{
+#ifdef __DBDUMP__
+	Dump();
+#endif//__DBDUMP__
+ 	if (aError==KErrBadDescriptor)
+ 		{
+ 		// this completes message as well so we have to handle it in
+ 		// ServiceL
+ 		_LIT(KCategory,"DBMS-server");
+ 		Server().Panic(KCategory,EDbsBadDescriptor);
+ 		}
+ 	CSession2::ServiceError(aMessage,aError);
+   	}
+
+// Read aPtr as a name
+const TDesC& CDbsSession::ReadName0L(TInt aIndex,const RMessage2& aMessage)
+	{
+	TDes& name=Server().Name0();
+	aMessage.ReadL(aIndex,name);
+	return name;
+	}
+
+// Read Ptr1 as a name
+const TDesC& CDbsSession::ReadName1L(TInt aIndex,const RMessage2& aMessage)
+	{
+	TDes& name=Server().Name1();
+	aMessage.ReadL(aIndex,name);
+	return name;
+	}
+
+// Reads aPtr as a variable length 8-bit descriptor
+HBufC8* CDbsSession::ReadHBuf8LC(TInt aIndex,const RMessage2& aMessage)
+	{
+	TInt len= aMessage.GetDesLengthL(aIndex);
+	HBufC8* buf=HBufC8::NewLC(len);
+	TPtr8 read(buf->Des());
+	aMessage.ReadL(aIndex,read);
+	return buf;
+	}
+
+// Reads aPtr as a variable length build-width descriptor
+HBufC* CDbsSession::ReadHBufLC(TInt aIndex,const RMessage2& aMessage)
+	{
+	TInt len= aMessage.GetDesLengthL(aIndex);
+	HBufC* buf=HBufC::NewLC(len);
+	TPtr read(buf->Des());
+	aMessage.ReadL(aIndex,read);
+	return buf;
+	}
+
+// Pulls a column set from the client
+CDbColSet* CDbsSession::ColSetLC(TInt aIndex,const RMessage2& aMessage)
+	{
+	CDbColSet* set=CDbColSet::NewLC();
+	HBufC8* data=ReadHBuf8LC(aIndex,aMessage);
+	RDesReadStream strm(*data);
+	strm>>*set;
+	CleanupStack::PopAndDestroy();	// data
+	return set;
+	}
+
+// Pulls a key from the client
+CDbKey* CDbsSession::KeyLC(TInt aIndex,const RMessage2& aMessage)
+	{
+	CDbKey* key=CDbKey::NewLC();
+	HBufC8* data=ReadHBuf8LC(aIndex,aMessage);
+	RDesReadStream strm(*data);
+	strm>>*key;
+	CleanupStack::PopAndDestroy();	// data
+	return key;
+	}
+
+// Reconstructs a TDbLookupKey from the message parameter
+TDbLookupKey* CDbsSession::LookupKeyLC(TInt aIndex,TInt aSize,const RMessage2& aMessage)
+	{
+	TDbLookupKey* key=(TDbLookupKey*)User::AllocLC(aSize);
+	TPtr8 pckg((TUint8*)key,aSize);
+	aMessage.ReadL(aIndex,pckg); 
+	TDbLookupKey::SColumn* iter=CONST_CAST(TDbLookupKey::SColumn*,key->First());
+	const TDbLookupKey::SColumn* end=iter+key->Count();
+	if ((TUint8*)end-(TUint8*)key<aSize)
+		{	// there is some text data following...
+		do
+			{
+			switch (iter->iType)
+				{
+			default:
+				break;
+			case EDbColText8:
+				iter->iDes8.iPtr=(TUint8*)key+TInt(iter->iDes8.iPtr);
+				break;
+			case EDbColText16:
+				iter->iDes16.iPtr=(TUint16*)((TUint8*)key+TInt(iter->iDes8.iPtr));
+				break;
+				};
+			} while (++iter<end);
+		}
+	return key;
+	}
+
+// Reads the row from the client buffer into the server-side buffer
+void CDbsSession::ReadRowL(RDbRow& aRow,TInt aSize,const RMessage2& aMessage)
+	{
+	if (aSize)
+		{
+		aRow.GrowL(aSize);
+		TPtr8 buf((TUint8*)aRow.First(),aSize);
+		aMessage.ReadL(0,buf);
+		}
+	aRow.SetSize(aSize);
+	}
+
+// Writes a row from the client into the cursor
+// Any blobs which are modified must not be transferred into the cursor row buffer
+void CDbsSession::PutRowL(CDbCursor& aCursor,const RMessage2& aMessage)
+	{
+	RDbRow* pRow=aCursor.RowBuffer();
+	TInt size= aMessage.Int1();
+	const TBool omitBlobs=aMessage.Int2();
+
+	if (!omitBlobs && pRow)
+		{	// write straight into cursor row
+		ReadRowL(*pRow,size,aMessage);
+		return;
+		}
+	RDbRow row;
+	row.PushL();
+	ReadRowL(row,size,aMessage);
+	TInt max=aCursor.ColumnCount();
+	for (TInt ii=0;++ii<=max;)
+		{
+		if (omitBlobs && TDbCol::IsLong(aCursor.ColumnType(ii)))
+			;
+		else
+			aCursor.Column(ii).SetL(row.ColCell(ii));
+		}
+	CleanupStack::PopAndDestroy();		// row
+	}
+
+// Writes the row buffer to the client row buffer, if big enough
+// If the client buffer is too small it will attempt a second retrieval
+TInt CDbsSession::WriteRowL(const RDbRow& aRow,const RMessage2& aMessage)
+	{
+	TInt size=aRow.Size();
+	if (size>0 && size<=aMessage.Int2())
+		aMessage.WriteL(3,TPtrC8((const TUint8*)aRow.First(),size));
+	return size+1;		// return 0 reserved for Goto
+	}
+
+// Returns a row to the client
+TInt CDbsSession::RetrieveRowL(CDbCursor& aCursor,const RMessage2& aMessage)
+	{
+	RDbRow* pRow=aCursor.RowBuffer();
+	if (pRow)	// direct row transfer
+		return WriteRowL(*pRow,aMessage);
+	// need to retrieve columns independantly
+	RDbRow row;
+	row.PushL();
+	TInt max=aCursor.ColumnCount();
+	for (TInt ii=0;++ii<=max;)
+		TDbColumn(row,ii).SetL(aCursor.ColumnC(ii));
+	TInt size=WriteRowL(row,aMessage);
+	CleanupStack::PopAndDestroy();	// row
+	return size;
+	}
+
+//This method creates new EDbsCursor type object.
+//It is used at table level so it needs table object security policies.
+//The related table MPolicy interface will be 
+//put together with the EDbsCursor object in TEntry list.
+//
+//Complete the cursor construction
+TInt CDbsSession::NewCursorL(CDbCursor* aCursor,const RMessage2& aMessage, const MPolicy* aTblSecurityPolicy)
+	{
+	aCursor->PushL();		// it has a context: use safe cleanup
+	TPckgBuf<TDbsColumns> cols;
+	TInt ii=cols().iCount=aCursor->ColumnCount();
+	if (ii<=cols().EMax)
+		{
+		while (--ii>=0)
+			cols().iData[ii]=TUint8(aCursor->ColumnType(ii+1));
+		}
+	aMessage.WriteL(3,cols);
+	CleanupStack::Pop(aCursor);
+	return Add(aCursor, aTblSecurityPolicy);
+	}
+
+//This method creates new EDbsIncremental type object.
+//It is used either at database or  table level so it needs database or table object
+//security policies. The related database/table MPolicy interface will be
+//put together with the EDbsIncremental object in TEntry list.
+//
+//Complete a message which returns an incremental object by writing the step back
+//When there is no work to do, aIncremental may be 0: then return a null handle
+TInt CDbsSession::NewIncrementalL(CDbIncremental* aIncremental,
+								  TInt& aInit,const RMessage2& aMessage,
+								  const MPolicy* aPolicy)
+	{
+	aIncremental->PushL();		// it has a context: use safe cleanup
+	aMessage.WriteL(3,TPckgC<TInt>(aInit));
+	CleanupStack::Pop();
+	return aIncremental ? Add(aIncremental, aPolicy) : 0;
+	}
+
+//This method creates new EDbsStream type object.
+//It is used either at database or table level so it needs either 
+//database or table object security policies.
+//The related database/table MPolicy interface will be
+//put together with the EDbsStream object in TEntry list.
+//
+//Complete a stream based message return
+TInt CDbsSession::NewStreamL(MStreamBuf* aHost,const RMessage2& aMessage,
+							 const MPolicy* aPolicy,TInt aExtent)
+	{
+	aHost->PushL();
+	TPckgBuf<TDbsStreamBuf> buf;
+	if (aExtent>0)	// read the first buffer-full
+		aHost->ReadL(buf().iData,Min(aExtent,KDbsStreamBufSize));
+	TInt h=0;
+	if (aExtent<0 || aExtent>KDbsStreamBufSize)
+		{	// create the stream object
+		HDbsStream* stream = new(ELeave) HDbsStream(aHost,KDbsStreamBufSize);
+		h=Add(stream, aPolicy);
+		CleanupStack::Pop();		// aHost
+		}
+	else	// no more data to send
+		CleanupStack::PopAndDestroy();		// aHost
+	if (aExtent>=0)
+		{
+		buf().iExt=aExtent;
+		aMessage.WriteL(3,buf);
+		}
+	return h;
+	}
+
+//This method creates new EDbsStream type object.
+//It is used at database level so it needs the database object security policies.
+//The related database MPolicy interface will be 
+//put together with the EDbsStream object in TEntry list.
+//
+//Generic object passing code
+//aPtr should be on the cleanup stack, aExter can externalize it
+TInt CDbsSession::NewStreamL(TAny* aPtr,TExternalizeFunction aExter,
+							 const RMessage2& aMessage, const MPolicy* aDbSecurityPolicy)
+	{
+	RWriteStream strm(HBufBuf::NewLC());
+	aExter(aPtr,strm);
+	strm.CommitL();
+	TInt ext=strm.Sink()->SizeL();
+	CleanupStack::Pop();			// host
+	CleanupStack::PopAndDestroy();	// aPtr
+	TInt res = NewStreamL(strm.Sink(),aMessage,aDbSecurityPolicy,ext);
+	return res;
+	}
+
+//allocates a free entry if required
+void CDbsSession::AllocL()
+	{
+	__ASSERT(TUint(iFree)<=TUint(iSize));
+	if (iFree==iSize)
+		{
+		TInt size=iSize+EIndexGranularity;
+		if (size>KDbsIndexLimit)	// maximum number of objects reached
+			__LEAVE(KErrNoMemory);
+		TEntry* ix=iIx=(TEntry*)User::ReAllocL(iIx,size*sizeof(TEntry));
+		iSize=size;
+		for (TInt ii=iFree;ii<size;)
+			{
+			TEntry& e=ix[ii];
+			e.iNext=++ii;
+			e.iType=TUint8(EDbsFree);
+			e.iPolicy = NULL;
+			}
+		}
+	}
+
+// Sets the free entry and return a handle to it
+TInt CDbsSession::DoAdd(TAny* aObject,TDbsType aType, const MPolicy* aPolicy)
+	{
+	__ASSERT(TUint(iFree)<TUint(iSize));
+	__ASSERT(aType!=EDbsFree);
+	TInt ix=iFree;
+	TEntry& e=iIx[ix];
+	__ASSERT(e.Type()==EDbsFree);
+	iFree=e.iNext;
+	__ASSERT(TUint(iFree)<=TUint(iSize));
+	e.iObject=aObject;
+	e.iType=TUint8(aType);
+	e.iPolicy = aPolicy;
+	TInt magic=(e.iMagic+1)&KDbsMagicMask;
+	e.iMagic=TUint8(magic);
+	return DbsMakeHandle(ix,magic,aType);
+	}
+
+// releases the object and the entry to the free pool
+void CDbsSession::Free(TEntry& aEntry)
+	{
+	__ASSERT(TUint(iFree)<=TUint(iSize));
+	aEntry.Release();
+	aEntry.iNext=iFree;
+	iFree=&aEntry-&iIx[0];
+	__ASSERT(TUint(iFree)<TUint(iSize));
+	}
+
+CDbsSession::TEntry& CDbsSession::Object(TInt aHandle)
+	{
+	TEntry* e=0;
+	TInt ix=DbsObjectIndex(aHandle);
+	if (TUint(ix)<TUint(iSize))
+		{
+		e=&iIx[ix];
+		if (DbsMakeHandle(ix,e->iMagic,e->Type())!=aHandle)
+			e=0;
+		}
+	__ASSERT_ALWAYS(e && e->iPolicy,::Panic(EDbsBadHandle));
+	return *e;
+	}
+
+// Reports how many objects are allocated by the client
+TInt CDbsSession::CountResources()
+	{
+	TInt alloc=0;
+	const TEntry* const base=iIx;
+	if (base)
+		{
+		for (const TEntry* e=base+iSize;--e>=base;)
+			{
+			if (e->Type()!=EDbsFree)
+				++alloc;
+			}
+		}
+	return alloc;
+	}
+
+#ifdef __DBDUMP__
+//Using CDbsSession::Dump() method you can dump the session content
+//into a stream. Note that the dump works only if you have __DBDUMP__ macro defined.
+void CDbsSession::Dump()
+	{
+	RFile dumpFile;
+	RFs fileSess;
+	TInt err = fileSess.Connect();
+	if(err == KErrNone)
+		{
+		_LIT(KDumpFileName, "_:\\PUBLIC\\DBMS\\DUMP%X.TXT");
+		TFileName dumpFileName(KDumpFileName);
+		dumpFileName[0] = 'A' + static_cast<TInt>(RFs::GetSystemDrive());
+		
+		TBuf<40> buf;
+		buf.Format(dumpFileName, this);
+		err = fileSess.MkDirAll(buf);
+		if(err == KErrNone || err == KErrAlreadyExists)
+			{
+			err = dumpFile.Replace(fileSess, buf, EFileWrite);
+			if(err == KErrNone)
+				{
+				TEntry* const base = iIx;
+				if(base)
+					{
+					for(TEntry* e=base+iSize;--e>=base;)
+						{
+						if(e->Type() != EDbsFree)
+							{
+							e->Dump(dumpFile);
+							}
+						}
+					}//end of - if(base)
+				}//end of - if(err == KErrNone)
+			}
+		}//end of - if(err == KErrNone)
+	dumpFile.Close();
+	fileSess.Close();
+	RDebug::Print(_L("CDbsSession::Dump() error=%d\n"), err);
+	__ASSERT_ALWAYS(err == KErrNone, User::Invariant());
+	}
+#endif//__DBDUMP__
+
+/**
+Reserves a prederfined amount of disk space on aDrive drive. 
+At the moment the max possible amount, allowed by the file server, is reserved on aDrive drive.
+
+Use this call to ensure that if your "delete records" transaction fails because of "out of
+disk space" circumstances, you can get an access to the already reserved disk space and
+complete your transaction successfully the second time.
+
+There is no strong, 100% guarantee, that the reserved disk space will always help the client
+in "low memory" situations.
+
+This method processes EDbsReserveDriveSpace message.
+
+@param aDrive Drive number to reserve space on
+@leave KErrArgument Invalid aDrive value.
+@leave CDbsSessDriveSpace::ReserveL() leaving error codes
+@see CDbsSessDriveSpace::ReserveL()
+*/
+void CDbsSession::ReserveDriveSpaceL(TDriveNumber aDrive)
+	{
+	if(aDrive < EDriveA || aDrive > EDriveZ)
+        {
+        __LEAVE(KErrArgument);
+        }
+    iSessDriveSpace->ReserveL(aDrive);
+	}
+
+/**
+The method frees the reserved by the DBMS session disk space.
+
+This method processes EDbsFreeReservedSpace message.
+
+@param aDrive Drive number, which reserved space has to be freed.
+@see CDbsSessDriveSpace::Free()
+@panic Client side panic "DBMS-server 10" in debug mode, if the drive number is invalid.
+@panic In debug mode there will be a panic with the line number as an error code if 
+       there is no reserved disk space for aDrive. 
+@panic In debug mode there will be a panic with the line number as an error code if 
+       the reserved disk space is granted but not released.
+*/
+void CDbsSession::FreeReservedSpace(TDriveNumber aDrive)
+    {
+    TBool valid = aDrive >= EDriveA && aDrive <= EDriveZ;
+    __ASSERT_DEBUG(valid, ::Panic(EDbsInvalidDrive));
+    if(valid)
+        {
+        iSessDriveSpace->Free(aDrive);
+        }
+    }
+
+/**
+Grants access to a given area on a given drive for CDbsSession session.
+Note this session must have reserved space on this particular drive in order to be 
+granted access to the reserved area.
+
+This method processes EDbsReserveGetAccess message.
+  
+@param aDrive Drive number with a reserved disk space, an access to which is requested.
+@leave KErrArgument Invalid drive.
+@leave CDbsSessDriveSpace::GrantAccessL() leaving error codes
+@see CDbsSessDriveSpace::GrantAccessL()
+*/
+void CDbsSession::GetReserveAccessL(TDriveNumber aDrive)
+	{
+	if(aDrive < EDriveA || aDrive > EDriveZ)
+        {
+        __LEAVE(KErrArgument);
+        }
+    iSessDriveSpace->GrantAccessL(aDrive);
+	}
+
+/**
+Revokes access on a given drive for CDbsSession session.
+
+This method processes EDbsReserveReleaseAccess message.
+  
+@param aDrive Drive number with a reserved disk space, the access to which has to be released.
+@panic Client side panic "DBMS-server 10" in debug mode, if the drive number is invalid.
+@panic In debug mode there will be a panic with the line number as an error code if 
+       there is no reserved disk space for aDrive. 
+@panic In debug mode there will be a panic with the line number as an error code if 
+       there is no granted access to the reserved disk space. 
+*/
+void CDbsSession::ReleaseReserveAccess(TDriveNumber aDrive)
+	{
+    TBool valid = aDrive >= EDriveA && aDrive <= EDriveZ;
+    __ASSERT_DEBUG(valid, ::Panic(EDbsInvalidDrive));
+    if(valid)
+        {
+        iSessDriveSpace->ReleaseAccess(aDrive);
+        }
+	}