Bug #61991 SQLGetData return shorter than expected string when multiple rows are fetched
Submitted: 26 Jul 2011 21:14 Modified: 21 Feb 2024 23:43
Reporter: Yan Dai Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / ODBC Severity:S2 (Serious)
Version:5.1.8 OS:Windows (Windows 7 Enterprise)
Assigned to: Bogdan Degtyariov CPU Architecture:Any

[26 Jul 2011 21:14] Yan Dai
Description:
I am running MySQL connector installed from version 
5.1.8 on a 64 bit machine.

The table names from select table query are truncated on some test scenarios.

Please see "How to repeat" section.

With SQLGetData calls, the returned table name are "object_equip" and "Transactions". It appeared last record's length is used for return data when doing multiple row fetch.

How to repeat:
First create two tables:

object_equipment
Transactions

Then call following functions. To show the code cleanly, I omitted the return error checking.

SQLExecDirect(handle, SqlString("SELECT table_name from information_schema.TABLES where table_schema=(select database())"), SQL_NTS);

SQLULEN nRowsFetched = 0;
SetStatementAttrPtr(SQL_ATTR_ROWS_FETCHED_PTR, &nRowsFetched);
SetStatementAttr(SQL_ATTR_ROW_ARRAY_SIZE, 100);

SQLFetchScroll(handle, SQL_FETCH_NEXT, 0);

SQLSetPos(handle, 1, SQL_POSITION, SQL_LOCK_NO_CHANGE);
SQLLEN len;
SQLCHAR pBuffer[65536];
SQLGetData(handle, 1, SQL_C_CHAR, pBuffer, 65536, &len);

The len returned will be 12 instead of real length of "object_equipment".

Suggested fix:
In results.c sql_get_data() function, the length should not use the length in last row, it should use the corresponding column current_values. 

The following code 

    /* catalog functions with "fake" results won't have lengths */
    length= irrec->row.datalen;
    if (!length && stmt->current_values[ColumnNumber])
      length= strlen(stmt->current_values[ColumnNumber]);

changed to:

    /* catalog functions with "fake" results won't have lengths */
    length= irrec->row.datalen;
    if (stmt->current_values[ColumnNumber])
      length= strlen(stmt->current_values[ColumnNumber]);

These changes would fix the issue.
[5 Aug 2011 11:35] Bogdan Degtyariov
Yan,

Thank you for the very detailed bug description.
I was able to repeat the problem locally.
Setting the bug status to verified and checking the solution kindly offered by you.
[5 Aug 2011 12:20] Bogdan Degtyariov
We cannot just use your patch as it is because it would break handling empty result sets.

It seems that the irrec->row.datalen is set to the last result length, which is 12 in this particular case because the length of the table name `Transactions` is 12.
[5 Aug 2011 16:43] Yan Dai
I found another issue in SQLGetData that using strlen for column value length did not work for blob or unicode data. I would suggest to add current_lengths corresponding to current_values in STMT struct and set current_lengths via mysql_fetch_lengths() call when mysql_fetch_row is called.

I made a patch to solve the original issue and incorrect blob length issue. Please see the attachment.
[5 Aug 2011 16:44] Yan Dai
bug fix for length setup in SQLGetData

Attachment: bug61991.patch (application/octet-stream, text), 3.04 KiB.

[15 Sep 2011 18:49] Yan Dai
Hi Bogdan,
   Thanks for reviewing the previous patch. Did you get a chance to review the patch I submitted on Aug, 5th?

Thanks,
Yan
[15 Dec 2023 6:16] Bogdan Degtyariov
Posted by developer:
 
The driver is now updating the lengths when the position in the rowset is changed using SQLSetPos() function.

The patch has been pushed into the source tree.
[21 Feb 2024 23:43] Philip Olson
Posted by developer:
 
Fixed as of the upcoming MySQL Connector/ODBC 8.4.0 release, and here's the proposed changelog entry from the documentation team:

Changing position in the row set with SQLSetPos() would not update the
lengths, which could cause SQLGetData() to retrieve less data than
expected.

Thank you for the bug report.