1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sql/SRC/Client/SqlStatementImpl.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,872 @@
1.4 +// Copyright (c) 2005-2010 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +// NTT DOCOMO, INC - Fix for defect 1915 "SQL server panics when using long column type strings"
1.16 +//
1.17 +// Description:
1.18 +//
1.19 +
1.20 +#include "SqlStatementImpl.h" //CSqlStatementImpl
1.21 +#include "SqlDatabaseImpl.h" //CSqlDatabaseImpl::Session()
1.22 +
1.23 +//Constants
1.24 +
1.25 +_LIT(KTextKWD, "TEXT");
1.26 +_LIT(KCharKWD, "CHAR");
1.27 +_LIT(KClobKWD, "CLOB");
1.28 +
1.29 +_LIT(KBinaryKWD,"BINARY");
1.30 +_LIT(KBlobKWD, "BLOB");
1.31 +
1.32 +_LIT(KRealKWD, "REAL");
1.33 +_LIT(KFloatKWD, "FLOAT");
1.34 +_LIT(KDoubleKWD,"DOUBLE");
1.35 +
1.36 +/////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.37 +////////////////////////// RSqlLongColumnColl ////////////////////////////////////////////
1.38 +/////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.39 +
1.40 +/**
1.41 +This "comparison" function is used for searching a particular column value, identified by aIndex, in the long column
1.42 +values collection.
1.43 +@param aIndex An integer pointer to long column index value
1.44 +@param aData A reference to particular elemt of the long column values collection
1.45 +@return True of the index of aData item is the same as *aIndex, false otherwise
1.46 +@panic SqlDb 4 In _DEBUG mode, aIndex is NULL.
1.47 +@panic SqlDb 4 In _DEBUG mode, *aIndex value is negative.
1.48 +*/
1.49 +TBool RSqlLongColumnColl::TData::Compare(const TInt* aIndex, const RSqlLongColumnColl::TData& aData)
1.50 + {
1.51 + __ASSERT_DEBUG(aIndex != NULL, __SQLPANIC2(ESqlPanicBadArgument));
1.52 + __ASSERT_DEBUG(*aIndex >= 0, __SQLPANIC2(ESqlPanicBadArgument));
1.53 + return *aIndex == aData.iIndex;
1.54 + }
1.55 +
1.56 +/**
1.57 +Reads a long column value, identified by aColumnIndex parameter, from the server and stores the value in the collection.
1.58 +@param aReader A RSqlLongColumnColl::TColumnReader object, which performs the "read column value" operation.
1.59 +@param aColumnIndex Column index
1.60 +@param aColumnSize The column size in bytes
1.61 +@panic SqlDb 4 In _DEBUG mode, aColumnIndex value is negative.
1.62 +@panic SqlDb 4 In _DEBUG mode, aColumnSize is less than KSqlMaxDesLen (not a long column value)
1.63 +@return KErrNone The call has completed successfully;
1.64 + KErrNoMemory Out of memory;
1.65 + Note that other system-wide or database specific error codes may also be returned.
1.66 +*/
1.67 +TInt RSqlLongColumnColl::Append(RSqlLongColumnColl::TColumnReader& aReader, TInt aColumnIndex, TInt aColumnSize)
1.68 + {
1.69 + __ASSERT_DEBUG(aColumnIndex >= 0, __SQLPANIC(ESqlPanicBadArgument));
1.70 + __ASSERT_DEBUG(aColumnSize >= KSqlMaxDesLen, __SQLPANIC(ESqlPanicBadArgument));
1.71 + LONGCOL_INVARIANT();
1.72 + HBufC8* colBuf = HBufC8::New(aColumnSize);
1.73 + if(!colBuf)
1.74 + {
1.75 + return KErrNoMemory;
1.76 + }
1.77 + TPtr8 ptr = colBuf->Des();
1.78 + TInt err = aReader.Read(aColumnIndex, ptr);
1.79 + if(err == KErrNone)
1.80 + {
1.81 + err = iValues.Append(RSqlLongColumnColl::TData(aColumnIndex, colBuf));
1.82 + }
1.83 + if(err != KErrNone)
1.84 + {
1.85 + delete colBuf;
1.86 + }
1.87 + LONGCOL_INVARIANT();
1.88 + return err;
1.89 + }
1.90 +
1.91 +#ifdef _DEBUG
1.92 +/**
1.93 +RSqlLongColumnColl invariant.
1.94 +The collection cannot have two column values with the same column index.
1.95 +The collection cannot have NULL column value, or negative column index.
1.96 +*/
1.97 +void RSqlLongColumnColl::Invariant() const
1.98 + {
1.99 + for(TInt i=iValues.Count()-1;i>=0;--i)
1.100 + {
1.101 + const RSqlLongColumnColl::TData& data = iValues[i];
1.102 + __ASSERT_DEBUG(data.iIndex >= 0, __SQLPANIC(ESqlPanicInternalError));
1.103 + __ASSERT_DEBUG(data.iData != NULL, __SQLPANIC(ESqlPanicInternalError));
1.104 + for(TInt j=i-1;j>=0;--j)
1.105 + {
1.106 + __ASSERT_DEBUG(data.iIndex != iValues[j].iIndex, __SQLPANIC(ESqlPanicInternalError));
1.107 + }
1.108 + }
1.109 + }
1.110 +#endif
1.111 +
1.112 +/////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.113 +////////////////////////// CSqlStatementImpl ////////////////////////////////////////////
1.114 +/////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.115 +
1.116 +/**
1.117 +RSqlLongColumnColl::TColumnReader derived class, which implements the pure virtual RSqlLongColumnColl::TColumnReader::Read().
1.118 +The class is used for retrieving long column values from the server.
1.119 +@internalComponent
1.120 +*/
1.121 +NONSHARABLE_STRUCT(TSqlLongColumnReader) : public RSqlLongColumnColl::TColumnReader
1.122 + {
1.123 + TSqlLongColumnReader(RSqlStatementSession& aStmtSession) :
1.124 + iStmtSession(aStmtSession)
1.125 + {
1.126 + }
1.127 + virtual TInt Read(TInt aColumnIndex, TDes8& aBuf)
1.128 + {
1.129 + return iStmtSession.ReadColumnValue(aColumnIndex, aBuf);
1.130 + }
1.131 + RSqlStatementSession iStmtSession;
1.132 + };
1.133 +
1.134 +/////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.135 +////////////////////////// CSqlStatementImpl ////////////////////////////////////////////
1.136 +/////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.137 +
1.138 +/**
1.139 +Frees the allocated memory and other resources.
1.140 +*/
1.141 +CSqlStatementImpl::~CSqlStatementImpl()
1.142 + {
1.143 + iDeclaredColumnTypes.Close();
1.144 + iLongColumnColl.Close();
1.145 + iParamValueBuf.Close();
1.146 + iParamNameBuf.Close();
1.147 + iColumnValueBuf.Close();
1.148 + iColumnNameBuf.Close();
1.149 + iSqlStmtSession.Close();
1.150 + }
1.151 +
1.152 +
1.153 +
1.154 +/**
1.155 +Resets the prepared SQL statement back to its initial state and makes it ready for re-execution.
1.156 +The parameters of the SQL statement retain their values.
1.157 +If CSqlStatementImpl object processes parametrized SQL statement, the parameter values can be bound after
1.158 +the Reset() call.
1.159 +
1.160 +The method sets the internal object's state to CSqlStatementImpl::EUnknown. The column data accessors
1.161 +cannot be used until the next successful Next() call.
1.162 +
1.163 +@return KSqlErrStmtExpired, statement expired (if new functions or collating sequences are
1.164 + registered or if an authorizer function is added or changed);
1.165 + KErrNone, the operation has completed successfully.
1.166 +
1.167 +@see RSqlStatement::Reset()
1.168 +*/
1.169 +TInt CSqlStatementImpl::Reset()
1.170 + {
1.171 + iState = CSqlStatementImpl::EUnknown;
1.172 + iLongColumnColl.Reset();
1.173 + if(iParamCnt > 0)
1.174 + {
1.175 + iParamValueBuf.ResetAndMinimize();
1.176 + }
1.177 + return iSqlStmtSession.Reset();
1.178 + }
1.179 +
1.180 +/**
1.181 +Executes the prepared DDL/DML SQL statement.
1.182 +
1.183 +If the SQL statement contains parameters, their values will be bound right before the execution.
1.184 +
1.185 +The method sets the internal object's state to CSqlStatementImpl::EUnknown. The column data accessors
1.186 +cannot be used until the next successful Next() call.
1.187 +
1.188 +@return >=0, The operation has completed successfully. The number of database rows that were
1.189 + changed/inserted/deleted by the most recently completed DDL/DML sql statement.
1.190 + Exception: If the executed statement is "DELETE FROM <table>", then the function returns 0
1.191 + if the operation has completed successfully (disregarding the number of the deleted rows);
1.192 + KSqlErrStmtExpired, statement has expired (if new functions or collating sequences are
1.193 + registered or if an authorizer function is added or changed);
1.194 + KErrNoMemory, an out of memory condition has occurred.
1.195 + Note that database specific errors categorised as ESqlDbError, and
1.196 + other system-wide error codes may also be returned.
1.197 +
1.198 +@see RSqlStatement::Exec()
1.199 +*/
1.200 +TInt CSqlStatementImpl::Exec()
1.201 + {
1.202 + iState = CSqlStatementImpl::EUnknown;
1.203 + TInt rc = 0;
1.204 + if(iBound)
1.205 + {
1.206 + rc = iSqlStmtSession.Exec();
1.207 + }
1.208 + else
1.209 + {
1.210 + rc = iSqlStmtSession.BindExec(iParamValueBuf);
1.211 + iBound = ETrue;
1.212 + iParamValueBuf.ResetAndMinimize();
1.213 + }
1.214 + return rc;
1.215 + }
1.216 +
1.217 +/**
1.218 +Executes the prepared DDL/DML SQL statement asynchronously.
1.219 +
1.220 +If the SQL statement contains parameters, their values will be bound right before the execution.
1.221 +
1.222 +The method sets the internal object's state to CSqlStatementImpl::EUnknown. The column data accessors
1.223 +cannot be used until the next successful Next() call.
1.224 +
1.225 +@param aStatus Completion status of asynchronous request, one of the following:
1.226 + >=0, The operation has completed successfully. The number of database rows that were
1.227 + changed/inserted/deleted by the most recently completed DDL/DML sql statement.
1.228 + Exception: If the executed statement is "DELETE FROM <table>", then the function returns 0
1.229 + if the operation has completed successfully (disregarding the number of the deleted rows);
1.230 + KSqlErrStmtExpired, the SQL statement has expired (if new functions or
1.231 + collating sequences have been registered or if an
1.232 + authorizer function has been added or changed);
1.233 + KErrNoMemory, an out of memory condition has occurred - the statement
1.234 + will be reset.
1.235 + Note that aStatus may be set with database specific errors categorised as ESqlDbError,
1.236 + and other system-wide error codes.
1.237 +
1.238 +
1.239 +@see RSqlStatement::Exec()
1.240 +*/
1.241 +void CSqlStatementImpl::Exec(TRequestStatus& aStatus)
1.242 + {
1.243 + iState = CSqlStatementImpl::EUnknown;
1.244 + if(iBound)
1.245 + {
1.246 + iSqlStmtSession.Exec(aStatus);
1.247 + }
1.248 + else
1.249 + {
1.250 + iSqlStmtSession.BindExec(iParamValueBuf, aStatus);
1.251 + iBound = ETrue;
1.252 + //Here: it is not possible to reset iParamValueBuf for "safety", because this is an asynchronous call
1.253 + // and the buffer content has to be preserved until the operation completes.
1.254 + }
1.255 + }
1.256 +
1.257 +/**
1.258 +Retrieves a record.
1.259 +
1.260 +If the prepared SQL statement is a "SELECT" statement, and is expected to
1.261 +return a set of records, then this function can be used to retrieve that record data.
1.262 +
1.263 +If the SQL statement contains parameters, then their values must be bound before
1.264 +this function is called.
1.265 +
1.266 +If the call to this function completes successfully, i.e. it returns
1.267 +with KSqlAtRow, then this CSqlStatementImpl object contains the record data, and
1.268 +this data will remain valid for access until another call is made to any
1.269 +CSqlStatementImpl function.
1.270 +
1.271 +The record data can be accessed using the following functions:
1.272 +- CSqlStatementImpl::ColumnType()
1.273 +- CSqlStatementImpl::ColumnSize()
1.274 +- CSqlStatementImpl::Column<Type>()
1.275 +
1.276 +@return KSqlAtRow, the record data is ready for processing by the caller;
1.277 + KSqlAtEnd, there is no more record data;
1.278 + KSqlErrBusy, the database file is locked;
1.279 + KErrNoMemory, an out of memory condition has occurred - the statement
1.280 + will be reset;
1.281 + KSqlErrGeneral, a run-time error has occured - this function must not
1.282 + be called again;
1.283 + KSqlErrMisuse, this function has been called after a previous call
1.284 + returned KSqlAtEnd or KSqlErrGeneral.
1.285 + KSqlErrStmtExpired, the SQL statement has expired (if new functions or
1.286 + collating sequences have been registered or if an
1.287 + authorizer function has been added or changed);
1.288 +
1.289 +@see RSqlStatement::Next()
1.290 +*/
1.291 +TInt CSqlStatementImpl::Next()
1.292 + {
1.293 + iLongColumnColl.Reset();
1.294 + iColumnValueBuf.ResetAndMinimize();
1.295 + iState = CSqlStatementImpl::EUnknown;
1.296 + TInt err = KErrNone;
1.297 + if(iBound)
1.298 + {
1.299 + err = iSqlStmtSession.Next(iColumnValueBuf);
1.300 + }
1.301 + else
1.302 + {
1.303 + err = iSqlStmtSession.BindNext(iParamValueBuf, iColumnValueBuf);
1.304 + iBound = ETrue;
1.305 + iParamValueBuf.ResetAndMinimize();
1.306 + }
1.307 + iColumnValBufIt.Set(iColumnValueBuf);
1.308 + if(err == KSqlAtRow)
1.309 + {
1.310 + iState = CSqlStatementImpl::EAtRow;
1.311 + }
1.312 + return err;
1.313 + }
1.314 +
1.315 +/**
1.316 +Implements RSqlStatement::BindNull().
1.317 +
1.318 +@panic SqlDb 5 Parameter index out of bounds.
1.319 +
1.320 +@see RSqlStatement::BindNull()
1.321 +*/
1.322 +TInt CSqlStatementImpl::BindNull(TInt aParamIndex)
1.323 + {
1.324 + __ASSERT_ALWAYS((TUint)aParamIndex < (TUint)iParamCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.325 + iBound = EFalse;
1.326 + iParamValBufIt.MoveTo(aParamIndex);
1.327 + iParamValBufIt.SetNull();
1.328 + return KErrNone;
1.329 + }
1.330 +
1.331 +/**
1.332 +Implements RSqlStatement::BindInt().
1.333 +
1.334 +@panic SqlDb 5 Parameter index out of bounds.
1.335 +
1.336 +@see RSqlStatement::BindInt()
1.337 +*/
1.338 +TInt CSqlStatementImpl::BindInt(TInt aParamIndex, TInt aParamValue)
1.339 + {
1.340 + __ASSERT_ALWAYS((TUint)aParamIndex < (TUint)iParamCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.341 + iBound = EFalse;
1.342 + iParamValBufIt.MoveTo(aParamIndex);
1.343 + return iParamValBufIt.SetInt(aParamValue);
1.344 + }
1.345 +
1.346 +/**
1.347 +Implements RSqlStatement::BindInt64().
1.348 +
1.349 +@panic SqlDb 5 Parameter index out of bounds.
1.350 +
1.351 +@see RSqlStatement::BindInt64()
1.352 +*/
1.353 +TInt CSqlStatementImpl::BindInt64(TInt aParamIndex, TInt64 aParamValue)
1.354 + {
1.355 + __ASSERT_ALWAYS((TUint)aParamIndex < (TUint)iParamCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.356 + iBound = EFalse;
1.357 + iParamValBufIt.MoveTo(aParamIndex);
1.358 + return iParamValBufIt.SetInt64(aParamValue);
1.359 + }
1.360 +
1.361 +/**
1.362 +Implements RSqlStatement::BindReal().
1.363 +
1.364 +@panic SqlDb 5 Parameter index out of bounds.
1.365 +
1.366 +@see RSqlStatement::BindReal()
1.367 +*/
1.368 +TInt CSqlStatementImpl::BindReal(TInt aParamIndex, TReal aParamValue)
1.369 + {
1.370 + __ASSERT_ALWAYS((TUint)aParamIndex < (TUint)iParamCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.371 + iBound = EFalse;
1.372 + iParamValBufIt.MoveTo(aParamIndex);
1.373 + return iParamValBufIt.SetReal(aParamValue);
1.374 + }
1.375 +
1.376 +/**
1.377 +Implements RSqlStatement::BindText().
1.378 +
1.379 +@panic SqlDb 5 Parameter index out of bounds.
1.380 +
1.381 +@see RSqlStatement::BindText()
1.382 +*/
1.383 +TInt CSqlStatementImpl::BindText(TInt aParamIndex, const TDesC& aParamText)
1.384 + {
1.385 + __ASSERT_ALWAYS((TUint)aParamIndex < (TUint)iParamCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.386 + iBound = EFalse;
1.387 + iParamValBufIt.MoveTo(aParamIndex);
1.388 + return iParamValBufIt.SetText(aParamText);
1.389 + }
1.390 +
1.391 +/**
1.392 +Implements RSqlStatement::BindBinary().
1.393 +
1.394 +@panic SqlDb 5 Parameter index out of bounds.
1.395 +
1.396 +@see RSqlStatement::BindBinary()
1.397 +*/
1.398 +TInt CSqlStatementImpl::BindBinary(TInt aParamIndex, const TDesC8& aParamData)
1.399 + {
1.400 + __ASSERT_ALWAYS((TUint)aParamIndex < (TUint)iParamCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.401 + iBound = EFalse;
1.402 + iParamValBufIt.MoveTo(aParamIndex);
1.403 + return iParamValBufIt.SetBinary(aParamData);
1.404 + }
1.405 +
1.406 +/**
1.407 +Implements RSqlStatement::BindZeroBlob().
1.408 +
1.409 +@panic SqlDb 5 Parameter index out of bounds.
1.410 +
1.411 +@see RSqlStatement::BindZeroBlob()
1.412 +*/
1.413 +TInt CSqlStatementImpl::BindZeroBlob(TInt aParamIndex, TInt aBlobSize)
1.414 + {
1.415 + __ASSERT_ALWAYS((TUint)aParamIndex < (TUint)iParamCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.416 + iBound = EFalse;
1.417 + iParamValBufIt.MoveTo(aParamIndex);
1.418 + return iParamValBufIt.SetZeroBlob(aBlobSize);
1.419 + }
1.420 +
1.421 +/**
1.422 +Implements RSqlStatement::ColumnType().
1.423 +
1.424 +@panic SqlDb 5 Column index out of bounds.
1.425 +@panic SqlDb 11 Statement cursor not positioned on a row.
1.426 +
1.427 +@see RSqlStatement::ColumnType().
1.428 +*/
1.429 +TSqlColumnType CSqlStatementImpl::ColumnType(TInt aColumnIndex)
1.430 + {
1.431 + __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.432 + __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
1.433 + iColumnValBufIt.MoveTo(aColumnIndex);
1.434 + return static_cast <TSqlColumnType> (iColumnValBufIt.Type());
1.435 + }
1.436 +
1.437 +/**
1.438 +Implements RSqlStatement::DeclaredColumnType().
1.439 +
1.440 +@param aColumnIndex The index value identifying the column. This is 0 for the first column.
1.441 +@param aColumnType Output parameter. Upon completion this will contain the type of the column.
1.442 +
1.443 +@return KErrNone, the operation completed successfully;
1.444 + KErrNoMemory, an out of memory condition has occurred.
1.445 + One of the other system-wide error codes may also be returned.
1.446 +
1.447 +@panic SqlDb 5 Column index out of bounds.
1.448 +
1.449 +@see RSqlStatement::DeclaredColumnType().
1.450 +*/
1.451 +TInt CSqlStatementImpl::DeclaredColumnType(TInt aColumnIndex, TSqlColumnType& aColumnType)
1.452 + {
1.453 + __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.454 + if(iDeclaredColumnTypes.Count() == 0) //initialise iDeclaredColumnTypes array if necessary
1.455 + {
1.456 + RSqlBufFlat declaredColumnTypeBuf;
1.457 + TInt err = declaredColumnTypeBuf.SetCount(iColumnCnt);
1.458 + if(err != KErrNone)
1.459 + {
1.460 + declaredColumnTypeBuf.Close();
1.461 + return err;
1.462 + }
1.463 +
1.464 + //Resize buffer to minimise the chance that two IPC calls are required to get all the column type name data.
1.465 + //Allocates enough space to contain the header cells (already created by calling SetCount()) and a data buffer
1.466 + //which assumes an average column type name length of 20 characters plus 8-byte alignment padding
1.467 + const TInt KBufSizePerColumn = 48;
1.468 + TInt newSize = declaredColumnTypeBuf.Size() + iColumnCnt*KBufSizePerColumn;
1.469 +
1.470 + err = declaredColumnTypeBuf.ReAlloc(newSize);
1.471 + if(err != KErrNone)
1.472 + {
1.473 + declaredColumnTypeBuf.Close();
1.474 + return err;
1.475 + }
1.476 +
1.477 + err = iSqlStmtSession.GetDeclColumnTypes(declaredColumnTypeBuf);
1.478 + if(err != KErrNone)
1.479 + {
1.480 + declaredColumnTypeBuf.Close();
1.481 + return err;
1.482 + }
1.483 +
1.484 + err = iDeclaredColumnTypes.Reserve(iColumnCnt);//We know what the array size should be - iColumnCnt
1.485 + if(err != KErrNone)
1.486 + {
1.487 + declaredColumnTypeBuf.Close();
1.488 + return err;
1.489 + }
1.490 +
1.491 + //Iterate over the column type names buffer and map each column type name to one of the TSqlColumnType enum item values.
1.492 + TSqlBufRIterator declColumnTypeBufIt;
1.493 + declColumnTypeBufIt.Set(declaredColumnTypeBuf);
1.494 + TInt colIdx = 0;
1.495 + while(declColumnTypeBufIt.Next())
1.496 + {
1.497 + TPtrC colTypeName(declColumnTypeBufIt.Text());
1.498 + TSqlColumnType colType = ESqlInt;
1.499 + if(colTypeName.FindF(KCharKWD) >= 0 || colTypeName.FindF(KTextKWD) >= 0 || colTypeName.FindF(KClobKWD) >= 0)
1.500 + {
1.501 + colType = ESqlText;
1.502 + }
1.503 + else if(colTypeName.FindF(KBinaryKWD) >= 0 || colTypeName.FindF(KBlobKWD) >= 0)
1.504 + {
1.505 + colType = ESqlBinary;
1.506 + }
1.507 + else if(colTypeName.FindF(KRealKWD) >= 0 || colTypeName.FindF(KFloatKWD) >= 0 || colTypeName.FindF(KDoubleKWD) >= 0)
1.508 + {
1.509 + colType = ESqlReal;
1.510 + }
1.511 + err = iDeclaredColumnTypes.Append(colType);
1.512 + __ASSERT_DEBUG(err == KErrNone, __SQLPANIC(ESqlPanicInternalError));//memory for the array elements has been reserved already
1.513 + ++colIdx;
1.514 + } //end of - while(declColumnTypeBufIt.Next())
1.515 + __ASSERT_DEBUG(colIdx == iColumnCnt, __SQLPANIC(ESqlPanicInternalError));
1.516 + declaredColumnTypeBuf.Close();
1.517 + } //end of - if(iDeclaredColumnTypes.Count() == 0 && iColumnCnt > 0)
1.518 + aColumnType = iDeclaredColumnTypes[aColumnIndex];
1.519 + return KErrNone;
1.520 + }
1.521 +
1.522 +/**
1.523 +Implements RSqlStatement::ColumnSize().
1.524 +
1.525 +@panic SqlDb 5 Column index out of bounds.
1.526 +@panic SqlDb 11 Statement cursor not positioned on a row
1.527 +
1.528 +@see RSqlStatement::ColumnSize().
1.529 +*/
1.530 +TInt CSqlStatementImpl::ColumnSize(TInt aColumnIndex)
1.531 + {
1.532 + __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.533 + __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
1.534 + iColumnValBufIt.MoveTo(aColumnIndex);
1.535 + return iColumnValBufIt.Size();
1.536 + }
1.537 +
1.538 +/**
1.539 +Implements RSqlStatement::ColumnInt().
1.540 +
1.541 +@panic SqlDb 5 Column index out of bounds.
1.542 +@panic SqlDb 11 Statement cursor not positioned on a row
1.543 +
1.544 +@see RSqlStatement::ColumnInt().
1.545 +*/
1.546 +TInt CSqlStatementImpl::ColumnInt(TInt aColumnIndex)
1.547 + {
1.548 + __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.549 + __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
1.550 + iColumnValBufIt.MoveTo(aColumnIndex);
1.551 + __ASSERT_DEBUG(iColumnValBufIt.IsPresent(), __SQLPANIC(ESqlPanicValueNotPresent));
1.552 + return iColumnValBufIt.Int();
1.553 + }
1.554 +
1.555 +/**
1.556 +Implements RSqlStatement::ColumnInt64().
1.557 +
1.558 +@panic SqlDb 5 Column index out of bounds.
1.559 +@panic SqlDb 11 Statement cursor not positioned on a row
1.560 +
1.561 +@see RSqlStatement::ColumnInt64().
1.562 +*/
1.563 +TInt64 CSqlStatementImpl::ColumnInt64(TInt aColumnIndex)
1.564 + {
1.565 + __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.566 + __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
1.567 + iColumnValBufIt.MoveTo(aColumnIndex);
1.568 + __ASSERT_DEBUG(iColumnValBufIt.IsPresent(), __SQLPANIC(ESqlPanicValueNotPresent));
1.569 + return iColumnValBufIt.Int64();
1.570 + }
1.571 +
1.572 +/**
1.573 +Implements RSqlStatement::ColumnReal().
1.574 +
1.575 +@panic SqlDb 5 Column index out of bounds.
1.576 +@panic SqlDb 11 Statement cursor not positioned on a row
1.577 +
1.578 +@see RSqlStatement::ColumnReal().
1.579 +*/
1.580 +TReal CSqlStatementImpl::ColumnReal(TInt aColumnIndex)
1.581 + {
1.582 + __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.583 + __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
1.584 + iColumnValBufIt.MoveTo(aColumnIndex);
1.585 + __ASSERT_DEBUG(iColumnValBufIt.IsPresent(), __SQLPANIC(ESqlPanicValueNotPresent));
1.586 + return iColumnValBufIt.Real();
1.587 + }
1.588 +
1.589 +/**
1.590 +Return a text (16 bit) descriptor to a text column identified by aColumnIndex.
1.591 +
1.592 +@param aColumnIndex Column index
1.593 +@param aPtr An output parameter which will be set to point to the column data.
1.594 +
1.595 +@return KErrNone, if the function completes successfully,
1.596 + otherwise one of the other system-wide error codes.
1.597 +
1.598 +@panic SqlDb 5 Column index out of bounds.
1.599 +@panic SqlDb 11 Statement cursor not positioned on a row
1.600 +*/
1.601 +TInt CSqlStatementImpl::ColumnText(TInt aColumnIndex, TPtrC& aPtr)
1.602 + {
1.603 + __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.604 + __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
1.605 + iColumnValBufIt.MoveTo(aColumnIndex);
1.606 + if(iColumnValBufIt.IsPresent())
1.607 + {
1.608 + aPtr.Set(iColumnValBufIt.Text());
1.609 + return KErrNone;
1.610 + }
1.611 + //The text column value has not been transferred to the client side if its length is >= KSqlMaxDesLen characters.
1.612 + //In this case an additional call to the server is made to get the column value.
1.613 + //The column value is stored in a separate collection (iLongColumnColl), because if iColumnValueBuf gets reallocated,
1.614 + //the client can get a dangling pointer to some of the located in iColumnValueBuf text/binary column values.
1.615 + if(iColumnValBufIt.Type() != ESqlText)
1.616 + {
1.617 + aPtr.Set(KNullDesC);
1.618 + return KErrNone;
1.619 + }
1.620 + if(!iLongColumnColl.IsPresent(aColumnIndex))
1.621 + {
1.622 + TSqlLongColumnReader colReader(iSqlStmtSession);
1.623 + TInt err = iLongColumnColl.Append(colReader, aColumnIndex, iColumnValBufIt.Size() * sizeof(TUint16));
1.624 + if(err != KErrNone)
1.625 + {
1.626 + return err;
1.627 + }
1.628 + }
1.629 + aPtr.Set(iLongColumnColl.Text(aColumnIndex));
1.630 + return KErrNone;
1.631 + }
1.632 +
1.633 +/**
1.634 +Copies the content of a text column, identified by aColumnIndex, to the place refered by aDest parameter.
1.635 +
1.636 +If the destination buffer is not big enough, the function will copy as much data as possible and will
1.637 +return KErrOverflow.
1.638 +
1.639 +@param aColumnIndex Column index
1.640 +@param aDest Refers to the place where the column data will be copied.
1.641 +
1.642 +@return KErrNone, if the function completes successfully,
1.643 + otherwise one of the other system-wide error codes.
1.644 +
1.645 +@panic SqlDb 5 Column index out of bounds.
1.646 +@panic SqlDb 11 Statement cursor not positioned on a row
1.647 +*/
1.648 +TInt CSqlStatementImpl::ColumnText(TInt aColumnIndex, TDes& aDest)
1.649 + {
1.650 + __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.651 + __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
1.652 + iColumnValBufIt.MoveTo(aColumnIndex);
1.653 + TInt err = KErrNone;
1.654 + //The text column value has not been transferred to the client side if its length is >= KSqlMaxDesLen characters.
1.655 + //In this case an additional call to the server is made to get the column value.
1.656 + if(!iColumnValBufIt.IsPresent())
1.657 + {
1.658 + if(iColumnValBufIt.Type() != ESqlText)
1.659 + {
1.660 + aDest.Zero();
1.661 + return err;
1.662 + }
1.663 + TPtr8 ptr(reinterpret_cast <TUint8*> (const_cast <TUint16*> (aDest.Ptr())), aDest.MaxLength() * sizeof(TUint16));
1.664 + err = iSqlStmtSession.ReadColumnValue(aColumnIndex, ptr);
1.665 + switch(err)
1.666 + {
1.667 + case KErrNone:
1.668 + case KErrOverflow:
1.669 + aDest.SetLength(ptr.Length() / sizeof(TUint16));
1.670 + break;
1.671 + default:
1.672 + break;
1.673 + }
1.674 + }
1.675 + else
1.676 + {
1.677 + TPtrC src = iColumnValBufIt.Text();
1.678 + TInt len = src.Length();
1.679 + if(len > aDest.MaxLength())
1.680 + {
1.681 + len = aDest.MaxLength();
1.682 + err = KErrOverflow;
1.683 + }
1.684 + aDest.Copy(src.Ptr(), len);
1.685 + }
1.686 + return err;
1.687 + }
1.688 +
1.689 +/**
1.690 +Return a binary (8 bit) descriptor to a binary column identified by aColumnIndex.
1.691 +
1.692 +@param aColumnIndex Column index
1.693 +@param aPtr An output parameter which will be set to point to the column data.
1.694 +
1.695 +@return KErrNone, if the function completes successfully,
1.696 + otherwise one of the other system-wide error codes.
1.697 +
1.698 +@panic SqlDb 5 Column index out of bounds.
1.699 +@panic SqlDb 11 Statement cursor not positioned on a row
1.700 +*/
1.701 +TInt CSqlStatementImpl::ColumnBinary(TInt aColumnIndex, TPtrC8& aPtr)
1.702 + {
1.703 + __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.704 + __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
1.705 + iColumnValBufIt.MoveTo(aColumnIndex);
1.706 + if(iColumnValBufIt.IsPresent())
1.707 + {
1.708 + aPtr.Set(iColumnValBufIt.Binary());
1.709 + return KErrNone;
1.710 + }
1.711 + //The binary column value has not been transferred to the client side if its length is >= KSqlMaxDesLen characters.
1.712 + //In this case an additional call to the server is made to get the column value.
1.713 + //The column value is stored in a separate collection (iLongColumnColl), because if iColumnValueBuf gets reallocated,
1.714 + //the client can get a dangling pointer to some of the located in iColumnValueBuf text/binary column values.
1.715 + if(iColumnValBufIt.Type() != ESqlBinary)
1.716 + {
1.717 + aPtr.Set(KNullDesC8);
1.718 + return KErrNone;
1.719 + }
1.720 + if(!iLongColumnColl.IsPresent(aColumnIndex))
1.721 + {
1.722 + TSqlLongColumnReader colReader(iSqlStmtSession);
1.723 + TInt err = iLongColumnColl.Append(colReader, aColumnIndex, iColumnValBufIt.Size());
1.724 + if(err != KErrNone)
1.725 + {
1.726 + return err;
1.727 + }
1.728 + }
1.729 + aPtr.Set(iLongColumnColl.Binary(aColumnIndex));
1.730 + return KErrNone;
1.731 + }
1.732 +
1.733 +/**
1.734 +Copies the content of a binary column, identified by aColumnIndex, to the place refered by aDest parameter.
1.735 +
1.736 +If the destination buffer is not big enough, the function will copy as much data as possible and will
1.737 +return KErrOverflow.
1.738 +
1.739 +@param aColumnIndex Column index
1.740 +@param aDest Refers to the place where the column data will be copied.
1.741 +
1.742 +@return KErrNone, if the function completes successfully,
1.743 + otherwise one of the other system-wide error codes.
1.744 +
1.745 +@panic SqlDb 5 Column index out of bounds.
1.746 +@panic SqlDb 11 Statement cursor not positioned on a row
1.747 +*/
1.748 +TInt CSqlStatementImpl::ColumnBinary(TInt aColumnIndex, TDes8& aDest)
1.749 + {
1.750 + __ASSERT_ALWAYS((TUint)aColumnIndex < (TUint)iColumnCnt, __SQLPANIC(ESqlPanicBadColumnIndex));
1.751 + __ASSERT_ALWAYS(iState == CSqlStatementImpl::EAtRow, __SQLPANIC(ESqlPanicInvalidRow));
1.752 + iColumnValBufIt.MoveTo(aColumnIndex);
1.753 + TInt err = KErrNone;
1.754 + //The binary column value has not been transferred to the client side if its length is >= KSqlMaxDesLen bytes.
1.755 + //In this case an additional call to the server is made to get the column value.
1.756 + if(!iColumnValBufIt.IsPresent())
1.757 + {
1.758 + if(iColumnValBufIt.Type() != ESqlBinary)
1.759 + {
1.760 + aDest.Zero();
1.761 + return err;
1.762 + }
1.763 + err = iSqlStmtSession.ReadColumnValue(aColumnIndex, aDest);
1.764 + }
1.765 + else
1.766 + {
1.767 + TPtrC8 src = iColumnValBufIt.Binary();
1.768 + TInt len = src.Length();
1.769 + if(len > aDest.MaxLength())
1.770 + {
1.771 + len = aDest.MaxLength();
1.772 + err = KErrOverflow;
1.773 + }
1.774 + aDest.Copy(src.Ptr(), len);
1.775 + }
1.776 + return err;
1.777 + }
1.778 +
1.779 +/**
1.780 + * Obtain the name of a column after performing a query.
1.781 + *
1.782 + * @param aColumnIndex Column index
1.783 + * @param aNameDest Descriptor which will be set to column name
1.784 + * @return KErrNone if successfull or one of the system-wide error codes on error
1.785 + */
1.786 +TInt CSqlStatementImpl::ColumnName(TInt aColumnIndex, TPtrC& aNameDest)
1.787 + {
1.788 + return Index2Name(aColumnIndex, iColumnNameBuf, iColumnCnt, ESqlSrvStmtColumnNames, iColumnNameBufPresent, aNameDest);
1.789 + }
1.790 +
1.791 +/**
1.792 + * Obtain the name of a parameter after preparing a DML query.
1.793 + *
1.794 + * @param aParamIndex Parameter index
1.795 + * @param aNameDest Descriptor which will be set to column name
1.796 + * @return KErrNone if successfull or one of the system-wide error codes on error
1.797 + */
1.798 +TInt CSqlStatementImpl::ParameterName(TInt aParamIndex, TPtrC& aNameDest)
1.799 + {
1.800 + return Index2Name(aParamIndex, iParamNameBuf, iParamCnt, ESqlSrvStmtParamNames, iParamNameBufPresent, aNameDest);
1.801 + }
1.802 +
1.803 +
1.804 +TInt CSqlStatementImpl::Name2Index(const TDesC& aName, RSqlBufFlat& aNameBufFlat, TInt aCount, TSqlSrvFunction aFunction, TBool& aPresent)
1.805 + {
1.806 + if(aCount == 0)
1.807 + {
1.808 + return KErrNotFound;
1.809 + }
1.810 + TInt err = CheckNameBufPresent(aPresent, aNameBufFlat, aCount, aFunction);
1.811 + if ( err != KErrNone )
1.812 + {
1.813 + return err;
1.814 + }
1.815 + TInt idx = -1;
1.816 + aPresent = ETrue;
1.817 + TSqlBufRIterator nameBufIt;
1.818 + nameBufIt.Set(aNameBufFlat);
1.819 + while(nameBufIt.Next())
1.820 + {
1.821 + ++idx;
1.822 + if(::CompareNoCase16(aName, nameBufIt.Text()) == 0)
1.823 + {
1.824 + return idx;
1.825 + }
1.826 + }
1.827 + return KErrNotFound;
1.828 + }
1.829 +
1.830 +
1.831 +TInt CSqlStatementImpl::Index2Name(TInt aIndex, RSqlBufFlat& aNameBufFlat, TInt aCount, TSqlSrvFunction aFunction, TBool& aPresent, TPtrC& aColName)
1.832 + {
1.833 + if( aCount == 0 || aIndex < 0 || aIndex >= aCount )
1.834 + {
1.835 + return KErrNotFound;
1.836 + }
1.837 + TInt err = CheckNameBufPresent(aPresent, aNameBufFlat, aCount, aFunction);
1.838 + if ( err != KErrNone )
1.839 + {
1.840 + return err;
1.841 + }
1.842 + aPresent = ETrue;
1.843 + TSqlBufRIterator nameBufIt;
1.844 + nameBufIt.Set(aNameBufFlat);
1.845 + nameBufIt.MoveTo(aIndex);
1.846 + aColName.Set(nameBufIt.Text());
1.847 + return KErrNone;
1.848 + }
1.849 +
1.850 +/**
1.851 +Ensures that the specified names buffer is present on the client side.
1.852 +Name buffers are used for transporting parameter and column names.
1.853 +
1.854 +@return KErrNone if successfull or one of the system-wide error codes on error
1.855 +@internalComponent
1.856 +*/
1.857 +TInt CSqlStatementImpl::CheckNameBufPresent(TBool& aPresent, RSqlBufFlat& aNameBufFlat, TInt aCount, TSqlSrvFunction aFunction)
1.858 + {
1.859 + if(!aPresent)
1.860 + {
1.861 + aNameBufFlat.Close();
1.862 + TInt err = aNameBufFlat.SetCount(aCount);
1.863 + if(err != KErrNone)
1.864 + {
1.865 + return err;
1.866 + }
1.867 + err = iSqlStmtSession.GetNames(aFunction, aNameBufFlat);
1.868 + if(err != KErrNone)
1.869 + {
1.870 + return err;
1.871 + }
1.872 + }
1.873 + return KErrNone;
1.874 + }
1.875 +