From: Date: May 19 2006 8:50am Subject: Connector/ODBC 5 commit: r258 - MYODBCC/MYODBCCLib MYODBCC/include MYSQLPlus/MYSQLPlusLib List-Archive: http://lists.mysql.com/commits/6611 Message-Id: <200605190650.k4J6oKJh031050@bk-internal.mysql.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modified: MYODBCC/MYODBCCLib/MYODBCC.cpp MYODBCC/include/MYODBCC.h MYSQLPlus/MYSQLPlusLib/MResult.cpp MYSQLPlus/MYSQLPlusLib/MResult.h Log: Modified: MYODBCC/MYODBCCLib/MYODBCC.cpp =================================================================== --- MYODBCC/MYODBCCLib/MYODBCC.cpp 2006-05-18 21:38:18 UTC (rev 257) +++ MYODBCC/MYODBCCLib/MYODBCC.cpp 2006-05-19 06:50:17 UTC (rev 258) @@ -1391,13 +1391,106 @@ return true; } #else - BOOLEAN MYODBCC::doStrNCpy( SQLWCHAR *pszDest, size_t nChars, const SQLWCHAR *pszSrc ) + BOOLEAN MYODBCC::doStrNCpy( SQLWCHAR *pszDest, size_t nMaxChars, const SQLWCHAR *pszSrc ) { wcsncpy( pszDest, pszSrc, nChars ); return true; } #endif +/*! + \brief Copies a C string. + + The following occurs in this method; + + 1. the dest string is always null terminated (unless buffer is not provided) + 2. considers truncation + + \return BOOLEAN + + \retval true Copy completed with no warnings/errors + false Copy completed but result was truncated due to lack of space in dest buffer +*/ +BOOLEAN MYODBCC::doStringCopyOut( SQLCHAR *pszDest, SQLINTEGER nDestMaxChars, SQLCHAR *pszSrc ) +{ + SQLINTEGER nIndex = 0; + + /* sanity checks */ + if ( !pszDest || nDestMaxChars < 1 ) + { + if ( *pszSrc ) + return false; + return true; + } + + if ( !pszSrc ) + { + *pszDest = '\0'; + return true; /* ok - but nothing to copy */ + } + + /* copy chars while room in pszDest or end of pszSrc */ + for ( nIndex = 0; nIndex < nDestMaxChars; nIndex++ ) + { + pszDest[nIndex] = pszSrc[nIndex]; + if ( pszSrc[nIndex] == '\0' ) + return true; + } + + /* pszDest full - ensure last char is null terminator */ + pszDest[nIndex-1] = '\0'; + + /* results are truncated */ + return false; +} + +/*! + \brief Copies a wide character C string. + + The following occurs in this method; + + 1. the dest string is always null terminated (unless buffer is not provided) + 2. considers truncation + + \return BOOLEAN + + \retval true Copy completed with no warnings/errors + false Copy completed but result was truncated due to lack of space in dest buffer +*/ +BOOLEAN MYODBCC::doStringCopyOut( SQLWCHAR *pszDest, SQLINTEGER nDestMaxChars, SQLWCHAR *pszSrc ) +{ + SQLINTEGER nIndex = 0; + + /* sanity checks */ + if ( !pszDest || nDestMaxChars < 1 ) + { + if ( *pszSrc ) + return false; + return true; + } + + if ( !pszSrc ) + { + *pszDest = '\0'; + return true; /* ok - but nothing to copy */ + } + + /* copy chars while room in pszDest or end of pszSrc */ + for ( nIndex = 0; nIndex < nDestMaxChars; nIndex++ ) + { + pszDest[nIndex] = pszSrc[nIndex]; + if ( pszSrc[nIndex] == '\0' ) + return true; + } + + /* pszDest full - ensure last char is null terminator */ + pszDest[nIndex-1] = '\0'; + + /* results are truncated */ + return false; +} + + void MYODBCC::doFree( void *p ) { if ( p ) Modified: MYODBCC/include/MYODBCC.h =================================================================== --- MYODBCC/include/MYODBCC.h 2006-05-18 21:38:18 UTC (rev 257) +++ MYODBCC/include/MYODBCC.h 2006-05-19 06:50:17 UTC (rev 258) @@ -250,6 +250,9 @@ static BOOLEAN doStrNCpy( SQLWCHAR *pszDest, size_t nSizeInWords, const SQLWCHAR *pszSrc ); #endif + static BOOLEAN doStringCopyOut( SQLCHAR *pszDest, SQLINTEGER nDestMaxChars, SQLCHAR *pszSrc ); + static BOOLEAN doStringCopyOut( SQLWCHAR *pszDest, SQLINTEGER nDestMaxChars, SQLWCHAR *pszSrc ); + static void doFree( void *p ); static BOOLEAN isConnectAttr( SQLINTEGER nAttribute ); Modified: MYSQLPlus/MYSQLPlusLib/MResult.cpp =================================================================== --- MYSQLPlus/MYSQLPlusLib/MResult.cpp 2006-05-18 21:38:18 UTC (rev 257) +++ MYSQLPlus/MYSQLPlusLib/MResult.cpp 2006-05-19 06:50:17 UTC (rev 258) @@ -41,7 +41,6 @@ pnIndicator = NULL; nTargetTypeAdjusted = SQL_C_CHAR; - nBytesRemaining = 0; nIndicator = SQL_NO_TOTAL; variantData.clear(); pDescriptorRecordIRD = NULL; @@ -56,7 +55,7 @@ MYODBCDbgEnter(); if ( this->nColumn == nColumn && - nBytesRemaining > 0 && + !variantData.isNull() && this->nTargetType == nTargetType && MDescriptorRecordIRD::isVariableLength( nType ) ) { @@ -1007,6 +1006,14 @@ | SQL_C_CHAR | Byte length of data < BufferLength | Data | Length of data in bytes | n/a | | | Byte length of data >= BufferLength | Truncated data | Length of data in bytes | 01004 | +-------------+-------------------------------------+-----------------+-------------------------+----------+ + + When character data is returned from the driver to the application, the driver must always null-terminate it. + This gives the application the choice of whether to handle the data as a string or a character array. If the + application buffer is not large enough to return all of the character data, the driver truncates it to the byte + length of the buffer less the number of bytes required by the null-termination character, null-terminates the + truncated data, and stores it in the buffer. Therefore, applications must always allocate extra space for the + null-termination character in buffers used to retrieve character data. For example, a 51-byte buffer is needed + to retrieve 50 characters of data. */ if ( !resultGetData.variantData.canConvert() ) @@ -1015,16 +1022,24 @@ QString stringData = resultGetData.variantData.toString(); if ( resultGetData.pTarget && resultGetData.nBytesMax ) { - MYODBCC::doStrNCpy( (SQLCHAR*)resultGetData.pTarget, resultGetData.nBytesMax, stringData.toAscii().data() ); - if ( resultGetData.nBytesMax >= stringData.length() ) + if ( MYODBCC::doStringCopy( (SQLCHAR*)resultGetData.pTarget, resultGetData.nBytesMax, stringData.toAscii().data() ) ) + { + variantData.clear(); + if ( resultGetData.pnBytesRemaining ) *resultGetData.pnBytesRemaining = 0; + } + else + { + if ( resultGetData.pnBytesRemaining ) *resultGetData.pnBytesRemaining = stringData.length() - resultGetData.nBytesMax; + variantData.setValue( stringData.mid( resultGetData.nBytesMax - 1 ) ); MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_01004 ) ); + } } else + { + if ( resultGetData.pnBytesRemaining ) *resultGetData.pnBytesRemaining = stringData.length(); MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_01004 ) ); + } - resultGetData.nBytesRemaining = ( stringData.length() + 1 ) - resultGetData.nBytesMax; - if ( resultGetData.pnBytesRemaining ) *resultGetData.pnBytesRemaining = resultGetData.nBytesRemaining; - MYODBCDbgReturn( SQL_SUCCESS ); } @@ -1041,6 +1056,14 @@ | SQL_C_WCHAR | Character length of data < BufferLength | Data | Length of data in characters | n/a | | | Character length of data >= BufferLength | Truncated data | Length of data in characters | 01004 | +-------------+------------------------------------------+-----------------+------------------------------+----------+ + + When character data is returned from the driver to the application, the driver must always null-terminate it. + This gives the application the choice of whether to handle the data as a string or a character array. If the + application buffer is not large enough to return all of the character data, the driver truncates it to the byte + length of the buffer less the number of bytes required by the null-termination character, null-terminates the + truncated data, and stores it in the buffer. Therefore, applications must always allocate extra space for the + null-termination character in buffers used to retrieve character data. For example, a 51-byte buffer is needed + to retrieve 50 characters of data. */ if ( !resultGetData.variantData.canConvert() ) @@ -1049,16 +1072,24 @@ QString stringData = resultGetData.variantData.toString(); if ( resultGetData.pTarget && resultGetData.nBytesMax ) { - MYODBCC::doStrNCpy( (SQLWCHAR*)resultGetData.pTarget, resultGetData.nBytesMax / sizeof(SQLWCHAR), stringData.utf16() ); - if ( resultGetData.nBytesMax >= stringData.length() / sizeof(SQLWCHAR) ) + if ( MYODBCC::doStringCopy( (SQLWCHAR*)resultGetData.pTarget, resultGetData.nBytesMax / sizeof(SQLWCHAR), stringData.utf16() ) ) + { + variantData.clear(); + if ( resultGetData.pnBytesRemaining ) *resultGetData.pnBytesRemaining = 0; + } + else + { + if ( resultGetData.pnBytesRemaining ) *resultGetData.pnBytesRemaining = stringData.length() * sizeof(SQLWCHAR) - resultGetData.nBytesMax; + variantData.setValue( stringData.mid( (resultGetData.nBytesMax - 1) / sizeof(SQLWCHAR) ) ); MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_01004 ) ); + } } else + { + if ( resultGetData.pnBytesRemaining ) *resultGetData.pnBytesRemaining = stringData.length() * sizeof(SQLWCHAR); MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_01004 ) ); + } - resultGetData.nBytesRemaining = ( stringData.length() + 1 ) - resultGetData.nBytesMax / sizeof(SQLWCHAR); - if ( resultGetData.pnBytesRemaining ) *resultGetData.pnBytesRemaining = resultGetData.nBytesRemaining; - MYODBCDbgReturn( SQL_SUCCESS ); } @@ -1231,13 +1262,32 @@ { MYODBCDbgEnter(); + if ( !resultGetData.variantData.canConvert() ) + MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_07006 ) ); + QByteArray bytearray = resultGetData.variantData.toByteArray(); - MYODBCC::doMemCpy( resultGetData.pTarget, bytearray.constData(), resultGetData.nBytesMax ); + if ( resultGetData.pTarget && resultGetData.nBytesMax ) + { + MYODBCC::doMemCpy( resultGetData.pTarget, bytearray.constData(), min( resultGetData.nBytesMax, bytearray.size() ) ); + if ( bytearray.size() <= resultGetData.nBytesMax ) + { + variantData.clear(); + if ( resultGetData.pnBytesRemaining ) *resultGetData.pnBytesRemaining = 0; + } + else + { + if ( resultGetData.pnBytesRemaining ) *resultGetData.pnBytesRemaining = bytearray.size() - resultGetData.nBytesMax; + variantData.setValue( bytearray.mid( resultGetData.nBytesMax - 1 ) ); + MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_01004 ) ); + } + } + else + { + if ( resultGetData.pnBytesRemaining ) *resultGetData.pnBytesRemaining = bytearray.size(); + MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_01004 ) ); + } - resultGetData.nBytesRemaining = bytearray.size() - resultGetData.nBytesMax; - if ( resultGetData.pnBytesRemaining ) *resultGetData.pnBytesRemaining = resultGetData.nBytesRemaining; - MYODBCDbgReturn( SQL_SUCCESS ); } Modified: MYSQLPlus/MYSQLPlusLib/MResult.h =================================================================== --- MYSQLPlus/MYSQLPlusLib/MResult.h 2006-05-18 21:38:18 UTC (rev 257) +++ MYSQLPlus/MYSQLPlusLib/MResult.h 2006-05-19 06:50:17 UTC (rev 258) @@ -41,7 +41,6 @@ /* these are additional fields which assist in maintaining our getData state */ SQLSMALLINT nTargetTypeAdjusted; /*!< is nTargetType, SQL_C_DEFAULT derived, or ARD derived */ - SQLINTEGER nBytesRemaining; /*!< cached ver of value at pnBytesRemaining */ SQLINTEGER nIndicator; /*!< cached ver of value at pnIndicator */ QVariant variantData; /*!< resultset cell data */ MDescriptorRecordIRD * pDescriptorRecordIRD; /*!< descriptor describing the resultset column */