bug #19491 (CAST do DATETIME wrong result)

parent 001aaedd
...@@ -179,3 +179,15 @@ a ...@@ -179,3 +179,15 @@ a
2006-06-06 15:55:55 2006-06-06 15:55:55
DROP PREPARE s; DROP PREPARE s;
DROP TABLE t1; DROP TABLE t1;
SELECT CAST(CAST('2006-08-10' AS DATE) AS DECIMAL(20,6));
CAST(CAST('2006-08-10' AS DATE) AS DECIMAL(20,6))
20060810.000000
SELECT CAST(CAST('2006-08-10 10:11:12' AS DATETIME) AS DECIMAL(20,6));
CAST(CAST('2006-08-10 10:11:12' AS DATETIME) AS DECIMAL(20,6))
20060810101112.000000
SELECT CAST(CAST('2006-08-10 10:11:12' AS DATETIME) + INTERVAL 14 MICROSECOND AS DECIMAL(20,6));
CAST(CAST('2006-08-10 10:11:12' AS DATETIME) + INTERVAL 14 MICROSECOND AS DECIMAL(20,6))
20060810101112.000014
SELECT CAST(CAST('10:11:12.098700' AS TIME) AS DECIMAL(20,6));
CAST(CAST('10:11:12.098700' AS TIME) AS DECIMAL(20,6))
101112.098700
...@@ -1412,3 +1412,11 @@ i2 count(distinct j) ...@@ -1412,3 +1412,11 @@ i2 count(distinct j)
1.0 2 1.0 2
2.0 2 2.0 2
drop table t1; drop table t1;
create table t1(f1 decimal(20,6));
insert into t1 values (CAST('10:11:12' AS date) + interval 14 microsecond);
insert into t1 values (CAST('10:11:12' AS time));
select * from t1;
f1
20101112000000.000014
20101112.000000
drop table t1;
...@@ -125,3 +125,13 @@ PREPARE s FROM 'SELECT a FROM t1 WHERE a=(SELECT MAX(a) FROM t1) AND (a="2006060 ...@@ -125,3 +125,13 @@ PREPARE s FROM 'SELECT a FROM t1 WHERE a=(SELECT MAX(a) FROM t1) AND (a="2006060
EXECUTE s; EXECUTE s;
DROP PREPARE s; DROP PREPARE s;
DROP TABLE t1; DROP TABLE t1;
#
# Bug 19491 (CAST DATE AS DECIMAL returns incorrect result
#
SELECT CAST(CAST('2006-08-10' AS DATE) AS DECIMAL(20,6));
SELECT CAST(CAST('2006-08-10 10:11:12' AS DATETIME) AS DECIMAL(20,6));
SELECT CAST(CAST('2006-08-10 10:11:12' AS DATETIME) + INTERVAL 14 MICROSECOND AS DECIMAL(20,6));
SELECT CAST(CAST('10:11:12.098700' AS TIME) AS DECIMAL(20,6));
...@@ -1108,3 +1108,11 @@ insert into t1 values (1,1), (1,2), (2,3), (2,4); ...@@ -1108,3 +1108,11 @@ insert into t1 values (1,1), (1,2), (2,3), (2,4);
select i, count(distinct j) from t1 group by i; select i, count(distinct j) from t1 group by i;
select i+0.0 as i2, count(distinct j) from t1 group by i2; select i+0.0 as i2, count(distinct j) from t1 group by i2;
drop table t1; drop table t1;
create table t1(f1 decimal(20,6));
insert into t1 values (CAST('10:11:12' AS date) + interval 14 microsecond);
insert into t1 values (CAST('10:11:12' AS time));
select * from t1;
drop table t1;
...@@ -2413,6 +2413,13 @@ int Field_new_decimal::store_decimal(const my_decimal *decimal_value) ...@@ -2413,6 +2413,13 @@ int Field_new_decimal::store_decimal(const my_decimal *decimal_value)
} }
int Field_new_decimal::store_time(TIME *ltime, timestamp_type t_type)
{
my_decimal decimal_value;
return store_value(date2my_decimal(ltime, &decimal_value));
}
double Field_new_decimal::val_real(void) double Field_new_decimal::val_real(void)
{ {
double dbl; double dbl;
......
...@@ -489,6 +489,7 @@ class Field_new_decimal :public Field_num { ...@@ -489,6 +489,7 @@ class Field_new_decimal :public Field_num {
int store(const char *to, uint length, CHARSET_INFO *charset); int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr); int store(double nr);
int store(longlong nr, bool unsigned_val); int store(longlong nr, bool unsigned_val);
int store_time(TIME *ltime, timestamp_type t_type);
int store_decimal(const my_decimal *); int store_decimal(const my_decimal *);
double val_real(void); double val_real(void);
longlong val_int(void); longlong val_int(void);
......
...@@ -272,6 +272,34 @@ my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value) ...@@ -272,6 +272,34 @@ my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value)
} }
my_decimal *Item::val_decimal_from_date(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
TIME ltime;
longlong date;
if (get_date(&ltime, TIME_FUZZY_DATE))
{
my_decimal_set_zero(decimal_value);
return 0;
}
return date2my_decimal(&ltime, decimal_value);
}
my_decimal *Item::val_decimal_from_time(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
TIME ltime;
longlong date;
if (get_time(&ltime))
{
my_decimal_set_zero(decimal_value);
return 0;
}
return date2my_decimal(&ltime, decimal_value);
}
double Item::val_real_from_decimal() double Item::val_real_from_decimal()
{ {
/* Note that fix_fields may not be called for Item_avg_field items */ /* Note that fix_fields may not be called for Item_avg_field items */
...@@ -295,6 +323,25 @@ longlong Item::val_int_from_decimal() ...@@ -295,6 +323,25 @@ longlong Item::val_int_from_decimal()
return result; return result;
} }
int Item::save_time_in_field(Field *field)
{
TIME ltime;
if (get_time(&ltime))
return set_field_to_null(field);
field->set_notnull();
return field->store_time(&ltime, MYSQL_TIMESTAMP_TIME);
}
int Item::save_date_in_field(Field *field)
{
TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE))
return set_field_to_null(field);
field->set_notnull();
return field->store_time(&ltime, MYSQL_TIMESTAMP_DATETIME);
}
Item::Item(): Item::Item():
rsize(0), name(0), orig_name(0), name_length(0), fixed(0), rsize(0), name(0), orig_name(0), name_length(0), fixed(0),
......
...@@ -605,9 +605,14 @@ class Item { ...@@ -605,9 +605,14 @@ class Item {
my_decimal *val_decimal_from_real(my_decimal *decimal_value); my_decimal *val_decimal_from_real(my_decimal *decimal_value);
my_decimal *val_decimal_from_int(my_decimal *decimal_value); my_decimal *val_decimal_from_int(my_decimal *decimal_value);
my_decimal *val_decimal_from_string(my_decimal *decimal_value); my_decimal *val_decimal_from_string(my_decimal *decimal_value);
my_decimal *val_decimal_from_date(my_decimal *decimal_value);
my_decimal *val_decimal_from_time(my_decimal *decimal_value);
longlong val_int_from_decimal(); longlong val_int_from_decimal();
double val_real_from_decimal(); double val_real_from_decimal();
int save_time_in_field(Field *field);
int save_date_in_field(Field *field);
virtual Field *get_tmp_table_field() { return 0; } virtual Field *get_tmp_table_field() { return 0; }
/* This is also used to create fields in CREATE ... SELECT: */ /* This is also used to create fields in CREATE ... SELECT: */
virtual Field *tmp_table_field(TABLE *t_arg) { return 0; } virtual Field *tmp_table_field(TABLE *t_arg) { return 0; }
......
...@@ -1294,17 +1294,6 @@ String *Item_date::val_str(String *str) ...@@ -1294,17 +1294,6 @@ String *Item_date::val_str(String *str)
} }
int Item_date::save_in_field(Field *field, bool no_conversions)
{
TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE))
return set_field_to_null(field);
field->set_notnull();
field->store_time(&ltime, MYSQL_TIMESTAMP_DATE);
return 0;
}
longlong Item_date::val_int() longlong Item_date::val_int()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
......
...@@ -339,12 +339,20 @@ class Item_date :public Item_func ...@@ -339,12 +339,20 @@ class Item_date :public Item_func
decimals=0; decimals=0;
max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
} }
int save_in_field(Field *to, bool no_conversions);
Field *tmp_table_field(TABLE *t_arg) Field *tmp_table_field(TABLE *t_arg)
{ {
return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
} }
bool result_as_longlong() { return TRUE; } bool result_as_longlong() { return TRUE; }
my_decimal *val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
return val_decimal_from_date(decimal_value);
}
int save_in_field(Field *field, bool no_conversions)
{
return save_date_in_field(field);
}
}; };
...@@ -361,21 +369,57 @@ class Item_date_func :public Item_str_func ...@@ -361,21 +369,57 @@ class Item_date_func :public Item_str_func
return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin)); return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin));
} }
bool result_as_longlong() { return TRUE; } bool result_as_longlong() { return TRUE; }
my_decimal *val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
return val_decimal_from_date(decimal_value);
}
int save_in_field(Field *field, bool no_conversions)
{
return save_date_in_field(field);
}
};
class Item_str_timefunc :public Item_str_func
{
public:
Item_str_timefunc() :Item_str_func() {}
Item_str_timefunc(Item *a) :Item_str_func(a) {}
Item_str_timefunc(Item *a,Item *b) :Item_str_func(a,b) {}
Item_str_timefunc(Item *a, Item *b, Item *c) :Item_str_func(a, b ,c) {}
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
void fix_length_and_dec()
{
decimals=0;
max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
}
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
}
my_decimal *val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
return val_decimal_from_time(decimal_value);
}
int save_in_field(Field *field, bool no_conversions)
{
return save_time_in_field(field);
}
}; };
/* Abstract CURTIME function. Children should define what time zone is used */ /* Abstract CURTIME function. Children should define what time zone is used */
class Item_func_curtime :public Item_func class Item_func_curtime :public Item_str_timefunc
{ {
longlong value; longlong value;
char buff[9*2+32]; char buff[9*2+32];
uint buff_length; uint buff_length;
public: public:
Item_func_curtime() :Item_func() {} Item_func_curtime() :Item_str_timefunc() {}
Item_func_curtime(Item *a) :Item_func(a) {} Item_func_curtime(Item *a) :Item_str_timefunc(a) {}
enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; } double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; } longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
String *val_str(String *str); String *val_str(String *str);
...@@ -602,10 +646,10 @@ class Item_func_convert_tz :public Item_date_func ...@@ -602,10 +646,10 @@ class Item_func_convert_tz :public Item_date_func
}; };
class Item_func_sec_to_time :public Item_str_func class Item_func_sec_to_time :public Item_str_timefunc
{ {
public: public:
Item_func_sec_to_time(Item *item) :Item_str_func(item) {} Item_func_sec_to_time(Item *item) :Item_str_timefunc(item) {}
double val_real() double val_real()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
...@@ -615,17 +659,12 @@ class Item_func_sec_to_time :public Item_str_func ...@@ -615,17 +659,12 @@ class Item_func_sec_to_time :public Item_str_func
String *val_str(String *); String *val_str(String *);
void fix_length_and_dec() void fix_length_and_dec()
{ {
Item_str_timefunc::fix_length_and_dec();
collation.set(&my_charset_bin); collation.set(&my_charset_bin);
maybe_null=1; maybe_null=1;
decimals= DATETIME_DEC; decimals= DATETIME_DEC;
max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
} }
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
const char *func_name() const { return "sec_to_time"; } const char *func_name() const { return "sec_to_time"; }
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
}
bool result_as_longlong() { return TRUE; } bool result_as_longlong() { return TRUE; }
}; };
...@@ -759,6 +798,15 @@ class Item_date_typecast :public Item_typecast_maybe_null ...@@ -759,6 +798,15 @@ class Item_date_typecast :public Item_typecast_maybe_null
} }
bool result_as_longlong() { return TRUE; } bool result_as_longlong() { return TRUE; }
longlong val_int(); longlong val_int();
my_decimal *val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
return val_decimal_from_date(decimal_value);
}
int save_in_field(Field *field, bool no_conversions)
{
return save_date_in_field(field);
}
}; };
...@@ -777,6 +825,15 @@ class Item_time_typecast :public Item_typecast_maybe_null ...@@ -777,6 +825,15 @@ class Item_time_typecast :public Item_typecast_maybe_null
} }
bool result_as_longlong() { return TRUE; } bool result_as_longlong() { return TRUE; }
longlong val_int(); longlong val_int();
my_decimal *val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
return val_decimal_from_time(decimal_value);
}
int save_in_field(Field *field, bool no_conversions)
{
return save_time_in_field(field);
}
}; };
...@@ -794,12 +851,21 @@ class Item_datetime_typecast :public Item_typecast_maybe_null ...@@ -794,12 +851,21 @@ class Item_datetime_typecast :public Item_typecast_maybe_null
} }
bool result_as_longlong() { return TRUE; } bool result_as_longlong() { return TRUE; }
longlong val_int(); longlong val_int();
my_decimal *val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
return val_decimal_from_date(decimal_value);
}
int save_in_field(Field *field, bool no_conversions)
{
return save_date_in_field(field);
}
}; };
class Item_func_makedate :public Item_str_func class Item_func_makedate :public Item_date_func
{ {
public: public:
Item_func_makedate(Item *a,Item *b) :Item_str_func(a,b) {} Item_func_makedate(Item *a,Item *b) :Item_date_func(a,b) {}
String *val_str(String *str); String *val_str(String *str);
const char *func_name() const { return "makedate"; } const char *func_name() const { return "makedate"; }
enum_field_types field_type() const { return MYSQL_TYPE_DATE; } enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
...@@ -812,8 +878,16 @@ class Item_func_makedate :public Item_str_func ...@@ -812,8 +878,16 @@ class Item_func_makedate :public Item_str_func
{ {
return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
} }
bool result_as_longlong() { return TRUE; }
longlong val_int(); longlong val_int();
my_decimal *val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
return val_decimal_from_date(decimal_value);
}
int save_in_field(Field *field, bool no_conversions)
{
return save_date_in_field(field);
}
}; };
...@@ -845,45 +919,46 @@ class Item_func_add_time :public Item_str_func ...@@ -845,45 +919,46 @@ class Item_func_add_time :public Item_str_func
} }
void print(String *str); void print(String *str);
const char *func_name() const { return "add_time"; } const char *func_name() const { return "add_time"; }
my_decimal *val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
if (cached_field_type == MYSQL_TYPE_TIME)
return val_decimal_from_time(decimal_value);
if (cached_field_type == MYSQL_TYPE_DATETIME)
return val_decimal_from_date(decimal_value);
return Item_str_func::val_decimal(decimal_value);
}
int save_in_field(Field *field, bool no_conversions)
{
if (cached_field_type == MYSQL_TYPE_TIME)
return save_time_in_field(field);
if (cached_field_type == MYSQL_TYPE_DATETIME)
return save_date_in_field(field);
return Item_str_func::save_in_field(field, no_conversions);
}
}; };
class Item_func_timediff :public Item_str_func class Item_func_timediff :public Item_str_timefunc
{ {
public: public:
Item_func_timediff(Item *a, Item *b) Item_func_timediff(Item *a, Item *b)
:Item_str_func(a, b) {} :Item_str_timefunc(a, b) {}
String *val_str(String *str); String *val_str(String *str);
const char *func_name() const { return "timediff"; } const char *func_name() const { return "timediff"; }
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
void fix_length_and_dec() void fix_length_and_dec()
{ {
decimals=0; Item_str_timefunc::fix_length_and_dec();
max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null= 1; maybe_null= 1;
} }
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
}
}; };
class Item_func_maketime :public Item_str_func class Item_func_maketime :public Item_str_timefunc
{ {
public: public:
Item_func_maketime(Item *a, Item *b, Item *c) Item_func_maketime(Item *a, Item *b, Item *c)
:Item_str_func(a, b ,c) {} :Item_str_timefunc(a, b ,c) {}
String *val_str(String *str); String *val_str(String *str);
const char *func_name() const { return "maketime"; } const char *func_name() const { return "maketime"; }
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
void fix_length_and_dec()
{
decimals=0;
max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
}
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
}
}; };
class Item_func_microsecond :public Item_int_func class Item_func_microsecond :public Item_int_func
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysql_priv.h" #include "mysql_priv.h"
#include <time.h>
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
/* /*
...@@ -190,6 +192,23 @@ int str2my_decimal(uint mask, const char *from, uint length, ...@@ -190,6 +192,23 @@ int str2my_decimal(uint mask, const char *from, uint length,
} }
my_decimal *date2my_decimal(TIME *ltime, my_decimal *dec)
{
longlong date;
date = (ltime->year*100L + ltime->month)*100L + ltime->day;
if (ltime->time_type > MYSQL_TIMESTAMP_DATE)
date= ((date*100L + ltime->hour)*100L+ ltime->minute)*100L + ltime->second;
if (int2my_decimal(E_DEC_FATAL_ERROR, date, FALSE, dec))
return dec;
if (ltime->second_part)
{
dec->buf[(dec->intg-1) / 9 + 1]= ltime->second_part * 1000;
dec->frac= 6;
}
return dec;
}
#ifndef DBUG_OFF #ifndef DBUG_OFF
/* routines for debugging print */ /* routines for debugging print */
......
...@@ -295,7 +295,12 @@ int string2my_decimal(uint mask, const String *str, my_decimal *d) ...@@ -295,7 +295,12 @@ int string2my_decimal(uint mask, const String *str, my_decimal *d)
{ {
return str2my_decimal(mask, str->ptr(), str->length(), str->charset(), d); return str2my_decimal(mask, str->ptr(), str->length(), str->charset(), d);
} }
#endif
my_decimal *date2my_decimal(TIME *ltime, my_decimal *dec);
#endif /*defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) */
inline inline
int double2my_decimal(uint mask, double val, my_decimal *d) int double2my_decimal(uint mask, double val, my_decimal *d)
......
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