Details
-
Bug
-
Resolution: Done
-
P2: Important
-
4.5.3
-
None
-
46d5f85a03bd87708152baba2674f2e5f36afe22
Description
Since the MYSQL_FIELD member named length describes the width of a column as the "display length" ( http://dev.mysql.com/doc/refman/5.0/en/c-api-datatypes.html ), it includes formatting information--such as the display width for numeric types. As documented at http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html , "The display width does not constrain the range of values that can be stored in the column, nor the number of digits that are displayed for values having a width exceeding that specified for the column. For example, a column specified as SMALLINT(3) has the usual SMALLINT range of -32768 to 32767, and values outside the range allowed by three characters are displayed using more than three characters." Therefore, when using length to allocate buffers in QMYSQLResultPrivate::bindInValues(), the buffer may be too small to hold values.
The db_length, on the other hand describes the width of the column as represented in the database. Therefore, the attached patch changes QMYSQLResultPrivate::bindInValues() to use db_length when allocating buffers for non-BLOB fields.
The attached test application, test_qt_data_truncation.cpp , can be used to see the effect of the invalid buffer allocation. The application creates a temporary table with a TINYINT(1) column and populates the table with rows, including a row in the middle of the table with a value of 127. To use the test application edit the database host, database name, username, and password as appropriate.
Without the attached patch, qt-4.5-use_db_length_for_buffer_allocation.patch , the call to QSqlQuery::next() for the row with the value 127 when the statement was executed as a prepared statement results in mysql_stmt_fetch() returning MYSQL_DATA_TRUNCATED because the allocated buffer is too small to hold the field value. When this occurs, QSqlQuery::next() returns false and the loop is terminated--without accessing the rest of the values in the result.
Note, also, that the patch at http://bugreports.qt.nokia.com/browse/QTBUG-5758 ensures that a lastError is set when an error or data truncation occurs in QMYSQLResult::fetchNext() (so without the patch in QTBUG-5758, the lastError will be empty when the failure occurs).
Additional notes for reproducing the issue:
Before Qt4, the Qt MySQL drivers never used real prepared queries. Therefore, this issue did not occur in Qt3.
In Qt4 version 4.4.x and below,~prepared statements were only used if the developer explicitly requested prepared statements with QSqlQuery::prepare().
In Qt4 version 4.5.0 and above, the Qt MySQL drivers always attempt to use prepared queries (and succeed for SELECT statements), even if the developer does not request a prepared query using QSqlQuery::prepare(). Therefore, the described bug will always affect users of Qt 4.5.x and above.