Commit a30fcdc6 authored by konstantin@mysql.com's avatar konstantin@mysql.com

Fix for Bug#4030 "Client side conversion string -> date type doesn't

work (prepared statements)" and after-review fixes:
- str_to_TIME renamed to str_to_datetime to pair with str_to_time
- functions str_to_time and str_to_TIME moved to sql-common
- send_data_str now supports MYSQL_TYPE_TIME, MYSQL_TIME_DATE,
  MYSQL_TIME_DATETIME types of user input buffers.
- few more comments in the client library
- a test case added.
parent 3bcbdcb4
......@@ -427,6 +427,10 @@ SOURCE=.\pack.c
# End Source File
# Begin Source File
SOURCE=.\my_time.c
# End Source File
# Begin Source File
SOURCE=.\password.c
# End Source File
# Begin Source File
......
......@@ -368,6 +368,10 @@ SOURCE="..\sql-common\pack.c"
# End Source File
# Begin Source File
SOURCE=..\sql-common\my_time.c
# End Source File
# Begin Source File
SOURCE=..\libmysql\password.c
# End Source File
# Begin Source File
......
......@@ -1053,6 +1053,10 @@ SOURCE=.\pack.c
# End Source File
# Begin Source File
SOURCE=.\my_time.c
# End Source File
# Begin Source File
SOURCE=.\password.c
!IF "$(CFG)" == "mysqld - Win32 Release"
......
......@@ -22,7 +22,7 @@ pkginclude_HEADERS = my_dbug.h m_string.h my_sys.h my_list.h my_xml.h \
errmsg.h my_global.h my_net.h my_alloc.h \
my_getopt.h sslopt-longopts.h my_dir.h typelib.h \
sslopt-vars.h sslopt-case.h sql_common.h keycache.h \
sql_state.h $(BUILT_SOURCES)
sql_state.h mysql_time.h $(BUILT_SOURCES)
noinst_HEADERS = config-win.h config-os2.h config-netware.h \
nisam.h heap.h merge.h my_bitmap.h\
myisam.h myisampack.h myisammrg.h ft_global.h\
......
/* Copyright (C) 2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
This is a private header of sql-common library, containing
declarations for my_time.c
*/
#ifndef _my_time_h_
#define _my_time_h_
#include "my_global.h"
#include "mysql_time.h"
C_MODE_START
extern ulonglong log_10_int[20];
#define YY_PART_YEAR 70
/* Flags to str_to_datetime */
#define TIME_FUZZY_DATE 1
#define TIME_DATETIME_ONLY 2
enum enum_mysql_timestamp_type
str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
uint flags, int *was_cut);
bool str_to_time(const char *str,uint length, MYSQL_TIME *l_time,
int *was_cut);
C_MODE_END
#endif /* _my_time_h_ */
......@@ -55,6 +55,7 @@ typedef int my_socket;
#endif /* _global_h */
#include "mysql_com.h"
#include "mysql_time.h"
#include "mysql_version.h"
#include "typelib.h"
......@@ -533,23 +534,6 @@ enum enum_mysql_stmt_state
MYSQL_STMT_FETCH_DONE
};
/*
client TIME structure to handle TIME, DATE and TIMESTAMP directly in
binary protocol
*/
enum mysql_st_timestamp_type { MYSQL_TIMESTAMP_NONE, MYSQL_TIMESTAMP_DATE,
MYSQL_TIMESTAMP_FULL, MYSQL_TIMESTAMP_TIME };
typedef struct mysql_st_time
{
unsigned int year,month,day,hour,minute,second;
unsigned long second_part;
my_bool neg;
enum mysql_st_timestamp_type time_type;
} MYSQL_TIME;
/* bind structure */
typedef struct st_mysql_bind
......
/* Copyright (C) 2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _mysql_time_h_
#define _mysql_time_h_
/* Time declarations shared between server and client library */
enum enum_mysql_timestamp_type
{
MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1,
MYSQL_TIMESTAMP_DATE= 0, MYSQL_TIMESTAMP_DATETIME= 1, MYSQL_TIMESTAMP_TIME= 2
};
typedef struct st_mysql_time
{
unsigned int year, month, day, hour, minute, second;
unsigned long second_part;
my_bool neg;
enum enum_mysql_timestamp_type time_type;
} MYSQL_TIME;
#endif /* _mysql_time_h_ */
......@@ -65,7 +65,7 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \
my_pread.lo mf_cache.lo md5.lo sha1.lo\
my_getopt.lo my_gethostbyname.lo my_port.lo
sqlobjects = net.lo
sql_cmn_objects = pack.lo client.lo
sql_cmn_objects = pack.lo client.lo my_time.lo
# Not needed in the minimum library
mysysobjects2 = my_lib.lo
......
......@@ -16,6 +16,7 @@
#include <my_global.h>
#include <my_sys.h>
#include <my_time.h>
#include <mysys_err.h>
#include <m_string.h>
#include <m_ctype.h>
......@@ -3008,33 +3009,33 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
/********************************************************************
Fetch-bind related implementations
Fetch and conversion of result set rows (binary protocol).
*********************************************************************/
/****************************************************************************
Functions to fetch data to application buffers
All functions have the following characteristics:
SYNOPSIS
fetch_result_xxx()
param MySQL bind param
row Row value
RETURN VALUES
0 ok
1 Error (Can't alloc net->buffer)
****************************************************************************/
static void set_zero_time(MYSQL_TIME *tm)
{
tm->year= tm->month= tm->day= 0;
tm->hour= tm->minute= tm->second= 0;
tm->second_part= 0;
tm->neg= (bool)0;
bzero((void *)tm, sizeof(*tm));
}
/* Read TIME from binary packet and return it to MYSQL_TIME */
/*
Read date, (time, datetime) value from network buffer and store it
in MYSQL_TIME structure.
SYNOPSIS
read_binary_{date,time,datetime}()
tm MYSQL_TIME structure to fill
pos pointer to current position in network buffer.
These functions increase pos to point to the beginning of this
field (this is just due to implementation of net_field_length
which is used to get length of binary representation of
time value).
Auxiliary functions to read time (date, datetime) values from network
buffer and store in MYSQL_TIME structure. Jointly used by conversion
and no-conversion fetching.
*/
static uint read_binary_time(MYSQL_TIME *tm, uchar **pos)
{
uchar *to;
......@@ -3060,7 +3061,6 @@ static uint read_binary_time(MYSQL_TIME *tm, uchar **pos)
return length;
}
/* Read DATETIME from binary packet and return it to MYSQL_TIME */
static uint read_binary_datetime(MYSQL_TIME *tm, uchar **pos)
{
uchar *to;
......@@ -3091,7 +3091,6 @@ static uint read_binary_datetime(MYSQL_TIME *tm, uchar **pos)
return length;
}
/* Read DATE from binary packet and return it to MYSQL_TIME */
static uint read_binary_date(MYSQL_TIME *tm, uchar **pos)
{
uchar *to;
......@@ -3115,7 +3114,8 @@ static uint read_binary_date(MYSQL_TIME *tm, uchar **pos)
}
/* Convert Numeric to buffer types */
/* Convert integer value to client buffer type. */
static void send_data_long(MYSQL_BIND *param, MYSQL_FIELD *field,
longlong value)
{
......@@ -3273,6 +3273,21 @@ static void send_data_str(MYSQL_BIND *param, char *value, uint length)
doublestore(buffer, data);
break;
}
case MYSQL_TYPE_TIME:
{
int dummy;
MYSQL_TIME *tm= (MYSQL_TIME *)buffer;
str_to_time(value, length, tm, &dummy);
break;
}
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
{
int dummy;
MYSQL_TIME *tm= (MYSQL_TIME *)buffer;
str_to_datetime(value, length, tm, 0, &dummy);
break;
}
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
......@@ -3332,7 +3347,7 @@ static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime,
length= my_sprintf(buff,(buff, "%04d-%02d-%02d", ltime.year,
ltime.month,ltime.day));
break;
case MYSQL_TIMESTAMP_FULL:
case MYSQL_TIMESTAMP_DATETIME:
length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d",
ltime.year,ltime.month,ltime.day,
ltime.hour,ltime.minute,ltime.second));
......@@ -3351,7 +3366,7 @@ static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime,
}
/* Fetch data to buffers */
/* Fetch data to client buffers with conversion. */
static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row)
{
......@@ -3437,7 +3452,7 @@ static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row)
MYSQL_TIME tm;
length= read_binary_datetime(&tm, row);
tm.time_type= MYSQL_TIMESTAMP_FULL;
tm.time_type= MYSQL_TIMESTAMP_DATETIME;
send_data_time(param, tm, length);
break;
}
......@@ -3450,6 +3465,25 @@ static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row)
}
/*
Functions to fetch data to application buffers without conversion.
All functions have the following characteristics:
SYNOPSIS
fetch_result_xxx()
param MySQL bind param
pos Row value
DESCRIPTION
These are no-conversion functions, used in binary protocol to store
rows in application buffers. A function used only if type of binary data
is compatible with type of application buffer.
RETURN
none
*/
static void fetch_result_tinyint(MYSQL_BIND *param, uchar **row)
{
*param->buffer= **row;
......
......@@ -33,7 +33,8 @@ noinst_LIBRARIES = libmysqld_int.a
pkglib_LIBRARIES = libmysqld.a
SUBDIRS = . examples
libmysqld_sources= libmysqld.c lib_sql.cc emb_qcache.cc
libmysqlsources = errmsg.c get_password.c libmysql.c client.c pack.c
libmysqlsources = errmsg.c get_password.c libmysql.c client.c pack.c \
my_time.c
noinst_HEADERS = embedded_priv.h emb_qcache.h
......@@ -56,7 +57,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \
sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \
unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \
spatial.cc gstream.cc sql_help.cc tztime.cc
spatial.cc gstream.cc sql_help.cc tztime.cc my_time.c
libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources)
libmysqld_a_SOURCES=
......
......@@ -15,7 +15,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## Process this file with automake to create Makefile.in
EXTRA_DIST = client.c pack.c
EXTRA_DIST = client.c pack.c my_time.c
# Don't update the files from bitkeeper
%::SCCS/s.%
......@@ -89,7 +89,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
client.c sql_client.cc mini_client_errors.c pack.c\
stacktrace.c repl_failsafe.h repl_failsafe.cc \
gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \
tztime.cc examples/ha_example.cc examples/ha_archive.cc
tztime.cc my_time.c \
examples/ha_example.cc examples/ha_archive.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
......@@ -114,6 +115,8 @@ link_sources:
@LN_CP_F@ ../sql-common/pack.c pack.c
rm -f client.c
@LN_CP_F@ ../sql-common/client.c client.c
rm -f my_time.c
@LN_CP_F@ ../sql-common/my_time.c my_time.c
gen_lex_hash.o: gen_lex_hash.cc lex.h
$(CXXCOMPILE) -c $(INCLUDES) $<
......
This diff is collapsed.
......@@ -228,8 +228,8 @@ bool Item::get_date(TIME *ltime,uint fuzzydate)
char buff[40];
String tmp(buff,sizeof(buff), &my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
str_to_TIME_with_warn(res->ptr(),res->length(),ltime,fuzzydate) <=
TIMESTAMP_DATETIME_ERROR)
str_to_datetime_with_warn(res->ptr(), res->length(),
ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
{
bzero((char*) ltime,sizeof(*ltime));
return 1;
......
......@@ -425,21 +425,21 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
str->append(month_names[l_time->month-1],3);
break;
case 'W':
if (type == TIMESTAMP_TIME)
if (type == MYSQL_TIMESTAMP_TIME)
return 1;
weekday= calc_weekday(calc_daynr(l_time->year,l_time->month,
l_time->day),0);
str->append(day_names[weekday]);
break;
case 'a':
if (type == TIMESTAMP_TIME)
if (type == MYSQL_TIMESTAMP_TIME)
return 1;
weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
l_time->day),0);
str->append(day_names[weekday],3);
break;
case 'D':
if (type == TIMESTAMP_TIME)
if (type == MYSQL_TIMESTAMP_TIME)
return 1;
length= int10_to_str(l_time->day, intbuff, 10) - intbuff;
str->append_with_prefill(intbuff, length, 1, '0');
......@@ -507,7 +507,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
str->append_with_prefill(intbuff, length, 2, '0');
break;
case 'j':
if (type == TIMESTAMP_TIME)
if (type == MYSQL_TIMESTAMP_TIME)
return 1;
length= int10_to_str(calc_daynr(l_time->year,l_time->month,
l_time->day) -
......@@ -555,7 +555,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
case 'u':
{
uint year;
if (type == TIMESTAMP_TIME)
if (type == MYSQL_TIMESTAMP_TIME)
return 1;
length= int10_to_str(calc_week(l_time,
(*ptr) == 'U' ?
......@@ -569,7 +569,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
case 'V':
{
uint year;
if (type == TIMESTAMP_TIME)
if (type == MYSQL_TIMESTAMP_TIME)
return 1;
length= int10_to_str(calc_week(l_time,
((*ptr) == 'V' ?
......@@ -584,7 +584,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
case 'X':
{
uint year;
if (type == TIMESTAMP_TIME)
if (type == MYSQL_TIMESTAMP_TIME)
return 1;
(void) calc_week(l_time,
((*ptr) == 'X' ?
......@@ -596,7 +596,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
}
break;
case 'w':
if (type == TIMESTAMP_TIME)
if (type == MYSQL_TIMESTAMP_TIME)
return 1;
weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
l_time->day),1);
......@@ -1107,7 +1107,7 @@ int Item_date::save_in_field(Field *field, bool no_conversions)
if (get_date(&ltime, TIME_FUZZY_DATE))
return set_field_to_null(field);
field->set_notnull();
field->store_time(&ltime, TIMESTAMP_DATE);
field->store_time(&ltime, MYSQL_TIMESTAMP_DATE);
return 0;
}
......@@ -1129,7 +1129,7 @@ bool Item_func_from_days::get_date(TIME *ltime, uint fuzzy_date)
return 1;
bzero(ltime, sizeof(TIME));
get_date_from_daynr((long) value, &ltime->year, &ltime->month, &ltime->day);
ltime->time_type= TIMESTAMP_DATE;
ltime->time_type= MYSQL_TIMESTAMP_DATE;
return 0;
}
......@@ -1144,7 +1144,7 @@ void Item_func_curdate::fix_length_and_dec()
/* We don't need to set second_part and neg because they already 0 */
ltime.hour= ltime.minute= ltime.second= 0;
ltime.time_type=TIMESTAMP_DATE;
ltime.time_type= MYSQL_TIMESTAMP_DATE;
value= (longlong) TIME_to_ulonglong_date(&ltime);
}
......@@ -1308,7 +1308,7 @@ bool Item_func_now::get_date(TIME *res,
int Item_func_now::save_in_field(Field *to, bool no_conversions)
{
to->set_notnull();
to->store_time(&ltime,TIMESTAMP_DATETIME);
to->store_time(&ltime, MYSQL_TIMESTAMP_DATETIME);
return 0;
}
......@@ -1494,7 +1494,9 @@ String *Item_func_date_format::val_str(String *str)
/* Create the result string */
if (!make_date_time(&date_time_format, &l_time,
is_time_format ? TIMESTAMP_TIME : TIMESTAMP_DATE, str))
is_time_format ? MYSQL_TIMESTAMP_TIME :
MYSQL_TIMESTAMP_DATE,
str))
return str;
null_date:
......@@ -1713,7 +1715,7 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date)
case INTERVAL_DAY_HOUR:
{
longlong sec, days, daynr, microseconds, extra_sec;
ltime->time_type=TIMESTAMP_DATETIME; // Return full date
ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date
microseconds= ltime->second_part + sign*interval.second_part;
extra_sec= microseconds/1000000L;
microseconds= microseconds%1000000L;
......@@ -1798,7 +1800,7 @@ String *Item_date_add_interval::val_str(String *str)
if (Item_date_add_interval::get_date(&ltime,0))
return 0;
if (ltime.time_type == TIMESTAMP_DATE)
if (ltime.time_type == MYSQL_TIMESTAMP_DATE)
format= DATE_ONLY;
else if (ltime.second_part)
format= DATE_TIME_MICROSECOND;
......@@ -1821,7 +1823,7 @@ longlong Item_date_add_interval::val_int()
if (Item_date_add_interval::get_date(&ltime,0))
return (longlong) 0;
date = (ltime.year*100L + ltime.month)*100L + ltime.day;
return ltime.time_type == TIMESTAMP_DATE ? date :
return ltime.time_type == MYSQL_TIMESTAMP_DATE ? date :
((date*100L + ltime.hour)*100L+ ltime.minute)*100L + ltime.second;
}
......@@ -2069,7 +2071,7 @@ String *Item_datetime_typecast::val_str(String *str)
bool Item_time_typecast::get_time(TIME *ltime)
{
bool res= get_arg0_time(ltime);
ltime->time_type= TIMESTAMP_TIME;
ltime->time_type= MYSQL_TIMESTAMP_TIME;
return res;
}
......@@ -2092,7 +2094,7 @@ String *Item_time_typecast::val_str(String *str)
bool Item_date_typecast::get_date(TIME *ltime, uint fuzzy_date)
{
bool res= get_arg0_date(ltime,1);
ltime->time_type= TIMESTAMP_DATE;
ltime->time_type= MYSQL_TIMESTAMP_DATE;
return res;
}
......@@ -2198,17 +2200,17 @@ String *Item_func_add_time::val_str(String *str)
{
if (get_arg0_date(&l_time1,1) ||
args[1]->get_time(&l_time2) ||
l_time1.time_type == TIMESTAMP_TIME ||
l_time2.time_type != TIMESTAMP_TIME)
l_time1.time_type == MYSQL_TIMESTAMP_TIME ||
l_time2.time_type != MYSQL_TIMESTAMP_TIME)
goto null_date;
}
else // ADDTIME function
{
if (args[0]->get_time(&l_time1) ||
args[1]->get_time(&l_time2) ||
l_time2.time_type == TIMESTAMP_DATETIME)
l_time2.time_type == MYSQL_TIMESTAMP_DATETIME)
goto null_date;
is_time= (l_time1.time_type == TIMESTAMP_TIME);
is_time= (l_time1.time_type == MYSQL_TIMESTAMP_TIME);
if (is_time && (l_time2.neg == l_time1.neg && l_time1.neg))
l_time3.neg= 1;
}
......@@ -2324,7 +2326,7 @@ String *Item_func_timediff::val_str(String *str)
if (l_time1.neg != l_time2.neg)
l_sign= -l_sign;
if (l_time1.time_type == TIMESTAMP_TIME) // Time value
if (l_time1.time_type == MYSQL_TIMESTAMP_TIME) // Time value
days= l_time1.day - l_sign*l_time2.day;
else // DateTime value
days= (calc_daynr((uint) l_time1.year,
......@@ -2466,13 +2468,13 @@ void Item_func_get_format::print(String *str)
str->append('(');
switch (type) {
case TIMESTAMP_DATE:
case MYSQL_TIMESTAMP_DATE:
str->append("DATE, ");
break;
case TIMESTAMP_DATETIME:
case MYSQL_TIMESTAMP_DATETIME:
str->append("DATETIME, ");
break;
case TIMESTAMP_TIME:
case MYSQL_TIMESTAMP_TIME:
str->append("TIME, ");
break;
default:
......@@ -2555,25 +2557,25 @@ void Item_func_str_to_date::fix_length_and_dec()
decimals=0;
cached_field_type= MYSQL_TYPE_STRING;
max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
cached_timestamp_type= TIMESTAMP_NONE;
cached_timestamp_type= MYSQL_TIMESTAMP_NONE;
if ((const_item= args[1]->const_item()))
{
format= args[1]->val_str(&format_str);
cached_format_type= check_result_type(format->ptr(), format->length());
switch (cached_format_type) {
case DATE_ONLY:
cached_timestamp_type= TIMESTAMP_DATE;
cached_timestamp_type= MYSQL_TIMESTAMP_DATE;
cached_field_type= MYSQL_TYPE_DATE;
max_length= MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
break;
case TIME_ONLY:
case TIME_MICROSECOND:
cached_timestamp_type= TIMESTAMP_TIME;
cached_timestamp_type= MYSQL_TIMESTAMP_TIME;
cached_field_type= MYSQL_TYPE_TIME;
max_length= MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
break;
default:
cached_timestamp_type= TIMESTAMP_DATETIME;
cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME;
cached_field_type= MYSQL_TYPE_DATETIME;
break;
}
......@@ -2599,7 +2601,7 @@ bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date)
if (extract_date_time(&date_time_format, val->ptr(), val->length(),
ltime, cached_timestamp_type))
goto null_date;
if (cached_timestamp_type == TIMESTAMP_TIME && ltime->day)
if (cached_timestamp_type == MYSQL_TIMESTAMP_TIME && ltime->day)
{
/*
Day part for time type can be nonzero value and so
......@@ -2640,6 +2642,6 @@ bool Item_func_last_day::get_date(TIME *ltime, uint fuzzy_date)
ltime->day= days_in_month[month_idx];
if ( month_idx == 1 && calc_days_in_year(ltime->year) == 366)
ltime->day= 29;
ltime->time_type= TIMESTAMP_DATE;
ltime->time_type= MYSQL_TIMESTAMP_DATE;
return 0;
}
......@@ -18,6 +18,7 @@
#include <mysql_version.h>
#include <mysql_embed.h>
#include <my_sys.h>
#include <my_time.h>
#include <m_string.h>
#include <hash.h>
#include <signal.h>
......@@ -1001,12 +1002,9 @@ void get_date_from_daynr(long daynr,uint *year, uint *month,
void init_time(void);
my_time_t my_system_gmt_sec(const TIME *, long *current_timezone, bool *not_exist);
my_time_t TIME_to_timestamp(THD *thd, const TIME *t, bool *not_exist);
bool str_to_time(const char *str,uint length,TIME *l_time, int *was_cut);
bool str_to_time_with_warn(const char *str,uint length,TIME *l_time);
timestamp_type str_to_TIME(const char *str, uint length, TIME *l_time,
uint flags, int *was_cut);
timestamp_type str_to_TIME_with_warn(const char *str, uint length,
TIME *l_time, uint flags);
timestamp_type str_to_datetime_with_warn(const char *str, uint length,
TIME *l_time, uint flags);
longlong number_to_TIME(longlong nr, TIME *time_res, bool fuzzy_date,
int *was_cut);
void localtime_to_TIME(TIME *to, struct tm *from);
......
......@@ -309,15 +309,6 @@ ulong my_bind_addr; /* the address we bind to */
volatile ulong cached_thread_count= 0;
double log_10[32]; /* 10 potences */
ulonglong log_10_int[20]=
{
1, 10, 100, 1000, 10000UL, 100000UL, 1000000UL, 10000000UL,
ULL(100000000), ULL(1000000000), ULL(10000000000), ULL(100000000000),
ULL(1000000000000), ULL(10000000000000), ULL(100000000000000),
ULL(1000000000000000), ULL(10000000000000000), ULL(100000000000000000),
ULL(1000000000000000000), ULL(10000000000000000000)
};
time_t start_time;
char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], system_time_zone[30];
......@@ -4928,18 +4919,18 @@ The minimum value for this variable is 4096.",
0, GET_ULONG, REQUIRED_ARG, 0, 0, 7L, 0, 1, 0},
{ "date-format", OPT_DATE_FORMAT,
"The DATE format (For future).",
(gptr*) &opt_date_time_formats[TIMESTAMP_DATE],
(gptr*) &opt_date_time_formats[TIMESTAMP_DATE],
(gptr*) &opt_date_time_formats[MYSQL_TIMESTAMP_DATE],
(gptr*) &opt_date_time_formats[MYSQL_TIMESTAMP_DATE],
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{ "datetime-format", OPT_DATETIME_FORMAT,
"The DATETIME/TIMESTAMP format (for future).",
(gptr*) &opt_date_time_formats[TIMESTAMP_DATETIME],
(gptr*) &opt_date_time_formats[TIMESTAMP_DATETIME],
(gptr*) &opt_date_time_formats[MYSQL_TIMESTAMP_DATETIME],
(gptr*) &opt_date_time_formats[MYSQL_TIMESTAMP_DATETIME],
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{ "time-format", OPT_TIME_FORMAT,
"The TIME format (for future).",
(gptr*) &opt_date_time_formats[TIMESTAMP_TIME],
(gptr*) &opt_date_time_formats[TIMESTAMP_TIME],
(gptr*) &opt_date_time_formats[MYSQL_TIMESTAMP_TIME],
(gptr*) &opt_date_time_formats[MYSQL_TIMESTAMP_TIME],
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
......@@ -6045,11 +6036,11 @@ static void get_options(int argc,char **argv)
if (opt_log_queries_not_using_indexes)
opt_specialflag|= SPECIAL_LOG_QUERIES_NOT_USING_INDEXES;
if (init_global_datetime_format(TIMESTAMP_DATE,
if (init_global_datetime_format(MYSQL_TIMESTAMP_DATE,
&global_system_variables.date_format) ||
init_global_datetime_format(TIMESTAMP_TIME,
init_global_datetime_format(MYSQL_TIMESTAMP_TIME,
&global_system_variables.time_format) ||
init_global_datetime_format(TIMESTAMP_DATETIME,
init_global_datetime_format(MYSQL_TIMESTAMP_DATETIME,
&global_system_variables.datetime_format))
exit(1);
}
......
......@@ -351,13 +351,13 @@ sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_p
sys_var_thd_date_time_format sys_time_format("time_format",
&SV::time_format,
TIMESTAMP_TIME);
MYSQL_TIMESTAMP_TIME);
sys_var_thd_date_time_format sys_date_format("date_format",
&SV::date_format,
TIMESTAMP_DATE);
MYSQL_TIMESTAMP_DATE);
sys_var_thd_date_time_format sys_datetime_format("datetime_format",
&SV::datetime_format,
TIMESTAMP_DATETIME);
MYSQL_TIMESTAMP_DATETIME);
/* Variables that are bits in THD */
......
......@@ -669,7 +669,7 @@ public:
class sys_var_thd_date_time_format :public sys_var_thd
{
DATE_TIME_FORMAT *SV::*offset;
enum timestamp_type date_time_type;
timestamp_type date_time_type;
public:
sys_var_thd_date_time_format(const char *name_arg,
DATE_TIME_FORMAT *SV::*offset_arg,
......
......@@ -361,7 +361,7 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
}
tm.day= tm.year= tm.month= 0;
param->set_time(&tm, TIMESTAMP_TIME,
param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
*pos+= length;
......@@ -396,7 +396,7 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
param->set_time(&tm, TIMESTAMP_DATETIME,
param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
*pos+= length;
......@@ -423,7 +423,7 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len)
tm.second_part= 0;
tm.neg= 0;
param->set_time(&tm, TIMESTAMP_DATE,
param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
*pos+= length;
......@@ -432,58 +432,25 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len)
#else/*!EMBEDDED_LIBRARY*/
void set_param_time(Item_param *param, uchar **pos, ulong len)
{
TIME tm;
MYSQL_TIME *to= (MYSQL_TIME*)*pos;
tm.second_part= to->second_part;
tm.day= to->day;
tm.hour= to->hour;
tm.minute= to->minute;
tm.second= to->second;
tm.year= tm.month= 0;
tm.neg= to->neg;
param->set_time(&tm, TIMESTAMP_TIME,
param->set_time(to, MYSQL_TIMESTAMP_TIME,
MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
void set_param_datetime(Item_param *param, uchar **pos, ulong len)
{
TIME tm;
MYSQL_TIME *to= (MYSQL_TIME*)*pos;
tm.second_part= to->second_part;
tm.day= to->day;
tm.hour= to->hour;
tm.minute= to->minute;
tm.second= to->second;
tm.year= to->year;
tm.month= to->month;
tm.neg= 0;
param->set_time(&tm, TIMESTAMP_DATETIME,
param->set_time(to, MYSQL_TIMESTAMP_DATETIME,
MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
void set_param_date(Item_param *param, uchar **pos, ulong len)
{
TIME tm;
MYSQL_TIME *to= (MYSQL_TIME*)*pos;
tm.second_part= to->second_part;
tm.day= to->day;
tm.year= to->year;
tm.month= to->month;
tm.neg= 0;
tm.hour= tm.minute= tm.second= 0;
tm.second_part= 0;
tm.neg= 0;
param->set_time(&tm, TIMESTAMP_DATE,
param->set_time(to, MYSQL_TIMESTAMP_DATE,
MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
#endif /*!EMBEDDED_LIBRARY*/
......
......@@ -3530,9 +3530,9 @@ interval:
| YEAR_SYM { $$=INTERVAL_YEAR; };
date_time_type:
DATE_SYM {$$=TIMESTAMP_DATE;}
| TIME_SYM {$$=TIMESTAMP_TIME;}
| DATETIME {$$=TIMESTAMP_DATETIME;};
DATE_SYM {$$=MYSQL_TIMESTAMP_DATE;}
| TIME_SYM {$$=MYSQL_TIMESTAMP_TIME;}
| DATETIME {$$=MYSQL_TIMESTAMP_DATETIME;};
table_alias:
/* empty */
......
......@@ -130,23 +130,14 @@ typedef struct st_read_record { /* Parameter to read_record */
} READ_RECORD;
enum timestamp_type
{
TIMESTAMP_NONE= -2, TIMESTAMP_DATETIME_ERROR= -1,
TIMESTAMP_DATE= 0, TIMESTAMP_DATETIME= 1, TIMESTAMP_TIME= 2
};
/* Parameters to str_to_TIME */
#define TIME_FUZZY_DATE 1
#define TIME_DATETIME_ONLY 2
typedef struct st_time {
uint year,month,day,hour,minute,second;
ulong second_part;
bool neg;
timestamp_type time_type;
} TIME;
/*
Originally MySQL used TIME structure inside server only, but since
4.1 it's exported to user in the new client API. Define aliases for
new names to keep existing code simple.
*/
typedef struct st_mysql_time TIME;
typedef enum enum_mysql_timestamp_type timestamp_type;
typedef struct {
......
This diff is collapsed.
......@@ -584,7 +584,7 @@ sec_to_TIME(TIME * tmp, my_time_t t, long offset)
/* filling MySQL specific TIME members */
tmp->neg= 0; tmp->second_part= 0;
tmp->time_type= TIMESTAMP_DATETIME;
tmp->time_type= MYSQL_TIMESTAMP_DATETIME;
}
......@@ -1011,7 +1011,7 @@ Time_zone_system::gmt_sec_to_TIME(TIME *tmp, my_time_t t) const
localtime_r(&tmp_t, &tmp_tm);
localtime_to_TIME(tmp, &tmp_tm);
tmp->time_type= TIMESTAMP_DATETIME;
tmp->time_type= MYSQL_TIMESTAMP_DATETIME;
}
......@@ -1094,7 +1094,7 @@ Time_zone_utc::gmt_sec_to_TIME(TIME *tmp, my_time_t t) const
time_t tmp_t= (time_t)t;
gmtime_r(&tmp_t, &tmp_tm);
localtime_to_TIME(tmp, &tmp_tm);
tmp->time_type= TIMESTAMP_DATETIME;
tmp->time_type= MYSQL_TIMESTAMP_DATETIME;
}
......
......@@ -9964,6 +9964,80 @@ static void test_bug4236()
}
static void test_bug4030()
{
MYSQL_STMT *stmt;
MYSQL_BIND bind[3];
MYSQL_TIME time_canonical, time_out;
MYSQL_TIME date_canonical, date_out;
MYSQL_TIME datetime_canonical, datetime_out;
const char *stmt_text;
int rc;
myheader("test_bug4030");
/* Check that microseconds are inserted and selected successfully */
/* Execute a query with time values in prepared mode */
stmt= mysql_stmt_init(mysql);
stmt_text= "SELECT '23:59:59.123456', '2003-12-31', "
"'2003-12-31 23:59:59.123456'";
rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
check_execute(stmt, rc);
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
/* Bind output buffers */
bzero(bind, sizeof(bind));
bzero(&time_canonical, sizeof(time_canonical));
bzero(&time_out, sizeof(time_out));
bzero(&date_canonical, sizeof(date_canonical));
bzero(&date_out, sizeof(date_out));
bzero(&datetime_canonical, sizeof(datetime_canonical));
bzero(&datetime_out, sizeof(datetime_out));
bind[0].buffer_type= MYSQL_TYPE_TIME;
bind[0].buffer= (char*) &time_out;
bind[1].buffer_type= MYSQL_TYPE_DATE;
bind[1].buffer= (char*) &date_out;
bind[2].buffer_type= MYSQL_TYPE_DATETIME;
bind[2].buffer= (char*) &datetime_out;
time_canonical.hour= 23;
time_canonical.minute= 59;
time_canonical.second= 59;
time_canonical.second_part= 123456;
time_canonical.time_type= MYSQL_TIMESTAMP_TIME;
date_canonical.year= 2003;
date_canonical.month= 12;
date_canonical.day= 31;
date_canonical.time_type= MYSQL_TIMESTAMP_DATE;
datetime_canonical= time_canonical;
datetime_canonical.year= 2003;
datetime_canonical.month= 12;
datetime_canonical.day= 31;
datetime_canonical.time_type= MYSQL_TIMESTAMP_DATETIME;
mysql_stmt_bind_result(stmt, bind);
rc= mysql_stmt_fetch(stmt);
assert(rc == 0);
printf("%d:%d:%d.%lu\n", time_out.hour, time_out.minute, time_out.second,
time_out.second_part);
printf("%d-%d-%d\n", date_out.year, date_out.month, date_out.day);
printf("%d-%d-%d %d:%d:%d.%lu\n", datetime_out.year, datetime_out.month,
datetime_out.day, datetime_out.hour,
datetime_out.minute, datetime_out.second,
datetime_out.second_part);
assert(memcmp(&time_canonical, &time_out, sizeof(time_out)) == 0);
assert(memcmp(&date_canonical, &date_out, sizeof(date_out)) == 0);
assert(memcmp(&datetime_canonical, &datetime_out, sizeof(datetime_out)) == 0);
mysql_stmt_close(stmt);
}
/*
Read and parse arguments and MySQL options from my.cnf
*/
......@@ -10259,6 +10333,8 @@ int main(int argc, char **argv)
test_bug4026(); /* test microseconds precision of time types */
test_bug4079(); /* erroneous subquery in prepared statement */
test_bug4236(); /* init -> execute */
test_bug4030(); /* test conversion string -> time types in
libmysql */
/*
XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST
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