diff --git a/mysql-test/main/rowid_filter_innodb.result b/mysql-test/main/rowid_filter_innodb.result index 276b57a106c..24b80881c6e 100644 --- a/mysql-test/main/rowid_filter_innodb.result +++ b/mysql-test/main/rowid_filter_innodb.result @@ -2917,7 +2917,7 @@ ORDER BY timestamp DESC; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL ixEventWhoisDomainDomain,ixEventWhoisDomainTimestamp NULL NULL NULL 60 22.22 Using where; Using filesort Warnings: -Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`domain` AS `domain`,`test`.`t1`.`registrant_name` AS `registrant_name`,`test`.`t1`.`registrant_organization` AS `registrant_organization`,`test`.`t1`.`registrant_street1` AS `registrant_street1`,`test`.`t1`.`registrant_street2` AS `registrant_street2`,`test`.`t1`.`registrant_street3` AS `registrant_street3`,`test`.`t1`.`registrant_street4` AS `registrant_street4`,`test`.`t1`.`registrant_street5` AS `registrant_street5`,`test`.`t1`.`registrant_city` AS `registrant_city`,`test`.`t1`.`registrant_postal_code` AS `registrant_postal_code`,`test`.`t1`.`registrant_country` AS `registrant_country`,`test`.`t1`.`registrant_email` AS `registrant_email`,`test`.`t1`.`registrant_telephone` AS `registrant_telephone`,`test`.`t1`.`administrative_name` AS `administrative_name`,`test`.`t1`.`administrative_organization` AS `administrative_organization`,`test`.`t1`.`administrative_street1` AS `administrative_street1`,`test`.`t1`.`administrative_street2` AS `administrative_street2`,`test`.`t1`.`administrative_street3` AS `administrative_street3`,`test`.`t1`.`administrative_street4` AS `administrative_street4`,`test`.`t1`.`administrative_street5` AS `administrative_street5`,`test`.`t1`.`administrative_city` AS `administrative_city`,`test`.`t1`.`administrative_postal_code` AS `administrative_postal_code`,`test`.`t1`.`administrative_country` AS `administrative_country`,`test`.`t1`.`administrative_email` AS `administrative_email`,`test`.`t1`.`administrative_telephone` AS `administrative_telephone`,`test`.`t1`.`technical_name` AS `technical_name`,`test`.`t1`.`technical_organization` AS `technical_organization`,`test`.`t1`.`technical_street1` AS `technical_street1`,`test`.`t1`.`technical_street2` AS `technical_street2`,`test`.`t1`.`technical_street3` AS `technical_street3`,`test`.`t1`.`technical_street4` AS `technical_street4`,`test`.`t1`.`technical_street5` AS `technical_street5`,`test`.`t1`.`technical_city` AS `technical_city`,`test`.`t1`.`technical_postal_code` AS `technical_postal_code`,`test`.`t1`.`technical_country` AS `technical_country`,`test`.`t1`.`technical_email` AS `technical_email`,`test`.`t1`.`technical_telephone` AS `technical_telephone`,`test`.`t1`.`json` AS `json`,`test`.`t1`.`timestamp` AS `timestamp` from `test`.`t1` where `test`.`t1`.`domain` = 'www.mailhost.i-dev.fr' and `test`.`t1`.`timestamp` >= ('2017-01-30 08:24:51' + interval -1 month) order by `test`.`t1`.`timestamp` desc +Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`domain` AS `domain`,`test`.`t1`.`registrant_name` AS `registrant_name`,`test`.`t1`.`registrant_organization` AS `registrant_organization`,`test`.`t1`.`registrant_street1` AS `registrant_street1`,`test`.`t1`.`registrant_street2` AS `registrant_street2`,`test`.`t1`.`registrant_street3` AS `registrant_street3`,`test`.`t1`.`registrant_street4` AS `registrant_street4`,`test`.`t1`.`registrant_street5` AS `registrant_street5`,`test`.`t1`.`registrant_city` AS `registrant_city`,`test`.`t1`.`registrant_postal_code` AS `registrant_postal_code`,`test`.`t1`.`registrant_country` AS `registrant_country`,`test`.`t1`.`registrant_email` AS `registrant_email`,`test`.`t1`.`registrant_telephone` AS `registrant_telephone`,`test`.`t1`.`administrative_name` AS `administrative_name`,`test`.`t1`.`administrative_organization` AS `administrative_organization`,`test`.`t1`.`administrative_street1` AS `administrative_street1`,`test`.`t1`.`administrative_street2` AS `administrative_street2`,`test`.`t1`.`administrative_street3` AS `administrative_street3`,`test`.`t1`.`administrative_street4` AS `administrative_street4`,`test`.`t1`.`administrative_street5` AS `administrative_street5`,`test`.`t1`.`administrative_city` AS `administrative_city`,`test`.`t1`.`administrative_postal_code` AS `administrative_postal_code`,`test`.`t1`.`administrative_country` AS `administrative_country`,`test`.`t1`.`administrative_email` AS `administrative_email`,`test`.`t1`.`administrative_telephone` AS `administrative_telephone`,`test`.`t1`.`technical_name` AS `technical_name`,`test`.`t1`.`technical_organization` AS `technical_organization`,`test`.`t1`.`technical_street1` AS `technical_street1`,`test`.`t1`.`technical_street2` AS `technical_street2`,`test`.`t1`.`technical_street3` AS `technical_street3`,`test`.`t1`.`technical_street4` AS `technical_street4`,`test`.`t1`.`technical_street5` AS `technical_street5`,`test`.`t1`.`technical_city` AS `technical_city`,`test`.`t1`.`technical_postal_code` AS `technical_postal_code`,`test`.`t1`.`technical_country` AS `technical_country`,`test`.`t1`.`technical_email` AS `technical_email`,`test`.`t1`.`technical_telephone` AS `technical_telephone`,`test`.`t1`.`json` AS `json`,`test`.`t1`.`timestamp` AS `timestamp` from `test`.`t1` where `test`.`t1`.`domain` = 'www.mailhost.i-dev.fr' and `test`.`t1`.`timestamp` >= TIMESTAMP/*WITH LOCAL TIME ZONE*/'2016-12-30 08:24:51' order by `test`.`t1`.`timestamp` desc SET optimizer_switch=@save_optimizer_switch; DROP TABLE t1; # diff --git a/mysql-test/main/timezone2.result b/mysql-test/main/timezone2.result index 787552d9159..382ed447c92 100644 --- a/mysql-test/main/timezone2.result +++ b/mysql-test/main/timezone2.result @@ -678,3 +678,188 @@ SELECT a, UNIX_TIMESTAMP(a) FROM t1 WHERE a >= ALL (SELECT * FROM t1); a UNIX_TIMESTAMP(a) 2010-10-31 02:25:25 1288481125 DROP TABLE t1; +# +# MDEV-32148 Inefficient WHERE timestamp_column=datetime_expr +# +# +# Testing a DST change (fall back) +# +SET time_zone='Europe/Moscow'; +SET @first_second_after_dst_fall_back=1288479600; +CREATE TABLE t1 (a TIMESTAMP NULL); +INSERT INTO t1 VALUES ('2001-01-01 10:20:30'),('2001-01-01 10:20:31'); +# +# Optimized (more than 24 hours before the DST fall back) +# +SET timestamp=@first_second_after_dst_fall_back-24*3600-1; +SELECT UNIX_TIMESTAMP(), NOW(); +UNIX_TIMESTAMP() NOW() +1288393199 2010-10-30 02:59:59 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2010-10-30 02:59:59' +# +# Not optimized (24 hours before the DST fall back) +# +SET timestamp=@first_second_after_dst_fall_back-24*3600; +SELECT UNIX_TIMESTAMP(), NOW(); +UNIX_TIMESTAMP() NOW() +1288393200 2010-10-30 03:00:00 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (current_timestamp()) +# +# Not optimized (less than 24 hours after the DST fall back) +# +SET timestamp=@first_second_after_dst_fall_back+24*3600-1; +SELECT UNIX_TIMESTAMP(), NOW(); +UNIX_TIMESTAMP() NOW() +1288565999 2010-11-01 01:59:59 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (current_timestamp()) +# +# Optimized (24 hours after the DST fall back) +# +SET timestamp=@first_second_after_dst_fall_back+24*3600; +SELECT UNIX_TIMESTAMP(), NOW(); +UNIX_TIMESTAMP() NOW() +1288566000 2010-11-01 02:00:00 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2010-11-01 02:00:00' +DROP TABLE t1; +SET time_zone=DEFAULT; +# +# Testing a DST change (spring forward) +# +SET time_zone='Europe/Moscow'; +SET @first_second_after_dst_spring_forward=1301180400; +CREATE TABLE t1 (a TIMESTAMP NULL); +INSERT INTO t1 VALUES ('2001-01-01 10:20:30'),('2001-01-01 10:20:31'); +# +# Optimized (more than 24 hours before the DST sprint forward) +# +SET timestamp=@first_second_after_dst_spring_forward-24*3600-1; +SELECT UNIX_TIMESTAMP(), NOW(); +UNIX_TIMESTAMP() NOW() +1301093999 2011-03-26 01:59:59 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2011-03-26 01:59:59' +# +# Not optimized (24 hours before the DST sprint forward) +# +SET timestamp=@first_second_after_dst_spring_forward-24*3600; +SELECT UNIX_TIMESTAMP(), NOW(); +UNIX_TIMESTAMP() NOW() +1301094000 2011-03-26 02:00:00 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (current_timestamp()) +# +# Not optimized (less than 24 hours after the DST sprint forward) +# +SET timestamp=@first_second_after_dst_spring_forward+24*3600-1; +SELECT UNIX_TIMESTAMP(), NOW(); +UNIX_TIMESTAMP() NOW() +1301266799 2011-03-28 02:59:59 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (current_timestamp()) +# +# Optimized (24 hours after the DST sprint forward) +# +SET timestamp=@first_second_after_dst_spring_forward+24*3600; +SELECT UNIX_TIMESTAMP(), NOW(); +UNIX_TIMESTAMP() NOW() +1301266800 2011-03-28 03:00:00 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2011-03-28 03:00:00' +DROP TABLE t1; +# +# Testing a leap second +# +SET time_zone='leap/Europe/Moscow'; +SET @leap_second=362793609; +/*The 60th leap second*/ +CREATE TABLE t1 (a TIMESTAMP); +SET timestamp=@leap_second-1; +INSERT INTO t1 VALUES (NOW()); +SET timestamp=@leap_second; +INSERT INTO t1 VALUES (NOW()); +SET timestamp=@leap_second+1; +INSERT INTO t1 VALUES (NOW()); +SELECT UNIX_TIMESTAMP(a), a FROM t1 ORDER BY UNIX_TIMESTAMP(a); +UNIX_TIMESTAMP(a) a +362793608 1981-07-01 03:59:59 +362793609 1981-07-01 03:59:59 +362793610 1981-07-01 04:00:00 +INSERT INTO t1 VALUES ('2001-01-01 10:20:30'); +# +# Optimized (more than 24 hours before the leap second) +# +SET timestamp=@leap_second-24*3600-1; +SELECT UNIX_TIMESTAMP(), NOW(); +UNIX_TIMESTAMP() NOW() +362707208 1981-06-30 03:59:59 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'1981-06-30 03:59:59' +# +# Not optimized (24 hours before the leap second) +# +SET timestamp=@leap_second-24*3600; +SELECT UNIX_TIMESTAMP(), NOW(); +UNIX_TIMESTAMP() NOW() +362707209 1981-06-30 04:00:00 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (current_timestamp()) +# +# Not optimized (less than 24 hours after the leap second) +# +SET timestamp=@leap_second+24*3600-1; +SELECT UNIX_TIMESTAMP(), NOW(); +UNIX_TIMESTAMP() NOW() +362880008 1981-07-02 03:59:58 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (current_timestamp()) +# +# Not optimized (24 hours after the leap second) +# +SET timestamp=@leap_second+24*3600; +SELECT UNIX_TIMESTAMP(), NOW(); +UNIX_TIMESTAMP() NOW() +362880009 1981-07-02 03:59:59 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'1981-07-02 03:59:59' +DROP TABLE t1; +SET time_zone=DEFAULT; diff --git a/mysql-test/main/timezone2.test b/mysql-test/main/timezone2.test index b5045203903..09be74089ce 100644 --- a/mysql-test/main/timezone2.test +++ b/mysql-test/main/timezone2.test @@ -630,3 +630,155 @@ SELECT a, UNIX_TIMESTAMP(a) FROM t1 ORDER BY a; SELECT a, UNIX_TIMESTAMP(a) FROM t1 WHERE a <= ALL (SELECT * FROM t1); SELECT a, UNIX_TIMESTAMP(a) FROM t1 WHERE a >= ALL (SELECT * FROM t1); DROP TABLE t1; + + +--echo # +--echo # MDEV-32148 Inefficient WHERE timestamp_column=datetime_expr +--echo # + +--echo # +--echo # Testing a DST change (fall back) +--echo # + +SET time_zone='Europe/Moscow'; +# '2010-10-31 02:59:59' (1288479599) +# '2010-10-31 02:00:00' (1288479600) +SET @first_second_after_dst_fall_back=1288479600; + +CREATE TABLE t1 (a TIMESTAMP NULL); +INSERT INTO t1 VALUES ('2001-01-01 10:20:30'),('2001-01-01 10:20:31'); + +--echo # +--echo # Optimized (more than 24 hours before the DST fall back) +--echo # + +SET timestamp=@first_second_after_dst_fall_back-24*3600-1; +SELECT UNIX_TIMESTAMP(), NOW(); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); + +--echo # +--echo # Not optimized (24 hours before the DST fall back) +--echo # + +SET timestamp=@first_second_after_dst_fall_back-24*3600; +SELECT UNIX_TIMESTAMP(), NOW(); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); + +--echo # +--echo # Not optimized (less than 24 hours after the DST fall back) +--echo # + +SET timestamp=@first_second_after_dst_fall_back+24*3600-1; +SELECT UNIX_TIMESTAMP(), NOW(); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); + +--echo # +--echo # Optimized (24 hours after the DST fall back) +--echo # + +SET timestamp=@first_second_after_dst_fall_back+24*3600; +SELECT UNIX_TIMESTAMP(), NOW(); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); + +DROP TABLE t1; +SET time_zone=DEFAULT; + + +--echo # +--echo # Testing a DST change (spring forward) +--echo # + +SET time_zone='Europe/Moscow'; +# '2011-03-27 01:59:59' (1301180399) +# '2011-03-27 03:00:00' (1301180400) +SET @first_second_after_dst_spring_forward=1301180400; + +CREATE TABLE t1 (a TIMESTAMP NULL); +INSERT INTO t1 VALUES ('2001-01-01 10:20:30'),('2001-01-01 10:20:31'); + +--echo # +--echo # Optimized (more than 24 hours before the DST sprint forward) +--echo # + +SET timestamp=@first_second_after_dst_spring_forward-24*3600-1; +SELECT UNIX_TIMESTAMP(), NOW(); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); + +--echo # +--echo # Not optimized (24 hours before the DST sprint forward) +--echo # + +SET timestamp=@first_second_after_dst_spring_forward-24*3600; +SELECT UNIX_TIMESTAMP(), NOW(); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); + +--echo # +--echo # Not optimized (less than 24 hours after the DST sprint forward) +--echo # + +SET timestamp=@first_second_after_dst_spring_forward+24*3600-1; +SELECT UNIX_TIMESTAMP(), NOW(); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); + +--echo # +--echo # Optimized (24 hours after the DST sprint forward) +--echo # + +SET timestamp=@first_second_after_dst_spring_forward+24*3600; +SELECT UNIX_TIMESTAMP(), NOW(); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); + +DROP TABLE t1; + +--echo # +--echo # Testing a leap second +--echo # + +SET time_zone='leap/Europe/Moscow'; +SET @leap_second=362793609; /*The 60th leap second*/ + +CREATE TABLE t1 (a TIMESTAMP); +SET timestamp=@leap_second-1; +INSERT INTO t1 VALUES (NOW()); +SET timestamp=@leap_second; +INSERT INTO t1 VALUES (NOW()); +SET timestamp=@leap_second+1; +INSERT INTO t1 VALUES (NOW()); +SELECT UNIX_TIMESTAMP(a), a FROM t1 ORDER BY UNIX_TIMESTAMP(a); +INSERT INTO t1 VALUES ('2001-01-01 10:20:30'); + +--echo # +--echo # Optimized (more than 24 hours before the leap second) +--echo # + +SET timestamp=@leap_second-24*3600-1; +SELECT UNIX_TIMESTAMP(), NOW(); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); + +--echo # +--echo # Not optimized (24 hours before the leap second) +--echo # + +SET timestamp=@leap_second-24*3600; +SELECT UNIX_TIMESTAMP(), NOW(); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); + +--echo # +--echo # Not optimized (less than 24 hours after the leap second) +--echo # + +SET timestamp=@leap_second+24*3600-1; +SELECT UNIX_TIMESTAMP(), NOW(); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); + +--echo # +--echo # Not optimized (24 hours after the leap second) +--echo # + +SET timestamp=@leap_second+24*3600; +SELECT UNIX_TIMESTAMP(), NOW(); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now(); + +DROP TABLE t1; + +SET time_zone=DEFAULT; diff --git a/mysql-test/main/type_timestamp.result b/mysql-test/main/type_timestamp.result index 78e860661c5..6b1e5bb8284 100644 --- a/mysql-test/main/type_timestamp.result +++ b/mysql-test/main/type_timestamp.result @@ -872,13 +872,13 @@ SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=' 2001-01-01 00:00:00'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00' EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=' 2001-01-01 00:00:00'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and (octet_length(TIMESTAMP'2001-01-01 00:00:00')) = 19 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00' and (octet_length(TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00')) = 19 + rand() EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=' garbage '; id select_type table type possible_keys key key_len ref rows filtered Extra @@ -905,13 +905,13 @@ SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=TIMESTAMP'2001-01-01 00:00:00.000000'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000' +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00.000000' EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIMESTAMP'2001-01-01 00:00:00.000000'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000' and (octet_length(TIMESTAMP'2001-01-01 00:00:00')) = 30 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00.000000' and (octet_length(TIMESTAMP'2001-01-01 00:00:00')) = 30 + rand() DROP TABLE t1; CREATE TABLE t1 (a TIMESTAMP(6));; INSERT INTO t1 VALUES ('2001-01-01 00:00:00.000000'),('2001-01-01 00:00:01.000000'); @@ -930,13 +930,13 @@ SELECT * FROM t1 WHERE LENGTH(a)=26 AND a=TIMESTAMP'2001-01-01 00:00:00.000000'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000' +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00.000000' EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=40+RAND() AND a=TIMESTAMP'2001-01-01 00:00:00.000000'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000' and (octet_length(TIMESTAMP'2001-01-01 00:00:00.000000')) = 40 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00.000000' and (octet_length(TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00.000000')) = 40 + rand() DROP TABLE t1; SET timestamp=UNIX_TIMESTAMP('2001-01-01 10:20:30'); CREATE TABLE t1 (a TIMESTAMP);; @@ -956,13 +956,13 @@ SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=TIME'00:00:00'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00' EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=40+RAND() AND a=TIME'00:00:00'; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and (octet_length(TIMESTAMP'2001-01-01 00:00:00')) = 40 + rand() +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00' and (octet_length(TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00')) = 40 + rand() DROP TABLE t1; # # End of 10.1 tests @@ -1347,6 +1347,540 @@ SET time_zone=DEFAULT; # End of 10.4 tests # # +# Start of 10.6 tests +# +# +# MDEV-32148 Inefficient WHERE timestamp_column=datetime_expr +# +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP); +INSERT INTO t1 VALUES ('0000-00-00 00:00:00'); +INSERT INTO t1 VALUES ('2001-01-01 10:20:30'), ('2001-01-01 10:20:31'); +# +# Comparison predicates: Bad TIMESTAMP values preserve DATETIME comparison +# +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1001-01-01 10:20:30'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'1001-01-01 10:20:30' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2001-01-00 00:00:00'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-00 00:00:00' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2040-01-01 10:20:30'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2040-01-01 10:20:30' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='1001-01-01 10:20:30'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'1001-01-01 10:20:30' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-00 00:00:00'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Warning 1292 Incorrect datetime value: '2001-01-00 00:00:00' +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = '2001-01-00 00:00:00' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2040-01-01 10:20:30'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2040-01-01 10:20:30' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10010101102030; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 10010101102030 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010100000000; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 20010100000000 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20400101102030; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 20400101102030 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10010101102030e0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 10010101102030e0 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010100000000e0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 20010100000000e0 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20400101102030e0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 20400101102030e0 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10010101102030.0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 10010101102030.0 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010100000000.0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 20010100000000.0 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20400101102030.0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 20400101102030.0 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=DATE_ADD('2020-01-01 10:20:30', INTERVAL 30 YEAR); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2050-01-01 10:20:30' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE COALESCE(NULL, a)=DATE_ADD('2020-01-01 10:20:30', INTERVAL 30 YEAR); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where coalesce(NULL,`test`.`t1`.`a`) = ('2020-01-01 10:20:30' + interval 30 year) +# +# Comparison predicates: Good TIMESTAMP values switch to TIMESTAMP comparison +# +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'0000-00-00 00:00:00'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2001-01-01 10:20:30'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='0000-00-00 00:00:00'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01 10:20:30'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010101102030; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=0e0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00.000000' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010101102030e0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.000000' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=0.0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00.0' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010101102030.0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.0' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=DATE_ADD('2001-01-01 10:20:00', INTERVAL 30 SECOND); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE COALESCE(NULL, a)=DATE_ADD('2001-01-01 10:20:00', INTERVAL 30 SECOND); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where coalesce(NULL,`test`.`t1`.`a`) = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30' +# +# Corner cases: DATETIME values before the supported optimization range +# FROM_UNIXTIME(0)..FROM_UNIXTIME(24*3600-1) +# +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 00:00:00'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'1970-01-01 00:00:00' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'1970-01-01 23:59:59' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.999999'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'1970-01-01 23:59:59.999999' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.9999999'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1292 Truncated incorrect DATETIME value: '1970-01-01 23:59:59.9999999' +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'1970-01-01 23:59:59.999999' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(24*3600-1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (from_unixtime(24 * 3600 - 1)) +# +# Corner cases: DATETIME values inside the supported optimization range: +# FROM_UNIXTIME(24*3600) .. FROM_UNIXTIME(0x7FFFFFFF-24*3600) +# +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(24*3600); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'1970-01-02 00:00:00' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-02 00:00:00'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'1970-01-02 00:00:00' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:07'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2038-01-18 03:14:07' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(0x7FFFFFFF-24*3600); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2038-01-18 03:14:07' +# +# Corner cases: DATETIME values after the supported optimization range +# FROM_UNIXTIME(0x7FFFFFFF-24*3600+1) .. FROM_UNIXTIME(0x7FFFFFFF) +# +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(0x7FFFFFFF-24*3600+1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (from_unixtime(0x7fffffff - 24 * 3600 + 1)) +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:08'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2038-01-18 03:14:08' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-19 03:14:07'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2038-01-19 03:14:07' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(0x7FFFFFFF); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (from_unixtime(0x7fffffff)) +# +# Corner cases: rounding +# +SET sql_mode=TIME_ROUND_FRACTIONAL; +# +# Not optimized (before the supported range) +# +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.999999'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'1970-01-01 23:59:59.999999' +# +# Optimized +# +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.9999999'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1292 Truncated incorrect DATETIME value: '1970-01-01 23:59:59.9999999' +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'1970-01-02 00:00:00.000000' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:07.999999'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2038-01-18 03:14:07.999999' +# +# Not optimized (after the supported range) +# +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:07.9999999'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1292 Truncated incorrect DATETIME value: '2038-01-18 03:14:07.9999999' +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2038-01-18 03:14:08.000000' +SET sql_mode=DEFAULT; +# +# NULLIF: Bad TIMESTAMP values preserve DATETIME comparison +# +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'1001-01-01 10:20:30'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP'1001-01-01 10:20:30') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'2001-01-00 00:00:00'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP'2001-01-00 00:00:00') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'2040-01-01 10:20:30'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP'2040-01-01 10:20:30') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'1001-01-01 10:20:30'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,'1001-01-01 10:20:30') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'2001-01-00 00:00:00'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,'2001-01-00 00:00:00') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'2040-01-01 10:20:30'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,'2040-01-01 10:20:30') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,10010101102030); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,10010101102030) +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010100000000); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,20010100000000) +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20400101102030); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,20400101102030) +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,10010101102030e0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,10010101102030e0) +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010100000000e0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,20010100000000e0) +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20400101102030e0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,20400101102030e0) +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,10010101102030.0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,10010101102030.0) +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010100000000.0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,20010100000000.0) +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20400101102030.0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,20400101102030.0) +# +# NULLIF: Good TIMESTAMP values switch to TIMESTAMP comparison +# +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'0000-00-00 00:00:00'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'2001-01-01 10:20:30'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'0000-00-00 00:00:00'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'2001-01-01 10:20:30'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010101102030); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,0e0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00.000000') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010101102030e0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.000000') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,0.0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00.0') +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010101102030.0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.0') +# +# Subqueries with bad TIMESTAMP values +# It's not clear from the output if the comparison is done as DATETIME or TIMESTAMP +# +CREATE TABLE t2 (a DATETIME); +INSERT INTO t2 VALUES ('1001-01-01 10:20:30'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where +2 SUBQUERY t2 system NULL NULL NULL NULL 1 100.00 +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (/* select#2 */ select max('1001-01-01 10:20:30') from dual) +DROP TABLE t2; +CREATE TABLE t2 (a DATETIME); +INSERT INTO t2 VALUES ('2001-00-00 00:00:00'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where +2 SUBQUERY t2 system NULL NULL NULL NULL 1 100.00 +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (/* select#2 */ select max('2001-00-00 00:00:00') from dual) +DROP TABLE t2; +CREATE TABLE t2 (a DATETIME); +INSERT INTO t2 VALUES ('2040-01-01 10:20:30'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where +2 SUBQUERY t2 system NULL NULL NULL NULL 1 100.00 +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (/* select#2 */ select max('2040-01-01 10:20:30') from dual) +DROP TABLE t2; +# +# Subqueries with good TIMESTAMP values +# It's not clear from the output if the comparison is done as DATETIME or TIMESTAMP +# +CREATE TABLE t2 (a DATETIME); +INSERT INTO t2 VALUES ('0000-00-00 00:00:00'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where +2 SUBQUERY t2 system NULL NULL NULL NULL 1 100.00 +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (/* select#2 */ select max('0000-00-00 00:00:00') from dual) +DROP TABLE t2; +CREATE TABLE t2 (a DATETIME); +INSERT INTO t2 VALUES ('2001-01-01 10:20:30'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where +2 SUBQUERY t2 system NULL NULL NULL NULL 1 100.00 +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (/* select#2 */ select max('2001-01-01 10:20:30') from dual) +DROP TABLE t2; +# +# Trivial equality elimination +# Covers Type_handler_timestamp_common::Item_const_eq() +# +EXPLAIN EXTENDED SELECT * FROM t1 +WHERE IF(a='2001-01-01 00:00:00',1,0)=IF(a='2001-01-01 00:00:00',1,0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where if(`test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00',1,0) = if(`test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00',1,0) +EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE (a<=>?)=(a<=>?)' + USING '2001-01-01 00:00:00', '2001-01-01 00:00:00'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where 1 +# +# Equal field propagation: Good TIMESTAMP values switch to TIMESTAMP comparison +# +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=TIMESTAMP'2001-01-01 10:20:30'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a='2001-01-01 10:20:30'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=20010101102030; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=20010101102030e0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.000000' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=20010101102030.0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.0' +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=TIMESTAMP'2001-01-01 10:20:30'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30' and (octet_length(TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30')) = 19 + rand() +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a='2001-01-01 10:20:30'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30' and (octet_length(TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30')) = 19 + rand() +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=20010101102030; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30' and (octet_length(TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30')) = 19 + rand() +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=20010101102030e0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.000000' and (octet_length(TIMESTAMP'2001-01-01 10:20:30')) = 19 + rand() +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=20010101102030.0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.0' and (octet_length(TIMESTAMP'2001-01-01 10:20:30')) = 19 + rand() +DROP TABLE t1; +SET time_zone=DEFAULT; +# +# End of 10.6 tests +# +# # MDEV-29225 make explicit_defaults_for_timestamps SESSION variable # set explicit_defaults_for_timestamp=OFF; diff --git a/mysql-test/main/type_timestamp.test b/mysql-test/main/type_timestamp.test index b3dfa19223d..34276caede4 100644 --- a/mysql-test/main/type_timestamp.test +++ b/mysql-test/main/type_timestamp.test @@ -907,6 +907,246 @@ SET time_zone=DEFAULT; --echo # End of 10.4 tests --echo # +--echo # +--echo # Start of 10.6 tests +--echo # + +--echo # +--echo # MDEV-32148 Inefficient WHERE timestamp_column=datetime_expr +--echo # + +SET time_zone='+00:00'; +CREATE TABLE t1 (a TIMESTAMP); +INSERT INTO t1 VALUES ('0000-00-00 00:00:00'); +INSERT INTO t1 VALUES ('2001-01-01 10:20:30'), ('2001-01-01 10:20:31'); + +--echo # +--echo # Comparison predicates: Bad TIMESTAMP values preserve DATETIME comparison +--echo # + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1001-01-01 10:20:30'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2001-01-00 00:00:00'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2040-01-01 10:20:30'; + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='1001-01-01 10:20:30'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-00 00:00:00'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2040-01-01 10:20:30'; + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10010101102030; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010100000000; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20400101102030; + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10010101102030e0; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010100000000e0; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20400101102030e0; + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10010101102030.0; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010100000000.0; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20400101102030.0; + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=DATE_ADD('2020-01-01 10:20:30', INTERVAL 30 YEAR); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE COALESCE(NULL, a)=DATE_ADD('2020-01-01 10:20:30', INTERVAL 30 YEAR); + +--echo # +--echo # Comparison predicates: Good TIMESTAMP values switch to TIMESTAMP comparison +--echo # + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'0000-00-00 00:00:00'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2001-01-01 10:20:30'; + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='0000-00-00 00:00:00'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01 10:20:30'; + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=0; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010101102030; + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=0e0; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010101102030e0; + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=0.0; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010101102030.0; + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=DATE_ADD('2001-01-01 10:20:00', INTERVAL 30 SECOND); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE COALESCE(NULL, a)=DATE_ADD('2001-01-01 10:20:00', INTERVAL 30 SECOND); + +--echo # +--echo # Corner cases: DATETIME values before the supported optimization range +--echo # FROM_UNIXTIME(0)..FROM_UNIXTIME(24*3600-1) +--echo # + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 00:00:00'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.999999'; + +# Truncation of the 7th flactional digit produces a NOTE only without --ps +--disable_ps_protocol +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.9999999'; +--enable_ps_protocol +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(24*3600-1); + +--echo # +--echo # Corner cases: DATETIME values inside the supported optimization range: +--echo # FROM_UNIXTIME(24*3600) .. FROM_UNIXTIME(0x7FFFFFFF-24*3600) +--echo # + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(24*3600); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-02 00:00:00'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:07'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(0x7FFFFFFF-24*3600); + +--echo # +--echo # Corner cases: DATETIME values after the supported optimization range +--echo # FROM_UNIXTIME(0x7FFFFFFF-24*3600+1) .. FROM_UNIXTIME(0x7FFFFFFF) +--echo # + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(0x7FFFFFFF-24*3600+1); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:08'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-19 03:14:07'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(0x7FFFFFFF); + +--echo # +--echo # Corner cases: rounding +--echo # + +SET sql_mode=TIME_ROUND_FRACTIONAL; + +--echo # +--echo # Not optimized (before the supported range) +--echo # +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.999999'; + +--echo # +--echo # Optimized +--echo # +--disable_ps_protocol +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.9999999'; +--enable_ps_protocol +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:07.999999'; + +--echo # +--echo # Not optimized (after the supported range) +--echo # +--disable_ps_protocol +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:07.9999999'; +--enable_ps_protocol + +SET sql_mode=DEFAULT; + +--echo # +--echo # NULLIF: Bad TIMESTAMP values preserve DATETIME comparison +--echo # + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'1001-01-01 10:20:30'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'2001-01-00 00:00:00'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'2040-01-01 10:20:30'); + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'1001-01-01 10:20:30'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'2001-01-00 00:00:00'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'2040-01-01 10:20:30'); + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,10010101102030); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010100000000); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20400101102030); + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,10010101102030e0); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010100000000e0); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20400101102030e0); + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,10010101102030.0); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010100000000.0); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20400101102030.0); + +--echo # +--echo # NULLIF: Good TIMESTAMP values switch to TIMESTAMP comparison +--echo # + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'0000-00-00 00:00:00'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'2001-01-01 10:20:30'); + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'0000-00-00 00:00:00'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'2001-01-01 10:20:30'); + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,0); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010101102030); + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,0e0); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010101102030e0); + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,0.0); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010101102030.0); + + +--echo # +--echo # Subqueries with bad TIMESTAMP values +--echo # It's not clear from the output if the comparison is done as DATETIME or TIMESTAMP +--echo # + +CREATE TABLE t2 (a DATETIME); +INSERT INTO t2 VALUES ('1001-01-01 10:20:30'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2); +DROP TABLE t2; + +CREATE TABLE t2 (a DATETIME); +INSERT INTO t2 VALUES ('2001-00-00 00:00:00'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2); +DROP TABLE t2; + +CREATE TABLE t2 (a DATETIME); +INSERT INTO t2 VALUES ('2040-01-01 10:20:30'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2); +DROP TABLE t2; + +--echo # +--echo # Subqueries with good TIMESTAMP values +--echo # It's not clear from the output if the comparison is done as DATETIME or TIMESTAMP +--echo # + +CREATE TABLE t2 (a DATETIME); +INSERT INTO t2 VALUES ('0000-00-00 00:00:00'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2); +DROP TABLE t2; + +CREATE TABLE t2 (a DATETIME); +INSERT INTO t2 VALUES ('2001-01-01 10:20:30'); +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2); +DROP TABLE t2; + +--echo # +--echo # Trivial equality elimination +--echo # Covers Type_handler_timestamp_common::Item_const_eq() +--echo # + +EXPLAIN EXTENDED SELECT * FROM t1 +WHERE IF(a='2001-01-01 00:00:00',1,0)=IF(a='2001-01-01 00:00:00',1,0); + +EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE (a<=>?)=(a<=>?)' + USING '2001-01-01 00:00:00', '2001-01-01 00:00:00'; + + +--echo # +--echo # Equal field propagation: Good TIMESTAMP values switch to TIMESTAMP comparison +--echo # + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=TIMESTAMP'2001-01-01 10:20:30'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a='2001-01-01 10:20:30'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=20010101102030; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=20010101102030e0; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=20010101102030.0; + +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=TIMESTAMP'2001-01-01 10:20:30'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a='2001-01-01 10:20:30'; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=20010101102030; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=20010101102030e0; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=20010101102030.0; + +DROP TABLE t1; + +SET time_zone=DEFAULT; + +--echo # +--echo # End of 10.6 tests +--echo # + --echo # --echo # MDEV-29225 make explicit_defaults_for_timestamps SESSION variable --echo # diff --git a/mysql-test/suite/versioning/r/cte.result b/mysql-test/suite/versioning/r/cte.result index 11d478ac456..4a9eba56006 100644 --- a/mysql-test/suite/versioning/r/cte.result +++ b/mysql-test/suite/versioning/r/cte.result @@ -40,7 +40,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 UNION e ALL NULL NULL NULL NULL 4 100.00 Using where NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Warnings: -Note 1003 with ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors` +Note 1003 with ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu')/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors` select row_start into @ts_2 from emp where name="john"; explain extended /* All report to 'Bill' */ with recursive @@ -64,7 +64,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 RECURSIVE UNION ref key0 key0 5 test.e.mgr 1 100.00 NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Warnings: -Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors` +Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu')/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors` /* All report to 'Bill' */ with recursive ancestors @@ -105,7 +105,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 RECURSIVE UNION ref key0 key0 5 test.e.mgr 1 100.00 NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Warnings: -Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors` +Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu')/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors` with recursive ancestors as @@ -146,7 +146,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 RECURSIVE UNION ref key0 key0 5 test.e.mgr 1 100.00 NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Warnings: -Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `test`.`emp`.`name` AS `name` from `test`.`emp` semi join (`ancestors`) where `ancestors`.`emp_id` = `test`.`emp`.`emp_id` and `test`.`emp`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999' +Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu')/* select#1 */ select `test`.`emp`.`name` AS `name` from `test`.`emp` semi join (`ancestors`) where `ancestors`.`emp_id` = `test`.`emp`.`emp_id` and `test`.`emp`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999' with recursive ancestors as diff --git a/mysql-test/suite/versioning/r/derived.result b/mysql-test/suite/versioning/r/derived.result index 700c92a8d5c..50cfb4020d0 100644 --- a/mysql-test/suite/versioning/r/derived.result +++ b/mysql-test/suite/versioning/r/derived.result @@ -211,12 +211,12 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join) Query A: -Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > (current_timestamp(6)) and `test`.`t2`.`row_start` <= (current_timestamp(6)) and `test`.`t1`.`row_end` > (current_timestamp(6)) and `test`.`t1`.`row_start` <= (current_timestamp(6)) +Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t2`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join) Query B: -Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > (current_timestamp(6)) and `test`.`t2`.`row_start` <= (current_timestamp(6)) and `test`.`t1`.`row_end` > (current_timestamp(6)) and `test`.`t1`.`row_start` <= (current_timestamp(6)) +Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t2`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' Fine result: queries A and B are equal. ## LEFT JOIN: t1, t2 versioned select * from ( diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 36ea54bb08e..c4e8df1a743 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -155,21 +155,21 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join) Warnings: -Note 1003 select `test`.`t1`.`x` AS `IJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0` and `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0` +Note 1003 select `test`.`t1`.`x` AS `IJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t2`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' explain extended select * from (select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x) for system_time as of timestamp @t0 as t; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join) Warnings: -Note 1003 select `test`.`t1`.`x` AS `LJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` left join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` on(`test`.`t2`.`x` = `test`.`t1`.`x` and `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0`) where `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0` +Note 1003 select `test`.`t1`.`x` AS `LJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` left join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` on(`test`.`t2`.`x` = `test`.`t1`.`x` and `test`.`t2`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t2`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu') where `test`.`t1`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' explain extended select * from (select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x) for system_time as of timestamp @t0 as t; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join) Warnings: -Note 1003 select `test`.`t1`.`x` AS `RJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` left join `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` on(`test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0`) where `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0` +Note 1003 select `test`.`t1`.`x` AS `RJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` left join `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` on(`test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu') where `test`.`t2`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t2`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' select * from (select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x) for system_time as of timestamp @t0 as t; IJ2_x1 y1 x2 y2 diff --git a/mysql-test/suite/versioning/t/cte.test b/mysql-test/suite/versioning/t/cte.test index 025e1b2319d..f57f7d14cef 100644 --- a/mysql-test/suite/versioning/t/cte.test +++ b/mysql-test/suite/versioning/t/cte.test @@ -5,6 +5,8 @@ if (`SELECT $PS_PROTOCOL != 0`) --source include/have_innodb.inc --source include/default_optimizer_switch.inc +--let $replace_regex_tsltz6= /TIMESTAMP..WITH LOCAL TIME ZONE..'....-..-.. ..:..:..[.]......'/TIMESTAMP\/*WITH LOCAL TIME ZONE*\/'YYYY-MM-DD hh:ss:mm:.uuuuuu'/ + SET @saved_stats_persistent = @@GLOBAL.innodb_stats_persistent; SET GLOBAL innodb_stats_persistent = OFF; @@ -42,6 +44,7 @@ select row_start into @ts_1 from emp where name="jane"; update emp set mgr=30 where name ="john"; +--replace_regex $replace_regex_tsltz6 explain extended with ancestors as ( select e.emp_id, e.name, e.mgr, e.salary from emp as e where name = 'bill' @@ -68,6 +71,7 @@ as ) select * from ancestors; +--replace_regex $replace_regex_tsltz6 eval explain extended $q; eval $q; @@ -86,6 +90,7 @@ as ) select * from ancestors for system_time as of timestamp @ts_1; +--replace_regex $replace_regex_tsltz6 eval explain extended $q; eval $q; @@ -104,6 +109,7 @@ as ) select name from emp where emp_id in (select emp_id from ancestors for system_time as of timestamp @ts_1); +--replace_regex $replace_regex_tsltz6 eval explain extended $q; eval $q; diff --git a/mysql-test/suite/versioning/t/derived.test b/mysql-test/suite/versioning/t/derived.test index 9d96856f01f..f599ede97c1 100644 --- a/mysql-test/suite/versioning/t/derived.test +++ b/mysql-test/suite/versioning/t/derived.test @@ -1,5 +1,7 @@ --source include/default_optimizer_switch.inc +--let $replace_regex_tsltz6= /TIMESTAMP..WITH LOCAL TIME ZONE..'....-..-.. ..:..:..[.]......'/TIMESTAMP\/*WITH LOCAL TIME ZONE*\/'YYYY-MM-DD hh:ss:mm:.uuuuuu'/ + create table emp ( emp_id int, @@ -164,6 +166,7 @@ select * from ( select t1.x, t1.y as y1, t2.x as x2, t2.y as y2 from t1 join t2 on t1.x = t2.x) for system_time as of now() as t; +--replace_regex $replace_regex_tsltz6 let $a=`show warnings`; --echo Query A: echo $a; @@ -174,6 +177,7 @@ select * from ( from t1 for system_time as of now() join t2 for system_time as of now() on t1.x = t2.x) as t; +--replace_regex $replace_regex_tsltz6 let $b=`show warnings`; --echo Query B: echo $b; diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 5603d1a3a12..b9a836f708e 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -6,6 +6,8 @@ if (`SELECT $PS_PROTOCOL != 0`) --source suite/versioning/common.inc --source include/default_optimizer_switch.inc +--let $replace_regex_tsltz6= /TIMESTAMP..WITH LOCAL TIME ZONE..'....-..-.. ..:..:..[.]......'/TIMESTAMP\/*WITH LOCAL TIME ZONE*\/'YYYY-MM-DD hh:ss:mm:.uuuuuu'/ + SET @saved_stats_persistent = @@GLOBAL.innodb_stats_persistent; SET GLOBAL innodb_stats_persistent = OFF; @@ -98,11 +100,14 @@ delete from t1; delete from t2; #384 +--replace_regex $replace_regex_tsltz6 explain extended select * from (select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x) for system_time as of timestamp @t0 as t; +--replace_regex $replace_regex_tsltz6 explain extended select * from (select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x) for system_time as of timestamp @t0 as t; #383 +--replace_regex $replace_regex_tsltz6 explain extended select * from (select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x) for system_time as of timestamp @t0 as t; diff --git a/sql/item.cc b/sql/item.cc index a385cb67f30..f3e358f93e4 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7332,6 +7332,17 @@ void Item_datetime_literal::print(String *str, enum_query_type query_type) } +void Item_timestamp_literal::print(String *str, enum_query_type query_type) +{ + str->append(STRING_WITH_LEN("TIMESTAMP/*WITH LOCAL TIME ZONE*/'")); + char buf[MAX_DATE_STRING_REP_LENGTH]; + Datetime dt= m_value.to_datetime(current_thd); + int length= my_datetime_to_str(dt.get_mysql_time(), buf, decimals); + str->append(buf, length); + str->append('\''); +} + + Item *Item_datetime_literal::clone_item(THD *thd) { return new (thd->mem_root) Item_datetime_literal(thd, &cached_time, decimals); diff --git a/sql/item.h b/sql/item.h index 16ba4514421..3915d8a7ca0 100644 --- a/sql/item.h +++ b/sql/item.h @@ -5005,9 +5005,21 @@ class Item_timestamp_literal: public Item_literal public: Item_timestamp_literal(THD *thd) :Item_literal(thd) - { } + { + collation= DTCollation_numeric(); + } + Item_timestamp_literal(THD *thd, + const Timestamp_or_zero_datetime &value, + decimal_digits_t dec) + :Item_literal(thd), + m_value(value) + { + collation= DTCollation_numeric(); + decimals= dec; + } const Type_handler *type_handler() const override { return &type_handler_timestamp2; } + void print(String *str, enum_query_type query_type) override; int save_in_field(Field *field, bool) override { Timestamp_or_zero_datetime_native native(m_value, decimals); @@ -5039,6 +5051,10 @@ public: { return m_value.to_native(to, decimals); } + const Timestamp_or_zero_datetime &value() const + { + return m_value; + } void set_value(const Timestamp_or_zero_datetime &value) { m_value= value; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index b324a8f5e6a..d1891818cd6 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -392,6 +392,9 @@ static bool convert_const_to_int(THD *thd, Item_field *field_item, This directly contradicts the manual (number and a string should be compared as doubles), but seems to provide more "intuitive" behavior in some cases (but less intuitive in others). + + This method should be moved to Type_handler::convert_item_for_comparison() + eventually. */ void Item_func::convert_const_compared_to_int_field(THD *thd) { @@ -412,6 +415,43 @@ void Item_func::convert_const_compared_to_int_field(THD *thd) } +bool Item_func::aggregate_args2_for_comparison_with_conversion( + THD *thd, + Type_handler_hybrid_field_type *th) +{ + DBUG_ASSERT(arg_count >= 2); + for (bool done= false ; !done ; ) + { + if (th->aggregate_for_comparison(func_name_cstring(), args, 2, false)) + return true; + if (thd->lex->is_ps_or_view_context_analysis()) + return false; + done= true; + for (uint subject= 0; subject < 2; subject++) + { + uint other_side= subject == 0 ? 1 : 0; + /* See comment in convert_const_to_int() */ + if (!args[subject]->with_sum_func() && + args[subject]->can_eval_in_optimize()) + { + Item *item= th->type_handler()->convert_item_for_comparison(thd, + args[subject], + args[other_side]); + if (!item) + return true; // An error happened, e.g. EOM + if (item != args[subject]) + { + thd->change_item_tree(&args[subject], item); + done= false; // Aggregate again, using the replacement item + break; + } + } + } + } + return false; +} + + /* Iterate through arguments and compare them to the original arguments in "old_args". If some argument was replaced: @@ -487,7 +527,7 @@ bool Item_bool_rowready_func2::fix_length_and_dec(THD *thd) Item_args old_args(args[0], args[1]); convert_const_compared_to_int_field(thd); Type_handler_hybrid_field_type tmp; - if (tmp.aggregate_for_comparison(func_name_cstring(), args, 2, false) || + if (aggregate_args2_for_comparison_with_conversion(thd, &tmp) || tmp.type_handler()->Item_bool_rowready_func2_fix_length_and_dec(thd, this)) { @@ -2804,7 +2844,10 @@ Item_func_nullif::fix_length_and_dec(THD *thd) set_maybe_null(); m_arg0= args[0]; convert_const_compared_to_int_field(thd); - if (cmp.set_cmp_func(thd, this, &args[0], &args[1], true/*set_null*/)) + Type_handler_hybrid_field_type tmp; + if (aggregate_args2_for_comparison_with_conversion(thd, &tmp) || + cmp.set_cmp_func(thd, this, tmp.type_handler(), + &args[0], &args[1], true/*set_null*/)) return true; /* A special code for EXECUTE..PREPARE. diff --git a/sql/item_func.h b/sql/item_func.h index e1d67a73134..5ec0e0f0608 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -83,6 +83,8 @@ protected: return print_sql_mode_qualified_name(to, query_type, func_name_cstring()); } + bool aggregate_args2_for_comparison_with_conversion(THD *thd, + Type_handler_hybrid_field_type *th); public: // Print an error message for a builtin-schema qualified function call diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 9535bf1fee5..6d290995c99 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1207,6 +1207,63 @@ void thd_gmt_sec_to_TIME(MYSQL_THD thd, MYSQL_TIME *ltime, my_time_t t) } +/* + @brief + Convert a non-zero DATETIME to its safe timeval based representation, + which guarantees a safe roundtrip DATETIME->timeval->DATETIME, + e.g. to optimize: + + WHERE timestamp_arg0 = datetime_arg1 + + in the way that we replace "datetime_arg1" to its TIMESTAMP equivalent + "timestamp_arg1" and switch from DATETIME comparison to TIMESTAMP comparison: + + WHERE timestamp_arg0 = timestamp_arg1 + + This helps to avoid slow TIMESTAMP->DATETIME data type conversion + for timestamp_arg0 per row. + + @detail + Round trip is possible if the input "YYYY-MM-DD hh:mm:ss" value + satisfies the following conditions: + + 1. TIME_to_gmt_sec() returns no errors or warnings, + which means the input value + a. has no zeros in YYYYMMDD + b. fits into the TIMESTAMP range + c. does not fall into the spring forward gap + (because values inside gaps get adjusted to the beginning of the gap) + + 2. The my_time_t value returned by TIME_to_gmt_sec() must not be + near a DST change or near a leap second, to avoid anomalies: + - "YYYY-MM-DD hh:mm:ss" has more than one matching my_time_t values + - "YYYY-MM-DD hh:mm:ss" has no matching my_time_t values + (e.g. fall into the spring forward gap) + + @param dt The DATETIME value to convert. + Must not be zero '0000-00-00 00:00:00.000000'. + (The zero value must be handled by the caller). + + @return The conversion result + @retval If succeeded, non-NULL Timeval value. + @retval Timeval_null value representing SQL NULL if the argument + does not have a safe replacement. +*/ +Timeval_null +THD::safe_timeval_replacement_for_nonzero_datetime(const Datetime &dt) +{ + used|= THD::TIME_ZONE_USED; + DBUG_ASSERT(non_zero_date(dt.get_mysql_time())); + uint error= 0; + const MYSQL_TIME *ltime= dt.get_mysql_time(); + my_time_t sec= variables.time_zone->TIME_to_gmt_sec(ltime, &error); + if (error /* (1) */ || + !variables.time_zone->is_monotone_continuous_around(sec) /* (2) */) + return Timeval_null(); + return Timeval_null(sec, ltime->second_part); +} + + #ifdef _WIN32 extern "C" my_thread_id next_thread_id_noinline() { diff --git a/sql/sql_class.h b/sql/sql_class.h index bca0edd859e..2b959196db8 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -4283,6 +4283,8 @@ public: utime_after_query= current_utime(); } + Timeval_null safe_timeval_replacement_for_nonzero_datetime(const Datetime &); + /** Update server status after execution of a top level statement. Currently only checks if a query was slow, and assigns diff --git a/sql/sql_type.cc b/sql/sql_type.cc index c68809ec784..926d83c3fc9 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -7686,6 +7686,104 @@ Item *Type_handler_row:: return NULL; } +/***************************************************************************/ + +/* + Check if in a predicate like: + + WHERE timestamp_arg=datetime_arg + + we can replace DATETIME comparison to TIMESTAMP comparison, + to avoid slow TIMESTAMP->DATETIME data type conversion per row. + + TIMESTAMP and DATETIME are compared as DATETIME historically. + This may be inefficient, because involves a conversion of + the TIMESTAMP side to DATETIME per row. + The conversion happens in Timezone::gmt_sec_to_TIME(). + E.g. in case of the SYSTEM timezone, it calls localtime_r(), + which is known to be slow. + + It's generally not possible to compare TIMESTAMP and DATETIME + as TIMESTAMP without behavior change, because: + - DATETIME has a wider range. + - Two different TIMESTAMP values can have the same DATETIME value + near the "fall back" DST change, as well as for leap seconds. + - There are DATETIME gaps during the "spring forward" DST switch. + + However, if the DATETIME side is a constant, then we can compare + it to TIMESTAMP as TIMESTAMP in many cases. The DATETIME argument can + be converted once to TIMESTAMP, so no data type conversion will + happen per row. This is faster for big tables. + + The comparison predicates must satisfy the following conditions: + 1. There must be a proper data type combination: + - other must be of the TIMESTAMP data type + - subject must be of the DATETIME data type, + or can convert to DATETIME. + 2. subject must be a constant + 3. subject must convert to TIMESTAMP safely + (without time zone anomalies near its value) +*/ + +Item * +Type_handler_datetime_common::convert_item_for_comparison( + THD *thd, + Item *subject, + const Item *counterpart) + const +{ + if (!dynamic_cast( + counterpart->type_handler()) || + !subject->type_handler()->can_return_date()) + return subject; + + struct Count_handler : public Internal_error_handler + { + uint hit= 0; + bool handle_condition(THD *thd, + uint sql_errno, + const char *sqlstate, + Sql_condition::enum_warning_level *level, + const char *msg, + Sql_condition **cond_hdl) + { + hit++; + return *level == Sql_condition::WARN_LEVEL_WARN; + } + } cnt_handler; + + // Suppress and count warnings + thd->push_internal_handler(&cnt_handler); + Datetime dt(thd, subject, Timestamp::DatetimeOptions(thd)); + thd->pop_internal_handler(); + + if (!dt.is_valid_datetime() || cnt_handler.hit) + { + /* + SQL NULL DATETIME, or a DATETIME with zeros in YYYYMMDD, + or warnings during DATETIME evaluation. + */ + return subject; + } + + // '0000-00-00 00:00:00' is a special valid MariaDB TIMESTAMP value + if (!non_zero_date(dt.get_mysql_time())) + return new (thd->mem_root) Item_timestamp_literal(thd, + Timestamp_or_zero_datetime::zero(), + subject->datetime_precision(thd)); + + const Timeval_null tv(thd->safe_timeval_replacement_for_nonzero_datetime(dt)); + if (tv.is_null()) + return subject; // Time zone anomalies found around "dt" + + // Should be safe to convert + const Timestamp_or_zero_datetime ts(Timestamp(tv.to_timeval())); + return new (thd->mem_root) Item_timestamp_literal(thd, + ts, + subject->datetime_precision(thd)); +} + + /***************************************************************************/ static const char* item_name(Item *a, String *str) @@ -8686,6 +8784,43 @@ Type_handler_temporal_result::Item_const_eq(const Item_const *a, b->get_type_all_attributes_from_const()->decimals); } + +/* + @brief + Check if two costant timestamp values are identical. + + @return + true <=> *a and *b are identical +*/ +bool +Type_handler_timestamp_common::Item_const_eq(const Item_const *a, + const Item_const *b, + bool binary_cmp) const +{ + /* + In a condition like: + WHERE IF(a='2001-01-01 00:00:00',1,0)=IF(a='2001-01-01 00:00:00',1,0); + Item_func_eq::fix_length_and_dec() calls get_timestamp_item_for_comparison() + which replaces string literals '2001-01-01 00:00:00' with + Item_timestamp_literal instances, which later during remove_eq_conds() + come to here. + + Note, Item_param bound to TIMESTAMP is not detected here, + so trivial conditions of this kind do not get eliminated: + DECLARE ts TIMESTAMP DEFAULT (SELECT MAX(ts_col) FROM t1); + EXECUTE IMMEDIATE + 'SELECT * FROM t1 WHERE COALESCE(ts_col,?)<=>COALESCE(ts_col,?)' + USING ts, ts; + It should be fixed by MDEV-14271. + */ + const Item_timestamp_literal *ta, *tb; + if (!(ta= dynamic_cast(a)) || + !(tb= dynamic_cast(b))) + return false; + return !ta->value().cmp(tb->value()); +} + + /***************************************************************************/ const Type_handler * diff --git a/sql/sql_type.h b/sql/sql_type.h index 8215a3ee759..d41282ff9f9 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -2837,6 +2837,11 @@ public: class Timestamp_or_zero_datetime: protected Timestamp { bool m_is_zero_datetime; +public: + static Timestamp_or_zero_datetime zero() + { + return Timestamp_or_zero_datetime(Timestamp(0, 0), true); + } public: Timestamp_or_zero_datetime() :Timestamp(0,0), m_is_zero_datetime(true) @@ -2845,7 +2850,7 @@ public: :Timestamp(native.length() ? Timestamp(native) : Timestamp(0,0)), m_is_zero_datetime(native.length() == 0) { } - Timestamp_or_zero_datetime(const Timestamp &tm, bool is_zero_datetime) + Timestamp_or_zero_datetime(const Timestamp &tm, bool is_zero_datetime= false) :Timestamp(tm), m_is_zero_datetime(is_zero_datetime) { } Timestamp_or_zero_datetime(THD *thd, const MYSQL_TIME *ltime, uint *err_code); @@ -2869,6 +2874,11 @@ public: return 1; return Timestamp::cmp(other); } + const Timestamp &to_timestamp() const + { + DBUG_ASSERT(!is_zero_datetime()); + return *this; + } bool to_TIME(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) const; /* Convert to native format: @@ -4206,6 +4216,33 @@ public: virtual Item *make_const_item_for_comparison(THD *thd, Item *src, const Item *cmp) const= 0; + /** + When aggregating function arguments for comparison + (e.g. for =, <, >, <=, >=, NULLIF), in some cases we rewrite + arguments. For example, if the predicate + timestamp_expr0 = datetime_const_expr1 + decides to compare arguments as DATETIME, + we can try to rewrite datetime_const_expr1 to a TIMESTAMP constant + and perform the comparison as TIMESTAMP, which is faster because + does not have to perform TIMESTAMP->DATETIME data type conversion per row. + + "this" is the type handler that is used to compare + "subject" and "counterpart" (DATETIME in the above example). + @param thd the current thread + @param subject the comparison side that we want try to rewrite + @param counterpart the other comparison side + @retval subject, if the subject does not need to be rewritten + @retval NULL in case of error (e.g. EOM) + @retval Otherwise, a pointer to a new Item which can + be used as a replacement for the subject. + */ + virtual Item *convert_item_for_comparison(THD *thd, + Item *subject, + const Item *counterpart) const + { + return subject; + } + virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0; virtual Item *make_constructor_item(THD *thd, List *args) const { @@ -6524,6 +6561,9 @@ public: } String *print_item_value(THD *thd, Item *item, String *str) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; + Item *convert_item_for_comparison(THD *thd, + Item *subject, + const Item *counterpart) const override; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override; double Item_func_min_max_val_real(Item_func_min_max *) const override; longlong Item_func_min_max_val_int(Item_func_min_max *) const override; @@ -6695,6 +6735,8 @@ public: my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *) const override; bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override; + bool Item_const_eq(const Item_const *a, const Item_const *b, + bool binary_cmp) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, diff --git a/sql/structs.h b/sql/structs.h index c8351efd8bf..029543ceb01 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -1035,4 +1035,29 @@ public: }; +/* + A value that's either a Timeval or SQL NULL +*/ + +class Timeval_null: protected Timeval +{ + bool m_is_null; +public: + Timeval_null() + :Timeval(0, 0), + m_is_null(true) + { } + Timeval_null(const my_time_t sec, ulong usec) + :Timeval(sec, usec), + m_is_null(false) + { } + const Timeval & to_timeval() const + { + DBUG_ASSERT(!m_is_null); + return *this; + } + bool is_null() const { return m_is_null; } +}; + + #endif /* STRUCTS_INCLUDED */ diff --git a/sql/tztime.cc b/sql/tztime.cc index 9a1f8c6fc52..0ccf3cc76eb 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2426,6 +2426,59 @@ void Time_zone::adjust_leap_second(MYSQL_TIME *t) t->second= 59; } + +/* + @brief + Check if timestamp<->datetime conversion is guaranteed to be reversible + around the given time value. +*/ + +bool Time_zone::is_monotone_continuous_around(my_time_t sec) const +{ + const my_time_t width= 24 * 60 * 60; + /* + Let's check that the TIMESTAMP range [sec - width, sec + width] + converts back to a DATETIME range [dtmin, dtmax], and the difference + (dtmax-dtmin), calculated using DATETIME arithmetics, + is also equal to exactly 2*width. + + This should almost guarantee that the TIMESTAMP range around sec + is monotone and continuous and thus has no DST changes or leap seconds. + + It's still possible that there are two or more timezone offset changes + in the given range. But there are no such time zones according to + our knowledge. + Note, DST changes and leap seconds do not interfere on a short time_t range: + - Leap seconds happen in winter and summer + - DST changes happen in spring and fall + + The largest time zone change that ever happened in a single place + was 24 hours: + - from SST (UTC-11) - the American Samoa Time Zone + - to WST (UTC+13) - the Independent State of Samoa Time Zone + The Independent State of Samoa used SST until it moved across + the International Date Line at the end of 29 December 2011, to WST. + It is now 24 hours ahead of American Samoa + (and 25 hours in Southern hemisphere summer). + Let's use 24 hours as width (48 hours range total). + */ + + if (sec < width || sec > TIMESTAMP_MAX_VALUE - width) + return false; + + MYSQL_TIME dtmin, dtmax; + gmt_sec_to_TIME(&dtmin, sec - width); + gmt_sec_to_TIME(&dtmax, sec + width); + + ulonglong seconds; + ulong useconds; + if (calc_time_diff(&dtmax, &dtmin, 1, &seconds, &useconds)) + return false; // dtmax is smaller than dtmin, should not happen. + if (seconds != (ulonglong) width * 2) + return false; // Anomalies found (DST changes or leap seconds) + return true; +} + #endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */ diff --git a/sql/tztime.h b/sql/tztime.h index 3dabbe8d118..3c394014946 100644 --- a/sql/tztime.h +++ b/sql/tztime.h @@ -80,6 +80,13 @@ public: */ virtual ~Time_zone() = default; + /** + Check if the time zone does not have any anomalies around "sec", such as: + - DST changes (spring forward, fall back) + - leap seconds (the 60-th second) + */ + bool is_monotone_continuous_around(my_time_t sec) const; + protected: static inline void adjust_leap_second(MYSQL_TIME *t); }; diff --git a/storage/spider/mysql-test/spider/r/timestamp.result b/storage/spider/mysql-test/spider/r/timestamp.result index 4618d9207bf..a717860ab6c 100644 --- a/storage/spider/mysql-test/spider/r/timestamp.result +++ b/storage/spider/mysql-test/spider/r/timestamp.result @@ -257,7 +257,7 @@ select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timest select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (_latin1'2018-10-28 01:30:00' > t0.`col_ts`) select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` between _latin1'2018-10-28 00:30:00' and _latin1'2018-10-28 01:30:00') select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where ((t0.`col_ts` >= _latin1'2018-10-28 00:30:00') and (t0.`col_ts` <= _latin1'2018-10-28 01:30:00')) -select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > '2018-03-25 01:00:00') +select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > _latin1'2018-03-25 01:00:00') select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > '1970-01-01 00:00:01') SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' SELECT col_a, col_dt, col_ts, unix_timestamp(col_ts) FROM tbl_a ORDER BY col_a; @@ -344,7 +344,7 @@ select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timest select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (_latin1'2018-10-28 01:30:00' > t0.`col_ts`) select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` between _latin1'2018-10-28 00:30:00' and _latin1'2018-10-28 01:30:00') select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where ((t0.`col_ts` >= _latin1'2018-10-28 00:30:00') and (t0.`col_ts` <= _latin1'2018-10-28 01:30:00')) -select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > '2018-03-25 01:00:00') +select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > _latin1'2018-03-25 01:00:00') select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > '1970-01-01 00:00:01') SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %' SELECT col_a, col_dt, col_ts, unix_timestamp(col_ts) FROM tbl_a ORDER BY col_a;