summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/my_time.h14
-rw-r--r--libmysql/libmysql.c24
-rw-r--r--sql-common/my_time.c72
-rw-r--r--sql/field.cc8
-rw-r--r--sql/item.cc14
-rw-r--r--sql/item_timefunc.cc11
-rw-r--r--sql/mysql_priv.h9
-rw-r--r--sql/protocol.cc7
-rw-r--r--sql/time.cc59
-rw-r--r--tests/client_test.c47
10 files changed, 153 insertions, 112 deletions
diff --git a/include/my_time.h b/include/my_time.h
index d4dbe459c3b..dab17904b2d 100644
--- a/include/my_time.h
+++ b/include/my_time.h
@@ -60,6 +60,20 @@ my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap)
void set_zero_time(MYSQL_TIME *tm);
+/*
+ Required buffer length for my_time_to_str, my_date_to_str,
+ my_datetime_to_str and TIME_to_string functions. Note, that the
+ caller is still responsible to check that given TIME structure
+ has values in valid ranges, otherwise size of the buffer could
+ be not enough.
+*/
+#define MAX_DATE_STRING_REP_LENGTH 30
+
+int my_time_to_str(const MYSQL_TIME *l_time, char *to);
+int my_date_to_str(const MYSQL_TIME *l_time, char *to);
+int my_datetime_to_str(const MYSQL_TIME *l_time, char *to);
+int my_TIME_to_str(const MYSQL_TIME *l_time, char *to);
+
C_MODE_END
#endif /* _my_time_h_ */
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index ef926e2f93d..fe008d24e63 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -3556,28 +3556,8 @@ static void fetch_datetime_with_conversion(MYSQL_BIND *param,
Convert time value to string and delegate the rest to
fetch_string_with_conversion:
*/
- char buff[25];
- uint length;
-
- switch (time->time_type) {
- case MYSQL_TIMESTAMP_DATE:
- length= my_sprintf(buff,(buff, "%04d-%02d-%02d",
- time->year, time->month, time->day));
- break;
- case MYSQL_TIMESTAMP_DATETIME:
- length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d",
- time->year, time->month, time->day,
- time->hour, time->minute, time->second));
- break;
- case MYSQL_TIMESTAMP_TIME:
- length= my_sprintf(buff, (buff, "%02d:%02d:%02d",
- time->hour, time->minute, time->second));
- break;
- default:
- length= 0;
- buff[0]='\0';
- break;
- }
+ char buff[MAX_DATE_STRING_REP_LENGTH];
+ uint length= my_TIME_to_str(time, buff);
/* Resort to string conversion */
fetch_string_with_conversion(param, (char *)buff, length);
break;
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index 4b5daf53bea..93549f7340c 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -726,3 +726,75 @@ void set_zero_time(MYSQL_TIME *tm)
tm->time_type= MYSQL_TIMESTAMP_NONE;
}
+
+/*
+ Functions to convert time/date/datetime value to a string,
+ using default format.
+ This functions don't check that given TIME structure members are
+ in valid range. If they are not, return value won't reflect any
+ valid date either. Additionally, make_time doesn't take into
+ account time->day member: it's assumed that days have been converted
+ to hours already.
+
+ RETURN
+ number of characters written to 'to'
+*/
+
+int my_time_to_str(const MYSQL_TIME *l_time, char *to)
+{
+ return my_sprintf(to, (to, "%s%02d:%02d:%02d",
+ (l_time->neg ? "-" : ""),
+ l_time->hour,
+ l_time->minute,
+ l_time->second));
+}
+
+int my_date_to_str(const MYSQL_TIME *l_time, char *to)
+{
+ return my_sprintf(to, (to, "%04d-%02d-%02d",
+ l_time->year,
+ l_time->month,
+ l_time->day));
+}
+
+int my_datetime_to_str(const MYSQL_TIME *l_time, char *to)
+{
+ return my_sprintf(to, (to, "%04d-%02d-%02d %02d:%02d:%02d",
+ l_time->year,
+ l_time->month,
+ l_time->day,
+ l_time->hour,
+ l_time->minute,
+ l_time->second));
+}
+
+
+/*
+ Convert struct DATE/TIME/DATETIME value to string using built-in
+ MySQL time conversion formats.
+
+ SYNOPSIS
+ my_TIME_to_string()
+
+ NOTE
+ The string must have at least MAX_DATE_STRING_REP_LENGTH bytes reserved.
+*/
+
+int my_TIME_to_str(const MYSQL_TIME *l_time, char *to)
+{
+ switch (l_time->time_type) {
+ case MYSQL_TIMESTAMP_DATETIME:
+ return my_datetime_to_str(l_time, to);
+ case MYSQL_TIMESTAMP_DATE:
+ return my_date_to_str(l_time, to);
+ case MYSQL_TIMESTAMP_TIME:
+ return my_time_to_str(l_time, to);
+ case MYSQL_TIMESTAMP_NONE:
+ case MYSQL_TIMESTAMP_ERROR:
+ to[0]='\0';
+ return 0;
+ default:
+ DBUG_ASSERT(0);
+ return 0;
+ }
+}
diff --git a/sql/field.cc b/sql/field.cc
index 3dc1375dff3..c98276b961d 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -455,11 +455,9 @@ bool Field::get_time(TIME *ltime)
void Field::store_time(TIME *ltime,timestamp_type type)
{
- char buff[MAX_DATE_REP_LENGTH];
- String tmp;
- tmp.set(buff, sizeof(buff), &my_charset_bin);
- TIME_to_string(ltime, &tmp);
- store(buff, tmp.length(), &my_charset_bin);
+ char buff[MAX_DATE_STRING_REP_LENGTH];
+ uint length= (uint) my_TIME_to_str(ltime, buff);
+ store(buff, length, &my_charset_bin);
}
diff --git a/sql/item.cc b/sql/item.cc
index 0366ea29485..cff7b739893 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -988,9 +988,10 @@ String *Item_param::val_str(String* str)
return str;
case TIME_VALUE:
{
- if (str->reserve(MAX_DATE_REP_LENGTH))
+ if (str->reserve(MAX_DATE_STRING_REP_LENGTH))
break;
- TIME_to_string(&value.time, str);
+ str->length((uint) my_TIME_to_str(&value.time, (char*) str->ptr()));
+ str->set_charset(&my_charset_bin);
return str;
}
case NULL_VALUE:
@@ -1020,24 +1021,19 @@ const String *Item_param::query_val_str(String* str) const
case TIME_VALUE:
{
char *buf, *ptr;
- String tmp;
str->length(0);
/*
TODO: in case of error we need to notify replication
that binary log contains wrong statement
*/
- if (str->reserve(MAX_DATE_REP_LENGTH+3))
+ if (str->reserve(MAX_DATE_STRING_REP_LENGTH+3))
break;
/* Create date string inplace */
buf= str->c_ptr_quick();
ptr= buf;
*ptr++= '\'';
- tmp.set(ptr, MAX_DATE_REP_LENGTH, &my_charset_bin);
- tmp.length(0);
- TIME_to_string(&value.time, &tmp);
-
- ptr+= tmp.length();
+ ptr+= (uint) my_TIME_to_str(&value.time, ptr);
*ptr++= '\'';
str->length((uint32) (ptr - buf));
break;
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 863b041044e..48c1f2c5443 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1292,14 +1292,13 @@ String *Item_func_curtime::val_str(String *str)
void Item_func_curtime::fix_length_and_dec()
{
TIME ltime;
- String tmp((char*) buff,sizeof(buff), &my_charset_bin);
decimals=0;
collation.set(&my_charset_bin);
store_now_in_TIME(&ltime);
value= TIME_to_ulonglong_time(&ltime);
- make_time((DATE_TIME_FORMAT *) 0, &ltime, &tmp);
- max_length= buff_length= tmp.length();
+ buff_length= (uint) my_time_to_str(&ltime, buff);
+ max_length= buff_length;
}
@@ -1341,16 +1340,14 @@ String *Item_func_now::val_str(String *str)
void Item_func_now::fix_length_and_dec()
{
- String tmp((char*) buff,sizeof(buff),&my_charset_bin);
-
decimals=0;
collation.set(&my_charset_bin);
store_now_in_TIME(&ltime);
value= (longlong) TIME_to_ulonglong_datetime(&ltime);
- make_datetime((DATE_TIME_FORMAT *) 0, &ltime, &tmp);
- max_length= buff_length= tmp.length();
+ buff_length= (uint) my_datetime_to_str(&ltime, buff);
+ max_length= buff_length;
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 1a0879c6347..15bdfdaacfc 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -284,14 +284,6 @@ void debug_sync_point(const char* lock_name, uint lock_timeout);
#define WEEK_MONDAY_FIRST 1
#define WEEK_YEAR 2
#define WEEK_FIRST_WEEKDAY 4
-/*
- Required buffer length for make_date, make_time, make_datetime
- and TIME_to_string functions. Note, that the caller is still
- responsible to check that given TIME structure has values
- in valid ranges, otherwise size of the buffer could be not
- enough.
-*/
-#define MAX_DATE_REP_LENGTH 30
enum enum_parsing_place
{
@@ -1046,7 +1038,6 @@ void make_date(const DATE_TIME_FORMAT *format, const TIME *l_time,
String *str);
void make_time(const DATE_TIME_FORMAT *format, const TIME *l_time,
String *str);
-void TIME_to_string(const TIME *time, String *str);
ulonglong TIME_to_ulonglong_datetime(const TIME *time);
ulonglong TIME_to_ulonglong_date(const TIME *time);
ulonglong TIME_to_ulonglong_time(const TIME *time);
diff --git a/sql/protocol.cc b/sql/protocol.cc
index c2d9117b062..060dc14be10 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -880,10 +880,9 @@ bool Protocol_simple::store_date(TIME *tm)
field_types[field_pos] == MYSQL_TYPE_DATE);
field_pos++;
#endif
- char buff[40];
- String tmp((char*) buff,sizeof(buff),&my_charset_bin);
- make_date((DATE_TIME_FORMAT *) 0, tm, &tmp);
- return net_store_data((char*) tmp.ptr(), tmp.length());
+ char buff[MAX_DATE_STRING_REP_LENGTH];
+ int length= my_date_to_str(tm, buff);
+ return net_store_data(buff, (uint) length);
}
diff --git a/sql/time.cc b/sql/time.cc
index 4421b6aa00f..e76b169b336 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -747,13 +747,7 @@ const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)),
const TIME *l_time, String *str)
{
- long length= my_sprintf((char*) str->ptr(),
- ((char*) str->ptr(),
- "%s%02d:%02d:%02d",
- (l_time->neg ? "-" : ""),
- l_time->hour,
- l_time->minute,
- l_time->second));
+ uint length= (uint) my_time_to_str(l_time, (char*) str->ptr());
str->length(length);
str->set_charset(&my_charset_bin);
}
@@ -762,12 +756,7 @@ void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)),
void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)),
const TIME *l_time, String *str)
{
- long length= my_sprintf((char*) str->ptr(),
- ((char*) str->ptr(),
- "%04d-%02d-%02d",
- l_time->year,
- l_time->month,
- l_time->day));
+ uint length= (uint) my_date_to_str(l_time, (char*) str->ptr());
str->length(length);
str->set_charset(&my_charset_bin);
}
@@ -776,15 +765,7 @@ void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)),
void make_datetime(const DATE_TIME_FORMAT *format __attribute__((unused)),
const TIME *l_time, String *str)
{
- long length= my_sprintf((char*) str->ptr(),
- ((char*) str->ptr(),
- "%04d-%02d-%02d %02d:%02d:%02d",
- l_time->year,
- l_time->month,
- l_time->day,
- l_time->hour,
- l_time->minute,
- l_time->second));
+ uint length= (uint) my_datetime_to_str(l_time, (char*) str->ptr());
str->length(length);
str->set_charset(&my_charset_bin);
}
@@ -894,38 +875,4 @@ ulonglong TIME_to_ulonglong(const TIME *time)
return 0;
}
-
-/*
- Convert struct DATE/TIME/DATETIME value to string using built-in
- MySQL time conversion formats.
-
- SYNOPSIS
- TIME_to_string()
-
- NOTE
- The string must have at least MAX_DATE_REP_LENGTH bytes reserved.
-*/
-
-void TIME_to_string(const TIME *time, String *str)
-{
- switch (time->time_type) {
- case MYSQL_TIMESTAMP_DATETIME:
- make_datetime((DATE_TIME_FORMAT*) 0, time, str);
- break;
- case MYSQL_TIMESTAMP_DATE:
- make_date((DATE_TIME_FORMAT*) 0, time, str);
- break;
- case MYSQL_TIMESTAMP_TIME:
- make_time((DATE_TIME_FORMAT*) 0, time, str);
- break;
- case MYSQL_TIMESTAMP_NONE:
- case MYSQL_TIMESTAMP_ERROR:
- str->length(0);
- str->set_charset(&my_charset_bin);
- break;
- default:
- DBUG_ASSERT(0);
- }
-}
-
#endif
diff --git a/tests/client_test.c b/tests/client_test.c
index 0b30cc3386d..5cafd2e033e 100644
--- a/tests/client_test.c
+++ b/tests/client_test.c
@@ -10541,6 +10541,52 @@ static void test_bug5315()
}
+static void test_bug6049()
+{
+ MYSQL_STMT *stmt;
+ MYSQL_BIND bind[1];
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ const char *stmt_text;
+ char *buffer[30];
+ ulong length;
+ int rc;
+
+ myheader("test_bug6049");
+
+ stmt_text= "SELECT MAKETIME(-25, 12, 12)";
+
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+ res= mysql_store_result(mysql);
+ row= mysql_fetch_row(res);
+
+ stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+ check_execute(stmt, rc);
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+
+ bzero(bind, sizeof(bind));
+ bind[0].buffer_type = MYSQL_TYPE_STRING;
+ bind[0].buffer = &buffer;
+ bind[0].buffer_length = sizeof(buffer);
+ bind[0].length = &length;
+
+ mysql_stmt_bind_result(stmt, bind);
+ rc= mysql_stmt_fetch(stmt);
+ DIE_UNLESS(rc == 0);
+
+ printf("Result from query: %s\n", row[0]);
+ printf("Result from prepared statement: %s\n", buffer);
+
+ DIE_UNLESS(strcmp(row[0], buffer) == 0);
+
+ mysql_free_result(res);
+ mysql_stmt_close(stmt);
+}
+
+
/*
Read and parse arguments and MySQL options from my.cnf
*/
@@ -10851,6 +10897,7 @@ int main(int argc, char **argv)
test_bug5194(); /* bulk inserts in prepared mode */
test_bug5315(); /* check that mysql_change_user closes all
prepared statements */
+ test_bug6049(); /* check support for negative TIME values */
/*
XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST
DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH.