-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
From https://sourceforge.net/p/poco/bugs/608/
When a result set contains a largeblob or largetext field, mysql_fetch_fields() returns 2^32 as length of that field. ResultMetadata::init() adds this huge number when calculating the row buffer, and actually allocates this memory!!!
Proposed solution: When a 2^32 value of length is detected, assign a NULL buffer for that field. This will result in mysql_stmt_fetch() returning MYSQL_DATA_TRUNCATED which currently is handled as error. So, the error check should accept this return code as normal. Ideally, it should be checked which field was truncated and whether this field was assigned a NULL buffer. If not, then the data truncation is due to something else and should be reported as error. But currently this is not trivial because the StatementExecutor does not know about the ResultMetadata instance.
The actual length querying and buffer allocation is already implemented properly in Extractor.cpp, but that code was not executed the way it was meant.
As I had problems generating a diff (seems the indentation of my version was changed), I am pasting the code snippets here:
In ResultMetadata.cpp -
ResultMetadata::init()
for (size_t i = 0; i < count; i++)
{
+ unsigned long size = fieldSize(fields[i]);
+ if (size == 0xFFFFFFFF)
+ size = 0;
_columns.push_back(MetaColumn(
i, // position
fields[i].name, // name
fieldType(fields[i]), // type
+ size, // length
0, // TODO: precision (Now I dont know how to get it)
!IS_NOT_NULL(fields[i].flags) // nullable
));
commonSize += size;
}
.....
for (size_t i = 0; i < count; i++)
{
std::memset(&_row[i], 0, sizeof(MYSQL_BIND));
+ unsigned int len = static_cast<unsigned int>(_columns[i].length());
_row[i].buffer_type = fields[i].type;
_row[i].buffer_length = len;
+ _row[i].buffer = (len>0)?(&_buffer[0] + offset):NULL;
_row[i].length = &_lengths[i];
_row[i].is_null = &_isNull[i];
_row[i].is_unsigned = (my_bool) ((fields[i].flags & UNSIGNED_FLAG) == UNSIGNED_FLAG);
offset += _row[i].buffer_length;
}
In StatementExecutor.cpp, StatementExecutor::fetch()
+ if ((res != 0) && (res != MYSQL_NO_DATA) && (res != MYSQL_DATA_TRUNCATED)) //we have specified zero buffers for BLOBs, so DATA_TRUNCATED is normal in this case
{
throw StatementException("mysql_stmt_fetch error", h, _query);
}
+ return ((res == 0) || (res == MYSQL_DATA_TRUNCATED));
}