Commit 8b7fd8f5 authored by Sergei Golubchik's avatar Sergei Golubchik

lp:731124 Loss of precision on DISTINCT

many changes:
* NOT_FIXED_DEC now create hires fields, not old ones.
  As a result, temp tables preserve microseconds (on DISTINCT, GROUP BY)
* I_S tables force decimals=0 on temporal types (backward compatibility)
* Item_func_coalesce calculates decimals for temporal types
* no precision for TIME/DATETIME in CAST means 0, not NOT_FIXED_DEC
* addtime/timediff calculate decimals from arguments (not NOT_FIXED_DEC)

sql/field.h:
  NOT_FIXED_DEC now create hires fields, not old ones
sql/item.h:
  force decimals=0 for I_S tables
sql/item_cmpfunc.cc:
  Item_func_coalesce calculates decimals for temporal types
sql/item_create.cc:
  no precision for TIME/DATETIME in CAST means 0, not NOT_FIXED_DEC
sql/item_timefunc.cc:
  addtime calculates decimals from arguments (not NOT_FIXED_DEC)
sql/item_timefunc.h:
  timediff calculates decimals from arguments (not NOT_FIXED_DEC)
parent 2c80662d
......@@ -196,16 +196,16 @@ date format datetime
0003-01-02 8:11:2.123456 %Y-%m-%d %H:%i:%S.%# 0003-01-02 08:11:02
03-01-02 8:11:2.123456 %Y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02
2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12
2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.123450
2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.123450
2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.123450
2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12
2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12
2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12
2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12
10:20:10 %H:%i:%s 0000-00-00 10:20:10
10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10
10:20:10 %T 0000-00-00 10:20:10
10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10
10:20:10AM %r 0000-00-00 10:20:10
10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.440000
10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10
15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58
15 September 2001 %d %M %Y 2001-09-15 00:00:00
15 SEPTEMB 2001 %d %M %Y 2001-09-15 00:00:00
......@@ -487,7 +487,7 @@ str_to_date(a,b)
create table t2 select str_to_date(a,b) from t1;
describe t2;
Field Type Null Key Default Extra
str_to_date(a,b) datetime YES NULL
str_to_date(a,b) datetime(6) YES NULL
select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f") as f1,
str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S") as f2,
str_to_date("2003-01-02", "%Y-%m-%d") as f3,
......
......@@ -805,3 +805,16 @@ a
2010-10-10
20101010
drop table t1;
create table t1 (f1 varchar(40));
insert into t1 values ('2010-10-10 00:00:00.0001'),('2010-10-10 00:00:00.0002'),('2010-10-10 00:00:00.0003');
select time(f1) from t1 ;
time(f1)
00:00:00.000100
00:00:00.000200
00:00:00.000300
select distinct time(f1) from t1 ;
time(f1)
00:00:00.000100
00:00:00.000200
00:00:00.000300
drop table t1;
......@@ -195,17 +195,17 @@ time("1997-12-31 23:59:59.000001") as f9;
describe t1;
Field Type Null Key Default Extra
f1 date YES NULL
f2 datetime YES NULL
f3 time YES NULL
f4 time YES NULL
f5 time YES NULL
f2 datetime(6) YES NULL
f3 time(6) YES NULL
f4 time(6) YES NULL
f5 time(6) YES NULL
f6 time YES NULL
f7 datetime YES NULL
f7 datetime(6) YES NULL
f8 date YES NULL
f9 time YES NULL
f9 time(6) YES NULL
select * from t1;
f1 f2 f3 f4 f5 f6 f7 f8 f9
1997-01-01 1998-01-02 01:01:00 49:01:01 46:58:57 -24:00:00 10:11:12 2001-12-01 01:01:01 1997-12-31 23:59:59
1997-01-01 1998-01-02 01:01:00.000003 49:01:01.000001 46:58:57.999999 8275:29:36.710655 10:11:12 2001-12-01 01:01:01.000000 1997-12-31 23:59:59.000001
create table test(t1 datetime, t2 time, t3 time, t4 datetime);
insert into test values
('2001-01-01 01:01:01', '01:01:01', null, '2001-02-01 01:01:01'),
......@@ -230,8 +230,8 @@ SELECT TIMEDIFF(t1, t4) As ttt, TIMEDIFF(t2, t3) As qqq,
TIMEDIFF(t3, t2) As eee, TIMEDIFF(t2, t4) As rrr from test;
ttt qqq eee rrr
-744:00:00 NULL NULL NULL
838:59:59.999999 22:58:58 -22:58:58 NULL
-838:59:59.999999 -22:58:58 22:58:58 NULL
838:59:59 22:58:58 -22:58:58 NULL
-838:59:59 -22:58:58 22:58:58 NULL
NULL 26:02:02 -26:02:02 NULL
00:00:00 -26:02:02 26:02:02 NULL
NULL NULL NULL NULL
......
......@@ -37,7 +37,7 @@ Table Create Table
t1 CREATE TABLE `t1` (
`sec_to_time(12345)` time DEFAULT NULL,
`sec_to_time(12345.6789)` time(4) DEFAULT NULL,
`sec_to_time(1234567e-2)` time DEFAULT NULL,
`sec_to_time(1234567e-2)` time(6) DEFAULT NULL,
`now()` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`curtime(0)` time NOT NULL DEFAULT '00:00:00',
`utc_timestamp(1)` datetime(1) NOT NULL DEFAULT '0000-00-00 00:00:00.0',
......@@ -52,7 +52,7 @@ t1 CREATE TABLE `t1` (
select * from t1;
sec_to_time(12345) 03:25:45
sec_to_time(12345.6789) 03:25:45.6789
sec_to_time(1234567e-2) 03:25:45
sec_to_time(1234567e-2) 03:25:45.670000
now() 2011-01-01 01:01:01
curtime(0) 01:01:01
utc_timestamp(1) 2010-12-31 22:01:01.1
......
......@@ -624,3 +624,12 @@ select * from t1 where a = DATE('2010-10-10');
select distinct a from t1 where a = DATE('2010-10-10');
drop table t1;
#
# lp:731124 Loss of precision on DISTINCT
#
create table t1 (f1 varchar(40));
insert into t1 values ('2010-10-10 00:00:00.0001'),('2010-10-10 00:00:00.0002'),('2010-10-10 00:00:00.0003');
select time(f1) from t1 ;
select distinct time(f1) from t1 ;
drop table t1;
......@@ -1501,12 +1501,13 @@ new_Field_timestamp(uchar *ptr, uchar *null_ptr, uchar null_bit,
enum Field::utype unireg_check, const char *field_name,
TABLE_SHARE *share, uint dec, CHARSET_INFO *cs)
{
if (dec==0 || dec == NOT_FIXED_DEC)
if (dec==0)
return new Field_timestamp(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit,
unireg_check, field_name, share, cs);
else
return new Field_timestamp_hires(ptr, null_ptr, null_bit, unireg_check,
field_name, share, dec, cs);
if (dec == NOT_FIXED_DEC)
dec= MAX_DATETIME_PRECISION;
return new Field_timestamp_hires(ptr, null_ptr, null_bit, unireg_check,
field_name, share, dec, cs);
}
static inline Field_time *
......@@ -1514,12 +1515,13 @@ new_Field_time(uchar *ptr, uchar *null_ptr, uchar null_bit,
enum Field::utype unireg_check, const char *field_name,
uint dec, CHARSET_INFO *cs)
{
if (dec == 0 || dec == NOT_FIXED_DEC)
if (dec == 0)
return new Field_time(ptr, MIN_TIME_WIDTH, null_ptr, null_bit,
unireg_check, field_name, cs);
else
return new Field_time_hires(ptr, null_ptr, null_bit,
unireg_check, field_name, dec, cs);
if (dec == NOT_FIXED_DEC)
dec= MAX_DATETIME_PRECISION;
return new Field_time_hires(ptr, null_ptr, null_bit,
unireg_check, field_name, dec, cs);
}
static inline Field_datetime *
......@@ -1527,12 +1529,13 @@ new_Field_datetime(uchar *ptr, uchar *null_ptr, uchar null_bit,
enum Field::utype unireg_check,
const char *field_name, uint dec, CHARSET_INFO *cs)
{
if (dec == 0 || dec == NOT_FIXED_DEC)
if (dec == 0)
return new Field_datetime(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit,
unireg_check, field_name, cs);
else
return new Field_datetime_hires(ptr, null_ptr, null_bit,
unireg_check, field_name, dec, cs);
if (dec == NOT_FIXED_DEC)
dec= MAX_DATETIME_PRECISION;
return new Field_datetime_hires(ptr, null_ptr, null_bit,
unireg_check, field_name, dec, cs);
}
class Field_string :public Field_longstr {
......
......@@ -2075,7 +2075,7 @@ class Item_return_date_time :public Item_partition_func_safe_string
enum_field_types field_type_arg)
:Item_partition_func_safe_string(name_arg, length_arg, &my_charset_bin),
date_time_field_type(field_type_arg)
{ }
{ decimals= 0; }
enum_field_types field_type() const { return date_time_field_type; }
};
......
......@@ -2920,6 +2920,13 @@ void Item_func_coalesce::fix_length_and_dec()
{
cached_field_type= agg_field_type(args, arg_count);
agg_result_type(&hybrid_type, args, arg_count);
Item_result cmp_type;
agg_cmp_type(&cmp_type, args, arg_count);
if (cmp_type == TIME_RESULT)
{
count_real_length();
return;
}
switch (hybrid_type) {
case STRING_RESULT:
count_only_length();
......
......@@ -5091,7 +5091,7 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type,
}
}
else
len= NOT_FIXED_DEC;
len= 0;
if (cast_type == ITEM_CAST_TIME)
res= new (thd->mem_root) Item_time_typecast(a, len);
......
......@@ -2379,7 +2379,7 @@ void Item_func_add_time::fix_length_and_dec()
{
enum_field_types arg0_field_type;
max_length= MAX_DATETIME_WIDTH;
decimals= NOT_FIXED_DEC;
decimals= max(args[0]->decimals, args[1]->decimals);
maybe_null= 1;
/*
......
......@@ -765,7 +765,7 @@ class Item_func_timediff :public Item_timefunc
const char *func_name() const { return "timediff"; }
void fix_length_and_dec()
{
decimals= NOT_FIXED_DEC;
decimals= max(args[0]->decimals, args[1]->decimals);
Item_timefunc::fix_length_and_dec();
maybe_null= 1;
}
......
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