Description:
Inserting integer values whose high bits are set into fields of type "int unsigned", "smallint
unsigned", and "tinyint signed" using the C prepared statement API results in incorrect
values in the database. For the 2 unsigned types, large positive values (high bit set)
result in a 0 in the database. For signed 8-bit, negative values result in a 127 in the
database.
How to repeat:
Run the following program linked with the C API library, then inspect the database tables
uint32_table, uint16_table, sint8_table:
#include <iostream>
#include "mysql.h"
void main()
{
MYSQL sql, * mysql;
mysql_init(&sql);
mysql = mysql_real_connect(&sql,"localhost","XXXX","XXXX","testdb",0,NULL,0);
if (!mysql)
{
std::cout << "mysql_real_connect failed" << std::endl;
return;
}
mysql_query( mysql, "drop table if exists uint32_table" );
mysql_query( mysql, "drop table if exists uint16_table" );
mysql_query( mysql, "drop table if exists sint8_table" );
mysql_query( mysql, "create table uint32_table (a int unsigned)" );
mysql_query( mysql, "create table uint16_table (a smallint unsigned)" );
mysql_query( mysql, "create table sint8_table (a tinyint signed)" );
char *query = "insert into uint32_table values ( ? )";
MYSQL_STMT *stmt = mysql_prepare( mysql, query,strlen(query));
if (!stmt)
{
std::cout << "mysql_prepare failed uint32" << std::endl;
return;
}
unsigned int value = std::numeric_limits<unsigned int>::max() / 2 + 10;
std::cout << "unsigned int value = " << value << std::endl;
my_bool is_null = 0;
unsigned long length = sizeof(value);
MYSQL_BIND parm;
parm.buffer_type = MYSQL_TYPE_LONG;
parm.buffer = reinterpret_cast<char*>( &value );
parm.buffer_length = sizeof(value);
parm.length = &length;
parm.is_null = &is_null;
if (mysql_bind_param(stmt,&parm ))
{
fprintf(stderr,"mysql_bind_param uint32 failed");
return;
}
if (mysql_execute( stmt ) )
{
fprintf(stderr,"mysql_execute uint32 failed");
return;
}
mysql_stmt_close( stmt );
query = "insert into uint16_table values ( ? )";
stmt = mysql_prepare( mysql, query,strlen(query));
if (!stmt)
{
std::cout << "mysql_prepare failed uint16" << std::endl;
return;
}
unsigned short int value2 = std::numeric_limits<unsigned short int>::max() / 2 + 10;
std::cout << "unsigned short int value = " << value2 << std::endl;
length = sizeof(value2);
parm.buffer_type = MYSQL_TYPE_SHORT;
parm.buffer = reinterpret_cast<char*>( &value2 );
parm.buffer_length = sizeof(value2);
if (mysql_bind_param(stmt,&parm ))
{
fprintf(stderr,"mysql_bind_param uint16 failed");
return;
}
if (mysql_execute( stmt ) )
{
fprintf(stderr,"mysql_execute uint16 failed");
return;
}
mysql_stmt_close( stmt );
query = "insert into sint8_table values ( ? )";
stmt = mysql_prepare( mysql, query,strlen(query));
if (!stmt)
{
std::cout << "mysql_prepare failed sint8" << std::endl;
return;
}
signed char value3 = -3;
std::cout << "signed char value = " << int(value3) << std::endl;
length = sizeof(value3);
parm.buffer_type = MYSQL_TYPE_TINY;
parm.buffer = reinterpret_cast<char*>( &value3 );
parm.buffer_length = sizeof(value3);
if (mysql_bind_param(stmt,&parm ))
{
fprintf(stderr,"mysql_bind_param sint8 failed");
return;
}
if (mysql_execute( stmt ) )
{
fprintf(stderr,"mysql_execute sint8 failed");
return;
}
mysql_stmt_close( stmt );
}