persistentstorage/sql/SRC/Server/SqlSrvStatement.cpp
changeset 17 55f2396f6d25
parent 0 08ec8eefde2f
child 22 a7ba600cb39d
--- a/persistentstorage/sql/SRC/Server/SqlSrvStatement.cpp	Fri Apr 16 16:49:27 2010 +0300
+++ b/persistentstorage/sql/SRC/Server/SqlSrvStatement.cpp	Mon May 03 14:09:14 2010 +0300
@@ -1,4 +1,4 @@
-// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+// 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"
@@ -9,6 +9,7 @@
 // Nokia Corporation - initial contribution.
 //
 // Contributors:
+// NTT DOCOMO, INC - Fix for defect 1915 "SQL server panics when using long column type strings"
 //
 // Description:
 //
@@ -28,7 +29,7 @@
 //This is the name prefix which will be given to the nameless parameters.
 //For example, if the SQL string is:
 //   SELECT * FROM A WHERE ColA1 = ? AND ColA2 = ?
-//then the names which will be give to the parameters will be:
+//then the names which will be given to the parameters will be:
 //"?0" and "?1"
 _LIT(KNamelessParameter, "?");
 
@@ -90,7 +91,7 @@
 bound statement is about to be finalized. That means, when the "stream close" operation on the client side 
 makes an attempt to synch the HSqlSrvStmtParamBuf object, no attempt should be made to bound the parameter data,
 because the statement object is gone.
-After this call the bound statement objects seases to exist.
+After this call the bound statement objects ceases to exist.
 
 Actions, performed by this method:
  - if the buffer type is "simple bind", the buffer will be destroyed. No reason to keep it alive, there is no bound IPC
@@ -200,7 +201,7 @@
 /**
 Sets SQL statement parameter values.
 
-Only parameters, which values are set by the client, will be processed.
+Only parameters, whose values are set by the client, will be processed.
 
 @param aParamBuf Flat buffer with parameter values.
 
@@ -277,7 +278,7 @@
 /**
 Collects column names in a flat buffer and returns a reference to the buffer. 
 
-@return A const reference to a flat buffer containing the column values.
+@return A const reference to a flat buffer containing the column names.
 
 @leave KErrNoMemory, an out of memory condition has occurred.
 
@@ -306,7 +307,7 @@
 /**
 Collects parameter names in a flat buffer and returns a reference to the buffer. 
 
-@return A const reference to a flat buffer containing the column values.
+@return A const reference to a flat buffer containing the parameter names.
 
 @leave KErrNoMemory, an out of memory condition has occurred.
 
@@ -382,13 +383,22 @@
 			case SQLITE_TEXT:
 				{
 				TInt charLength = (TUint)sqlite3_column_bytes16(iStmtHandle, colIdx) / sizeof(TUint16);
+                //"charLength == 0" - this might be an indication of an "out of memory" problem, if the column text is in UTF8 format. 
+                //(sqlite3_column_bytes16() may allocate memory for UTF8->UTF16 conversion)
+				if(charLength == 0 && sqlite3_errcode(sqlite3_db_handle(iStmtHandle)) == SQLITE_NOMEM)
+                    {
+                    __SQLLEAVE(KErrNoMemory);
+                    }
 				if(charLength >= KSqlMaxDesLen)
 					{
 					it.SetAsNotPresent(ESqlText, charLength);
 					}
 				else
-					{
-					__SQLLEAVE_IF_ERROR(it.SetText(TPtrC16(reinterpret_cast <const TUint16*> (sqlite3_column_text16(iStmtHandle, colIdx)), charLength)));
+					{//sqlite3_column_bytes16() already allocated the needed memory if a UTF8->UTF16 conversion
+                     //had to be performed. The sqlite3_column_text16() on the next line is guaranteed to succeed.
+					const TUint16* text = reinterpret_cast <const TUint16*> (sqlite3_column_text16(iStmtHandle, colIdx));
+					__SQLASSERT(text != NULL, ESqlPanicInternalError);
+					__SQLLEAVE_IF_ERROR(it.SetText(TPtrC16(text, charLength)));
 					}
 				}
 				break;
@@ -434,8 +444,11 @@
 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
 	TInt colType = sqlite3_column_type(iStmtHandle, aColumnIndex);
 	if(colType == SQLITE_TEXT)
-		{
+        {//Since the first called function after the Next() operation is always CSqlSrvStatement::ColumnValuesL(), then
+         //sqlite3_column_bytes16() (called from  ColumnValuesL()) already allocated the needed memory if a UTF8->UTF16 
+         //conversion had to be performed. The sqlite3_column_text16() on the next line is guaranteed to succeed.
 		const void* text = sqlite3_column_text16(iStmtHandle, aColumnIndex);
+        __SQLASSERT(text != NULL, ESqlPanicInternalError);
 		TInt length  = sqlite3_column_bytes16(iStmtHandle, aColumnIndex);
 		aColumnSource.Set(reinterpret_cast <const TUint8*> (text), length);
 		}
@@ -645,10 +658,12 @@
 		
 @see RSqlStatement
 
+@leave KErrNoMemory, an out of memory condition has occurred.
+
 @panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object.
 @panic SqlDb 4 In _DEBUG mode. Invalid aColIdx value.
 */
-TPtrC CSqlSrvStatement::ColumnText(TInt aColIdx) const
+TPtrC CSqlSrvStatement::ColumnTextL(TInt aColIdx) const
 	{
 	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
 	__SQLASSERT((TUint)aColIdx < iColumnCount, ESqlPanicBadArgument);
@@ -657,7 +672,17 @@
 	if(colType == SQLITE_TEXT)
 		{
 		TInt charLength = (TUint)sqlite3_column_bytes16(iStmtHandle, aColIdx) / sizeof(TUint16);
-		res.Set(reinterpret_cast <const TUint16*> (sqlite3_column_text16(iStmtHandle, aColIdx)), charLength);
+        //"charLength == 0" - this might be an indication of an "out of memory" problem, if the column text is in UTF8 format. 
+        //(sqlite3_column_bytes16() may allocate memory for UTF8->UTF16 conversion)
+        if(charLength == 0 && sqlite3_errcode(sqlite3_db_handle(iStmtHandle)) == SQLITE_NOMEM)
+            {
+            __SQLLEAVE(KErrNoMemory);
+            }
+        //sqlite3_column_bytes16() already allocated the needed memory if a UTF8->UTF16 conversion
+        //had to be performed. The sqlite3_column_text16() on the next line is guaranteed to succeed.
+        const TUint16* text = reinterpret_cast <const TUint16*> (sqlite3_column_text16(iStmtHandle, aColIdx));
+        __SQLASSERT(text != NULL, ESqlPanicInternalError);
+		res.Set(text, charLength);
 		}
 	return res;
 	}
@@ -688,37 +713,52 @@
 	}
 
 /**
-This function is used by the DBMS emulation library only.
-The function retrieves the declared column types from the SQLITE library, compiles them in a single string
-and then returns the string to the caller.
+Retrieves the declared column types using the SQLITE library storing in a 
+flat buffer and returns a reference to the buffer. 
+
+@return A const reference to a flat buffer containing the declared column type names.
 
-The function also initializes iColumnText8 array, where particular array element with index "idx" will 
-be set to 1, if the column with index "idx" is a 8-bit text column.
+@leave KErrNoMemory, an out of memory condition has occurred;
 
-@return A pointer to a heap allocated HBufC object with the delcared column types. The caller is responsible
-		for the HBufC object destruction.
+@panic SqlDb 2 In _DEBUG mode. Invalid (not created) CSqlSrvStatement object.
 */
-HBufC* CSqlSrvStatement::GetDeclColumnTypesL()
+const RSqlBufFlat& CSqlSrvStatement::GetDeclColumnTypesL()
 	{
-	HBufC* buf = HBufC::NewL(iColumnCount * 20);//20 as length is enough for a single column type text
-	TPtr ptr = buf->Des();
-	for(TInt i=0;i<iColumnCount;++i)
+	__SQLASSERT(iStmtHandle != NULL, ESqlPanicInvalidObj);
+	iBufFlatType = static_cast <TSqlBufFlatType> (-1);
+	__SQLLEAVE_IF_ERROR(iBufFlat.SetCount(iColumnCount));
+	TSqlBufWIterator it;
+	it.Set(iBufFlat);
+	TInt colIdx = -1;
+	while(it.Next())
 		{
-		const TUint16* declTypeTxt = reinterpret_cast <const TUint16*> (sqlite3_column_decltype16(iStmtHandle, i));
-		if(declTypeTxt)
-			{
-			TPtrC type(declTypeTxt, User::StringLength(declTypeTxt));
-			ptr.Append(type);
-			}
-		ptr.Append(TChar(';'));
+		++colIdx;//the first SQLITE column index is 0
+		const TUint16* declTypeTxt = reinterpret_cast <const TUint16*> (sqlite3_column_decltype16(iStmtHandle, colIdx));
+		TPtrC ptr(KNullDesC);
+        if(declTypeTxt)
+            {
+            ptr.Set(declTypeTxt, User::StringLength(declTypeTxt));
+            }
+        else
+            {
+            //If sqlite3_column_decltype16() returns NULL but sqlite3_column_decltype() doesn't, then it is an "out of memory" condition 
+            if(sqlite3_column_decltype(iStmtHandle, colIdx))
+                {
+                __SQLLEAVE(KErrNoMemory);
+                }
+            }
+		__SQLLEAVE_IF_ERROR(it.SetText(ptr));
 		}
-	return buf;
+	iBufFlatType = ESqlDeclColumnTypesBuf;
+	return iBufFlat;	
 	}
 
+
 /**
-Creates a new HSqlSrvStmtParamBuf object.
+Creates a new HSqlSrvStmtParamBuf object for the parameter with index "aParamIndex" or
+reuses the existing one.
 
-@param aParameterIndex Parameter index, zero based.
+@param aParamIndex Parameter index, zero based.
 @param aDataType Parameter value type - binary, text8 or text16.
 @param aIsStreamBuf True if the param data will be retrieved from an IPC stream
 
@@ -746,7 +786,7 @@
 
 /**
 This function will extend the iParamBufArray array (filling the new array items with NULL), if it is needed - 
-to ensure that there is enough place for the buffer for the parameter identified by aParamIndex.
+to ensure that there is enough place in the buffer for the parameter identified by aParamIndex.
 
 @param aParamIndex The parameter index