mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
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. include/my_time.h: Declaration for set_zero_time: a tiny piece of code, which I see no reason to not reuse. libmysql/libmysql.c: set_zero_time implementation is now shared between client and server. sql-common/my_time.c: set_zero_time implementation added. sql/sql_prepare.cc: A fix 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. tests/client_test.c: Test case for bug#4231 "Wrong result with MYSQL_TIME parameters"
This commit is contained in:
@ -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,
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#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)
|
|||||||
tm.second= 59;
|
tm.second= 59;
|
||||||
}
|
}
|
||||||
tm.day= tm.year= tm.month= 0;
|
tm.day= tm.year= tm.month= 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
set_zero_time(&tm);
|
||||||
param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
|
param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
|
||||||
MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
|
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)
|
|||||||
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;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
set_zero_time(&tm);
|
||||||
param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
|
param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
|
||||||
MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
|
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)
|
|||||||
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;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
set_zero_time(&tm);
|
||||||
param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
|
param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
|
||||||
MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
|
MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
|
||||||
}
|
|
||||||
*pos+= length;
|
*pos+= length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
|||||||
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.
|
||||||
|
Reference in New Issue
Block a user