Before calling TMySQLStatement::GetBinary, Amore calls TMySQLStatement::StoreResult() in which TMySQLStatement::SetSQLParamType(Int_t npar, int sqltype, bool sig, int sqlsize) is called.
There is a “switch(sqltype)” which treats MYSQL_TYPE_LONG_BLOB as MYSQL_TYPE_BLOB.
This switch sets the value of allocsize :
case MYSQL_TYPE_BLOB : allocsize = sqlsize >= 65525 ? sqlsize + 10 : 65535; break;
The problem is that the value used when SetSQLParamType is called is a “long unsigned” and not an “int”. So sqlsize is not 4,294,967,295 but -1. Therefore when one gets a long blob object, one allocates 64kB instead of 4GB ! So a long blob is treated like a simple blob which is the cause of the error.
I would propose to change the type of sqlsize from int to long unsigned and to modify the line 748 as follows :
Indeed, what Guillaume says is correct. If we load a data bigger than 65k then there is a bug in TMysqlStatement::SetSQLParamType() :
Bool_t TMySQLStatement::SetSQLParamType(Int_t npar, int sqltype, bool sig, int sqlsize) // wrong type for sqlsize leading to an overflow
{
// SNIP
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB: allocsize = sqlsize >= 65525 ? sqlsize + 10 : 65535; // if there is the overflow, then sqlsize == -1 and allocsize == 65535 which is too small
break;
If you check sqlsize in TMysqlStatement::SetSQLParamType() when executing the macro I previously attached, you will see that sqlsize=-1 and not 2^32, as it should, which leads to a wrong allocsize value of 65535.
This is due to an overflow coming from a wrong type of parameter (int instead of long unsigned).
Can a ROOT developer confirm our explanation ?
EDIT : sorry for this post which is a bit a duplicate of guillaume’s one. The first version of Guillaume’s post was shorter and I tried to fill some holes
There is additional argument in TSQLStatement::SetBinary() method,
which defines maximum allowed size of binary data to be set.
By default this limit is 4K and thus it forces usage of normal BLOB type.
First of all, SetBinary is used in your TestDB.C script, line 17.
Without setting correct maximum size of binary field
you are not able to submit data bigger than 64K.
This was your first message in the thread.
That you are proposing is to allocatate 1GB of internal buffer for any binary field. If you have several of them, you will run out of memory.
Can you check actual value of sqlsize in SetSQLParamType after you modify call of SetBinary? As I understood, you getting -1 in current version?
I see your arguments about int and unsigned long in SetSQLParamType.
I will correct this soon.
You can also use root svn repository - I submit patch, where this limit can be defined via static method TMySQLStatement::SetAllocSizeLimit(unsigned long sz). Default value is 128 Mb. I also put unsigned long in several methods to correctly treat size values. In most cases it should be enough.
But this is just workaround. To solve problem in general, one should be able to retrieve binary fields in portions, which is not supported by current
TSQLStatetment class interface.