persistentstorage/sql/SRC/Client/IPC/IPCBuf.cpp
changeset 0 08ec8eefde2f
child 23 26645d81f48d
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <e32base.h>
       
    17 #include "IPCBuf.h"
       
    18 #include "SqlPanic.h"
       
    19 #include "SqlDbSession.h"
       
    20 
       
    21 /**
       
    22 Standard, phase-one HIpcBuf factory method.
       
    23 Created HIpcBuf instance will be used for transfering large text or binary objects from/to SQL server.
       
    24 The created HIpcBuf instance will be placed in the cleanup stack.
       
    25 
       
    26 @param aSession A reference to RSqlDbSession instance.
       
    27 @param aFunction Prepared function code (with all statement handle bits set)
       
    28 @param aArgs A set of IPC arguments to be sent to the SQL server.
       
    29 
       
    30 @return A pointer to the created HIpcBuf instance
       
    31 
       
    32 @leave KErrNoMemory Out of memory.
       
    33 */
       
    34 HIpcBuf* HIpcBuf::NewLC(RSqlDbSession& aSession, TInt aFunction, TIpcArgs& aArgs)
       
    35 	{
       
    36 	HIpcBuf* self = new (ELeave) HIpcBuf(aSession);
       
    37 	self->PushL();
       
    38 	self->ConstructL(aFunction, aArgs);
       
    39 	return self;
       
    40 	}
       
    41 
       
    42 /**
       
    43 Standard, phase-one HIpcBuf factory method.
       
    44 Created HIpcBuf instance will be used for transfering large text or binary objects from/to SQL server.
       
    45 
       
    46 @param aSession A reference to RSqlDbSession instance.
       
    47 @param aFunction Prepared function code (with all statement handle bits set)
       
    48 @param aArgs A set of IPC arguments to be sent to the SQL server.
       
    49 
       
    50 @return A pointer to the created HIpcBuf instance
       
    51 
       
    52 @leave KErrNoMemory Out of memory.
       
    53 */
       
    54 HIpcBuf* HIpcBuf::NewL(RSqlDbSession& aSession, TInt aFunction, TIpcArgs& aArgs)
       
    55 	{
       
    56 	HIpcBuf* self = NewLC(aSession, aFunction, aArgs);
       
    57 	CleanupStack::Pop();
       
    58 	return self;
       
    59 	}
       
    60 
       
    61 /**
       
    62 Standard, phase-two HIpcBuf construction method.
       
    63 
       
    64 @param aFunction The command code which will be sent to the SQL server
       
    65 @param aArgs A set of IPC arguments to be sent to the SQL server.
       
    66 
       
    67 @leave KErrNoMemory Out of memory.
       
    68 
       
    69 Usage of the IPC call arguments:
       
    70 Arg 2: [in/out]  IPC buffer
       
    71 iBuf.iExt: [in]  stream size in bytes
       
    72 */
       
    73 void HIpcBuf::ConstructL(TInt aFunction, TIpcArgs& aArgs)
       
    74 	{
       
    75 	TPckg<TIpcStreamBuf> pckg(iBuf);
       
    76 	aArgs.Set(2, &pckg);
       
    77 	__SQLLEAVE_IF_ERROR(iHandle = iSession.SendReceive(aFunction, aArgs));
       
    78 	TUint8* base = iBuf.iData;
       
    79 	// if reading we already have one buffer-full of data
       
    80 	TInt avail = Max(0, Min(iBuf.iExt, KIpcBufSize));
       
    81 	SetBuf(ERead, base, base + avail);
       
    82 	SetPos(ERead, avail);
       
    83 	SetBuf(EWrite, base, base);
       
    84 	SetPos(EWrite, 0);
       
    85 	}
       
    86 
       
    87 /**
       
    88 @param aSession A reference to a sesion object.
       
    89 */
       
    90 HIpcBuf::HIpcBuf(RSqlDbSession& aSession) :
       
    91 	iSession(aSession),
       
    92 	iHandle(0),
       
    93 	iRPos(0),
       
    94 	iWPos(0)
       
    95 	{
       
    96 	iBuf.iExt = -1;
       
    97 	}
       
    98 
       
    99 /**
       
   100 */
       
   101 HIpcBuf::~HIpcBuf()
       
   102 	{
       
   103 	if(iHandle > 0) //iHandle is valid only when > 0.
       
   104 		{
       
   105 		(void)iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamClose, ESqlSrvStreamHandle, iHandle));
       
   106 		}
       
   107 	}
       
   108 
       
   109 /**
       
   110 Fill the buffer's read area.
       
   111 */
       
   112 TInt HIpcBuf::UnderflowL(TInt)
       
   113 	{
       
   114 	// when handle is null there is no data to read from server
       
   115 	if(!iHandle)
       
   116 		{
       
   117 		return 0;
       
   118 		}
       
   119 	__SQLASSERT(Avail(ERead) == 0, ESqlPanicInternalError);
       
   120 	TUint8* base=iBuf.iData;
       
   121 	IpcWriteL(base,Lag(EWrite));
       
   122 	SetBuf(EWrite,base,base);
       
   123 
       
   124 	TInt len=IpcReadL(base,iBuf.ESize);
       
   125 	SetBuf(ERead,base,base+len);
       
   126 	return len;
       
   127 	}
       
   128 
       
   129 /**
       
   130 Set up the buffer's write area.
       
   131 */
       
   132 void HIpcBuf::OverflowL()
       
   133 	{
       
   134 	__SQLASSERT(Avail(EWrite) == 0, ESqlPanicInternalError);
       
   135 	
       
   136 	TUint8* base = iBuf.iData;
       
   137 	MovePos(ERead, Lag(ERead));
       
   138 	SetBuf(ERead, base, base);
       
   139 
       
   140 	IpcWriteL(base, Lag(EWrite));
       
   141 	SetBuf(EWrite, base, base + iBuf.ESize);
       
   142 	}
       
   143 
       
   144 /**
       
   145 Destroys HIpcBuf instance.
       
   146 */
       
   147 void HIpcBuf::DoRelease()
       
   148 	{
       
   149 	delete this;
       
   150 	}
       
   151 
       
   152 /**
       
   153 Synchronise this buffer with its file, giving up on outstanding writes in case of failure.
       
   154 */
       
   155 void HIpcBuf::DoSynchL()
       
   156 	{
       
   157 	TUint8* base = iBuf.iData;
       
   158 	MovePos(ERead, Lag(ERead));
       
   159 	TInt lag = Lag(EWrite);
       
   160 	SetBuf(ERead | EWrite, base, base);
       
   161 	iBuf.iExt = -1;
       
   162 	IpcWriteL(base, lag);
       
   163 	__SQLLEAVE_IF_ERROR(iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamSynch, ESqlSrvStreamHandle, iHandle)));
       
   164 	}
       
   165 
       
   166 /**
       
   167 Read direct from ipc if asked to transfer more than a bufferful.
       
   168 */
       
   169 TInt HIpcBuf::DoReadL(TAny* aPtr, TInt aMaxLength)
       
   170 	{
       
   171 	__SQLASSERT(aMaxLength > 0, ESqlPanicInternalError);
       
   172 	TInt avail = Avail(ERead);
       
   173 	__SQLASSERT(avail >= 0 && Avail(EWrite) >= 0, ESqlPanicInternalError);
       
   174 	if(avail > 0)
       
   175 		{
       
   176 		TInt len = Min(aMaxLength, avail);
       
   177 		TUint8* ptr = Ptr(ERead);
       
   178 		aPtr = Mem::Copy(aPtr, ptr, len);
       
   179 		SetPtr(ERead, ptr + len);
       
   180 		aMaxLength -= len;
       
   181 		if(aMaxLength == 0)
       
   182 			return len; // that's it
       
   183 		}
       
   184 	__SQLASSERT(Avail(ERead) == 0, ESqlPanicInternalError);
       
   185 	if(aMaxLength < iBuf.ESize)
       
   186 		return avail + TStreamBuf::DoReadL(aPtr, aMaxLength);
       
   187 
       
   188 	// when handle is null there is no more data to read from server
       
   189 	if(!iHandle)
       
   190 		{
       
   191 		return 0;
       
   192 		}
       
   193 
       
   194 	TUint8* base = iBuf.iData;
       
   195 	IpcWriteL(base, Lag(EWrite));
       
   196 	SetBuf(ERead | EWrite, base, base);
       
   197 	return avail + IpcReadL(aPtr, aMaxLength);
       
   198 	}
       
   199 
       
   200 /**
       
   201 Write direct to ipc if asked to transfer more than a bufferful.
       
   202 */
       
   203 void HIpcBuf::DoWriteL(const TAny* aPtr,TInt aLength)
       
   204 	{
       
   205 	__SQLASSERT(aLength > 0, ESqlPanicInternalError);
       
   206 	TInt avail = Avail(EWrite);
       
   207 	__SQLASSERT(Avail(ERead) >= 0 && avail >= 0, ESqlPanicInternalError);
       
   208 	if(avail > 0)
       
   209 		{
       
   210 		TInt len = Min(aLength, avail);
       
   211 		SetPtr(EWrite, Mem::Copy(Ptr(EWrite), aPtr, len));
       
   212 		aLength -= len;
       
   213 		if(aLength == 0)
       
   214 			return; // done
       
   215 
       
   216 		aPtr = (TUint8*)aPtr + len;
       
   217 		}
       
   218 	__SQLASSERT(Avail(EWrite) == 0, ESqlPanicInternalError);
       
   219 	if(aLength < iBuf.ESize)
       
   220 		TStreamBuf::DoWriteL(aPtr, aLength);
       
   221 	else
       
   222 		{
       
   223 		TUint8* base = iBuf.iData;
       
   224 		IpcWriteL(base, Lag(EWrite));
       
   225 		MovePos(ERead, Lag(ERead));
       
   226 		SetBuf(ERead | EWrite, base, base);
       
   227 		IpcWriteL(aPtr, aLength);
       
   228 		}
       
   229 	}
       
   230 
       
   231 /**
       
   232 Position the mark(s) indicated by aMark at aOffset from aLocation.
       
   233 */
       
   234 TStreamPos HIpcBuf::DoSeekL(TMark aMark, TStreamLocation aLocation, TInt aOffset)
       
   235 	{
       
   236 	TUint8* base = iBuf.iData;
       
   237 	TInt end = EndL();
       
   238 
       
   239 	switch(aLocation)
       
   240 		{
       
   241 	case EStreamBeginning:
       
   242 		break;
       
   243 	case EStreamMark:
       
   244 		switch(aMark)
       
   245 			{
       
   246 		case ERead:
       
   247 			aOffset += Mark(ERead);
       
   248 			break;
       
   249 		case EWrite:
       
   250 			aOffset += Mark(EWrite);
       
   251 			break;
       
   252 		default:
       
   253 			__SQLASSERT_ALWAYS(0, ESqlPanicStreamMarkInvalid);
       
   254 			break;
       
   255 			}
       
   256 		break;
       
   257 	case EStreamEnd:
       
   258 		aOffset += end;
       
   259 		break;
       
   260 	default:
       
   261 		__SQLASSERT_ALWAYS(0, ESqlPanicStreamLocationInvalid);
       
   262 		break;
       
   263 		}
       
   264 	TInt r = KErrNone;
       
   265 	if(aOffset < 0)
       
   266 		{
       
   267 		aOffset = 0;
       
   268 		r = KErrEof;
       
   269 		}
       
   270 	else if(aOffset > end)
       
   271 		{
       
   272 		aOffset = end;
       
   273 		r = KErrEof;
       
   274 		}
       
   275 
       
   276 	__SQLASSERT_ALWAYS(!(aMark & ~(ERead | EWrite)), ESqlPanicStreamMarkInvalid);
       
   277 	if(aMark & ERead)
       
   278 		{
       
   279 		TInt lag = aOffset - Pos(ERead);
       
   280 		if(lag >= base - End(ERead) && lag <= 0)
       
   281 			SetPtr(ERead, End(ERead) + lag);
       
   282 		else
       
   283 			{
       
   284 			SetPos(ERead, aOffset);
       
   285 			SetBuf(ERead, base, base);
       
   286 			}
       
   287 		}
       
   288 	if(aMark & EWrite && aOffset != Mark(EWrite))
       
   289 		{
       
   290 		IpcWriteL(base, Lag(EWrite));
       
   291 		SetPos(EWrite, aOffset);
       
   292 		SetBuf(EWrite, base, base);
       
   293 		}
       
   294 	__SQLLEAVE_IF_ERROR(r);
       
   295 	return TStreamPos(aOffset);
       
   296 	}
       
   297 
       
   298 /**
       
   299 Read from the server at the current read position.
       
   300 Arg 0:            not used
       
   301 Arg 1: [out]      from which position to read
       
   302 Arg 2: [in/out]   IPC buffer
       
   303 Arg 3: [out]      max length of the requested data
       
   304 */
       
   305 TInt HIpcBuf::IpcReadL(TAny* aPtr, TInt aMaxLength)
       
   306 	{
       
   307 	__SQLASSERT(aMaxLength >= 0, ESqlPanicInternalError);
       
   308 	if(aMaxLength == 0)
       
   309 		return 0;
       
   310 
       
   311 	TPtr8 des((TUint8*)aPtr, aMaxLength);
       
   312 	TInt pos = Pos(ERead);
       
   313 		
       
   314 	TInt len = __SQLLEAVE_IF_ERROR(iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamRead, ESqlSrvStreamHandle, iHandle), TIpcArgs(0, pos, &des, aMaxLength)));
       
   315 	pos += len;
       
   316 	if(len < aMaxLength)
       
   317 		iBuf.iExt = pos; // end-of-file encountered
       
   318 	SetPos(ERead, pos);
       
   319 	return len;
       
   320 	}
       
   321 
       
   322 /**
       
   323 Write to the server at the current write position.
       
   324 Arg 0:            not used
       
   325 Arg 1: [out]      from which position to write
       
   326 Arg 2: [in/out]   IPC buffer
       
   327 */
       
   328 void HIpcBuf::IpcWriteL(const TAny* aPtr, TInt aLength)
       
   329 	{
       
   330 	__SQLASSERT(aLength >= 0, ESqlPanicInternalError);
       
   331 	if(aLength == 0)
       
   332 		return;
       
   333 
       
   334 	TPtrC8 ptr((TUint8*)aPtr, aLength);
       
   335 	TInt ext = iBuf.iExt;
       
   336 	iBuf.iExt = -1;
       
   337 	TInt pos = Pos(EWrite);
       
   338 	__SQLLEAVE_IF_ERROR(iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamWrite, ESqlSrvStreamHandle, iHandle), TIpcArgs(0, pos, &ptr)));
       
   339 	pos += aLength;
       
   340 	if(ext >=0 && pos > ext)
       
   341 		iBuf.iExt = pos;
       
   342 	SetPos(EWrite, pos);
       
   343 	}
       
   344 
       
   345 /**
       
   346 Determine the end of the stream
       
   347 */
       
   348 TInt HIpcBuf::EndL()
       
   349 	{
       
   350 	TInt ext = iBuf.iExt;
       
   351 	if(ext < 0)
       
   352 		{
       
   353 		iBuf.iExt = ext = __SQLLEAVE_IF_ERROR(iSession.SendReceive(::MakeMsgCode(ESqlSrvStreamSize, ESqlSrvStreamHandle, iHandle)));
       
   354 		}
       
   355 	return Max(ext, Mark(EWrite));
       
   356 	}
       
   357