persistentstorage/sql/SRC/Server/SqlSrvStatement.cpp
changeset 0 08ec8eefde2f
child 9 667e88a979d7
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <utf.h>					//CnvUtfConverter
       
    17 #include <e32math.h>
       
    18 #include "SqliteSymbian.h"			//sqlite3SymbianLastOsError()
       
    19 #include "sqlite3.h"
       
    20 #include "SqlSrvStatement.h"
       
    21 #include "SqlBufIterator.h"			//TSqlBufRIterator
       
    22 #include "SqlSrvResourceProfiler.h"
       
    23 #include "UTraceSql.h"
       
    24 //////////////////////////////////////////////////////////////////////////////////////////////////////
       
    25 /////////////////////////////      local const data       ////////////////////////////////////////////
       
    26 //////////////////////////////////////////////////////////////////////////////////////////////////////
       
    27 
       
    28 //This is the name prefix which will be given to the nameless parameters.
       
    29 //For example, if the SQL string is:
       
    30 //   SELECT * FROM A WHERE ColA1 = ? AND ColA2 = ?
       
    31 //then the names which will be give to the parameters will be:
       
    32 //"?0" and "?1"
       
    33 _LIT(KNamelessParameter, "?");
       
    34 
       
    35 
       
    36 /////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    37 //////////////////                HSqlSrvStmtParamBuf                  //////////////////////////////////
       
    38 /////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    39 
       
    40 /**
       
    41 Destroys the parameter buffer.
       
    42 
       
    43 Virtual method.
       
    44 */
       
    45 HSqlSrvStmtParamBuf::~HSqlSrvStmtParamBuf()
       
    46 	{
       
    47 	delete iBuf;
       
    48 	}
       
    49 
       
    50 /**
       
    51 Binds the parameter value.
       
    52 The buffer can be synch-ed if:
       
    53  - this is the first synch operation;
       
    54  - the bound statement object is still alive (not finalized);
       
    55  - the current object is alive;
       
    56  - the current object data is retrieved from an IPC stream;
       
    57  
       
    58 If none of the conditions above is true, the synch operation is no-op.
       
    59 
       
    60 Virtual method.
       
    61 */
       
    62 void HSqlSrvStmtParamBuf::DoSynchL()
       
    63 	{
       
    64 	if(iSynchDone || !iAlive || iStatementFinalized || iBufType != HSqlSrvStmtParamBuf::EBufIpcStream)
       
    65 		{
       
    66 		return;	
       
    67 		}
       
    68 	iSynchDone = ETrue;
       
    69 	TBufBuf::DoSynchL();
       
    70 	iStatement.BindParamBufL(iParamIndex);
       
    71 	}
       
    72 
       
    73 /**
       
    74 Destroys the HSqlSrvStmtParamBuf instance.
       
    75 This method is a no-op if the statement is not finalized yet.
       
    76 
       
    77 Virtual method.
       
    78 */
       
    79 void HSqlSrvStmtParamBuf::DoRelease()
       
    80  	{
       
    81 	iAlive = EFalse;
       
    82  	if(iStatementFinalized)
       
    83  		{//The bound statement has been finalized - destroy the current object then.
       
    84  		delete this;
       
    85  		}
       
    86 	}
       
    87 
       
    88 /**
       
    89 This function is called by the bound statement object to notify the current HSqlSrvStmtParamBuf object that the
       
    90 bound statement is about to be finalized. That means, when the "stream close" operation on the client side 
       
    91 makes an attempt to synch the HSqlSrvStmtParamBuf object, no attempt should be made to bound the parameter data,
       
    92 because the statement object is gone.
       
    93 After this call the bound statement objects seases to exist.
       
    94 
       
    95 Actions, performed by this method:
       
    96  - if the buffer type is "simple bind", the buffer will be destroyed. No reason to keep it alive, there is no bound IPC
       
    97    stream object on the client side;
       
    98  - if the buffer type is an IPC stream buffer and the buffer is alive, that means: the bound statement object is about to be
       
    99    finalized, but there is a bound client side IPC stream object that is still alive. In this case the buffer won't be destroyed,
       
   100    but will be "told" that the bound statement is finalized, so when the client side IPC stream is closed, this object will get destroyed;
       
   101  - if the buffer type is an IPC stream buffer and the buffer is "dead", that means there is no bound IPC stream object on the client
       
   102    side and it is safe to destroy the buffer;
       
   103 
       
   104 */ 	
       
   105 void HSqlSrvStmtParamBuf::NotifyStatementFinalized()
       
   106 	{
       
   107 	iStatementFinalized = ETrue;
       
   108 	if(iBufType == HSqlSrvStmtParamBuf::EBufSimpleBind || !iAlive)
       
   109 		{
       
   110 		DoRelease();	
       
   111 		}
       
   112 	}
       
   113 
       
   114 //////////////////////////////////////////////////////////////////////////////////////////////////////
       
   115 /////////////////////////////   CSqlSrvStatement class    ////////////////////////////////////////////
       
   116 //////////////////////////////////////////////////////////////////////////////////////////////////////
       
   117 
       
   118 /**
       
   119 Creates a new CSqlSrvStatement instance.
       
   120 
       
   121 The created CSqlSrvStatement instance will be placed in the cleanup stack.
       
   122 
       
   123 @param aDbHandle The database handle
       
   124 @param aSqlStmt 16-bit SQL statement, zero-terminated string
       
   125 @param aColumnCount Output parameter. It will be initialized with the column count.
       
   126 @param aParamCount Output parameter. It will be initialized with the parameter count.
       
   127 
       
   128 @return A pointer to the created CSqlSrvStatement instance.
       
   129 
       
   130 @leave KErrNoMemory, an out of memory condition has occurred;
       
   131 	   KErrArgument, bad argument, for example - the SQL string contains more than one SQL statements.
       
   132                   Note that the function may also leave with some other database specific 
       
   133                   errors categorised as ESqlDbError.
       
   134 
       
   135 @panic SqlDb 4 In _DEBUG mode if aSqlStmt is not zero-terminated string.
       
   136 */	
       
   137 CSqlSrvStatement* CSqlSrvStatement::NewLC(sqlite3* aDbHandle, const TDesC16& aSqlStmt, TInt& aColumnCount, TInt& aParamCount)
       
   138 	{
       
   139 	__SQLASSERT(aSqlStmt.Length() > 0 ? (TInt)aSqlStmt[aSqlStmt.Length() - 1] == 0 : ETrue, ESqlPanicBadArgument);
       
   140 	
       
   141 	CSqlSrvStatement* self = new (ELeave) CSqlSrvStatement;
       
   142 	CleanupStack::PushL(self);
       
   143 	self->ConstructL(aDbHandle, aSqlStmt);
       
   144 	SYMBIAN_TRACE_SQL_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KSrvStmtCreated, self));
       
   145 	aColumnCount = self->iColumnCount;
       
   146 	aParamCount = self->iParamCount;
       
   147 	return self;
       
   148 	}
       
   149 	
       
   150 /**
       
   151 Creates a new CSqlSrvStatement instance.
       
   152 
       
   153 The created CSqlSrvStatement instance will be placed in the cleanup stack.
       
   154 
       
   155 @param aDbHandle The database handle
       
   156 @param aSqlStmt 8-bit SQL statement, zero-terminated string
       
   157 @param aColumnCount Output parameter. It will be initialized with the column count.
       
   158 @param aParamCount Output parameter. It will be initialized with the parameter count.
       
   159 
       
   160 @return A pointer to the created CSqlSrvStatement instance.
       
   161 
       
   162 @leave KErrNoMemory, an out of memory condition has occurred;
       
   163 	   KErrArgument, bad argument, for example - the SQL string contains more than one SQL statements.
       
   164                   Note that the function may also leave with some other database specific 
       
   165                   errors categorised as ESqlDbError.
       
   166 
       
   167 @panic SqlDb 4 In _DEBUG mode if aSqlStmt is not zero-terminated string.
       
   168 */	
       
   169 CSqlSrvStatement* CSqlSrvStatement::NewLC(sqlite3* aDbHandle, const TDesC8& aSqlStmt, TInt& aColumnCount, TInt& aParamCount)
       
   170 	{
       
   171 	__SQLASSERT(aSqlStmt.Length() > 0 ? (TInt)aSqlStmt[aSqlStmt.Length() - 1] == 0 : ETrue, ESqlPanicBadArgument);
       
   172 
       
   173 	CSqlSrvStatement* self = new (ELeave) CSqlSrvStatement;
       
   174 	CleanupStack::PushL(self);
       
   175 	self->ConstructL(aDbHandle, aSqlStmt);
       
   176 	SYMBIAN_TRACE_SQL_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KSrvStmtCreated, self));
       
   177 	aColumnCount = self->iColumnCount;
       
   178 	aParamCount = self->iParamCount;
       
   179 	return self;
       
   180 	}
       
   181 	
       
   182 /**
       
   183 Destroys the allocated by CSqlSrvStatement instance memory and other resources.
       
   184 */	
       
   185 CSqlSrvStatement::~CSqlSrvStatement()
       
   186 	{
       
   187 	DestroyParamBufArray();
       
   188 	iBufFlat.Close();
       
   189 	if(iStmtHandle)
       
   190 		{
       
   191 #ifdef SYMBIAN_TRACE_SQL_EVENTS
       
   192 		TInt scanCount = sqlite3_stmt_status(iStmtHandle, SQLITE_STMTSTATUS_FULLSCAN_STEP, ETrue);
       
   193 		TInt sortCount = sqlite3_stmt_status(iStmtHandle, SQLITE_STMTSTATUS_SORT, ETrue);
       
   194 		SYMBIAN_TRACE_SQL_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KSrvStmtStatus, this, scanCount, sortCount));
       
   195 #endif
       
   196 		(void)sqlite3_finalize(iStmtHandle);
       
   197 		}
       
   198 	}
       
   199 
       
   200 /**
       
   201 Sets SQL statement parameter values.
       
   202 
       
   203 Only parameters, which values are set by the client, will be processed.
       
   204 
       
   205 @param aParamBuf Flat buffer with parameter values.
       
   206 
       
   207 @leave KErrArgument, unknown parameter type;
       
   208 	   KSqlErrStmtExpired, statement handle expired.
       
   209                   Note that the function may also leave with some other database specific 
       
   210                   errors categorised as ESqlDbError.
       
   211 
       
   212 @panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object.
       
   213 */	
       
   214 void CSqlSrvStatement::BindL(const RSqlBufFlat& aParamBuf)
       
   215 	{
       
   216 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
       
   217 	
       
   218 	(void)sqlite3SymbianLastOsError();//clear last OS error
       
   219 	if(sqlite3_expired(iStmtHandle))
       
   220 		{
       
   221 		__SQLLEAVE_IF_ERROR(KSqlErrStmtExpired);
       
   222 		}
       
   223 
       
   224 	TSqlBufRIterator it;
       
   225 	it.Set(aParamBuf);
       
   226 	TInt prmIdx = 0;
       
   227 	
       
   228 	TInt err = SQLITE_OK;
       
   229 	while(it.Next() && err == SQLITE_OK)
       
   230 		{
       
   231 		++prmIdx;//the first SQLITE parameter index is 1
       
   232 		if(it.IsPresent())
       
   233 			{
       
   234 			switch(it.Type())
       
   235  				{
       
   236 				case ESqlInt:
       
   237 					err = sqlite3_bind_int(iStmtHandle, prmIdx, it.Int());
       
   238 					break;
       
   239 				case ESqlInt64:
       
   240 					err = sqlite3_bind_int64(iStmtHandle, prmIdx, it.Int64());
       
   241 					break;
       
   242 				case ESqlReal: 
       
   243 					err = sqlite3_bind_double(iStmtHandle, prmIdx, it.Real());
       
   244 					break;
       
   245 				case ESqlText: 
       
   246 					//SQLITE_STATIC is used as an argument, because the text data will be kept and can be used by the next bind call
       
   247 					{
       
   248 					TPtrC text = it.Text();
       
   249 					TPtrC8 prmDataCopy(reinterpret_cast <const TUint8*> (text.Ptr()), text.Length() * sizeof(TUint16));
       
   250 					prmDataCopy.Set(CopyAndStoreParamL(prmIdx - 1, HSqlSrvStmtParamBuf::EText16, prmDataCopy));
       
   251 					err = sqlite3_bind_text16(iStmtHandle, prmIdx, prmDataCopy.Ptr(), prmDataCopy.Length(), SQLITE_STATIC);
       
   252 					}
       
   253 					break;
       
   254 				case ESqlBinary:
       
   255 					//SQLITE_STATIC is used as an argument, because the blob data will be kept and can be used by the next bind call
       
   256 					{
       
   257 					TPtrC8 prmDataCopy = CopyAndStoreParamL(prmIdx - 1, HSqlSrvStmtParamBuf::EBinary, it.Binary());
       
   258 					err = sqlite3_bind_blob(iStmtHandle, prmIdx, prmDataCopy.Ptr(), prmDataCopy.Length(), SQLITE_STATIC);
       
   259 					}
       
   260 					break;
       
   261 				case ESqlNull:
       
   262 					err = sqlite3_bind_null(iStmtHandle, prmIdx);
       
   263 					break;
       
   264 				case ESqlZeroBlob:
       
   265 					err = sqlite3_bind_zeroblob(iStmtHandle, prmIdx, it.Int());
       
   266 					break;
       
   267 				default:
       
   268 					__SQLLEAVE(KErrArgument);//unknown parameter type
       
   269 					break;
       
   270 				}
       
   271 			}//end of - if(it.IsPresent())
       
   272 		}//end of - while(it.Next() && err == SQLITE_OK)
       
   273 	err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
       
   274 	__SQLLEAVE_IF_ERROR(err);
       
   275 	}
       
   276 
       
   277 /**
       
   278 Collects column names in a flat buffer and returns a reference to the buffer. 
       
   279 
       
   280 @return A const reference to a flat buffer containing the column values.
       
   281 
       
   282 @leave KErrNoMemory, an out of memory condition has occurred.
       
   283 
       
   284 @panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object.
       
   285 */	
       
   286 const RSqlBufFlat& CSqlSrvStatement::ColumnNamesL()
       
   287 	{
       
   288 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
       
   289 	iBufFlatType = static_cast <TSqlBufFlatType> (-1);
       
   290 	__SQLLEAVE_IF_ERROR(iBufFlat.SetCount(iColumnCount));
       
   291 	TSqlBufWIterator it;
       
   292 	it.Set(iBufFlat);
       
   293 	TInt colIdx = -1;
       
   294 	while(it.Next())
       
   295 		{
       
   296 		++colIdx;//the first SQLITE column index is 0
       
   297 		const TUint16* name = reinterpret_cast <const TUint16*> (__SQLLEAVE_IF_NULL(const_cast <void*> (sqlite3_column_name16(iStmtHandle, colIdx))));
       
   298 		TPtrC ptr(name, User::StringLength(name));
       
   299 		__SQLLEAVE_IF_ERROR(it.SetText(ptr));
       
   300 		}
       
   301 	iBufFlatType = ESqlColumnNamesBuf;
       
   302 	SQLPROFILER_REPORT_ALLOC(iBufFlat.MaxSize());
       
   303 	return iBufFlat;
       
   304 	}
       
   305 
       
   306 /**
       
   307 Collects parameter names in a flat buffer and returns a reference to the buffer. 
       
   308 
       
   309 @return A const reference to a flat buffer containing the column values.
       
   310 
       
   311 @leave KErrNoMemory, an out of memory condition has occurred.
       
   312 
       
   313 @panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object.
       
   314 */	
       
   315 const RSqlBufFlat& CSqlSrvStatement::ParamNamesL()
       
   316 	{
       
   317 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
       
   318 	iBufFlatType = static_cast <TSqlBufFlatType> (-1);
       
   319 	__SQLLEAVE_IF_ERROR(iBufFlat.SetCount(iParamCount));
       
   320 	TSqlBufWIterator it;
       
   321 	it.Set(iBufFlat);
       
   322 	TInt prmIdx = 0;
       
   323 	while(it.Next())
       
   324 		{
       
   325 		++prmIdx;//the first SQLITE parameter index is 1
       
   326 		const TUint8* name8 = reinterpret_cast <const TUint8*> (sqlite3_bind_parameter_name(iStmtHandle, prmIdx));
       
   327 		if(name8)
       
   328 			{
       
   329 			HBufC* name = CnvUtfConverter::ConvertToUnicodeFromUtf8L(TPtrC8(name8, User::StringLength(name8)));
       
   330 			TInt err = it.SetText(name->Des());
       
   331 			delete name;
       
   332 			__SQLLEAVE_IF_ERROR(err);
       
   333 			}
       
   334 		else //nameless parameter case
       
   335 			{
       
   336 			//The parameter name in this case will be formatted as "?<num>", where <num> is the parameter index.
       
   337 			TBuf<5> prmName;
       
   338 			prmName.Append(KNamelessParameter);
       
   339 			prmName.AppendNum((TInt64)(prmIdx - 1));
       
   340 			__SQLLEAVE_IF_ERROR(it.SetText(prmName));
       
   341 			}
       
   342 		}
       
   343 	iBufFlatType = ESqlParamNamesBuf;
       
   344 	SQLPROFILER_REPORT_ALLOC(iBufFlat.MaxSize());
       
   345 	return iBufFlat;
       
   346 	}
       
   347 	
       
   348 /**
       
   349 Collects the column values in a flat buffer and returns a reference to the buffer. 
       
   350 
       
   351 @leave KErrNoMemory, an out of memory condition has occurred.
       
   352 
       
   353 @return A const reference to a flat buffer containing the column values.
       
   354 
       
   355 @panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object
       
   356 */	
       
   357 const RSqlBufFlat& CSqlSrvStatement::ColumnValuesL()
       
   358 	{
       
   359 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
       
   360 	
       
   361 	iBufFlatType = static_cast <TSqlBufFlatType> (-1);
       
   362 	iBufFlat.SetCount(iColumnCount);
       
   363 	TSqlBufWIterator it;
       
   364 	it.Set(iBufFlat);
       
   365 	TInt colIdx = -1;
       
   366 	
       
   367 	while(it.Next())
       
   368 		{
       
   369 		++colIdx;//the first SQLITE column index is 0
       
   370 		TInt colType = sqlite3_column_type(iStmtHandle, colIdx);
       
   371 		switch(colType)
       
   372 			{
       
   373 			case SQLITE_INTEGER:
       
   374 				{
       
   375 				TInt64 val = sqlite3_column_int64(iStmtHandle, colIdx);
       
   376 				__SQLLEAVE_IF_ERROR(val == TInt64(TInt32(val)) ? it.SetInt(static_cast <TInt> (val)) : it.SetInt64(val));
       
   377 				}
       
   378 				break;
       
   379 			case SQLITE_FLOAT:
       
   380 				__SQLLEAVE_IF_ERROR(it.SetReal(sqlite3_column_double(iStmtHandle, colIdx)));
       
   381 				break;
       
   382 			case SQLITE_TEXT:
       
   383 				{
       
   384 				TInt charLength = (TUint)sqlite3_column_bytes16(iStmtHandle, colIdx) / sizeof(TUint16);
       
   385 				if(charLength >= KSqlMaxDesLen)
       
   386 					{
       
   387 					it.SetAsNotPresent(ESqlText, charLength);
       
   388 					}
       
   389 				else
       
   390 					{
       
   391 					__SQLLEAVE_IF_ERROR(it.SetText(TPtrC16(reinterpret_cast <const TUint16*> (sqlite3_column_text16(iStmtHandle, colIdx)), charLength)));
       
   392 					}
       
   393 				}
       
   394 				break;
       
   395 			case SQLITE_BLOB:
       
   396 				{
       
   397 				TInt byteLength = sqlite3_column_bytes(iStmtHandle, colIdx);
       
   398 				if(byteLength >= KSqlMaxDesLen)
       
   399 					{
       
   400 					it.SetAsNotPresent(ESqlBinary, byteLength);
       
   401 					}
       
   402 				else
       
   403 					{
       
   404 					__SQLLEAVE_IF_ERROR(it.SetBinary(TPtrC8(reinterpret_cast <const TUint8*> (sqlite3_column_blob(iStmtHandle, colIdx)), byteLength)));
       
   405 					}
       
   406 				}
       
   407 				break;
       
   408 			case SQLITE_NULL:
       
   409 				it.SetNull();
       
   410 				break;
       
   411 			default:
       
   412 				__SQLASSERT(EFalse, ESqlPanicInternalError);
       
   413 				break;
       
   414 			}//end of switch(...)
       
   415 		}//end of - while(it.Next())
       
   416 	iBufFlatType = ESqlColumnValuesBuf;
       
   417 	SQLPROFILER_REPORT_ALLOC(iBufFlat.MaxSize());
       
   418 	return iBufFlat;
       
   419 	}
       
   420 
       
   421 /**
       
   422 This method sets aColumnSource parameter to point to the column data.
       
   423 
       
   424 @param aColumnIndex Column Index, zero based. 
       
   425 @param aColumnSource Output parameter. It is set to point to the column data.
       
   426 
       
   427 @return KErrNone, the operation completed successfully;
       
   428 		KErrArgument, the refered by aColumnIndex index column is not a binary or text column.
       
   429 
       
   430 @panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object.
       
   431 */	
       
   432 TInt CSqlSrvStatement::ColumnSource(TInt aColumnIndex, TPtrC8& aColumnSource) const
       
   433 	{
       
   434 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
       
   435 	TInt colType = sqlite3_column_type(iStmtHandle, aColumnIndex);
       
   436 	if(colType == SQLITE_TEXT)
       
   437 		{
       
   438 		const void* text = sqlite3_column_text16(iStmtHandle, aColumnIndex);
       
   439 		TInt length  = sqlite3_column_bytes16(iStmtHandle, aColumnIndex);
       
   440 		aColumnSource.Set(reinterpret_cast <const TUint8*> (text), length);
       
   441 		}
       
   442 	else if(colType == SQLITE_BLOB)
       
   443 		{
       
   444 		const void* data = sqlite3_column_blob(iStmtHandle, aColumnIndex);
       
   445 		TInt length  = sqlite3_column_bytes(iStmtHandle, aColumnIndex);
       
   446 		aColumnSource.Set(reinterpret_cast <const TUint8*> (data), length);
       
   447 		}
       
   448 	else
       
   449 		{
       
   450 		return KErrArgument;	
       
   451 		}
       
   452 	return KErrNone;
       
   453 	}
       
   454 
       
   455 /**
       
   456 Retrieves from the SQLITE library columns and parameters count.
       
   457 
       
   458 @panic SqlDb 4 In _DEBUG mode. aDbHandle is NULL.
       
   459 */	
       
   460 void CSqlSrvStatement::DoCommonConstructL()
       
   461 	{
       
   462 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
       
   463 	iColumnCount = sqlite3_column_count(iStmtHandle);
       
   464 	iParamCount = sqlite3_bind_parameter_count(iStmtHandle);
       
   465 	__SQLLEAVE_IF_ERROR(iBufFlat.SetCount(Max(iColumnCount, iParamCount)));
       
   466 	}
       
   467 
       
   468 /**
       
   469 Destroys the parameter buffer array (used for text or binary parameters).
       
   470 Before the array destruction, each array member is notified that the statement is about to be finalized.
       
   471 */
       
   472 void CSqlSrvStatement::DestroyParamBufArray()
       
   473 	{
       
   474 	TInt idx = iParamBufArray.Count();
       
   475 	while(--idx >= 0)
       
   476 		{
       
   477 		if(iParamBufArray[idx])
       
   478 			{
       
   479 			iParamBufArray[idx]->NotifyStatementFinalized();	
       
   480 			}
       
   481 		}
       
   482 	iParamBufArray.Close();
       
   483 	}
       
   484 	
       
   485 /**
       
   486 Binds a streamed text or binary parameter value.
       
   487 
       
   488 @param aParamIndex The text/binary parameter index
       
   489 
       
   490 @leave KErrNoMemory, an out of memory condition has occurred;
       
   491 	   KSqlErrStmtExpired, statement handle has expired.
       
   492                   Note that the function may also leave with some other database specific 
       
   493                   errors categorised as ESqlDbError.
       
   494 
       
   495 @panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object.
       
   496 @panic SqlDb 4 In _DEBUG mode. No parameter buffer has been created yet for this parameter.
       
   497 @panic SqlDb 4 In _DEBUG mode. Parameter index out of bounds.
       
   498 */
       
   499 void CSqlSrvStatement::BindParamBufL(TInt aParamIndex)
       
   500 	{
       
   501 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
       
   502 	__SQLASSERT(aParamIndex >= 0 && aParamIndex < sqlite3_bind_parameter_count(iStmtHandle), ESqlPanicBadArgument);
       
   503 	__SQLASSERT(aParamIndex < iParamBufArray.Count(), ESqlPanicBadArgument);
       
   504 	__SQLASSERT(iParamBufArray[aParamIndex] != NULL, ESqlPanicBadArgument);
       
   505 	(void)sqlite3SymbianLastOsError();//clear last OS error
       
   506 	if(sqlite3_expired(iStmtHandle))
       
   507 		{
       
   508 		__SQLLEAVE_IF_ERROR(KSqlErrStmtExpired);
       
   509 		}
       
   510 	//Bind the parameter value.
       
   511 	//SQLITE_STATIC is used as an argument, because the text/blob data will be kept and can be used by the next bind call
       
   512 	HSqlSrvStmtParamBuf& paramBuf = *iParamBufArray[aParamIndex];
       
   513 	const TPtrC8 paramData(paramBuf.Data());
       
   514 	SQLPROFILER_REPORT_ALLOC(paramData.Length());
       
   515 	TInt err = KErrNone;
       
   516 	++aParamIndex;//SQLite uses positive parameter indexes, the SQL server - parameter indexes begin from 0
       
   517 	switch(paramBuf.DataType())
       
   518 		{
       
   519 		case HSqlSrvStmtParamBuf::EText16:
       
   520 			//sqlite3_bind_text16() expects 4-th argument to be the bytes count, not the characters count.
       
   521 			err = sqlite3_bind_text16(iStmtHandle, aParamIndex, paramData.Ptr(), paramData.Length(), SQLITE_STATIC);
       
   522 			break;
       
   523 		case HSqlSrvStmtParamBuf::EBinary:
       
   524 		default:
       
   525 			err = sqlite3_bind_blob(iStmtHandle, aParamIndex, paramData.Ptr(), paramData.Length(), SQLITE_STATIC);
       
   526 			break;
       
   527 		}
       
   528 	err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
       
   529 	__SQLLEAVE_IF_ERROR(err);
       
   530 	}
       
   531 
       
   532 /**
       
   533 @return Represents the content of the column identified by aColIdx as integer value.
       
   534 		If the current column type does not refer to an integer, then 
       
   535 		the function will do a data conversion as described in the table which can be found
       
   536 		in SqlDb.h file.
       
   537 @see RSqlStatement
       
   538 
       
   539 @panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object.
       
   540 @panic SqlDb 4 In _DEBUG mode. Invalid aColIdx value.
       
   541 */
       
   542 TInt CSqlSrvStatement::ColumnInt(TInt aColIdx) const
       
   543 	{
       
   544 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
       
   545 	__SQLASSERT((TUint)aColIdx < iColumnCount, ESqlPanicBadArgument);
       
   546 	TInt colType = sqlite3_column_type(iStmtHandle, aColIdx);
       
   547 	switch(colType)
       
   548 		{
       
   549 		case SQLITE_FLOAT:
       
   550 			{
       
   551 			TReal roundVal;
       
   552 			TInt err = Math::Round(roundVal, sqlite3_column_double(iStmtHandle, aColIdx), 0);
       
   553 			if(err != KErrNone)
       
   554 				{
       
   555 				return KMinTInt;
       
   556 				}
       
   557 			TRealX val(roundVal);
       
   558 			return static_cast <TInt> (val);
       
   559 			}
       
   560 		case SQLITE_NULL:
       
   561 		case SQLITE_TEXT:
       
   562 		case SQLITE_BLOB:
       
   563 			return 0;
       
   564 		default:			//int, int64
       
   565 			{
       
   566 			TInt64 val = sqlite3_column_int64(iStmtHandle, aColIdx);
       
   567 			return val == (TInt)val ? (TInt)val : (val < KMinTInt ? KMinTInt : KMaxTInt);
       
   568 			}
       
   569 		}
       
   570 	}
       
   571 	
       
   572 /**
       
   573 @return Represents the content of the column identified by aColIdx as 64-bit integer value.
       
   574 		If the current column type does not refer to a 64-bit integer, then 
       
   575 		the function will do a data conversion as described in the table which can be found
       
   576 		in SqlDb.h file.
       
   577 @see RSqlStatement
       
   578 
       
   579 @panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object.
       
   580 @panic SqlDb 4 In _DEBUG mode. Invalid aColIdx value.
       
   581 */
       
   582 TInt64 CSqlSrvStatement::ColumnInt64(TInt aColIdx) const
       
   583 	{
       
   584 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
       
   585 	__SQLASSERT((TUint)aColIdx < iColumnCount, ESqlPanicBadArgument);
       
   586 	TInt colType = sqlite3_column_type(iStmtHandle, aColIdx);
       
   587 	switch(colType)
       
   588 		{
       
   589 		case SQLITE_FLOAT:
       
   590 			{
       
   591 			TReal roundVal;
       
   592 			TInt err = Math::Round(roundVal, sqlite3_column_double(iStmtHandle, aColIdx), 0);
       
   593 			if(err != KErrNone)
       
   594 				{
       
   595 				return KMinTInt64;
       
   596 				}
       
   597 			TRealX val(roundVal);
       
   598 			return static_cast <TInt64> (val);
       
   599 			}
       
   600 		case SQLITE_NULL:
       
   601 		case SQLITE_TEXT:
       
   602 		case SQLITE_BLOB:
       
   603 			return 0;
       
   604 		default:			//int, int64
       
   605 			return sqlite3_column_int64(iStmtHandle, aColIdx);
       
   606 		}
       
   607 	}
       
   608 	
       
   609 /**
       
   610 @return Represents the content of the column identified by aColIdx as real value.
       
   611 		If the current column type does not refer to a real, then 
       
   612 		the function will do a data conversion as described in the table which can be found
       
   613 		in SqlDb.h file.
       
   614 @see RSqlStatement
       
   615 
       
   616 @panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object.
       
   617 @panic SqlDb 4 In _DEBUG mode. Invalid aColIdx value.
       
   618 */
       
   619 TReal CSqlSrvStatement::ColumnReal(TInt aColIdx) const
       
   620 	{
       
   621 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
       
   622 	__SQLASSERT((TUint)aColIdx < iColumnCount, ESqlPanicBadArgument);
       
   623 	TInt colType = sqlite3_column_type(iStmtHandle, aColIdx);
       
   624 	switch(colType)
       
   625 		{
       
   626 		case SQLITE_INTEGER:
       
   627 			{
       
   628 			TRealX val(sqlite3_column_int64(iStmtHandle, aColIdx));	
       
   629 			return static_cast <TReal> (val);
       
   630 			}
       
   631 		case SQLITE_NULL:
       
   632 		case SQLITE_TEXT:
       
   633 		case SQLITE_BLOB:
       
   634 			return 0.0;
       
   635 		default:
       
   636 			return sqlite3_column_double(iStmtHandle, aColIdx);
       
   637 		}
       
   638 	}
       
   639 	
       
   640 /**
       
   641 Represents the content of the column identified by aColIdx as text (16 bit) descriptor.
       
   642 If the current column type does not refer to a text block of data, then 
       
   643 the function will do a data conversion as described in the table which can be found
       
   644 in SqlDb.h file.
       
   645 		
       
   646 @see RSqlStatement
       
   647 
       
   648 @panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object.
       
   649 @panic SqlDb 4 In _DEBUG mode. Invalid aColIdx value.
       
   650 */
       
   651 TPtrC CSqlSrvStatement::ColumnText(TInt aColIdx) const
       
   652 	{
       
   653 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
       
   654 	__SQLASSERT((TUint)aColIdx < iColumnCount, ESqlPanicBadArgument);
       
   655 	TPtrC res;
       
   656 	TInt colType = sqlite3_column_type(iStmtHandle, aColIdx);
       
   657 	if(colType == SQLITE_TEXT)
       
   658 		{
       
   659 		TInt charLength = (TUint)sqlite3_column_bytes16(iStmtHandle, aColIdx) / sizeof(TUint16);
       
   660 		res.Set(reinterpret_cast <const TUint16*> (sqlite3_column_text16(iStmtHandle, aColIdx)), charLength);
       
   661 		}
       
   662 	return res;
       
   663 	}
       
   664 	
       
   665 /**
       
   666 Represents the content of the column identified by aColIdx as binary (8 bit) descriptor.
       
   667 If the current column type does not refer to a binary block of data, then 
       
   668 the function will do a data conversion as described in the table which can be found
       
   669 in SqlDb.h file.
       
   670                       
       
   671 @see RSqlStatement
       
   672 
       
   673 @panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object.
       
   674 @panic SqlDb 4 In _DEBUG mode. Invalid aColIdx value.
       
   675 */
       
   676 TPtrC8 CSqlSrvStatement::ColumnBinary(TInt aColIdx) const
       
   677 	{
       
   678 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
       
   679 	__SQLASSERT((TUint)aColIdx < iColumnCount, ESqlPanicBadArgument);
       
   680 	TPtrC8 res;
       
   681 	TInt colType = sqlite3_column_type(iStmtHandle, aColIdx);
       
   682 	if(colType == SQLITE_BLOB)
       
   683 		{
       
   684 		TInt byteLength = sqlite3_column_bytes(iStmtHandle, aColIdx);
       
   685 		res.Set(reinterpret_cast <const TUint8*> (sqlite3_column_blob(iStmtHandle, aColIdx)), byteLength);
       
   686 		}
       
   687 	return res;
       
   688 	}
       
   689 
       
   690 /**
       
   691 This function is used by the DBMS emulation library only.
       
   692 The function retrieves the declared column types from the SQLITE library, compiles them in a single string
       
   693 and then returns the string to the caller.
       
   694 
       
   695 The function also initializes iColumnText8 array, where particular array element with index "idx" will 
       
   696 be set to 1, if the column with index "idx" is a 8-bit text column.
       
   697 
       
   698 @return A pointer to a heap allocated HBufC object with the delcared column types. The caller is responsible
       
   699 		for the HBufC object destruction.
       
   700 */
       
   701 HBufC* CSqlSrvStatement::GetDeclColumnTypesL()
       
   702 	{
       
   703 	HBufC* buf = HBufC::NewL(iColumnCount * 20);//20 as length is enough for a single column type text
       
   704 	TPtr ptr = buf->Des();
       
   705 	for(TInt i=0;i<iColumnCount;++i)
       
   706 		{
       
   707 		const TUint16* declTypeTxt = reinterpret_cast <const TUint16*> (sqlite3_column_decltype16(iStmtHandle, i));
       
   708 		if(declTypeTxt)
       
   709 			{
       
   710 			TPtrC type(declTypeTxt, User::StringLength(declTypeTxt));
       
   711 			ptr.Append(type);
       
   712 			}
       
   713 		ptr.Append(TChar(';'));
       
   714 		}
       
   715 	return buf;
       
   716 	}
       
   717 
       
   718 /**
       
   719 Creates a new HSqlSrvStmtParamBuf object.
       
   720 
       
   721 @param aParameterIndex Parameter index, zero based.
       
   722 @param aDataType Parameter value type - binary, text8 or text16.
       
   723 @param aIsStreamBuf True if the param data will be retrieved from an IPC stream
       
   724 
       
   725 @return A pointer to the created HSqlSrvStmtParamBuf instance.
       
   726 
       
   727 @leave KErrNoMemory, an out of memory condition has occurred;
       
   728 */
       
   729 HSqlSrvStmtParamBuf* CSqlSrvStatement::GetParamBufL(TInt aParamIndex, HSqlSrvStmtParamBuf::TDataType aDataType, 
       
   730 													HSqlSrvStmtParamBuf::TBufType aBufType)
       
   731 	{
       
   732 	__SQLASSERT(aParamIndex >= 0 && aParamIndex < sqlite3_bind_parameter_count(iStmtHandle), ESqlPanicBadArgument);
       
   733 	ExtendParamBufArrayL(aParamIndex);
       
   734 	HSqlSrvStmtParamBuf*& paramBuf = iParamBufArray[aParamIndex];
       
   735 	if(paramBuf)
       
   736 		{//Reset and reuse the existing buffer
       
   737 		__SQLASSERT(paramBuf->ParamIndex() == aParamIndex, ESqlPanicInternalError);
       
   738 		paramBuf->Reset(aDataType, aBufType);	
       
   739 		}
       
   740 	else
       
   741 		{
       
   742 		paramBuf = HSqlSrvStmtParamBuf::NewL(*this, aParamIndex, aDataType, aBufType);
       
   743 		}
       
   744 	return paramBuf;
       
   745 	}
       
   746 
       
   747 /**
       
   748 This function will extend the iParamBufArray array (filling the new array items with NULL), if it is needed - 
       
   749 to ensure that there is enough place for the buffer for the parameter identified by aParamIndex.
       
   750 
       
   751 @param aParamIndex The parameter index
       
   752 
       
   753 @leave KErrNoMemory, an out of memory condition has occurred;
       
   754 
       
   755 @panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object.
       
   756 @panic SqlDb 4 In _DEBUG mode. Parameter index out of bounds.
       
   757 */
       
   758 void CSqlSrvStatement::ExtendParamBufArrayL(TInt aParamIndex)
       
   759 	{
       
   760 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
       
   761 	__SQLASSERT(aParamIndex >= 0 && aParamIndex < sqlite3_bind_parameter_count(iStmtHandle), ESqlPanicBadArgument);
       
   762 	TInt ext = aParamIndex - iParamBufArray.Count() + 1;
       
   763 	while(ext-- > 0)
       
   764 		{
       
   765 		__SQLLEAVE_IF_ERROR(iParamBufArray.Append(NULL));
       
   766 		}
       
   767 	}
       
   768 
       
   769 /**
       
   770 This function will create a copy of the aParamValue and store it in the iParamBufArray array for later use.
       
   771 The reason: once bound, the parameter value can be used multiple times by the SQLite if it is not set explicitly again.
       
   772 
       
   773 @param aParamIndex The parameter index
       
   774 @param aDataType Parameter value type - binary, text8 or text16.
       
   775 @param aParamValue The parameter value
       
   776 
       
   777 @return 8-bit descriptor to the stored parameter value
       
   778 
       
   779 @leave KErrNoMemory, an out of memory condition has occurred;
       
   780                      
       
   781 @panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object.
       
   782 @panic SqlDb 4 In _DEBUG mode. Parameter index out of bounds.
       
   783 */
       
   784 TPtrC8 CSqlSrvStatement::CopyAndStoreParamL(TInt aParamIndex, HSqlSrvStmtParamBuf::TDataType aDataType, const TDesC8& aParamValue)
       
   785 	{
       
   786 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
       
   787 	__SQLASSERT(aParamIndex >= 0 && aParamIndex < sqlite3_bind_parameter_count(iStmtHandle), ESqlPanicBadArgument);
       
   788 	HSqlSrvStmtParamBuf* paramBuf = GetParamBufL(aParamIndex, aDataType, HSqlSrvStmtParamBuf::EBufSimpleBind);
       
   789 	return paramBuf->SetDataL(aParamValue);
       
   790 	}