Bug #8550 | Wrong calculate field length in the mysql_stmt_bind_result() | ||
---|---|---|---|
Submitted: | 16 Feb 2005 16:16 | Modified: | 16 Feb 2007 19:55 |
Reporter: | Alex Dzuba | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: Documentation | Severity: | S2 (Serious) |
Version: | 5.0.26-BK, 5.0, 4.1.9 | OS: | Windows (Windows) |
Assigned to: | Paul DuBois | CPU Architecture: | Any |
[16 Feb 2005 16:16]
Alex Dzuba
[17 Feb 2005 0:54]
MySQL Verification Team
Could you please provide your complete code's test case. Thanks in advance.
[18 Mar 2005 0:00]
Bugs System
No feedback was provided for this bug for over a month, so it is being suspended automatically. If you are able to provide the information that was originally requested, please do so and change the status of the bug back to "Open".
[7 Sep 2006 17:10]
emerson clarke
Assuming you have a MYSQL_STMT, and MYSQL object, the following code reproduces the bug as long as there is a date, time or timestamp field in the query. MYSQL * db = ??; MYSQL_STMT * st = ??; MYSQL_RES * res = mysql_stmt_result_metadata(st); int fields = mysql_num_fields(res); // Use any fixed length here, its not important char bindBuffer[256]; unsigned long * bindLengths = new unsigned long[fields]; MYSQL_FIELD * field = mysql_fetch_fields(res); for (int i=0;i<fields;++i) { int length = (field[i].max_length)?field[i].max_length:field[i].length; bind[i].buffer_length = length; bind[i].buffer_type = field[i].type; bind[i].buffer = bindBuffer; bind[i].length = &bindLengths[i]; } mysql_stmt_bind_result(st,bind); int state=0; while ((state=mysql_stmt_fetch(st))==0) { for (int i=0;i<fields;++i) { assert(bindLengths[i] <= bind[i].buffer_length); } }
[7 Sep 2006 17:31]
emerson clarke
Sorry, this occurs on version 5.0 !
[8 Sep 2006 12:02]
Valeriy Kravchuk
Bug #22114 was marked as duplicate of this one.
[21 Sep 2006 17:56]
Valeriy Kravchuk
Yes, it looks like sizeof(MYSQL_TIME) should be returned for TIMESTAMP column, and not a "display width" of 19 characters, or anything else.
[17 Oct 2006 12:48]
Konstantin Osipov
This is a documentation issue. Prepared statement API always returns the length of string representation in field->max_length. The rationale behind this is that unless your output buffers are strings, you can easily find out the maximum needeed buffer size by means of sizeof(). Below is the code in the client library that is responsible for max_length assignment for fixed size data types: case MYSQL_TYPE_TINY: param->pack_length= 1; field->max_length= 4; /* as in '-127' */ break; case MYSQL_TYPE_YEAR: case MYSQL_TYPE_SHORT: param->pack_length= 2; field->max_length= 6; /* as in '-32767' */ break; case MYSQL_TYPE_INT24: field->max_length= 9; /* as in '16777216' or in '-8388607' */ param->pack_length= 4; break; case MYSQL_TYPE_LONG: field->max_length= 11; /* '-2147483647' */ param->pack_length= 4; break; case MYSQL_TYPE_LONGLONG: field->max_length= 21; /* '18446744073709551616' */ param->pack_length= 8; break; case MYSQL_TYPE_FLOAT: param->pack_length= 4; field->max_length= MAX_DOUBLE_STRING_REP_LENGTH; break; case MYSQL_TYPE_DOUBLE: param->pack_length= 8; field->max_length= MAX_DOUBLE_STRING_REP_LENGTH; break; case MYSQL_TYPE_TIME: field->max_length= 15; /* 19:23:48.123456 */ param->skip_result= skip_result_with_length; case MYSQL_TYPE_DATE: field->max_length= 10; /* 2003-11-11 */ param->skip_result= skip_result_with_length; break; break; case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIMESTAMP: param->skip_result= skip_result_with_length; field->max_length= MAX_DATE_STRING_REP_LENGTH;
[22 Dec 2006 19:59]
emerson clarke
http://dev.mysql.com/doc/refman/5.0/en/c-api-datatypes.html http://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-fields.html The rational you have given does not make sense. This is not a documentation issue, if anything it is an api design issue. You cant have an api function called mysql_fetch_fields which was designed to return field definitions and at the same time expect users to use sizeof() for all non string types. Why is the constant MAX_DATE_STRING_REP_LENGTH set to 30, when the sizeof(MYSQL_TIME) is 36 bytes, or is it just a coincidence that for all other types the max_length happens to be creater than the sizeof() ? Why is it not documented that max_length returns the string representation and not the "maximum length for the field", as currently stated. Why would you want the string representation length and not the field length anyway. What is the purpose of returning the string lengths in the MYSQL_FIELD structure and how do you propose that these would be used ? I think your missing the point of the problem. The MYSQL_FIELD data structure returns max_length's so that the user can allocate buffers which can be bound to MYSQL_BIND to receive the field data using mysql_stmt_fetch(). There must be a *consistent* way for the user to determine the maximum length of each field. Why should the user assume that max_length is only valid for strings ? It doesnt make sense that the user should jump through hoops to determine the size of the buffer required for strings but not be able to use the same approach for other types.
[14 Feb 2007 19:41]
Konstantin Osipov
Dear Clarke, let me try to answer your questions. > You cant have an api function called mysql_fetch_fields which was designed to > return field definitions and at the same time expect users to use sizeof() for > all non string types. mysql_fetch_fields is a function from 3.23 text protocol API and returns MYSQL_FIELD strcuture, which is also part of the 3.23 text protocol. In 3.23 text protocol member max_length is defined to return the maximal buffer size that is needed to hold string, not binary, representation of a column. Well, the whole concept of binary representation is not available in 3.23 text protocol. This definition of max_length member is not changed by the prepared statements protocol. Regardless of the protocol, max_length contains the maximal length of string representation. I agree that it is a valid request to have a member that contains length of `binary' representation. Unfortunately MYSQL_FIELD structure was not extended with addition of the binary protocol. > Why is the constant MAX_DATE_STRING_REP_LENGTH set to 30, when the > sizeof(MYSQL_TIME) is 36 bytes, or is it just a coincidence that for all other > types the max_length happens to be creater than the sizeof() ? It is a coincidence. MAX_DATE_STRING_REP_LENGTH means (as the comment for this variable in the code clarifies) - maximal length of string representation of MYSQL_TIME. > Why is it not documented that max_length returns the string representation and > not the "maximum length for the field", as currently stated. This is a deficiency in our documentation that we will fix. > Why would you want the string representation length and not the field length > anyway. What is the purpose of returning the string lengths in the MYSQL_FIELD > structure and how do you propose that these would be used ? This field can be used if you would like to convert all columns to text format on retreival. In this case you can assign all MYSQL_BIND buffer_type's to MYSQL_TYPE_STRING and allocate buffers of sufficient size (the size is given in max_length). Note, that even if max_length contained binary length, you couldn't have simply assigned buffers of this length to MYSQL_BIND.buffer. Buffers that will store integer types need to be properly aligned, and unless you allocate every single buffer with an own "malloc" you risk getting an alignment error (SIGBUS). > I think your missing the point of the problem. The MYSQL_FIELD data structure > returns max_length's so that the user can allocate buffers which can be bound > to MYSQL_BIND to receive the field data using mysql_stmt_fetch(). I have to say I perhaps do and your point is valid. But in any case this is broken-as-designed - that is, if you're indeed right, I missed the point when wrote this code. Still, changing the semantics of max_length depending on the protocol does not seem to be right to me - but I agree we could perhaps have a separate member that holds the binary length. And you can always unequivocally deduce the length of binary representation from the type of the C/C++ language type you specify for binding and its corresponding MYSQL_ type code. > There must be a *consistent* way for the user to determine the maximum length > of each field. Why should the user assume that max_length is only valid for > strings ? max_length is valid for all types if you set STMT_ATTR_UPDATE_MAX_LENGTH. But currently it contains maximal length of string representation. If you don't need this, you don't have to jump through hoops - the length of binary representation of fixed-size objects does not change from record to record, so it has to be set only once, when you bind output buffers.
[16 Feb 2007 19:55]
Paul DuBois
Thank you for your bug report. This issue has been addressed in the documentation. The updated documentation will appear on our website shortly, and will be included in the next release of the relevant products. I have updated this section to indicate that max_length refers to the string representation fo the values, and that it is off by default for prepared statements and must be enabled: http://dev.mysql.com/doc/refman/5.0/en/c-api-datatypes.html I have update this section to point out the distinction between the values returned in max_length and the sizes of the output buffers needed for prepared statement value retrieval: http://dev.mysql.com/doc/refman/5.0/en/c-api-prepared-statement-datatypes.html