diff -r 31a8f755b7fe -r 211563e4b919 persistentstorage/sql/SRC/Server/SqlSrvStatement.cpp --- a/persistentstorage/sql/SRC/Server/SqlSrvStatement.cpp Thu Apr 01 00:19:42 2010 +0300 +++ b/persistentstorage/sql/SRC/Server/SqlSrvStatement.cpp Wed Apr 14 17:46:32 2010 +0300 @@ -9,6 +9,7 @@ // Nokia Corporation - initial contribution. // // Contributors: +// NTT DOCOMO, INC - Fix for Bug 1915 "SQL server panics when using long column type strings" // // Description: // @@ -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 (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 (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 (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 (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 (sqlite3_column_text16(iStmtHandle, aColIdx)); + __SQLASSERT(text != NULL, ESqlPanicInternalError); + res.Set(text, charLength); } return res; } @@ -688,30 +713,47 @@ } /** -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. -@return A pointer to a heap allocated HBufC object with the delcared column types. The caller is responsible - for the HBufC object destruction. +@leave KErrNoMemory, an out of memory condition has occurred; + +@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 (-1); + __SQLLEAVE_IF_ERROR(iBufFlat.SetCount(iColumnCount)); + TSqlBufWIterator it; + it.Set(iBufFlat); + TInt colIdx = -1; + while(it.Next()) { - const TUint16* declTypeTxt = reinterpret_cast (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 (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 for the parameter with index "aParamIndex" or reuses the existing one.