persistentstorage/sql/SRC/Client/IPC/IPCBuf.cpp
changeset 0 08ec8eefde2f
child 23 26645d81f48d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/sql/SRC/Client/IPC/IPCBuf.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,357 @@
+// Copyright (c) 2005-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 <e32base.h>
+#include "IPCBuf.h"
+#include "SqlPanic.h"
+#include "SqlDbSession.h"
+
+/**
+Standard, phase-one HIpcBuf factory method.
+Created HIpcBuf instance will be used for transfering large text or binary objects from/to SQL server.
+The created HIpcBuf instance will be placed in the cleanup stack.
+
+@param aSession A reference to RSqlDbSession instance.
+@param aFunction Prepared function code (with all statement handle bits set)
+@param aArgs A set of IPC arguments to be sent to the SQL server.
+
+@return A pointer to the created HIpcBuf instance
+
+@leave KErrNoMemory Out of memory.
+*/
+HIpcBuf* HIpcBuf::NewLC(RSqlDbSession& aSession, TInt aFunction, TIpcArgs& aArgs)
+	{
+	HIpcBuf* self = new (ELeave) HIpcBuf(aSession);
+	self->PushL();
+	self->ConstructL(aFunction, aArgs);
+	return self;
+	}
+
+/**
+Standard, phase-one HIpcBuf factory method.
+Created HIpcBuf instance will be used for transfering large text or binary objects from/to SQL server.
+
+@param aSession A reference to RSqlDbSession instance.
+@param aFunction Prepared function code (with all statement handle bits set)
+@param aArgs A set of IPC arguments to be sent to the SQL server.
+
+@return A pointer to the created HIpcBuf instance
+
+@leave KErrNoMemory Out of memory.
+*/
+HIpcBuf* HIpcBuf::NewL(RSqlDbSession& aSession, TInt aFunction, TIpcArgs& aArgs)
+	{
+	HIpcBuf* self = NewLC(aSession, aFunction, aArgs);
+	CleanupStack::Pop();
+	return self;
+	}
+
+/**
+Standard, phase-two HIpcBuf construction method.
+
+@param aFunction The command code which will be sent to the SQL server
+@param aArgs A set of IPC arguments to be sent to the SQL server.
+
+@leave KErrNoMemory Out of memory.
+
+Usage of the IPC call arguments:
+Arg 2: [in/out]  IPC buffer
+iBuf.iExt: [in]  stream size in bytes
+*/
+void HIpcBuf::ConstructL(TInt aFunction, TIpcArgs& aArgs)
+	{
+	TPckg<TIpcStreamBuf> pckg(iBuf);
+	aArgs.Set(2, &pckg);
+	__SQLLEAVE_IF_ERROR(iHandle = iSession.SendReceive(aFunction, aArgs));
+	TUint8* base = iBuf.iData;
+	// if reading we already have one buffer-full of data
+	TInt avail = Max(0, Min(iBuf.iExt, KIpcBufSize));
+	SetBuf(ERead, base, base + avail);
+	SetPos(ERead, avail);
+	SetBuf(EWrite, base, base);
+	SetPos(EWrite, 0);
+	}
+
+/**
+@param aSession A reference to a sesion object.
+*/
+HIpcBuf::HIpcBuf(RSqlDbSession& aSession) :
+	iSession(aSession),
+	iHandle(0),
+	iRPos(0),
+	iWPos(0)
+	{
+	iBuf.iExt = -1;
+	}
+
+/**
+*/
+HIpcBuf::~HIpcBuf()
+	{
+	if(iHandle > 0) //iHandle is valid only when > 0.
+		{
+		(void)iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamClose, ESqlSrvStreamHandle, iHandle));
+		}
+	}
+
+/**
+Fill the buffer's read area.
+*/
+TInt HIpcBuf::UnderflowL(TInt)
+	{
+	// when handle is null there is no data to read from server
+	if(!iHandle)
+		{
+		return 0;
+		}
+	__SQLASSERT(Avail(ERead) == 0, ESqlPanicInternalError);
+	TUint8* base=iBuf.iData;
+	IpcWriteL(base,Lag(EWrite));
+	SetBuf(EWrite,base,base);
+
+	TInt len=IpcReadL(base,iBuf.ESize);
+	SetBuf(ERead,base,base+len);
+	return len;
+	}
+
+/**
+Set up the buffer's write area.
+*/
+void HIpcBuf::OverflowL()
+	{
+	__SQLASSERT(Avail(EWrite) == 0, ESqlPanicInternalError);
+	
+	TUint8* base = iBuf.iData;
+	MovePos(ERead, Lag(ERead));
+	SetBuf(ERead, base, base);
+
+	IpcWriteL(base, Lag(EWrite));
+	SetBuf(EWrite, base, base + iBuf.ESize);
+	}
+
+/**
+Destroys HIpcBuf instance.
+*/
+void HIpcBuf::DoRelease()
+	{
+	delete this;
+	}
+
+/**
+Synchronise this buffer with its file, giving up on outstanding writes in case of failure.
+*/
+void HIpcBuf::DoSynchL()
+	{
+	TUint8* base = iBuf.iData;
+	MovePos(ERead, Lag(ERead));
+	TInt lag = Lag(EWrite);
+	SetBuf(ERead | EWrite, base, base);
+	iBuf.iExt = -1;
+	IpcWriteL(base, lag);
+	__SQLLEAVE_IF_ERROR(iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamSynch, ESqlSrvStreamHandle, iHandle)));
+	}
+
+/**
+Read direct from ipc if asked to transfer more than a bufferful.
+*/
+TInt HIpcBuf::DoReadL(TAny* aPtr, TInt aMaxLength)
+	{
+	__SQLASSERT(aMaxLength > 0, ESqlPanicInternalError);
+	TInt avail = Avail(ERead);
+	__SQLASSERT(avail >= 0 && Avail(EWrite) >= 0, ESqlPanicInternalError);
+	if(avail > 0)
+		{
+		TInt len = Min(aMaxLength, avail);
+		TUint8* ptr = Ptr(ERead);
+		aPtr = Mem::Copy(aPtr, ptr, len);
+		SetPtr(ERead, ptr + len);
+		aMaxLength -= len;
+		if(aMaxLength == 0)
+			return len; // that's it
+		}
+	__SQLASSERT(Avail(ERead) == 0, ESqlPanicInternalError);
+	if(aMaxLength < iBuf.ESize)
+		return avail + TStreamBuf::DoReadL(aPtr, aMaxLength);
+
+	// when handle is null there is no more data to read from server
+	if(!iHandle)
+		{
+		return 0;
+		}
+
+	TUint8* base = iBuf.iData;
+	IpcWriteL(base, Lag(EWrite));
+	SetBuf(ERead | EWrite, base, base);
+	return avail + IpcReadL(aPtr, aMaxLength);
+	}
+
+/**
+Write direct to ipc if asked to transfer more than a bufferful.
+*/
+void HIpcBuf::DoWriteL(const TAny* aPtr,TInt aLength)
+	{
+	__SQLASSERT(aLength > 0, ESqlPanicInternalError);
+	TInt avail = Avail(EWrite);
+	__SQLASSERT(Avail(ERead) >= 0 && avail >= 0, ESqlPanicInternalError);
+	if(avail > 0)
+		{
+		TInt len = Min(aLength, avail);
+		SetPtr(EWrite, Mem::Copy(Ptr(EWrite), aPtr, len));
+		aLength -= len;
+		if(aLength == 0)
+			return; // done
+
+		aPtr = (TUint8*)aPtr + len;
+		}
+	__SQLASSERT(Avail(EWrite) == 0, ESqlPanicInternalError);
+	if(aLength < iBuf.ESize)
+		TStreamBuf::DoWriteL(aPtr, aLength);
+	else
+		{
+		TUint8* base = iBuf.iData;
+		IpcWriteL(base, Lag(EWrite));
+		MovePos(ERead, Lag(ERead));
+		SetBuf(ERead | EWrite, base, base);
+		IpcWriteL(aPtr, aLength);
+		}
+	}
+
+/**
+Position the mark(s) indicated by aMark at aOffset from aLocation.
+*/
+TStreamPos HIpcBuf::DoSeekL(TMark aMark, TStreamLocation aLocation, TInt aOffset)
+	{
+	TUint8* base = iBuf.iData;
+	TInt end = EndL();
+
+	switch(aLocation)
+		{
+	case EStreamBeginning:
+		break;
+	case EStreamMark:
+		switch(aMark)
+			{
+		case ERead:
+			aOffset += Mark(ERead);
+			break;
+		case EWrite:
+			aOffset += Mark(EWrite);
+			break;
+		default:
+			__SQLASSERT_ALWAYS(0, ESqlPanicStreamMarkInvalid);
+			break;
+			}
+		break;
+	case EStreamEnd:
+		aOffset += end;
+		break;
+	default:
+		__SQLASSERT_ALWAYS(0, ESqlPanicStreamLocationInvalid);
+		break;
+		}
+	TInt r = KErrNone;
+	if(aOffset < 0)
+		{
+		aOffset = 0;
+		r = KErrEof;
+		}
+	else if(aOffset > end)
+		{
+		aOffset = end;
+		r = KErrEof;
+		}
+
+	__SQLASSERT_ALWAYS(!(aMark & ~(ERead | EWrite)), ESqlPanicStreamMarkInvalid);
+	if(aMark & ERead)
+		{
+		TInt lag = aOffset - Pos(ERead);
+		if(lag >= base - End(ERead) && lag <= 0)
+			SetPtr(ERead, End(ERead) + lag);
+		else
+			{
+			SetPos(ERead, aOffset);
+			SetBuf(ERead, base, base);
+			}
+		}
+	if(aMark & EWrite && aOffset != Mark(EWrite))
+		{
+		IpcWriteL(base, Lag(EWrite));
+		SetPos(EWrite, aOffset);
+		SetBuf(EWrite, base, base);
+		}
+	__SQLLEAVE_IF_ERROR(r);
+	return TStreamPos(aOffset);
+	}
+
+/**
+Read from the server at the current read position.
+Arg 0:            not used
+Arg 1: [out]      from which position to read
+Arg 2: [in/out]   IPC buffer
+Arg 3: [out]      max length of the requested data
+*/
+TInt HIpcBuf::IpcReadL(TAny* aPtr, TInt aMaxLength)
+	{
+	__SQLASSERT(aMaxLength >= 0, ESqlPanicInternalError);
+	if(aMaxLength == 0)
+		return 0;
+
+	TPtr8 des((TUint8*)aPtr, aMaxLength);
+	TInt pos = Pos(ERead);
+		
+	TInt len = __SQLLEAVE_IF_ERROR(iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamRead, ESqlSrvStreamHandle, iHandle), TIpcArgs(0, pos, &des, aMaxLength)));
+	pos += len;
+	if(len < aMaxLength)
+		iBuf.iExt = pos; // end-of-file encountered
+	SetPos(ERead, pos);
+	return len;
+	}
+
+/**
+Write to the server at the current write position.
+Arg 0:            not used
+Arg 1: [out]      from which position to write
+Arg 2: [in/out]   IPC buffer
+*/
+void HIpcBuf::IpcWriteL(const TAny* aPtr, TInt aLength)
+	{
+	__SQLASSERT(aLength >= 0, ESqlPanicInternalError);
+	if(aLength == 0)
+		return;
+
+	TPtrC8 ptr((TUint8*)aPtr, aLength);
+	TInt ext = iBuf.iExt;
+	iBuf.iExt = -1;
+	TInt pos = Pos(EWrite);
+	__SQLLEAVE_IF_ERROR(iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamWrite, ESqlSrvStreamHandle, iHandle), TIpcArgs(0, pos, &ptr)));
+	pos += aLength;
+	if(ext >=0 && pos > ext)
+		iBuf.iExt = pos;
+	SetPos(EWrite, pos);
+	}
+
+/**
+Determine the end of the stream
+*/
+TInt HIpcBuf::EndL()
+	{
+	TInt ext = iBuf.iExt;
+	if(ext < 0)
+		{
+		iBuf.iExt = ext = __SQLLEAVE_IF_ERROR(iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamSize, ESqlSrvStreamHandle, iHandle)));
+		}
+	return Max(ext, Mark(EWrite));
+	}
+