diff -r 000000000000 -r bde4ae8d615e os/persistentdata/persistentstorage/sql/SRC/Client/SqlStatementImpl.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/os/persistentdata/persistentstorage/sql/SRC/Client/SqlStatementImpl.cpp Fri Jun 15 03:10:57 2012 +0200
@@ -0,0 +1,872 @@
+// Copyright (c) 2005-2010 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:
+// NTT DOCOMO, INC - Fix for defect 1915 "SQL server panics when using long column type strings"
+//
+// Description:
+//
+
+#include "SqlStatementImpl.h" //CSqlStatementImpl
+#include "SqlDatabaseImpl.h" //CSqlDatabaseImpl::Session()
+
+//Constants
+
+_LIT(KTextKWD, "TEXT");
+_LIT(KCharKWD, "CHAR");
+_LIT(KClobKWD, "CLOB");
+
+_LIT(KBinaryKWD,"BINARY");
+_LIT(KBlobKWD, "BLOB");
+
+_LIT(KRealKWD, "REAL");
+_LIT(KFloatKWD, "FLOAT");
+_LIT(KDoubleKWD,"DOUBLE");
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////// RSqlLongColumnColl ////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+This "comparison" function is used for searching a particular column value, identified by aIndex, in the long column
+values collection.
+@param aIndex An integer pointer to long column index value
+@param aData A reference to particular elemt of the long column values collection
+@return True of the index of aData item is the same as *aIndex, false otherwise
+@panic SqlDb 4 In _DEBUG mode, aIndex is NULL.
+@panic SqlDb 4 In _DEBUG mode, *aIndex value is negative.
+*/
+TBool RSqlLongColumnColl::TData::Compare(const TInt* aIndex, const RSqlLongColumnColl::TData& aData)
+ {
+ __ASSERT_DEBUG(aIndex != NULL, __SQLPANIC2(ESqlPanicBadArgument));
+ __ASSERT_DEBUG(*aIndex >= 0, __SQLPANIC2(ESqlPanicBadArgument));
+ return *aIndex == aData.iIndex;
+ }
+
+/**
+Reads a long column value, identified by aColumnIndex parameter, from the server and stores the value in the collection.
+@param aReader A RSqlLongColumnColl::TColumnReader object, which performs the "read column value" operation.
+@param aColumnIndex Column index
+@param aColumnSize The column size in bytes
+@panic SqlDb 4 In _DEBUG mode, aColumnIndex value is negative.
+@panic SqlDb 4 In _DEBUG mode, aColumnSize is less than KSqlMaxDesLen (not a long column value)
+@return KErrNone The call has completed successfully;
+ KErrNoMemory Out of memory;
+ Note that other system-wide or database specific error codes may also be returned.
+*/
+TInt RSqlLongColumnColl::Append(RSqlLongColumnColl::TColumnReader& aReader, TInt aColumnIndex, TInt aColumnSize)
+ {
+ __ASSERT_DEBUG(aColumnIndex >= 0, __SQLPANIC(ESqlPanicBadArgument));
+ __ASSERT_DEBUG(aColumnSize >= KSqlMaxDesLen, __SQLPANIC(ESqlPanicBadArgument));
+ LONGCOL_INVARIANT();
+ HBufC8* colBuf = HBufC8::New(aColumnSize);
+ if(!colBuf)
+ {
+ return KErrNoMemory;
+ }
+ TPtr8 ptr = colBuf->Des();
+ TInt err = aReader.Read(aColumnIndex, ptr);
+ if(err == KErrNone)
+ {
+ err = iValues.Append(RSqlLongColumnColl::TData(aColumnIndex, colBuf));
+ }
+ if(err != KErrNone)
+ {
+ delete colBuf;
+ }
+ LONGCOL_INVARIANT();
+ return err;
+ }
+
+#ifdef _DEBUG
+/**
+RSqlLongColumnColl invariant.
+The collection cannot have two column values with the same column index.
+The collection cannot have NULL column value, or negative column index.
+*/
+void RSqlLongColumnColl::Invariant() const
+ {
+ for(TInt i=iValues.Count()-1;i>=0;--i)
+ {
+ const RSqlLongColumnColl::TData& data = iValues[i];
+ __ASSERT_DEBUG(data.iIndex >= 0, __SQLPANIC(ESqlPanicInternalError));
+ __ASSERT_DEBUG(data.iData != NULL, __SQLPANIC(ESqlPanicInternalError));
+ for(TInt j=i-1;j>=0;--j)
+ {
+ __ASSERT_DEBUG(data.iIndex != iValues[j].iIndex, __SQLPANIC(ESqlPanicInternalError));
+ }
+ }
+ }
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////// CSqlStatementImpl ////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+RSqlLongColumnColl::TColumnReader derived class, which implements the pure virtual RSqlLongColumnColl::TColumnReader::Read().
+The class is used for retrieving long column values from the server.
+@internalComponent
+*/
+NONSHARABLE_STRUCT(TSqlLongColumnReader) : public RSqlLongColumnColl::TColumnReader
+ {
+ TSqlLongColumnReader(RSqlStatementSession& aStmtSession) :
+ iStmtSession(aStmtSession)
+ {
+ }
+ virtual TInt Read(TInt aColumnIndex, TDes8& aBuf)
+ {
+ return iStmtSession.ReadColumnValue(aColumnIndex, aBuf);
+ }
+ RSqlStatementSession iStmtSession;
+ };
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////// CSqlStatementImpl ////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Frees the allocated memory and other resources.
+*/
+CSqlStatementImpl::~CSqlStatementImpl()
+ {
+ iDeclaredColumnTypes.Close();
+ iLongColumnColl.Close();
+ iParamValueBuf.Close();
+ iParamNameBuf.Close();
+ iColumnValueBuf.Close();
+ iColumnNameBuf.Close();
+ iSqlStmtSession.Close();
+ }
+
+
+
+/**
+Resets the prepared SQL statement back to its initial state and makes it ready for re-execution.
+The parameters of the SQL statement retain their values.
+If CSqlStatementImpl object processes parametrized SQL statement, the parameter values can be bound after
+the Reset() call.
+
+The method sets the internal object's state to CSqlStatementImpl::EUnknown. The column data accessors
+cannot be used until the next successful Next() call.
+
+@return KSqlErrStmtExpired, statement expired (if new functions or collating sequences are
+ registered or if an authorizer function is added or changed);
+ KErrNone, the operation has completed successfully.
+
+@see RSqlStatement::Reset()
+*/
+TInt CSqlStatementImpl::Reset()
+ {
+ iState = CSqlStatementImpl::EUnknown;
+ iLongColumnColl.Reset();
+ if(iParamCnt > 0)
+ {
+ iParamValueBuf.ResetAndMinimize();
+ }
+ return iSqlStmtSession.Reset();
+ }
+
+/**
+Executes the prepared DDL/DML SQL statement.
+
+If the SQL statement contains parameters, their values will be bound right before the execution.
+
+The method sets the internal object's state to CSqlStatementImpl::EUnknown. The column data accessors
+cannot be used until the next successful Next() call.
+
+@return >=0, The operation has completed successfully. The number of database rows that were
+ changed/inserted/deleted by the most recently completed DDL/DML sql statement.
+ Exception: If the executed statement is "DELETE FROM
", then the function returns 0
+ if the operation has completed successfully (disregarding the number of the deleted rows);
+ KSqlErrStmtExpired, statement has expired (if new functions or collating sequences are
+ registered or if an authorizer function is added or changed);
+ KErrNoMemory, an out of memory condition has occurred.
+ Note that database specific errors categorised as ESqlDbError, and
+ other system-wide error codes may also be returned.
+
+@see RSqlStatement::Exec()
+*/
+TInt CSqlStatementImpl::Exec()
+ {
+ iState = CSqlStatementImpl::EUnknown;
+ TInt rc = 0;
+ if(iBound)
+ {
+ rc = iSqlStmtSession.Exec();
+ }
+ else
+ {
+ rc = iSqlStmtSession.BindExec(iParamValueBuf);
+ iBound = ETrue;
+ iParamValueBuf.ResetAndMinimize();
+ }
+ return rc;
+ }
+
+/**
+Executes the prepared DDL/DML SQL statement asynchronously.
+
+If the SQL statement contains parameters, their values will be bound right before the execution.
+
+The method sets the internal object's state to CSqlStatementImpl::EUnknown. The column data accessors
+cannot be used until the next successful Next() call.
+
+@param aStatus Completion status of asynchronous request, one of the following:
+ >=0, The operation has completed successfully. The number of database rows that were
+ changed/inserted/deleted by the most recently completed DDL/DML sql statement.
+ Exception: If the executed statement is "DELETE FROM ", then the function returns 0
+ if the operation has completed successfully (disregarding the number of the deleted rows);
+ KSqlErrStmtExpired, the SQL statement has expired (if new functions or
+ collating sequences have been registered or if an
+ authorizer function has been added or changed);
+ KErrNoMemory, an out of memory condition has occurred - the statement
+ will be reset.
+ Note that aStatus may be set with database specific errors categorised as ESqlDbError,
+ and other system-wide error codes.
+
+
+@see RSqlStatement::Exec()
+*/
+void CSqlStatementImpl::Exec(TRequestStatus& aStatus)
+ {
+ iState = CSqlStatementImpl::EUnknown;
+ if(iBound)
+ {
+ iSqlStmtSession.Exec(aStatus);
+ }
+ else
+ {
+ iSqlStmtSession.BindExec(iParamValueBuf, aStatus);
+ iBound = ETrue;
+ //Here: it is not possible to reset iParamValueBuf for "safety", because this is an asynchronous call
+ // and the buffer content has to be preserved until the operation completes.
+ }
+ }
+
+/**
+Retrieves a record.
+
+If the prepared SQL statement is a "SELECT" statement, and is expected to
+return a set of records, then this function can be used to retrieve that record data.
+
+If the SQL statement contains parameters, then their values must be bound before
+this function is called.
+
+If the call to this function completes successfully, i.e. it returns
+with KSqlAtRow, then this CSqlStatementImpl object contains the record data, and
+this data will remain valid for access until another call is made to any
+CSqlStatementImpl function.
+
+The record data can be accessed using the following functions:
+- CSqlStatementImpl::ColumnType()
+- CSqlStatementImpl::ColumnSize()
+- CSqlStatementImpl::Column()
+
+@return KSqlAtRow, the record data is ready for processing by the caller;
+ KSqlAtEnd, there is no more record data;
+ KSqlErrBusy, the database file is locked;
+ KErrNoMemory, an out of memory condition has occurred - the statement
+ will be reset;
+ KSqlErrGeneral, a run-time error has occured - this function must not
+ be called again;
+ KSqlErrMisuse, this function has been called after a previous call
+ returned KSqlAtEnd or KSqlErrGeneral.
+ KSqlErrStmtExpired, the SQL statement has expired (if new functions or
+ collating sequences have been registered or if an
+ authorizer function has been added or changed);
+
+@see RSqlStatement::Next()
+*/
+TInt CSqlStatementImpl::Next()
+ {
+ iLongColumnColl.Reset();
+ iColumnValueBuf.ResetAndMinimize();
+ iState = CSqlStatementImpl::EUnknown;
+ TInt err = KErrNone;
+ if(iBound)
+ {
+ err = iSqlStmtSession.Next(iColumnValueBuf);
+ }
+ else
+ {
+ err = iSqlStmtSession.BindNext(iParamValueBuf, iColumnValueBuf);
+ iBound = ETrue;
+ iParamValueBuf.ResetAndMinimize();
+ }
+ iColumnValBufIt.Set(iColumnValueBuf);
+ if(err == KSqlAtRow)
+ {
+ iState = CSqlStatementImpl::EAtRow;
+ }
+ return err;
+ }
+
+/**
+Implements RSqlStatement::BindNull().
+
+@panic SqlDb 5 Parameter index out of bounds.
+
+@see RSqlStatement::BindNull()
+*/
+TInt CSqlStatementImpl::BindNull(TInt aParamIndex)
+ {
+ __ASSERT_ALWAYS((TUint)aParamIndex < (TUint)iParamCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ iBound = EFalse;
+ iParamValBufIt.MoveTo(aParamIndex);
+ iParamValBufIt.SetNull();
+ return KErrNone;
+ }
+
+/**
+Implements RSqlStatement::BindInt().
+
+@panic SqlDb 5 Parameter index out of bounds.
+
+@see RSqlStatement::BindInt()
+*/
+TInt CSqlStatementImpl::BindInt(TInt aParamIndex, TInt aParamValue)
+ {
+ __ASSERT_ALWAYS((TUint)aParamIndex < (TUint)iParamCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ iBound = EFalse;
+ iParamValBufIt.MoveTo(aParamIndex);
+ return iParamValBufIt.SetInt(aParamValue);
+ }
+
+/**
+Implements RSqlStatement::BindInt64().
+
+@panic SqlDb 5 Parameter index out of bounds.
+
+@see RSqlStatement::BindInt64()
+*/
+TInt CSqlStatementImpl::BindInt64(TInt aParamIndex, TInt64 aParamValue)
+ {
+ __ASSERT_ALWAYS((TUint)aParamIndex < (TUint)iParamCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ iBound = EFalse;
+ iParamValBufIt.MoveTo(aParamIndex);
+ return iParamValBufIt.SetInt64(aParamValue);
+ }
+
+/**
+Implements RSqlStatement::BindReal().
+
+@panic SqlDb 5 Parameter index out of bounds.
+
+@see RSqlStatement::BindReal()
+*/
+TInt CSqlStatementImpl::BindReal(TInt aParamIndex, TReal aParamValue)
+ {
+ __ASSERT_ALWAYS((TUint)aParamIndex < (TUint)iParamCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ iBound = EFalse;
+ iParamValBufIt.MoveTo(aParamIndex);
+ return iParamValBufIt.SetReal(aParamValue);
+ }
+
+/**
+Implements RSqlStatement::BindText().
+
+@panic SqlDb 5 Parameter index out of bounds.
+
+@see RSqlStatement::BindText()
+*/
+TInt CSqlStatementImpl::BindText(TInt aParamIndex, const TDesC& aParamText)
+ {
+ __ASSERT_ALWAYS((TUint)aParamIndex < (TUint)iParamCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ iBound = EFalse;
+ iParamValBufIt.MoveTo(aParamIndex);
+ return iParamValBufIt.SetText(aParamText);
+ }
+
+/**
+Implements RSqlStatement::BindBinary().
+
+@panic SqlDb 5 Parameter index out of bounds.
+
+@see RSqlStatement::BindBinary()
+*/
+TInt CSqlStatementImpl::BindBinary(TInt aParamIndex, const TDesC8& aParamData)
+ {
+ __ASSERT_ALWAYS((TUint)aParamIndex < (TUint)iParamCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ iBound = EFalse;
+ iParamValBufIt.MoveTo(aParamIndex);
+ return iParamValBufIt.SetBinary(aParamData);
+ }
+
+/**
+Implements RSqlStatement::BindZeroBlob().
+
+@panic SqlDb 5 Parameter index out of bounds.
+
+@see RSqlStatement::BindZeroBlob()
+*/
+TInt CSqlStatementImpl::BindZeroBlob(TInt aParamIndex, TInt aBlobSize)
+ {
+ __ASSERT_ALWAYS((TUint)aParamIndex < (TUint)iParamCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ iBound = EFalse;
+ iParamValBufIt.MoveTo(aParamIndex);
+ return iParamValBufIt.SetZeroBlob(aBlobSize);
+ }
+
+/**
+Implements RSqlStatement::ColumnType().
+
+@panic SqlDb 5 Column index out of bounds.
+@panic SqlDb 11 Statement cursor not positioned on a row.
+
+@see RSqlStatement::ColumnType().
+*/
+TSqlColumnType CSqlStatementImpl::ColumnType(TInt aColumnIndex)
+ {
+ __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
+ iColumnValBufIt.MoveTo(aColumnIndex);
+ return static_cast (iColumnValBufIt.Type());
+ }
+
+/**
+Implements RSqlStatement::DeclaredColumnType().
+
+@param aColumnIndex The index value identifying the column. This is 0 for the first column.
+@param aColumnType Output parameter. Upon completion this will contain the type of the column.
+
+@return KErrNone, the operation completed successfully;
+ KErrNoMemory, an out of memory condition has occurred.
+ One of the other system-wide error codes may also be returned.
+
+@panic SqlDb 5 Column index out of bounds.
+
+@see RSqlStatement::DeclaredColumnType().
+*/
+TInt CSqlStatementImpl::DeclaredColumnType(TInt aColumnIndex, TSqlColumnType& aColumnType)
+ {
+ __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ if(iDeclaredColumnTypes.Count() == 0) //initialise iDeclaredColumnTypes array if necessary
+ {
+ RSqlBufFlat declaredColumnTypeBuf;
+ TInt err = declaredColumnTypeBuf.SetCount(iColumnCnt);
+ if(err != KErrNone)
+ {
+ declaredColumnTypeBuf.Close();
+ return err;
+ }
+
+ //Resize buffer to minimise the chance that two IPC calls are required to get all the column type name data.
+ //Allocates enough space to contain the header cells (already created by calling SetCount()) and a data buffer
+ //which assumes an average column type name length of 20 characters plus 8-byte alignment padding
+ const TInt KBufSizePerColumn = 48;
+ TInt newSize = declaredColumnTypeBuf.Size() + iColumnCnt*KBufSizePerColumn;
+
+ err = declaredColumnTypeBuf.ReAlloc(newSize);
+ if(err != KErrNone)
+ {
+ declaredColumnTypeBuf.Close();
+ return err;
+ }
+
+ err = iSqlStmtSession.GetDeclColumnTypes(declaredColumnTypeBuf);
+ if(err != KErrNone)
+ {
+ declaredColumnTypeBuf.Close();
+ return err;
+ }
+
+ err = iDeclaredColumnTypes.Reserve(iColumnCnt);//We know what the array size should be - iColumnCnt
+ if(err != KErrNone)
+ {
+ declaredColumnTypeBuf.Close();
+ return err;
+ }
+
+ //Iterate over the column type names buffer and map each column type name to one of the TSqlColumnType enum item values.
+ TSqlBufRIterator declColumnTypeBufIt;
+ declColumnTypeBufIt.Set(declaredColumnTypeBuf);
+ TInt colIdx = 0;
+ while(declColumnTypeBufIt.Next())
+ {
+ TPtrC colTypeName(declColumnTypeBufIt.Text());
+ TSqlColumnType colType = ESqlInt;
+ if(colTypeName.FindF(KCharKWD) >= 0 || colTypeName.FindF(KTextKWD) >= 0 || colTypeName.FindF(KClobKWD) >= 0)
+ {
+ colType = ESqlText;
+ }
+ else if(colTypeName.FindF(KBinaryKWD) >= 0 || colTypeName.FindF(KBlobKWD) >= 0)
+ {
+ colType = ESqlBinary;
+ }
+ else if(colTypeName.FindF(KRealKWD) >= 0 || colTypeName.FindF(KFloatKWD) >= 0 || colTypeName.FindF(KDoubleKWD) >= 0)
+ {
+ colType = ESqlReal;
+ }
+ err = iDeclaredColumnTypes.Append(colType);
+ __ASSERT_DEBUG(err == KErrNone, __SQLPANIC(ESqlPanicInternalError));//memory for the array elements has been reserved already
+ ++colIdx;
+ } //end of - while(declColumnTypeBufIt.Next())
+ __ASSERT_DEBUG(colIdx == iColumnCnt, __SQLPANIC(ESqlPanicInternalError));
+ declaredColumnTypeBuf.Close();
+ } //end of - if(iDeclaredColumnTypes.Count() == 0 && iColumnCnt > 0)
+ aColumnType = iDeclaredColumnTypes[aColumnIndex];
+ return KErrNone;
+ }
+
+/**
+Implements RSqlStatement::ColumnSize().
+
+@panic SqlDb 5 Column index out of bounds.
+@panic SqlDb 11 Statement cursor not positioned on a row
+
+@see RSqlStatement::ColumnSize().
+*/
+TInt CSqlStatementImpl::ColumnSize(TInt aColumnIndex)
+ {
+ __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
+ iColumnValBufIt.MoveTo(aColumnIndex);
+ return iColumnValBufIt.Size();
+ }
+
+/**
+Implements RSqlStatement::ColumnInt().
+
+@panic SqlDb 5 Column index out of bounds.
+@panic SqlDb 11 Statement cursor not positioned on a row
+
+@see RSqlStatement::ColumnInt().
+*/
+TInt CSqlStatementImpl::ColumnInt(TInt aColumnIndex)
+ {
+ __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
+ iColumnValBufIt.MoveTo(aColumnIndex);
+ __ASSERT_DEBUG(iColumnValBufIt.IsPresent(), __SQLPANIC(ESqlPanicValueNotPresent));
+ return iColumnValBufIt.Int();
+ }
+
+/**
+Implements RSqlStatement::ColumnInt64().
+
+@panic SqlDb 5 Column index out of bounds.
+@panic SqlDb 11 Statement cursor not positioned on a row
+
+@see RSqlStatement::ColumnInt64().
+*/
+TInt64 CSqlStatementImpl::ColumnInt64(TInt aColumnIndex)
+ {
+ __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
+ iColumnValBufIt.MoveTo(aColumnIndex);
+ __ASSERT_DEBUG(iColumnValBufIt.IsPresent(), __SQLPANIC(ESqlPanicValueNotPresent));
+ return iColumnValBufIt.Int64();
+ }
+
+/**
+Implements RSqlStatement::ColumnReal().
+
+@panic SqlDb 5 Column index out of bounds.
+@panic SqlDb 11 Statement cursor not positioned on a row
+
+@see RSqlStatement::ColumnReal().
+*/
+TReal CSqlStatementImpl::ColumnReal(TInt aColumnIndex)
+ {
+ __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
+ iColumnValBufIt.MoveTo(aColumnIndex);
+ __ASSERT_DEBUG(iColumnValBufIt.IsPresent(), __SQLPANIC(ESqlPanicValueNotPresent));
+ return iColumnValBufIt.Real();
+ }
+
+/**
+Return a text (16 bit) descriptor to a text column identified by aColumnIndex.
+
+@param aColumnIndex Column index
+@param aPtr An output parameter which will be set to point to the column data.
+
+@return KErrNone, if the function completes successfully,
+ otherwise one of the other system-wide error codes.
+
+@panic SqlDb 5 Column index out of bounds.
+@panic SqlDb 11 Statement cursor not positioned on a row
+*/
+TInt CSqlStatementImpl::ColumnText(TInt aColumnIndex, TPtrC& aPtr)
+ {
+ __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
+ iColumnValBufIt.MoveTo(aColumnIndex);
+ if(iColumnValBufIt.IsPresent())
+ {
+ aPtr.Set(iColumnValBufIt.Text());
+ return KErrNone;
+ }
+ //The text column value has not been transferred to the client side if its length is >= KSqlMaxDesLen characters.
+ //In this case an additional call to the server is made to get the column value.
+ //The column value is stored in a separate collection (iLongColumnColl), because if iColumnValueBuf gets reallocated,
+ //the client can get a dangling pointer to some of the located in iColumnValueBuf text/binary column values.
+ if(iColumnValBufIt.Type() != ESqlText)
+ {
+ aPtr.Set(KNullDesC);
+ return KErrNone;
+ }
+ if(!iLongColumnColl.IsPresent(aColumnIndex))
+ {
+ TSqlLongColumnReader colReader(iSqlStmtSession);
+ TInt err = iLongColumnColl.Append(colReader, aColumnIndex, iColumnValBufIt.Size() * sizeof(TUint16));
+ if(err != KErrNone)
+ {
+ return err;
+ }
+ }
+ aPtr.Set(iLongColumnColl.Text(aColumnIndex));
+ return KErrNone;
+ }
+
+/**
+Copies the content of a text column, identified by aColumnIndex, to the place refered by aDest parameter.
+
+If the destination buffer is not big enough, the function will copy as much data as possible and will
+return KErrOverflow.
+
+@param aColumnIndex Column index
+@param aDest Refers to the place where the column data will be copied.
+
+@return KErrNone, if the function completes successfully,
+ otherwise one of the other system-wide error codes.
+
+@panic SqlDb 5 Column index out of bounds.
+@panic SqlDb 11 Statement cursor not positioned on a row
+*/
+TInt CSqlStatementImpl::ColumnText(TInt aColumnIndex, TDes& aDest)
+ {
+ __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
+ iColumnValBufIt.MoveTo(aColumnIndex);
+ TInt err = KErrNone;
+ //The text column value has not been transferred to the client side if its length is >= KSqlMaxDesLen characters.
+ //In this case an additional call to the server is made to get the column value.
+ if(!iColumnValBufIt.IsPresent())
+ {
+ if(iColumnValBufIt.Type() != ESqlText)
+ {
+ aDest.Zero();
+ return err;
+ }
+ TPtr8 ptr(reinterpret_cast (const_cast (aDest.Ptr())), aDest.MaxLength() * sizeof(TUint16));
+ err = iSqlStmtSession.ReadColumnValue(aColumnIndex, ptr);
+ switch(err)
+ {
+ case KErrNone:
+ case KErrOverflow:
+ aDest.SetLength(ptr.Length() / sizeof(TUint16));
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ TPtrC src = iColumnValBufIt.Text();
+ TInt len = src.Length();
+ if(len > aDest.MaxLength())
+ {
+ len = aDest.MaxLength();
+ err = KErrOverflow;
+ }
+ aDest.Copy(src.Ptr(), len);
+ }
+ return err;
+ }
+
+/**
+Return a binary (8 bit) descriptor to a binary column identified by aColumnIndex.
+
+@param aColumnIndex Column index
+@param aPtr An output parameter which will be set to point to the column data.
+
+@return KErrNone, if the function completes successfully,
+ otherwise one of the other system-wide error codes.
+
+@panic SqlDb 5 Column index out of bounds.
+@panic SqlDb 11 Statement cursor not positioned on a row
+*/
+TInt CSqlStatementImpl::ColumnBinary(TInt aColumnIndex, TPtrC8& aPtr)
+ {
+ __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
+ iColumnValBufIt.MoveTo(aColumnIndex);
+ if(iColumnValBufIt.IsPresent())
+ {
+ aPtr.Set(iColumnValBufIt.Binary());
+ return KErrNone;
+ }
+ //The binary column value has not been transferred to the client side if its length is >= KSqlMaxDesLen characters.
+ //In this case an additional call to the server is made to get the column value.
+ //The column value is stored in a separate collection (iLongColumnColl), because if iColumnValueBuf gets reallocated,
+ //the client can get a dangling pointer to some of the located in iColumnValueBuf text/binary column values.
+ if(iColumnValBufIt.Type() != ESqlBinary)
+ {
+ aPtr.Set(KNullDesC8);
+ return KErrNone;
+ }
+ if(!iLongColumnColl.IsPresent(aColumnIndex))
+ {
+ TSqlLongColumnReader colReader(iSqlStmtSession);
+ TInt err = iLongColumnColl.Append(colReader, aColumnIndex, iColumnValBufIt.Size());
+ if(err != KErrNone)
+ {
+ return err;
+ }
+ }
+ aPtr.Set(iLongColumnColl.Binary(aColumnIndex));
+ return KErrNone;
+ }
+
+/**
+Copies the content of a binary column, identified by aColumnIndex, to the place refered by aDest parameter.
+
+If the destination buffer is not big enough, the function will copy as much data as possible and will
+return KErrOverflow.
+
+@param aColumnIndex Column index
+@param aDest Refers to the place where the column data will be copied.
+
+@return KErrNone, if the function completes successfully,
+ otherwise one of the other system-wide error codes.
+
+@panic SqlDb 5 Column index out of bounds.
+@panic SqlDb 11 Statement cursor not positioned on a row
+*/
+TInt CSqlStatementImpl::ColumnBinary(TInt aColumnIndex, TDes8& aDest)
+ {
+ __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
+ __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
+ iColumnValBufIt.MoveTo(aColumnIndex);
+ TInt err = KErrNone;
+ //The binary column value has not been transferred to the client side if its length is >= KSqlMaxDesLen bytes.
+ //In this case an additional call to the server is made to get the column value.
+ if(!iColumnValBufIt.IsPresent())
+ {
+ if(iColumnValBufIt.Type() != ESqlBinary)
+ {
+ aDest.Zero();
+ return err;
+ }
+ err = iSqlStmtSession.ReadColumnValue(aColumnIndex, aDest);
+ }
+ else
+ {
+ TPtrC8 src = iColumnValBufIt.Binary();
+ TInt len = src.Length();
+ if(len > aDest.MaxLength())
+ {
+ len = aDest.MaxLength();
+ err = KErrOverflow;
+ }
+ aDest.Copy(src.Ptr(), len);
+ }
+ return err;
+ }
+
+/**
+ * Obtain the name of a column after performing a query.
+ *
+ * @param aColumnIndex Column index
+ * @param aNameDest Descriptor which will be set to column name
+ * @return KErrNone if successfull or one of the system-wide error codes on error
+ */
+TInt CSqlStatementImpl::ColumnName(TInt aColumnIndex, TPtrC& aNameDest)
+ {
+ return Index2Name(aColumnIndex, iColumnNameBuf, iColumnCnt, ESqlSrvStmtColumnNames, iColumnNameBufPresent, aNameDest);
+ }
+
+/**
+ * Obtain the name of a parameter after preparing a DML query.
+ *
+ * @param aParamIndex Parameter index
+ * @param aNameDest Descriptor which will be set to column name
+ * @return KErrNone if successfull or one of the system-wide error codes on error
+ */
+TInt CSqlStatementImpl::ParameterName(TInt aParamIndex, TPtrC& aNameDest)
+ {
+ return Index2Name(aParamIndex, iParamNameBuf, iParamCnt, ESqlSrvStmtParamNames, iParamNameBufPresent, aNameDest);
+ }
+
+
+TInt CSqlStatementImpl::Name2Index(const TDesC& aName, RSqlBufFlat& aNameBufFlat, TInt aCount, TSqlSrvFunction aFunction, TBool& aPresent)
+ {
+ if(aCount == 0)
+ {
+ return KErrNotFound;
+ }
+ TInt err = CheckNameBufPresent(aPresent, aNameBufFlat, aCount, aFunction);
+ if ( err != KErrNone )
+ {
+ return err;
+ }
+ TInt idx = -1;
+ aPresent = ETrue;
+ TSqlBufRIterator nameBufIt;
+ nameBufIt.Set(aNameBufFlat);
+ while(nameBufIt.Next())
+ {
+ ++idx;
+ if(::CompareNoCase16(aName, nameBufIt.Text()) == 0)
+ {
+ return idx;
+ }
+ }
+ return KErrNotFound;
+ }
+
+
+TInt CSqlStatementImpl::Index2Name(TInt aIndex, RSqlBufFlat& aNameBufFlat, TInt aCount, TSqlSrvFunction aFunction, TBool& aPresent, TPtrC& aColName)
+ {
+ if( aCount == 0 || aIndex < 0 || aIndex >= aCount )
+ {
+ return KErrNotFound;
+ }
+ TInt err = CheckNameBufPresent(aPresent, aNameBufFlat, aCount, aFunction);
+ if ( err != KErrNone )
+ {
+ return err;
+ }
+ aPresent = ETrue;
+ TSqlBufRIterator nameBufIt;
+ nameBufIt.Set(aNameBufFlat);
+ nameBufIt.MoveTo(aIndex);
+ aColName.Set(nameBufIt.Text());
+ return KErrNone;
+ }
+
+/**
+Ensures that the specified names buffer is present on the client side.
+Name buffers are used for transporting parameter and column names.
+
+@return KErrNone if successfull or one of the system-wide error codes on error
+@internalComponent
+*/
+TInt CSqlStatementImpl::CheckNameBufPresent(TBool& aPresent, RSqlBufFlat& aNameBufFlat, TInt aCount, TSqlSrvFunction aFunction)
+ {
+ if(!aPresent)
+ {
+ aNameBufFlat.Close();
+ TInt err = aNameBufFlat.SetCount(aCount);
+ if(err != KErrNone)
+ {
+ return err;
+ }
+ err = iSqlStmtSession.GetNames(aFunction, aNameBufFlat);
+ if(err != KErrNone)
+ {
+ return err;
+ }
+ }
+ return KErrNone;
+ }
+