summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/my_time.h2
-rw-r--r--libmysql/libmysql.c7
-rw-r--r--sql-common/my_time.c10
-rw-r--r--sql/sql_prepare.cc50
-rw-r--r--tests/client_test.c74
5 files changed, 116 insertions, 27 deletions
diff --git a/include/my_time.h b/include/my_time.h
index 6c53e39d1d8..d4dbe459c3b 100644
--- a/include/my_time.h
+++ b/include/my_time.h
@@ -58,6 +58,8 @@ void init_time(void);
my_time_t
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
#endif /* _my_time_h_ */
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 380e53d7d47..7d71998f37d 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -3167,13 +3167,6 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
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
in MYSQL_TIME structure.
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index fcfa2efef61..4b5daf53bea 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -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;
} /* 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;
+}
+
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 708ca3a516f..25b6434c184 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -329,15 +329,22 @@ static void set_param_double(Item_param *param, uchar **pos, ulong len)
}
#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)
{
- ulong length;
- uint day;
+ MYSQL_TIME tm;
+ ulong length= get_param_length(pos, len);
- if ((length= get_param_length(pos, len)) >= 8)
+ if (length >= 8)
{
uchar *to= *pos;
- TIME tm;
+ uint day;
tm.neg= (bool) to[0];
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.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;
}
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;
- TIME tm;
tm.neg= 0;
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.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;
}
static void set_param_date(Item_param *param, uchar **pos, ulong len)
{
- ulong length;
-
- if ((length= get_param_length(pos, len)) >= 4)
+ MYSQL_TIME tm;
+ ulong length= get_param_length(pos, len);
+
+ if (length >= 4)
{
uchar *to= *pos;
- TIME tm;
/*
Note, that though ranges of hour, minute and second are not checked
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.second_part= 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;
}
diff --git a/tests/client_test.c b/tests/client_test.c
index 552e49ec862..8a14fe3b4f7 100644
--- a/tests/client_test.c
+++ b/tests/client_test.c
@@ -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
*/
@@ -10389,6 +10461,8 @@ int main(int argc, char **argv)
test_bug4030(); /* test conversion string -> time types 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
DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH.