Commit 2f191db2 authored by konstantin@mysql.com's avatar konstantin@mysql.com

A fix and test case for Bug#4231 "Wrong result with MYSQL_TIME

parameters": when unpacking binary time recieved from client, handle
the case when length is 0: it means all MYSQL_TIME members are zero.
parent ea5fd2b4
...@@ -58,6 +58,8 @@ void init_time(void); ...@@ -58,6 +58,8 @@ void init_time(void);
my_time_t my_time_t
my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap); my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap);
void set_zero_time(MYSQL_TIME *tm);
C_MODE_END C_MODE_END
#endif /* _my_time_h_ */ #endif /* _my_time_h_ */
...@@ -3167,13 +3167,6 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number, ...@@ -3167,13 +3167,6 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
Fetch and conversion of result set rows (binary protocol). Fetch and conversion of result set rows (binary protocol).
*********************************************************************/ *********************************************************************/
static void set_zero_time(MYSQL_TIME *tm)
{
bzero((void *)tm, sizeof(*tm));
tm->time_type= MYSQL_TIMESTAMP_NONE;
}
/* /*
Read date, (time, datetime) value from network buffer and store it Read date, (time, datetime) value from network buffer and store it
in MYSQL_TIME structure. in MYSQL_TIME structure.
......
...@@ -716,3 +716,13 @@ my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap) ...@@ -716,3 +716,13 @@ my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap)
return (my_time_t) tmp; return (my_time_t) tmp;
} /* my_system_gmt_sec */ } /* my_system_gmt_sec */
/* Set MYSQL_TIME structure to 0000-00-00 00:00:00.000000 */
void set_zero_time(MYSQL_TIME *tm)
{
bzero((void*) tm, sizeof(*tm));
tm->time_type= MYSQL_TIMESTAMP_NONE;
}
...@@ -329,15 +329,22 @@ static void set_param_double(Item_param *param, uchar **pos, ulong len) ...@@ -329,15 +329,22 @@ static void set_param_double(Item_param *param, uchar **pos, ulong len)
} }
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
/*
Read date/time/datetime parameter values from network (binary
protocol). See writing counterparts of these functions in
libmysql.c (store_param_{time,date,datetime}).
*/
static void set_param_time(Item_param *param, uchar **pos, ulong len) static void set_param_time(Item_param *param, uchar **pos, ulong len)
{ {
ulong length; MYSQL_TIME tm;
uint day; ulong length= get_param_length(pos, len);
if ((length= get_param_length(pos, len)) >= 8) if (length >= 8)
{ {
uchar *to= *pos; uchar *to= *pos;
TIME tm; uint day;
tm.neg= (bool) to[0]; tm.neg= (bool) to[0];
day= (uint) sint4korr(to+1); day= (uint) sint4korr(to+1);
...@@ -359,21 +366,22 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len) ...@@ -359,21 +366,22 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
tm.second= 59; tm.second= 59;
} }
tm.day= tm.year= tm.month= 0; tm.day= tm.year= tm.month= 0;
param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
} }
else
set_zero_time(&tm);
param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
*pos+= length; *pos+= length;
} }
static void set_param_datetime(Item_param *param, uchar **pos, ulong len) static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
{ {
uint length; MYSQL_TIME tm;
ulong length= get_param_length(pos, len);
if ((length= get_param_length(pos, len)) >= 4) if (length >= 4)
{ {
uchar *to= *pos; uchar *to= *pos;
TIME tm;
tm.neg= 0; tm.neg= 0;
tm.year= (uint) sint2korr(to); tm.year= (uint) sint2korr(to);
...@@ -394,21 +402,22 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len) ...@@ -394,21 +402,22 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
tm.hour= tm.minute= tm.second= 0; tm.hour= tm.minute= tm.second= 0;
tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0; tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
} }
else
set_zero_time(&tm);
param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
*pos+= length; *pos+= length;
} }
static void set_param_date(Item_param *param, uchar **pos, ulong len) static void set_param_date(Item_param *param, uchar **pos, ulong len)
{ {
ulong length; MYSQL_TIME tm;
ulong length= get_param_length(pos, len);
if ((length= get_param_length(pos, len)) >= 4)
if (length >= 4)
{ {
uchar *to= *pos; uchar *to= *pos;
TIME tm;
/* /*
Note, that though ranges of hour, minute and second are not checked Note, that though ranges of hour, minute and second are not checked
here we rely on them being < 256: otherwise here we rely on them being < 256: otherwise
...@@ -421,10 +430,11 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len) ...@@ -421,10 +430,11 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len)
tm.hour= tm.minute= tm.second= 0; tm.hour= tm.minute= tm.second= 0;
tm.second_part= 0; tm.second_part= 0;
tm.neg= 0; tm.neg= 0;
param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
} }
else
set_zero_time(&tm);
param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
*pos+= length; *pos+= length;
} }
......
...@@ -10091,6 +10091,78 @@ static void test_bug5126() ...@@ -10091,6 +10091,78 @@ static void test_bug5126()
} }
static void test_bug4231()
{
MYSQL_STMT *stmt;
MYSQL_BIND bind[2];
MYSQL_TIME tm[2];
const char *stmt_text;
int rc;
myheader("test_bug4231");
stmt_text= "DROP TABLE IF EXISTS t1";
rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
myquery(rc);
stmt_text= "CREATE TABLE t1 (a int)";
rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
myquery(rc);
stmt_text= "INSERT INTO t1 VALUES (1)";
rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
myquery(rc);
stmt= mysql_stmt_init(mysql);
stmt_text= "SELECT a FROM t1 WHERE ? = ?";
rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
check_execute(stmt, rc);
/* Bind input buffers */
bzero(bind, sizeof(bind));
bzero(tm, sizeof(tm));
bind[0].buffer_type= MYSQL_TYPE_TIME;
bind[0].buffer= (void*) tm;
bind[1].buffer_type= MYSQL_TYPE_TIME;
bind[1].buffer= (void*) tm+1;
mysql_stmt_bind_param(stmt, bind);
check_execute(stmt, rc);
/*
First set server-side params to some non-zero non-equal values:
then we will check that they are not used when client sends
new (zero) times.
*/
tm[0].time_type = MYSQL_TIMESTAMP_DATE;
tm[0].year = 2000;
tm[0].month = 1;
tm[0].day = 1;
tm[1]= tm[0];
--tm[1].year; /* tm[0] != tm[1] */
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
rc= mysql_stmt_fetch(stmt);
/* binds are unequal, no rows should be returned */
DBUG_ASSERT(rc == MYSQL_NO_DATA);
/* Set one of the dates to zero */
tm[0].year= tm[0].month= tm[0].day= 0;
tm[1]= tm[1];
mysql_stmt_execute(stmt);
rc= mysql_stmt_fetch(stmt);
DBUG_ASSERT(rc == 0);
mysql_stmt_close(stmt);
stmt_text= "DROP TABLE t1";
rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
myquery(rc);
}
/* /*
Read and parse arguments and MySQL options from my.cnf Read and parse arguments and MySQL options from my.cnf
*/ */
...@@ -10389,6 +10461,8 @@ int main(int argc, char **argv) ...@@ -10389,6 +10461,8 @@ int main(int argc, char **argv)
test_bug4030(); /* test conversion string -> time types in test_bug4030(); /* test conversion string -> time types in
libmysql */ libmysql */
test_bug5126(); /* support for mediumint type in libmysql */ test_bug5126(); /* support for mediumint type in libmysql */
test_bug4231(); /* proper handling of all-zero times and
dates in the server */
/* /*
XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST
DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH. DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment