Bug #3035 prepared statement integer inserts
Submitted: 2 Mar 2004 2:37 Modified: 30 Apr 2004 10:02
Reporter: Peter Pebler Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server Severity:S2 (Serious)
Version:4.1.1-alpha OS:MacOS (Mac OSX 10.2.8)
Assigned to: Konstantin Osipov CPU Architecture:Any

[2 Mar 2004 2:37] Peter Pebler
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 );
}
[2 Mar 2004 10:26] Dean Ellis
Verified against 4.1.2/Linux.  Thank you.
[4 Mar 2004 6:29] Konstantin Osipov
Thank you for your bug report.
We're aware of this problem, and soon will add type codes for unsigned data types:
MYSQL_TYPE_UTINY
MYSQL_TYPE_USHORT
...
[29 Apr 2004 1:26] Konstantin Osipov
Instead of adding of MYSQL_TYPE_UTINY, MYSQL_TYPE_USHORT, and similar type codes we decided to 
add unsigned flag to MYSQL_BIND structure.
This is more in line with MySQL design.
This bug was fixed and the patch will be pushed as soon as it is reviewed: bk commit into 4.1 tree (konstantin:1.1829).
[30 Apr 2004 10:02] Konstantin Osipov
Fixed in 4.1 tree: bk commit - 4.1 tree (konstantin:1.1829)