Commit 7bb6a725 authored by unknown's avatar unknown

Bug#27590: Wrong DATE/DATETIME comparison.

DATE and DATETIME can be compared either as strings or as int. Both
methods have their disadvantages. Strings can contain valid DATETIME value
but have insignificant zeros omitted thus became non-comparable with
other DATETIME strings. The comparison as int usually will require conversion
from the string representation and the automatic conversion in most cases is
carried out in a wrong way thus producing wrong comparison result. Another
problem occurs when one tries to compare DATE field with a DATETIME constant.
The constant is converted to DATE losing its precision i.e. losing time part.

This fix addresses the problems described above by adding a special
DATE/DATETIME comparator. The comparator correctly converts DATE/DATETIME
string values to int when it's necessary, adds zero time part (00:00:00)
to DATE values to compare them correctly to DATETIME values. Due to correct
conversion malformed DATETIME string values are correctly compared to other
DATE/DATETIME values.

As of this patch a DATE value equals to DATETIME value with zero time part.
For example '2001-01-01' equals to '2001-01-01 00:00:00'.

The compare_datetime() function is added to the Arg_comparator class.
It implements the correct comparator for DATE/DATETIME values.
Two supplementary functions called get_date_from_str() and get_datetime_value()
are added. The first one extracts DATE/DATETIME value from a string and the
second one retrieves the correct DATE/DATETIME value from an item.
The new Arg_comparator::can_compare_as_dates() function is added and used
to check whether two given items can be compared by the compare_datetime()
comparator.
Two caching variables were added to the Arg_comparator class to speedup the
DATE/DATETIME comparison.
One more store() method was added to the Item_cache_int class to cache int
values.
The new is_datetime() function was added to the Item class. It indicates
whether the item returns a DATE/DATETIME value.


sql/item.cc:
  Bug#27590: Wrong DATE/DATETIME comparison.
  One more store() method was added to the Item_cache_int class to cache int
  values.
  The new is_datetime() function was added to the Item class. It indicates
  whether the item returns a DATE/DATETIME value.
sql/item.h:
  Bug#27590: Wrong DATE/DATETIME comparison.
  One more store() method was added to the Item_cache_int class to cache int
  values.
  The new is_datetime() function was added to the Item class. It indicates
  whether the item returns a DATE/DATETIME value.
sql/item_cmpfunc.cc:
  Bug#27590: Wrong DATE/DATETIME comparison.
  The compare_datetime() function is added to the Arg_comparator class.
  It implements the correct comparator for DATE/DATETIME values.
  Two supplementary functions called get_date_from_str() and get_datetime_value()
  are added. The first one extracts DATE/DATETIME value from a string and the
  second one retrieves the correct DATE/DATETIME value from an item.
  The new Arg_comparator::can_compare_as_dates() function is added and used
  to check whether two given items can be compared by the compare_datetime()
  comparator.
sql/item_cmpfunc.h:
  Bug#27590: Wrong DATE/DATETIME comparison.
  The compare_datetime() function is added to the Arg_comparator class.
  It implements the correct comparator for DATE/DATETIME values.
  Two supplementary functions called get_date_from_str() and get_datetime_value()
  are added. The first one extracts DATE/DATETIME value from a string and the
  second one retrieves the correct DATE/DATETIME value from an item.
  The new Arg_comparator::can_compare_as_dates() function is added and used
  to check whether two given items can be compared by the compare_datetime()
  comparator.
  Two caching variables were added to the Arg_comparator class to speedup the
  DATE/DATETIME comparison.
mysql-test/include/ps_conv.inc:
  Test case adjusted after fix for bug#27590.
mysql-test/r/distinct.result:
  Test cases results are corrected after fix for bug#27590.
sql/sql_select.cc:
  Bug#27590: Wrong DATE/DATETIME comparison.
  The test_if_equality_guarantees_uniqueness() function now uses
  Arg_comparator::can_compare_as_dates() to detect comparable DATE/DATETIME items.
mysql-test/r/ps_2myisam.result:
  The result of the adjusted test case after fix for bug#27590.
mysql-test/r/ps_3innodb.result:
  The result of the adjusted test case after fix for bug#27590.
mysql-test/r/ps_4heap.result:
  The result of the adjusted test case after fix for bug#27590.
mysql-test/r/ps_5merge.result:
  The result of the adjusted test case after fix for bug#27590.
mysql-test/r/subselect.result:
  Test cases results are corrected after fix for bug#27590.
mysql-test/r/type_datetime.result:
  Added a test case for the bug#27590: Wrong DATE/DATETIME comparison.
mysql-test/t/type_datetime.test:
  Added a test case for the bug#27590: Wrong DATE/DATETIME comparison.
tests/mysql_client_test.c:
  Test case adjusted after fix for bug#27590.
parent 6073ae71
...@@ -1171,7 +1171,7 @@ execute stmt1 using @arg00, @arg00, @arg00, @arg00, @arg00 ; ...@@ -1171,7 +1171,7 @@ execute stmt1 using @arg00, @arg00, @arg00, @arg00, @arg00 ;
######## SELECT .. WHERE column(date/time/..)=value(DATETIME/LONGBLOB) ######## ######## SELECT .. WHERE column(date/time/..)=value(DATETIME/LONGBLOB) ########
set @arg00= CAST('1991-01-01 01:01:01' as datetime) ; set @arg00= CAST('1991-01-01 01:01:01' as datetime) ;
select 'true' as found from t9 select 'true' as found from t9
where c1= 20 and c13= CAST('1991-01-01 01:01:01' as datetime) and where c1= 20 and c13= CAST('1991-01-01 00:00:00' as datetime) and
c14= CAST('1991-01-01 01:01:01' as datetime) and c14= CAST('1991-01-01 01:01:01' as datetime) and
c15= CAST('1991-01-01 01:01:01' as datetime) and c15= CAST('1991-01-01 01:01:01' as datetime) and
c16= CAST('1991-01-01 01:01:01' as datetime) and c16= CAST('1991-01-01 01:01:01' as datetime) and
...@@ -1180,7 +1180,7 @@ select 'true' as found from t9 ...@@ -1180,7 +1180,7 @@ select 'true' as found from t9
where c1= 20 and c13= CAST(@arg00 AS DATE) and c14= @arg00 and c15= @arg00 and c16= @arg00 where c1= 20 and c13= CAST(@arg00 AS DATE) and c14= @arg00 and c15= @arg00 and c16= @arg00
and c17= @arg00 ; and c17= @arg00 ;
prepare stmt1 from "select 'true' as found from t9 prepare stmt1 from "select 'true' as found from t9
where c1= 20 and c13= CAST('1991-01-01 01:01:01' as datetime) and where c1= 20 and c13= CAST('1991-01-01 00:00:00' as datetime) and
c14= CAST('1991-01-01 01:01:01' as datetime) and c14= CAST('1991-01-01 01:01:01' as datetime) and
c15= CAST('1991-01-01 01:01:01' as datetime) and c15= CAST('1991-01-01 01:01:01' as datetime) and
c16= CAST('1991-01-01 01:01:01' as datetime) and c16= CAST('1991-01-01 01:01:01' as datetime) and
......
set autocommit=1;
reset master;
create table bug16206 (a int);
insert into bug16206 values(1);
start transaction;
insert into bug16206 values(2);
commit;
show binlog events;
Log_name Pos Event_type Server_id End_log_pos Info
f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4
f n Query 1 n use `test`; create table bug16206 (a int)
f n Query 1 n use `test`; insert into bug16206 values(1)
f n Query 1 n use `test`; insert into bug16206 values(2)
drop table bug16206;
reset master;
create table bug16206 (a int) engine= bdb;
insert into bug16206 values(0);
insert into bug16206 values(1);
start transaction;
insert into bug16206 values(2);
commit;
insert into bug16206 values(3);
show binlog events;
Log_name Pos Event_type Server_id End_log_pos Info
f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4
f n Query 1 n use `test`; create table bug16206 (a int) engine= bdb
f n Query 1 n use `test`; insert into bug16206 values(0)
f n Query 1 n use `test`; insert into bug16206 values(1)
f n Query 1 n use `test`; BEGIN
f n Query 1 n use `test`; insert into bug16206 values(2)
f n Query 1 n use `test`; COMMIT
f n Query 1 n use `test`; insert into bug16206 values(3)
drop table bug16206;
set autocommit=0;
End of 5.0 tests
...@@ -633,7 +633,7 @@ EXPLAIN SELECT (SELECT DISTINCT ADDDATE(a,1) FROM t1 ...@@ -633,7 +633,7 @@ EXPLAIN SELECT (SELECT DISTINCT ADDDATE(a,1) FROM t1
WHERE ADDDATE(a,1) = '2002-08-03'); WHERE ADDDATE(a,1) = '2002-08-03');
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where; Using temporary 2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where
CREATE TABLE t2 (a CHAR(5) CHARACTER SET latin1 COLLATE latin1_general_ci); CREATE TABLE t2 (a CHAR(5) CHARACTER SET latin1 COLLATE latin1_general_ci);
INSERT INTO t2 VALUES (0xf6); INSERT INTO t2 VALUES (0xf6);
INSERT INTO t2 VALUES ('oe'); INSERT INTO t2 VALUES ('oe');
......
...@@ -3070,7 +3070,7 @@ found ...@@ -3070,7 +3070,7 @@ found
true true
set @arg00= CAST('1991-01-01 01:01:01' as datetime) ; set @arg00= CAST('1991-01-01 01:01:01' as datetime) ;
select 'true' as found from t9 select 'true' as found from t9
where c1= 20 and c13= CAST('1991-01-01 01:01:01' as datetime) and where c1= 20 and c13= CAST('1991-01-01 00:00:00' as datetime) and
c14= CAST('1991-01-01 01:01:01' as datetime) and c14= CAST('1991-01-01 01:01:01' as datetime) and
c15= CAST('1991-01-01 01:01:01' as datetime) and c15= CAST('1991-01-01 01:01:01' as datetime) and
c16= CAST('1991-01-01 01:01:01' as datetime) and c16= CAST('1991-01-01 01:01:01' as datetime) and
...@@ -3083,7 +3083,7 @@ and c17= @arg00 ; ...@@ -3083,7 +3083,7 @@ and c17= @arg00 ;
found found
true true
prepare stmt1 from "select 'true' as found from t9 prepare stmt1 from "select 'true' as found from t9
where c1= 20 and c13= CAST('1991-01-01 01:01:01' as datetime) and where c1= 20 and c13= CAST('1991-01-01 00:00:00' as datetime) and
c14= CAST('1991-01-01 01:01:01' as datetime) and c14= CAST('1991-01-01 01:01:01' as datetime) and
c15= CAST('1991-01-01 01:01:01' as datetime) and c15= CAST('1991-01-01 01:01:01' as datetime) and
c16= CAST('1991-01-01 01:01:01' as datetime) and c16= CAST('1991-01-01 01:01:01' as datetime) and
......
...@@ -3053,7 +3053,7 @@ found ...@@ -3053,7 +3053,7 @@ found
true true
set @arg00= CAST('1991-01-01 01:01:01' as datetime) ; set @arg00= CAST('1991-01-01 01:01:01' as datetime) ;
select 'true' as found from t9 select 'true' as found from t9
where c1= 20 and c13= CAST('1991-01-01 01:01:01' as datetime) and where c1= 20 and c13= CAST('1991-01-01 00:00:00' as datetime) and
c14= CAST('1991-01-01 01:01:01' as datetime) and c14= CAST('1991-01-01 01:01:01' as datetime) and
c15= CAST('1991-01-01 01:01:01' as datetime) and c15= CAST('1991-01-01 01:01:01' as datetime) and
c16= CAST('1991-01-01 01:01:01' as datetime) and c16= CAST('1991-01-01 01:01:01' as datetime) and
...@@ -3066,7 +3066,7 @@ and c17= @arg00 ; ...@@ -3066,7 +3066,7 @@ and c17= @arg00 ;
found found
true true
prepare stmt1 from "select 'true' as found from t9 prepare stmt1 from "select 'true' as found from t9
where c1= 20 and c13= CAST('1991-01-01 01:01:01' as datetime) and where c1= 20 and c13= CAST('1991-01-01 00:00:00' as datetime) and
c14= CAST('1991-01-01 01:01:01' as datetime) and c14= CAST('1991-01-01 01:01:01' as datetime) and
c15= CAST('1991-01-01 01:01:01' as datetime) and c15= CAST('1991-01-01 01:01:01' as datetime) and
c16= CAST('1991-01-01 01:01:01' as datetime) and c16= CAST('1991-01-01 01:01:01' as datetime) and
......
...@@ -3054,7 +3054,7 @@ found ...@@ -3054,7 +3054,7 @@ found
true true
set @arg00= CAST('1991-01-01 01:01:01' as datetime) ; set @arg00= CAST('1991-01-01 01:01:01' as datetime) ;
select 'true' as found from t9 select 'true' as found from t9
where c1= 20 and c13= CAST('1991-01-01 01:01:01' as datetime) and where c1= 20 and c13= CAST('1991-01-01 00:00:00' as datetime) and
c14= CAST('1991-01-01 01:01:01' as datetime) and c14= CAST('1991-01-01 01:01:01' as datetime) and
c15= CAST('1991-01-01 01:01:01' as datetime) and c15= CAST('1991-01-01 01:01:01' as datetime) and
c16= CAST('1991-01-01 01:01:01' as datetime) and c16= CAST('1991-01-01 01:01:01' as datetime) and
...@@ -3067,7 +3067,7 @@ and c17= @arg00 ; ...@@ -3067,7 +3067,7 @@ and c17= @arg00 ;
found found
true true
prepare stmt1 from "select 'true' as found from t9 prepare stmt1 from "select 'true' as found from t9
where c1= 20 and c13= CAST('1991-01-01 01:01:01' as datetime) and where c1= 20 and c13= CAST('1991-01-01 00:00:00' as datetime) and
c14= CAST('1991-01-01 01:01:01' as datetime) and c14= CAST('1991-01-01 01:01:01' as datetime) and
c15= CAST('1991-01-01 01:01:01' as datetime) and c15= CAST('1991-01-01 01:01:01' as datetime) and
c16= CAST('1991-01-01 01:01:01' as datetime) and c16= CAST('1991-01-01 01:01:01' as datetime) and
......
...@@ -2990,7 +2990,7 @@ found ...@@ -2990,7 +2990,7 @@ found
true true
set @arg00= CAST('1991-01-01 01:01:01' as datetime) ; set @arg00= CAST('1991-01-01 01:01:01' as datetime) ;
select 'true' as found from t9 select 'true' as found from t9
where c1= 20 and c13= CAST('1991-01-01 01:01:01' as datetime) and where c1= 20 and c13= CAST('1991-01-01 00:00:00' as datetime) and
c14= CAST('1991-01-01 01:01:01' as datetime) and c14= CAST('1991-01-01 01:01:01' as datetime) and
c15= CAST('1991-01-01 01:01:01' as datetime) and c15= CAST('1991-01-01 01:01:01' as datetime) and
c16= CAST('1991-01-01 01:01:01' as datetime) and c16= CAST('1991-01-01 01:01:01' as datetime) and
...@@ -3003,7 +3003,7 @@ and c17= @arg00 ; ...@@ -3003,7 +3003,7 @@ and c17= @arg00 ;
found found
true true
prepare stmt1 from "select 'true' as found from t9 prepare stmt1 from "select 'true' as found from t9
where c1= 20 and c13= CAST('1991-01-01 01:01:01' as datetime) and where c1= 20 and c13= CAST('1991-01-01 00:00:00' as datetime) and
c14= CAST('1991-01-01 01:01:01' as datetime) and c14= CAST('1991-01-01 01:01:01' as datetime) and
c15= CAST('1991-01-01 01:01:01' as datetime) and c15= CAST('1991-01-01 01:01:01' as datetime) and
c16= CAST('1991-01-01 01:01:01' as datetime) and c16= CAST('1991-01-01 01:01:01' as datetime) and
...@@ -6004,7 +6004,7 @@ found ...@@ -6004,7 +6004,7 @@ found
true true
set @arg00= CAST('1991-01-01 01:01:01' as datetime) ; set @arg00= CAST('1991-01-01 01:01:01' as datetime) ;
select 'true' as found from t9 select 'true' as found from t9
where c1= 20 and c13= CAST('1991-01-01 01:01:01' as datetime) and where c1= 20 and c13= CAST('1991-01-01 00:00:00' as datetime) and
c14= CAST('1991-01-01 01:01:01' as datetime) and c14= CAST('1991-01-01 01:01:01' as datetime) and
c15= CAST('1991-01-01 01:01:01' as datetime) and c15= CAST('1991-01-01 01:01:01' as datetime) and
c16= CAST('1991-01-01 01:01:01' as datetime) and c16= CAST('1991-01-01 01:01:01' as datetime) and
...@@ -6017,7 +6017,7 @@ and c17= @arg00 ; ...@@ -6017,7 +6017,7 @@ and c17= @arg00 ;
found found
true true
prepare stmt1 from "select 'true' as found from t9 prepare stmt1 from "select 'true' as found from t9
where c1= 20 and c13= CAST('1991-01-01 01:01:01' as datetime) and where c1= 20 and c13= CAST('1991-01-01 00:00:00' as datetime) and
c14= CAST('1991-01-01 01:01:01' as datetime) and c14= CAST('1991-01-01 01:01:01' as datetime) and
c15= CAST('1991-01-01 01:01:01' as datetime) and c15= CAST('1991-01-01 01:01:01' as datetime) and
c16= CAST('1991-01-01 01:01:01' as datetime) and c16= CAST('1991-01-01 01:01:01' as datetime) and
......
...@@ -394,13 +394,13 @@ EXPLAIN EXTENDED SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'; ...@@ -394,13 +394,13 @@ EXPLAIN EXTENDED SELECT DISTINCT date FROM t1 WHERE date='2002-08-03';
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 43 NULL 2 Using where; Using index 1 SIMPLE t1 index NULL PRIMARY 43 NULL 2 Using where; Using index
Warnings: Warnings:
Note 1003 select distinct `test`.`t1`.`date` AS `date` from `test`.`t1` where (`test`.`t1`.`date` = 20020803) Note 1003 select distinct `test`.`t1`.`date` AS `date` from `test`.`t1` where (`test`.`t1`.`date` = _latin1'2002-08-03')
EXPLAIN EXTENDED SELECT (SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'); EXPLAIN EXTENDED SELECT (SELECT DISTINCT date FROM t1 WHERE date='2002-08-03');
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
2 SUBQUERY t1 index NULL PRIMARY 43 NULL 2 Using where; Using index 2 SUBQUERY t1 index NULL PRIMARY 43 NULL 2 Using where; Using index
Warnings: Warnings:
Note 1003 select (select distinct `test`.`t1`.`date` AS `date` from `test`.`t1` where (`test`.`t1`.`date` = 20020803)) AS `(SELECT DISTINCT date FROM t1 WHERE date='2002-08-03')` Note 1003 select (select distinct `test`.`t1`.`date` AS `date` from `test`.`t1` where (`test`.`t1`.`date` = _latin1'2002-08-03')) AS `(SELECT DISTINCT date FROM t1 WHERE date='2002-08-03')`
SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'; SELECT DISTINCT date FROM t1 WHERE date='2002-08-03';
date date
2002-08-03 2002-08-03
......
...@@ -192,3 +192,42 @@ CAST(CAST('2006-08-10 10:11:12' AS DATETIME) + INTERVAL 14 MICROSECOND AS DECIMA ...@@ -192,3 +192,42 @@ CAST(CAST('2006-08-10 10:11:12' AS DATETIME) + INTERVAL 14 MICROSECOND AS DECIMA
SELECT CAST(CAST('10:11:12.098700' AS TIME) AS DECIMAL(20,6)); 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)) CAST(CAST('10:11:12.098700' AS TIME) AS DECIMAL(20,6))
101112.098700 101112.098700
create table t1 (f1 date, f2 datetime, f3 timestamp);
insert into t1(f1) values(curdate());
select curdate() < now(), f1 < now(), cast(f1 as date) < now() from t1;
curdate() < now() f1 < now() cast(f1 as date) < now()
1 1 1
delete from t1;
insert into t1 values('2001-01-01','2001-01-01 01:01:01','2001-01-01 01:01:01');
insert into t1 values('2001-02-05','2001-02-05 00:00:00','2001-02-05 01:01:01');
insert into t1 values('2001-03-10','2001-03-09 01:01:01','2001-03-10 01:01:01');
insert into t1 values('2001-04-15','2001-04-15 00:00:00','2001-04-15 00:00:00');
insert into t1 values('2001-05-20','2001-05-20 01:01:01','2001-05-20 01:01:01');
select f1, f3 from t1 where f1 >= '2001-02-05 00:00:00' and f3 <= '2001-04-15';
f1 f3
2001-02-05 2001-02-05 01:01:01
2001-03-10 2001-03-10 01:01:01
2001-04-15 2001-04-15 00:00:00
select f1, f3 from t1 where f1 >= '2001-2-5 0:0:0' and f2 <= '2001-4-15';
f1 f3
2001-02-05 2001-02-05 01:01:01
2001-03-10 2001-03-10 01:01:01
2001-04-15 2001-04-15 00:00:00
select f1, f2 from t1 where if(1, f1, 0) >= f2;
f1 f2
2001-02-05 2001-02-05 00:00:00
2001-03-10 2001-03-09 01:01:01
2001-04-15 2001-04-15 00:00:00
select 1 from dual where cast('2001-1-1 2:3:4' as date) = cast('2001-01-01' as datetime);
1
1
select f1, f2, UNIX_TIMESTAMP(f2), UNIX_TIMESTAMP(f1),
f1 > f2, f1 = f2, f1 < f2
from t1;
f1 f2 UNIX_TIMESTAMP(f2) UNIX_TIMESTAMP(f1) f1 > f2 f1 = f2 f1 < f2
2001-01-01 2001-01-01 01:01:01 978300061 978296400 0 0 1
2001-02-05 2001-02-05 00:00:00 981320400 981320400 0 1 0
2001-03-10 2001-03-09 01:01:01 984088861 984171600 1 0 0
2001-04-15 2001-04-15 00:00:00 987282000 987282000 0 1 0
2001-05-20 2001-05-20 01:01:01 990309661 990306000 0 0 1
drop table t1;
-- source include/not_embedded.inc
-- source include/have_bdb.inc
#
# Bug #16206: Superfluous COMMIT event in binlog when updating BDB in autocommit mode
#
set autocommit=1;
let $VERSION=`select version()`;
reset master;
create table bug16206 (a int);
insert into bug16206 values(1);
start transaction;
insert into bug16206 values(2);
commit;
--replace_result $VERSION VERSION
--replace_column 1 f 2 n 5 n
show binlog events;
drop table bug16206;
reset master;
create table bug16206 (a int) engine= bdb;
insert into bug16206 values(0);
insert into bug16206 values(1);
start transaction;
insert into bug16206 values(2);
commit;
insert into bug16206 values(3);
--replace_result $VERSION VERSION
--replace_column 1 f 2 n 5 n
show binlog events;
drop table bug16206;
set autocommit=0;
--echo End of 5.0 tests
...@@ -141,3 +141,23 @@ SELECT CAST(CAST('2006-08-10 10:11:12' AS DATETIME) AS DECIMAL(20,6)); ...@@ -141,3 +141,23 @@ 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('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)); SELECT CAST(CAST('10:11:12.098700' AS TIME) AS DECIMAL(20,6));
#
# Bug#27590: Wrong DATE/DATETIME comparison.
#
create table t1 (f1 date, f2 datetime, f3 timestamp);
insert into t1(f1) values(curdate());
select curdate() < now(), f1 < now(), cast(f1 as date) < now() from t1;
delete from t1;
insert into t1 values('2001-01-01','2001-01-01 01:01:01','2001-01-01 01:01:01');
insert into t1 values('2001-02-05','2001-02-05 00:00:00','2001-02-05 01:01:01');
insert into t1 values('2001-03-10','2001-03-09 01:01:01','2001-03-10 01:01:01');
insert into t1 values('2001-04-15','2001-04-15 00:00:00','2001-04-15 00:00:00');
insert into t1 values('2001-05-20','2001-05-20 01:01:01','2001-05-20 01:01:01');
select f1, f3 from t1 where f1 >= '2001-02-05 00:00:00' and f3 <= '2001-04-15';
select f1, f3 from t1 where f1 >= '2001-2-5 0:0:0' and f2 <= '2001-4-15';
select f1, f2 from t1 where if(1, f1, 0) >= f2;
select 1 from dual where cast('2001-1-1 2:3:4' as date) = cast('2001-01-01' as datetime);
select f1, f2, UNIX_TIMESTAMP(f2), UNIX_TIMESTAMP(f1),
f1 > f2, f1 = f2, f1 < f2
from t1;
drop table t1;
...@@ -4166,6 +4166,21 @@ enum_field_types Item::field_type() const ...@@ -4166,6 +4166,21 @@ enum_field_types Item::field_type() const
} }
bool Item::is_datetime()
{
switch (field_type())
{
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
return TRUE;
default:
break;
}
return FALSE;
}
/* /*
Create a field to hold a string value from an item Create a field to hold a string value from an item
...@@ -6123,6 +6138,14 @@ void Item_cache_int::store(Item *item) ...@@ -6123,6 +6138,14 @@ void Item_cache_int::store(Item *item)
} }
void Item_cache_int::store(Item *item, longlong val_arg)
{
value= val_arg;
null_value= item->null_value;
unsigned_flag= item->unsigned_flag;
}
String *Item_cache_int::val_str(String *str) String *Item_cache_int::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
......
...@@ -847,6 +847,7 @@ public: ...@@ -847,6 +847,7 @@ public:
representation is more precise than the string one). representation is more precise than the string one).
*/ */
virtual bool result_as_longlong() { return FALSE; } virtual bool result_as_longlong() { return FALSE; }
bool is_datetime();
}; };
...@@ -2406,11 +2407,13 @@ public: ...@@ -2406,11 +2407,13 @@ public:
Item_cache_int(): Item_cache(), value(0) {} Item_cache_int(): Item_cache(), value(0) {}
void store(Item *item); void store(Item *item);
void store(Item *item, longlong val_arg);
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);
my_decimal *val_decimal(my_decimal *); my_decimal *val_decimal(my_decimal *);
enum Item_result result_type() const { return INT_RESULT; } enum Item_result result_type() const { return INT_RESULT; }
bool result_as_longlong() { return TRUE; }
}; };
......
This diff is collapsed.
...@@ -35,12 +35,19 @@ class Arg_comparator: public Sql_alloc ...@@ -35,12 +35,19 @@ class Arg_comparator: public Sql_alloc
Item_bool_func2 *owner; Item_bool_func2 *owner;
Arg_comparator *comparators; // used only for compare_row() Arg_comparator *comparators; // used only for compare_row()
double precision; double precision;
/* Fields used in DATE/DATETIME comparison. */
THD *thd;
enum_field_types a_type, b_type; // Types of a and b items
Item *a_cache, *b_cache; // Cached values of a and b items
bool is_nulls_eq; // TRUE <=> compare for the EQUAL_FUNC
enum enum_date_cmp_type { CMP_DATE_DFLT= 0, CMP_DATE_WITH_DATE,
CMP_DATE_WITH_STR, CMP_STR_WITH_DATE };
public: public:
DTCollation cmp_collation; DTCollation cmp_collation;
Arg_comparator() {}; Arg_comparator(): thd(0), a_cache(0), b_cache(0) {};
Arg_comparator(Item **a1, Item **a2): a(a1), b(a2) {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), thd(0),
a_cache(0), b_cache(0) {};
int set_compare_func(Item_bool_func2 *owner, Item_result type); int set_compare_func(Item_bool_func2 *owner, Item_result type);
inline int set_compare_func(Item_bool_func2 *owner_arg) inline int set_compare_func(Item_bool_func2 *owner_arg)
...@@ -48,14 +55,10 @@ public: ...@@ -48,14 +55,10 @@ public:
return set_compare_func(owner_arg, item_cmp_type((*a)->result_type(), return set_compare_func(owner_arg, item_cmp_type((*a)->result_type(),
(*b)->result_type())); (*b)->result_type()));
} }
inline int set_cmp_func(Item_bool_func2 *owner_arg, int set_cmp_func(Item_bool_func2 *owner_arg,
Item **a1, Item **a2, Item **a1, Item **a2,
Item_result type) Item_result type);
{
a= a1;
b= a2;
return set_compare_func(owner_arg, type);
}
inline int set_cmp_func(Item_bool_func2 *owner_arg, inline int set_cmp_func(Item_bool_func2 *owner_arg,
Item **a1, Item **a2) Item **a1, Item **a2)
{ {
...@@ -83,6 +86,10 @@ public: ...@@ -83,6 +86,10 @@ public:
int compare_e_row(); // compare args[0] & args[1] int compare_e_row(); // compare args[0] & args[1]
int compare_real_fixed(); int compare_real_fixed();
int compare_e_real_fixed(); int compare_e_real_fixed();
int compare_datetime(); // compare args[0] & args[1] as DATETIMEs
static enum enum_date_cmp_type can_compare_as_dates(Item *a, Item *b,
ulonglong *const_val_arg);
static arg_cmp_func comparator_matrix [5][2]; static arg_cmp_func comparator_matrix [5][2];
......
...@@ -8621,17 +8621,13 @@ static bool ...@@ -8621,17 +8621,13 @@ static bool
test_if_equality_guarantees_uniqueness(Item *l, Item *r) test_if_equality_guarantees_uniqueness(Item *l, Item *r)
{ {
return r->const_item() && return r->const_item() &&
/* elements must be of the same result type */ /* elements must be compared as dates */
(r->result_type() == l->result_type() || (Arg_comparator::can_compare_as_dates(l, r, 0) ||
/* or dates compared to longs */ /* or of the same result type */
(((l->type() == Item::FIELD_ITEM && (r->result_type() == l->result_type() &&
((Item_field *)l)->field->can_be_compared_as_longlong()) || /* and must have the same collation if compared as strings */
(l->type() == Item::FUNC_ITEM && (l->result_type() != STRING_RESULT ||
((Item_func *)l)->result_as_longlong())) && l->collation.collation == r->collation.collation)));
r->result_type() == INT_RESULT))
/* and must have the same collation if compared as strings */
&& (l->result_type() != STRING_RESULT ||
l->collation.collation == r->collation.collation);
} }
/* /*
......
...@@ -8852,12 +8852,14 @@ static void test_ts() ...@@ -8852,12 +8852,14 @@ static void test_ts()
mysql_free_result(prep_res); mysql_free_result(prep_res);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
char queries [3][60]= {"SELECT a, b, c FROM test_ts WHERE %c=?",
"SELECT a, b, c FROM test_ts WHERE %c=?",
"SELECT a, b, c FROM test_ts WHERE %c=CAST(? AS DATE)"};
for (name= 'a'; field_count--; name++) for (name= 'a'; field_count--; name++)
{ {
int row_count= 0; int row_count= 0;
sprintf(query, "SELECT a, b, c FROM test_ts WHERE %c=?", name); sprintf(query, queries[field_count], name);
if (!opt_silent) if (!opt_silent)
fprintf(stdout, "\n %s", query); fprintf(stdout, "\n %s", query);
......
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