--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/sql/SRC/Server/SqlSrvSession.cpp Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,1773 @@
+// 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 "SqlSrvMain.h" //CSqlServer
+#include "SqlSrvSession.h" //CSqlSrvSession
+#include "SqlSrvStatement.h" //CSqlSrvStatement, HSqlSrvStmtParamBuf
+#include "SqlSecurityImpl.h" //CSqlSecurityPolicy
+#include "SqlSrvUtil.h" //Global server functions
+#include "SqlUtil.h" // config length
+#include "SqlSrvDriveSpace.h" //CSqlDriveSpace, RSqlDriveSpaceCol
+#include "SqlSrvBlob.h"
+#include "SqlResourceProfiler.h"
+#include "SqlCompact.h"
+#include "UTraceSql.h"
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef _DEBUG
+
+const TInt KDelayedDbHeapFailureMask = 0x1000;
+
+//Puts the database connection in a test mode
+//Returns true if the heap failure simulation has to be delayed untill the database is opened
+//Initialises iDbResourceTestMode and iFailedAllocNumber (if delayed simulation) data members
+inline TBool CSqlSrvSession::ActivateDbTestMode(TInt aHeapFailureMode, TInt aFailedAllocNumber)
+ {
+ iDbResourceTestMode = aHeapFailureMode;
+ if(aHeapFailureMode & KDelayedDbHeapFailureMask)
+ {
+ iFailedAllocNumber = aFailedAllocNumber;
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+//If the database connection is in a test mode then the macro will reset the heap allocation failure type.
+//and stop the test mode.
+inline void CSqlSrvSession::StopDbTestMode()
+ {
+ if(iDbResourceTestMode)
+ {
+ iDbResourceTestMode = 0;
+ User::__DbgSetAllocFail(RHeap::EUser, RHeap::ENone, 0);
+ }
+ }
+
+//If the database connection is in a test mode then the function will mark the allocated by the
+//server resources.
+inline void CSqlSrvSession::DbResourceMark()
+ {
+ if(iDbResourceTestMode)
+ {
+ ResourceCountMarkStart();
+ }
+ }
+
+//If the database connection is in a test mode then the macro will check the allocated by the server resources,
+//comparing their count with the resource count at the moment DbResourceMark() has been called.
+//The client will be panicked if the resource count now is different.
+inline void CSqlSrvSession::DbResourceEnd(const RMessage2& aMessage)
+ {
+ if(iDbResourceTestMode)
+ {
+ ResourceCountMarkEnd(aMessage);
+ }
+ }
+
+//Executes the heap simulation failure.
+inline void CSqlSrvSession::DbSetAllocFail(TInt aHeapFailureMode, TInt aFailedAllocNumber)
+ {
+ User::__DbgSetAllocFail(RHeap::EUser,
+ static_cast <RHeap::TAllocFail> (aHeapFailureMode & (KDelayedDbHeapFailureMask - 1)),
+ aFailedAllocNumber);
+ }
+
+//Executes the delayed heap simulation failure, if the connection is in test mode
+inline void CSqlSrvSession::DbSetDelayedAllocFail()
+ {
+ if(iDbResourceTestMode & KDelayedDbHeapFailureMask)
+ {
+ User::__DbgSetAllocFail(RHeap::EUser,
+ static_cast <RHeap::TAllocFail> (iDbResourceTestMode & (KDelayedDbHeapFailureMask - 1)),
+ iFailedAllocNumber);
+ }
+ }
+
+#else //_DEBUG
+
+inline TBool CSqlSrvSession::ActivateDbTestMode(TInt, TInt)
+ {
+ return EFalse;
+ }
+
+inline void CSqlSrvSession::StopDbTestMode()
+ {
+ }
+
+inline void CSqlSrvSession::DbResourceMark()
+ {
+ }
+
+inline void CSqlSrvSession::DbResourceEnd(const RMessage2&)
+ {
+ }
+
+inline void CSqlSrvSession::DbSetAllocFail(TInt, TInt)
+ {
+ }
+
+inline void CSqlSrvSession::DbSetDelayedAllocFail()
+ {
+ }
+
+#endif//_DEBUG
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Searches aContainer for an object identified by aHandle.
+If such object exists, a reference to it is returned.
+If there is no object, the client gets a panic.
+
+@panic SqlDb 4 Client panic. Invalid aHandle parameter value (zero, negative or out of range).
+
+@internalComponent
+*/
+template <class T> T& SqlSessObjFind(RDbObjContainer<T>& aContainer, TInt aHandle, const RMessage2& aMessage)
+ {
+ T* obj = aContainer.Find(aHandle);
+ __SQLPANIC_CLIENT(obj != NULL, aMessage, ESqlPanicBadArgument);
+ return *obj;
+ }
+
+//This function return true, if there is free disk space on drive where the main database file is.
+static TBool HasFreeDiskSpace(RFs& aFs, TDriveNumber aDrive)
+ {
+ TVolumeInfo volInfo;
+ TInt err = aFs.Volume(volInfo, aDrive);
+ if(err == KErrNone)
+ {
+ const TInt64 KDiskSpaceThreshold = 1024 * 4;
+ return volInfo.iFree > KDiskSpaceThreshold;
+ }
+ return ETrue;
+ }
+
+//If aError is KSqlErrFull and there is no free disk space, then KSqlErrFull is converted to KErrDiskFull
+//and returned.
+static TInt ConvertSqlFull2DiskFullErr(TInt aError, RFs& aFs, TDriveNumber aDrive)
+ {
+ if(aError == KSqlErrFull && !HasFreeDiskSpace(aFs, aDrive))
+ {
+ aError = KErrDiskFull;
+ }
+ return aError;
+ }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Creates a new instance of CSqlSrvSession class.
+
+This function shall never be called directly.
+It is CSqlServer responsibility to create a new server side session object as a responce to the criation of a
+client side session instance.
+
+@return A pointer to the created CSqlSrvSession instance.
+
+@leave KErrNoMemory, an out of memory condition has occurred;
+
+@see CSqlServer
+@see CSqlServer::NewSessionL()
+*/
+CSqlSrvSession* CSqlSrvSession::NewL()
+ {
+ CSqlSrvSession* self = new (ELeave) CSqlSrvSession;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+Frees the allocated by CSqlSrvSession instance resources and memory.
+*/
+CSqlSrvSession::~CSqlSrvSession()
+ {
+ StopDbTestMode();
+ DbFreeReservedSpace();
+ iIpcStreams.Close();
+ iStatements.Close();
+ delete iDatabase;
+ }
+
+/**
+Receives and dispatches all client side requests.
+
+CSession2::ServiceL() implementation.
+
+@param aMessage Client message containing the request (function code and data)
+
+@leave The function may leave with some database specific
+ errors categorised as ESqlDbError or system-wide error codes.
+
+@see CSession2::ServiceL()
+*/
+void CSqlSrvSession::ServiceL(const RMessage2& aMessage)
+ {
+ TSqlSrvFunction funcCode = ESqlSrvTestBase;
+ TInt handle = 0;
+ Extract(aMessage, funcCode, handle);
+ TInt retCode = KErrNone;
+ if(funcCode >= ESqlSrvDbBase)
+ {
+ SQLPROFILER_REPORT_IPC(ESqlIpcRq, 0);
+ }
+ SYMBIAN_TRACE_SQL_EVENTS_ONLY(TPtrC8 funcName = GetIPCFuncStr(funcCode));
+ SYMBIAN_TRACE_SQL_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EBorder), KSrvMsgStr, &funcName));
+
+ SQLPROFILER_IPC_START(iIpcCounter, iDatabase ? (TUint)iDatabase->RawDbHandle() : 0);
+
+ switch(funcCode)
+ {
+ ////////////////////// resource check operations ///////////////////////////
+ case ESqlSrvResourceMark:
+ ResourceCountMarkStart();
+ break;
+ case ESqlSrvResourceCheck:
+ ResourceCountMarkEnd(aMessage);
+ break;
+ case ESqlSrvResourceCount:
+ retCode = CountResources(); //Returns the recourse count
+ break;
+ case ESqlSrvSetDbHeapFailure:
+ if(ActivateDbTestMode(aMessage.Int0(), aMessage.Int1()))
+ {
+ break;
+ }
+ case ESqlSrvSetHeapFailure:
+ DbSetAllocFail(aMessage.Int0(), aMessage.Int1());
+ break;
+ ////////////////////// profiling operations //////////////////////////////////
+ case ESqlSrvProfilerStart:
+ TSqlSrvResourceProfiler::StartL(aMessage);
+ break;
+ case ESqlSrvProfilerStop:
+ TSqlSrvResourceProfiler::StopL(aMessage);
+ break;
+ case ESqlSrvProfilerReset:
+ TSqlSrvResourceProfiler::ResetL(aMessage);
+ break;
+ case ESqlSrvProfilerQuery:
+ ProfilerQueryL(aMessage);
+ break;
+ ////////////////////// database operations //////////////////////////////////
+ case ESqlSrvDbCreate:
+ case ESqlSrvDbCreateSecure:
+ case ESqlSrvDbOpen:
+ DbResourceMark();
+ DbCreateObjectL(aMessage, funcCode);
+ DbSetDelayedAllocFail();
+ break;
+ case ESqlSrvDbOpenFromHandle:
+ DbResourceMark();
+ DbCreateObjectFromHandleL(aMessage);
+ DbSetDelayedAllocFail();
+ break;
+ case ESqlSrvDbAttach:
+ DbAttachL(aMessage);
+ break;
+ case ESqlSrvDbAttachFromHandle:
+ DbAttachFromHandleL(aMessage);
+ break;
+ case ESqlSrvDbDetach:
+ DbDetachL(aMessage);
+ break;
+ case ESqlSrvDbClose:
+ DbDestroyObject();
+ DbResourceEnd(aMessage);
+ StopDbTestMode();
+ break;
+ case ESqlSrvDbCopy:
+ DbResourceMark();
+ DbCopyFileL(aMessage);
+ break;
+ case ESqlSrvDbDelete:
+ DbResourceMark();
+ DbDeleteFileL(aMessage);
+ break;
+ case ESqlSrvLastErrorMsg:
+ retCode = DbLastErrorMessageL(aMessage);//may return that the client buffer is not big enough for the message
+ break;
+ case ESqlSrvDbLastInsertedRowId:
+ DbLastInsertedRowIdL(aMessage);
+ break;
+ case ESqlSrvDbExec8:
+ retCode = DbExecSql8L(aMessage); //returns the count of affected records
+ break;
+ case ESqlSrvDbExec16:
+ retCode = DbExecSql16L(aMessage); //returns the count of affected records
+ break;
+ case ESqlSrvDbSetIsolationLevel:
+ DbSetIsolationLevelL(aMessage);
+ break;
+ case ESqlSrvDbGetSecurityPolicy:
+ retCode = DbGetSecurityPolicyL(aMessage);//may return that the client buffer is not big enough for the security policy
+ break;
+ case ESqlSrvDbScalarFullSelect8:
+ retCode = DbScalarFullSelectL(aMessage, EFalse);//may return that the client buffer is not big enough for the column value
+ break;
+ case ESqlSrvDbScalarFullSelect16:
+ retCode = DbScalarFullSelectL(aMessage, ETrue);//may return that the client buffer is not big enough for the column value
+ break;
+ case ESqlSrvDbInTransaction:
+ retCode = DbInTransaction(aMessage); //Returns whether the database in in transaction or not - true/false
+ break;
+ case ESqlSrvDbSize:
+ retCode = DbSizeL(aMessage); //Returns the database size
+ break;
+ case ESqlSrvDbSize2:
+ DbSize2L(aMessage);
+ break;
+ case ESqlSrvDbCompact:
+ retCode = DbCompactL(aMessage); //Returns the amount of the removed free database space
+ break;
+ ////////////////////// reserved drive space management ////////////////////////
+ case ESqlSrvDbReserveDriveSpace:
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ DbReserveDriveSpaceL();
+ break;
+ case ESqlSrvDbFreeReservedSpace:
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ DbFreeReservedSpace();
+ break;
+ case ESqlSrvDbGetReserveAccess:
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ DbGetReserveAccessL();
+ break;
+ case ESqlSrvDbReleaseReserveAccess:
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ DbReleaseReserveAccess();
+ break;
+ ////////////////////// BLOB source ///////////////////////////////////////////
+ case ESqlSrvDbBlobSource:
+ retCode = DbBlobSourceL(aMessage); //Returns the BLOB handle
+ break;
+ ////////////////////// statement operations //////////////////////////////////
+ case ESqlSrvStmtPrepare8:
+ retCode = StmtPrepareL(aMessage, EFalse);//returns the statement handle
+ break;
+ case ESqlSrvStmtPrepare16:
+ retCode = StmtPrepareL(aMessage, ETrue);//returns the statement handle
+ break;
+ case ESqlSrvStmtClose:
+ iStatements.Remove(handle);
+ break;
+ case ESqlSrvStmtReset:
+ retCode = ::SqlSessObjFind(iStatements, handle, aMessage).Reset();//May return that the statement has expired
+ break;
+ case ESqlSrvStmtExec:
+ case ESqlSrvStmtAsyncExec:
+ case ESqlSrvStmtBindExec:
+ case ESqlSrvStmtAsyncBindExec:
+ retCode = StmtExecL(aMessage, handle, funcCode);//returns the count of affected records
+ break;
+ case ESqlSrvStmtNext:
+ case ESqlSrvStmtBindNext:
+ retCode = StmtNextL(aMessage, handle, funcCode);//returns a non-negative number if the client side buffer is too small
+ break;
+ case ESqlSrvStmtColumnNames:
+ case ESqlSrvStmtParamNames:
+ retCode = StmtNamesL(aMessage, handle, funcCode);//returns a non-negative number if the client side buffer is too small
+ break;
+ case ESqlSrvStmtColumnSource:
+ retCode = StmtColumnSourceL(aMessage, handle);//returns an IPC stream handle
+ break;
+ case ESqlSrvStmtBinParamSink:
+ case ESqlSrvStmtTxtParamSink16:
+ retCode = StmtParamSinkL(aMessage, handle, funcCode);//returns an IPC stream handle
+ break;
+ case ESqlSrvStmtBufFlat:
+ StmtGetBufFlatL(aMessage, handle);
+ break;
+ case ESqlSrvStmtColumnValue:
+ StmtColumnValueL(aMessage, handle);
+ break;
+ case ESqlSrvStmtDeclColumnTypes:
+ StmtDeclColumnTypesL(aMessage, handle);
+ break;
+ ////////////////////// stream operations //////////////////////////////////
+ case ESqlSrvStreamRead:
+ retCode = ::SqlSessObjFind(iIpcStreams, handle, aMessage).ReadL(aMessage);
+ break;
+ case ESqlSrvStreamWrite:
+ ::SqlSessObjFind(iIpcStreams, handle, aMessage).WriteL(aMessage);
+ break;
+ case ESqlSrvStreamSize:
+ retCode = ::SqlSessObjFind(iIpcStreams, handle, aMessage).SizeL();
+ break;
+ case ESqlSrvStreamSynch:
+ ::SqlSessObjFind(iIpcStreams, handle, aMessage).SynchL();
+ break;
+ case ESqlSrvStreamClose:
+ iIpcStreams.Remove(handle);
+ break;
+ ////////////////////// //////////////////////////////////
+ default:
+ retCode = KErrNotSupported;
+ break;
+ }
+ Server().Compactor().RestartTimer();
+ Server().MinimizeBuffers();
+ if(!aMessage.IsNull())
+ {
+ aMessage.Complete(retCode);
+ }
+ SQLPROFILER_IPC_END(iIpcCounter, funcCode, iDatabase ? (TUint)iDatabase->RawDbHandle() : 0, iIpcTraceData, retCode);
+ }
+
+/**
+If aError is KErrBadDescriptor, then panic the client, else - default error handling.
+KErrBadDescriptor error may be thrown from "message write" operations, if the client supplied a bad
+descriptor to the server.
+*/
+void CSqlSrvSession::ServiceError(const RMessage2& aMessage, TInt aError)
+ {
+ Server().MinimizeBuffers();
+ aError = ::ConvertSqlFull2DiskFullErr(aError, Server().FileData().Fs(), iDrive);
+ if(aError == KErrBadDescriptor)
+ {
+ //The __SQLPANIC_CLIENT() macro cannot be used here because it calls a leaving function. A leaving call
+ //from a leaving call will terminate the server.
+ _LIT(KPanicCategory, "SqlDb");
+
+ SYMBIAN_TRACE_SQL_ERR_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EError), KSqlSrvPanicClient, aError));
+ aMessage.Panic(KPanicCategory, ESqlPanicBadDescriptor);
+ }
+
+ SYMBIAN_TRACE_SQL_ERR_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EError), KSqlSrvError, aError));
+ SQLPROFILER_IPC_ERROR(iIpcCounter, static_cast <TSqlSrvFunction> (KSqlSrvFunctionMask & aMessage.Function()),
+ iDatabase ? (TUint)iDatabase->RawDbHandle() : 0, aError);
+ CSession2::ServiceError(aMessage, aError);
+ }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////// Profiler operations ///////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Retrieves the counter values for the specified profiling counter.
+
+@leave KErrNone, the operation completed successfully,
+ KErrOverflow, the receiving buffer size is too small;
+ One of the other system-wide error codes may also be returned.
+
+@see TSqlResourceProfiler
+
+Usage of the IPC call arguments:
+ - Arg 0: [in] profiling counter type, one of the TSqlResourceProfiler::TSqlCounter enum item values.
+ - Arg 1: [in] the size of the buffer for the profiling counter values.
+ - Arg 2: [out] the buffer for the profiling counter values.
+
+@panic SqlDb 2 Client panic. iDatabase is NULL (the database object is not created yet).
+*/
+void CSqlSrvSession::ProfilerQueryL(const RMessage2& aMessage)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ if(aMessage.Int0() == TSqlResourceProfiler::ESqlCounterConfig)
+ {
+ const TInt KConfigBufLen = 128;
+ if(aMessage.Int1() < KConfigBufLen)
+ {
+ __SQLLEAVE(KErrOverflow);
+ }
+ TBuf8<KConfigBufLen> res;
+ iDatabase->QueryConfigL(res);
+ aMessage.WriteL(2, res);
+ }
+ else
+ {
+ TSqlSrvResourceProfiler::QueryL(aMessage);
+ }
+ }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////// Database operations ///////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Processes the request for creating/opening a database.
+
+The function initializes iDatabase and iDrive data members.
+
+Usage of the IPC call arguments:
+Arg 0: [in] database file name length in 16-bit characters
+Arg 1: [in] database file name
+Arg 2: [in] PPPPCCCC, where PPPP is the security policy length, CCCC is the config string length.
+Arg 3: [in] security policies buffer | config string
+
+@leave KErrArgument If config string length or security policy length is invalid (negative length or too big length)
+@panic SqlDb 1 Client panic. iDatabase is not NULL (it has been created already)
+*/
+void CSqlSrvSession::DbCreateObjectL(const RMessage2& aMessage, TSqlSrvFunction aFunction)
+ {
+ __SQLPANIC_CLIENT(!iDatabase, aMessage, ESqlPanicObjExists);
+ const TInt KSecurityPolicyLen = (aMessage.Int2() & 0x7fff0000) >> 16;
+ const TInt KConfigStringLen = aMessage.Int2() & 0xffff;
+ if(KSecurityPolicyLen < 0 || KConfigStringLen < 0 || KConfigStringLen > KSqlSrvMaxConfigStrLen)
+ {
+ __SQLLEAVE(KErrArgument);
+ }
+ TBuf8<KSqlSrvMaxConfigStrLen> configStr;
+ if(KConfigStringLen > 0)
+ {
+ aMessage.ReadL(3, configStr, KSecurityPolicyLen);
+ SQLPROFILER_REPORT_IPC(ESqlIpcRead, KConfigStringLen);
+ }
+ TSqlSrvFileData& fileData = Server().FileData();
+ fileData.SetL(aMessage, aMessage.Int0(), 1, &configStr);
+ iDrive = fileData.Drive();
+ switch(aFunction)
+ {
+ case ESqlSrvDbCreate:
+ if(fileData.IsSecureFileNameFmt())
+ {
+ __SQLLEAVE(KErrArgument);
+ }
+ iDatabase = CSqlSrvDatabase::CreateL(fileData);
+ break;
+ case ESqlSrvDbCreateSecure:
+ {
+ if(!fileData.IsSecureFileNameFmt())
+ {
+ __SQLLEAVE(KErrArgument);
+ }
+ //The caller can create a secure database which secure UID matches his secure UID.
+ if(fileData.SecureUid() != aMessage.SecureId())
+ {
+ __SQLLEAVE(KErrPermissionDenied);
+ }
+ CSqlSecurityPolicy* policy = InternalizeSecurityPolicyL(aMessage);
+ iDatabase = CSqlSrvDatabase::CreateSecureL(fileData, policy);
+ }
+ break;
+ case ESqlSrvDbOpen:
+ iDatabase = CSqlSrvDatabase::OpenL(fileData);
+ break;
+ default:
+ __SQLLEAVE(KErrArgument);
+ break;
+ }
+ }
+
+/**
+Processes the request for opening a database from file handle.
+The server expects that the database to be opened/created is in the applicatio's private data cage.
+
+Usage of the IPC call arguments:
+ - Arg 0: [in] The 32 bits of the argument are used as follow:
+ @code
+ MSB LSB
+ 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ Ro Cr C C C C C C C C C C C C C C F F F F F F F F F F F F F F F F
+ @endcode
+ Where:
+ @code
+ - "Ro" - read-only flag, true if the file is read-only;
+ - "Cr" - create/open flag, true if the file was created, false if the file was opened;
+ - "C" - config string length in 16-bit characters;
+ - "F" - database file name length in 16-bit characters;
+ @endcode
+ - Arg 1: [in] database file name | config string
+ - Arg 2: [in] file session handle
+ - Arg 3: [in] database file handle
+
+@panic SqlDb 1 Client panic. iDatabase is not NULL (it has been created already)
+*/
+void CSqlSrvSession::DbCreateObjectFromHandleL(const RMessage2& aMessage)
+ {
+ __SQLPANIC_CLIENT(!iDatabase, aMessage, ESqlPanicObjExists);
+ const TBool KReadOnly = (aMessage.Int0() & 0x80000000) != 0;
+ const TBool KCreated = (aMessage.Int0() & 0x40000000) != 0;
+ const TInt KDbFileNameLen = aMessage.Int0() & 0x0000FFFF;
+ const TInt KConfigStringLen = (aMessage.Int0() & 0x3FFF0000) >> 16;
+ if(KConfigStringLen < 0 || KConfigStringLen > KSqlSrvMaxConfigStrLen)
+ {
+ __SQLLEAVE(KErrArgument);
+ }
+ if(KDbFileNameLen < 1 || KDbFileNameLen > KMaxFileName)
+ {
+ __SQLLEAVE(KErrBadName);
+ }
+ TDes16& buffer = Server().GetBuf16L(KDbFileNameLen + KConfigStringLen);
+ aMessage.ReadL(1, buffer);
+ SQLPROFILER_REPORT_IPC(ESqlIpcRead, ((KDbFileNameLen + KConfigStringLen) * sizeof(TText)));
+ TFileName dbFileName;
+ dbFileName.Copy(buffer.LeftTPtr(KDbFileNameLen));
+ TBuf8<KSqlSrvMaxConfigStrLen> configStr;
+ if(KConfigStringLen > 0)
+ {
+ configStr.Copy(buffer.MidTPtr(KDbFileNameLen, KConfigStringLen));
+ }
+ TSqlSrvFileData& fileData = Server().FileData();
+ fileData.SetFromHandleL(aMessage, dbFileName, KCreated, KReadOnly, &configStr);
+ iDrive = fileData.Drive();
+ iDatabase = CSqlSrvDatabase::OpenL(fileData);
+ }
+
+/**
+Processes the request for copying a database.
+
+Only the database creator can copy the database if the database is a secure database.
+
+Usage of the IPC call arguments:
+Arg 0: [in] source database file name length
+Arg 1: [in] source database file name
+Arg 2: [in] destination database file name length
+Arg 3: [in] destination database file name
+*/
+void CSqlSrvSession::DbCopyFileL(const RMessage2& aMessage)
+ {
+ const TInt KDbCnt = 2; //"2" - because we have 2 dbases: src and dest
+ const TInt KSrcDbIdx = 0;
+ const TInt KDestDbIdx = 1;
+ TInt fileNameLen[KDbCnt] = {aMessage.Int0(), aMessage.Int2()};
+ TSqlSrvFileData& fileData = Server().FileData();
+ TUint dbSecureFlag[KDbCnt];
+ TUid dbSID[KDbCnt] = {KNullUid, KNullUid};
+ TFileName dbFileName[KDbCnt];
+ //Initialize dbSecureFlag[], dbSID[] and dbFileName[] array elements
+ for(TInt i=0;i<KDbCnt;++i)
+ {
+ fileData.SetL(aMessage, fileNameLen[i], i * KDbCnt + 1); //"i * KDbCnt + 1" is the RMessage2 parameter number: 1 for src db, 3 for dest db
+ dbSecureFlag[i] = fileData.IsSecureFileNameFmt() ? 1 : 0;
+ if(dbSecureFlag[i])
+ {
+ dbSID[i] = fileData.SecureUid();
+ }
+ dbFileName[i].Copy(fileData.FileName());
+ }
+ //It is not allowed to copy non-secure to a secure or secure to a non-secure database.
+ if(dbSecureFlag[KSrcDbIdx] ^ dbSecureFlag[KDestDbIdx])
+ {
+ __SQLLEAVE(KErrPermissionDenied);
+ }
+ //If this is a secure database "copy" operation, then...
+ if(dbSecureFlag[KSrcDbIdx])
+ {
+ TUid callerSid = aMessage.SecureId();
+ //A secure database can be copied only by its owner (database SID matches caller SID).
+ if(callerSid != dbSID[KSrcDbIdx] || callerSid != dbSID[KDestDbIdx])
+ {
+ __SQLLEAVE(KErrPermissionDenied);
+ }
+ }
+ //Copy the database
+ CFileMan* fileMan = CFileMan::NewL(fileData.Fs());
+ CleanupStack::PushL(fileMan);
+ __SQLLEAVE_IF_ERROR(fileMan->Copy(dbFileName[KSrcDbIdx], dbFileName[KDestDbIdx]));
+ //"Copy" operation executed without errors. Now it is a time to turn off the read-only
+ //flag of the target file (which may be on if the source file is on a read-only drive)
+ __SQLLEAVE_IF_ERROR(fileData.Fs().SetAtt(dbFileName[KDestDbIdx], 0, KEntryAttReadOnly));
+ CleanupStack::PopAndDestroy(fileMan);
+ }
+
+/**
+Processes the request for deleting a database.
+
+Only the database creator can delete the database if the database is a secure database.
+
+Usage of the IPC call arguments:
+Arg 0: [in] database file name length
+Arg 1: [in] database file name
+*/
+void CSqlSrvSession::DbDeleteFileL(const RMessage2& aMessage)
+ {
+ TSqlSrvFileData& fileData = Server().FileData();
+ fileData.SetL(aMessage, aMessage.Int0(), 1);
+ if(fileData.IsSecureFileNameFmt())
+ {
+ //A secure database can be deleted only by its owner (database SID matches caller SID).
+ if(fileData.SecureUid() != aMessage.SecureId())
+ {
+ __SQLLEAVE(KErrPermissionDenied);
+ }
+ }
+ #ifdef _NOTIFY
+ TPtrC fname = fileData.FileName();
+ RDebug::Print(_L("--SrvSess, delete, fname=\"%S\"\r\n"), &fname);
+ #endif
+ __SQLLEAVE_IF_ERROR(fileData.Fs().Delete(fileData.FileName()));
+ }
+
+/**
+Processes the request for retrieving the last error message.
+
+If the client side buffer size is not big enough, the function returns the needed
+buffer size + KSqlClientBufOverflowCode.
+In this case the client must increase the buffer and try again to get the message.
+
+Usage of the IPC call arguments:
+Arg 0: [in] Message buffer length in 16-bit characters
+Arg 1: [in/out] Message buffer
+
+@panic SqlDb 2 Client panic. iDatabase is NULL (the database object is not created yet).
+@panic SqlDb 4 Client panic. Negative client message buffer length (Arg 0).
+*/
+TInt CSqlSrvSession::DbLastErrorMessageL(const RMessage2& aMessage)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ TPtrC msg = iDatabase->LastErrorMessage();
+ TInt msgLen = msg.Length();
+ TInt bufSize = aMessage.Int0();
+ __SQLPANIC_CLIENT(bufSize >= 0, aMessage, ESqlPanicBadArgument);
+ if(msgLen <= bufSize)
+ {
+ aMessage.WriteL(1, msg);
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, (msgLen * sizeof(TText)));
+ return 0;
+ }
+ return msgLen + KSqlClientBufOverflowCode;
+ }
+
+/**
+Processes the request for retrieving the last inserted ROWID of this database connection.
+
+Usage of the IPC call arguments:
+Arg 0: [in/out] Receiving buffer
+
+@panic SqlDb 2 Client panic. The database object is not yet created yet (iDatabase is NULL).
+*/
+void CSqlSrvSession::DbLastInsertedRowIdL(const RMessage2& aMessage)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ TInt64 rowid = iDatabase->LastInsertedRowId();
+ aMessage.WriteL(0, TPtrC8(reinterpret_cast <const TUint8*> (&rowid), sizeof(rowid)));
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, sizeof(rowid));
+ }
+
+/**
+Processes the request for retrieving the database security policies.
+
+The method leaves with KErrNotSupported if the database is not a secure database.
+
+If the client side buffer size is not big enough, the function returns the needed
+buffer size + KSqlClientBufOverflowCode.
+In this case the client must increase the buffer and try again to get the database security policy.
+
+Usage of the IPC call arguments:
+Arg 0: [in] security policy buffer length in bytes
+Arg 1: [in/out] buffer for the database security policies
+
+@panic SqlDb 2 Client panic. iDatabase is NULL (the database object is not created yet).
+*/
+TInt CSqlSrvSession::DbGetSecurityPolicyL(const RMessage2& aMessage)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ const CSqlSecurityPolicy* securityPolicy = iDatabase->SecurityPolicy();
+ if(!securityPolicy)
+ {
+ __SQLLEAVE(KErrNotSupported);
+ }
+ const RSqlBufFlat& bufFlat = securityPolicy->BufFlat();
+ TInt size = bufFlat.Size();
+ if(size <= aMessage.Int0())
+ {
+ aMessage.WriteL(1, bufFlat.BufDes());
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, size);
+ return 0;
+ }
+ return size + KSqlClientBufOverflowCode;
+ }
+
+/**
+If an error occurs during the execution the function leaves with the error code.
+Possible non-leaving return values:
+ - KErrNone - the function has completed successfully;
+ - Positive return value - the length of the column, which means - the destination buffer is too small.
+ This return value is possible only with text or binary columns.
+
+@panic SqlDb 2 Client panic. iDatabase is NULL (the database object is not created yet).
+
+Usage of the IPC call arguments:
+Arg 0: [in] (8/16-bit character length of SQL statement) | (expected column value type << 24).
+Arg 1: [in] SQL statement.
+Arg 2: [in] Byte max length of the receiving buffer
+Arg 3: [in/out] The receiving buffer
+*/
+TInt CSqlSrvSession::DbScalarFullSelectL(const RMessage2& aMessage, TBool aIsText16)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ TUint sqlLen = static_cast <TUint> (aMessage.Int0()) & 0x00FFFFFF;
+ TSqlColumnType colType = static_cast <TSqlColumnType> ((static_cast <TUint> (aMessage.Int0()) & 0xFF000000) >> 24);
+ TInt columnCount = -1;
+ TInt paramCount = -1;
+ CSqlSrvStatement* stmt = aIsText16 ?
+ CSqlSrvStatement::NewLC(iDatabase->RawDbHandle(), ReadString16ZL(aMessage, 1, sqlLen), columnCount, paramCount) :
+ CSqlSrvStatement::NewLC(iDatabase->RawDbHandle(), ReadString8ZL(aMessage, 1, sqlLen), columnCount, paramCount);
+ if(columnCount != 1 || paramCount != 0)
+ {
+ __SQLLEAVE(KErrArgument);
+ }
+ TInt err = stmt->Next();
+ if(err == KSqlAtRow)
+ {
+ err = GetColumnValueL(aMessage, *stmt, colType);
+ }
+ else
+ {
+ __SQLLEAVE(err == KSqlAtEnd ? KErrNotFound : err);
+ }
+ CleanupStack::PopAndDestroy(stmt);
+ return err;
+ }
+
+/**
+@return True, if the database is in transaction, false otherwise.
+
+@panic SqlDb 2 Client panic. iDatabase is NULL (the database object is not created yet).
+*/
+TBool CSqlSrvSession::DbInTransaction(const RMessage2& aMessage)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ return iDatabase->InTransaction();
+ }
+
+/**
+Main database size in bytes.
+
+@return Main database size in bytes.
+
+@leave KErrNoMemory, an out of memory condition has occurred,
+ Note that the function may also leave with some other system wide errors or
+ database specific errors categorised as ESqlDbError,
+ KErrTooBig, The database is very big and the size cannot fit in a 32-bit signed integer.
+
+@panic SqlDb 2 Client panic. iDatabase is NULL (the database object is not created yet).
+*/
+TInt CSqlSrvSession::DbSizeL(const RMessage2& aMessage)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ TInt64 size = iDatabase->SizeL();
+ if(size > KMaxTInt)
+ {
+ __SQLLEAVE(KErrTooBig);
+ }
+ return size;
+ }
+
+/**
+Retrieves the database size and free space.
+
+Usage of the IPC call arguments:
+Arg 0: [in/out] Points to a RSqlDatabase::TSize object, where the database size and free space values
+ will be copied.
+Arg 1: [in] The database name length in 16-bit characters
+Arg 2: [in] The attached database name or KNullDesC for the main database
+
+@leave KErrNoMemory, an out of memory condition has occurred,
+ Note that the function may also leave with some other system wide errors or
+ database specific errors categorised as ESqlDbError.
+ KErrBadName, Invalid database name
+
+@panic SqlDb 2 Client panic. iDatabase is NULL (the database object is not created yet).
+*/
+void CSqlSrvSession::DbSize2L(const RMessage2& aMessage)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ const TInt KDbNameLen = aMessage.Int1();
+ if(KDbNameLen < 0 || KDbNameLen > KMaxFileName)
+ {
+ __SQLLEAVE(KErrBadName);
+ }
+ TPtrC dbName(KNullDesC);
+ if(KDbNameLen > 0)
+ {
+ dbName.Set(ReadString16L(aMessage, 2, KDbNameLen));
+ }
+ TPckgBuf<RSqlDatabase::TSize> data;
+ data().iSize = iDatabase->SizeL(dbName);
+ data().iFree = iDatabase->FreeSpaceL(dbName);
+ aMessage.WriteL(0, data);
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, sizeof(RSqlDatabase::TSize));
+ }
+
+/**
+Runs database compaction.
+
+Usage of the IPC call arguments:
+Arg 0: [in] How much space in bytes should be compacted, all free pages should be removed if the
+ parameter value is RSqlDatabase::EMaxCompaction.
+ Note that the requested space to be compacted will be rounded up to the nearest page count,
+ e.g. request for removing 1 byte will remove one free page from the database file.
+Arg 1: [in] The database name length in characters
+Arg 2: [in] The attached database name or KNullDesC for the main database
+
+@return The size of the removed free space
+
+@panic SqlDb 2 Client panic. iDatabase is NULL (the database object is not created yet).
+*/
+TInt CSqlSrvSession::DbCompactL(const RMessage2& aMessage)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ const TInt KSize = aMessage.Int0();
+ if(KSize < 0)
+ {
+ if(KSize != RSqlDatabase::EMaxCompaction)
+ {
+ __SQLLEAVE(KErrArgument);
+ }
+ }
+ if(KSize == 0)
+ {
+ return 0;
+ }
+ const TInt KDbNameLen = aMessage.Int1();
+ if(KDbNameLen < 0 || KDbNameLen > KMaxFileName)
+ {
+ __SQLLEAVE(KErrBadName);
+ }
+ TPtrC dbName(KNullDesC);
+ if(KDbNameLen > 0)
+ {
+ dbName.Set(ReadString16L(aMessage, 2, KDbNameLen));
+ }
+ return iDatabase->CompactL(KSize, dbName);
+ }
+
+/**
+Usage of the IPC call arguments:
+Arg 0: [in] requested size of the space to be reserved - not used
+
+The function leaves with KErrAlreadyExists if a drive space has been reserved already by this session.
+*/
+void CSqlSrvSession::DbReserveDriveSpaceL()
+ {
+ if(iDriveSpaceReserved)
+ {
+ __SQLLEAVE(KErrAlreadyExists);
+ }
+ RSqlDriveSpaceCol& driveSpaceCol = Server().DriveSpaceCol();
+ if(!driveSpaceCol.Find(iDrive))
+ {
+ (void)driveSpaceCol.AddL(iDrive);
+ }
+
+ iDriveSpaceReserved = ETrue;
+ //Only iDriveSpaceReserved is set, nothing more needs to be done, because RSqlDriveSpaceCol::AddL() will
+ //reserve a drive space on the specified drive.
+ //Although it looks like that the implementation can ommit "iDriveSpaceReserved" flag, this flag plays important
+ //role, because it is used to ensure that every "reserve drive space" request is matched by a "free drive space"
+ //call.
+ }
+
+/**
+If the client has been given an access to the reserved drive space, that access will be released.
+*/
+void CSqlSrvSession::DbFreeReservedSpace()
+ {
+ DbReleaseReserveAccess();
+ iDriveSpaceReserved = EFalse;
+ }
+
+/**
+The function leaves with KErrInUse if an access to the reserved drive space has been given to the client.
+The function leaves with KErrNotFound if no drive space has been reserved for the drive, where the database file is.
+*/
+void CSqlSrvSession::DbGetReserveAccessL()
+ {
+ if(iDriveSpaceInUse)
+ {
+ __SQLLEAVE(KErrInUse);
+ }
+ if(!iDriveSpaceReserved)
+ {
+ __SQLLEAVE(KErrNotFound);
+ }
+ CSqlDriveSpace* driveSpace = Server().DriveSpaceCol().Find(iDrive);
+ if(!driveSpace)
+ {
+ __SQLLEAVE(KErrNotFound);
+ }
+ driveSpace->GetAccessL();
+ iDriveSpaceInUse = ETrue;
+ }
+
+/**
+Releases the drive space reserve if it has been in use by this session (resp. client).
+*/
+void CSqlSrvSession::DbReleaseReserveAccess()
+ {
+ if(iDriveSpaceInUse)
+ {
+ CSqlDriveSpace* driveSpace = Server().DriveSpaceCol().Find(iDrive);
+ if(driveSpace)
+ {
+ driveSpace->ReleaseAccess();
+ }
+ iDriveSpaceInUse = EFalse;
+ }
+ }
+
+/**
+Processes the request for attaching a secure or non-secure database.
+
+Usage of the IPC call arguments:
+Arg 0: [in] Database file name length (counted in 16-bit characters).
+Arg 1: [in] Database file name.
+Arg 2: [in] Logical database name length (counted in 16-bit characters).
+Arg 3: [in] Logical database name.
+
+@panic SqlDb 2 Client panic. iDatabase is NULL (the database object is not created yet).
+*/
+void CSqlSrvSession::DbAttachL(const RMessage2& aMessage)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ TSqlSrvFileData& fileData = Server().FileData();
+ fileData.SetL(aMessage, aMessage.Int0(), 1);
+ TInt logicalDbNameLen = aMessage.Int2();
+ if(logicalDbNameLen < 1 || logicalDbNameLen > KMaxFileName)
+ {
+ __SQLLEAVE(KErrBadName);
+ }
+ iDatabase->AttachDbL(fileData, ReadString16L(aMessage, 3, logicalDbNameLen));
+ }
+
+/**
+Processes the request for attaching a database using file session and file handles sent by the client.
+
+Usage of the IPC call arguments:
+ - Arg 0: [in] The 32 bits of the argument are used as follow:
+ @code
+ MSB LSB
+ 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ Ro F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F
+ @endcode
+ Where:
+ @code
+ - "Ro" - read-only flag, true if the file is read-only;
+ - "F" - database file name length in 16-bit characters;
+ @endcode
+Arg 1: [in] db names buffer
+Arg 2: [in] file session handle
+Arg 3: [in] database file handle
+
+@panic SqlDb 2 Client panic. iDatabase is NULL (the database object is not created yet).
+*/
+void CSqlSrvSession::DbAttachFromHandleL(const RMessage2& aMessage)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ //Read-only flag, buffer length, buffer allocation
+ TBool readOnly = (aMessage.Int0() & 0x80000000) != 0;
+ const TInt KBufLen = aMessage.Int0() & 0x7FFFFFFF;
+ if(KBufLen <= 0)
+ {
+ __SQLLEAVE(KErrArgument);
+ }
+ HBufC8* buf = HBufC8::NewLC(KBufLen);
+ TPtr8 bufPtr = buf->Des();
+ aMessage.ReadL(1, bufPtr);
+ SQLPROFILER_REPORT_IPC(ESqlIpcRead, KBufLen);
+ if(KBufLen != bufPtr.Length())
+ {
+ __SQLLEAVE(KErrArgument);
+ }
+ RDesReadStream in(bufPtr);
+ TDes& dbFileName = Server().FileNameBuf();
+ TDes16& dbName = Server().GetBuf16L(KMaxFileName);
+ in >> dbFileName;
+ in >> dbName;
+ CleanupStack::PopAndDestroy(buf);
+ TSqlSrvFileData& fileData = Server().FileData();
+ fileData.SetFromHandleL(aMessage, dbFileName, EFalse, readOnly);
+ iDatabase->AttachDbL(fileData, dbName);
+ }
+
+/**
+Processes the request for detaching a secure or non-secure database.
+
+Usage of the IPC call arguments:
+Arg 0: [in] Logical database name length (counted in 16-bit characters).
+Arg 1: [in] Logical database name.
+
+@panic SqlDb 2 Client panic. iDatabase is NULL (the database object is not created yet).
+*/
+void CSqlSrvSession::DbDetachL(const RMessage2& aMessage)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ TInt logicalDbNameLen = aMessage.Int0();
+ if(logicalDbNameLen < 1 || logicalDbNameLen > KMaxFileName)
+ {
+ __SQLLEAVE(KErrBadName);
+ }
+ iDatabase->DetachDbL(ReadString16L(aMessage, 1, logicalDbNameLen));
+ }
+
+/**
+Reads a 16-bit string from the specified stream and returns it in zero-terminated
+8-bit format in aNameOut.
+If the string is of zero length then the substitute string provided will be used instead.
+
+@param aStrm The read stream
+@param aNameOut The output parameter that will contain the string read
+@param aEmptyNameSubstitute The substitute string to use if the string to be read from
+ the stream is zero length
+
+@leave KErrNoMemory, An out of memory condition has occurred;
+ KErrArgument, The UTF-16 to UTF-8 string conversion failed;
+ KErrBadName, The string has an invalid length;
+*/
+void CSqlSrvSession::ExtractNameL(RDesReadStream& aStrm, TDes8& aNameOut, const TDesC& aEmptyNameSubstitute)
+ {
+ TBool replace = EFalse;
+ TInt32 len;
+ aStrm >> len;
+
+ if(len == 0)
+ {
+ if(aEmptyNameSubstitute.Length() > 0)
+ {
+ len = aEmptyNameSubstitute.Length();
+ replace = ETrue;
+ }
+ else
+ {
+ __SQLLEAVE(KErrBadName);
+ }
+ }
+
+ if(len < 1 || len > KMaxFileName)
+ {
+ __SQLLEAVE(KErrBadName);
+ }
+
+ HBufC* buf = HBufC::NewLC(len + 1);
+ TPtr ptr = buf->Des();
+ if(replace)
+ {
+ ptr.Copy(aEmptyNameSubstitute);
+ }
+ else
+ {
+ aStrm >> ptr;
+ }
+ ptr.Append(0);
+
+ if(!::UTF16ZToUTF8Z(ptr, aNameOut))
+ {
+ __SQLLEAVE(KErrArgument);
+ }
+
+ CleanupStack::PopAndDestroy(buf);
+ }
+
+/**
+Processes the request for creating an IPC stream for accessing the content of a blob column.
+
+@param aMessage The client request wrapped in an IPC message
+
+@return The blob stream handle
+
+@leave KErrNoMemory, An out of memory condition has occurred;
+ KErrArgument, The IPC data buffer length is invalid, or the ROWID is invalid,
+ or UTF-16 to UTF-8 string conversion failed;
+ KErrBadDescriptor The transferred data is bigger than the specified length;
+ KErrBadName, The table name, column name or database name has an invalid length;
+ KErrPermissionDenied, The client does not have the required security capabilites for this operation;
+ Note that the function may also leave with some other system wide errors or
+ database specific errors categorised as ESqlDbError.
+
+@panic SqlDb 2 Client panic. The database object is not yet created (iDatabase is NULL)
+@panic SqlDb 3 Client panic. Failed to create a blob stream handle
+
+Usage of the IPC call arguments:
+Arg 0: [in] The length of the IPC data buffer
+Arg 1: [in] IPC data buffer containing blob parameters: table name, column name, rowid, mode, database name.
+Arg 2: [out] IPC buffer containing the blob stream handle
+*/
+TInt CSqlSrvSession::DbBlobSourceL(const RMessage2& aMessage)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+
+ iIpcStreams.AllocL();
+
+ TInt ipcPrmLen = aMessage.Int0();
+ if(ipcPrmLen < 1)
+ {
+ __SQLLEAVE(KErrArgument);
+ }
+ TDes8& ipcPrmDes = ReadString8ZL(aMessage, 1, ipcPrmLen);
+ RDesReadStream strm(ipcPrmDes);
+
+ TBuf8<KMaxFileName + 1> tblName;
+ ExtractNameL(strm, tblName);
+
+ TBuf8<KMaxFileName + 1> colName;
+ ExtractNameL(strm, colName);
+
+ TInt64 rowId;
+ strm >> rowId;
+ if(rowId == -1)
+ {
+ rowId = iDatabase->LastInsertedRowId();
+ }
+ if(rowId <= 0)
+ {
+ __SQLLEAVE(KErrArgument);
+ }
+
+ TInt32 tmp;
+ strm >> tmp;
+ TBool isReadOnly = tmp != 0;
+
+ TBuf8<KMaxFileName + 1> dbName;
+ ExtractNameL(strm, dbName, KMainDb16);
+
+ strm.Close();
+
+ // If the database is secure then check that the client has the required capabilities for the operation
+ TInt dbOpType = isReadOnly ? SQLITE_READ : SQLITE_UPDATE;
+ if(CSqlSrvDatabase::AuthorizeCallback(iDatabase, dbOpType, (char*)tblName.Ptr(), (char*)colName.Ptr(), (char*)dbName.Ptr(), '\0') != SQLITE_OK)
+ {
+ __SQLLEAVE(KErrPermissionDenied);
+ }
+
+ // Create the stream buffer
+ HBlobBuf* blobBuf = HBlobBuf::NewL(iDatabase->RawDbHandle(), dbName, tblName, colName, rowId, isReadOnly ? HBlobBuf::EReadOnly : HBlobBuf::EReadWrite);
+ blobBuf->PushL();
+
+ // Return the blob size to the client
+ TPckgBuf<TIpcStreamBuf> ipcBuf;
+ TInt size = blobBuf->SizeL();
+ ipcBuf().iExt = size;
+
+ // If this is a read stream then return the first client buffer-full of data
+ TInt len = 0;
+ if(isReadOnly && (size > 0))
+ {
+ len = Min(size, KIpcBufSize);
+ blobBuf->ReadL(ipcBuf().iData, len);
+ }
+
+ // Create the stream object
+ HIpcStream* ipcStream = new (ELeave) HIpcStream(blobBuf, len);
+ TInt strmHandle = iIpcStreams.Add(ipcStream);
+ __SQLPANIC_CLIENT(strmHandle > 0, aMessage, ESqlPanicBadHandle);
+ CleanupStack::Pop(blobBuf);
+
+ // Send the size and data to the client
+ aMessage.WriteL(2, ipcBuf);
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, size);
+
+ return strmHandle;
+ }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////// Statement operations //////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Processes the request for preparing a 8/16-bit SQL statement.
+
+@panic SqlDb 2 Client panic. iDatabase is NULL (the database object is not created yet).
+@panic SqlDb 3 Client panic. Internal error - invalid statement handle.
+
+Usage of the IPC call arguments:
+Arg 0: [out] Column count and parameter count
+Arg 1: [in] 8/16-bit character length of SQL statement
+Arg 2: [in] SQL statement
+*/
+TInt CSqlSrvSession::StmtPrepareL(const RMessage2& aMessage, TBool aIsText16)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ iStatements.AllocL();
+ TInt columnCount = -1;
+ TInt paramCount = -1;
+ TUint len = static_cast <TUint> (aMessage.Int1());
+ CSqlSrvStatement* stmt = aIsText16 ?
+ CSqlSrvStatement::NewLC(iDatabase->RawDbHandle(), ReadString16ZL(aMessage, 2, len), columnCount, paramCount) :
+ CSqlSrvStatement::NewLC(iDatabase->RawDbHandle(), ReadString8ZL(aMessage, 2, len), columnCount, paramCount);
+ TPckgBuf<TSqlIpcData> data;
+ data().iPrm1 = static_cast <TUint32> (columnCount);
+ data().iPrm2 = static_cast <TUint32> (paramCount);
+ aMessage.WriteL(0, data);
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, sizeof(TSqlIpcData));
+ TInt stmtHandle = iStatements.Add(stmt);
+ __SQLPANIC_CLIENT(stmtHandle > 0, aMessage, ESqlPanicBadHandle);
+ CleanupStack::Pop(stmt);
+ return stmtHandle;
+ }
+
+/**
+Processes the request for executing the SQL statement.
+
+@param aFunction ESqlSrvStmtExec, ESqlSrvStmtAsyncExec, ESqlSrvStmtBindExec, ESqlSrvStmtBindExecRowId, ESqlSrvStmtAsyncBindExec
+
+Usage of the IPC call arguments:
+Arg 0: [in] parameter buffer length in bytes (if aFunction == ESqlSrvStmtBindExec || aFunction == ESqlSrvStmtAsyncBindExec)
+Arg 1: [in] parameter buffer (if aFunction == ESqlSrvStmtBindExec || aFunction == ESqlSrvStmtAsyncBindExec)
+*/
+TInt CSqlSrvSession::StmtExecL(const RMessage2& aMessage, TInt aStmtHandle, TSqlSrvFunction aFunction)
+ {
+ CSqlSrvStatement& stmt = ::SqlSessObjFind(iStatements, aStmtHandle, aMessage);
+ if(aFunction == ESqlSrvStmtBindExec || aFunction == ESqlSrvStmtAsyncBindExec)
+ {
+ DoStmtBindL(aMessage, stmt);
+ }
+ __SQLLEAVE_IF_ERROR(stmt.Exec());
+ return iDatabase->LastChangesCount();
+ }
+
+/**
+Processes the request for moving the SQL statement on the next record.
+
+If the call does not fail, the only valid acceptable return codes should be KSqlAtRow and KSqlAtEnd.
+
+@panic SqlDb 7 In _DEBUG mode. The call completed with no error but the return code is not KSqlAtRow or KSqlAtEnd.
+
+Usage of the IPC call arguments:
+Arg 0: [in] parameter buffer length in bytes (if aFunction == ESqlSrvStmtBindNext)
+Arg 1: [in] parameter buffer (if aFunction == ESqlSrvStmtBindNext)
+Arg 2: [in] client side column buffer length in bytes
+Arg 3: [out] column buffer
+*/
+TInt CSqlSrvSession::StmtNextL(const RMessage2& aMessage, TInt aStmtHandle, TSqlSrvFunction aFunction)
+ {
+ CSqlSrvStatement& stmt = ::SqlSessObjFind(iStatements, aStmtHandle, aMessage);
+ if(aFunction == ESqlSrvStmtBindNext)
+ {
+ DoStmtBindL(aMessage, stmt);
+ }
+ TInt err = stmt.Next();
+ if(err == KSqlAtRow)
+ {
+ const RSqlBufFlat& bufFlat = stmt.ColumnValuesL();
+ TInt size = bufFlat.Size();
+ if(size > aMessage.Int2())
+ {
+ return size + KSqlClientBufOverflowCode;
+ }
+ aMessage.WriteL(3, bufFlat.BufDes());
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, size);
+ }
+ __SQLLEAVE_IF_ERROR(err);
+ __SQLASSERT(err == KSqlAtRow || err == KSqlAtEnd, ESqlPanicInternalError);
+ return err;
+ }
+
+/**
+Processes the request for retrieving the statement column or parameter names.
+
+If the client side buffer size is not big enough, the function returns the size + KSqlClientBufOverflowCode.
+In this case the client must increase the buffer and try again to get the buffer only.
+
+Usage of the IPC call arguments:
+Arg 0: [in] size of the client side buffer for the names (in bytes)
+Arg 1: [out] ipc buffer, column or parameter names
+*/
+TInt CSqlSrvSession::StmtNamesL(const RMessage2& aMessage, TInt aStmtHandle, TSqlSrvFunction aFunction)
+ {
+ CSqlSrvStatement& stmt = ::SqlSessObjFind(iStatements, aStmtHandle, aMessage);
+ const RSqlBufFlat& namesBuf = aFunction == ESqlSrvStmtParamNames ? stmt.ParamNamesL() : stmt.ColumnNamesL();
+ TInt size = namesBuf.Size();
+ if(size <= aMessage.Int0())
+ {
+ aMessage.WriteL(1, namesBuf.BufDes());
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, size);
+ return 0;
+ }
+ return size + KSqlClientBufOverflowCode;
+ }
+
+/**
+Processes the request for accessing a large column value as a stream of bytes/characters.
+
+Usage of the IPC call arguments:
+Arg 0: [in] column index (0 based)
+Arg 2: [out] ipc buffer, column source
+*/
+TInt CSqlSrvSession::StmtColumnSourceL(const RMessage2& aMessage, TInt aStmtHandle)
+ {
+ CSqlSrvStatement& stmt = ::SqlSessObjFind(iStatements, aStmtHandle, aMessage);
+ TInt columnIndex = aMessage.Int0();
+ TPtrC8 columnSource;
+ TInt err = stmt.ColumnSource(columnIndex, columnSource);
+ __SQLLEAVE_IF_ERROR(err);
+ HIpcReadBuf* ipcBuf = HIpcReadBuf::NewL(columnSource);
+ return NewOutputStreamL(aMessage, ipcBuf);
+ }
+
+/**
+Processes the request for setting a large parameter value from a stream of bytes or 8/16-bit characters.
+
+@panic SqlDb 3 Client panic. Internal error - invalid stream handle.
+
+Usage of the IPC call arguments:
+Arg 0: [in] parameter index (0 based)
+Arg 2: [out] ipc buffer, parameter source
+*/
+TInt CSqlSrvSession::StmtParamSinkL(const RMessage2& aMessage, TInt aStmtHandle, TSqlSrvFunction aFunction)
+ {
+ iIpcStreams.AllocL();
+ TInt parameterIndex = aMessage.Int0();
+ CSqlSrvStatement& stmt = ::SqlSessObjFind(iStatements, aStmtHandle, aMessage);
+ HSqlSrvStmtParamBuf::TDataType dataType = aFunction == ESqlSrvStmtBinParamSink ? HSqlSrvStmtParamBuf::EBinary : HSqlSrvStmtParamBuf::EText16;
+ HSqlSrvStmtParamBuf* paramBuf = stmt.GetParamBufL(parameterIndex, dataType, HSqlSrvStmtParamBuf::EBufIpcStream);
+ HIpcStream* ipcStream = new (ELeave) HIpcStream(paramBuf, 0);
+ TInt strmHandle = iIpcStreams.Add(ipcStream);
+ __SQLPANIC_CLIENT(strmHandle > 0, aMessage, ESqlPanicBadHandle);
+ return strmHandle;
+ }
+
+/**
+Usage of the IPC call arguments:
+Arg 0: [in] the client side buffer length in bytes
+Arg 1: [out] refers to a place where the buffer data will be copied to.
+*/
+void CSqlSrvSession::StmtGetBufFlatL(const RMessage2& aMessage, TInt aStmtHandle)
+ {
+ CSqlSrvStatement& stmt = ::SqlSessObjFind(iStatements, aStmtHandle, aMessage);
+ const RSqlBufFlat& bufFlat = stmt.BufFlatL(static_cast <TSqlBufFlatType> (aMessage.Int0()));
+ aMessage.WriteL(1, bufFlat.BufDes());
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, bufFlat.Size());
+ }
+
+/**
+Usage of the IPC call arguments:
+Arg 0: [in] column index
+Arg 1: [in] column buffer length in bytes
+Arg 2: [in/out] column buffer
+*/
+void CSqlSrvSession::StmtColumnValueL(const RMessage2& aMessage, TInt aStmtHandle)
+ {
+ CSqlSrvStatement& stmt = ::SqlSessObjFind(iStatements, aStmtHandle, aMessage);
+ TPtrC8 columnSource;
+ TInt columnIndex = aMessage.Int0();
+ TInt err = stmt.ColumnSource(columnIndex, columnSource);
+ __SQLLEAVE_IF_ERROR(err);
+ TInt len = aMessage.Int1();
+ if(columnSource.Length() > len)
+ {
+ TPtr8 ptr(const_cast <TUint8*> (columnSource.Ptr()), columnSource.Length(), columnSource.Length());
+ ptr.SetLength(len);
+ aMessage.WriteL(2, ptr);
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, len);
+ __SQLLEAVE(KErrOverflow);
+ }
+ else
+ {
+ aMessage.WriteL(2, columnSource);
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, len);
+ }
+ }
+
+/**
+Usage of the IPC call arguments:
+Arg 0: [in] parameter buffer length in bytes
+Arg 1: [in] parameter buffer
+*/
+void CSqlSrvSession::DoStmtBindL(const RMessage2& aMessage, CSqlSrvStatement& aStmt)
+ {
+ TInt prmLen = aMessage.Int0();
+ RSqlBufFlat& prmBuf = Server().GetFlatBufL(prmLen);
+ aMessage.ReadL(1, prmBuf.BufPtr());
+ SQLPROFILER_REPORT_IPC(ESqlIpcRead, prmLen);
+ aStmt.BindL(prmBuf);
+ }
+
+/**
+Usage of the IPC call arguments:
+Arg 0: [in] input buffer max length in 16-bit characters
+Arg 1: [in/out] buffer
+*/
+void CSqlSrvSession::StmtDeclColumnTypesL(const RMessage2& aMessage, TInt aStmtHandle)
+ {
+ CSqlSrvStatement& stmt = ::SqlSessObjFind(iStatements, aStmtHandle, aMessage);
+ HBufC* colTypesBuf = stmt.GetDeclColumnTypesL();
+ CleanupStack::PushL(colTypesBuf);
+ if(colTypesBuf->Des().Length() > aMessage.Int0())
+ {
+ __SQLLEAVE(KErrOverflow);
+ }
+ aMessage.WriteL(1, colTypesBuf->Des());
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, (colTypesBuf->Des().Length() * sizeof(TText)));
+ CleanupStack::PopAndDestroy(colTypesBuf);
+ }
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////// Helper methods /////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Creates a new output IPC stream object using the aStreamBuf parameter as a stream buffer (stream data source).
+
+This method immediately pushes aStreamBuf onto the cleanup stack before creating a new output IPC
+stream and so callers of this method should ensure that aStreamBuf is not already on the cleanup stack.
+
+Returns the handle of the created stream.
+
+@panic SqlDb 3 Client panic. Internal error - invalid stream handle.
+
+Usage of the IPC call arguments:
+Arg 2: [in/out] IPC buffer
+*/
+TInt CSqlSrvSession::NewOutputStreamL(const RMessage2& aMessage, MStreamBuf* aStreamBuf)
+ {
+ aStreamBuf->PushL();
+ iIpcStreams.AllocL();
+ TInt size = aStreamBuf->SizeL();
+ TPckgBuf<TIpcStreamBuf> ipcBuf;
+ if(size > 0) // read the first buffer-full
+ {
+ TInt len = Min(size, KIpcBufSize);
+ aStreamBuf->ReadL(ipcBuf().iData, len);
+ }
+ TInt handle = 0;
+ if(size < 0 || size > KIpcBufSize)
+ { // create the stream object
+ HIpcStream* ipcStream = new (ELeave) HIpcStream(aStreamBuf, KIpcBufSize);
+ handle = iIpcStreams.Add(ipcStream);
+ __SQLPANIC_CLIENT(handle > 0, aMessage, ESqlPanicBadHandle);
+ CleanupStack::Pop(aStreamBuf);
+ }
+ else // no more data to send
+ {
+ CleanupStack::PopAndDestroy(aStreamBuf);
+ }
+ if(size >= 0)
+ {
+ ipcBuf().iExt = size;
+ aMessage.WriteL(2, ipcBuf);
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, size);
+ }
+ return handle;
+ }
+
+/**
+Reads a 8-bit string with "aByteLen" bytes length, which is in "aArgNum" argument of aMessage.
+The string will be zero terminated after the "read" operation.
+Returns TDes8 reference pointing to the zero-terminated string.
+
+@leave KErrBadDescriptor The transferred data length is bigger than the aByteLen value
+
+@panic SqlDb 4 Client panic. Negative aByteLen value.
+*/
+TDes8& CSqlSrvSession::ReadString8ZL(const RMessage2& aMessage, TInt aArgNum, TInt aByteLen)
+ {
+ __SQLPANIC_CLIENT(aByteLen >= 0, aMessage, ESqlPanicBadArgument);
+ TDes8& buf = Server().GetBuf8L(aByteLen + 1);
+ aMessage.ReadL(aArgNum, buf);
+ SQLPROFILER_REPORT_IPC(ESqlIpcRead, aByteLen);
+ if(buf.Length() > aByteLen)
+ {
+ __SQLLEAVE(KErrBadDescriptor);
+ }
+ buf.Append(TChar(0));
+ return buf;
+ }
+
+/**
+Reads a 16-bit string with "aCharLen" character length, which is in "aArgNum" argument of aMessage.
+The string will be zero terminated after the "read" operation.
+Returns TDes16 reference pointing to the zero-terminated string.
+
+@leave KErrBadDescriptor The transferred data length is bigger than the aCharLen value
+
+@panic SqlDb 4 Client panic. Negative aCharLen value.
+*/
+TDes16& CSqlSrvSession::ReadString16ZL(const RMessage2& aMessage, TInt aArgNum, TInt aCharLen)
+ {
+ __SQLPANIC_CLIENT(aCharLen >= 0, aMessage, ESqlPanicBadArgument);
+ TDes16& buf = Server().GetBuf16L(aCharLen + 1);
+ aMessage.ReadL(aArgNum, buf);
+ SQLPROFILER_REPORT_IPC(ESqlIpcRead, (aCharLen * sizeof(TText)));
+ if(buf.Length() > aCharLen)
+ {
+ __SQLLEAVE(KErrBadDescriptor);
+ }
+ buf.Append(TChar(0));
+ return buf;
+ }
+
+/**
+Reads a 16-bit string with "aCharLen" character length, which is in "aArgNum" argument of aMessage.
+Returns TDes16 reference pointing to the string.
+
+@leave KErrBadDescriptor The transferred data length is bigger than the aCharLen value
+
+@panic SqlDb 4 Client panic. Negative aCharLen value.
+*/
+TDes16& CSqlSrvSession::ReadString16L(const RMessage2& aMessage, TInt aArgNum, TInt aCharLen)
+ {
+ __SQLPANIC_CLIENT(aCharLen >= 0, aMessage, ESqlPanicBadArgument);
+ TDes16& buf = Server().GetBuf16L(aCharLen);
+ aMessage.ReadL(aArgNum, buf);
+ SQLPROFILER_REPORT_IPC(ESqlIpcRead, (aCharLen * sizeof(TText)));
+ if(buf.Length() > aCharLen)
+ {
+ __SQLLEAVE(KErrBadDescriptor);
+ }
+ return buf;
+ }
+
+/**
+The method reads the message argument 1 data and constructs a CSqlSecurityPolicy object from the data.
+
+@param aMessage Client request encapsulated in RMessage2 object.
+
+@return A pointer to the created CSqlSecurityPolicy instance.
+
+@leave KErrArgument, if aMessage argument 0 length is 0 or negative (no security data);
+ KErrNoMemory, out of memory condition has occured.
+
+Usage of the IPC call arguments:
+Arg 2: [in] security policies buffer length in bytes if aFunction is ESqlSrvDbCreateSecure
+Arg 3: [in] security policies buffer if aFunction is ESqlSrvDbCreateSecure
+*/
+CSqlSecurityPolicy* CSqlSrvSession::InternalizeSecurityPolicyL(const RMessage2& aMessage)
+ {
+ // Leave if there is no security policy data
+ // The format of arg[2] is an unsigned int
+ // with the policy length shifted and concated to the config length
+ // the policy data is the first part of arg[3]
+ const TUint KConfigStrLenBitWidth = 16;
+ TInt securityPolicyLen = aMessage.Int2() >> KConfigStrLenBitWidth;
+ if(securityPolicyLen < 1)
+ {
+ __SQLLEAVE(KErrArgument);
+ }
+ TSecurityPolicy defaultPolicy(TSecurityPolicy::EAlwaysFail);
+ CSqlSecurityPolicy* dbPolicy = CSqlSecurityPolicy::NewLC(defaultPolicy);
+ RSqlBufFlat& bufFlat = dbPolicy->BufFlat();
+ if(securityPolicyLen > bufFlat.MaxSize())
+ {
+ __SQLLEAVE_IF_ERROR(bufFlat.ReAlloc(securityPolicyLen));
+ }
+ TPtr8& ptr = bufFlat.BufPtr();
+ aMessage.ReadL(3, ptr);
+ SQLPROFILER_REPORT_IPC(ESqlIpcRead, securityPolicyLen);
+ // trim off config data if any
+ TInt extraBytes = ptr.Length() - securityPolicyLen;
+ if(extraBytes > 0)
+ {
+ ptr.Delete(securityPolicyLen, extraBytes);
+ }
+ CleanupStack::Pop(dbPolicy);
+ return dbPolicy;
+ }
+
+/**
+Reports how many objects are allocated by the client.
+If the database connection is not in a test mode, the allocated memory cells count will be ignored.
+*/
+TInt CSqlSrvSession::CountResources()
+ {
+ return iStatements.Count() + iIpcStreams.Count() + (iDbResourceTestMode ? User::CountAllocCells() : 0);
+ }
+
+/**
+Extracts from aMessage:
+- function code;
+- stream or statement handle;
+The function will panic the client if aMessage contains bad function code or bad handle encoded in it.
+*/
+void CSqlSrvSession::Extract(const RMessage2& aMessage, TSqlSrvFunction& aFunction, TInt& aHandle)
+ {
+ TInt msgCode = aMessage.Function();
+ aFunction = static_cast <TSqlSrvFunction> (KSqlSrvFunctionMask & msgCode);
+ //All operations with code > ESqlSrvDbDelete require valid iDatabase object.
+ if(aFunction > ESqlSrvDbDelete)
+ {
+ __SQLPANIC_CLIENT(iDatabase != NULL, aMessage, ESqlPanicInvalidObj);
+ }
+ if(aFunction >= ESqlSrvStmtClose)
+ {
+ //Extracting handle and handle type from the message code
+ TSqlSrvHandleType handleType = static_cast <TSqlSrvHandleType> (msgCode & KSqlSrvHandleTypeMask);
+ aHandle = (msgCode & KSqlSrvHandleMask) >> KSqlSrvHandleShiftBits;
+ __SQLPANIC_CLIENT(aHandle > 0, aMessage, ESqlPanicBadArgument);
+ if(aFunction >= ESqlSrvStmtClose && aFunction < ESqlSrvStreamBase)
+ {
+ __SQLPANIC_CLIENT(handleType == ESqlSrvStatementHandle, aMessage, ESqlPanicBadArgument);
+ }
+ else if(aFunction > ESqlSrvStreamBase)
+ {
+ __SQLPANIC_CLIENT(handleType == ESqlSrvStreamHandle, aMessage, ESqlPanicBadArgument);
+ }
+ }
+ }
+
+/**
+The function reads aStmt column 0 value and copies it into the client buffer, accessed via aMessage argument.
+
+If an error occurs during the execution the function leaves with the error code.
+Possible non-leaving return values:
+ - KErrNone - the function has completed successfully;
+ - Positive return value - the length of the column, which means - the destination buffer is too small.
+ This return value is possible only with text or binary columns.
+
+Usage of the IPC call arguments:
+Arg 0: [in] (8/16-bit character length of SQL statement) | (expected column value type << 24).
+Arg 1: [in] SQL statement.
+Arg 2: [in] Byte max length of the receiving buffer
+Arg 3: [in/out] The receiving buffer
+*/
+TInt CSqlSrvSession::GetColumnValueL(const RMessage2& aMessage, CSqlSrvStatement& aStmt, TSqlColumnType aColType)
+ {
+ TInt rc = KErrNone;
+ switch(aColType)
+ {
+ case ESqlInt:
+ {
+ TInt val = aStmt.ColumnInt(0);
+ aMessage.WriteL(3, TPtrC8(reinterpret_cast <const TUint8*> (&val), sizeof(val)));
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, sizeof(val));
+ }
+ break;
+ case ESqlInt64:
+ {
+ TInt64 val = aStmt.ColumnInt64(0);
+ aMessage.WriteL(3, TPtrC8(reinterpret_cast <const TUint8*> (&val), sizeof(val)));
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, sizeof(val));
+ }
+ break;
+ case ESqlReal:
+ {
+ TReal val = aStmt.ColumnReal(0);
+ aMessage.WriteL(3, TPtrC8(reinterpret_cast <const TUint8*> (&val), sizeof(val)));
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, sizeof(val));
+ }
+ break;
+ case ESqlText:
+ case ESqlBinary:
+ default:
+ {
+ TPtrC8 val;
+ if(aColType == ESqlText)
+ {
+ TPtrC textVal = aStmt.ColumnText(0);
+ val.Set(reinterpret_cast <const TUint8*> (textVal.Ptr()), textVal.Length() * sizeof(TUint16));
+ }
+ else
+ {
+ val.Set(aStmt.ColumnBinary(0));
+ }
+ TInt len = val.Length();
+ if(len > aMessage.Int2())
+ {
+ rc = aColType == ESqlText ? (TUint)len / sizeof(TUint16) : len;
+ len = aMessage.Int2();
+ }
+ aMessage.WriteL(3, val.Left(len));
+ SQLPROFILER_REPORT_IPC(ESqlIpcWrite, len);
+ }
+ break;
+ }
+ return rc;
+ }