Bug #42276 mysql_stmt_bind_result should be not assert with bad MYSQL_BIND
Submitted: 22 Jan 2009 19:22 Modified: 5 Nov 2009 0:28
Reporter: Jeremy Cole (Basic Quality Contributor) (OCA) Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: C API (client library) Severity:S3 (Non-critical)
Version:5.0.75, 4.1, 5.0, 5.1, 6.0 bzr OS:Any
Assigned to: CPU Architecture:Any
Tags: assert, C API, mysql_bind, mysql_stmt_bind_result, prepared statement, qc

[22 Jan 2009 19:22] Jeremy Cole
Description:
The MySQL C API behaves quite poorly with badly behaved prepared statement code.  Isn't it possible to issue an error message rather than a DBUG_ASSERT in a debug library (or ignoring the condition in a release build)?

From libmysql.c, in setup_one_fetch_function as called by mysql_stmt_bind_result:

  case MYSQL_TYPE_TINY_BLOB:
  case MYSQL_TYPE_MEDIUM_BLOB:
  case MYSQL_TYPE_LONG_BLOB:
  case MYSQL_TYPE_BLOB:
  case MYSQL_TYPE_BIT:
    DBUG_ASSERT(param->buffer_length != 0);
    param->fetch_result= fetch_result_bin;
    break;
  case MYSQL_TYPE_VAR_STRING:
  case MYSQL_TYPE_STRING:
  case MYSQL_TYPE_DECIMAL:
  case MYSQL_TYPE_NEWDECIMAL:
  case MYSQL_TYPE_NEWDATE:
    DBUG_ASSERT(param->buffer_length != 0);
    param->fetch_result= fetch_result_str;
    break;

How to repeat:
Pass a 0 as param->buffer_length for one of the MYSQL_TYPE_* fields as above.

Suggested fix:
Return some reasonable error/failure case for all errors in the C API.  Why should we ever assert() or ignore an error condition *deep* inside someone else's code?
[22 Jan 2009 21:01] Sveta Smirnova
Thank you for the report.

Verified as described.
[22 Jan 2009 21:05] Sveta Smirnova
Test used to verify:

#include "mysql.h"
#include <stdio.h>
#include <strings.h>

int main()
{
  MYSQL *mysql;
  char out[10];
  int len;
  int OK;
  char *query;
  MYSQL_ROW row;
  MYSQL_RES *result;
  
  MYSQL_STMT    *stmt;
  MYSQL_BIND    bind[1];

  mysql= mysql_init(NULL);
  mysql= mysql_real_connect(mysql, "127.0.0.1", "root", "", "test", 4040, NULL, 0);

  query = "select 'foo'";

  stmt = mysql_stmt_init(mysql);

  OK = mysql_stmt_prepare(stmt, query, strlen(query));
  
  OK = mysql_stmt_execute(stmt);
  
  memset(bind, 0, sizeof(bind));
 
  bind[0].buffer_type= MYSQL_TYPE_STRING;
  bind[0].buffer= (void*) "some";
  bind[0].is_null= 0;
  bind[0].length= 0;

  OK = mysql_stmt_bind_result(stmt, bind);

  mysql_stmt_close(stmt);

  mysql_close(mysql);

  return 0;
}
[4 Nov 2009 19:03] Byron Campen
I am not convinced that this is an error at all; setting a buffer_length to 0 will cause MYSQL_DATA_TRUNCATED to be returned when mysql_stmt_fetch is called, allowing the caller to determine the needed buffer length. (ie; this can be used as a "peek" operation to determine how large a buffer to create)
[5 Nov 2009 0:28] Jeremy Cole
Hi Byron,

The point is that a reasonable error is NOT returned when using a debug library, instead the library asserts, which means that the user's program loses control.

Regards,

Jeremy