diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 62a18282ea6..f456dcd37c4 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -163,11 +163,6 @@ void STDCALL mysql_thread_end() #define reset_sigpipe(mysql) #endif -#define map_to_size(A,L) {\ - char *tmp= (char *)&A;\ - memset(tmp+L,0,8-L);\ -} - static MYSQL* spawn_init(MYSQL* parent, const char* host, unsigned int port, const char* user, @@ -3967,6 +3962,7 @@ unsigned int alloc_stmt_fields(MYSQL_STMT *stmt) field->org_table= strdup_root(alloc,fields->org_table); field->name = strdup_root(alloc,fields->name); field->org_name = strdup_root(alloc,fields->org_name); + field->charsetnr= fields->charsetnr; field->length = fields->length; field->type = fields->type; field->flags = fields->flags; @@ -4871,31 +4867,38 @@ static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime, /* Fetch data to buffers */ -static void fetch_results(MYSQL_BIND *param, uint field_type, uchar **row) +static void fetch_results(MYSQL_BIND *param, uint field_type, uchar **row, + my_bool field_is_unsigned) { ulong length; switch (field_type) { case MYSQL_TYPE_TINY: { - longlong value= (longlong) **row; - map_to_size(value,(length= 1)); - send_data_long(param,value); + char value= (char) **row; + longlong data= (field_is_unsigned) ? (longlong) (unsigned char) value: + (longlong) value; + send_data_long(param,data); + length= 1; break; } case MYSQL_TYPE_SHORT: case MYSQL_TYPE_YEAR: { - longlong value= (longlong)sint2korr(*row); - map_to_size(value,(length= 2)); - send_data_long(param, value); + short value= sint2korr(*row); + longlong data= (field_is_unsigned) ? (longlong) (unsigned short) value: + (longlong) value; + send_data_long(param,data); + length= 2; break; } case MYSQL_TYPE_LONG: { - longlong value= (longlong)sint4korr(*row); - map_to_size(value,(length= 4)); - send_data_long(param,value); + long value= sint4korr(*row); + longlong data= (field_is_unsigned) ? (longlong) (unsigned long) value: + (longlong) value; + send_data_long(param,data); + length= 4; break; } case MYSQL_TYPE_LONGLONG: @@ -5165,7 +5168,10 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row) if (field->type == bind->buffer_type) (*bind->fetch_result)(bind, &row); else - fetch_results(bind, field->type, &row); + { + my_bool field_is_unsigned= (field->flags & UNSIGNED_FLAG) ? 1: 0; + fetch_results(bind, field->type, &row, field_is_unsigned); + } } if (! ((bit<<=1) & 255)) { diff --git a/tests/client_test.c b/tests/client_test.c index c2d81729f52..0ba4b4e564c 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -166,7 +166,7 @@ static void client_connect() int rc; myheader_r("client_connect"); - fprintf(stdout, "\n Establishig a connection ..."); + fprintf(stdout, "\n Establishing a connection ..."); if (!(mysql = mysql_init(NULL))) { @@ -5529,10 +5529,10 @@ static void test_ushort_bug() rc = mysql_fetch(stmt); mystmt(stmt, rc); - fprintf(stdout,"\n ushort: %d (%ld)", short_value, s_length); - fprintf(stdout,"\n ulong : %ld (%ld)", long_value, l_length); - fprintf(stdout,"\n ulong : %lld (%ld)", longlong_value, ll_length); - fprintf(stdout,"\n ulong : %d (%ld)", tiny_value, t_length); + fprintf(stdout,"\n ushort : %d (%ld)", short_value, s_length); + fprintf(stdout,"\n ulong : %ld (%ld)", long_value, l_length); + fprintf(stdout,"\n longlong : %lld (%ld)", longlong_value, ll_length); + fprintf(stdout,"\n tinyint : %d (%ld)", tiny_value, t_length); myassert(short_value == 35999); myassert(s_length == 2); @@ -5552,6 +5552,174 @@ static void test_ushort_bug() mysql_stmt_close(stmt); } +/* + To test a misc smallint-signed conversion bug +*/ +static void test_sshort_bug() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[4]; + short short_value; + long long_value; + ulong s_length, l_length, ll_length, t_length; + ulonglong longlong_value; + int rc; + uchar tiny_value; + + myheader("test_sshort_bug"); + + rc= mysql_query(mysql,"DROP TABLE IF EXISTS test_sshort"); + myquery(rc); + + rc= mysql_query(mysql,"CREATE TABLE test_sshort(a smallint signed, \ + b smallint signed, \ + c smallint unsigned, \ + d smallint unsigned)"); + myquery(rc); + + rc= mysql_query(mysql,"INSERT INTO test_sshort VALUES(-5999, -5999, 35999, 200)"); + myquery(rc); + + + stmt = mysql_prepare(mysql,"SELECT * FROM test_sshort",50); + mystmt_init(stmt); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + bind[0].buffer_type= MYSQL_TYPE_SHORT; + bind[0].buffer= (char *)&short_value; + bind[0].is_null= 0; + bind[0].length= &s_length; + + bind[1].buffer_type= MYSQL_TYPE_LONG; + bind[1].buffer= (char *)&long_value; + bind[1].is_null= 0; + bind[1].length= &l_length; + + bind[2].buffer_type= MYSQL_TYPE_LONGLONG; + bind[2].buffer= (char *)&longlong_value; + bind[2].is_null= 0; + bind[2].length= &ll_length; + + bind[3].buffer_type= MYSQL_TYPE_TINY; + bind[3].buffer= (char *)&tiny_value; + bind[3].is_null= 0; + bind[3].length= &t_length; + + rc = mysql_bind_result(stmt, bind); + mystmt(stmt, rc); + + rc = mysql_fetch(stmt); + mystmt(stmt, rc); + + fprintf(stdout,"\n sshort : %d (%ld)", short_value, s_length); + fprintf(stdout,"\n slong : %ld (%ld)", long_value, l_length); + fprintf(stdout,"\n longlong : %lld (%ld)", longlong_value, ll_length); + fprintf(stdout,"\n tinyint : %d (%ld)", tiny_value, t_length); + + myassert(short_value == -5999); + myassert(s_length == 2); + + myassert(long_value == -5999); + myassert(l_length == 4); + + myassert(longlong_value == 35999); + myassert(ll_length == 8); + + myassert(tiny_value == 200); + myassert(t_length == 1); + + rc = mysql_fetch(stmt); + myassert(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + +/* + To test a misc tinyint-signed conversion bug +*/ +static void test_stiny_bug() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[4]; + short short_value; + long long_value; + ulong s_length, l_length, ll_length, t_length; + ulonglong longlong_value; + int rc; + uchar tiny_value; + + myheader("test_stiny_bug"); + + rc= mysql_query(mysql,"DROP TABLE IF EXISTS test_stiny"); + myquery(rc); + + rc= mysql_query(mysql,"CREATE TABLE test_stiny(a tinyint signed, \ + b tinyint signed, \ + c tinyint unsigned, \ + d tinyint unsigned)"); + myquery(rc); + + rc= mysql_query(mysql,"INSERT INTO test_stiny VALUES(-128, -127, 255, 0)"); + myquery(rc); + + + stmt = mysql_prepare(mysql,"SELECT * FROM test_stiny",50); + mystmt_init(stmt); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + bind[0].buffer_type= MYSQL_TYPE_SHORT; + bind[0].buffer= (char *)&short_value; + bind[0].is_null= 0; + bind[0].length= &s_length; + + bind[1].buffer_type= MYSQL_TYPE_LONG; + bind[1].buffer= (char *)&long_value; + bind[1].is_null= 0; + bind[1].length= &l_length; + + bind[2].buffer_type= MYSQL_TYPE_LONGLONG; + bind[2].buffer= (char *)&longlong_value; + bind[2].is_null= 0; + bind[2].length= &ll_length; + + bind[3].buffer_type= MYSQL_TYPE_TINY; + bind[3].buffer= (char *)&tiny_value; + bind[3].is_null= 0; + bind[3].length= &t_length; + + rc = mysql_bind_result(stmt, bind); + mystmt(stmt, rc); + + rc = mysql_fetch(stmt); + mystmt(stmt, rc); + + fprintf(stdout,"\n sshort : %d (%ld)", short_value, s_length); + fprintf(stdout,"\n slong : %ld (%ld)", long_value, l_length); + fprintf(stdout,"\n longlong : %lld (%ld)", longlong_value, ll_length); + fprintf(stdout,"\n tinyint : %d (%ld)", tiny_value, t_length); + + myassert(short_value == -128); + myassert(s_length == 2); + + myassert(long_value == -127); + myassert(l_length == 4); + + myassert(longlong_value == 255); + myassert(ll_length == 8); + + myassert(tiny_value == 0); + myassert(t_length == 1); + + rc = mysql_fetch(stmt); + myassert(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + /* Read and parse arguments and MySQL options from my.cnf */ @@ -5767,6 +5935,8 @@ int main(int argc, char **argv) test_pure_coverage(); /* keep pure coverage happy */ test_buffers(); /* misc buffer handling */ test_ushort_bug(); /* test a simple conv bug from php */ + test_sshort_bug(); /* test a simple conv bug from php */ + test_stiny_bug(); /* test a simple conv bug from php */ end_time= time((time_t *)0); total_time+= difftime(end_time, start_time);