--- /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));
+ }
+